/****************************************************************************** * * Copyright (C) 2002-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This module contains API of the audio/video distribution transport * protocol. * ******************************************************************************/ #include "avdt_api.h" #include #include "avdt_int.h" #include "avdtc_api.h" #include "bt_target.h" #include "bt_types.h" #include "btm_api.h" #include "btu.h" #include "l2c_api.h" #include "stack/include/a2dp_codec_api.h" /* Control block for AVDT */ tAVDT_CB avdt_cb; void avdt_ccb_idle_ccb_timer_timeout(void* data) { tAVDT_CCB* p_ccb = (tAVDT_CCB*)data; uint8_t avdt_event = AVDT_CCB_IDLE_TOUT_EVT; uint8_t err_code = AVDT_ERR_TIMEOUT; tAVDT_CCB_EVT avdt_ccb_evt; avdt_ccb_evt.err_code = err_code; avdt_ccb_event(p_ccb, avdt_event, &avdt_ccb_evt); } void avdt_ccb_ret_ccb_timer_timeout(void* data) { tAVDT_CCB* p_ccb = (tAVDT_CCB*)data; uint8_t avdt_event = AVDT_CCB_RET_TOUT_EVT; uint8_t err_code = AVDT_ERR_TIMEOUT; tAVDT_CCB_EVT avdt_ccb_evt; avdt_ccb_evt.err_code = err_code; avdt_ccb_event(p_ccb, avdt_event, &avdt_ccb_evt); } void avdt_ccb_rsp_ccb_timer_timeout(void* data) { tAVDT_CCB* p_ccb = (tAVDT_CCB*)data; uint8_t avdt_event = AVDT_CCB_RSP_TOUT_EVT; uint8_t err_code = AVDT_ERR_TIMEOUT; tAVDT_CCB_EVT avdt_ccb_evt; avdt_ccb_evt.err_code = err_code; avdt_ccb_event(p_ccb, avdt_event, &avdt_ccb_evt); } void avdt_scb_transport_channel_timer_timeout(void* data) { tAVDT_SCB* p_scb = (tAVDT_SCB*)data; uint8_t avdt_event = AVDT_SCB_TC_TOUT_EVT; avdt_scb_event(p_scb, avdt_event, NULL); } /******************************************************************************* * * Function AVDT_Register * * Description This is the system level registration function for the * AVDTP protocol. This function initializes AVDTP and * prepares the protocol stack for its use. This function * must be called once by the system or platform using AVDTP * before the other functions of the API an be used. * * * Returns void * ******************************************************************************/ void AVDT_Register(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback) { /* register PSM with L2CAP */ L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl); /* set security level */ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); /* do not use security on the media channel */ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); #if (AVDT_REPORTING == TRUE) /* do not use security on the reporting channel */ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); #endif /* initialize AVDTP data structures */ avdt_scb_init(); avdt_ccb_init(); avdt_ad_init(); /* copy registration struct */ memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG)); avdt_cb.p_conn_cback = p_cback; } /******************************************************************************* * * Function AVDT_Deregister * * Description This function is called to deregister use AVDTP protocol. * It is called when AVDTP is no longer being used by any * application in the system. Before this function can be * called, all streams must be removed with * AVDT_RemoveStream(). * * * Returns void * ******************************************************************************/ void AVDT_Deregister(void) { /* deregister PSM with L2CAP */ L2CA_Deregister(AVDT_PSM); } void AVDT_AbortReq(uint8_t handle) { AVDT_TRACE_WARNING("%s: handle=%d", __func__, handle); 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", __func__); } } /******************************************************************************* * * Function AVDT_CreateStream * * Description Create a stream endpoint. After a stream endpoint is * created an application can initiate a connection between * this endpoint and an endpoint on a peer device. In * addition, a peer device can discover, get the capabilities, * and connect to this endpoint. * * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs) { uint16_t result = AVDT_SUCCESS; tAVDT_SCB* p_scb; AVDT_TRACE_DEBUG("%s", __func__); /* Verify parameters; if invalid, return failure */ if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL)) { result = AVDT_BAD_PARAMS; } /* Allocate scb; if no scbs, return failure */ else { p_scb = avdt_scb_alloc(p_cs); if (p_scb == NULL) { result = AVDT_NO_RESOURCES; } else { *p_handle = avdt_scb_to_hdl(p_scb); } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * 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_t AVDT_RemoveStream(uint8_t handle) { uint16_t result = AVDT_SUCCESS; tAVDT_SCB* p_scb; AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle); /* look up scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; } else { /* send remove event to scb */ avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_DiscoverReq * * Description This function initiates a connection to the AVDTP service * on the peer device, if not already present, and discovers * the stream endpoints on the peer device. (Please note * that AVDTP discovery is unrelated to SDP discovery). * This function can be called at any time regardless of * whether there is an AVDTP connection to the peer device. * * When discovery is complete, an AVDT_DISCOVER_CFM_EVT * is sent to the application via its callback function. * The application must not call AVDT_GetCapReq() or * AVDT_DiscoverReq() again to the same device until * discovery is complete. * * The memory addressed by sep_info is allocated by the * application. This memory is written to by AVDTP as part * of the discovery procedure. This memory must remain * accessible until the application receives the * AVDT_DISCOVER_CFM_EVT. * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_DiscoverReq(const RawAddress& bd_addr, tAVDT_SEP_INFO* p_sep_info, uint8_t max_seps, tAVDT_CTRL_CBACK* p_cback) { tAVDT_CCB* p_ccb; uint16_t result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; AVDT_TRACE_DEBUG("%s", __func__); /* find channel control block for this bd addr; if none, allocate one */ p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb == NULL) { p_ccb = avdt_ccb_alloc(bd_addr); if (p_ccb == NULL) { /* could not allocate channel control block */ result = AVDT_NO_RESOURCES; } } if (result == AVDT_SUCCESS) { /* make sure no discovery or get capabilities req already in progress */ if (p_ccb->proc_busy) { result = AVDT_BUSY; } /* send event to ccb */ else { evt.discover.p_sep_info = p_sep_info; evt.discover.num_seps = max_seps; evt.discover.p_cback = p_cback; avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt); } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function avdt_get_cap_req * * Description internal function to serve both AVDT_GetCapReq and * AVDT_GetAllCapReq * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ static uint16_t avdt_get_cap_req(const RawAddress& bd_addr, tAVDT_CCB_API_GETCAP* p_evt) { tAVDT_CCB* p_ccb = NULL; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s", __func__); /* verify SEID */ if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX)) { AVDT_TRACE_ERROR("seid: %d", p_evt->single.seid); result = AVDT_BAD_PARAMS; } /* find channel control block for this bd addr; if none, allocate one */ else { p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb == NULL) { p_ccb = avdt_ccb_alloc(bd_addr); if (p_ccb == NULL) { /* could not allocate channel control block */ result = AVDT_NO_RESOURCES; } } } if (result == AVDT_SUCCESS) { /* make sure no discovery or get capabilities req already in progress */ if (p_ccb->proc_busy) { result = AVDT_BUSY; } /* send event to ccb */ else { avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT*)p_evt); } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_GetCapReq * * Description This function initiates a connection to the AVDTP service * on the peer device, if not already present, and gets the * capabilities of a stream endpoint on the peer device. * This function can be called at any time regardless of * whether there is an AVDTP connection to the peer device. * * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is * sent to the application via its callback function. The * application must not call AVDT_GetCapReq() or * AVDT_DiscoverReq() again until the procedure is complete. * * The memory pointed to by p_cfg is allocated by the * application. This memory is written to by AVDTP as part * of the get capabilities procedure. This memory must * remain accessible until the application receives * the AVDT_GETCAP_CFM_EVT. * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_GetCapReq(const RawAddress& bd_addr, uint8_t seid, tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback) { tAVDT_CCB_API_GETCAP getcap; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s", __func__); getcap.single.seid = seid; getcap.single.sig_id = AVDT_SIG_GETCAP; getcap.p_cfg = p_cfg; getcap.p_cback = p_cback; result = avdt_get_cap_req(bd_addr, &getcap); AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_GetAllCapReq * * Description This function initiates a connection to the AVDTP service * on the peer device, if not already present, and gets the * capabilities of a stream endpoint on the peer device. * This function can be called at any time regardless of * whether there is an AVDTP connection to the peer device. * * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is * sent to the application via its callback function. The * application must not call AVDT_GetCapReq() or * AVDT_DiscoverReq() again until the procedure is complete. * * The memory pointed to by p_cfg is allocated by the * application. This memory is written to by AVDTP as part * of the get capabilities procedure. This memory must * remain accessible until the application receives * the AVDT_GETCAP_CFM_EVT. * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_GetAllCapReq(const RawAddress& bd_addr, uint8_t seid, tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback) { tAVDT_CCB_API_GETCAP getcap; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s", __func__); getcap.single.seid = seid; getcap.single.sig_id = AVDT_SIG_GET_ALLCAP; getcap.p_cfg = p_cfg; getcap.p_cback = p_cback; result = avdt_get_cap_req(bd_addr, &getcap); AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * 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_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) { tAVDT_SCB* p_scb; uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; AVDT_TRACE_DEBUG("%s: handle=%d ceid=%d delay=%d", __func__, handle, seid, delay); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); 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_t AVDT_OpenReq(uint8_t handle, const RawAddress& bd_addr, uint8_t seid, tAVDT_CFG* p_cfg) { tAVDT_CCB* p_ccb = NULL; tAVDT_SCB* p_scb = NULL; uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; AVDT_TRACE_DEBUG("%s: handle=%d seid=%d", __func__, handle, seid); /* verify SEID */ if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) { result = AVDT_BAD_PARAMS; } /* map handle to scb */ else { p_scb = avdt_scb_by_hdl(handle); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; } /* find channel control block for this bd addr; if none, allocate one */ else { p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb == NULL) { p_ccb = avdt_ccb_alloc(bd_addr); if (p_ccb == NULL) { /* could not allocate channel control block */ result = AVDT_NO_RESOURCES; } } } } /* send event to scb */ if (result == AVDT_SUCCESS) { A2DP_DumpCodecInfo(p_cfg->codec_info); 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * 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_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint8_t category) { tAVDT_SCB* p_scb; tAVDT_SCB_EVT evt; uint16_t result = AVDT_SUCCESS; uint8_t event_code; AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__, handle, label, error_code, category); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_StartReq * * Description Start one or more stream endpoints. This initiates the * transfer of media packets for the streams. All stream * endpoints must previously be opened. When the streams * are started, an AVDT_START_CFM_EVT is sent to the * application via the control callback function for each * stream. * * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) { tAVDT_SCB* p_scb = NULL; tAVDT_CCB_EVT evt; uint16_t result = AVDT_SUCCESS; int i; AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles); if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { result = AVDT_BAD_PARAMS; } else { /* verify handles */ for (i = 0; i < num_handles; i++) { p_scb = avdt_scb_by_hdl(p_handles[i]); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; break; } } } if (result == AVDT_SUCCESS) { if (p_scb->p_ccb == NULL) { result = AVDT_BAD_HANDLE; } else { /* send event to ccb */ memcpy(evt.msg.multi.seid_list, p_handles, num_handles); evt.msg.multi.num_seps = num_handles; avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt); } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_SuspendReq * * Description Suspend one or more stream endpoints. This suspends the * transfer of media packets for the streams. All stream * endpoints must previously be open and started. When the * streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to * the application via the control callback function for * each stream. * * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) { tAVDT_SCB* p_scb = NULL; tAVDT_CCB_EVT evt; uint16_t result = AVDT_SUCCESS; int i; AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles); if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { result = AVDT_BAD_PARAMS; } else { /* verify handles */ for (i = 0; i < num_handles; i++) { p_scb = avdt_scb_by_hdl(p_handles[i]); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; break; } } } if (result == AVDT_SUCCESS) { if (p_scb->p_ccb == NULL) { result = AVDT_BAD_HANDLE; } else { /* send event to ccb */ memcpy(evt.msg.multi.seid_list, p_handles, num_handles); evt.msg.multi.num_seps = num_handles; avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt); } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * 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_t AVDT_CloseReq(uint8_t handle) { tAVDT_SCB* p_scb; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; } else /* send event to scb */ { avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); 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_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg) { tAVDT_SCB* p_scb; uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); 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_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint8_t category) { tAVDT_SCB* p_scb; tAVDT_SCB_EVT evt; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__, handle, label, error_code, category); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); 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_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) { tAVDT_SCB* p_scb; uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; AVDT_TRACE_DEBUG("%s: handle=%d len=%d", __func__, handle, len); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_SecurityRsp * * Description Respond to a security request from the peer device. * This function must be called if the application receives * an AVDT_SECURITY_IND_EVT through its control callback. * (Please note that AVDTP security procedures are unrelated * to Bluetooth link level security.) * * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint8_t* p_data, uint16_t len) { tAVDT_SCB* p_scb; uint16_t result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d len=%d", __func__, handle, label, error_code, len); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == NULL) { result = AVDT_BAD_HANDLE; } /* send event to scb */ else { evt.msg.security_rsp.hdr.err_code = error_code; evt.msg.security_rsp.hdr.label = label; evt.msg.security_rsp.p_data = p_data; evt.msg.security_rsp.len = len; avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); 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_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, uint8_t m_pt, tAVDT_DATA_OPT_MASK opt) { tAVDT_SCB* p_scb; tAVDT_SCB_EVT evt; uint16_t result = AVDT_SUCCESS; AVDT_TRACE_DEBUG("%s: handle=%d timestamp=%d m_pt=0x%x opt=0x%x", __func__, handle, time_stamp, m_pt, opt); /* map handle to scb */ p_scb = avdt_scb_by_hdl(handle); if (p_scb == 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; avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_WriteReq * * 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. * 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. * * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_WriteReq(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp, uint8_t m_pt) { return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE); } /******************************************************************************* * * 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_t AVDT_ConnectReq(const RawAddress& bd_addr, uint8_t sec_mask, tAVDT_CTRL_CBACK* p_cback) { tAVDT_CCB* p_ccb = NULL; uint16_t result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; AVDT_TRACE_DEBUG("%s: sec_mask=0x%x", __func__, sec_mask); /* find channel control block for this bd addr; if none, allocate one */ p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb == NULL) { p_ccb = avdt_ccb_alloc(bd_addr); if (p_ccb == 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); } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } /******************************************************************************* * * Function AVDT_DisconnectReq * * Description This function disconnect an AVDTP signaling connection * to the peer device. When disconnected an * AVDT_DISCONNECT_IND_EVT is sent to the application via its * control callback function. * * Returns AVDT_SUCCESS if successful, otherwise error. * ******************************************************************************/ uint16_t AVDT_DisconnectReq(const RawAddress& bd_addr, tAVDT_CTRL_CBACK* p_cback) { tAVDT_CCB* p_ccb = NULL; uint16_t result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; AVDT_TRACE_WARNING("%s: address=%s", __func__, bd_addr.ToString().c_str()); /* find channel control block for this bd addr; if none, error */ p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb == NULL) { result = AVDT_BAD_PARAMS; } if (result == AVDT_SUCCESS) { /* send event to ccb */ evt.disconnect.p_cback = p_cback; avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt); } AVDT_TRACE_DEBUG("%s: address=%s result=%d", __func__, bd_addr.ToString().c_str(), result); return result; } /******************************************************************************* * * Function AVDT_GetL2CapChannel * * Description Get the L2CAP CID used by the handle. * * Returns CID if successful, otherwise 0. * ******************************************************************************/ uint16_t AVDT_GetL2CapChannel(uint8_t handle) { tAVDT_SCB* p_scb; tAVDT_CCB* p_ccb; uint8_t tcid; uint16_t lcid = 0; /* map handle to scb */ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && ((p_ccb = p_scb->p_ccb) != NULL)) { /* get tcid from type, scb */ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; } return (lcid); } /******************************************************************************* * * Function AVDT_GetSignalChannel * * Description Get the L2CAP CID used by the signal channel of the given * handle. * * Returns CID if successful, otherwise 0. * ******************************************************************************/ uint16_t AVDT_GetSignalChannel(uint8_t handle, const RawAddress& bd_addr) { tAVDT_SCB* p_scb; tAVDT_CCB* p_ccb; uint8_t tcid = 0; /* tcid is always 0 for signal channel */ uint16_t lcid = 0; /* map handle to scb */ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && ((p_ccb = p_scb->p_ccb) != NULL)) { lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; } else { p_ccb = avdt_ccb_by_bd(bd_addr); if (p_ccb != NULL) { lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; } } return (lcid); } #if (AVDT_REPORTING == TRUE) /******************************************************************************* * * Function AVDT_SendReport * * Description * * * * Returns * ******************************************************************************/ uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type, tAVDT_REPORT_DATA* p_data) { tAVDT_SCB* p_scb; uint16_t result = AVDT_BAD_PARAMS; tAVDT_TC_TBL* p_tbl; uint8_t *p, *plen, *pm1, *p_end; uint32_t ssrc; uint16_t len; AVDT_TRACE_DEBUG("%s: handle=%d type=%d", __func__, handle, type); /* map handle to scb && verify parameters */ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && (p_scb->p_ccb != NULL) && (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) || ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) || (type == AVDT_RTCP_PT_SDES))) { result = AVDT_NO_RESOURCES; /* build SR - assume fit in one packet */ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb); if (p_tbl->state == AVDT_AD_ST_OPEN) { BT_HDR* p_pkt = (BT_HDR*)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR)); p_pkt->offset = L2CAP_MIN_OFFSET; p = (uint8_t*)(p_pkt + 1) + p_pkt->offset; pm1 = p; *p++ = AVDT_MEDIA_OCTET1 | 1; *p++ = type; /* save the location for length */ plen = p; p += 2; ssrc = avdt_scb_gen_ssrc(p_scb); UINT32_TO_BE_STREAM(p, ssrc); switch (type) { case AVDT_RTCP_PT_SR: /* Sender Report */ *pm1 = AVDT_MEDIA_OCTET1; UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec); UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac); UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time); UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count); UINT32_TO_BE_STREAM(p, p_data->sr.octet_count); break; case AVDT_RTCP_PT_RR: /* Receiver Report */ *p++ = p_data->rr.frag_lost; AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost); p_data->rr.packet_lost &= 0xFFFFFF; AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost); UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost); UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd); UINT32_TO_BE_STREAM(p, p_data->rr.jitter); UINT32_TO_BE_STREAM(p, p_data->rr.lsr); UINT32_TO_BE_STREAM(p, p_data->rr.dlsr); break; case AVDT_RTCP_PT_SDES: /* Source Description */ *p++ = AVDT_RTCP_SDES_CNAME; len = strlen((char*)p_data->cname); if (len > AVDT_MAX_CNAME_SIZE) len = AVDT_MAX_CNAME_SIZE; *p++ = (uint8_t)len; strlcpy((char*)p, (char*)p_data->cname, len + 1); p += len; break; } p_end = p; len = p - pm1 - 1; UINT16_TO_BE_STREAM(plen, len); /* set the actual payload length */ p_pkt->len = p_end - p; /* send the packet */ if (L2CAP_DW_FAILED != avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt)) result = AVDT_SUCCESS; } } AVDT_TRACE_DEBUG("%s: result=%d", __func__, result); return result; } #endif /****************************************************************************** * * Function AVDT_SetTraceLevel * * Description Sets the trace level for AVDT. If 0xff is passed, the * current trace level is returned. * * Input Parameters: * new_level: The level to set the AVDT tracing to: * 0xff-returns the current setting. * 0-turns off tracing. * >= 1-Errors. * >= 2-Warnings. * >= 3-APIs. * >= 4-Events. * >= 5-Debug. * * Returns The new trace level or current trace level if * the input parameter is 0xff. * *****************************************************************************/ uint8_t AVDT_SetTraceLevel(uint8_t new_level) { if (new_level != 0xFF) avdt_cb.trace_level = new_level; return (avdt_cb.trace_level); }