diff options
Diffstat (limited to 'stack/avdt/avdt_api.c')
-rw-r--r-- | stack/avdt/avdt_api.c | 1370 |
1 files changed, 1370 insertions, 0 deletions
diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c new file mode 100644 index 0000000..02e9e57 --- /dev/null +++ b/stack/avdt/avdt_api.c @@ -0,0 +1,1370 @@ +/***************************************************************************** +** +** Name: avdt_api.c +** +** Description: This module contains API of the audio/video distribution +** transport protocol. +** +** Copyright (c) 2002-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include <string.h> +#include "data_types.h" +#include "bt_target.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "l2c_api.h" +#include "btm_api.h" +#include "btu.h" + + +#if (defined BTTRC_INCLUDED && BTTRC_INCLUDED == TRUE) +#include "bttrc_str_ids.h" +#endif + +/* Control block for AVDT */ +#if AVDT_DYNAMIC_MEMORY == FALSE +tAVDT_CB avdt_cb; +#endif + + +/******************************************************************************* +** +** 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_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) +{ + + BTTRC_AVDT_API0(AVDT_TRACE_API_REGISTER); + + /* 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(); +#if defined(AVDT_INITIAL_TRACE_LEVEL) + avdt_cb.trace_level = AVDT_INITIAL_TRACE_LEVEL; +#else + avdt_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif + + /* 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) +{ + BTTRC_AVDT_API0(AVDT_TRACE_API_DEREGISTER); + + /* deregister PSM with L2CAP */ + L2CA_Deregister(AVDT_PSM); +} + +/******************************************************************************* +** +** 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 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs) +{ + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB *p_scb; + + BTTRC_AVDT_API0(AVDT_TRACE_API_CREATESTREAM); + + /* 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 if ((p_scb = avdt_scb_alloc(p_cs)) == NULL) + { + result = AVDT_NO_RESOURCES; + } + else + { + *p_handle = avdt_scb_to_hdl(p_scb); + } + 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 AVDT_RemoveStream(UINT8 handle) +{ + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB *p_scb; + + + BTTRC_AVDT_API0(AVDT_TRACE_API_REMOVESTREAM); + + /* 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_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 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info, + UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB *p_ccb; + UINT16 result = AVDT_SUCCESS; + tAVDT_CCB_EVT evt; + + BTTRC_AVDT_API0(AVDT_TRACE_API_DISCOVER_REQ); + + /* 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; + } + } + + 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); + } + } + 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 avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP *p_evt) +{ + tAVDT_CCB *p_ccb = NULL; + UINT16 result = AVDT_SUCCESS; + + /* verify SEID */ + if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX)) + { + AVDT_TRACE_ERROR1("seid: %d", p_evt->single.seid); + result = AVDT_BAD_PARAMS; + } + /* 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; + } + } + + 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); + } + } + 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 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB_API_GETCAP getcap; + + BTTRC_AVDT_API1(AVDT_TRACE_API_GETCAP_REQ, BTTRC_PARAM_UINT8, seid); + + getcap.single.seid = seid; + getcap.single.sig_id = AVDT_SIG_GETCAP; + getcap.p_cfg = p_cfg; + getcap.p_cback = p_cback; + return avdt_get_cap_req (bd_addr, &getcap); +} + +/******************************************************************************* +** +** 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 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB_API_GETCAP getcap; + + BTTRC_AVDT_API1(AVDT_TRACE_API_GET_ALLCAP_REQ, BTTRC_PARAM_UINT8, seid); + + getcap.single.seid = seid; + getcap.single.sig_id = AVDT_SIG_GET_ALLCAP; + getcap.p_cfg = p_cfg; + getcap.p_cback = p_cback; + return avdt_get_cap_req (bd_addr, &getcap); +} + +/******************************************************************************* +** +** 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; + + BTTRC_AVDT_API0(AVDT_TRACE_API_DELAY_REPORT); + + /* 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_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_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_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 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles) +{ + tAVDT_SCB *p_scb = NULL; + tAVDT_CCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + int i; + + BTTRC_AVDT_API0(AVDT_TRACE_API_START_REQ); + + if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) + { + result = AVDT_BAD_PARAMS; + } + else + { + /* verify handles */ + for (i = 0; i < num_handles; i++) + { + if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == 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); + } + } + 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 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles) +{ + tAVDT_SCB *p_scb = NULL; + tAVDT_CCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + int i; + + BTTRC_AVDT_API0(AVDT_TRACE_API_SUSPEND_REQ); + + if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) + { + result = AVDT_BAD_PARAMS; + } + else + { + /* verify handles */ + for (i = 0; i < num_handles; i++) + { + if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == 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); + } + } + + 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 AVDT_CloseReq(UINT8 handle) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + + BTTRC_AVDT_API0(AVDT_TRACE_API_CLOSE_REQ); + + /* 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_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; + + BTTRC_AVDT_API0(AVDT_TRACE_API_RECONFIG_REQ); + + /* 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_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; + + BTTRC_AVDT_API0(AVDT_TRACE_API_RECONFIG_RSP); + + /* 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_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; + + BTTRC_AVDT_API0(AVDT_TRACE_API_SECURITY_REQ); + + /* 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_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 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, + UINT8 *p_data, UINT16 len) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + BTTRC_AVDT_API0(AVDT_TRACE_API_SECURITY_RSP); + + /* 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.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); + } + 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 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +{ + tAVDT_SCB *p_scb; + tAVDT_SCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + + BTTRC_AVDT_API0(AVDT_TRACE_API_WRITE_REQ); + + /* 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; +#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_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; + + BTTRC_AVDT_API0(AVDT_TRACE_API_CONNECT_REQ); + + /* 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_WARNING0("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_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 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB *p_ccb = NULL; + UINT16 result = AVDT_SUCCESS; + tAVDT_CCB_EVT evt; + + BTTRC_AVDT_API0(AVDT_TRACE_API_DISCONNECT_REQ); + + + /* find channel control block for this bd addr; if none, error */ + if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == 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); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_GetL2CapChannel +** +** Description Get the L2CAP CID used by the handle. +** +** Returns CID if successful, otherwise 0. +** +*******************************************************************************/ +UINT16 AVDT_GetL2CapChannel(UINT8 handle) +{ + tAVDT_SCB *p_scb; + tAVDT_CCB *p_ccb; + UINT8 tcid; + UINT16 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; + } + + BTTRC_AVDT_API1(AVDT_TRACE_API_GET_L2CAP_CHAN, BTTRC_PARAM_UINT16, 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 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr) +{ + tAVDT_SCB *p_scb; + tAVDT_CCB *p_ccb; + UINT8 tcid = 0; /* tcid is always 0 for signal channel */ + UINT16 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 if ((p_ccb = avdt_ccb_by_bd(bd_addr)) != NULL) + { + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; + } + + BTTRC_AVDT_API1(AVDT_TRACE_API_GET_SIGNAL_CHAN, BTTRC_PARAM_UINT16, lcid); + + return (lcid); +} + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** 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; +} +#endif + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function AVDT_SetMediaBuf +** +** Description Assigns buffer for media packets or forbids using of assigned +** buffer if argument p_buf is NULL. This function can only +** be called if the stream is a SNK. +** +** AVDTP uses this buffer to reassemble fragmented media packets. +** When AVDTP receives a complete media packet, it calls the +** p_media_cback assigned by AVDT_CreateStream(). +** This function can be called during callback to assign a +** different buffer for next media packet or can leave the current +** buffer for next packet. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +AVDT_API extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + + BTTRC_AVDT_API0(AVDT_TRACE_API_SET_MEDIABUF); + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) + { + result = AVDT_BAD_HANDLE; + } + else + { + if(p_buf && p_scb->cs.p_media_cback == NULL) + result = AVDT_NO_RESOURCES; + else + { + p_scb->p_media_buf = p_buf; + p_scb->media_buf_len = buf_len; + } + } + + return result; +} +#endif + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function AVDT_SendReport +** +** Description +** +** +** +** Returns +** +*******************************************************************************/ +UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_BAD_PARAMS; + BT_HDR *p_pkt; + tAVDT_TC_TBL *p_tbl; + UINT8 *p, *plen, *pm1, *p_end; +#if AVDT_MULTIPLEXING == TRUE + UINT8 *p_al, u; +#endif + UINT32 ssrc; + UINT16 len; + + BTTRC_AVDT_API0(AVDT_TRACE_API_SEND_REPORT); + + /* 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) && + (p_pkt = (BT_HDR *)GKI_getbuf(p_tbl->peer_mtu)) != NULL) + { + p_pkt->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; +#if AVDT_MULTIPLEXING == TRUE + if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX) + { + /* Adaptation Layer header later */ + p_al = p; + p += 2; + } +#endif + 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_API1("packet_lost: %d", p_data->rr.packet_lost); + p_data->rr.packet_lost &= 0xFFFFFF; + AVDT_TRACE_API1("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)len; + BCM_STRNCPY_S((char *)p, len+1, (char *)p_data->cname, len+1); + p += len; + break; + } + p_end = p; + len = p - pm1 - 1; + UINT16_TO_BE_STREAM(plen, len); + +#if AVDT_MULTIPLEXING == TRUE + if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX) + { + /* Adaptation Layer header */ + p = p_al; + len++; + UINT16_TO_BE_STREAM(p_al, len ); + /* TSID, no-fragment bit and coding of length(9-bit length field) */ + u = *p; + *p = (p_scb->curr_cfg.mux_tsid_report<<3) | AVDT_ALH_LCODE_9BITM0; + if(u) + *p |= AVDT_ALH_LCODE_9BITM1; + } +#endif + + /* 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; + } + } + + 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 AVDT_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + avdt_cb.trace_level = new_level; + + return (avdt_cb.trace_level); +} + |