mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-03 22:08:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2188 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2188 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/******************************************************************************
 | 
						|
 *
 | 
						|
 *  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 "stack/bt_types.h"
 | 
						|
#include "common/bt_target.h"
 | 
						|
#include "common/bt_defs.h"
 | 
						|
#include "stack/avdt_api.h"
 | 
						|
#include "stack/avdtc_api.h"
 | 
						|
#include "avdt_int.h"
 | 
						|
#include "stack/btu.h"
 | 
						|
#include "osi/allocator.h"
 | 
						|
 | 
						|
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
 | 
						|
 | 
						|
/* 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");
 | 
						|
        osi_free(p_data->p_pkt);
 | 
						|
        p_data->p_pkt = NULL;
 | 
						|
    }
 | 
						|
    /* 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
 | 
						|
            osi_free(p_data->p_pkt);
 | 
						|
            p_data->p_pkt = NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#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(ssrc);
 | 
						|
        UNUSED(o_p);
 | 
						|
        UNUSED(o_v);
 | 
						|
        UNUSED(o_cc);
 | 
						|
 | 
						|
        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\n",
 | 
						|
                                    ssrc, o_cc, *p, *(p + 1), p + 2);
 | 
						|
                result = AVDT_BUSY;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
        default:
 | 
						|
            AVDT_TRACE_ERROR( "Bad Report pkt - packet type: %d\n", 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: %p - p:%p < 4\n", 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\n", 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\n",
 | 
						|
                             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)\n", 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)\n", 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)\n", al_len, p_scb->media_buf_len);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            AVDT_TRACE_DEBUG("al:%d media:%d frag_org_len:%d frag_off:%d\n",
 | 
						|
                             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\n",
 | 
						|
                                   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\n",
 | 
						|
                               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\n",
 | 
						|
                         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:%p p_payload:%p\n",
 | 
						|
                                       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:%p p_payload:%p\n",
 | 
						|
                                   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\n",
 | 
						|
                             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");
 | 
						|
    }
 | 
						|
    osi_free(p_data->p_pkt);
 | 
						|
    p_data->p_pkt = NULL;
 | 
						|
}
 | 
						|
#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);
 | 
						|
            osi_free(p_data->p_pkt);
 | 
						|
            p_data->p_pkt = NULL;
 | 
						|
        } 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);
 | 
						|
 | 
						|
    AVDT_TRACE_ERROR("%s dropped incoming media packet", __func__);
 | 
						|
    osi_free(p_data->p_pkt);
 | 
						|
    p_data->p_pkt = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
**
 | 
						|
** 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;
 | 
						|
        /* 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 {
 | 
						|
        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_send_delay_report_cmd
 | 
						|
**
 | 
						|
** Description      This function is to initiate the delay reporting command.
 | 
						|
**
 | 
						|
** Returns          Nothing.
 | 
						|
**
 | 
						|
*******************************************************************************/
 | 
						|
