--- /dev/null
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * ommon API for the Advanced Audio Distribution Profile (A2DP)
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "sdpdefs.h"
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "avdt_api.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if A2D_DYNAMIC_MEMORY == FALSE
+tA2D_CB a2d_cb;
+#endif
+
+
+/******************************************************************************
+**
+** Function a2d_sdp_cback
+**
+** Description This is the SDP callback function used by A2D_FindService.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves various parameters
+** from the record. When it is finished it calls the
+** application callback function.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void a2d_sdp_cback(UINT16 status)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ BOOLEAN found = FALSE;
+ tA2D_Service a2d_svc;
+ tSDP_PROTOCOL_ELEM elem;
+
+ A2D_TRACE_API("a2d_sdp_cback status: %d", status);
+
+ if (status == SDP_SUCCESS)
+ {
+ /* loop through all records we found */
+ do
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(a2d_cb.find.p_db,
+ a2d_cb.find.service_uuid, p_rec)) == NULL)
+ {
+ break;
+ }
+ memset(&a2d_svc, 0, sizeof(tA2D_Service));
+
+ /* get service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SERVICE_NAME)) != NULL)
+ {
+ a2d_svc.p_service_name = (char *) p_attr->attr_value.v.array;
+ a2d_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get provider name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_PROVIDER_NAME)) != NULL)
+ {
+ a2d_svc.p_provider_name = (char *) p_attr->attr_value.v.array;
+ a2d_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get supported features */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec,
+ ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+ {
+ a2d_svc.features = p_attr->attr_value.v.u16;
+ }
+
+ /* get AVDTP version */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem))
+ {
+ a2d_svc.avdt_version = elem.params[0];
+ A2D_TRACE_DEBUG("avdt_version: 0x%x", a2d_svc.avdt_version);
+ }
+
+ /* we've got everything, we're done */
+ found = TRUE;
+ break;
+
+ } while (TRUE);
+ }
+
+ a2d_cb.find.service_uuid = 0;
+ /* return info from sdp record in app callback function */
+ if (a2d_cb.find.p_cback != NULL)
+ {
+ (*a2d_cb.find.p_cback)(found, &a2d_svc);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function a2d_set_avdt_sdp_ver
+**
+** Description This function allows the script wrapper to change the
+** avdt version of a2dp.
+**
+** Returns None
+**
+*******************************************************************************/
+void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver)
+{
+ a2d_cb.avdt_sdp_ver = avdt_sdp_ver;
+}
+
+/******************************************************************************
+**
+** Function A2D_AddRecord
+**
+** Description This function is called by a server application to add
+** SRC or SNK information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+**
+** features: Profile supported features.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
+ UINT16 features, UINT32 sdp_handle)
+{
+ UINT16 browse_list[1];
+ BOOLEAN result = TRUE;
+ UINT8 temp[8];
+ UINT8 *p;
+ tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS];
+
+ A2D_TRACE_API("A2D_AddRecord uuid: %x", service_uuid);
+
+ if( (sdp_handle == 0) ||
+ (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) )
+ return A2D_INVALID_PARAMS;
+
+ /* add service class id list */
+ result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
+
+ memset((void*) proto_list, 0 , A2D_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol descriptor list */
+ proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_list[0].num_params = 1;
+ proto_list[0].params[0] = AVDT_PSM;
+ proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;
+ proto_list[1].num_params = 1;
+ proto_list[1].params[0] = a2d_cb.avdt_sdp_ver;
+
+ result &= SDP_AddProtocolList(sdp_handle, A2D_NUM_PROTO_ELEMS, proto_list);
+
+ /* add profile descriptor list */
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2D_VERSION);
+
+ /* add supported feature */
+ if (features != 0)
+ {
+ p = temp;
+ UINT16_TO_BE_STREAM(p, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+ }
+
+ /* add provider name */
+ if (p_provider_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+
+ return (result ? A2D_SUCCESS : A2D_FAIL);
+}
+
+/******************************************************************************
+**
+** Function A2D_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve SRC or SNK SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** A2D_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: Pointer to the information to initialize
+** the discovery database.
+**
+** p_cback: Pointer to the A2D_FindService()
+** callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_BUSY if discovery is already in progress.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback)
+{
+ tSDP_UUID uuid_list;
+ BOOLEAN result = TRUE;
+ UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_PROVIDER_NAME};
+
+ A2D_TRACE_API("A2D_FindService uuid: %x", service_uuid);
+ if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
+ p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+ return A2D_INVALID_PARAMS;
+
+ if( a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
+ a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
+ return A2D_BUSY;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if(p_db->p_attrs == NULL || p_db->num_attr == 0)
+ {
+ p_db->p_attrs = a2d_attr_list;
+ p_db->num_attr = A2D_NUM_ATTR;
+ }
+
+ result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
+ p_db->p_attrs);
+
+ if (result == TRUE)
+ {
+ /* store service_uuid and discovery db pointer */
+ a2d_cb.find.p_db = p_db->p_db;
+ a2d_cb.find.service_uuid = service_uuid;
+ a2d_cb.find.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, a2d_sdp_cback);
+ if(FALSE == result)
+ {
+ a2d_cb.find.service_uuid = 0;
+ }
+ }
+
+ return (result ? A2D_SUCCESS : A2D_FAIL);
+}
+
+/******************************************************************************
+**
+** Function A2D_SetTraceLevel
+**
+** Description Sets the trace level for A2D. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the A2D 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 A2D_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ a2d_cb.trace_level = new_level;
+
+ return (a2d_cb.trace_level);
+}
+
+/******************************************************************************
+** Function A2D_BitsSet
+**
+** Description Check the given num for the number of bits set
+** Returns A2D_SET_ONE_BIT, if one and only one bit is set
+** A2D_SET_ZERO_BIT, if all bits clear
+** A2D_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+UINT8 A2D_BitsSet(UINT8 num)
+{
+ UINT8 count;
+ BOOLEAN res;
+ if(num == 0)
+ res = A2D_SET_ZERO_BIT;
+ else
+ {
+ count = (num & (num - 1));
+ res = ((count==0)?A2D_SET_ONE_BIT:A2D_SET_MULTL_BIT);
+ }
+ return res;
+}
+
+/*******************************************************************************
+**
+** Function A2D_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void A2D_Init(void)
+{
+ memset(&a2d_cb, 0, sizeof(tA2D_CB));
+
+ a2d_cb.avdt_sdp_ver = AVDT_VERSION;
+
+#if defined(A2D_INITIAL_TRACE_LEVEL)
+ a2d_cb.trace_level = A2D_INITIAL_TRACE_LEVEL;
+#else
+ a2d_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse SBC Codec Information Element
+ * and Media Payload.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_sbc.h"
+#include "bt_utils.h"
+
+/*************************************************************************************************
+ * SBC descramble code
+ * Purpose: to tie the SBC code with BTE/mobile stack code,
+ * especially for the case when the SBC is ported into a third-party Multimedia chip
+ *
+ * Algorithm:
+ * init process: all counters reset to 0,
+ * calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2)
+ * scramble side: the init process happens every time SBC_Encoder_Init() is called.
+ * descramble side: it would be nice to know if he "init" process has happened.
+ * alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100).
+ *
+ * scramble process:
+ * The CRC byte:
+ * Every SBC frame has a frame header.
+ * The 1st byte is the sync word and the following 2 bytes are about the stream format.
+ * They are supposed to be "constant" within a "song"
+ * The 4th byte is the CRC byte. The CRC byte is bound to be random.
+ * Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index".
+ *
+ * SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame.
+ *
+ * The "use" bit is any bit in SBC_PRTC_USE_MASK is set.
+ * If set, SBC uses the "index" from the current frame.
+ * If not set, SBC uses the "index" from the previous frame or 0.
+ *
+ * index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index
+ *
+ * if(index > 0)
+ * {
+ * p = &u8frame[base_index];
+ * if((index&1)&&(u16PacketLength > (base_index+index*2)))
+ * {
+ * // odd index: swap 2 bytes
+ * tmp = p[index];
+ * p[index] = p[index*2];
+ * p[index*2] = tmp;
+ * }
+ * else
+ * {
+ * // even index: shift by 3
+ * tmp = (p[index] >> 3) + (p[index] << 5);
+ * p[index] = tmp;
+ * }
+ * }
+ * //else index is 0. The frame stays unaltered
+ *
+ */
+#define A2D_SBC_SYNC_WORD 0x9C
+#define A2D_SBC_CRC_IDX 3
+#define A2D_SBC_USE_MASK 0x64
+#define A2D_SBC_SYNC_MASK 0x10
+#define A2D_SBC_CIDX 0
+#define A2D_SBC_LIDX 1
+#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */
+#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */
+
+#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2))
+
+typedef struct
+{
+ UINT8 use;
+ UINT8 idx;
+} tA2D_SBC_FR_CB;
+
+typedef struct
+{
+ tA2D_SBC_FR_CB fr[2];
+ UINT8 index;
+ UINT8 base;
+} tA2D_SBC_DS_CB;
+
+static tA2D_SBC_DS_CB a2d_sbc_ds_cb;
+/*int a2d_count = 0;*/
+/******************************************************************************
+**
+** Function A2D_SbcChkFrInit
+**
+** Description check if need to init the descramble control block.
+**
+** Returns nothing.
+******************************************************************************/
+void A2D_SbcChkFrInit(UINT8 *p_pkt)
+{
+ UINT8 fmt;
+ UINT8 num_chnl = 1;
+ UINT8 num_subband = 4;
+
+ if((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0)
+ {
+ a2d_cb.use_desc = TRUE;
+ fmt = p_pkt[1];
+ p_pkt[0] |= A2D_SBC_SYNC_MASK;
+ memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB));
+ if(fmt & A2D_SBC_CH_M_BITS)
+ num_chnl = 2;
+ if(fmt & A2D_SBC_SUBBAND_BIT)
+ num_subband = 8;
+ a2d_sbc_ds_cb.base = 6 + num_chnl*num_subband/2;
+ /*printf("base: %d\n", a2d_sbc_ds_cb.base);
+ a2d_count = 0;*/
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_SbcDescramble
+**
+** Description descramble the packet.
+**
+** Returns nothing.
+******************************************************************************/
+void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len)
+{
+ tA2D_SBC_FR_CB *p_cur, *p_last;
+ UINT32 idx, tmp, tmp2;
+
+ if(a2d_cb.use_desc)
+ {
+ /* c2l */
+ p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX];
+ p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX];
+ p_last->idx = p_cur->idx;
+ p_last->use = p_cur->use;
+ /* getc */
+ p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK;
+ p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]);
+ a2d_sbc_ds_cb.index = (p_cur->use)?A2D_SBC_CIDX:A2D_SBC_LIDX;
+ /*
+ printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ",
+ a2d_count++,
+ A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK,
+ (p_cur->use)?"cur":"lst", p_cur->idx);
+ */
+ /* descramble */
+ idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx;
+ if(idx > 0)
+ {
+ p_pkt = &p_pkt[a2d_sbc_ds_cb.base];
+ if((idx&1) && (len > (a2d_sbc_ds_cb.base+(idx<<1))))
+ {
+ tmp2 = (idx<<1);
+ tmp = p_pkt[idx];
+ p_pkt[idx] = p_pkt[tmp2];
+ p_pkt[tmp2] = tmp;
+ /*
+ printf("tmp2: %02d, len: %d, idx: %d\n",
+ tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx);
+ */
+ }
+ else
+ {
+ tmp2 = p_pkt[idx];
+ tmp = (tmp2>>3)+(tmp2<<5);
+ p_pkt[idx] = (UINT8)tmp;
+ /*
+ printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n",
+ (UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx,
+ (a2d_sbc_ds_cb.base+(idx<<1)));
+ */
+ }
+ }
+ /*
+ else
+ {
+ printf("!!!!\n");
+ }
+ */
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_BldSbcInfo
+**
+** Description This function is called by an application to build
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The SBC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, UINT8 *p_result)
+{
+ tA2D_STATUS status;
+
+ if( p_ie == NULL || p_result == NULL ||
+ (p_ie->samp_freq & ~A2D_SBC_IE_SAMP_FREQ_MSK) ||
+ (p_ie->ch_mode & ~A2D_SBC_IE_CH_MD_MSK) ||
+ (p_ie->block_len & ~A2D_SBC_IE_BLOCKS_MSK) ||
+ (p_ie->num_subbands & ~A2D_SBC_IE_SUBBAND_MSK) ||
+ (p_ie->alloc_mthd & ~A2D_SBC_IE_ALLOC_MD_MSK) ||
+ (p_ie->max_bitpool < p_ie->min_bitpool) ||
+ (p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL) ||
+ (p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL) )
+ {
+ /* if any unused bit is set */
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_SBC_INFO_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_MEDIA_CT_SBC;
+
+ /* Media Codec Specific Information Element */
+ *p_result++ = p_ie->samp_freq | p_ie->ch_mode;
+
+ *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_mthd;
+
+ *p_result++ = p_ie->min_bitpool;
+ *p_result = p_ie->max_bitpool;
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcInfo
+**
+** Description This function is called by an application to parse
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: The SBC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+
+ if( p_ie == NULL || p_info == NULL)
+ status = A2D_INVALID_PARAMS;
+ else
+ {
+ losc = *p_info++;
+ p_info++;
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if(losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC)
+ status = A2D_WRONG_CODEC;
+ else
+ {
+ p_info++;
+ p_ie->samp_freq = *p_info & A2D_SBC_IE_SAMP_FREQ_MSK;
+ p_ie->ch_mode = *p_info & A2D_SBC_IE_CH_MD_MSK;
+ p_info++;
+ p_ie->block_len = *p_info & A2D_SBC_IE_BLOCKS_MSK;
+ p_ie->num_subbands = *p_info & A2D_SBC_IE_SUBBAND_MSK;
+ p_ie->alloc_mthd = *p_info & A2D_SBC_IE_ALLOC_MD_MSK;
+ p_info++;
+ p_ie->min_bitpool = *p_info++;
+ p_ie->max_bitpool = *p_info;
+ status = A2D_SUCCESS;
+ if(p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL )
+ status = A2D_BAD_MIN_BITPOOL;
+
+ if(p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL ||
+ p_ie->max_bitpool < p_ie->min_bitpool)
+ status = A2D_BAD_MAX_BITPOOL;
+
+ if(for_caps == FALSE)
+ {
+ if(A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if(A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CH_MODE;
+ if(A2D_BitsSet(p_ie->block_len) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_BLOCK_LEN;
+ if(A2D_BitsSet(p_ie->num_subbands) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SUBBANDS;
+ if(A2D_BitsSet(p_ie->alloc_mthd) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_ALLOC_MTHD;
+ }
+ }
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_BldSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Output Parameters:
+** p_dst: the resulting media payload header byte sequence.
+**
+** Returns void.
+******************************************************************************/
+void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, BOOLEAN last, UINT8 num)
+{
+ if(p_dst)
+ {
+ *p_dst = 0;
+ if(frag)
+ *p_dst |= A2D_SBC_HDR_F_MSK;
+ if(start)
+ *p_dst |= A2D_SBC_HDR_S_MSK;
+ if(last)
+ *p_dst |= A2D_SBC_HDR_L_MSK;
+ *p_dst |= (A2D_SBC_HDR_NUM_MSK & num);
+ }
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** p_src: the byte sequence to parse..
+**
+** Output Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Returns void.
+******************************************************************************/
+void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, BOOLEAN *p_start, BOOLEAN *p_last, UINT8 *p_num)
+{
+ if(p_src && p_frag && p_start && p_last && p_num)
+ {
+ *p_frag = (*p_src & A2D_SBC_HDR_F_MSK) ? TRUE: FALSE;
+ *p_start= (*p_src & A2D_SBC_HDR_S_MSK) ? TRUE: FALSE;
+ *p_last = (*p_src & A2D_SBC_HDR_L_MSK) ? TRUE: FALSE;
+ *p_num = (*p_src & A2D_SBC_HDR_NUM_MSK);
+ }
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * 2DP internal header file
+ *
+ ******************************************************************************/
+#ifndef A2D_INT_H
+#define A2D_INT_H
+
+#include "a2d_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define A2D_VERSION 0x0102
+
+/* Number of attributes in A2D SDP record. */
+#define A2D_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define A2D_NUM_PROTO_ELEMS 2
+
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+
+/* Control block used by A2D_FindService(). */
+typedef struct
+{
+ tA2D_FIND_CBACK *p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT16 service_uuid; /* service UUID of search */
+} tA2D_FIND_CB;
+
+typedef struct
+{
+ tA2D_FIND_CB find; /* find service control block */
+ UINT8 trace_level;
+ BOOLEAN use_desc;
+ UINT16 avdt_sdp_ver; /* AVDTP version */
+} tA2D_CB;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if A2D_DYNAMIC_MEMORY == FALSE
+extern tA2D_CB a2d_cb;
+#else
+extern tA2D_CB *a2d_cb_ptr;
+#define a2d_cb (*a2d_cb_ptr)
+#endif
+
+/* Used only for conformance testing */
+extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_INT_H */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 control transport protocol.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gki.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "avct_api.h"
+#include "avct_int.h"
+
+/* Control block for AVCT */
+#if AVCT_DYNAMIC_MEMORY == FALSE
+tAVCT_CB avct_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function AVCT_Register
+**
+** Description This is the system level registration function for the
+** AVCTP protocol. This function initializes AVCTP and
+** prepares the protocol stack for its use. This function
+** must be called once by the system or platform using AVCTP
+** before the other functions of the API an be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask)
+{
+ UNUSED(mtu_br);
+
+ AVCT_TRACE_API("AVCT_Register");
+
+ /* register PSM with L2CAP */
+ L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl);
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+
+ /* initialize AVCTP data structures */
+ memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ /* Include the browsing channel which uses eFCR */
+ L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
+
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
+ BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
+
+ if (mtu_br < AVCT_MIN_BROWSE_MTU)
+ mtu_br = AVCT_MIN_BROWSE_MTU;
+ avct_cb.mtu_br = mtu_br;
+#endif
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+ avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+ avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+
+ if (mtu < AVCT_MIN_CONTROL_MTU)
+ mtu = AVCT_MIN_CONTROL_MTU;
+ /* store mtu */
+ avct_cb.mtu = mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_Deregister
+**
+** Description This function is called to deregister use AVCTP protocol.
+** It is called when AVCTP is no longer being used by any
+** application in the system. Before this function can be
+** called, all connections must be removed with
+** AVCT_RemoveConn().
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Deregister(void)
+{
+ AVCT_TRACE_API("AVCT_Deregister");
+
+ /* deregister PSM with L2CAP */
+ L2CA_Deregister(AVCT_PSM);
+}
+
+/*******************************************************************************
+**
+** Function AVCT_CreateConn
+**
+** Description Create an AVCTP connection. There are two types of
+** connections, initiator and acceptor, as determined by
+** the p_cc->role parameter. When this function is called to
+** create an initiator connection, an AVCTP connection to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
+
+ /* Allocate ccb; if no ccbs, return failure */
+ if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL)
+ {
+ result = AVCT_NO_RESOURCES;
+ }
+ else
+ {
+ /* get handle */
+ *p_handle = avct_ccb_to_idx(p_ccb);
+
+ /* if initiator connection */
+ if (p_cc->role == AVCT_INT)
+ {
+ /* find link; if none allocate a new one */
+ if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL)
+ {
+ if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL)
+ {
+ /* no link resources; free ccb as well */
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_NO_RESOURCES;
+ }
+ }
+ /* check if PID already in use */
+ else if (avct_lcb_has_pid(p_lcb, p_cc->pid))
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_PID_IN_USE;
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ /* bind lcb to ccb */
+ p_ccb->p_lcb = p_lcb;
+ AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
+ avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveConn
+**
+** Description Remove an AVCTP connection. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_RemoveConn(UINT8 handle)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+
+ AVCT_TRACE_API("AVCT_RemoveConn");
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ /* if connection not bound to lcb, dealloc */
+ else if (p_ccb->p_lcb == NULL)
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ }
+ /* send unbind event to lcb */
+ else
+ {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_CreateBrowse
+**
+** Description Create an AVCTP Browse channel. There are two types of
+** connections, initiator and acceptor, as determined by
+** the role parameter. When this function is called to
+** create an initiator connection, the Browse channel to
+** the peer device is initiated if one does not already exist.
+** If an acceptor connection is created, the connection waits
+** passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_CreateBrowse (UINT8 handle, UINT8 role)
+{
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_BCB *p_bcb;
+ int index;
+
+ AVCT_TRACE_API("AVCT_CreateBrowse: %d", role);
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ return AVCT_BAD_HANDLE;
+ }
+ else
+ {
+ /* mark this CCB as supporting browsing channel */
+ if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+ {
+ p_ccb->allocated |= AVCT_ALOC_BCB;
+ }
+ }
+
+ /* if initiator connection */
+ if (role == AVCT_INT)
+ {
+ /* the link control block must exist before this function is called as INT. */
+ if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0))
+ {
+ result = AVCT_NOT_OPEN;
+ }
+ else
+ {
+ /* find link; if none allocate a new one */
+ index = p_ccb->p_lcb->allocated;
+ if (index > AVCT_NUM_LINKS)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ else
+ {
+ p_bcb = &avct_cb.bcb[index - 1];
+ p_bcb->allocated = index;
+ }
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ /* bind bcb to ccb */
+ p_ccb->p_bcb = p_bcb;
+ AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ }
+
+ return result;
+#else
+ UNUSED(handle);
+ UNUSED(role);
+ return AVCT_NO_RESOURCES;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function AVCT_RemoveBrowse
+**
+** Description Remove an AVCTP Browse channel. This function is called when
+** the application is no longer using a connection. If this
+** is the last connection to a peer the L2CAP channel for AVCTP
+** will be closed.
+**
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_RemoveBrowse (UINT8 handle)
+{
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+
+ AVCT_TRACE_API("AVCT_RemoveBrowse");
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ }
+ else if (p_ccb->p_bcb != NULL)
+ /* send unbind event to bcb */
+ {
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ }
+ return result;
+#else
+ UNUSED(handle);
+ return AVCT_NO_RESOURCES;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function AVCT_GetBrowseMtu
+**
+** Description Get the peer_mtu for the AVCTP Browse channel of the given
+** connection.
+**
+** Returns the peer browsing channel MTU.
+**
+*******************************************************************************/
+UINT16 AVCT_GetBrowseMtu (UINT8 handle)
+{
+ UINT16 peer_mtu = AVCT_MIN_BROWSE_MTU;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ tAVCT_CCB *p_ccb;
+
+ if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL)
+ {
+ peer_mtu = p_ccb->p_bcb->peer_mtu;
+ }
+#else
+ UNUSED(handle);
+#endif
+ return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_GetPeerMtu
+**
+** Description Get the peer_mtu for the AVCTP channel of the given
+** connection.
+**
+** Returns the peer MTU size.
+**
+*******************************************************************************/
+UINT16 AVCT_GetPeerMtu (UINT8 handle)
+{
+ UINT16 peer_mtu = L2CAP_DEFAULT_MTU;
+ tAVCT_CCB *p_ccb;
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) != NULL)
+ {
+ if (p_ccb->p_lcb)
+ {
+ peer_mtu = p_ccb->p_lcb->peer_mtu;
+ }
+ }
+
+ return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function AVCT_MsgReq
+**
+** Description Send an AVCTP message to a peer device. In calling
+** AVCT_MsgReq(), the application should keep track of the
+** congestion state of AVCTP as communicated with events
+** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
+** application calls AVCT_MsgReq() when AVCTP is congested
+** the message may be discarded. The application may make its
+** first call to AVCT_MsgReq() after it receives an
+** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
+** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+**
+** p_msg->layer_specific must be set to
+** AVCT_DATA_CTRL for control channel traffic;
+** AVCT_DATA_BROWSE for for browse channel traffic.
+**
+** Returns AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg)
+{
+ UINT16 result = AVCT_SUCCESS;
+ tAVCT_CCB *p_ccb;
+ tAVCT_UL_MSG ul_msg;
+
+ AVCT_TRACE_API("AVCT_MsgReq");
+
+ /* verify p_msg parameter */
+ if (p_msg == NULL)
+ {
+ return AVCT_NO_RESOURCES;
+ }
+ AVCT_TRACE_API("len: %d", p_msg->len);
+
+ /* map handle to ccb */
+ if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+ {
+ result = AVCT_BAD_HANDLE;
+ GKI_freebuf(p_msg);
+ }
+ /* verify channel is bound to link */
+ else if (p_ccb->p_lcb == NULL)
+ {
+ result = AVCT_NOT_OPEN;
+ GKI_freebuf(p_msg);
+ }
+
+ if (result == AVCT_SUCCESS)
+ {
+ ul_msg.p_buf = p_msg;
+ ul_msg.p_ccb = p_ccb;
+ ul_msg.label = label;
+ ul_msg.cr = cr;
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ /* send msg event to bcb */
+ if (p_msg->layer_specific == AVCT_DATA_BROWSE)
+ {
+ if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+ {
+ /* BCB channel is not open and not allocated */
+ result = AVCT_BAD_HANDLE;
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ }
+ }
+ /* send msg event to lcb */
+ else
+#endif
+ {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ }
+ }
+ return result;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 functions which operate on the AVCTP connection
+ * control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+
+/*******************************************************************************
+**
+** Function avct_ccb_alloc
+**
+** Description Allocate a connection control block; copy parameters to ccb.
+**
+**
+** Returns pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (!p_ccb->allocated)
+ {
+ p_ccb->allocated = AVCT_ALOC_LCB;
+ memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
+ AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_CONN)
+ {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_dealloc
+**
+** Description Deallocate a connection control block and call application
+** callback.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr)
+{
+ tAVCT_CTRL_CBACK *p_cback = p_ccb->cc.p_ctrl_cback;
+
+ AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ if(p_ccb->p_bcb == NULL)
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
+ else
+ {
+ /* control channel is down, but the browsing channel is still connected 0 disconnect it now */
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+ p_ccb->p_lcb = NULL;
+ }
+#else
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
+#endif
+
+ if (event != AVCT_NO_EVT)
+ {
+ (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_to_idx
+**
+** Description Given a pointer to an ccb, return its index.
+**
+**
+** Returns Index of ccb.
+**
+*******************************************************************************/
+UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb)
+{
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_ccb - avct_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function avct_ccb_by_idx
+**
+** Description Return ccb pointer based on ccb index (or handle).
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_by_idx(UINT8 idx)
+{
+ tAVCT_CCB *p_ccb;
+
+ /* verify index */
+ if (idx < AVCT_NUM_CONN)
+ {
+ p_ccb = &avct_cb.ccb[idx];
+
+ /* verify ccb is allocated */
+ if (!p_ccb->allocated)
+ {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("ccb %d not allocated", idx);
+ }
+ }
+ else
+ {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 AVCTP module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE (1<<1)
+
+/* callback function declarations */
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_appl = {
+ avct_l2c_connect_ind_cback,
+ avct_l2c_connect_cfm_cback,
+ NULL,
+ avct_l2c_config_ind_cback,
+ avct_l2c_config_cfm_cback,
+ avct_l2c_disconnect_ind_cback,
+ avct_l2c_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_data_ind_cback,
+ avct_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function avct_l2c_is_passive
+**
+** Description check is the CCB associated with the given LCB was created
+** as passive
+**
+** Returns TRUE, if the given LCB is created as AVCT_PASSIVE
+**
+*******************************************************************************/
+static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
+{
+ BOOLEAN is_passive = FALSE;
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
+ if (p_ccb->cc.control & AVCT_PASSIVE)
+ {
+ is_passive = TRUE;
+ break;
+ }
+ }
+ }
+ return is_passive;
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 result = L2CAP_CONN_OK;
+ tL2CAP_CFG_INFO cfg;
+ UNUSED(psm);
+
+ /* do we already have a channel for this peer? */
+ if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
+ {
+ /* no, allocate lcb */
+ if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL)
+ {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ }
+ /* else we already have a channel for this peer */
+ else
+ {
+ if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN))
+ {
+ /* this LCB included CT role - reject */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* TG role only - accept the connection from CT. move the channel ID to the conflict list */
+ p_lcb->conflict_lcid = p_lcb->ch_lcid;
+ AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+ }
+ }
+
+ if(p_lcb)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
+ lcid, result, p_lcb->ch_state);
+ }
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store LCID */
+ p_lcb->ch_lcid = lcid;
+
+ /* transition to configuration state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+ }
+
+#if (BT_USE_TRACES == TRUE)
+ if(p_lcb)
+ AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_LCB *p_lcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
+ lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* set channel state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+ }
+ /* else failure */
+ else
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+ if (p_lcb->conflict_lcid == lcid)
+ p_lcb->conflict_lcid = 0;
+ else
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+ }
+ else if (p_lcb->conflict_lcid == lcid)
+ {
+ /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
+ AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
+ if (result == L2CAP_CONN_OK)
+ {
+ /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ p_lcb->conflict_lcid = 0;
+ }
+ AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_LCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_lcb->ch_state, p_cfg->result);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /* else failure */
+ else
+ {
+ AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
+ /* store result value */
+ p_lcb->ch_result = p_cfg->result;
+
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_LCB *p_lcb;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_lcb->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+ {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 result = AVCT_RESULT_FAIL;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_LCB *p_lcb;
+ UINT16 res;
+
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_lcb->ch_state, result);
+ /* result value may be previously stored */
+ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+ p_lcb->ch_result = 0;
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+ AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVCT_LCB *p_lcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+ }
+ else /* prevent buffer leak */
+ {
+ AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
+ GKI_freebuf(p_buf);
+ }
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 the link control state machine and functions which
+ * operate on the link control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "gki.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+
+#if BT_TRACE_VERBOSE == TRUE
+
+/* verbose state strings for trace */
+const char * const avct_lcb_st_str[] = {
+ "LCB_IDLE_ST",
+ "LCB_OPENING_ST",
+ "LCB_OPEN_ST",
+ "LCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avct_lcb_evt_str[] = {
+ "UL_BIND_EVT",
+ "UL_UNBIND_EVT",
+ "UL_MSG_EVT",
+ "INT_CLOSE_EVT",
+ "LL_OPEN_EVT",
+ "LL_CLOSE_EVT",
+ "LL_MSG_EVT",
+ "LL_CONG_EVT"
+};
+
+#endif
+
+/* lcb state machine states */
+enum {
+ AVCT_LCB_IDLE_ST,
+ AVCT_LCB_OPENING_ST,
+ AVCT_LCB_OPEN_ST,
+ AVCT_LCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVCT_LCB_CHNL_OPEN,
+ AVCT_LCB_CHNL_DISC,
+ AVCT_LCB_SEND_MSG,
+ AVCT_LCB_OPEN_IND,
+ AVCT_LCB_OPEN_FAIL,
+ AVCT_LCB_CLOSE_IND,
+ AVCT_LCB_CLOSE_CFM,
+ AVCT_LCB_MSG_IND,
+ AVCT_LCB_CONG_IND,
+ AVCT_LCB_BIND_CONN,
+ AVCT_LCB_BIND_FAIL,
+ AVCT_LCB_UNBIND_DISC,
+ AVCT_LCB_CHK_DISC,
+ AVCT_LCB_DISCARD_MSG,
+ AVCT_LCB_DEALLOC,
+ AVCT_LCB_FREE_MSG_IND,
+ AVCT_LCB_NUM_ACTIONS
+};
+
+#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
+
+/* action function list */
+const tAVCT_LCB_ACTION avct_lcb_action[] = {
+ avct_lcb_chnl_open,
+ avct_lcb_chnl_disc,
+ avct_lcb_send_msg,
+ avct_lcb_open_ind,
+ avct_lcb_open_fail,
+ avct_lcb_close_ind,
+ avct_lcb_close_cfm,
+ avct_lcb_msg_ind,
+ avct_lcb_cong_ind,
+ avct_lcb_bind_conn,
+ avct_lcb_bind_fail,
+ avct_lcb_unbind_disc,
+ avct_lcb_chk_disc,
+ avct_lcb_discard_msg,
+ avct_lcb_dealloc,
+ avct_lcb_free_msg_ind
+};
+
+/* state table information */
+#define AVCT_LCB_ACTIONS 2 /* number of actions */
+#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
+#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* UL_BIND_EVT */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* UL_UNBIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
+
+/* state table */
+const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
+ avct_lcb_st_idle,
+ avct_lcb_st_opening,
+ avct_lcb_st_open,
+ avct_lcb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function avct_lcb_event
+**
+** Description State machine event handling function for lcb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_LCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if BT_TRACE_VERBOSE == TRUE
+ AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
+#else
+ AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_lcb->state];
+
+ /* set next state */
+ p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ {
+ (*avct_lcb_action[action])(p_lcb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_bcb_event
+**
+** Description State machine event handling function for lcb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_LCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if BT_TRACE_VERBOSE == TRUE
+ AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
+#else
+ AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_bcb->state];
+
+ /* set next state */
+ p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ {
+ (*avct_bcb_action[action])(p_bcb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avct_lcb_by_bd
+**
+** Description This lookup function finds the lcb for a BD address.
+**
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ /* if allocated lcb has matching lcb */
+ if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* if no lcb found */
+ p_lcb = NULL;
+
+ AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_alloc
+**
+** Description Allocate a link control block.
+**
+**
+** Returns pointer to the lcb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ if (!p_lcb->allocated)
+ {
+ p_lcb->allocated = (UINT8)(i + 1);
+ memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
+ AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING("Out of lcbs");
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_dealloc
+**
+** Description Deallocate a link control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ BOOLEAN found = FALSE;
+ int i;
+ UNUSED(p_data);
+
+ AVCT_TRACE_DEBUG("avct_lcb_dealloc %d", p_lcb->allocated);
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ if (p_ccb->p_lcb == p_lcb)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_dealloc now");
+
+ /* clear reassembled msg buffer if in use */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ }
+ memset(p_lcb, 0, sizeof(tAVCT_LCB));
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_by_lcid
+**
+** Description Find the LCB associated with the L2CAP LCID
+**
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
+{
+ tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+ {
+ if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS)
+ {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
+ }
+
+ return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_has_pid
+**
+** Description See if any ccbs on this lcb have a particular pid.
+**
+**
+** Returns Pointer to CCB if PID found, NULL otherwise.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
+ {
+ return p_ccb;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_last_ccb
+**
+** Description See if given ccb is only one on the lcb.
+**
+**
+** Returns TRUE if ccb is last, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ AVCT_TRACE_WARNING("avct_lcb_last_ccb");
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x",
+ i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 action functions of the link control state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "gki.h"
+#include "btm_api.h"
+
+/* packet header length lookup table */
+const UINT8 avct_lcb_pkt_type_len[] = {
+ AVCT_HDR_LEN_SINGLE,
+ AVCT_HDR_LEN_START,
+ AVCT_HDR_LEN_CONT,
+ AVCT_HDR_LEN_END
+};
+
+/*******************************************************************************
+**
+** Function avct_lcb_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+ UINT16 buf_len;
+
+ /* parse the message header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_PRS_PKT_TYPE(p, pkt_type);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ p_lcb->p_rx_msg = NULL;
+ AVCT_TRACE_WARNING("Got single during reassembly");
+ }
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVCT_PKT_TYPE_START)
+ {
+ /* if reassembly in progress drop message and process new start */
+ if (p_lcb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_lcb->p_rx_msg);
+ AVCT_TRACE_WARNING("Got start during reassembly");
+ }
+ /* Allocate bigger buffer for reassembly. As lower layers are
+ * not aware of possible packet size after reassembly they
+ * would have allocated smaller buffer.
+ */
+ p_lcb->p_rx_msg = (BT_HDR*)GKI_getbuf(GKI_MAX_BUF_SIZE);
+ if (p_lcb->p_rx_msg == NULL)
+ {
+ AVCT_TRACE_ERROR ("Cannot alloc buffer for reassembly !!");
+ GKI_freebuf(p_buf);
+ }
+ else
+ {
+ memcpy (p_lcb->p_rx_msg, p_buf,
+ sizeof(BT_HDR) + p_buf->offset + p_buf->len);
+ /* Free original buffer */
+ GKI_freebuf(p_buf);
+
+ /* update p to point to new buffer */
+ p = (UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_lcb->p_rx_msg->len -= 1;
+ }
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else
+ {
+ /* if no reassembly in progress drop message */
+ if (p_lcb->p_rx_msg == NULL)
+ {
+ GKI_freebuf(p_buf);
+ AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* get size of buffer holding assembled message */
+ buf_len = GKI_get_buf_size(p_lcb->p_rx_msg) - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVCT_HDR_LEN_CONT;
+ p_buf->len -= AVCT_HDR_LEN_CONT;
+
+ /* verify length */
+ if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len)
+ {
+ /* won't fit; free everything */
+ GKI_freebuf(p_lcb->p_rx_msg);
+ p_lcb->p_rx_msg = NULL;
+ GKI_freebuf(p_buf);
+ p_ret = NULL;
+ AVCT_TRACE_WARNING("Fragmented message to big!");
+ }
+ else
+ {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
+ (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVCT_PKT_TYPE_END)
+ {
+ p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = p_lcb->p_rx_msg;
+ p_lcb->p_rx_msg = NULL;
+ }
+ else
+ {
+ p_lcb->p_rx_msg->offset += p_buf->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+
+/*******************************************************************************
+**
+** Function avct_lcb_chnl_open
+**
+** Description Open L2CAP channel to peer
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 result = AVCT_RESULT_FAIL;
+ UNUSED(p_data);
+
+ BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
+ /* call l2cap connect req */
+ p_lcb->ch_state = AVCT_CH_CONN;
+ if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0)
+ {
+ /* if connect req failed, send ourselves close event */
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_unbind_disc
+**
+** Description Deallocate ccb and call callback with disconnect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UNUSED(p_lcb);
+
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_open_ind
+**
+** Description Handle an LL_OPEN event. For each allocated ccb already
+** bound to this lcb, send a connect event. For each
+** unbound ccb with a new PID, bind that ccb to this lcb and
+** send a connect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ BOOLEAN bind = FALSE;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ /* if bound to this lcb send connect confirm event */
+ if (p_ccb->p_lcb == p_lcb)
+ {
+ bind = TRUE;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ /* if unbound acceptor and lcb doesn't already have a ccb for this PID */
+ else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+ (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
+ {
+ /* bind ccb to lcb and send connect ind event */
+ bind = TRUE;
+ p_ccb->p_lcb = p_lcb;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ }
+ }
+
+ /* if no ccbs bound to this lcb, disconnect */
+ if (bind == FALSE)
+ {
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_open_fail
+**
+** Description L2CAP channel open attempt failed. Deallocate any ccbs
+** on this lcb and send connect confirm event with failure.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT,
+ p_data->result, p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_close_ind
+**
+** Description L2CAP channel closed by peer. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UNUSED(p_data);
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ if (p_ccb->cc.role == AVCT_INT)
+ {
+ avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ else
+ {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT,
+ 0, p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_close_cfm
+**
+** Description L2CAP channel closed by us. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ /* if this ccb initiated close send disconnect cfm otherwise ind */
+ if (p_ccb->ch_close)
+ {
+ p_ccb->ch_close = FALSE;
+ event = AVCT_DISCONNECT_CFM_EVT;
+ }
+ else
+ {
+ event = AVCT_DISCONNECT_IND_EVT;
+ }
+
+ if (p_ccb->cc.role == AVCT_INT)
+ {
+ avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
+ }
+ else
+ {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event,
+ p_data->result, p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_bind_conn
+**
+** Description Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ p_data->p_ccb->p_lcb = p_lcb;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_chk_disc
+**
+** Description A ccb wants to close; if it is the last ccb on this lcb,
+** close channel. Otherwise just deallocate and call
+** callback.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_WARNING("avct_lcb_chk_disc");
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ avct_close_bcb(p_lcb, p_data);
+#endif
+ if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb))
+ {
+ AVCT_TRACE_WARNING("closing");
+ p_data->p_ccb->ch_close = TRUE;
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+ else
+ {
+ AVCT_TRACE_WARNING("dealloc ccb");
+ avct_lcb_unbind_disc(p_lcb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_chnl_disc
+**
+** Description Disconnect L2CAP channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ L2CA_DisconnectReq(p_lcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_bind_fail
+**
+** Description Deallocate ccb and call callback with connect event
+** with failure result.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UNUSED(p_lcb);
+
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_cong_ind
+**
+** Description Handle congestion indication from L2CAP.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ UINT8 event;
+ BT_HDR *p_buf;
+
+ /* set event */
+ event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+ p_lcb->cong = p_data->cong;
+ if (p_lcb->cong == FALSE && GKI_getfirst(&p_lcb->tx_q))
+ {
+ while ( !p_lcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_lcb->tx_q)) != NULL)
+ {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_lcb->cong = TRUE;
+ }
+ }
+ }
+
+ /* send event to all ccbs on this lcb */
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+ {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_discard_msg
+**
+** Description Discard a message sent in from the API.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UNUSED(p_lcb);
+
+ AVCT_TRACE_WARNING("Dropping msg");
+
+ GKI_freebuf(p_data->ul_msg.p_buf);
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_send_msg
+**
+** Description Build and send an AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 hdr_len;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 nosp = 0; /* number of subsequent packets */
+ UINT16 temp;
+ UINT16 buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+
+
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+
+ /* initialize packet type and other stuff */
+ if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+ {
+ pkt_type = AVCT_PKT_TYPE_SINGLE;
+ }
+ else
+ {
+ pkt_type = AVCT_PKT_TYPE_START;
+ temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
+ nosp = temp / (p_lcb->peer_mtu - 1) + 1;
+ if ( (temp % (p_lcb->peer_mtu - 1)) != 0)
+ nosp++;
+ }
+
+ /* while we haven't sent all packets */
+ while (curr_msg_len != 0)
+ {
+ /* set header len */
+ hdr_len = avct_lcb_pkt_type_len[pkt_type];
+
+ /* if remaining msg must be fragmented */
+ if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len))
+ {
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getbuf(buf_size)) == NULL)
+ {
+ /* whoops; free original msg buf and bail */
+ AVCT_TRACE_ERROR ("avct_lcb_send_msg cannot alloc buffer!!");
+ GKI_freebuf(p_data->ul_msg.p_buf);
+ break;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_lcb->peer_mtu - hdr_len;
+
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len);
+
+ p_data->ul_msg.p_buf->offset += p_buf->len;
+ p_data->ul_msg.p_buf->len -= p_buf->len;
+ }
+ else
+ {
+ p_buf = p_data->ul_msg.p_buf;
+ }
+
+ curr_msg_len -= p_buf->len;
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ if (pkt_type == AVCT_PKT_TYPE_START)
+ {
+ UINT8_TO_STREAM(p, nosp);
+ }
+ if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE))
+ {
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+ }
+
+ if (p_lcb->cong == TRUE)
+ {
+ GKI_enqueue (&p_lcb->tx_q, p_buf);
+ }
+
+ /* send message to L2CAP */
+ else
+ {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_lcb->cong = TRUE;
+ }
+ }
+
+ /* update pkt type for next packet */
+ if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END))
+ {
+ pkt_type = AVCT_PKT_TYPE_CONT;
+ }
+ else
+ {
+ pkt_type = AVCT_PKT_TYPE_END;
+ }
+ }
+ AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d", GKI_queue_length(&p_lcb->tx_q));
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_free_msg_ind
+**
+** Description Discard an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UNUSED(p_lcb);
+
+ if (p_data)
+ GKI_freebuf(p_data->p_buf);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avct_lcb_msg_ind
+**
+** Description Handle an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT8 label, type, cr_ipid;
+ UINT16 pid;
+ tAVCT_CCB *p_ccb;
+ BT_HDR *p_buf;
+
+ /* this p_buf is to be reported through p_msg_cback. The layer_specific
+ * needs to be set properly to indicate that it is received through
+ * control channel */
+ p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
+
+ /* reassemble message; if no message available (we received a fragment) return */
+ if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL)
+ {
+ return;
+ }
+
+ p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse header byte */
+ AVCT_PRS_HDR(p, label, type, cr_ipid);
+ UNUSED(type);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID)
+ {
+ AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+ GKI_freebuf(p_data->p_buf);
+ return;
+ }
+
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+ {
+ /* PID found; send msg up, adjust bt hdr and call msg callback */
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+ }
+ else
+ {
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+ GKI_freebuf(p_data->p_buf);
+
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD)
+ {
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL)
+ {
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+ }
+ }
+ }
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 contains constants definitions and other information from the AVCTP
+ * specification. This file is intended for use internal to AVCT only.
+ *
+ ******************************************************************************/
+#ifndef AVCT_DEFS_H
+#define AVCT_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* packet type */
+#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
+#define AVCT_PKT_TYPE_START 1 /* start packet */
+#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
+#define AVCT_PKT_TYPE_END 3 /* end packet */
+
+/* header lengths for different packet types */
+#define AVCT_HDR_LEN_SINGLE 3
+#define AVCT_HDR_LEN_START 4
+#define AVCT_HDR_LEN_CONT 1
+#define AVCT_HDR_LEN_END 1
+
+/* invalid cr+ipid value */
+#define AVCT_CR_IPID_INVALID 1
+
+/*****************************************************************************
+** message parsing and building macros
+*****************************************************************************/
+
+#define AVCT_BLD_HDR(p, label, type, cr_ipid) \
+ *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
+
+#define AVCT_PRS_HDR(p, label, type, cr_ipid) \
+ label = *(p) >> 4; \
+ type = (*(p) >> 2) & 3; \
+ cr_ipid = *(p)++ & 3;
+
+#define AVCT_PRS_PKT_TYPE(p, type) \
+ type = (*(p) >> 2) & 3;
+
+#endif /* AVCT_DEFS_H */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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 file contains interfaces which are internal to AVCTP.
+ *
+ ******************************************************************************/
+#ifndef AVCT_INT_H
+#define AVCT_INT_H
+
+#include "gki.h"
+#include "avct_api.h"
+#include "avct_defs.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* lcb state machine events */
+enum {
+ AVCT_LCB_UL_BIND_EVT,
+ AVCT_LCB_UL_UNBIND_EVT,
+ AVCT_LCB_UL_MSG_EVT,
+ AVCT_LCB_INT_CLOSE_EVT,
+ AVCT_LCB_LL_OPEN_EVT,
+ AVCT_LCB_LL_CLOSE_EVT,
+ AVCT_LCB_LL_MSG_EVT,
+ AVCT_LCB_LL_CONG_EVT
+};
+
+
+/* "states" used for L2CAP channel */
+#define AVCT_CH_IDLE 0 /* No connection */
+#define AVCT_CH_CONN 1 /* Waiting for connection confirm */
+#define AVCT_CH_CFG 2 /* Waiting for configuration complete */
+#define AVCT_CH_OPEN 3 /* Channel opened */
+
+/* "no event" indicator used by ccb dealloc */
+#define AVCT_NO_EVT 0xFF
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+} tAVCT_SCB;
+
+/* link control block type */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+ BT_HDR *p_rx_msg; /* Message being reassembled */
+ UINT16 conflict_lcid; /* L2CAP channel LCID */
+ BD_ADDR peer_addr; /* BD address of peer */
+ BUFFER_Q tx_q; /* Transmit data buffer queue */
+ BOOLEAN cong; /* TRUE, if congested */
+} tAVCT_LCB;
+
+/* browse control block type */
+typedef struct {
+ UINT16 peer_mtu; /* peer l2c mtu */
+ UINT16 ch_result; /* L2CAP connection result value */
+ UINT16 ch_lcid; /* L2CAP channel LCID */
+ UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
+ UINT8 state; /* The state machine state */
+ UINT8 ch_state; /* L2CAP channel state */
+ UINT8 ch_flags; /* L2CAP configuration flags */
+ BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
+ UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
+} tAVCT_BCB;
+
+#define AVCT_ALOC_LCB 0x01
+#define AVCT_ALOC_BCB 0x02
+/* connection control block */
+typedef struct {
+ tAVCT_CC cc; /* parameters from connection creation */
+ tAVCT_LCB *p_lcb; /* Associated LCB */
+ tAVCT_BCB *p_bcb; /* associated BCB */
+ BOOLEAN ch_close; /* Whether CCB initiated channel close */
+ UINT8 allocated; /* Whether LCB/BCB is allocated */
+} tAVCT_CCB;
+
+/* data type associated with UL_MSG_EVT */
+typedef struct {
+ BT_HDR *p_buf;
+ tAVCT_CCB *p_ccb;
+ UINT8 label;
+ UINT8 cr;
+} tAVCT_UL_MSG;
+
+/* union associated with lcb state machine events */
+typedef union {
+ tAVCT_UL_MSG ul_msg;
+ BT_HDR *p_buf;
+ tAVCT_CCB *p_ccb;
+ UINT16 result;
+ BOOLEAN cong;
+ UINT8 err_code;
+} tAVCT_LCB_EVT;
+
+/* Control block for AVCT */
+typedef struct {
+ tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */
+ tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */
+ tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */
+ UINT16 mtu; /* our L2CAP MTU */
+ UINT16 mtu_br; /* our L2CAP MTU for the Browsing channel */
+ UINT8 trace_level; /* trace level */
+} tAVCT_CB;
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* LCB function declarations */
+extern void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+extern void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data);
+extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
+extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
+extern BOOLEAN avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
+extern tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid);
+#endif
+extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
+extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr);
+extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid);
+extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid);
+extern BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last);
+
+/* LCB action functions */
+extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+
+/* BCB action functions */
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern const tAVCT_BCB_ACTION avct_bcb_action[];
+extern const UINT8 avct_lcb_pkt_type_len[];
+extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
+#endif
+
+/* CCB function declarations */
+extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc);
+extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr);
+extern UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb);
+extern tAVCT_CCB *avct_ccb_by_idx(UINT8 idx);
+
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Main control block */
+#if AVCT_DYNAMIC_MEMORY == FALSE
+extern tAVCT_CB avct_cb;
+#else
+extern tAVCT_CB *avct_cb_ptr;
+#define avct_cb (*avct_cb_ptr)
+#endif
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avct_l2c_appl;
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVCT_INT_H */
--- /dev/null
+/******************************************************************************
+ *
+ * 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 the AVDTP adaption layer.
+ *
+ ******************************************************************************/
+
+// #include <assert.h>
+#include "bt_trace.h"
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_type_to_tcid
+**
+** Description Derives the TCID from the channel type and SCB.
+**
+**
+** Returns TCID value.
+**
+*******************************************************************************/
+UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb)
+{
+ UINT8 scb_idx;
+
+ if (type == AVDT_CHAN_SIG)
+ {
+ return 0;
+ }
+ else
+ {
+ scb_idx = avdt_scb_to_hdl(p_scb) - 1;
+ /*
+ AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
+ */
+ return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tcid_to_type
+**
+** Description Derives the channel type from the TCID.
+**
+**
+** Returns Channel type value.
+**
+*******************************************************************************/
+static UINT8 avdt_ad_tcid_to_type(UINT8 tcid)
+{
+ UINT8 type;
+
+ if (tcid == 0)
+ {
+ type = AVDT_CHAN_SIG;
+ }
+ else
+ {
+ /* tcid translates to type based on number of channels, as follows:
+ ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
+ ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
+ ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
+ */
+ type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
+ }
+ AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type);
+ return type;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_init
+**
+** Description Initialize adaption layer.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_init(void)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
+
+ /* make sure the peer_mtu is a valid value */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_st
+**
+** Description Find adaption layer transport channel table entry matching
+** the given state.
+**
+**
+** Returns Pointer to matching entry. For control channel it returns
+** the matching entry. For media or other it returns the
+** first matching entry (there could be more than one).
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ UINT8 ccb_idx;
+
+ if (p_ccb == NULL)
+ {
+ /* resending security req */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ /* must be AVDT_CHAN_SIG - tcid always zero */
+ if ((p_tbl->tcid == 0) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (type == AVDT_CHAN_SIG)
+ {
+ /* if control channel, tcid always zero */
+ if ((p_tbl->tcid == 0) &&
+ (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* if other channel, tcid is always > zero */
+ if ((p_tbl->tcid > 0) &&
+ (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state))
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ /* if nothing found return null */
+ if (i == AVDT_NUM_TC_TBL)
+ {
+ p_tbl = NULL;
+ }
+
+ return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_lcid
+**
+** Description Find adaption layer transport channel table entry by LCID.
+**
+**
+** Returns Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid)
+{
+ UINT8 idx;
+
+ idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < AVDT_NUM_TC_TBL)
+ {
+ return &avdt_cb.ad.tc_tbl[idx];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_by_type
+**
+** Description This function retrieves the transport channel table entry
+** for a particular channel.
+**
+**
+** Returns Pointer to transport channel table entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+ UINT8 tcid;
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+ UINT8 ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx))
+ {
+ break;
+ }
+ }
+
+ assert(i != AVDT_NUM_TC_TBL);
+
+ return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_alloc
+**
+** Description Allocate an entry in the traffic channel table.
+**
+**
+** Returns Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
+{
+ int i;
+ tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+ {
+ if (p_tbl->state == AVDT_AD_ST_UNUSED)
+ {
+ break;
+ }
+ }
+
+ /* sanity check */
+ assert(i != AVDT_NUM_TC_TBL);
+
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags = 0;
+ p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
+ p_tbl->state = AVDT_AD_ST_IDLE;
+ return p_tbl;
+
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_tbl_to_idx
+**
+** Description Convert a transport channel table entry to an index.
+**
+**
+** Returns Index value.
+**
+*******************************************************************************/
+UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
+{
+ AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_tc_close_ind
+**
+** Description This function is called by the L2CAP interface when the
+** L2CAP channel is closed. It looks up the CCB or SCB for
+** the channel and sends it a close event. The reason
+** parameter is the same value passed by the L2CAP
+** callback function.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_TC_CLOSE close;
+ UNUSED(reason);
+
+ close.old_tc_state = p_tbl->state;
+ /* clear avdt_ad_tc_tbl entry */
+ p_tbl->state = AVDT_AD_ST_UNUSED;
+ p_tbl->cfg_flags = 0;
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+ AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d",
+ p_tbl->tcid, close.old_tc_state);
+ /* if signaling channel, notify ccb that channel open */
+ if (p_tbl->tcid == 0)
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
+ }
+ /* if media or other channel, notify scb that channel close */
+ 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)
+ {
+ close.tcid = p_tbl->tcid;
+ close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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_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_ad_tc_data_ind
+**
+** Description This function is called by the L2CAP interface layer when
+** incoming data is received from L2CAP. It looks up the CCB
+** or SCB for the channel and routes the data accordingly.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_SCB *p_scb;
+
+ /* store type (media, recovery, reporting) */
+ p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
+
+
+ /* if signaling channel, handle control message */
+ if (p_tbl->tcid == 0)
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_msg_ind(p_ccb, p_buf);
+ }
+ /* if media or other channel, send event to scb */
+ else
+ {
+ 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_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
+ }
+ else
+ {
+ GKI_freebuf(p_buf);
+ AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_write_req
+**
+** Description This function is called by a CCB or SCB to send data to a
+** transport channel. It looks up the LCID of the channel
+** based on the type, CCB, and SCB (if present). Then it
+** passes the data to L2CA_DataWrite().
+**
+**
+** Returns AVDT_AD_SUCCESS, if data accepted, else FALSE
+** AVDT_AD_CONGESTED, if data accepted and the channel is congested
+** AVDT_AD_FAILED, if error
+**
+*******************************************************************************/
+UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
+{
+ UINT8 tcid;
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+
+ return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ad_open_req
+**
+** Description This function is called by a CCB or SCB to open a transport
+** channel. This function allocates and initializes a
+** transport channel table entry. The channel can be opened
+** in two roles: as an initiator or acceptor. When opened
+** as an initiator the function will start an L2CAP connection.
+** When opened as an acceptor the function simply configures
+** the table entry to listen for an incoming channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
+{
+ tAVDT_TC_TBL *p_tbl;
+ UINT16 lcid;
+
+ if((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL)
+ {
+ AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
+ return;
+ }
+
+
+ p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
+ AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
+ type, role, p_tbl->tcid);
+
+ if (type == AVDT_CHAN_SIG)
+ {
+ /* if signaling, get mtu from registration control block */
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ }
+ else
+ {
+ /* otherwise get mtu from scb */
+ p_tbl->my_mtu = p_scb->cs.mtu;
+ p_tbl->my_flush_to = p_scb->cs.flush_to;
+
+ /* also set scb_hdl in rt_tbl */
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
+ AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+ avdt_scb_to_hdl(p_scb));
+ }
+
+ /* if we're acceptor, we're done; just sit back and listen */
+ if (role == AVDT_ACP)
+ {
+ p_tbl->state = AVDT_AD_ST_ACP;
+ }
+ /* else we're inititator, start the L2CAP connection */
+ else
+ {
+ p_tbl->state = AVDT_AD_ST_CONN;
+
+ /* call l2cap connect req */
+ if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)
+ {
+ /* if connect req ok, store tcid in lcid table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
+ (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
+
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+ AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+ lcid);
+ }
+ else
+ {
+ /* if connect req failed, call avdt_ad_tc_close_ind() */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ad_close_req
+**
+** Description This function is called by a CCB or SCB to close a
+** transport channel. The function looks up the LCID for the
+** channel and calls L2CA_DisconnectReq().
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+ UINT8 tcid;
+ tAVDT_TC_TBL *p_tbl;
+
+ p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
+ AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
+
+ switch(p_tbl->state)
+ {
+ case AVDT_AD_ST_UNUSED:
+ /* probably for reporting */
+ break;
+ case AVDT_AD_ST_ACP:
+ /* if we're listening on this channel, send ourselves a close ind */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ break;
+ default:
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ /* call l2cap disconnect req */
+ L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
+ }
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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 <string.h>
+#include "bt_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"
+
+
+/* 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)
+{
+ /* 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);
+}
+
+/*******************************************************************************
+**
+** Function AVDT_SINK_Activate
+**
+** Description Activate SEP of A2DP Sink. In Use parameter is adjusted.
+** In Use will be made false in case of activation. A2DP SRC
+** will receive in_use as false and can open A2DP Sink
+** connection
+**
+** Returns void.
+**
+*******************************************************************************/
+void AVDT_SINK_Activate()
+{
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+ AVDT_TRACE_DEBUG("AVDT_SINK_Activate");
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
+ {
+ AVDT_TRACE_DEBUG("AVDT_SINK_Activate found scb");
+ p_scb->sink_activated = TRUE;
+ /* update in_use */
+ p_scb->in_use = FALSE;
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function AVDT_SINK_Deactivate
+**
+** Description Deactivate SEP of A2DP Sink. In Use parameter is adjusted.
+** In Use will be made TRUE in case of activation. A2DP SRC
+** will receive in_use as true and will not open A2DP Sink
+** connection
+**
+** Returns void.
+**
+*******************************************************************************/
+void AVDT_SINK_Deactivate()
+{
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+ AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate");
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
+ {
+ AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate, found scb");
+ p_scb->sink_activated = FALSE;
+ /* update in_use */
+ p_scb->in_use = TRUE;
+ break;
+ }
+ }
+}
+
+void AVDT_AbortReq(UINT8 handle)
+{
+ AVDT_TRACE_ERROR("%s", __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", __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 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs)
+{
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_SCB *p_scb;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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_ERROR("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;
+
+ 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;
+
+ 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ 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;
+
+ 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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_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_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)
+{
+ 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 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, tAVDT_CTRL_CBACK *p_cback)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ UINT16 result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ /* find channel control block for this bd addr; if none, allocate one */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+ else if (p_ccb->ll_opened == FALSE)
+ {
+ AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening");
+
+ /* ccb was already allocated for the incoming signalling. */
+ result = AVDT_BUSY;
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* send event to ccb */
+ evt.connect.p_cback = p_cback;
+ evt.connect.sec_mask = sec_mask;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_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;
+
+ /* 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;
+ }
+
+ 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;
+ }
+
+ 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.
+**
+*******************************************************************************/
+extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len,
+ UINT32 time_stamp, UINT8 m_pt, UINT8 marker)
+{
+
+ tAVDT_SCB *p_scb;
+ tAVDT_SCB_EVT evt;
+ UINT16 result = AVDT_SUCCESS;
+
+ do
+ {
+ /* check length of media frame */
+ if(data_len > AVDT_MAX_MEDIA_SIZE)
+ {
+ result = AVDT_BAD_PARAMS;
+ break;
+ }
+ /* map handle to scb */
+ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+ {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ AVDT_TRACE_WARNING("mux_tsid_media:%d", p_scb->curr_cfg.mux_tsid_media);
+
+ if (p_scb->p_pkt != NULL
+ || p_scb->p_ccb == NULL
+ || !GKI_queue_is_empty(&p_scb->frag_q)
+ || p_scb->frag_off != 0
+ || p_scb->curr_cfg.mux_tsid_media == 0)
+ {
+ result = AVDT_ERR_BAD_STATE;
+ AVDT_TRACE_WARNING("p_scb->p_pkt=%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_WARNING("AVDT_WriteDataReq out of GKI buffers");
+ result = AVDT_ERR_RESOURCE;
+ break;
+ }
+ evt.apiwrite.data_len = data_len;
+ evt.apiwrite.p_data = p_data;
+
+ /* process the fragments queue */
+ evt.apiwrite.time_stamp = time_stamp;
+ evt.apiwrite.m_pt = m_pt | (marker<<7);
+ avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
+ } while (0);
+
+#if (BT_USE_TRACES == TRUE)
+ if(result != AVDT_SUCCESS)
+ {
+ AVDT_TRACE_WARNING("*** AVDT_WriteDataReq failed result=%d",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.
+**
+*******************************************************************************/
+extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len)
+{
+ 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
+ {
+ 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=NULL, u;
+#endif
+ UINT32 ssrc;
+ UINT16 len;
+
+ /* 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_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)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);
+}
--- /dev/null
+/******************************************************************************
+ *
+ * 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 the channel control block state machine and
+ * functions which operate on the channel control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if AVDT_DEBUG == TRUE
+
+/* verbose state strings for trace */
+const char * const avdt_ccb_st_str[] = {
+ "CCB_IDLE_ST",
+ "CCB_OPENING_ST",
+ "CCB_OPEN_ST",
+ "CCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_ccb_evt_str[] = {
+ "API_DISCOVER_REQ_EVT",
+ "API_GETCAP_REQ_EVT",
+ "API_START_REQ_EVT",
+ "API_SUSPEND_REQ_EVT",
+ "API_DISCOVER_RSP_EVT",
+ "API_GETCAP_RSP_EVT",
+ "API_START_RSP_EVT",
+ "API_SUSPEND_RSP_EVT",
+ "API_CONNECT_REQ_EVT",
+ "API_DISCONNECT_REQ_EVT",
+ "MSG_DISCOVER_CMD_EVT",
+ "MSG_GETCAP_CMD_EVT",
+ "MSG_START_CMD_EVT",
+ "MSG_SUSPEND_CMD_EVT",
+ "MSG_DISCOVER_RSP_EVT",
+ "MSG_GETCAP_RSP_EVT",
+ "MSG_START_RSP_EVT",
+ "MSG_SUSPEND_RSP_EVT",
+ "RCVRSP_EVT",
+ "SENDMSG_EVT",
+ "RET_TOUT_EVT",
+ "RSP_TOUT_EVT",
+ "IDLE_TOUT_EVT",
+ "UL_OPEN_EVT",
+ "UL_CLOSE_EVT",
+ "LL_OPEN_EVT",
+ "LL_CLOSE_EVT",
+ "LL_CONG_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_CCB_ACTION avdt_ccb_action[] = {
+ avdt_ccb_chan_open,
+ avdt_ccb_chan_close,
+ avdt_ccb_chk_close,
+ avdt_ccb_hdl_discover_cmd,
+ avdt_ccb_hdl_discover_rsp,
+ avdt_ccb_hdl_getcap_cmd,
+ avdt_ccb_hdl_getcap_rsp,
+ avdt_ccb_hdl_start_cmd,
+ avdt_ccb_hdl_start_rsp,
+ avdt_ccb_hdl_suspend_cmd,
+ avdt_ccb_hdl_suspend_rsp,
+ avdt_ccb_snd_discover_cmd,
+ avdt_ccb_snd_discover_rsp,
+ avdt_ccb_snd_getcap_cmd,
+ avdt_ccb_snd_getcap_rsp,
+ avdt_ccb_snd_start_cmd,
+ avdt_ccb_snd_start_rsp,
+ avdt_ccb_snd_suspend_cmd,
+ avdt_ccb_snd_suspend_rsp,
+ avdt_ccb_clear_cmds,
+ avdt_ccb_cmd_fail,
+ avdt_ccb_free_cmd,
+ avdt_ccb_cong_state,
+ avdt_ccb_ret_cmd,
+ avdt_ccb_snd_cmd,
+ avdt_ccb_snd_msg,
+ avdt_ccb_set_reconn,
+ avdt_ccb_clr_reconn,
+ avdt_ccb_chk_reconn,
+ avdt_ccb_chk_timer,
+ avdt_ccb_set_conn,
+ avdt_ccb_set_disconn,
+ avdt_ccb_do_disconn,
+ avdt_ccb_ll_closed,
+ avdt_ccb_ll_opened,
+ avdt_ccb_dealloc
+};
+
+/* state table information */
+#define AVDT_CCB_ACTIONS 2 /* number of actions */
+#define AVDT_CCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_CCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_CHAN_OPEN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_LL_OPENED, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_SND_CMD, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_SND_START_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_SND_SUSPEND_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_SND_DISCOVER_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_SND_GETCAP_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_SND_START_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_SND_SUSPEND_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_HDL_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_HDL_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_HDL_START_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_HDL_SUSPEND_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_OPEN_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_FREE_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_SND_MSG, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_RET_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_CMD_FAIL, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_CHK_TIMER, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_SND_MSG, AVDT_CCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CLOSING_ST},
+/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SET_CONN, AVDT_CCB_CLOSING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_SET_DISCONN, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* UL_CLOSE_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+/* LL_CLOSE_EVT */ {AVDT_CCB_CHK_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS];
+
+/* state table */
+const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = {
+ avdt_ccb_st_idle,
+ avdt_ccb_st_opening,
+ avdt_ccb_st_open,
+ avdt_ccb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function avdt_ccb_init
+**
+** Description Initialize channel control block module.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_init(void)
+{
+ memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
+ avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_event
+**
+** Description State machine event handling function for ccb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if AVDT_DEBUG == TRUE
+ AVDT_TRACE_EVENT("CCB ccb=%d event=%s state=%s", avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state]);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avdt_ccb_st_tbl[p_ccb->state];
+
+ /* set next state */
+ if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE]) {
+ p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE];
+ }
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_CCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVDT_CCB_IGNORE)
+ {
+ (*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_ccb_by_bd
+**
+** Description This lookup function finds the ccb for a BD address.
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr)
+{
+ tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+ {
+ /* if allocated ccb has matching ccb */
+ if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN)))
+ {
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS)
+ {
+ /* if no ccb found */
+ p_ccb = NULL;
+
+ AVDT_TRACE_DEBUG("No ccb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_alloc
+**
+** Description Allocate a channel control block.
+**
+**
+** Returns pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr)
+{
+ tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+ {
+ if (!p_ccb->allocated)
+ {
+ p_ccb->allocated = TRUE;
+ memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
+ GKI_init_q(&p_ccb->cmd_q);
+ GKI_init_q(&p_ccb->rsp_q);
+ p_ccb->timer_entry.param = (UINT32) p_ccb;
+ AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS)
+ {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_dealloc
+**
+** Description Deallocate a stream control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
+ btu_stop_timer(&p_ccb->timer_entry);
+ memset(p_ccb, 0, sizeof(tAVDT_CCB));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_to_idx
+**
+** Description Given a pointer to an ccb, return its index.
+**
+**
+** Returns Index of ccb.
+**
+*******************************************************************************/
+UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb)
+{
+ /* use array arithmetic to determine index */
+ return (UINT8) (p_ccb - avdt_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_by_idx
+**
+** Description Return ccb pointer based on ccb index.
+**
+**
+** Returns pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx)
+{
+ tAVDT_CCB *p_ccb;
+
+ /* verify index */
+ if (idx < AVDT_NUM_LINKS)
+ {
+ p_ccb = &avdt_cb.ccb[idx];
+ }
+ else
+ {
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2006-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 the action functions associated with the channel
+ * control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clear_ccb
+**
+** Description This function clears out certain buffers, queues, and
+** other data elements of a ccb.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ /* clear certain ccb variables */
+ p_ccb->cong = FALSE;
+ p_ccb->ret_count = 0;
+
+ /* free message being fragmented */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_msg);
+ p_ccb->p_curr_msg = NULL;
+ }
+
+ /* free message being reassembled */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ }
+
+ /* clear out response queue */
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_open
+**
+** Description This function calls avdt_ad_open_req() to
+** initiate a signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
+ avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_close
+**
+** Description This function calls avdt_ad_close_req() to close a
+** signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ /* close the transport channel used by this CCB */
+ avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_close
+**
+** Description This function checks for active streams on this CCB.
+** If there are none, it starts an idle timer.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UNUSED(p_data);
+
+ /* see if there are any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ break;
+ }
+ }
+
+ /* if no active scbs start idle timer */
+ if (i == AVDT_NUM_SEPS)
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_IDLE, avdt_cb.rcb.idle_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_cmd
+**
+** Description This function is called when a discover command is
+** received from the peer. It gathers up the stream
+** information for all allocated streams and initiates
+** sending of a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+
+ p_data->msg.discover_rsp.p_sep_info = sep_info;
+ p_data->msg.discover_rsp.num_seps = 0;
+
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if (p_scb->allocated)
+ {
+ /* copy sep info */
+ sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
+ sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
+ sep_info[p_data->msg.discover_rsp.num_seps].media_type = p_scb->cs.media_type;
+ sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep;
+
+ p_data->msg.discover_rsp.num_seps++;
+ }
+ }
+
+ /* send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_rsp
+**
+** Description This function is called when a discover response or
+** reject is received from the peer. It calls the application
+** callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.discover_rsp));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_cmd
+**
+** Description This function is called when a get capabilities command
+** is received from the peer. It retrieves the stream
+** configuration for the requested stream and initiates
+** sending of a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+
+ /* look up scb for seid sent to us */
+ p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
+
+ p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_rsp
+**
+** Description This function is called with a get capabilities response
+** or reject is received from the peer. It calls the
+** application callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.svccap));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_cmd
+**
+** Description This function is called when a start command is received
+** from the peer. It verifies that all requested streams
+** are in the proper state. If so, it initiates sending of
+** a start response. Otherwise it sends a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = 0;
+
+ /* verify all streams in the right state */
+ UINT8 seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code);
+ if (seid == 0 && err_code == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data);
+ } else {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_rsp
+**
+** Description This function is called when a start response or reject
+** is received from the peer. Using the SEIDs stored in the
+** current command message, it sends a start response or start
+** reject event to each SCB associated with the command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_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_START_RSP_EVT : AVDT_SCB_MSG_START_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_ccb_hdl_suspend_cmd
+**
+** Description This function is called when a suspend command is received
+** from the peer. It verifies that all requested streams are
+** in the proper state. If so, it initiates sending of a
+** suspend response. Otherwise it sends a suspend reject.
+
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 seid;
+ UINT8 err_code = 0;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0 &&
+ err_code == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** 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_ccb_snd_discover_cmd
+**
+** Description This function is called to send a discover command to the
+** peer. It copies variables needed for the procedure from
+** the event to the CCB. It marks the CCB as busy and then
+** sends a discover command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->discover.p_sep_info;
+ p_ccb->proc_cback = p_data->discover.p_cback;
+ p_ccb->proc_param = p_data->discover.num_seps;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_discover_rsp
+**
+** Description This function is called to send a discover response to
+** the peer. It takes the stream information passed in the
+** event and sends a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_cmd
+**
+** Description This function is called to send a get capabilities command
+** to the peer. It copies variables needed for the procedure
+** from the event to the CCB. It marks the CCB as busy and
+** then sends a get capabilities command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->getcap.p_cfg;
+ p_ccb->proc_cback = p_data->getcap.p_cback;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG *) &p_data->getcap.single);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_rsp
+**
+** Description This function is called to send a get capabilities response
+** to the peer. It takes the stream information passed in the
+** event and sends a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_cmd
+**
+** Description This function is called to send a start command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a start command. Otherwise
+** send ourselves back a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_rsp
+**
+** Description This function is called to send a start response to the
+** peer. It takes the stream information passed in the event
+** and sends a start response. Then it sends a start event
+** to the SCB for each stream.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_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_START, &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_START_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_suspend_cmd
+**
+** Description This function is called to send a suspend command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a suspend command.
+** Otherwise it calls the callback function for each requested
+** stream and sends a suspend confirmation with failure.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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_ccb_clear_cmds
+**
+** Description This function is called when the signaling channel is
+** closed to clean up any pending commands. For each pending
+** command in the command queue, it frees the command and
+** calls the application callback function indicating failure.
+** Certain CCB variables are also initialized.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UINT8 err_code = AVDT_ERR_CONNECT;
+ UNUSED(p_data);
+
+ /* clear the ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out command queue; this is a little tricky here; we need
+ ** to handle the case where there is a command on deck in p_curr_cmd,
+ ** plus we need to clear out the queue
+ */
+ do
+ {
+ /* we know p_curr_cmd = NULL after this */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* set up next message */
+ p_ccb->p_curr_cmd = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q);
+
+ } while (p_ccb->p_curr_cmd != NULL);
+
+ /* send a CC_CLOSE_EVT any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cmd_fail
+**
+** Description This function is called when there is a response timeout.
+** The currently pending command is freed and we fake a
+** reject message back to ourselves.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_MSG msg;
+ UINT8 evt;
+ tAVDT_SCB *p_scb;
+
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ /* set up data */
+ msg.hdr.err_code = p_data->err_code;
+ msg.hdr.err_param = 0;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* pretend that we received a rej message */
+ evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1];
+
+ if (evt & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event(p_ccb, (UINT8) (evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+ }
+ else
+ {
+ /* we get the scb out of the current cmd */
+ p_scb = avdt_scb_by_hdl(*((UINT8 *)(p_ccb->p_curr_cmd + 1)));
+ if (p_scb != NULL)
+ {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+ }
+ }
+
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_free_cmd
+**
+** Description This function is called when a response is received for a
+** currently pending command. The command is freed.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cong_state
+**
+** Description This function is called to set the congestion state for
+** the CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ret_cmd
+**
+** Description This function is called to retransmit the currently
+** pending command. The retransmission count is incremented.
+** If the count reaches the maximum number of retransmissions,
+** the event is treated as a response timeout.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_TIMEOUT;
+ BT_HDR *p_msg;
+
+ p_ccb->ret_count++;
+ if (p_ccb->ret_count == AVDT_RET_MAX)
+ {
+ /* command failed */
+ p_ccb->ret_count = 0;
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* go to next queued command */
+ avdt_ccb_snd_cmd(p_ccb, p_data);
+ }
+ else
+ {
+ /* if command pending and we're not congested and not sending a fragment */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL))
+ {
+ /* make copy of message in p_curr_cmd and send it */
+ if ((p_msg = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_msg, p_ccb->p_curr_cmd,
+ (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len));
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+
+ /* restart timer */
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_cmd
+**
+** Description This function is called the send the next command,
+** if any, in the command queue.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+ UNUSED(p_data);
+
+ /* do we have commands to send? send next command; make sure we're clear;
+ ** not congested, not sending fragment, not waiting for response
+ */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL))
+ {
+ if ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q)) != NULL)
+ {
+ /* make a copy of buffer in p_curr_cmd */
+ if ((p_ccb->p_curr_cmd = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_ccb->p_curr_cmd, p_msg, (sizeof(BT_HDR) + p_msg->offset + p_msg->len));
+
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_msg
+**
+** Description
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+ UNUSED(p_data);
+
+ /* if not congested */
+ if (!p_ccb->cong)
+ {
+ /* are we sending a fragmented message? continue sending fragment */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ avdt_msg_send(p_ccb, NULL);
+ }
+ /* do we have responses to send? send them */
+ else if (!GKI_queue_is_empty(&p_ccb->rsp_q))
+ {
+ while ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ if (avdt_msg_send(p_ccb, p_msg) == TRUE)
+ {
+ /* break out if congested */
+ break;
+ }
+ }
+ }
+
+ /* do we have commands to send? send next command */
+ avdt_ccb_snd_cmd(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_reconn
+**
+** Description This function is called to enable a reconnect attempt when
+** a channel transitions from closing to idle state. It sets
+** the reconn variable to TRUE.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ p_ccb->reconn = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clr_reconn
+**
+** Description This function is called to clear the reconn variable.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ p_ccb->reconn = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_reconn
+**
+** Description This function is called to check if a reconnect attempt
+** is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT
+** to the CCB. If disabled, the CCB is deallocated.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_CONNECT;
+ UNUSED(p_data);
+
+ if (p_ccb->reconn)
+ {
+ p_ccb->reconn = FALSE;
+
+ /* clear out ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out current command, if any */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* reopen the signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+ }
+ else
+ {
+ avdt_ccb_ll_closed(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_timer
+**
+** Description This function stops the CCB timer if the idle timer is
+** running.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ if (p_ccb->timer_entry.event == BTU_TTYPE_AVDT_CCB_IDLE)
+ {
+ btu_stop_timer(&p_ccb->timer_entry);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_conn
+**
+** Description Set CCB variables associated with AVDT_ConnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* save callback */
+ p_ccb->p_conn_cback = p_data->connect.p_cback;
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_disconn
+**
+** Description Set CCB variables associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /*
+ AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x",
+ p_ccb->p_conn_cback, p_data->disconnect.p_cback);
+ */
+ /* save callback */
+ if (p_data->disconnect.p_cback)
+ p_ccb->p_conn_cback = p_data->disconnect.p_cback;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_do_disconn
+**
+** Description Do action associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* close channel */
+ avdt_ccb_chan_close(p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_closed
+**
+** Description Clear commands from and deallocate CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL_CBACK *p_cback;
+ BD_ADDR bd_addr;
+ tAVDT_CTRL avdt_ctrl;
+ UNUSED(p_data);
+
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* save callback pointer, bd addr */
+ p_cback = p_ccb->p_conn_cback;
+ if (!p_cback)
+ p_cback = avdt_cb.p_conn_cback;
+ memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* dealloc ccb */
+ avdt_ccb_dealloc(p_ccb, NULL);
+
+ /* call callback */
+ if (p_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_opened
+**
+** Description Call callback on open.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+
+ p_ccb->ll_opened = TRUE;
+
+ if (!p_ccb->p_conn_cback)
+ p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+
+ /* call callback */
+ if (p_ccb->p_conn_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
+ (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
--- /dev/null
+/******************************************************************************
+ *
+ * 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 AVDTP adaption layer module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+
+/* callback function declarations */
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avdt_l2c_appl = {
+ avdt_l2c_connect_ind_cback,
+ avdt_l2c_connect_cfm_cback,
+ NULL,
+ avdt_l2c_config_ind_cback,
+ avdt_l2c_config_cfm_cback,
+ avdt_l2c_disconnect_ind_cback,
+ avdt_l2c_disconnect_cfm_cback,
+ NULL,
+ avdt_l2c_data_ind_cback,
+ avdt_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function avdt_sec_check_complete_term
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ void *p_ref_data, UINT8 res)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL *p_tbl;
+ UNUSED(p_ref_data);
+
+ AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
+ if (!bd_addr)
+ {
+ AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
+ return;
+
+ }
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
+ if (p_tbl == NULL)
+ return;
+
+ if (res == BTM_SUCCESS)
+ {
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_sec_check_complete_orig
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+ void *p_ref_data, UINT8 res)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL *p_tbl;
+ UNUSED(p_ref_data);
+
+ AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
+ if (bd_addr)
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
+ if(p_tbl == NULL)
+ return;
+
+ if( res == BTM_SUCCESS )
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ else
+ {
+ L2CA_DisconnectReq (p_tbl->lcid);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+/*******************************************************************************
+**
+** Function avdt_l2c_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVDT_CCB *p_ccb;
+ tAVDT_TC_TBL *p_tbl = NULL;
+ UINT16 result;
+ tL2CAP_CFG_INFO cfg;
+ tBTM_STATUS rc;
+ UNUSED(psm);
+
+ /* do we already have a control channel for this peer? */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ /* no, allocate ccb */
+ if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+ {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* allocate and set up entry; first channel is always signaling */
+ p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ p_tbl->tcid = AVDT_CHAN_SIG;
+ p_tbl->lcid = lcid;
+ p_tbl->id = id;
+ p_tbl->state = AVDT_AD_ST_SEC_ACP;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
+
+ /* Check the security */
+ rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
+ FALSE, BTM_SEC_PROTO_AVDT,
+ AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_term, NULL);
+ if(rc == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+ return;
+ }
+ }
+ /* deal with simultaneous control channel connect case */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
+ {
+ /* reject their connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ /* this must be a traffic channel; are we accepting a traffic channel
+ ** for this ccb?
+ */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+ {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#if AVDT_REPORTING == TRUE
+ /* this must be a reporting channel; are we accepting a reporting channel
+ ** for this ccb?
+ */
+ else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+ {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#endif
+ /* else we're not listening for traffic channel; reject */
+ else
+ {
+ result = L2CAP_CONN_NO_PSM;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_connect_cfm_cback
+**
+** Description This is the L2CAP connect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVDT_TC_TBL *p_tbl;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_CCB *p_ccb;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CONN)
+ {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK)
+ {
+ if(p_tbl->tcid != AVDT_CHAN_SIG)
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = TRUE;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ else
+ {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ if(p_ccb == NULL)
+ {
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ else
+ {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_SEC_INT;
+ p_tbl->lcid = lcid;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+
+ /* Check the security */
+ btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
+ TRUE, BTM_SEC_PROTO_AVDT,
+ AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_orig, NULL);
+ }
+ }
+ }
+
+ /* failure; notify adaption that channel closed */
+ if (result != L2CAP_CONN_OK)
+ {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_config_cfm_cback
+**
+** Description This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ p_tbl->lcid = lcid;
+
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CFG)
+ {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CONN_OK)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
+ {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ /* else failure */
+ else
+ {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_config_ind_cback
+**
+** Description This is the L2CAP config indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present)
+ {
+ p_tbl->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
+ {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_disconnect_ind_cback
+**
+** Description This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+ lcid, ack_needed);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
+ lcid, result);
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_cong_ind(p_tbl, is_congested);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_l2c_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVDT_TC_TBL *p_tbl;
+
+ /* look up info for this channel */
+ if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+ {
+ avdt_ad_tc_data_ind(p_tbl, p_buf);
+ }
+ else /* prevent buffer leak */
+ GKI_freebuf(p_buf);
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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 functions for parsing and building AVDTP signaling
+ * messages. It also contains functions called by the SCB or CCB state
+ * machines for sending command, response, and reject messages. It also
+ * contains a function that processes incoming messages and dispatches them
+ * to the appropriate SCB or CCB.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* mask of all psc values */
+#define AVDT_MSG_PSC_MASK (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT | \
+ AVDT_PSC_RECOV | AVDT_PSC_HDRCMP | AVDT_PSC_MUX)
+#define AVDT_PSC_PROTECT (1<<4) /* Content Protection */
+#define AVDT_PSC_CODEC (1<<7) /* codec */
+
+
+/*****************************************************************************
+** type definitions
+*****************************************************************************/
+
+/* type for message building functions */
+typedef void (*tAVDT_MSG_BLD)(UINT8 **p, tAVDT_MSG *p_msg);
+
+/* type for message parsing functions */
+typedef UINT8 (*tAVDT_MSG_PRS)(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+
+
+/*****************************************************************************
+** local function declarations
+*****************************************************************************/
+
+static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg);
+
+static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len);
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* table of information element minimum lengths used for parsing */
+const UINT8 avdt_msg_ie_len_min[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MIN, /* media transport */
+ AVDT_LEN_REPORT_MIN, /* reporting */
+ AVDT_LEN_RECOV_MIN, /* recovery */
+ AVDT_LEN_PROTECT_MIN, /* content protection */
+ AVDT_LEN_HDRCMP_MIN, /* header compression */
+ AVDT_LEN_MUX_MIN, /* multiplexing */
+ AVDT_LEN_CODEC_MIN, /* codec */
+ AVDT_LEN_DELAY_RPT_MIN /* delay report */
+};
+
+/* table of information element minimum lengths used for parsing */
+const UINT8 avdt_msg_ie_len_max[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MAX, /* media transport */
+ AVDT_LEN_REPORT_MAX, /* reporting */
+ AVDT_LEN_RECOV_MAX, /* recovery */
+ AVDT_LEN_PROTECT_MAX, /* content protection */
+ AVDT_LEN_HDRCMP_MAX, /* header compression */
+ AVDT_LEN_MUX_MAX, /* multiplexing */
+ AVDT_LEN_CODEC_MAX, /* codec */
+ AVDT_LEN_DELAY_RPT_MAX /* delay report */
+};
+
+/* table of error codes used when decoding information elements */
+const UINT8 avdt_msg_ie_err[] = {
+ 0, /* unused */
+ AVDT_ERR_MEDIA_TRANS, /* media transport */
+ AVDT_ERR_LENGTH, /* reporting */
+ AVDT_ERR_RECOV_FMT, /* recovery */
+ AVDT_ERR_CP_FMT, /* content protection */
+ AVDT_ERR_ROHC_FMT, /* header compression */
+ AVDT_ERR_MUX_FMT, /* multiplexing */
+ AVDT_ERR_SERVICE, /* codec */
+ AVDT_ERR_SERVICE /* delay report ?? */
+};
+
+/* table of packet type minimum lengths */
+static const UINT8 avdt_msg_pkt_type_len[] = {
+ AVDT_LEN_TYPE_SINGLE,
+ AVDT_LEN_TYPE_START,
+ AVDT_LEN_TYPE_CONT,
+ AVDT_LEN_TYPE_END
+};
+
+/* function table for building command messages */
+const tAVDT_MSG_BLD avdt_msg_bld_cmd[] = {
+ avdt_msg_bld_none, /* discover */
+ avdt_msg_bld_single, /* get capabilities */
+ avdt_msg_bld_setconfig_cmd, /* set configuration */
+ avdt_msg_bld_single, /* get configuration */
+ avdt_msg_bld_reconfig_cmd, /* reconfigure */
+ avdt_msg_bld_single, /* open */
+ avdt_msg_bld_multi, /* start */
+ avdt_msg_bld_single, /* close */
+ avdt_msg_bld_multi, /* suspend */
+ avdt_msg_bld_single, /* abort */
+ avdt_msg_bld_security_cmd, /* security control */
+ avdt_msg_bld_single, /* get all capabilities */
+ avdt_msg_bld_delay_rpt /* delay report */
+};
+
+/* function table for building response messages */
+const tAVDT_MSG_BLD avdt_msg_bld_rsp[] = {
+ avdt_msg_bld_discover_rsp, /* discover */
+ avdt_msg_bld_svccap, /* get capabilities */
+ avdt_msg_bld_none, /* set configuration */
+ avdt_msg_bld_all_svccap, /* get configuration */
+ avdt_msg_bld_none, /* reconfigure */
+ avdt_msg_bld_none, /* open */
+ avdt_msg_bld_none, /* start */
+ avdt_msg_bld_none, /* close */
+ avdt_msg_bld_none, /* suspend */
+ avdt_msg_bld_none, /* abort */
+ avdt_msg_bld_security_rsp, /* security control */
+ avdt_msg_bld_all_svccap, /* get all capabilities */
+ avdt_msg_bld_none /* delay report */
+};
+
+/* function table for parsing command messages */
+const tAVDT_MSG_PRS avdt_msg_prs_cmd[] = {
+ avdt_msg_prs_none, /* discover */
+ avdt_msg_prs_single, /* get capabilities */
+ avdt_msg_prs_setconfig_cmd, /* set configuration */
+ avdt_msg_prs_single, /* get configuration */
+ avdt_msg_prs_reconfig_cmd, /* reconfigure */
+ avdt_msg_prs_single, /* open */
+ avdt_msg_prs_multi, /* start */
+ avdt_msg_prs_single, /* close */
+ avdt_msg_prs_multi, /* suspend */
+ avdt_msg_prs_single, /* abort */
+ avdt_msg_prs_security_cmd, /* security control */
+ avdt_msg_prs_single, /* get all capabilities */
+ avdt_msg_prs_delay_rpt /* delay report */
+};
+
+/* function table for parsing response messages */
+const tAVDT_MSG_PRS avdt_msg_prs_rsp[] = {
+ avdt_msg_prs_discover_rsp, /* discover */
+ avdt_msg_prs_svccap, /* get capabilities */
+ avdt_msg_prs_none, /* set configuration */
+ avdt_msg_prs_all_svccap, /* get configuration */
+ avdt_msg_prs_none, /* reconfigure */
+ avdt_msg_prs_none, /* open */
+ avdt_msg_prs_none, /* start */
+ avdt_msg_prs_none, /* close */
+ avdt_msg_prs_none, /* suspend */
+ avdt_msg_prs_none, /* abort */
+ avdt_msg_prs_security_rsp, /* security control */
+ avdt_msg_prs_all_svccap, /* get all capabilities */
+ avdt_msg_prs_none /* delay report */
+};
+
+/* command message-to-event lookup table */
+const UINT8 avdt_msg_cmd_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_CMD_EVT, /* open */
+ AVDT_CCB_MSG_START_CMD_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_CMD_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_CMD_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_CMD_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT /* delay report */
+};
+
+/* response message-to-event lookup table */
+const UINT8 avdt_msg_rsp_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_RSP_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT /* delay report */
+};
+
+/* reject message-to-event lookup table */
+const UINT8 avdt_msg_rej_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_REJ_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ 0 /* delay report */
+};
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_cfg
+**
+** Description This function builds the configuration parameters contained
+** in a command or response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_cfg(UINT8 **p, tAVDT_CFG *p_cfg)
+{
+ UINT8 len;
+
+ /* for now, just build media transport, codec, and content protection, and multiplexing */
+
+ /* media transport */
+ if (p_cfg->psc_mask & AVDT_PSC_TRANS)
+ {
+ *(*p)++ = AVDT_CAT_TRANS;
+ *(*p)++ = 0; /* length */
+ }
+
+#if AVDT_REPORTING == TRUE
+ /* reporting transport */
+ if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ {
+ *(*p)++ = AVDT_CAT_REPORT;
+ *(*p)++ = 0; /* length */
+ }
+#endif
+
+ /* codec */
+ if (p_cfg->num_codec != 0)
+ {
+ *(*p)++ = AVDT_CAT_CODEC;
+ len = p_cfg->codec_info[0] + 1;
+ if( len > AVDT_CODEC_SIZE )
+ len = AVDT_CODEC_SIZE;
+
+ memcpy(*p, p_cfg->codec_info, len);
+ *p += len;
+ }
+
+ /* content protection */
+ if (p_cfg->num_protect != 0)
+ {
+ *(*p)++ = AVDT_CAT_PROTECT;
+ len = p_cfg->protect_info[0] + 1;
+ if( len > AVDT_PROTECT_SIZE )
+ len = AVDT_PROTECT_SIZE;
+
+ memcpy(*p, p_cfg->protect_info, len);
+ *p += len;
+ }
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* multiplexing */
+ if (p_cfg->psc_mask & AVDT_PSC_MUX)
+ {
+ *(*p)++ = AVDT_CAT_MUX;
+ /* length */
+ if (p_cfg->psc_mask & AVDT_PSC_RECOV)
+ *(*p)++ = 7; /* frag (1) + media + report + recovery */
+ else if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ *(*p)++ = 5; /* frag (1) + media + report */
+ else
+ *(*p)++ = 3; /* frag (1) + media */
+
+ /* allow fragmentation */
+ if(p_cfg->mux_mask & AVDT_MUX_FRAG)
+ *(*p)++ = 0x80;
+ else
+ *(*p)++ = 0;
+
+ /* media transport session */
+ *(*p)++ = p_cfg->mux_tsid_media<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_media<<3; /* TCID */
+
+ if (p_cfg->psc_mask & AVDT_PSC_RECOV)
+ {
+ /* reporting transport session */
+ *(*p)++ = p_cfg->mux_tsid_report<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_report<<3; /* TCID */
+ /* recovery transport session */
+ *(*p)++ = p_cfg->mux_tsid_recov<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_recov<<3; /* TCID */
+ }
+ else if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+ {
+ /* reporting transport session */
+ *(*p)++ = p_cfg->mux_tsid_report<<3; /* TSID */
+ *(*p)++ = p_cfg->mux_tcid_report<<3; /* TCID */
+ }
+ }
+#endif
+
+ /* delay report */
+ if (p_cfg->psc_mask & AVDT_PSC_DELAY_RPT)
+ {
+ *(*p)++ = AVDT_CAT_DELAY_RPT;
+ *(*p)++ = 0; /* length */
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_none
+**
+** Description This message building function builds an empty message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ UNUSED(p);
+ UNUSED(p_msg);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_single
+**
+** Description This message building function builds a message containing
+** a single SEID.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->single.seid);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_setconfig_cmd
+**
+** Description This message building function builds a set configuration
+** command message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.hdr.seid);
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.int_seid);
+ avdt_msg_bld_cfg(p, p_msg->config_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_reconfig_cmd
+**
+** Description This message building function builds a reconfiguration
+** command message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->reconfig_cmd.hdr.seid);
+
+ /* force psc mask zero to build only codec and security */
+ p_msg->reconfig_cmd.p_cfg->psc_mask = 0;
+ avdt_msg_bld_cfg(p, p_msg->reconfig_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_multi
+**
+** Description This message building function builds a message containing
+** multiple SEID's.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ int i;
+
+ for (i = 0; i < p_msg->multi.num_seps; i++)
+ {
+ AVDT_MSG_BLD_SEID(*p, p_msg->multi.seid_list[i]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_security_cmd
+**
+** Description This message building function builds a security
+** command message.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->security_cmd.hdr.seid);
+ memcpy(*p, p_msg->security_cmd.p_data, p_msg->security_cmd.len);
+ *p += p_msg->security_cmd.len;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_delay_rpt
+**
+** Description This message building function builds a delay report
+** command message.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ AVDT_MSG_BLD_SEID(*p, p_msg->delay_rpt_cmd.hdr.seid);
+ UINT16_TO_BE_STREAM(*p, p_msg->delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_discover_rsp
+**
+** Description This message building function builds a discover
+** response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ int i;
+
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+ {
+ /* build discover rsp info */
+ AVDT_MSG_BLD_DISC(*p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_svccap
+**
+** Description This message building function builds a message containing
+** service capabilities parameters.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ tAVDT_CFG cfg;
+
+ /* make sure the delay report category is not reported */
+ memcpy (&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG));
+ cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+ avdt_msg_bld_cfg(p, &cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_all_svccap
+**
+** Description This message building function builds a message containing
+** service capabilities parameters.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ avdt_msg_bld_cfg(p, p_msg->svccap.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_bld_security_rsp
+**
+** Description This message building function builds a security
+** response message.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg)
+{
+ memcpy(*p, p_msg->security_rsp.p_data, p_msg->security_rsp.len);
+ *p += p_msg->security_rsp.len;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_cfg
+**
+** Description This message parsing function parses the configuration
+** parameters field of a message.
+**
+**
+** Returns Error code or zero if no error, and element that failed
+** in p_elem.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8* p_elem, UINT8 sig_id)
+{
+ UINT8 *p_end;
+ UINT8 elem = 0;
+ UINT8 elem_len;
+ UINT8 tmp;
+ UINT8 err = 0;
+ UINT8 protect_offset = 0;
+
+ if (!p_cfg)
+ {
+ AVDT_TRACE_ERROR ("not expecting this cfg");
+ return AVDT_ERR_BAD_STATE;
+ }
+
+ p_cfg->psc_mask = 0;
+ p_cfg->num_codec = 0;
+ p_cfg->num_protect = 0;
+#if AVDT_MULTIPLEXING == TRUE
+ p_cfg->mux_mask = 0;
+#endif
+
+ /* while there is still data to parse */
+ p_end = p + len;
+ while ((p < p_end) && (err == 0))
+ {
+ /* verify overall length */
+ if ((p_end - p) < AVDT_LEN_CFG_MIN)
+ {
+ err = AVDT_ERR_PAYLOAD;
+ break;
+ }
+
+ /* get and verify info elem id, length */
+ elem = *p++;
+ elem_len = *p++;
+
+ if ((elem == 0) || (elem > AVDT_CAT_MAX_CUR))
+ {
+ /* this may not be really bad.
+ * It may be a service category that is too new for us.
+ * allow these to be parsed without reporting an error.
+ * If this is a "capability" (as in GetCapRsp & GetConfigRsp), this is filtered out.
+ * If this is a Configuration (as in SetConfigCmd & ReconfigCmd),
+ * this will be marked as an error in the caller of this function */
+ if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG))
+ {
+ /* Cannot accept unknown category. */
+ err = AVDT_ERR_CATEGORY;
+ break;
+ }
+ else /* GETCAP or GET_ALLCAP */
+ {
+ /* Skip unknown categories. */
+ p += elem_len;
+ AVDT_TRACE_DEBUG("skipping unknown service category=%d len: %d", elem, elem_len);
+ continue;
+ }
+ }
+
+ if ((elem_len > avdt_msg_ie_len_max[elem]) ||
+ (elem_len < avdt_msg_ie_len_min[elem]))
+ {
+ err = avdt_msg_ie_err[elem];
+ break;
+ }
+
+ /* add element to psc mask, but mask out codec or protect */
+ p_cfg->psc_mask |= (1 << elem);
+ AVDT_TRACE_DEBUG("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len, p_cfg->psc_mask);
+
+ /* parse individual information elements with additional parameters */
+ switch (elem)
+ {
+ case AVDT_CAT_RECOV:
+ p_cfg->recov_type = *p++;
+ p_cfg->recov_mrws = *p++;
+ p_cfg->recov_mnmp = *p++;
+ if (p_cfg->recov_type != AVDT_RECOV_RFC2733)
+ {
+ err = AVDT_ERR_RECOV_TYPE;
+ }
+ else if ((p_cfg->recov_mrws < AVDT_RECOV_MRWS_MIN) ||
+ (p_cfg->recov_mrws > AVDT_RECOV_MRWS_MAX) ||
+ (p_cfg->recov_mnmp < AVDT_RECOV_MNMP_MIN) ||
+ (p_cfg->recov_mnmp > AVDT_RECOV_MNMP_MAX))
+ {
+ err = AVDT_ERR_RECOV_FMT;
+ }
+ break;
+
+ case AVDT_CAT_PROTECT:
+ p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
+ if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
+ {
+ p_cfg->num_protect++;
+ p_cfg->protect_info[protect_offset] = elem_len;
+ protect_offset++;
+ memcpy(&p_cfg->protect_info[protect_offset], p, elem_len);
+ protect_offset += elem_len;
+ }
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_HDRCMP:
+ p_cfg->hdrcmp_mask = *p++;
+ break;
+
+#if AVDT_MULTIPLEXING == TRUE
+ case AVDT_CAT_MUX:
+ /* verify length */
+ AVDT_TRACE_WARNING("psc_mask=0x%x elem_len=%d", p_cfg->psc_mask, elem_len);
+ if( ((0 == (p_cfg->psc_mask & (AVDT_PSC_RECOV|AVDT_PSC_REPORT))) && (elem_len != 3))
+ || (((p_cfg->psc_mask & AVDT_PSC_REPORT) && !(p_cfg->psc_mask & AVDT_PSC_RECOV))
+ && (elem_len != 5))
+ || ((!(p_cfg->psc_mask & AVDT_PSC_REPORT) && (p_cfg->psc_mask & AVDT_PSC_RECOV))
+ && (elem_len != 5))
+ || (((p_cfg->psc_mask & AVDT_PSC_REPORT) && (p_cfg->psc_mask & AVDT_PSC_RECOV))
+ && (elem_len != 7)) )
+ {
+ err = AVDT_ERR_MUX_FMT;
+ break;
+ }
+
+ /* parse fragmentation */
+ p_cfg->mux_mask = *p++ & (UINT8)AVDT_MUX_FRAG;
+
+ /* parse TSIDs and TCIDs */
+ if(--elem_len)
+ p_cfg->mux_tsid_media = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_media = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tsid_report = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_report = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tsid_recov = (*p++)>>3;
+ else
+ break;
+
+ if(--elem_len)
+ p_cfg->mux_tcid_recov = (*p++)>>3;
+ else
+ break;
+ break;
+#endif
+
+ case AVDT_CAT_CODEC:
+ p_cfg->psc_mask &= ~AVDT_PSC_CODEC;
+ tmp = elem_len;
+ if (elem_len >= AVDT_CODEC_SIZE)
+ {
+ tmp = AVDT_CODEC_SIZE - 1;
+ }
+ p_cfg->num_codec++;
+ p_cfg->codec_info[0] = elem_len;
+ memcpy(&p_cfg->codec_info[1], p, tmp);
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_DELAY_RPT:
+ break;
+
+ default:
+ p += elem_len;
+ break;
+ } /* switch */
+ } /* while ! err, !end*/
+ *p_elem = elem;
+ AVDT_TRACE_DEBUG("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem, p_cfg->psc_mask);
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_none
+**
+** Description This message parsing function parses a message with no parameters.
+
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UNUSED(p_msg);
+ UNUSED(p);
+ UNUSED(len);
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_single
+**
+** Description This message parsing function parses a message with a
+** single SEID.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_SINGLE)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->single.seid);
+
+ if (avdt_scb_by_hdl(p_msg->single.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_setconfig_cmd
+**
+** Description This message parsing function parses a set configuration
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SETCONFIG_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seids */
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->config_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.int_seid);
+ if ((p_msg->config_cmd.int_seid < AVDT_SEID_MIN) ||
+ (p_msg->config_cmd.int_seid > AVDT_SEID_MAX))
+ {
+ err = AVDT_ERR_SEID;
+ }
+ }
+
+ if (!err)
+ {
+ /* parse configuration parameters */
+ len -= 2;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_SETCONFIG);
+
+ if (!err)
+ {
+ /* verify protocol service capabilities are supported */
+ if (((p_msg->config_cmd.p_cfg->psc_mask & (~AVDT_PSC)) != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0))
+ {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_reconfig_cmd
+**
+** Description This message parsing function parses a reconfiguration
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_RECONFIG_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->reconfig_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->reconfig_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ /* parse config parameters */
+ len--;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_RECONFIG);
+
+ /* verify no protocol service capabilities in parameters */
+ if (!err)
+ {
+ AVDT_TRACE_DEBUG("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x", p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK);
+ if ((p_msg->config_cmd.p_cfg->psc_mask != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0 && p_msg->config_cmd.p_cfg->num_protect == 0))
+ {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_multi
+**
+** Description This message parsing function parses a message containing
+** multiple SEID's.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ int i;
+ UINT8 err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_MULTI_MIN || (len > AVDT_NUM_SEPS))
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get and verify all seps */
+ for (i = 0; i < len; i++)
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->multi.seid_list[i]);
+ if (avdt_scb_by_hdl(p_msg->multi.seid_list[i]) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ p_msg->hdr.err_param = p_msg->multi.seid_list[i];
+ break;
+ }
+ }
+ p_msg->multi.num_seps = (UINT8)i;
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_security_cmd
+**
+** Description This message parsing function parses a security
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SECURITY_MIN)
+ {
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->security_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->security_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ p_msg->security_cmd.p_data = p;
+ p_msg->security_cmd.len = len - 1;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_discover_rsp
+**
+** Description This message parsing function parses a discover
+** response message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ int i;
+ UINT8 err = 0;
+
+ /* determine number of seps; seps in msg is len/2, but set to minimum
+ ** of seps app has supplied memory for and seps in msg
+ */
+ if (p_msg->discover_rsp.num_seps > (len / 2))
+ {
+ p_msg->discover_rsp.num_seps = (len / 2);
+ }
+
+ /* parse out sep info */
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+ {
+ /* parse discover rsp info */
+ AVDT_MSG_PRS_DISC(p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+
+ /* verify that seid is valid */
+ if ((p_msg->discover_rsp.p_sep_info[i].seid < AVDT_SEID_MIN) ||
+ (p_msg->discover_rsp.p_sep_info[i].seid > AVDT_SEID_MAX))
+ {
+ err = AVDT_ERR_SEID;
+ break;
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_svccap
+**
+** Description This message parsing function parses a message containing
+** service capabilities parameters.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ /* parse parameters */
+ UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GETCAP);
+ if (p_msg->svccap.p_cfg)
+ {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_LEG_PSC;
+ }
+
+ return (err);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_all_svccap
+**
+** Description This message parsing function parses a message containing
+** service capabilities parameters.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GET_ALLCAP);
+ if (p_msg->svccap.p_cfg)
+ {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_MSG_PSC_MASK;
+ }
+ return (err);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_security_rsp
+**
+** Description This message parsing function parsing a security
+** response message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ p_msg->security_rsp.p_data = p;
+ p_msg->security_rsp.len = len;
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_rej
+**
+** Description
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_rej(tAVDT_MSG *p_msg, UINT8 *p, UINT8 sig)
+{
+ if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG))
+ {
+ p_msg->hdr.err_param = *p++;
+ p_msg->hdr.err_code = *p;
+ }
+ else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND))
+ {
+ AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+ p_msg->hdr.err_code = *p;
+ }
+ else
+ {
+ p_msg->hdr.err_code = *p;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_prs_delay_rpt
+**
+** Description This message parsing function parses a security
+** command message.
+**
+**
+** Returns Error code or zero if no error.
+**
+*******************************************************************************/
+static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len)
+{
+ UINT8 err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_DELAY_RPT)
+ {
+ AVDT_TRACE_WARNING("avdt_msg_prs_delay_rpt expected len: %u got: %u", AVDT_LEN_DELAY_RPT, len);
+ err = AVDT_ERR_LENGTH;
+ }
+ else
+ {
+ /* get seid */
+ AVDT_MSG_PRS_SEID (p, p_msg->delay_rpt_cmd.hdr.seid);
+
+ if (avdt_scb_by_hdl(p_msg->delay_rpt_cmd.hdr.seid) == NULL)
+ {
+ err = AVDT_ERR_SEID;
+ }
+ else
+ {
+ BE_STREAM_TO_UINT16 (p_msg->delay_rpt_cmd.delay, p);
+ AVDT_TRACE_DEBUG("avdt_msg_prs_delay_rpt delay: %u", p_msg->delay_rpt_cmd.delay);
+ }
+ }
+ return err;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send
+**
+** Description Send, and if necessary fragment the next message.
+**
+**
+** Returns Congested state; TRUE if CCB congested, FALSE if not.
+**
+*******************************************************************************/
+BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 hdr_len;
+ tAVDT_TC_TBL *p_tbl;
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 label;
+ UINT8 msg;
+ UINT8 sig;
+ UINT8 nosp = 0; /* number of subsequent packets */
+
+ /* look up transport channel table entry to get peer mtu */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_SIG, p_ccb, NULL);
+
+ /* set the current message if there is a message passed in */
+ if (p_msg != NULL)
+ {
+ p_ccb->p_curr_msg = p_msg;
+ }
+
+ /* store copy of curr_msg->len */
+ curr_msg_len = p_ccb->p_curr_msg->len;
+
+ /* while not congested and we haven't sent it all */
+ while ((!p_ccb->cong) && (p_ccb->p_curr_msg != NULL))
+ {
+ /* check what kind of message we've got here; we are using the offset
+ ** to indicate that a message is being fragmented
+ */
+
+ /* if message isn't being fragmented and it fits in mtu */
+ if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len <= p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+ {
+ pkt_type = AVDT_PKT_TYPE_SINGLE;
+ hdr_len = AVDT_LEN_TYPE_SINGLE;
+ p_buf = p_ccb->p_curr_msg;
+ }
+ /* if message isn't being fragmented and it doesn't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len > p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+ {
+ pkt_type = AVDT_PKT_TYPE_START;
+ hdr_len = AVDT_LEN_TYPE_START;
+ nosp = (p_ccb->p_curr_msg->len + AVDT_LEN_TYPE_START - p_tbl->peer_mtu) /
+ (p_tbl->peer_mtu - 1) + 2;
+
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL)
+ {
+ /* do we even want to try and recover from this? could do so
+ by setting retransmission timer */
+ return TRUE;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes don't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset > AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len > (p_tbl->peer_mtu - AVDT_LEN_TYPE_CONT)))
+ {
+ pkt_type = AVDT_PKT_TYPE_CONT;
+ hdr_len = AVDT_LEN_TYPE_CONT;
+
+ /* get a new buffer for fragment we are sending */
+ if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL)
+ {
+ /* do we even want to try and recover from this? could do so
+ by setting retransmission timer */
+ return TRUE;
+ }
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
+ (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes do fit in mtu */
+ else
+ {
+ pkt_type = AVDT_PKT_TYPE_END;
+ hdr_len = AVDT_LEN_TYPE_END;
+ p_buf = p_ccb->p_curr_msg;
+ }
+
+ /* label, sig id, msg type are in hdr of p_curr_msg */
+ label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific);
+ msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific);
+ sig = (UINT8) p_ccb->p_curr_msg->event;
+ AVDT_TRACE_DEBUG("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig);
+
+ /* keep track of how much of msg we've sent */
+ curr_msg_len -= p_buf->len;
+ if (curr_msg_len == 0)
+ {
+ /* entire message sent; mark as finished */
+ p_ccb->p_curr_msg = NULL;
+
+ /* start timer here for commands */
+ if (msg == AVDT_MSG_TYPE_CMD)
+ {
+ /* if retransmit timeout set to zero, sig doesn't use retransmit */
+ if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) ||
+ (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0))
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RSP, avdt_cb.rcb.sig_tout);
+ }
+ else if (sig != AVDT_SIG_DELAY_RPT)
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout);
+ }
+ }
+ }
+ else
+ {
+ /* message being fragmented and not completely sent */
+ p_ccb->p_curr_msg->len -= p_buf->len;
+ p_ccb->p_curr_msg->offset += p_buf->len;
+ }
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVDT_MSG_BLD_HDR(p, label, pkt_type, msg);
+ if (pkt_type == AVDT_PKT_TYPE_START)
+ {
+ AVDT_MSG_BLD_NOSP(p, nosp);
+ }
+ if ((pkt_type == AVDT_PKT_TYPE_START) || (pkt_type == AVDT_PKT_TYPE_SINGLE))
+ {
+ AVDT_MSG_BLD_SIG(p, sig);
+ }
+
+ /* send msg buffer down */
+ avdt_ad_write_req(AVDT_CHAN_SIG, p_ccb, NULL, p_buf);
+ }
+ return (p_ccb->cong);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+ UINT16 buf_len;
+
+ /* parse the message header */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVDT_MSG_PRS_PKT_TYPE(p, pkt_type);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avdt_msg_pkt_type_len[pkt_type])
+ {
+ GKI_freebuf(p_buf);
+ AVDT_TRACE_WARNING("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVDT_PKT_TYPE_SINGLE)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ AVDT_TRACE_WARNING("Got single during reassembly");
+ }
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVDT_PKT_TYPE_START)
+ {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ AVDT_TRACE_WARNING("Got start during reassembly");
+ }
+ p_ccb->p_rx_msg = p_buf;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_ccb->p_rx_msg->len -= 1;
+
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else
+ {
+ /* if no reassembly in progress drop message */
+ if (p_ccb->p_rx_msg == NULL)
+ {
+ GKI_freebuf(p_buf);
+ AVDT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* get size of buffer holding assembled message */
+ buf_len = GKI_get_buf_size(p_ccb->p_rx_msg) - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVDT_LEN_TYPE_CONT;
+ p_buf->len -= AVDT_LEN_TYPE_CONT;
+
+ /* verify length */
+ if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len)
+ {
+ /* won't fit; free everything */
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ GKI_freebuf(p_buf);
+ p_ret = NULL;
+ }
+ else
+ {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((UINT8 *)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset,
+ (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVDT_PKT_TYPE_END)
+ {
+ p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = p_ccb->p_rx_msg;
+ p_ccb->p_rx_msg = NULL;
+ }
+ else
+ {
+ p_ccb->p_rx_msg->offset += p_buf->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_cmd
+**
+** Description This function is called to send a command message. The
+** sig_id parameter indicates the message type, p_params
+** points to the message parameters, if any. It gets a buffer
+** from the AVDTP command pool, executes the message building
+** function for this message type. It then queues the message
+** in the command queue for this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL)
+ {
+ AVDT_TRACE_ERROR("avdt_msg_send_cmd out of buffer!!");
+ return;
+ }
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_cmd[sig_id - 1])(&p, p_params);
+
+ /* set len */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* now store scb hdls, if any, in buf */
+ if (p_scb != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1);
+
+ /* for start and suspend, p_scb points to array of handles */
+ if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND))
+ {
+ memcpy(p, (UINT8 *) p_scb, p_buf->len);
+ }
+ /* for all others, p_scb points to scb as usual */
+ else
+ {
+ *p = avdt_scb_to_hdl((tAVDT_SCB *) p_scb);
+ }
+ }
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_CMD, p_ccb->label);
+
+ /* increment label */
+ p_ccb->label = (p_ccb->label + 1) % 16;
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->cmd_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_rsp
+**
+** Description This function is called to send a response message. The
+** sig_id parameter indicates the message type, p_params
+** points to the message parameters, if any. It gets a buffer
+** from the AVDTP command pool, executes the message building
+** function for this message type. It then queues the message
+** in the response queue for this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_rsp[sig_id - 1])(&p, p_params);
+
+ /* set length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP, p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_rej
+**
+** Description This function is called to send a reject message. The
+** sig_id parameter indicates the message type. It gets
+** a buffer from the AVDTP command pool and builds the
+** message based on the message type and the error code.
+** It then queues the message in the response queue for
+** this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* if sig id included, build into message */
+ if (sig_id != AVDT_SIG_NONE)
+ {
+ /* if this sig has a parameter, add the parameter */
+ if ((sig_id == AVDT_SIG_SETCONFIG) ||
+ (sig_id == AVDT_SIG_RECONFIG))
+ {
+ AVDT_MSG_BLD_PARAM(p, p_params->hdr.err_param);
+ }
+ else if ((sig_id == AVDT_SIG_START) ||
+ (sig_id == AVDT_SIG_SUSPEND))
+ {
+ AVDT_MSG_BLD_SEID(p, p_params->hdr.err_param);
+ }
+
+ /* add the error code */
+ AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code);
+ }
+ AVDT_TRACE_DEBUG("avdt_msg_send_rej");
+
+ /* calculate length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ, p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_send_grej
+**
+** Description This function is called to send a general reject message. The
+** sig_id parameter indicates the message type. It gets
+** a buffer from the AVDTP command pool and builds the
+** message based on the message type and the error code.
+** It then queues the message in the response queue for
+** this CCB.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+ UINT8 *p_start;
+
+ /* get a buffer */
+ p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID);
+ if (p_buf == NULL) return;
+
+ /* set up gki buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* calculate length */
+ p_buf->len = (UINT16) (p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = 0;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, 0, p_params->hdr.label);
+ AVDT_TRACE_DEBUG("avdt_msg_send_grej");
+
+ /* queue message and trigger ccb to send it */
+ GKI_enqueue(&p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_msg_ind
+**
+** Description This function is called by the adaption layer when an
+** incoming message is received on the signaling channel.
+** It parses the message and sends an event to the appropriate
+** SCB or CCB for the message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+ tAVDT_SCB *p_scb;
+ UINT8 *p;
+ BOOLEAN ok = TRUE;
+ BOOLEAN handle_rsp = FALSE;
+ BOOLEAN gen_rej = FALSE;
+ UINT8 label;
+ UINT8 pkt_type;
+ UINT8 msg_type;
+ UINT8 sig = 0;
+ tAVDT_MSG msg;
+ tAVDT_CFG cfg;
+ UINT8 err;
+ UINT8 evt = 0;
+ UINT8 scb_hdl;
+
+ /* reassemble message; if no message available (we received a fragment) return */
+ if ((p_buf = avdt_msg_asmbl(p_ccb, p_buf)) == NULL)
+ {
+ return;
+ }
+
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* parse the message header */
+ AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type);
+
+ UNUSED(pkt_type);
+
+ AVDT_TRACE_DEBUG("msg_type=%d, sig=%d", msg_type, sig);
+ /* set up label and ccb_idx in message hdr */
+ msg.hdr.label = label;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* verify msg type */
+ if (msg_type == AVDT_MSG_TYPE_GRJ)
+ {
+ AVDT_TRACE_WARNING("Dropping msg msg_type=%d", msg_type);
+ ok = FALSE;
+ }
+ /* check for general reject */
+ else if ((msg_type == AVDT_MSG_TYPE_REJ) && (p_buf->len == AVDT_LEN_GEN_REJ))
+ {
+ gen_rej = TRUE;
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ msg.hdr.sig_id = sig = (UINT8) p_ccb->p_curr_cmd->event;
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ msg.hdr.err_code = AVDT_ERR_NSC;
+ msg.hdr.err_param = 0;
+ }
+ }
+ else /* not a general reject */
+ {
+ /* get and verify signal */
+ AVDT_MSG_PRS_SIG(p, sig);
+ msg.hdr.sig_id = sig;
+ if ((sig == 0) || (sig > AVDT_SIG_MAX))
+ {
+ AVDT_TRACE_WARNING("Dropping msg sig=%d msg_type:%d", sig, msg_type);
+ ok = FALSE;
+
+ /* send a general reject */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ avdt_msg_send_grej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ if (ok && !gen_rej)
+ {
+ /* skip over header (msg length already verified during reassembly) */
+ p_buf->len -= AVDT_LEN_TYPE_SINGLE;
+
+ /* set up to parse message */
+ if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER))
+ {
+ /* parse discover rsp message to struct supplied by app */
+ msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO *) p_ccb->p_proc_data;
+ msg.discover_rsp.num_seps = p_ccb->proc_param;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
+ ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP)))
+ {
+ /* parse discover rsp message to struct supplied by app */
+ msg.svccap.p_cfg = (tAVDT_CFG *) p_ccb->p_proc_data;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG))
+ {
+ /* parse get config rsp message to struct allocated locally */
+ msg.svccap.p_cfg = &cfg;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG))
+ {
+ /* parse config cmd message to struct allocated locally */
+ msg.config_cmd.p_cfg = &cfg;
+ }
+ else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG))
+ {
+ /* parse reconfig cmd message to struct allocated locally */
+ msg.reconfig_cmd.p_cfg = &cfg;
+ }
+
+ /* parse message; while we're at it map message sig to event */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ msg.hdr.err_code = err = (*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_cmd_2_evt[sig - 1];
+ }
+ else if (msg_type == AVDT_MSG_TYPE_RSP)
+ {
+ msg.hdr.err_code = err = (*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_rsp_2_evt[sig - 1];
+ }
+ else /* msg_type == AVDT_MSG_TYPE_REJ */
+ {
+ err = avdt_msg_prs_rej(&msg, p, sig);
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ }
+
+ /* if parsing failed */
+ if (err != 0)
+ {
+ AVDT_TRACE_WARNING("Parsing failed sig=%d err=0x%x", sig, err);
+
+ /* if its a rsp or rej, drop it; if its a cmd, send a rej;
+ ** note special case for abort; never send abort reject
+ */
+ ok = FALSE;
+ if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT))
+ {
+ avdt_msg_send_rej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ /* if its a rsp or rej, check sent cmd to see if we're waiting for
+ ** the rsp or rej. If we didn't send a cmd for it, drop it. If
+ ** it does match a cmd, stop timer for the cmd.
+ */
+ if (ok)
+ {
+ if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ))
+ {
+ if ((p_ccb->p_curr_cmd != NULL) &&
+ (p_ccb->p_curr_cmd->event == sig) &&
+ (AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label))
+ {
+ /* stop timer */
+ btu_stop_timer(&p_ccb->timer_entry);
+
+ /* clear retransmission count */
+ p_ccb->ret_count = 0;
+
+ /* later in this function handle ccb event */
+ handle_rsp = TRUE;
+ }
+ else
+ {
+ ok = FALSE;
+ AVDT_TRACE_WARNING("Cmd not found for rsp sig=%d label=%d", sig, label);
+ }
+ }
+ }
+
+ if (ok)
+ {
+ /* if it's a ccb event send to ccb */
+ if (evt & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event(p_ccb, (UINT8)(evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+ }
+ /* if it's a scb event */
+ else
+ {
+ /* Scb events always have a single seid. For cmd, get seid from
+ ** message. For rej and rsp, get seid from p_curr_cmd.
+ */
+ if (msg_type == AVDT_MSG_TYPE_CMD)
+ {
+ scb_hdl = msg.single.seid;
+ }
+ else
+ {
+ scb_hdl = *((UINT8 *)(p_ccb->p_curr_cmd + 1));
+ }
+
+ /* Map seid to the scb and send it the event. For cmd, seid has
+ ** already been verified by parsing function.
+ */
+ if (evt && (p_scb = avdt_scb_by_hdl(scb_hdl)) != NULL)
+ {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+ }
+ }
+ }
+
+ /* free message buffer */
+ GKI_freebuf(p_buf);
+
+ /* if its a rsp or rej, send event to ccb to free associated
+ ** cmd msg buffer and handle cmd queue
+ */
+ if (handle_rsp)
+ {
+ avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL);
+ }
+}
--- /dev/null
+/******************************************************************************
+ *
+ * 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 the stream control block and functions which
+ * operate on the stream control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if AVDT_DEBUG == TRUE
+
+/* verbose state strings for trace */
+const char * const avdt_scb_st_str[] = {
+ "SCB_IDLE_ST",
+ "SCB_CONF_ST",
+ "SCB_OPENING_ST",
+ "SCB_OPEN_ST",
+ "SCB_STREAM_ST",
+ "SCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_scb_evt_str[] = {
+ "API_REMOVE_EVT",
+ "API_WRITE_REQ_EVT",
+ "API_GETCONFIG_REQ_EVT",
+ "API_DELAY_RPT_REQ",
+ "API_SETCONFIG_REQ_EVT",
+ "API_OPEN_REQ_EVT",
+ "API_CLOSE_REQ_EVT",
+ "API_RECONFIG_REQ_EVT",
+ "API_SECURITY_REQ_EVT",
+ "API_ABORT_REQ_EVT",
+ "API_GETCONFIG_RSP_EVT",
+ "API_SETCONFIG_RSP_EVT",
+ "API_SETCONFIG_REJ_EVT",
+ "API_OPEN_RSP_EVT",
+ "API_CLOSE_RSP_EVT",
+ "API_RECONFIG_RSP_EVT",
+ "API_SECURITY_RSP_EVT",
+ "API_ABORT_RSP_EVT",
+ "MSG_SETCONFIG_CMD_EVT",
+ "MSG_GETCONFIG_CMD_EVT",
+ "MSG_OPEN_CMD_EVT",
+ "MSG_START_CMD_EVT",
+ "MSG_SUSPEND_CMD_EVT",
+ "MSG_CLOSE_CMD_EVT",
+ "MSG_ABORT_CMD_EVT",
+ "MSG_RECONFIG_CMD_EVT",
+ "MSG_SECURITY_CMD_EVT",
+ "MSG_DELAY_RPT_CMD_EVT",
+ "MSG_DELAY_RPT_RSP_EVT",
+ "MSG_SETCONFIG_RSP_EVT",
+ "MSG_GETCONFIG_RSP_EVT",
+ "MSG_OPEN_RSP_EVT",
+ "MSG_START_RSP_EVT",
+ "MSG_SUSPEND_RSP_EVT",
+ "MSG_CLOSE_RSP_EVT",
+ "MSG_ABORT_RSP_EVT",
+ "MSG_RECONFIG_RSP_EVT",
+ "MSG_SECURITY_RSP_EVT",
+ "MSG_SETCONFIG_REJ_EVT",
+ "MSG_OPEN_REJ_EVT",
+ "MSG_START_REJ_EVT",
+ "MSG_SUSPEND_REJ_EVT",
+ "TC_TOUT_EVT",
+ "TC_OPEN_EVT",
+ "TC_CLOSE_EVT",
+ "TC_CONG_EVT",
+ "TC_DATA_EVT",
+ "CC_CLOSE_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_SCB_ACTION avdt_scb_action[] = {
+ avdt_scb_hdl_abort_cmd,
+ avdt_scb_hdl_abort_rsp,
+ avdt_scb_hdl_close_cmd,
+ avdt_scb_hdl_close_rsp,
+ avdt_scb_hdl_getconfig_cmd,
+ avdt_scb_hdl_getconfig_rsp,
+ avdt_scb_hdl_open_cmd,
+ avdt_scb_hdl_open_rej,
+ avdt_scb_hdl_open_rsp,
+ avdt_scb_hdl_pkt,
+ avdt_scb_drop_pkt,
+ avdt_scb_hdl_reconfig_cmd,
+ avdt_scb_hdl_reconfig_rsp,
+ avdt_scb_hdl_security_cmd,
+ avdt_scb_hdl_security_rsp,
+ avdt_scb_hdl_setconfig_cmd,
+ avdt_scb_hdl_setconfig_rej,
+ avdt_scb_hdl_setconfig_rsp,
+ avdt_scb_hdl_start_cmd,
+ avdt_scb_hdl_start_rsp,
+ avdt_scb_hdl_suspend_cmd,
+ avdt_scb_hdl_suspend_rsp,
+ avdt_scb_hdl_tc_close,
+#if AVDT_REPORTING == TRUE
+ avdt_scb_hdl_tc_close_sto,
+#endif
+ avdt_scb_hdl_tc_open,
+#if AVDT_REPORTING == TRUE
+ avdt_scb_hdl_tc_open_sto,
+#endif
+ avdt_scb_snd_delay_rpt_req,
+ avdt_scb_hdl_delay_rpt_cmd,
+ avdt_scb_hdl_delay_rpt_rsp,
+ avdt_scb_hdl_write_req,
+ avdt_scb_snd_abort_req,
+ avdt_scb_snd_abort_rsp,
+ avdt_scb_snd_close_req,
+ avdt_scb_snd_stream_close,
+ avdt_scb_snd_close_rsp,
+ avdt_scb_snd_getconfig_req,
+ avdt_scb_snd_getconfig_rsp,
+ avdt_scb_snd_open_req,
+ avdt_scb_snd_open_rsp,
+ avdt_scb_snd_reconfig_req,
+ avdt_scb_snd_reconfig_rsp,
+ avdt_scb_snd_security_req,
+ avdt_scb_snd_security_rsp,
+ avdt_scb_snd_setconfig_req,
+ avdt_scb_snd_setconfig_rej,
+ avdt_scb_snd_setconfig_rsp,
+ avdt_scb_snd_tc_close,
+ avdt_scb_cb_err,
+ avdt_scb_cong_state,
+ avdt_scb_rej_state,
+ avdt_scb_rej_in_use,
+ avdt_scb_rej_not_in_use,
+ avdt_scb_set_remove,
+ avdt_scb_free_pkt,
+ avdt_scb_clr_pkt,
+ avdt_scb_chk_snd_pkt,
+ avdt_scb_tc_timer,
+ avdt_scb_clr_vars,
+ avdt_scb_dealloc
+};
+
+/* state table information */
+#define AVDT_SCB_ACTIONS 2 /* number of actions */
+#define AVDT_SCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_SCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const UINT8 avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_DEALLOC, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_SND_SETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_SETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_NOT_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_HDL_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_CLR_VARS, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
+};
+
+/* state table for configured state */
+const UINT8 avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CONF_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_SND_OPEN_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_SND_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_HDL_OPEN_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_HDL_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_HDL_OPEN_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const UINT8 avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for open state */
+const UINT8 avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_SND_RECONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_SND_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_HDL_START_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_HDL_RECONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#if AVDT_REPORTING == TRUE
+/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#else
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#endif
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for streaming state */
+const UINT8 avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_HDL_WRITE_REQ, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_CLR_PKT, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_HDL_SUSPEND_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_HDL_PKT, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for closing state */
+const UINT8 avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = {
+/* Event Action 1 Action 2 Next state */
+/* API_REMOVE_EVT */ {AVDT_SCB_SET_REMOVE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_CLOSE_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_TOUT_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+/* CC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS];
+
+/* state table */
+const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = {
+ avdt_scb_st_idle,
+ avdt_scb_st_conf,
+ avdt_scb_st_opening,
+ avdt_scb_st_open,
+ avdt_scb_st_stream,
+ avdt_scb_st_closing
+};
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_event
+**
+** Description State machine event handling function for scb
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_SCB_ST_TBL state_table;
+ UINT8 action;
+ int i;
+
+#if AVDT_DEBUG == TRUE
+ AVDT_TRACE_EVENT("SCB hdl=%d event=%d/%s state=%s", avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state]);
+#endif
+ /* set current event */
+ p_scb->curr_evt = event;
+
+ /* look up the state table for the current state */
+ state_table = avdt_scb_st_tbl[p_scb->state];
+
+ /* set next state */
+ if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE]) {
+ p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE];
+ }
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_SCB_ACTIONS; i++)
+ {
+ if ((action = state_table[event][i]) != AVDT_SCB_IGNORE)
+ {
+ (*avdt_cb.p_scb_act[action])(p_scb, p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_init
+**
+** Description Initialize stream control block module.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_init(void)
+{
+ memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
+ avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action;
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_alloc
+**
+** Description Allocate a stream control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
+{
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+
+ /* find available scb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if (!p_scb->allocated)
+ {
+ memset(p_scb,0,sizeof(tAVDT_SCB));
+ p_scb->allocated = TRUE;
+ p_scb->p_ccb = NULL;
+
+ /* initialize sink as activated */
+ if (p_cs->tsep == AVDT_TSEP_SNK)
+ {
+ p_scb->sink_activated = TRUE;
+ }
+
+ memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
+#if AVDT_MULTIPLEXING == TRUE
+ /* initialize fragments gueue */
+ GKI_init_q(&p_scb->frag_q);
+
+ if(p_cs->cfg.psc_mask & AVDT_PSC_MUX)
+ {
+ p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+#if AVDT_REPORTING == TRUE
+ if(p_cs->cfg.psc_mask & AVDT_PSC_REPORT)
+ {
+ p_scb->cs.cfg.mux_tcid_report = avdt_ad_type_to_tcid(AVDT_CHAN_REPORT, p_scb);
+ }
+#endif
+ }
+#endif
+ p_scb->timer_entry.param = (UINT32) p_scb;
+ AVDT_TRACE_DEBUG("avdt_scb_alloc hdl=%d, psc_mask:0x%x", i+1, p_cs->cfg.psc_mask);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_SEPS)
+ {
+ /* out of ccbs */
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("Out of scbs");
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_dealloc
+**
+** Description Deallocate a stream control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ void *p_buf;
+#endif
+ UNUSED(p_data);
+
+ AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d", avdt_scb_to_hdl(p_scb));
+ btu_stop_timer(&p_scb->timer_entry);
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* free fragments we're holding, if any; it shouldn't happen */
+ while ((p_buf = GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_buf);
+#endif
+
+ memset(p_scb, 0, sizeof(tAVDT_SCB));
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_to_hdl
+**
+** Description Given a pointer to an scb, return its handle (or seid).
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb)
+{
+ return (UINT8) (p_scb - avdt_cb.scb + 1);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_by_hdl
+**
+** Description Given an scb handle (or seid), return a pointer to the scb.
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl)
+{
+ tAVDT_SCB *p_scb;
+
+ /* verify index */
+ if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS))
+ {
+ p_scb = &avdt_cb.scb[hdl - 1];
+
+ /* verify scb is allocated */
+ if (!p_scb->allocated)
+ {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("scb hdl %d not allocated", hdl);
+ }
+ }
+ else
+ {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("scb hdl %d out of range", hdl);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_verify
+**
+** Description Verify the condition of a list of scbs.
+**
+**
+** Returns SEID that failed, or 0 if success.
+**
+*******************************************************************************/
+UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ UINT8 nsc_mask;
+ UINT8 ret = 0;
+
+ AVDT_TRACE_DEBUG("avdt_scb_verify state %d", state);
+ /* set nonsupported command mask */
+ /* translate public state into private state */
+ nsc_mask = 0;
+ if (state == AVDT_VERIFY_SUSPEND)
+ nsc_mask = AVDT_NSC_SUSPEND;
+
+ /* verify every scb */
+ for (i = 0, *p_err_code = 0; (i < num_seid) && (*p_err_code == 0) && (i < AVDT_NUM_SEPS); i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_seid[i])) == NULL)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ else if (p_scb->p_ccb != p_ccb)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ else if (p_scb->cs.nsc_mask & nsc_mask)
+ *p_err_code = AVDT_ERR_NSC;
+
+ switch (state) {
+ case AVDT_VERIFY_OPEN:
+ case AVDT_VERIFY_START:
+ if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+
+ case AVDT_VERIFY_SUSPEND:
+ case AVDT_VERIFY_STREAMING:
+ if (p_scb->state != AVDT_SCB_STREAM_ST)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+ }
+ }
+
+ if ((i != num_seid) && (i < AVDT_NUM_SEPS))
+ {
+ ret = p_seid[i];
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_peer_seid_list
+**
+** Description Given a list of SCB handles, return a list of peer SEIDs
+** for the handles, copied in place into the struct passed in.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+
+ for (i = 0; i < p_multi->num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_multi->seid_list[i])) != NULL)
+ {
+ p_multi->seid_list[i] = p_scb->peer_seid;
+ }
+ }
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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 the action functions associated with the stream
+ * control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+
+/* This table is used to lookup the callback event that matches a particular
+** state machine API request event. Note that state machine API request
+** events are at the beginning of the event list starting at zero, thus
+** allowing for this table.
+*/
+const UINT8 avdt_scb_cback_evt[] = {
+ 0, /* API_REMOVE_EVT (no event) */
+ AVDT_WRITE_CFM_EVT, /* API_WRITE_REQ_EVT */
+ 0, /* API_GETCONFIG_REQ_EVT (no event) */
+ 0, /* API_DELAY_RPT_REQ_EVT (no event) */
+ AVDT_OPEN_CFM_EVT, /* API_SETCONFIG_REQ_EVT */
+ AVDT_OPEN_CFM_EVT, /* API_OPEN_REQ_EVT */
+ AVDT_CLOSE_CFM_EVT, /* API_CLOSE_REQ_EVT */
+ AVDT_RECONFIG_CFM_EVT, /* API_RECONFIG_REQ_EVT */
+ AVDT_SECURITY_CFM_EVT, /* API_SECURITY_REQ_EVT */
+ 0 /* API_ABORT_REQ_EVT (no event) */
+};
+
+/* This table is used to look up the callback event based on the signaling
+** role when the stream is closed.
+*/
+const UINT8 avdt_scb_role_evt[] = {
+ AVDT_CLOSE_IND_EVT, /* AVDT_CLOSE_ACP */
+ AVDT_CLOSE_CFM_EVT, /* AVDT_CLOSE_INT */
+ AVDT_CLOSE_IND_EVT, /* AVDT_OPEN_ACP */
+ AVDT_OPEN_CFM_EVT /* AVDT_OPEN_INT */
+};
+
+/*******************************************************************************
+**
+** Function avdt_scb_gen_ssrc
+**
+** Description This function generates a SSRC number unique to the stream.
+**
+** Returns SSRC value.
+**
+*******************************************************************************/
+UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb)
+{
+ /* combine the value of the media type and codec type of the SCB */
+ return ((UINT32)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_abort_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT
+** to initiate sending of an abort response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_abort_rsp
+**
+** Description This function is an empty function; it serves as a
+** placeholder for a conformance API action function.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+ UNUSED(p_data);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_close_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT
+** to initiate sending of a close response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_close_rsp
+**
+** Description This function sets the close_code variable to the error
+** code returned in the close response.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->close_code = p_data->msg.hdr.err_code;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_getconfig_cmd
+**
+** Description This function retrieves the configuration parameters of
+** the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT
+** to initiate sending of a get configuration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb,tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_getconfig_rsp
+**
+** Description This function is an empty function; it serves as a
+** placeholder for a conformance API action function.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+ UNUSED(p_data);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_cmd
+**
+** Description This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT
+** to initiate sending of an open response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_rej
+**
+** Description This function calls the application callback function
+** indicating the open request has failed. It initializes
+** certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT
+** to the CCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* do exactly same as setconfig reject */
+ avdt_scb_hdl_setconfig_rej(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_open_rsp
+**
+** Description This function calls avdt_ad_open_req() to initiate
+** connection of the transport channel for this stream.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ /* initiate opening of trans channels for this SEID */
+ p_scb->role = AVDT_OPEN_INT;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
+
+ /* start tc connect timer */
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt_no_frag
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p, *p_start;
+ UINT8 o_v, o_p, o_x, o_cc;
+ UINT8 m_pt;
+ UINT8 marker;
+ UINT16 seq;
+ UINT32 time_stamp;
+ UINT16 offset;
+ UINT16 ex_len;
+ UINT8 pad_len = 0;
+
+ p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+
+ /* parse media packet header */
+ AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
+ AVDT_MSG_PRS_M_PT(p, m_pt, marker);
+ BE_STREAM_TO_UINT16(seq, p);
+ BE_STREAM_TO_UINT32(time_stamp, p);
+ p += 4;
+
+ UNUSED(o_v);
+
+ /* skip over any csrc's in packet */
+ p += o_cc * 4;
+
+ /* check for and skip over extension header */
+ if (o_x)
+ {
+ p += 2;
+ BE_STREAM_TO_UINT16(ex_len, p);
+ p += ex_len * 4;
+ }
+
+ /* save our new offset */
+ offset = (UINT16) (p - p_start);
+
+ /* adjust length for any padding at end of packet */
+ if (o_p)
+ {
+ /* padding length in last byte of packet */
+ pad_len = *(p_start + p_data->p_pkt->len);
+ }
+
+ /* do sanity check */
+ if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len))
+ {
+ AVDT_TRACE_WARNING("Got bad media packet");
+ GKI_freebuf(p_data->p_pkt);
+ }
+ /* adjust offset and length and send it up */
+ else
+ {
+ p_data->p_pkt->len -= (offset + pad_len);
+ p_data->p_pkt->offset += offset;
+
+ if (p_scb->cs.p_data_cback != NULL)
+ {
+ /* report sequence number */
+ p_data->p_pkt->layer_specific = seq;
+ (*p_scb->cs.p_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
+ time_stamp, (UINT8)(m_pt | (marker<<7)));
+ }
+ else
+ {
+#if AVDT_MULTIPLEXING == TRUE
+ if ((p_scb->cs.p_media_cback != NULL)
+ && (p_scb->p_media_buf != NULL)
+ && (p_scb->media_buf_len > p_data->p_pkt->len))
+ {
+ /* media buffer enough length is assigned by application. Lets use it*/
+ memcpy(p_scb->p_media_buf,(UINT8*)(p_data->p_pkt + 1) + p_data->p_pkt->offset,
+ p_data->p_pkt->len);
+ (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb),p_scb->p_media_buf,
+ p_scb->media_buf_len,time_stamp,seq,m_pt,marker);
+ }
+#endif
+ GKI_freebuf(p_data->p_pkt);
+ }
+ }
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_report
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
+{
+ UINT16 result = AVDT_SUCCESS;
+ UINT8 *p_start = p;
+ UINT32 ssrc;
+ UINT8 o_v, o_p, o_cc;
+ AVDT_REPORT_TYPE pt;
+ tAVDT_REPORT_DATA report, *p_rpt;
+
+ AVDT_TRACE_DEBUG( "avdt_scb_hdl_report");
+ if(p_scb->cs.p_report_cback)
+ {
+ p_rpt = &report;
+ /* parse report packet header */
+ AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
+ pt = *p++;
+ p += 2;
+ BE_STREAM_TO_UINT32(ssrc, p);
+
+ UNUSED(o_p);
+ UNUSED(o_v);
+
+ switch(pt)
+ {
+ case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */
+ BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
+ BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
+ BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
+ BE_STREAM_TO_UINT32(report.sr.pkt_count, p);
+ BE_STREAM_TO_UINT32(report.sr.octet_count, p);
+ break;
+
+ case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */
+ report.rr.frag_lost = *p;
+ BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
+ report.rr.packet_lost &= 0xFFFFFF;
+ BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p);
+ BE_STREAM_TO_UINT32(report.rr.jitter, p);
+ BE_STREAM_TO_UINT32(report.rr.lsr, p);
+ BE_STREAM_TO_UINT32(report.rr.dlsr, p);
+ break;
+
+ case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
+ if(*p == AVDT_RTCP_SDES_CNAME)
+ {
+ p_rpt = (tAVDT_REPORT_DATA *)(p+2);
+ }
+ else
+ {
+ AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s",
+ ssrc, o_cc, *p, *(p+1), p+2);
+ result = AVDT_BUSY;
+ }
+ break;
+
+ default:
+ AVDT_TRACE_ERROR( "Bad Report pkt - packet type: %d", pt);
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if(result == AVDT_SUCCESS)
+ (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
+
+ }
+ p_start += len;
+ return p_start;
+}
+#endif
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt_frag
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* Fields of Adaptation Layer Header */
+ UINT8 al_tsid,al_frag,al_lcode;
+ UINT16 al_len;
+ /* media header fields */
+ UINT8 o_v, o_p, o_x, o_cc;
+ UINT8 m_pt;
+ UINT8 marker;
+ UINT16 seq;
+ UINT32 time_stamp;
+ UINT32 ssrc;
+ UINT16 ex_len;
+ UINT8 pad_len;
+ /* other variables */
+ UINT8 *p; /* current pointer */
+ UINT8 *p_end; /* end of all packet */
+ UINT8 *p_payload; /* pointer to media fragment payload in the buffer */
+ UINT32 payload_len; /* payload length */
+ UINT16 frag_len; /* fragment length */
+
+ p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+ p_end = p + p_data->p_pkt->len;
+ /* parse all fragments */
+ while(p < p_end)
+ {
+ if (p_end - p < 4) /* length check. maximum length of AL header = 4 */
+ {
+ AVDT_TRACE_WARNING("p_end: 0x%x - p:0x%x < 4", p_end, p);
+ break;
+ }
+
+ /* parse first byte */
+ al_tsid = (*p)>>3;
+ al_frag = ( (*p) >> 2 ) & 0x01;
+ al_lcode = (*p++) & AVDT_ALH_LCODE_MASK;
+
+ /* in case of TSID=00000, a second AL header byte, before the length field,
+ ** is expected and contains the actual TSID, aligned with MSB */
+ if(al_tsid == 0)
+ al_tsid = *p++;
+
+ /* get remaining media length on base of lcode */
+ switch(al_lcode)
+ {
+ case AVDT_ALH_LCODE_NONE: /* No length field present. Take length from l2cap */
+ al_len = (UINT16)(p_end - p);
+ break;
+ case AVDT_ALH_LCODE_16BIT: /* 16 bit length field */
+ BE_STREAM_TO_UINT16(al_len, p);
+ break;
+ case AVDT_ALH_LCODE_9BITM0: /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
+ al_len = *p++;
+ break;
+ default: /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
+ al_len =(UINT16)*p++ + 0x100;
+ }
+
+ /* max fragment length */
+ frag_len = (UINT16)(p_end - p);
+ /* if it isn't last fragment */
+ if(frag_len >= al_len)
+ frag_len = al_len;
+
+ /* check TSID corresponds to config */
+ if (al_tsid != p_scb->curr_cfg.mux_tsid_media)
+ {
+#if AVDT_REPORTING == TRUE
+ if((p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) &&
+ (al_tsid == p_scb->curr_cfg.mux_tsid_report))
+ {
+ /* parse reporting packet */
+ p = avdt_scb_hdl_report(p_scb, p, frag_len);
+ continue;
+ }
+ else
+#endif
+ {
+ AVDT_TRACE_WARNING("bad tsid: %d, mux_tsid_media:%d", al_tsid, p_scb->curr_cfg.mux_tsid_media);
+ break;
+ }
+ }
+ /* check are buffer for assembling and related callback set */
+ else if ((p_scb->p_media_buf == NULL) || (p_scb->cs.p_media_cback == NULL))
+ {
+ AVDT_TRACE_WARNING("NULL p_media_buf or p_media_cback");
+ break;
+ }
+
+
+ /* it is media fragment beginning */
+ if(!al_frag) /* is it first fragment of original media packet */
+ {
+ AVDT_TRACE_DEBUG("al:%d media:%d",
+ al_len, p_scb->media_buf_len);
+
+ p_scb->frag_off = 0;
+ p_scb->frag_org_len = al_len; /* total length of original media packet */
+ /* length check: minimum length of media header is 12 */
+ if (p_scb->frag_org_len < 12)
+ {
+ AVDT_TRACE_WARNING("bad al_len: %d(<12)", al_len);
+ break;
+ }
+ /* check that data fit into buffer */
+ if (al_len > p_scb->media_buf_len)
+ {
+ AVDT_TRACE_WARNING("bad al_len: %d(>%d)", al_len, p_scb->media_buf_len);
+ break;
+ }
+ /* make sure it is the last fragment in l2cap packet */
+ if (p + al_len < p_end)
+ {
+ AVDT_TRACE_WARNING("bad al_len: %d(>%d)", al_len, p_scb->media_buf_len);
+ break;
+ }
+ }
+ else
+ {
+ AVDT_TRACE_DEBUG("al:%d media:%d frag_org_len:%d frag_off:%d",
+ al_len, p_scb->media_buf_len, p_scb->frag_org_len, p_scb->frag_off);
+
+ /* check that remaining length from AL header equals to original len - length of already received fragments */
+ if(al_len != p_scb->frag_org_len - p_scb->frag_off)
+ {
+ AVDT_TRACE_WARNING("al_len:%d != (frag_org_len:%d - frag_off:%d) %d",
+ al_len, p_scb->frag_org_len, p_scb->frag_off,
+ (p_scb->frag_org_len- p_scb->frag_off));
+ break;
+ }
+
+ /* do sanity check */
+ if (p_scb->frag_off == 0)
+ {
+ AVDT_TRACE_WARNING("frag_off=0");
+ break;
+ }
+ }
+ /* do common sanity check */
+ if((p_scb->frag_org_len <= p_scb->frag_off) || (p_scb->frag_org_len >= p_scb->media_buf_len))
+ {
+ AVDT_TRACE_WARNING("common sanity frag_off:%d frag_org_len:%d media_buf_len:%d",
+ p_scb->frag_off, p_scb->frag_org_len, p_scb->media_buf_len);
+ break;
+ }
+
+ AVDT_TRACE_DEBUG("Received fragment org_len=%d off=%d al_len=%d frag_len=%d",
+ p_scb->frag_org_len, p_scb->frag_off, al_len, frag_len);
+
+ /* copy fragment into buffer */
+ memcpy(p_scb->p_media_buf + p_scb->frag_off, p, frag_len);
+ p_scb->frag_off += frag_len;
+ /* move to the next fragment */
+ p += frag_len;
+ /* if it is last fragment in original media packet then process total media pocket */
+ if(p_scb->frag_off == p_scb->frag_org_len)
+ {
+ p_payload = p_scb->p_media_buf;
+
+ /* media header */
+ AVDT_MSG_PRS_OCTET1(p_payload, o_v, o_p, o_x, o_cc);
+ AVDT_MSG_PRS_M_PT(p_payload, m_pt, marker);
+ BE_STREAM_TO_UINT16(seq, p_payload);
+ BE_STREAM_TO_UINT32(time_stamp, p_payload);
+ BE_STREAM_TO_UINT32(ssrc, p_payload);
+
+ UNUSED(o_v);
+ UNUSED(ssrc);
+
+ /* skip over any csrc's in packet */
+ p_payload += o_cc * 4;
+
+ /* check for and skip over extension header */
+ if (o_x)
+ {
+ if(p_scb->p_media_buf + p_scb->frag_off - p_payload < 4)
+ {
+ AVDT_TRACE_WARNING("length check frag_off:%d p_media_buf:%d p_payload:%d",
+ p_scb->frag_off, p_scb->p_media_buf, p_payload);
+ break;/* length check */
+ }
+ p_payload += 2;
+ BE_STREAM_TO_UINT16(ex_len, p_payload);
+ p_payload += ex_len * 4;
+ }
+
+ if(p_payload >= p_scb->p_media_buf + p_scb->frag_off)
+ {
+ AVDT_TRACE_WARNING("length check2 frag_off:%d p_media_buf:%d p_payload:%d",
+ p_scb->frag_off, p_scb->p_media_buf, p_payload);
+ break;/* length check */
+ }
+
+ /* adjust length for any padding at end of packet */
+ if (o_p)
+ {
+ /* padding length in last byte of packet */
+ pad_len = *(p_scb->p_media_buf + p_scb->frag_off - 1);
+ }
+ else
+ pad_len = 0;
+ /* payload length */
+ payload_len = (UINT32)(p_scb->p_media_buf + p_scb->frag_off - pad_len - p_payload);
+
+ AVDT_TRACE_DEBUG("Received last fragment header=%d len=%d",
+ p_payload - p_scb->p_media_buf,payload_len);
+
+ /* send total media packet up */
+ if (p_scb->cs.p_media_cback != NULL)
+ {
+ (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_payload,
+ payload_len, time_stamp, seq, m_pt, marker);
+ }
+ }
+ } /* while(p < p_end) */
+
+ if(p < p_end)
+ {
+ AVDT_TRACE_WARNING("*** Got bad media packet");
+ }
+ GKI_freebuf(p_data->p_pkt);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_pkt
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_REPORTING == TRUE
+ UINT8 *p;
+#endif
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* select right function in dependance of is fragmentation supported or not */
+ if( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX))
+ {
+ avdt_scb_hdl_pkt_frag(p_scb, p_data);
+ }
+ else
+#endif
+#if AVDT_REPORTING == TRUE
+ if(p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT)
+ {
+ p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+ avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
+ GKI_freebuf(p_data->p_pkt);
+ }
+ else
+#endif
+ avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_drop_pkt
+**
+** Description Drop an incoming media packet. This function is called if
+** a media packet is received in any state besides streaming.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+
+ GKI_freebuf(p_data->p_pkt);
+ AVDT_TRACE_ERROR(" avdt_scb_drop_pkt Dropped incoming media packet");
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_reconfig_cmd
+**
+** Description This function calls the application callback function
+** with a reconfiguration indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG)
+ {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ p_data->msg.hdr.err_param = 0;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* store requested configuration */
+ memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_RECONFIG_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.reconfig_cmd);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_reconfig_rsp
+**
+** Description This function calls the application callback function
+** with a reconfiguration confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0)
+ {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0)
+ {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+ }
+ }
+
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_RECONFIG_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.svccap);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_security_cmd
+**
+** Description This function calls the application callback with a
+** security indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY)
+ {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_SECURITY_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.security_cmd);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_security_rsp
+**
+** Description This function calls the application callback with a
+** security confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_SECURITY_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.security_cmd);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_cmd
+**
+** Description This function marks the SCB as in use and copies the
+** configuration and peer SEID to the SCB. It then calls
+** the application callback with a configuration indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CFG *p_cfg;
+
+ if (!p_scb->in_use)
+ {
+ p_cfg = p_data->msg.config_cmd.p_cfg;
+ if(p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == p_cfg->codec_info[AVDT_CODEC_TYPE_INDEX])
+ {
+ /* set sep as in use */
+ p_scb->in_use = TRUE;
+
+ /* copy info to scb */
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
+ memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_CONFIG_IND_EVT,
+ (tAVDT_CTRL *) &p_data->msg.config_cmd);
+ }
+ else
+ {
+ p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+ }
+ }
+ else
+ {
+ avdt_scb_rej_in_use(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_rej
+**
+** Description This function marks the SCB as not in use and calls the
+** application callback with an open confirm indicating failure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_CCB_UL_CLOSE_EVT, NULL);
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ AVDT_OPEN_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_setconfig_rsp
+**
+** Description This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
+** to initiate sending of an open command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR single;
+ UNUSED(p_data);
+
+ if (p_scb->p_ccb != NULL)
+ {
+ /* save configuration */
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ /* initiate open */
+ single.seid = p_scb->peer_seid;
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_start_cmd
+**
+** Description This function calls the application callback with a
+** start indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_IND_EVT,
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_start_rsp
+**
+** Description This function calls the application callback with a
+** start confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_suspend_cmd
+**
+** Description This function calls the application callback with a suspend
+** indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_IND_EVT,
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_suspend_rsp
+**
+** Description This function calls the application callback with a suspend
+** confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_close
+**
+** Description This function is called when the transport channel is
+** closed. It marks the SCB as not in use and
+** initializes certain SCB parameters. It then sends
+** an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB
+** initiated the close. It then checks to see if the SCB
+** is to be removed. If it is it deallocates the SCB. Finally,
+** it calls the application callback with a close indication.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 hdl = avdt_scb_to_hdl(p_scb);
+ tAVDT_CTRL_CBACK *p_ctrl_cback = p_scb->cs.p_ctrl_cback;
+ tAVDT_CTRL avdt_ctrl;
+ UINT8 event;
+ tAVDT_CCB *p_ccb = p_scb->p_ccb;
+ BD_ADDR remote_addr;
+
+
+ memcpy (remote_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* set up hdr */
+ avdt_ctrl.hdr.err_code = p_scb->close_code;
+
+ /* clear sep variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ p_scb->media_seq = 0;
+ p_scb->cong = FALSE;
+
+ /* free pkt we're holding, if any */
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+ }
+
+ /* stop transport channel timer */
+ btu_stop_timer(&p_scb->timer_entry);
+
+ if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT))
+ {
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
+ }
+ event = (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT;
+ p_scb->role = AVDT_CLOSE_ACP;
+
+ if (p_scb->remove)
+ {
+ avdt_scb_dealloc(p_scb, NULL);
+ }
+
+ /* call app callback */
+ (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_delay_rpt_req
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_delay_rpt_req (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT, (tAVDT_MSG *) &p_data->apidelay);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_delay_rpt_cmd
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_cmd (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+
+ if (p_scb->p_ccb)
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
+ else
+ avdt_scb_rej_not_in_use(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_delay_rpt_rsp
+**
+** Description This function calls the application callback with a delay
+** report.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_rsp (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_CFM_EVT,
+ (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_close_sto
+**
+** Description This function is called when a channel is closed in OPEN
+** state. Check the channel type and process accordingly.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ /* AVDT_CHAN_SIG does not visit this action */
+ if(p_data && p_data->close.type != AVDT_CHAN_MEDIA)
+ {
+ /* it's reporting or recovery channel,
+ * the channel close in open state means the peer does not support it */
+ if(p_data->close.old_tc_state == AVDT_AD_ST_OPEN)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 0;
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
+ }
+ }
+ else
+ {
+ /* must be in OPEN state. need to go back to idle */
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL);
+ avdt_scb_hdl_tc_close(p_scb, p_data);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_open
+**
+** Description This function is called when the transport channel is
+** opened while in the opening state. It calls the
+** application callback with an open indication or open
+** confirm depending on who initiated the open procedure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 event;
+#if AVDT_REPORTING == TRUE
+ UINT8 role;
+#endif
+
+ /* stop transport channel connect timer */
+ btu_stop_timer(&p_scb->timer_entry);
+
+ event = (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
+ p_data->open.hdr.err_code = 0;
+
+ AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x",
+ p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask, p_scb->curr_cfg.psc_mask);
+#if AVDT_REPORTING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+ {
+ /* open the reporting channel, if both devices support it */
+ role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
+ avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
+ }
+#endif
+
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ event,
+ (tAVDT_CTRL *) &p_data->open);
+}
+
+#if AVDT_REPORTING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_tc_open_sto
+**
+** Description This function is called when the transport channel is
+** opened while in the opening state. It calls the
+** application callback with an open indication or open
+** confirm depending on who initiated the open procedure.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ /* open reporting channel here, when it is implemented */
+
+ /* call app callback */
+ if(p_data->open.hdr.err_code == AVDT_CHAN_REPORT)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 1;
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_CONN_EVT, &avdt_ctrl);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req_no_frag
+**
+** Description This function frees the media packet currently stored in
+** the SCB, if any. Then it builds a new media packet from
+** with the passed in buffer and stores it in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT32 ssrc;
+
+ /* free packet we're holding, if any; to be replaced with new */
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+
+ /* this shouldn't be happening */
+ AVDT_TRACE_WARNING("Dropped media packet; congested");
+ }
+
+ /* build a media packet */
+ /* Add RTP header if required */
+ if ( !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP) )
+ {
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+
+ p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE;
+ p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE;
+ p_scb->media_seq++;
+ p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset;
+
+ UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+ UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+ UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+ UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+ UINT32_TO_BE_STREAM(p, ssrc);
+ }
+
+ /* store it */
+ p_scb->p_pkt = p_data->apiwrite.p_buf;
+}
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req_frag
+**
+** Description This function builds a new fragments of media packet from
+** the passed in buffers and stores them in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT32 ssrc;
+ BT_HDR *p_frag;
+
+ /* free fragments we're holding, if any; it shouldn't happen */
+ if (!GKI_queue_is_empty(&p_scb->frag_q))
+ {
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+
+ /* this shouldn't be happening */
+ AVDT_TRACE_WARNING("*** Dropped media packet; congested");
+ }
+
+ /* build a media fragments */
+ p_scb->frag_off = p_data->apiwrite.data_len;
+ p_scb->p_next_frag = p_data->apiwrite.p_data;
+
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+
+ /* get first packet */
+ p_frag = (BT_HDR*)GKI_getfirst (&p_data->apiwrite.frag_q);
+ /* posit on Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+
+ /* Adaptation Layer header */
+ /* TSID, no-fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | AVDT_ALH_LCODE_16BIT;
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific+AVDT_MEDIA_HDR_SIZE );
+ /* media header */
+ UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+ UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+ UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+ UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+ UINT32_TO_BE_STREAM(p, ssrc);
+ p_scb->media_seq++;
+
+ while((p_frag = (BT_HDR*)GKI_getnext (p_frag)) != NULL)
+ {
+ /* posit on Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+ /* Adaptation Layer header */
+ /* TSID, fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
+ }
+
+ /* store it */
+ p_scb->frag_q = p_data->apiwrite.frag_q;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_hdl_write_req
+**
+** Description This function calls one of the two versions of building functions
+** for case with and without fragmentation
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ if (GKI_queue_is_empty(&p_data->apiwrite.frag_q))
+#endif
+ avdt_scb_hdl_write_req_no_frag(p_scb, p_data);
+#if AVDT_MULTIPLEXING == TRUE
+ else
+ avdt_scb_hdl_write_req_frag(p_scb, p_data);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_abort_req
+**
+** Description This function sends an abort command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+ UNUSED(p_data);
+
+ if (p_scb->p_ccb != NULL)
+ {
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG *) &hdr);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_abort_rsp
+**
+** Description This function sends an abort response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+
+ avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
+ &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_close_req
+**
+** Description This function sends a close command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+ UNUSED(p_data);
+
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_stream_close
+**
+** Description This function sends a close command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+
+ AVDT_TRACE_WARNING("avdt_scb_snd_stream_close c:%d, off:%d",
+ GKI_queue_length(&p_scb->frag_q), p_scb->frag_off);
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+ p_scb->frag_off = 0;
+#endif
+ if (p_scb->p_pkt)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+ }
+
+#if 0
+ if(p_scb->cong)
+ p_scb->cong = FALSE;
+
+ /* p_scb->curr_cfg.mux_tsid_media == 0 */
+#endif
+ avdt_scb_snd_close_req(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_close_rsp
+**
+** Description This function sends a close response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_getconfig_req
+**
+** Description This function sends a get configuration command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+ UNUSED(p_data);
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_getconfig_rsp
+**
+** Description This function sends a get configuration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_open_req
+**
+** Description This function sends an open command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_EVT_HDR hdr;
+ UNUSED(p_data);
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_open_rsp
+**
+** Description This function sends an open response message. It also
+** calls avdt_ad_open_req() to accept a transport channel
+** connection.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ /* notify adaption that we're waiting for transport channel open */
+ p_scb->role = AVDT_OPEN_ACP;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg);
+
+ /* start tc connect timer */
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_reconfig_req
+**
+** Description This function stores the configuration parameters in the
+** SCB and sends a reconfiguration command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_reconfig_rsp
+**
+** Description This function stores the configuration parameters in the
+** SCB and sends a reconfiguration response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0)
+ {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0)
+ {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+ }
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ }
+ else
+ {
+ /* send reject */
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_security_req
+**
+** Description This function sends a security command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_security_rsp
+**
+** Description This function sends a security response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_data->msg.hdr.err_code == 0)
+ {
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ }
+ else
+ {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_rej
+**
+** Description This function marks the SCB as not in use and sends a
+** set configuration reject message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_scb->p_ccb != NULL)
+ {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_req
+**
+** Description This function marks the SCB as in use and copies the
+** configuration parameters to the SCB. Then the function
+** sends a set configuration command message and initiates
+** opening of the signaling channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CFG *p_req, *p_cfg;
+
+ /* copy API parameters to scb, set scb as in use */
+ p_scb->in_use = TRUE;
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
+ p_req = p_data->msg.config_cmd.p_cfg;
+ p_cfg = &p_scb->cs.cfg;
+#if AVDT_MULTIPLEXING == TRUE
+ p_req->mux_tsid_media = p_cfg->mux_tsid_media;
+ p_req->mux_tcid_media = p_cfg->mux_tcid_media;
+ if(p_req->psc_mask & AVDT_PSC_REPORT)
+ {
+ p_req->mux_tsid_report = p_cfg->mux_tsid_report;
+ p_req->mux_tcid_report = p_cfg->mux_tcid_report;
+ }
+#endif
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* tell ccb to open channel */
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_setconfig_rsp
+**
+** Description This function copies the requested configuration into the
+** current configuration and sends a set configuration
+** response message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ if (p_scb->p_ccb != NULL)
+ {
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_snd_tc_close
+**
+** Description This function calls avdt_ad_close_req() to close the
+** transport channel for this SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+#if AVDT_REPORTING == TRUE
+ if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+ avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+#endif
+ avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_cb_err
+**
+** Description This function calls the application callback function
+** indicating an error.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ UNUSED(p_data);
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ /* call callback, using lookup table to get callback event */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ NULL,
+ avdt_scb_cback_evt[p_scb->curr_evt],
+ &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_cong_state
+**
+** Description This function sets the congestion state of the SCB media
+** transport channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ p_scb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_state
+**
+** Description This function sends a reject message to the peer indicating
+** incorrect state for the received command message.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+
+ p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_in_use
+**
+** Description This function sends a reject message to the peer indicating
+** the stream is in use.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+
+ p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_rej_not_in_use
+**
+** Description This function sends a reject message to the peer indicating
+** the stream is in use.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_scb);
+
+ p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_set_remove
+**
+** Description This function marks an SCB to be removed.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ p_scb->remove = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_free_pkt
+**
+** Description This function frees the media packet passed in.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+#endif
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ /* p_buf can be NULL in case using of fragments queue frag_q */
+ if(p_data->apiwrite.p_buf)
+ GKI_freebuf(p_data->apiwrite.p_buf);
+
+#if AVDT_MULTIPLEXING == TRUE
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_data->apiwrite.frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+#endif
+
+ AVDT_TRACE_WARNING("Dropped media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_clr_pkt
+**
+** Description This function frees the media packet stored in the SCB.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ tAVDT_CCB *p_ccb;
+ UINT8 tcid;
+ UINT16 lcid;
+#if AVDT_MULTIPLEXING == TRUE
+ BT_HDR *p_frag;
+#endif
+ UNUSED(p_data);
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+ /* flush the media data queued at L2CAP */
+ if((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;
+ L2CA_FlushChannel (lcid, L2CAP_FLUSH_CHANS_ALL);
+ }
+
+ if (p_scb->p_pkt != NULL)
+ {
+ GKI_freebuf(p_scb->p_pkt);
+ p_scb->p_pkt = NULL;
+
+ AVDT_TRACE_DEBUG("Dropped stored media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+ }
+#if AVDT_MULTIPLEXING == TRUE
+ else if(!GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ AVDT_TRACE_DEBUG("Dropped fragments queue");
+ /* clean fragments queue */
+ while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ GKI_freebuf(p_frag);
+
+ p_scb->frag_off = 0;
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function avdt_scb_chk_snd_pkt
+**
+** Description This function checks if the SCB is congested, and if not
+** congested it sends a stored media packet, if any. After it
+** sends the packet it calls the application callback function
+** with a write confirm.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+ BT_HDR *p_pkt;
+#if AVDT_MULTIPLEXING == TRUE
+ BOOLEAN sent = FALSE;
+ UINT8 res = AVDT_AD_SUCCESS;
+ tAVDT_SCB_EVT data;
+#endif
+ UNUSED(p_data);
+
+ avdt_ctrl.hdr.err_code = 0;
+
+ if (!p_scb->cong)
+ {
+ if (p_scb->p_pkt != NULL)
+ {
+ p_pkt = p_scb->p_pkt;
+ p_scb->p_pkt = NULL;
+ avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+ }
+#if AVDT_MULTIPLEXING == TRUE
+ else
+ {
+#if 0
+ AVDT_TRACE_DEBUG("num_q=%d",
+ L2CA_FlushChannel(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb)].lcid),
+ L2CAP_FLUSH_CHANS_GET);
+#endif
+ while((p_pkt = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
+ {
+ sent = TRUE;
+ AVDT_TRACE_DEBUG("Send fragment len=%d",p_pkt->len);
+ /* fragments queue contains fragment to send */
+ res = avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+ if(AVDT_AD_CONGESTED == res)
+ {
+ p_scb->cong = TRUE;
+ AVDT_TRACE_DEBUG("avdt/l2c congested!!");
+ break;/* exit loop if channel became congested */
+ }
+ }
+ AVDT_TRACE_DEBUG("res=%d left=%d",res, p_scb->frag_off);
+
+ if(p_scb->frag_off)
+ {
+ if(AVDT_AD_SUCCESS == res || GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ /* all buffers were sent to L2CAP, compose more to queue */
+ avdt_scb_queue_frags(p_scb, &p_scb->p_next_frag, &p_scb->frag_off, &p_scb->frag_q);
+ if(!GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ data.llcong = p_scb->cong;
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &data);
+ }
+ }
+ }
+
+ /* Send event AVDT_WRITE_CFM_EVT if it was last fragment */
+ else if (sent && GKI_queue_is_empty (&p_scb->frag_q))
+ {
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+ }
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_tc_timer
+**
+** Description This function is called to start a timer when the peer
+** initiates closing of the stream. The timer verifies that
+** the peer disconnects the transport channel.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_DISC_TOUT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_clr_vars
+**
+** Description This function initializes certain SCB variables.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+ UNUSED(p_data);
+
+ if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (!p_scb->sink_activated))
+ {
+ p_scb->in_use = TRUE;
+ }
+ else
+ {
+ p_scb->in_use = FALSE;
+ }
+ p_scb->p_ccb = NULL;
+ p_scb->peer_seid = 0;
+}
+
+#if AVDT_MULTIPLEXING == TRUE
+/*******************************************************************************
+**
+** Function avdt_scb_queue_frags
+**
+** Description This function breaks media payload into fragments
+** and put the fragments in the given queue.
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq)
+{
+ UINT16 lcid;
+ UINT16 num_frag;
+ UINT16 mtu_used;
+ UINT8 *p;
+ BOOLEAN al_hdr = FALSE;
+ UINT8 tcid;
+ tAVDT_TC_TBL *p_tbl;
+ UINT16 buf_size;
+ UINT16 offset = AVDT_MEDIA_OFFSET + AVDT_AL_HDR_SIZE;
+ UINT16 cont_offset = offset - AVDT_MEDIA_HDR_SIZE;
+ BT_HDR *p_frag;
+
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][tcid].lcid;
+
+ if( p_scb->frag_off != 0)
+ {
+ /* continuing process is usually triggered by un-congest event.
+ * the number of buffers at L2CAP is very small (if not 0).
+ * we do not need to L2CA_FlushChannel() */
+ offset = cont_offset;
+ al_hdr = TRUE;
+ num_frag = AVDT_MAX_FRAG_COUNT;
+ }
+ else
+ {
+ num_frag = L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_GET);
+ AVDT_TRACE_DEBUG("num_q=%d lcid=%d", num_frag, lcid);
+ if(num_frag >= AVDT_MAX_FRAG_COUNT)
+ {
+ num_frag = 0;
+ }
+ else
+ {
+ num_frag = AVDT_MAX_FRAG_COUNT - num_frag;
+ }
+ }
+
+ /* look up transport channel table entry to get peer mtu */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+ buf_size = p_tbl->peer_mtu + BT_HDR_SIZE;
+ AVDT_TRACE_DEBUG("peer_mtu: %d, buf_size: %d num_frag=%d",
+ p_tbl->peer_mtu, buf_size, num_frag);
+
+ if(buf_size > AVDT_DATA_POOL_SIZE)
+ buf_size = AVDT_DATA_POOL_SIZE;
+
+ mtu_used = buf_size - BT_HDR_SIZE;
+
+ while(*p_data_len && num_frag)
+ {
+ /* allocate buffer for fragment */
+ if(NULL == (p_frag = (BT_HDR*)GKI_getbuf(buf_size)))
+ {
+ AVDT_TRACE_WARNING("avdt_scb_queue_frags len=%d(out of GKI buffers)",*p_data_len);
+ break;
+ }
+ /* fill fragment by chunk of media payload */
+ p_frag->layer_specific = *p_data_len;/* length of all remaining transport packet */
+ p_frag->offset = offset;
+ /* adjust packet offset for continuing packets */
+ offset = cont_offset;
+
+ p_frag->len = mtu_used - p_frag->offset;
+ if(p_frag->len > *p_data_len)
+ p_frag->len = *p_data_len;
+ memcpy((UINT8*)(p_frag+1) + p_frag->offset, *pp_data, p_frag->len);
+ *pp_data += p_frag->len;
+ *p_data_len -= p_frag->len;
+ AVDT_TRACE_DEBUG("Prepared fragment len=%d", p_frag->len);
+
+ if(al_hdr)
+ {
+ /* Adaptation Layer header */
+ p_frag->len += AVDT_AL_HDR_SIZE;
+ p_frag->offset -= AVDT_AL_HDR_SIZE;
+ p = (UINT8 *)(p_frag + 1) + p_frag->offset;
+ /* TSID, fragment bit and coding of length(in 2 length octets following) */
+ *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
+
+ /* length of all remaining transport packet */
+ UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
+ }
+ /* put fragment into gueue */
+ GKI_enqueue(pq, p_frag);
+ num_frag--;
+ }
+}
+#endif
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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 file contains interfaces which are internal to AVDTP.
+ *
+ ******************************************************************************/
+#ifndef AVDT_INT_H
+#define AVDT_INT_H
+
+#include "gki.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_defs.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+#ifndef AVDT_DEBUG
+#define AVDT_DEBUG FALSE
+#endif
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* channel types */
+enum {
+ AVDT_CHAN_SIG, /* signaling channel */
+ AVDT_CHAN_MEDIA, /* media channel */
+#if AVDT_REPORTING == TRUE
+ AVDT_CHAN_REPORT, /* reporting channel */
+#endif
+ AVDT_CHAN_NUM_TYPES
+};
+
+/* protocol service capabilities of this AVDTP implementation */
+/* for now multiplexing will be used only for fragmentation */
+#if ((AVDT_MULTIPLEXING == TRUE) && (AVDT_REPORTING == TRUE))
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT)
+#else /* AVDT_MULTIPLEXING && AVDT_REPORTING */
+
+#if (AVDT_MULTIPLEXING == TRUE)
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX)
+#else /* AVDT_MULTIPLEXING */
+
+#if (AVDT_REPORTING == TRUE)
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
+#else /* AVDT_REPORTING */
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS)
+#endif /* AVDT_REPORTING */
+
+#endif /* AVDT_MULTIPLEXING */
+
+#endif /* AVDT_MULTIPLEXING && AVDT_REPORTING */
+
+/* initiator/acceptor signaling roles */
+#define AVDT_CLOSE_ACP 0
+#define AVDT_CLOSE_INT 1
+#define AVDT_OPEN_ACP 2
+#define AVDT_OPEN_INT 3
+
+/* states for avdt_scb_verify */
+#define AVDT_VERIFY_OPEN 0
+#define AVDT_VERIFY_STREAMING 1
+#define AVDT_VERIFY_SUSPEND 2
+#define AVDT_VERIFY_START 3
+
+/* to distinguish CCB events from SCB events */
+#define AVDT_CCB_MKR 0x80
+
+/* offset where AVDTP signaling message header starts in message */
+#define AVDT_HDR_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS)
+
+/* offset where AVDTP signaling message content starts;
+** use the size of a start header since it's the largest possible
+** layout of signaling message in a buffer is:
+**
+** | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... |
+**
+** Note that we "hide" the scb handles at the top of the message buffer.
+*/
+#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START)
+
+/* scb transport channel connect timeout value */
+#define AVDT_SCB_TC_CONN_TOUT 10
+
+/* scb transport channel disconnect timeout value */
+#define AVDT_SCB_TC_DISC_TOUT 10
+
+/* maximum number of command retransmissions */
+#ifndef AVDT_RET_MAX
+#define AVDT_RET_MAX 1
+#endif
+
+
+/* ccb state machine states */
+enum {
+ AVDT_CCB_IDLE_ST,
+ AVDT_CCB_OPENING_ST,
+ AVDT_CCB_OPEN_ST,
+ AVDT_CCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_CCB_CHAN_OPEN,
+ AVDT_CCB_CHAN_CLOSE,
+ AVDT_CCB_CHK_CLOSE,
+ AVDT_CCB_HDL_DISCOVER_CMD,
+ AVDT_CCB_HDL_DISCOVER_RSP,
+ AVDT_CCB_HDL_GETCAP_CMD,
+ AVDT_CCB_HDL_GETCAP_RSP,
+ AVDT_CCB_HDL_START_CMD,
+ AVDT_CCB_HDL_START_RSP,
+ AVDT_CCB_HDL_SUSPEND_CMD,
+ AVDT_CCB_HDL_SUSPEND_RSP,
+ AVDT_CCB_SND_DISCOVER_CMD,
+ AVDT_CCB_SND_DISCOVER_RSP,
+ AVDT_CCB_SND_GETCAP_CMD,
+ AVDT_CCB_SND_GETCAP_RSP,
+ AVDT_CCB_SND_START_CMD,
+ AVDT_CCB_SND_START_RSP,
+ AVDT_CCB_SND_SUSPEND_CMD,
+ AVDT_CCB_SND_SUSPEND_RSP,
+ AVDT_CCB_CLEAR_CMDS,
+ AVDT_CCB_CMD_FAIL,
+ AVDT_CCB_FREE_CMD,
+ AVDT_CCB_CONG_STATE,
+ AVDT_CCB_RET_CMD,
+ AVDT_CCB_SND_CMD,
+ AVDT_CCB_SND_MSG,
+ AVDT_CCB_SET_RECONN,
+ AVDT_CCB_CLR_RECONN,
+ AVDT_CCB_CHK_RECONN,
+ AVDT_CCB_CHK_TIMER,
+ AVDT_CCB_SET_CONN,
+ AVDT_CCB_SET_DISCONN,
+ AVDT_CCB_DO_DISCONN,
+ AVDT_CCB_LL_CLOSED,
+ AVDT_CCB_LL_OPENED,
+ AVDT_CCB_DEALLOC,
+ AVDT_CCB_NUM_ACTIONS
+};
+
+#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS
+
+/* ccb state machine events */
+enum {
+ AVDT_CCB_API_DISCOVER_REQ_EVT,
+ AVDT_CCB_API_GETCAP_REQ_EVT,
+ AVDT_CCB_API_START_REQ_EVT,
+ AVDT_CCB_API_SUSPEND_REQ_EVT,
+ AVDT_CCB_API_DISCOVER_RSP_EVT,
+ AVDT_CCB_API_GETCAP_RSP_EVT,
+ AVDT_CCB_API_START_RSP_EVT,
+ AVDT_CCB_API_SUSPEND_RSP_EVT,
+ AVDT_CCB_API_CONNECT_REQ_EVT,
+ AVDT_CCB_API_DISCONNECT_REQ_EVT,
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT,
+ AVDT_CCB_MSG_GETCAP_CMD_EVT,
+ AVDT_CCB_MSG_START_CMD_EVT,
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT,
+ AVDT_CCB_MSG_GETCAP_RSP_EVT,
+ AVDT_CCB_MSG_START_RSP_EVT,
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_CCB_RCVRSP_EVT,
+ AVDT_CCB_SENDMSG_EVT,
+ AVDT_CCB_RET_TOUT_EVT,
+ AVDT_CCB_RSP_TOUT_EVT,
+ AVDT_CCB_IDLE_TOUT_EVT,
+ AVDT_CCB_UL_OPEN_EVT,
+ AVDT_CCB_UL_CLOSE_EVT,
+ AVDT_CCB_LL_OPEN_EVT,
+ AVDT_CCB_LL_CLOSE_EVT,
+ AVDT_CCB_LL_CONG_EVT
+};
+
+
+/* scb state machine states; these state values are private to this module so
+** the scb state cannot be read or set by actions functions
+*/
+enum {
+ AVDT_SCB_IDLE_ST,
+ AVDT_SCB_CONF_ST,
+ AVDT_SCB_OPENING_ST,
+ AVDT_SCB_OPEN_ST,
+ AVDT_SCB_STREAM_ST,
+ AVDT_SCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_SCB_HDL_ABORT_CMD,
+ AVDT_SCB_HDL_ABORT_RSP,
+ AVDT_SCB_HDL_CLOSE_CMD,
+ AVDT_SCB_HDL_CLOSE_RSP,
+ AVDT_SCB_HDL_GETCONFIG_CMD,
+ AVDT_SCB_HDL_GETCONFIG_RSP,
+ AVDT_SCB_HDL_OPEN_CMD,
+ AVDT_SCB_HDL_OPEN_REJ,
+ AVDT_SCB_HDL_OPEN_RSP,
+ AVDT_SCB_HDL_PKT,
+ AVDT_SCB_DROP_PKT,
+ AVDT_SCB_HDL_RECONFIG_CMD,
+ AVDT_SCB_HDL_RECONFIG_RSP,
+ AVDT_SCB_HDL_SECURITY_CMD,
+ AVDT_SCB_HDL_SECURITY_RSP,
+ AVDT_SCB_HDL_SETCONFIG_CMD,
+ AVDT_SCB_HDL_SETCONFIG_REJ,
+ AVDT_SCB_HDL_SETCONFIG_RSP,
+ AVDT_SCB_HDL_START_CMD,
+ AVDT_SCB_HDL_START_RSP,
+ AVDT_SCB_HDL_SUSPEND_CMD,
+ AVDT_SCB_HDL_SUSPEND_RSP,
+ AVDT_SCB_HDL_TC_CLOSE,
+#if AVDT_REPORTING == TRUE
+ AVDT_SCB_HDL_TC_CLOSE_STO,
+#endif
+ AVDT_SCB_HDL_TC_OPEN,
+#if AVDT_REPORTING == TRUE
+ AVDT_SCB_HDL_TC_OPEN_STO,
+#endif
+ AVDT_SCB_SND_DELAY_RPT_REQ,
+ AVDT_SCB_HDL_DELAY_RPT_CMD,
+ AVDT_SCB_HDL_DELAY_RPT_RSP,
+ AVDT_SCB_HDL_WRITE_REQ,
+ AVDT_SCB_SND_ABORT_REQ,
+ AVDT_SCB_SND_ABORT_RSP,
+ AVDT_SCB_SND_CLOSE_REQ,
+ AVDT_SCB_SND_STREAM_CLOSE,
+ AVDT_SCB_SND_CLOSE_RSP,
+ AVDT_SCB_SND_GETCONFIG_REQ,
+ AVDT_SCB_SND_GETCONFIG_RSP,
+ AVDT_SCB_SND_OPEN_REQ,
+ AVDT_SCB_SND_OPEN_RSP,
+ AVDT_SCB_SND_RECONFIG_REQ,
+ AVDT_SCB_SND_RECONFIG_RSP,
+ AVDT_SCB_SND_SECURITY_REQ,
+ AVDT_SCB_SND_SECURITY_RSP,
+ AVDT_SCB_SND_SETCONFIG_REQ,
+ AVDT_SCB_SND_SETCONFIG_REJ,
+ AVDT_SCB_SND_SETCONFIG_RSP,
+ AVDT_SCB_SND_TC_CLOSE,
+ AVDT_SCB_CB_ERR,
+ AVDT_SCB_CONG_STATE,
+ AVDT_SCB_REJ_STATE,
+ AVDT_SCB_REJ_IN_USE,
+ AVDT_SCB_REJ_NOT_IN_USE,
+ AVDT_SCB_SET_REMOVE,
+ AVDT_SCB_FREE_PKT,
+ AVDT_SCB_CLR_PKT,
+ AVDT_SCB_CHK_SND_PKT,
+ AVDT_SCB_TC_TIMER,
+ AVDT_SCB_CLR_VARS,
+ AVDT_SCB_DEALLOC,
+ AVDT_SCB_NUM_ACTIONS
+};
+
+#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS
+
+/* scb state machine events */
+enum {
+ AVDT_SCB_API_REMOVE_EVT,
+ AVDT_SCB_API_WRITE_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_REQ_EVT,
+ AVDT_SCB_API_DELAY_RPT_REQ_EVT,
+ AVDT_SCB_API_SETCONFIG_REQ_EVT,
+ AVDT_SCB_API_OPEN_REQ_EVT,
+ AVDT_SCB_API_CLOSE_REQ_EVT,
+ AVDT_SCB_API_RECONFIG_REQ_EVT,
+ AVDT_SCB_API_SECURITY_REQ_EVT,
+ AVDT_SCB_API_ABORT_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_REJ_EVT,
+ AVDT_SCB_API_OPEN_RSP_EVT,
+ AVDT_SCB_API_CLOSE_RSP_EVT,
+ AVDT_SCB_API_RECONFIG_RSP_EVT,
+ AVDT_SCB_API_SECURITY_RSP_EVT,
+ AVDT_SCB_API_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_OPEN_CMD_EVT,
+ AVDT_SCB_MSG_START_CMD_EVT,
+ AVDT_SCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_SCB_MSG_CLOSE_CMD_EVT,
+ AVDT_SCB_MSG_ABORT_CMD_EVT,
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT,
+ AVDT_SCB_MSG_SECURITY_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_OPEN_RSP_EVT,
+ AVDT_SCB_MSG_START_RSP_EVT,
+ AVDT_SCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_SCB_MSG_CLOSE_RSP_EVT,
+ AVDT_SCB_MSG_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT,
+ AVDT_SCB_MSG_SECURITY_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT,
+ AVDT_SCB_MSG_OPEN_REJ_EVT,
+ AVDT_SCB_MSG_START_REJ_EVT,
+ AVDT_SCB_MSG_SUSPEND_REJ_EVT,
+ AVDT_SCB_TC_TOUT_EVT,
+ AVDT_SCB_TC_OPEN_EVT,
+ AVDT_SCB_TC_CLOSE_EVT,
+ AVDT_SCB_TC_CONG_EVT,
+ AVDT_SCB_TC_DATA_EVT,
+ AVDT_SCB_CC_CLOSE_EVT
+};
+
+/* adaption layer number of stream routing table entries */
+#if AVDT_REPORTING == TRUE
+/* 2 channels(1 media, 1 report) for each SEP and one for signalling */
+#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS<<1) + 1)
+#else
+#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1)
+#endif
+
+/* adaption layer number of transport channel table entries - moved to target.h
+#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
+
+/* "states" used in transport channel table */
+#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */
+#define AVDT_AD_ST_IDLE 1 /* No connection */
+#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */
+#define AVDT_AD_ST_INT 3 /* Initiating a connection */
+#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */
+#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */
+#define AVDT_AD_ST_OPEN 6 /* Channel opened */
+#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */
+#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */
+
+/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
+#define AVDT_L2C_CFG_IND_DONE (1<<0)
+#define AVDT_L2C_CFG_CFM_DONE (1<<1)
+#define AVDT_L2C_CFG_CONN_INT (1<<2)
+#define AVDT_L2C_CFG_CONN_ACP (1<<3)
+
+
+/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */
+#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */
+#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */
+#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+
+/* msg union of all message parameter types */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_EVT_HDR single;
+ tAVDT_SETCONFIG config_cmd;
+ tAVDT_CONFIG reconfig_cmd;
+ tAVDT_MULTI multi;
+ tAVDT_SECURITY security_cmd;
+ tAVDT_DISCOVER discover_rsp;
+ tAVDT_CONFIG svccap;
+ tAVDT_SECURITY security_rsp;
+ tAVDT_DELAY_RPT delay_rpt_cmd;
+} tAVDT_MSG;
+
+/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+ tAVDT_SEP_INFO *p_sep_info;
+ UINT8 num_seps;
+} tAVDT_CCB_API_DISCOVER;
+
+/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */
+typedef struct {
+ tAVDT_EVT_HDR single;
+ tAVDT_CTRL_CBACK *p_cback;
+ tAVDT_CFG *p_cfg;
+} tAVDT_CCB_API_GETCAP;
+
+/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+ UINT8 sec_mask;
+} tAVDT_CCB_API_CONNECT;
+
+/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK *p_cback;
+} tAVDT_CCB_API_DISCONNECT;
+
+/* union associated with ccb state machine events */
+typedef union {
+ tAVDT_CCB_API_DISCOVER discover;
+ tAVDT_CCB_API_GETCAP getcap;
+ tAVDT_CCB_API_CONNECT connect;
+ tAVDT_CCB_API_DISCONNECT disconnect;
+ tAVDT_MSG msg;
+ BOOLEAN llcong;
+ UINT8 err_code;
+} tAVDT_CCB_EVT;
+
+/* channel control block type */
+typedef struct {
+ BD_ADDR peer_addr; /* BD address of peer */
+ TIMER_LIST_ENT timer_entry; /* CCB timer list entry */
+ BUFFER_Q cmd_q; /* Queue for outgoing command messages */
+ BUFFER_Q rsp_q; /* Queue for outgoing response and reject messages */
+ tAVDT_CTRL_CBACK *proc_cback; /* Procedure callback function */
+ tAVDT_CTRL_CBACK *p_conn_cback; /* Connection/disconnection callback function */
+ void *p_proc_data; /* Pointer to data storage for procedure */
+ BT_HDR *p_curr_cmd; /* Current command being sent awaiting response */
+ BT_HDR *p_curr_msg; /* Current message being sent */
+ BT_HDR *p_rx_msg; /* Current message being received */
+ BOOLEAN allocated; /* Whether ccb is allocated */
+ UINT8 state; /* The CCB state machine state */
+ BOOLEAN ll_opened; /* TRUE if LL is opened */
+ BOOLEAN proc_busy; /* TRUE when a discover or get capabilities procedure in progress */
+ UINT8 proc_param; /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */
+ BOOLEAN cong; /* Whether signaling channel is congested */
+ UINT8 label; /* Message header "label" (sequence number) */
+ BOOLEAN reconn; /* If TRUE, reinitiate connection after transitioning from CLOSING to IDLE state */
+ UINT8 ret_count; /* Command retransmission count */
+} tAVDT_CCB;
+
+/* type for action functions */
+typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* type for AVDT_SCB_API_WRITE_REQ_EVT */
+typedef struct {
+ BT_HDR *p_buf;
+ UINT32 time_stamp;
+#if AVDT_MULTIPLEXING == TRUE
+ BUFFER_Q frag_q; /* Queue for outgoing media fragments. p_buf should be 0 */
+ UINT8 *p_data;
+ UINT32 data_len;
+#endif
+ UINT8 m_pt;
+ tAVDT_DATA_OPT_MASK opt;
+} tAVDT_SCB_APIWRITE;
+
+/* type for AVDT_SCB_TC_CLOSE_EVT */
+typedef struct {
+ UINT8 old_tc_state; /* channel state before closed */
+ UINT8 tcid; /* TCID */
+ UINT8 type; /* channel type */
+} tAVDT_SCB_TC_CLOSE;
+
+/* type for scb event data */
+typedef union {
+ tAVDT_MSG msg;
+ tAVDT_SCB_APIWRITE apiwrite;
+ tAVDT_DELAY_RPT apidelay;
+ tAVDT_OPEN open;
+ tAVDT_SCB_TC_CLOSE close;
+ BOOLEAN llcong;
+ BT_HDR *p_pkt;
+} tAVDT_SCB_EVT;
+
+/* stream control block type */
+typedef struct {
+ tAVDT_CS cs; /* stream creation struct */
+ tAVDT_CFG curr_cfg; /* current configuration */
+ tAVDT_CFG req_cfg; /* requested configuration */
+ TIMER_LIST_ENT timer_entry; /* timer entry */
+ BT_HDR *p_pkt; /* packet waiting to be sent */
+ tAVDT_CCB *p_ccb; /* ccb associated with this scb */
+ UINT16 media_seq; /* media packet sequence number */
+ BOOLEAN allocated; /* whether scb is allocated or unused */
+ BOOLEAN in_use; /* whether stream being used by peer */
+ BOOLEAN sink_activated; /* A2DP Sink activated/de-activated from Application */
+ UINT8 role; /* initiator/acceptor role in current procedure */
+ BOOLEAN remove; /* whether CB is marked for removal */
+ UINT8 state; /* state machine state */
+ UINT8 peer_seid; /* SEID of peer stream */
+ UINT8 curr_evt; /* current event; set only by state machine */
+ BOOLEAN cong; /* Whether media transport channel is congested */
+ UINT8 close_code; /* Error code received in close response */
+#if AVDT_MULTIPLEXING == TRUE
+ BUFFER_Q frag_q; /* Queue for outgoing media fragments */
+ UINT32 frag_off; /* length of already received media fragments */
+ UINT32 frag_org_len; /* original length before fragmentation of receiving media packet */
+ UINT8 *p_next_frag; /* next fragment to send */
+ UINT8 *p_media_buf; /* buffer for media packet assigned by AVDT_SetMediaBuf */
+ UINT32 media_buf_len; /* length of buffer for media packet assigned by AVDT_SetMediaBuf */
+#endif
+} tAVDT_SCB;
+
+/* type for action functions */
+typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+
+/* adaption layer type for transport channel table */
+typedef struct {
+ UINT16 peer_mtu; /* L2CAP mtu of the peer device */
+ UINT16 my_mtu; /* Our MTU for this channel */
+ UINT16 my_flush_to; /* Our flush timeout for this channel */
+ UINT16 lcid;
+ UINT8 tcid; /* transport channel id */
+ UINT8 ccb_idx; /* channel control block associated with this tc */
+ UINT8 state; /* transport channel state */
+ UINT8 cfg_flags; /* L2CAP configuration flags */
+ UINT8 id;
+} tAVDT_TC_TBL;
+
+/* adaption layer type for stream routing table */
+typedef struct {
+ UINT16 lcid; /* L2CAP LCID of the associated transport channel */
+ UINT8 scb_hdl; /* stream control block associated with this tc */
+} tAVDT_RT_TBL;
+
+
+/* adaption layer control block */
+typedef struct {
+ tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
+ tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL];
+ UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
+} tAVDT_AD;
+
+/* Control block for AVDT */
+typedef struct {
+ tAVDT_REG rcb; /* registration control block */
+ tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */
+ tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */
+ tAVDT_AD ad; /* adaption layer control block */
+ tAVDTC_CTRL_CBACK *p_conf_cback; /* conformance callback function */
+ tAVDT_CCB_ACTION *p_ccb_act; /* pointer to CCB action functions */
+ tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */
+ tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */
+ UINT8 trace_level; /* trace level */
+} tAVDT_CB;
+
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* CCB function declarations */
+extern void avdt_ccb_init(void);
+extern void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data);
+extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr);
+extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr);
+extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb);
+extern tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx);
+
+/* CCB action functions */
+extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* SCB function prototypes */
+extern void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_init(void);
+extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs);
+extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb);
+extern tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl);
+extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code);
+extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi);
+extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb);
+
+/* SCB action functions */
+extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq);
+
+/* msg function declarations */
+extern BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg);
+extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf);
+
+/* adaption layer function declarations */
+extern void avdt_ad_init(void);
+extern UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb);
+extern UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason);
+extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested);
+extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+extern UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf);
+extern void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role);
+extern void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+
+extern void avdt_process_timeout(TIMER_LIST_ENT *p_tle);
+
+/*****************************************************************************
+** macros
+*****************************************************************************/
+
+/* we store the scb and the label in the layer_specific field of the
+** current cmd
+*/
+#define AVDT_BLD_LAYERSPEC(ls, msg, label) \
+ ls = (((label) << 4) | (msg))
+
+#define AVDT_LAYERSPEC_LABEL(ls) ((UINT8)((ls) >> 4))
+
+#define AVDT_LAYERSPEC_MSG(ls) ((UINT8)((ls) & 0x000F))
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if AVDT_DYNAMIC_MEMORY == FALSE
+extern tAVDT_CB avdt_cb;
+#else
+extern tAVDT_CB *avdt_cb_ptr;
+#define avdt_cb (*avdt_cb_ptr)
+#endif
+
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avdt_l2c_appl;
+
+/* reject message event lookup table */
+extern const UINT8 avdt_msg_rej_2_evt[];
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDT_INT_H */
* Interface to AVRCP mandatory commands
*
******************************************************************************/
-#include <string.h>
+// #include <assert.h>
#include "bt_trace.h"
+#include <string.h>
+
#include "gki.h"
#include "avrc_api.h"
#include "avrc_int.h"
#include "avrc_api.h"
#include "avrc_defs.h"
#include "avrc_int.h"
+#include "bt_utils.h"
/*****************************************************************************
** Global data
* Interface to AVRCP optional commands
*
******************************************************************************/
+// #include <assert.h>
+#include "bt_target.h"
#include <string.h>
-#include "bt_trace.h"
+
#include "gki.h"
#include "avrc_api.h"
#include "avrc_int.h"
#include "avrc_api.h"
#include "avrc_defs.h"
#include "avrc_int.h"
+#include "bt_utils.h"
/*****************************************************************************
** Global data
#ifndef AVRC_INT_H
#define AVRC_INT_H
-//#include "avct_defs.h"
+#include "avct_defs.h"
#include "avrc_api.h"
/* DEBUG FLAGS
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * nterface to A2DP Application Programming Interface
+ *
+ ******************************************************************************/
+#ifndef A2D_API_H
+#define A2D_API_H
+#include "sdp_api.h"
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* Profile supported features */
+#define A2D_SUPF_PLAYER 0x0001
+#define A2D_SUPF_MIC 0x0002
+#define A2D_SUPF_TUNER 0x0004
+#define A2D_SUPF_MIXER 0x0008
+
+#define A2D_SUPF_HEADPHONE 0x0001
+#define A2D_SUPF_SPEAKER 0x0002
+#define A2D_SUPF_RECORDER 0x0004
+#define A2D_SUPF_AMP 0x0008
+
+/* AV Media Types */
+#define A2D_MEDIA_TYPE_AUDIO 0x00 /* audio media type + RFA */
+#define A2D_MEDIA_TYPE_VIDEO 0x10 /* video media type + RFA */
+#define A2D_MEDIA_TYPE_MULTI 0x20 /* multimedia media type + RFA */
+
+/* AV Media Codec Type (Audio Codec ID) */
+#define A2D_MEDIA_CT_SBC 0x00 /* SBC media codec type */
+#define A2D_MEDIA_CT_M12 0x01 /* MPEG-1, 2 Audio media codec type */
+#define A2D_MEDIA_CT_M24 0x02 /* MPEG-2, 4 AAC media codec type */
+#define A2D_MEDIA_CT_ATRAC 0x04 /* ATRAC family media codec type */
+
+#define A2D_SUCCESS 0 /* Success */
+#define A2D_FAIL 0x0A /* Failed */
+#define A2D_BUSY 0x0B /* A2D_FindService is already in progress */
+#define A2D_INVALID_PARAMS 0x0C /* bad parameters */
+#define A2D_WRONG_CODEC 0x0D /* wrong codec info */
+#define A2D_BAD_CODEC_TYPE 0xC1 /* Media Codec Type is not valid */
+#define A2D_NS_CODEC_TYPE 0xC2 /* Media Codec Type is not supported */
+#define A2D_BAD_SAMP_FREQ 0xC3 /* Sampling Frequency is not valid or multiple values have been selected */
+#define A2D_NS_SAMP_FREQ 0xC4 /* Sampling Frequency is not supported */
+#define A2D_BAD_CH_MODE 0xC5 /* Channel Mode is not valid or multiple values have been selected */
+#define A2D_NS_CH_MODE 0xC6 /* Channel Mode is not supported */
+#define A2D_BAD_SUBBANDS 0xC7 /* None or multiple values have been selected for Number of Subbands */
+#define A2D_NS_SUBBANDS 0xC8 /* Number of Subbands is not supported */
+#define A2D_BAD_ALLOC_MTHD 0xC9 /* None or multiple values have been selected for Allocation Method */
+#define A2D_NS_ALLOC_MTHD 0xCA /* Allocation Method is not supported */
+#define A2D_BAD_MIN_BITPOOL 0xCB /* Minimum Bitpool Value is not valid */
+#define A2D_NS_MIN_BITPOOL 0xCC /* Minimum Bitpool Value is not supported */
+#define A2D_BAD_MAX_BITPOOL 0xCD /* Maximum Bitpool Value is not valid */
+#define A2D_NS_MAX_BITPOOL 0xCE /* Maximum Bitpool Value is not supported */
+#define A2D_BAD_LAYER 0xCF /* None or multiple values have been selected for Layer */
+#define A2D_NS_LAYER 0xD0 /* Layer is not supported */
+#define A2D_NS_CRC 0xD1 /* CRC is not supported */
+#define A2D_NS_MPF 0xD2 /* MPF-2 is not supported */
+#define A2D_NS_VBR 0xD3 /* VBR is not supported */
+#define A2D_BAD_BIT_RATE 0xD4 /* None or multiple values have been selected for Bit Rate */
+#define A2D_NS_BIT_RATE 0xD5 /* Bit Rate is not supported */
+#define A2D_BAD_OBJ_TYPE 0xD6 /* Either 1) Object type is not valid (b3-b0) or 2) None or multiple values have been selected for Object Type */
+#define A2D_NS_OBJ_TYPE 0xD7 /* Object type is not supported */
+#define A2D_BAD_CHANNEL 0xD8 /* None or multiple values have been selected for Channels */
+#define A2D_NS_CHANNEL 0xD9 /* Channels is not supported */
+#define A2D_BAD_BLOCK_LEN 0xDD /* None or multiple values have been selected for Block Length */
+#define A2D_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */
+#define A2D_BAD_CP_FORMAT 0xE1 /* The format of Content Protection Service Capability/Content Protection Scheme Dependent Data is not correct. */
+
+typedef UINT8 tA2D_STATUS;
+
+/* the return values from A2D_BitsSet() */
+#define A2D_SET_ONE_BIT 1 /* one and only one bit is set */
+#define A2D_SET_ZERO_BIT 0 /* all bits clear */
+#define A2D_SET_MULTL_BIT 2 /* multiple bits are set */
+
+/*****************************************************************************
+** type definitions
+*****************************************************************************/
+
+/* This data type is used in A2D_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct
+{
+ UINT32 db_len; /* Length, in bytes, of the discovery database */
+ UINT16 num_attr;/* The number of attributes in p_attrs */
+ tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */
+ UINT16 *p_attrs; /* The attributes filter. If NULL, A2DP API sets the attribute filter
+ * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
+ * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME.
+ * If not NULL, the input is taken as the filter. */
+} tA2D_SDP_DB_PARAMS;
+
+/* This data type is used in tA2D_FIND_CBACK to report the result of the SDP discovery process. */
+typedef struct
+{
+ UINT16 service_len; /* Length, in bytes, of the service name */
+ UINT16 provider_len; /* Length, in bytes, of the provider name */
+ char * p_service_name; /* Pointer the service name. This character string may not be null terminated.
+ * Use the service_len parameter to safely copy this string */
+ char * p_provider_name;/* Pointer the provider name. This character string may not be null terminated.
+ * Use the provider_len parameter to safely copy this string */
+ UINT16 features; /* Profile supported features */
+ UINT16 avdt_version; /* AVDTP protocol version */
+} tA2D_Service;
+
+/* This is the callback to notify the result of the SDP discovery process. */
+typedef void (tA2D_FIND_CBACK)(BOOLEAN found, tA2D_Service * p_service);
+
+
+/*****************************************************************************
+** external function declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_AddRecord
+**
+** Description This function is called by a server application to add
+** SRC or SNK information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+**
+** features: Profile supported features.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+extern tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
+ UINT16 features, UINT32 sdp_handle);
+
+/******************************************************************************
+**
+** Function A2D_FindService
+**
+** Description This function is called by a client application to
+** perform service discovery and retrieve SRC or SNK SDP
+** record information from a server. Information is
+** returned for the first service record found on the
+** server that matches the service UUID. The callback
+** function will be executed when service discovery is
+** complete. There can only be one outstanding call to
+** A2D_FindService() at a time; the application must wait
+** for the callback before it makes another call to
+** the function.
+**
+** Input Parameters:
+** service_uuid: Indicates SRC or SNK.
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: Pointer to the information to initialize
+** the discovery database.
+**
+** p_cback: Pointer to the A2D_FindService()
+** callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns A2D_SUCCESS if function execution succeeded,
+** A2D_INVALID_PARAMS if bad parameters are given.
+** A2D_BUSY if discovery is already in progress.
+** A2D_FAIL if function execution failed.
+**
+******************************************************************************/
+extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback);
+
+/******************************************************************************
+**
+** Function A2D_SetTraceLevel
+**
+** Description Sets the trace level for A2D. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the A2D 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.
+**
+******************************************************************************/
+extern UINT8 A2D_SetTraceLevel (UINT8 new_level);
+
+/******************************************************************************
+** Function A2D_BitsSet
+**
+** Description Check the given num for the number of bits set
+** Returns A2D_SET_ONE_BIT, if one and only one bit is set
+** A2D_SET_ZERO_BIT, if all bits clear
+** A2D_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+extern UINT8 A2D_BitsSet(UINT8 num);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*******************************************************************************
+**
+** Function A2D_Init
+**
+** Description This function is called at stack startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** control block and tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void A2D_Init(void);
+
+#endif /* A2D_API_H */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * nterface to low complexity subband codec (SBC)
+ *
+ ******************************************************************************/
+#ifndef A2D_SBC_H
+#define A2D_SBC_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+/* the length of the SBC Media Payload header. */
+#define A2D_SBC_MPL_HDR_LEN 1
+
+/* the LOSC of SBC media codec capabilitiy */
+#define A2D_SBC_INFO_LEN 6
+
+/* for Codec Specific Information Element */
+#define A2D_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */
+#define A2D_SBC_IE_SAMP_FREQ_16 0x80 /* b7:16 kHz */
+#define A2D_SBC_IE_SAMP_FREQ_32 0x40 /* b6:32 kHz */
+#define A2D_SBC_IE_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
+#define A2D_SBC_IE_SAMP_FREQ_48 0x10 /* b4:48 kHz */
+
+#define A2D_SBC_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */
+#define A2D_SBC_IE_CH_MD_MONO 0x08 /* b3: mono */
+#define A2D_SBC_IE_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2D_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2D_SBC_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */
+
+#define A2D_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */
+#define A2D_SBC_IE_BLOCKS_4 0x80 /* 4 blocks */
+#define A2D_SBC_IE_BLOCKS_8 0x40 /* 8 blocks */
+#define A2D_SBC_IE_BLOCKS_12 0x20 /* 12blocks */
+#define A2D_SBC_IE_BLOCKS_16 0x10 /* 16blocks */
+
+#define A2D_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */
+#define A2D_SBC_IE_SUBBAND_4 0x08 /* b3: 4 */
+#define A2D_SBC_IE_SUBBAND_8 0x04 /* b2: 8 */
+
+#define A2D_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */
+#define A2D_SBC_IE_ALLOC_MD_S 0x02 /* b1: SNR */
+#define A2D_SBC_IE_ALLOC_MD_L 0x01 /* b0: loundess */
+
+#define A2D_SBC_IE_MIN_BITPOOL 2
+#define A2D_SBC_IE_MAX_BITPOOL 250
+
+/* for media payload header */
+#define A2D_SBC_HDR_F_MSK 0x80
+#define A2D_SBC_HDR_S_MSK 0x40
+#define A2D_SBC_HDR_L_MSK 0x20
+#define A2D_SBC_HDR_NUM_MSK 0x0F
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* data type for the SBC Codec Information Element*/
+typedef struct
+{
+ UINT8 samp_freq; /* Sampling frequency */
+ UINT8 ch_mode; /* Channel mode */
+ UINT8 block_len; /* Block length */
+ UINT8 num_subbands; /* Number of subbands */
+ UINT8 alloc_mthd; /* Allocation method */
+ UINT8 max_bitpool; /* Maximum bitpool */
+ UINT8 min_bitpool; /* Minimum bitpool */
+} tA2D_SBC_CIE;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_SbcChkFrInit
+**
+** Description check if need to init the descramble control block.
+**
+** Returns nothing.
+******************************************************************************/
+extern void A2D_SbcChkFrInit(UINT8 *p_pkt);
+
+/******************************************************************************
+**
+** Function A2D_SbcDescramble
+**
+** Description descramble the packet.
+**
+** Returns nothing.
+******************************************************************************/
+extern void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len);
+
+/******************************************************************************
+**
+** Function A2D_BldSbcInfo
+**
+** Description This function is called by an application to build
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** media_type: Indicates Audio, or Multimedia.
+**
+** p_ie: The SBC Codec Information Element information.
+**
+** Output Parameters:
+** p_result: the resulting codec info byte sequence.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+extern tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie,
+ UINT8 *p_result);
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcInfo
+**
+** Description This function is called by an application to parse
+** the SBC Media Codec Capabilities byte sequence
+** beginning from the LOSC octet.
+** Input Parameters:
+** p_info: the byte sequence to parse.
+**
+** for_caps: TRUE, if the byte sequence is for get capabilities response.
+**
+** Output Parameters:
+** p_ie: The SBC Codec Information Element information.
+**
+** Returns A2D_SUCCESS if function execution succeeded.
+** Error status code, otherwise.
+******************************************************************************/
+extern tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+
+/******************************************************************************
+**
+** Function A2D_BldSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Output Parameters:
+** p_dst: the resulting media payload header byte sequence.
+**
+** Returns void.
+******************************************************************************/
+extern void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start,
+ BOOLEAN last, UINT8 num);
+
+/******************************************************************************
+**
+** Function A2D_ParsSbcMplHdr
+**
+** Description This function is called by an application to parse
+** the SBC Media Payload header.
+** Input Parameters:
+** p_src: the byte sequence to parse..
+**
+** Output Parameters:
+** frag: 1, if fragmented. 0, otherwise.
+**
+** start: 1, if the starting packet of a fragmented frame.
+**
+** last: 1, if the last packet of a fragmented frame.
+**
+** num: If frag is 1, this is the number of remaining fragments
+** (including this fragment) of this frame.
+** If frag is 0, this is the number of frames in this packet.
+**
+** Returns void.
+******************************************************************************/
+extern void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag,
+ BOOLEAN *p_start, BOOLEAN *p_last,
+ UINT8 *p_num);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_SBC_H */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BT_UTILS_H
+#define BT_UTILS_H
+
+// static const char BT_UTILS_MODULE[] = "bt_utils_module";
+
+/*******************************************************************************
+** Type definitions
+********************************************************************************/
+
+typedef enum {
+ TASK_HIGH_MEDIA = 0,
+ TASK_HIGH_GKI_TIMER,
+ TASK_HIGH_BTU,
+ TASK_HIGH_HCI_WORKER,
+ TASK_HIGH_USERIAL_READ,
+ TASK_UIPC_READ,
+ TASK_JAVA_ALARM,
+ TASK_HIGH_MAX
+} tHIGH_PRIORITY_TASK;
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+// void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task);
+// void adjust_priority_a2dp(int start);
+#define UNUSED(x) (void)(x)
+#endif /* BT_UTILS_H */
bluedroid/gki/include \
bluedroid/hci/include \
bluedroid/osi/include \
+ bluedroid/utils/include \
bluedroid/profiles/core/include \
bluedroid/profiles/esp/blufi/include \
bluedroid/profiles/esp/include \
- bluedroid/profiles/std/avrc/include \
bluedroid/profiles/std/battery/include \
bluedroid/profiles/std/dis/include \
bluedroid/profiles/std/hid/include \
bluedroid/stack/l2cap/include \
bluedroid/stack/sdp/include \
bluedroid/stack/smp/include \
+ bluedroid/stack/avct/include \
+ bluedroid/stack/avrc/include \
+ bluedroid/stack/avdt/include \
+ bluedroid/stack/a2dp/include \
bluedroid/stack/include \
bluedroid/stack_api/include \
bluedroid/include \
bluedroid/profiles/esp/ble_button \
bluedroid/profiles/esp/wechat_AirSync \
bluedroid/profiles/esp \
- bluedroid/profiles/std/avrc \
bluedroid/profiles/std/battery \
bluedroid/profiles/std/dis \
bluedroid/profiles/std/hid \
bluedroid/stack/l2cap \
bluedroid/stack/sdp \
bluedroid/stack/smp \
+ bluedroid/stack/avct \
+ bluedroid/stack/avrc \
+ bluedroid/stack/avdt \
+ bluedroid/stack/a2dp \
bluedroid/stack \
bluedroid/stack_api \
bluedroid \