void avdt_scb_send_delay_report_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 | 
						|
{
 | 
						|
    UINT16          delay_value;
 | 
						|
    UNUSED(p_data);
 | 
						|
 | 
						|
    if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (p_scb->curr_cfg.psc_mask & AVDT_PSC_DELAY_RPT)) {
 | 
						|
        delay_value = AVDT_GetDelayValue();
 | 
						|
        AVDT_DelayReport(avdt_scb_to_hdl(p_scb), p_scb->peer_seid, delay_value);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
**
 | 
						|
** Function         avdt_scb_init_open_req
 | 
						|
**
 | 
						|
** 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_init_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 | 
						|
{
 | 
						|
    tAVDT_EVT_HDR   single;
 | 
						|
    UNUSED(p_data);
 | 
						|
 | 
						|
    if (p_scb->p_ccb != NULL && p_scb->role == AVDT_CONF_INT) {
 | 
						|
        if (!(p_scb->curr_cfg.psc_mask & AVDT_PSC_DELAY_RPT)) {
 | 
						|
            /* initiate open */
 | 
						|
            single.seid = p_scb->peer_seid;
 | 
						|
            avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
 | 
						|
        } else {
 | 
						|
            btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_DELAY_RPT, AVDT_SCB_TC_DELAY_RPT_TOUT);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
**
 | 
						|
** 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)
 | 
						|
{
 | 
						|
    UNUSED(p_data);
 | 
						|
 | 
						|
    if (p_scb->p_ccb != NULL) {
 | 
						|
        /* save configuration */
 | 
						|
        memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
 | 
						|
        p_scb->role = AVDT_CONF_INT;
 | 
						|
 | 
						|
        /* send delay reporting command */
 | 
						|
        avdt_scb_send_delay_report_cmd(p_scb, p_data);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
**
 | 
						|
** 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;
 | 
						|
    if (p_data) {
 | 
						|
        avdt_ctrl.hdr.err_param = p_data->close.disc_rsn;
 | 
						|
    } else {
 | 
						|
        avdt_ctrl.hdr.err_param = AVDT_DISC_RSN_NORMAL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* 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) {
 | 
						|
        osi_free(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)
 | 
						|
{
 | 
						|
    tAVDT_EVT_HDR single;
 | 
						|
 | 
						|
    (*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) {
 | 
						|
        if (p_scb->cs.cfg.psc_mask & AVDT_PSC_DELAY_RPT) {
 | 
						|
            avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
 | 
						|
            if(p_scb->role == AVDT_CONF_INT) {
 | 
						|
                btu_stop_timer(&p_scb->timer_entry);
 | 
						|
                /* initiate open */
 | 
						|
                single.seid = p_scb->peer_seid;
 | 
						|
                avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            p_data->msg.hdr.err_code = AVDT_ERR_NSC;
 | 
						|
            avdt_msg_send_rej(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)
 | 
						|
{
 | 
						|
    tAVDT_EVT_HDR single;
 | 
						|
 | 
						|
    if ((p_scb->cs.tsep == AVDT_TSEP_SNK) &&
 | 
						|
            (p_scb->state == AVDT_SCB_CONF_ST) && (p_scb->role == AVDT_CONF_INT)) {
 | 
						|
        btu_stop_timer(&p_scb->timer_entry);
 | 
						|
        /* initiate open */
 | 
						|
        single.seid = p_scb->peer_seid;
 | 
						|
        avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
 | 
						|
    }
 | 
						|
 | 
						|
    (*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_delay_rpt_tout
 | 
						|
 *
 | 
						|
 * Description      The timer triggers the sending of AVDT open_req.
 | 
						|
 *                  This function is theoretically not called.
 | 
						|
 *
 | 
						|
 * Returns          Nothing.
 | 
						|
 *
 | 
						|
 ******************************************************************************/
 | 
						|
void avdt_scb_hdl_delay_rpt_tout(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 | 
						|
{
 | 
						|
    tAVDT_EVT_HDR   single;
 | 
						|
    UNUSED(p_data);
 | 
						|
 | 
						|
    /* 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_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\n",
 | 
						|
                     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) {
 | 
						|
        osi_free(p_scb->p_pkt);
 | 
						|
        p_scb->p_pkt = NULL;
 | 
						|
 | 
						|
        /* 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;
 | 
						|
 | 
						|
    /* free fragments we're holding, if any; it shouldn't happen */
 | 
						|
    if (!fixed_queue_is_empty(p_scb->frag_q))
 | 
						|
    {
 | 
						|
        /* this shouldn't be happening */
 | 
						|
        AVDT_TRACE_WARNING("*** Dropped media packet; congested");
 | 
						|
        BT_HDR *p_frag;
 | 
						|
        while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL)
 | 
						|
             osi_free(p_frag);
 | 
						|
    }
 | 
						|
 | 
						|
    /* 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);
 | 
						|
 | 
						|
    if (! fixed_queue_is_empty(p_scb->frag_q)) {
 | 
						|
        list_t *list = fixed_queue_get_list(p_scb->frag_q);
 | 
						|
        const list_node_t *node = list_begin(list);
 | 
						|
        if (node != list_end(list)) {
 | 
						|
            BT_HDR *p_frag = (BT_HDR *)list_node(node);
 | 
						|
            node = list_next(node);
 | 
						|
 | 
						|
            /* get first packet */
 | 
						|
            /* 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++;
 | 
						|
        }
 | 
						|
 | 
						|
        for ( ; node != list_end(list); node = list_next(node)) {
 | 
						|
            BT_HDR *p_frag = (BT_HDR *)list_node(node);
 | 
						|
 | 
						|
            /* 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);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
#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 (fixed_queue_is_empty(p_scb->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
 | 
						|
    AVDT_TRACE_WARNING("%s c:%d, off:%d", __func__,
 | 
						|
        fixed_queue_length(p_scb->frag_q), p_scb->frag_off);
 | 
						|
 | 
						|
    /* clean fragments queue */
 | 
						|
    BT_HDR *p_frag;
 | 
						|
    while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) {
 | 
						|
        osi_free(p_frag);
 | 
						|
    }
 | 
						|
    p_scb->frag_off = 0;
 | 
						|
#endif
 | 
						|
    if (p_scb->p_pkt) {
 | 
						|
        osi_free(p_scb->p_pkt);
 | 
						|
        p_scb->p_pkt = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    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));
 | 
						|
        p_scb->role = AVDT_CONF_ACP;
 | 
						|
 | 
						|
        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;
 | 
						|
 | 
						|
    /* 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) {
 | 
						|
        osi_free(p_data->apiwrite.p_buf);
 | 
						|
        p_data->apiwrite.p_buf = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
#if AVDT_MULTIPLEXING == TRUE
 | 
						|
    /* clean fragments queue */
 | 
						|
    BT_HDR          *p_frag;
 | 
						|
    while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) {
 | 
						|
         osi_free(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;
 | 
						|
    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) {
 | 
						|
        osi_free(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 (!fixed_queue_is_empty(p_scb->frag_q)) {
 | 
						|
        AVDT_TRACE_DEBUG("Dropped fragments queue");
 | 
						|
        /* clean fragments queue */
 | 
						|
        BT_HDR *p_frag;
 | 
						|
        while ((p_frag = (BT_HDR*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) {
 | 
						|
             osi_free(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\n",
 | 
						|
                             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*)fixed_queue_dequeue(p_scb->frag_q, 0)) != NULL) {
 | 
						|
                sent = TRUE;
 | 
						|
                AVDT_TRACE_DEBUG("Send fragment len=%d\n", 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\n", res, p_scb->frag_off);
 | 
						|
 | 
						|
            if (p_scb->frag_off) {
 | 
						|
                if (AVDT_AD_SUCCESS == res || fixed_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 (!fixed_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 && fixed_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, fixed_queue_t *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\n", 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\n",
 | 
						|
                     p_tbl->peer_mtu, buf_size, num_frag);
 | 
						|
 | 
						|
    if (buf_size > AVDT_DATA_BUF_SIZE) {
 | 
						|
        buf_size = AVDT_DATA_BUF_SIZE;
 | 
						|
    }
 | 
						|
 | 
						|
    mtu_used = buf_size - BT_HDR_SIZE;
 | 
						|
 | 
						|
    while (*p_data_len && num_frag) {
 | 
						|
        /* allocate buffer for fragment */
 | 
						|
        if (NULL == (p_frag = (BT_HDR *)osi_malloc(buf_size))) {
 | 
						|
            AVDT_TRACE_WARNING("avdt_scb_queue_frags len=%d(out of GKI buffers)\n", *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\n", 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 */
 | 
						|
        fixed_queue_enqueue(p_scb->frag_q, p_frag, FIXED_QUEUE_MAX_TIMEOUT);
 | 
						|
        num_frag--;
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */
 |