小计之RTCP

在这里插入图片描述

高低位转换/
//u val to byte
#define U8_Conv_Byte(pBt, uVal, len) {(pBt)[0] = uVal; len += 1;}
#define U16_Conv_Byte(pBt, uVal, len) {USHORT Val = htons(uVal); memcpy(pBt, &Val, sizeof(Val)); len+=sizeof(Val);}
#define U32_Conv_Byte(pBt, uVal, len) {UINT Val = htonl(uVal); memcpy(pBt, &Val, sizeof(Val)); len+=sizeof(Val);}

//byte to u val
#define Byte_Conv_U8(pBt, uVal, len) {UCHAR pVal = (UCHAR)&uVal; pVal[0] = (pBt)[0]; len += 1;}
#define Byte_Conv_U16(pBt, uVal, len) {USHORT Val=0; memcpy(&Val, pBt, sizeof(Val)); uVal = ntohs(Val); len+=sizeof(Val);}
#define Byte_Conv_U32(pBt, uVal, len) {UINT Val=0; memcpy(&Val, pBt, sizeof(Val)); uVal = ntohl(Val); len+=sizeof(Val);}

rtcp_mod_proc.h


#ifndef __RTCP_MOD_PROC_H__
#define __RTCP_MOD_PROC_H__

#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "XpocRtcpMsg.h"
//#include "rtcp_mod_port.h"

#define RTCP_DEV_TYPE_UE        0   /*MCPT*/
#define RTCP_DEV_TYPE_TCF       1   /*TCF0*/
#define RTCP_DEV_TYPE_X         2   /*X0*/
#define RTCP_DEV_TYPE_MME       3   /*MME0*/

#define RTCP_PACK_DATA_LEN      1600    /*rtcp包的最大buffer*/
#define RTCP_QUEUE_SIZE         1024    /*rtcp发送队列最大长度*/
#define RTCP_MAX_EPOLL_FD       16      /*rtcp接收线程的FD最大数量*/

/*控制信令重发次数*/
#define RTCP_CTRL_CMD_RESEND_TIME   500 /*重发时间,毫秒*/
#define RTCP_CTRL_CMD_RESEND_LOOP   3   /*重发次数*/

#define Rtcp_Enable_Free_Lock_List  1    /*rtcp发送无锁消息队列保护开关*/


/************************************Beigin : 无锁队列保护相关, by weizhenliang***************************************/
/* define the unit type of list */
/* 定义列表的单元类型 */
typedef struct tagRtcpNodeIndex_t
{
    /* The index of RtcpQueueS.pkt[RTCP_QUEUE_SIZE] */
    UINT     u32PktNodeIndex;
    volatile struct tagRtcpNodeIndex_t*   pNext;
}RtcpNodeIndex_t;
typedef struct tagRtcpNodeIndex_t *PRtcpNodeIndex_t;

#define RTCP_LIST_UNLOCKED  (0)
#define RTCP_LIST_LOCKED    (1)

/* define the index list */
/* 定义索引链表 */
typedef struct tagRtcpNodeIndexList_t
{
    volatile RtcpNodeIndex_t* pHead;
    volatile RtcpNodeIndex_t  EmptyNode;
    volatile RtcpNodeIndex_t* pTail;
    volatile SINT              s32Count;
    volatile UINT              u32LockStatus;
}RtcpNodeIndexList_t;

/* define the pni list */
/* 定义数据包结点索引的总列表(含空闲与在用的列表信息) */
typedef struct tagRtcpIndexManageCtx_t
{
    /* 单链表方式实现的先进先出的无锁(队列)结构 */
    volatile RtcpNodeIndexList_t stFreeList;
    volatile RtcpNodeIndexList_t stSendList;
}RtcpIndexManageCtx_t;

///Bigin: 链表操作/支持函数   
UINT rtcpIndexManageInitCtx( RtcpIndexManageCtx_t* pManageCtx,  RtcpNodeIndex_t* pastRtcpNodeIndex,  UINT u32NodeIndexCount);
UINT RtcpIndexManageGetFromHead( volatile RtcpNodeIndexList_t *pIndexList,  RtcpNodeIndex_t** ppNodeIndex);
UINT RtcpIndexManageInsertToTail( volatile RtcpNodeIndexList_t *pIndexList,  RtcpNodeIndex_t* ppNodeIndex);
///End: 链表操作/支持函数   

/**************************************End : 无锁队列保护相关, by weizhenliang***************************************/

typedef void (*fnOnRecvRtcpCtrlMsg)(RtcpCtrlMsgS *pRtcpCtrlMsg, void *pUserData);
typedef void (*fnOnRtcpCtrlMsgTimeout)(RtcpCtrlMsgS *pRtcpCtrlMsg, void *pUserData);


typedef struct tagRtcpFdS
{
    SINT fd;
    UINT ulIP;
    USHORT port;
}RtcpFdS;

typedef struct tagRtcpParamS
{
    UINT                 ulIP;
    USHORT               usRtcpPort;
    fnOnRecvRtcpCtrlMsg fn; //OnRecvRtcpMsgDispatch
    void                *pUserData;
}RtcpParamS;

/*UDP包*/
typedef struct tagRtcpPaketNodeS
{
    RtcpCtrlMsgS            sRtcpMsg;
    ULONGLONG               u64LastSendMilliSec; /*上次发送时间*/
    struct sockaddr_in      addrTo;         /*数据包目的地址*/
    struct sockaddr_un      udsAddrTo;      // 本地套接字方式的对端地址
    UCHAR                   ucSentTimes;    /*已经发送次数*/
    SINT                    fd;             /*发送packet的fd*/
    fnOnRtcpCtrlMsgTimeout  fnTimeoutCB;    /*消息响应超时回调接口*/
    void                    *pUserData;
}RtcpPaketNodeS;

/*数据队列*/
typedef struct tagRtcpQueueS
{
    RtcpPaketNodeS pkt[RTCP_QUEUE_SIZE]; /*队列中的节点*/
    RtcpNodeIndex_t astPktNodeIndex[RTCP_QUEUE_SIZE];/*astPktNodeIndex 与 pkt的索引 相对应*/
    RtcpIndexManageCtx_t stIndexManageCtx; /*stIndexManageCtx 管理空闲与已用结点*/
}RtcpQueueS;

ULONGLONG RtcpGetCurrMilliSecondTime(void);
UINT rtcpGetDstParamByMsgTye(RtcpCtrlMsgTypeE entMsgType, UINT *ptSendMsgId, UINT *ptDstModId);
ULONGLONG FloorGetCurrMilliSecondTime(void);

// cce和mde间使用ip+port通信
void *threadRecvRtcp(void *pParam); /*epoll接收rtcp线程*/
void *threadSendRtcp(void *pParam); /*RTCP发送线程*/
SINT rtcpOpenSocket(RtcpFdS *pFdInfo, UINT ulIP, USHORT port);/*打开RTCP端口*/
SINT rtcpEpollSetAddFd(SINT iEpollSet, RtcpFdS *pFdInfo);/*epoll添加FD*/
UINT rtcpInitFloorThread(RtcpIpAddrSt *ptLocIpAddr, fnOnRecvRtcpCtrlMsg fn, void *pUserData);

SINT sendRtcpPacket(RtcpPaketNodeS *pPktNode, ULONGLONG u64NowMilliSec);
SINT rtcpMsgLenWLen(RtcpCtrlMsgS *pMsg, UCHAR *pByte, UINT ulByteLen);/*计算RTCP消息长度*/

UINT insertPkt2RtcpSendQueue(UINT ulRmtIP, USHORT usRmtPort, RtcpCtrlMsgS *pRtcpCtrlMsg);

// cce和mde间使用本地套接字通信
void *threadRecvRtcp1(void *pParam);
SINT rtcpOpenLocalSocket(RtcpFdS *pFdInfo, char* pcSerPath); // 使用本地套接字RTCP通信
UINT rtcpInitFloorThread1(RtcpIpAddrSt *ptLocIpAddr, fnOnRecvRtcpCtrlMsg fn, void *pUserData); // 使用本地套接字
SINT sendRtcpPacket1(RtcpPaketNodeS *pPktNode, ULONGLONG u64NowMilliSec);
UINT insertPkt2RtcpSendQueue1(char* pcSerPath, RtcpCtrlMsgS *pRtcpCtrlMsg);

#endif

rtcp_mod_decode.c


#include "rtcp_mod_decode.h"

RtcpCtrlMsgTypeE getRtcpMsgType(UINT ulName, UCHAR ucSubtype)
{
    RtcpCtrlMsgTypeE eMsgType = RTCP_CTRL_MSG_BUTT;
    switch (ulName)
    {
        case RTCP_NAME_MCPT:
        case RTCP_NAME_TCF:
        case RTCP_NAME_X:
        case RTCP_NAME_MME:
            eMsgType = (RtcpCtrlMsgTypeE)((UINT)D_FLOOR_MSG_BASE + ucSubtype);
            break;

        default:
            x_WarnLog("name[%x] subtype[%d] error.\n", ulName, ucSubtype);
            break;
    }
    
    return eMsgType;
}


UINT xFloorMsgHeadParse(UCHAR *pByte, UINT *pulByteLen, RtcpCtrlMsgS *pOutRtcpMsg, UCHAR ucInterfaceFlag)
{
    UCHAR ucSubtype = 0;    
    ucSubtype = (*pByte) & RTCP_MSG_SUBTYPE_POSITION;    

    /*版本号、填充比特、SubType*/
    pOutRtcpMsg->version = ((*pByte) & RTCP_MSG_VERSION_POSITION) >> 6;
    pOutRtcpMsg->p = ((*pByte) & RTCP_MSG_PADDING_POSITION) >> 5;
    pOutRtcpMsg->subtype = ucSubtype;
    *pulByteLen += sizeof(UCHAR);    

    /*PT域、length域、ssrc域*/
    Byte_Conv_U8(pByte + *pulByteLen, pOutRtcpMsg->pt, *pulByteLen);
    Byte_Conv_U16(pByte + *pulByteLen, pOutRtcpMsg->length, *pulByteLen);
    Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->ssrc, *pulByteLen);
    Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->ulName, *pulByteLen);

    if(RTCP_DEV_TYPE_NET_UNIT == ucInterfaceFlag)
    {
        Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->callId, *pulByteLen);
        Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->nodeId, *pulByteLen);
        xUdnField(pByte, pulByteLen, &pOutRtcpMsg->udn);
    }
    else if(RTCP_DEV_TYPE_STANDARD != ucInterfaceFlag)
    {
        x_WarnLog("xRtcpCtrlMsg: Invalid Interface Flag!\n");
        return XPOC_ERR_FAIL;
    }

    /*消息类型*/
    pOutRtcpMsg->eMsgType = getRtcpMsgType(pOutRtcpMsg->ulName, ucSubtype);
    
    return XPOC_ERR_SUCCESS;
}


UINT xFloorPriorityField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataPriorityS *pstFloorPriority
)
{
    UCHAR ucTempValue = 0;
    
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorPriority)
    {
        x_WarnLog("xFloorPriorityField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->length, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->priorityValue, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, ucTempValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorDurationField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataDurationS *pstFloorDuration
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorDuration)
    {
        x_WarnLog("xFloorDurationField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorDuration->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorDuration->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorDuration->durationValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorRejectCauseField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataRejectCauseS *pstFloorRejectCause
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorRejectCause)
    {
        x_WarnLog("xFloorRejectCauseField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorRejectCause->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorRejectCause->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorRejectCause->eRejectCause, *pulArrLen);
    if(pstFloorRejectCause->length > 2)
    {
        memcpy((UCHAR*)pstFloorRejectCause->rejectPhrase, pByte + *pulArrLen, pstFloorRejectCause->length - sizeof(USHORT));
        *pulArrLen += pstFloorRejectCause->length - sizeof(USHORT);
        *pulArrLen += (REMAINDER_SIZE - (pstFloorRejectCause->length - sizeof(USHORT)) % REMAINDER_SIZE) % REMAINDER_SIZE;
    }
    
    return XPOC_ERR_SUCCESS;
}

UINT xQueueInfoField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataQueueInfoS *pstFloorQueueInfo
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueueInfo)
    {
        x_WarnLog("xQueueInfoField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->length, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->queuePositionInfo, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->queuePriorityLevel, *pulArrLen);

    return XPOC_ERR_SUCCESS;
}

UINT xFloorGrantedPartyIdentityField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataGrantedPartyIdentityS *pstFloorGrantedPartyIdentity
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorGrantedPartyIdentity)
    {
        x_WarnLog("xFloorGrantedPartyIdentityField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorGrantedPartyIdentity->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorGrantedPartyIdentity->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorGrantedPartyIdentity->grantedPartyIdentity, pByte + *pulArrLen, pstFloorGrantedPartyIdentity->length);
    *pulArrLen += pstFloorGrantedPartyIdentity->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorGrantedPartyIdentity->length + sizeof(UCHAR) +sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorPermissionField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataPermissionS *pstFloorPermission
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorPermission)
    {
        x_WarnLog("xFloorPermissionField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPermission->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPermission->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorPermission->permissionValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorUserIdField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataUserIdS *pstFloorUserId
)
{ 
    if(NULL == pstFloorUserId || NULL == pByte || NULL == pulArrLen)
    {
        x_WarnLog("xFloorUserIdField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorUserId->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorUserId->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorUserId->userId, pByte + *pulArrLen, pstFloorUserId->length);
    *pulArrLen += pstFloorUserId->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorUserId->length + sizeof(UCHAR) +sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueueSizeField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataQueueSizeS *pstFloorQueueSize
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueueSize)
    {
        x_WarnLog("xFloorQueueSizeField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueSize->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueSize->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorQueueSize->queueSizeValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorMsgSeqNumField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataMsgSeqNumS *pstFloorMsgSeqNum
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorMsgSeqNum)
    {
        x_WarnLog("xFloorMsgSeqNumField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorMsgSeqNum->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorMsgSeqNum->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorMsgSeqNum->msgSeqNum, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xUdnField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     RtcpDataUDNS *pstUdn
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstUdn)
    {
        x_WarnLog("Byte2UdnField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstUdn->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstUdn->length, *pulArrLen);
    memcpy((UCHAR*)pstUdn->value, pByte + *pulArrLen, pstUdn->length);
    *pulArrLen += pstUdn->length;
    *pulArrLen += (REMAINDER_SIZE - (pstUdn->length + sizeof(UCHAR) + sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}


/*************************************************
*****************  函数说明 **********************
* 函数名    : xFloorFieldContent
* 功能说明  : 字节流转换成话权消息消息的某个域
*************************************************/
UINT xFloorFieldContent( UINT ulFileId,  UCHAR *pByte,  UINT ulMaxLen,  UINT *pulRealLen,  RtcpVoid_t* pField)
{
    UINT ulReturn = XPOC_ERR_SUCCESS;

    UINT ulBeforeFieldContentLen = 0;
    USHORT uFieldLengthValue = 0;
    UCHAR uByteFieldId = 0;

    if(NULL == pByte || NULL == pulRealLen || NULL == pField)
    {
        x_WarnLog("Invalid param: pByte[%p], pulRealLen[%p], pField[%p].",
            pByte, pulRealLen, pField);
        return XPOC_ERR_FAIL;
    }

    ulBeforeFieldContentLen = *pulRealLen + 2;
    uByteFieldId = (pByte + *pulRealLen)[0];    
    if(ulBeforeFieldContentLen >= ulMaxLen)
    {
        //已经解析到头了或域标识不一致,跳过该域的解析直接退出
        return XPOC_ERR_FAIL;
    } else if(ulFileId != (UINT)uByteFieldId)
    {
        //域标识不一致
        x_InfoLog("Different Field-id: want ulFieldId[%u], InRtcp-fieldId[%u].", 
            ulFileId, (UINT)uByteFieldId);
        return XPOC_ERR_FAIL;
    }

    uFieldLengthValue = (USHORT)(pByte + *pulRealLen)[1];  

    if((ulBeforeFieldContentLen + uFieldLengthValue) > ulMaxLen)
    {
        //域长度不合理,打印日志
        x_WarnLog("Invalid field[%u] length[%u]. With ulBeforeFieldContentLen[%u] over ulMaxLen[%u].",
            ulFileId, uFieldLengthValue, ulBeforeFieldContentLen, ulMaxLen);
        return XPOC_ERR_FAIL;
    }

    switch(ulFileId)
    {
        case D_FLOOR_DATA_ID_PRIORITY: 
        {
            xFloorPriorityField(pByte, pulRealLen, (FloorDataPriorityS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_DURATION:
        {
            xFloorDurationField(pByte, pulRealLen, (FloorDataDurationS*)pField);
            break;
        }        
        case D_FLOOR_DATA_ID_REJECT_CAUSE:
        {
            xFloorRejectCauseField(pByte, pulRealLen, (FloorDataRejectCauseS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUE_INFO:
        {
            xQueueInfoField(pByte, pulRealLen, (FloorDataQueueInfoS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_GRANTED_PARTY_IDENTITY:
        {
            xFloorGrantedPartyIdentityField(pByte, pulRealLen, (FloorDataGrantedPartyIdentityS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_PERMISSION:
        {
            xFloorPermissionField(pByte, pulRealLen, (FloorDataPermissionS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_USER_ID:
        {
            xFloorUserIdField(pByte, pulRealLen, (FloorDataUserIdS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUE_SIZE:
        {
            xFloorQueueSizeField(pByte, pulRealLen, (FloorDataQueueSizeS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_MSG_SEQ_NUM:
        {
            xFloorMsgSeqNumField(pByte, pulRealLen, (FloorDataMsgSeqNumS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUED_USER_ID:
        {
            xQueuedUserIdField(pByte, pulRealLen, (FloorDataQueuedUserIdS*)pField);
            break;
        }
        default : /* Invalid API received */
            x_WarnLog("Default case, unknow ulFileId[%u].\n", ulFileId);
            break;
    }

    return ulReturn;
}

UINT xQueuedUserIdField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataQueuedUserIdS *pstFloorQueuedUserId
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueuedUserId)
    {
        x_WarnLog("xQueuedUserIdField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueuedUserId->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueuedUserId->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorQueuedUserId->queuedUserId, pByte + *pulArrLen, pstFloorQueuedUserId->length);
    *pulArrLen += pstFloorQueuedUserId->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorQueuedUserId->length + sizeof(UCHAR) + sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;
    
    return XPOC_ERR_SUCCESS;
}


UINT xFloorRequestMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    }

    xFloorFieldContent(D_FLOOR_DATA_ID_PRIORITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRequest.priorityField);
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRequest.userIdField);
    }
    
    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorGrantedMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    }

    xFloorFieldContent(D_FLOOR_DATA_ID_DURATION, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.durationField);

    
    xFloorFieldContent(D_FLOOR_DATA_ID_PRIORITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.priorityField);  
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.userIdField); 
    }

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorDenyMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.rejectCauseField); 
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.userIdField);    
    }
    //xFloorFieldContent(D_FLOOR_DATA_ID_TRACK, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.trackField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorReleaseMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{

    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRelease.userIdField); 
    }
    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRelease.releaseCauseField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorIdleMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_MSG_SEQ_NUM, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorIdle.msgSeqNumField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorTakenMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_GRANTED_PARTY_IDENTITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.grantedPartyIdentityField); 
    xFloorFieldContent(D_FLOOR_DATA_ID_PERMISSION, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.permissionField); 

    xFloorFieldContent(D_FLOOR_DATA_ID_MSG_SEQ_NUM, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.msgSeqNumField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorRevokeMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRevoke.rejectCauseField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueuePositionRequestMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionRequest.userIdField); 
    }
    //xFloorFieldContent(D_FLOOR_DATA_ID_TRACK, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionRequest.trackField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueuePositionInfoMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionInfo.userIdField); 
    }
    
    xFloorFieldContent(D_FLOOR_DATA_ID_QUEUE_INFO, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionInfo.queueInfoField); 

    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorAckMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorNotifyMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}



UINT rtcpGetInterfaceByName_dec(UINT ulName, UCHAR *ptInterface)
{
    X_NULL_POINTER_CHK_ONE_PARA(ptInterface);

    switch (ulName)
    {
         /*MCPC/MCMC属于标准RTCP消息*/
        case RTCP_NAME_MCPT:
            *ptInterface = RTCP_DEV_TYPE_STANDARD;
            break;

        /*以下属于网元间消息*/
        case RTCP_NAME_TCF:
        case RTCP_NAME_X:
        case RTCP_NAME_MME:
            *ptInterface = RTCP_DEV_TYPE_NET_UNIT;
            break;    

        default:
            x_WarnLog("Rtcp Msg error, Name=%lu\n", ulName);
            return XPOC_ERR_FAIL;
    } 

    return XPOC_ERR_SUCCESS;
}

UINT RtcpxRtcpCtrlMsg(UCHAR *pByte, UINT ulMaxLen, RtcpCtrlMsgS *pOutRtcpMsg)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_ONE_PARA(pByte);
    
    UINT ulReturn = XPOC_ERR_SUCCESS;
    SINT len = 0;
    RtcpCtrlMsgTypeE eMsgType = RTCP_CTRL_MSG_BUTT;
    UCHAR ucInterfaceFlag = 0;
    UINT ulName = 0;

    /*第一字节包含消息类型*/
    UCHAR ucSubType = (*pByte) & (RTCP_MSG_SUBTYPE_POSITION);
    Byte_Conv_U32(pByte+8, ulName, len); /*9~13字节存name*/

    /*name,subtype就能确定消息类型*/
    eMsgType = getRtcpMsgType(ulName, ucSubType);
    (void)rtcpGetInterfaceByName_dec(ulName, &ucInterfaceFlag);
    
    x_DebugLog("[FLOOR][RTCP] RtcpxRtcpCtrlMsg:name[0x%x],msgType[0x%x],interface[%d],maxLen[%d].\n", 
                ulName, eMsgType, ucInterfaceFlag, ulMaxLen);

    UINT ulByteLen = ulMaxLen;
        
    switch(eMsgType)
    {
        case D_FLOOR_REQUEST_SUBTYPE_UM:
            ulReturn = xFloorRequestMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_GRANTED_SUBTYPE_UM:
        case D_FLOOR_GRANTED_SUBTYPE_AM:
            ulReturn = xFloorGrantedMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_DENY_SUBTYPE_UM:
        case D_FLOOR_DENY_SUBTYPE_AM:
            ulReturn = xFloorDenyMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_RELEASE_SUBTYPE_UM:
        case D_FLOOR_RELEASE_SUBTYPE_AM:
            ulReturn = xFloorReleaseMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_IDLE_SUBTYPE_UM:
        case D_FLOOR_IDLE_SUBTYPE_AM:
            ulReturn = xFloorIdleMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_TAKEN_SUBTYPE_UM:
        case D_FLOOR_TAKEN_SUBTYPE_AM:
            ulReturn = xFloorTakenMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_REVOKE_SUBTYPE_UM:
            ulReturn = xFloorRevokeMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
        
        case D_FLOOR_QUEUE_POSITION_REQUEST_SUBTYPE_UM:
            ulReturn = xFloorQueuePositionRequestMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_QUEUE_POSITION_INFO_SUBTYPE_UM:
        case D_FLOOR_QUEUE_POSITION_INFO_SUBTYPE_AM:
            ulReturn = xFloorQueuePositionInfoMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_ACK_SUBTYPE_UM:
            ulReturn = xFloorAckMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_NOTIFY_SUBTYPE_UM:
        case D_FLOOR_NOTIFY_SUBTYPE_AM:
            ulReturn = xFloorNotifyMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        default:
            x_ErrorLog("xRtcpCtrlMsg default subtype[%d]!\n", ucSubType);
            return XPOC_ERR_FAIL;
    }

    XPOC_TRACEFUNC_OUT;
    return ulReturn;
}






rtcp_mod_encode.c


#include "rtcp_mod_decode.h"

RtcpCtrlMsgTypeE getRtcpMsgType(UINT ulName, UCHAR ucSubtype)
{
    RtcpCtrlMsgTypeE eMsgType = RTCP_CTRL_MSG_BUTT;
    switch (ulName)
    {
        case RTCP_NAME_MCPT:
        case RTCP_NAME_TCF:
        case RTCP_NAME_X:
        case RTCP_NAME_MME:
            eMsgType = (RtcpCtrlMsgTypeE)((UINT)D_FLOOR_MSG_BASE + ucSubtype);
            break;

        default:
            x_WarnLog("name[%x] subtype[%d] error.\n", ulName, ucSubtype);
            break;
    }
    
    return eMsgType;
}


UINT xFloorMsgHeadParse(UCHAR *pByte, UINT *pulByteLen, RtcpCtrlMsgS *pOutRtcpMsg, UCHAR ucInterfaceFlag)
{
    UCHAR ucSubtype = 0;    
    ucSubtype = (*pByte) & RTCP_MSG_SUBTYPE_POSITION;    

    /*版本号、填充比特、SubType*/
    pOutRtcpMsg->version = ((*pByte) & RTCP_MSG_VERSION_POSITION) >> 6;
    pOutRtcpMsg->p = ((*pByte) & RTCP_MSG_PADDING_POSITION) >> 5;
    pOutRtcpMsg->subtype = ucSubtype;
    *pulByteLen += sizeof(UCHAR);    

    /*PT域、length域、ssrc域*/
    Byte_Conv_U8(pByte + *pulByteLen, pOutRtcpMsg->pt, *pulByteLen);
    Byte_Conv_U16(pByte + *pulByteLen, pOutRtcpMsg->length, *pulByteLen);
    Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->ssrc, *pulByteLen);
    Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->ulName, *pulByteLen);

    if(RTCP_DEV_TYPE_NET_UNIT == ucInterfaceFlag)
    {
        Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->callId, *pulByteLen);
        Byte_Conv_U32(pByte + *pulByteLen, pOutRtcpMsg->nodeId, *pulByteLen);
        xUdnField(pByte, pulByteLen, &pOutRtcpMsg->udn);
    }
    else if(RTCP_DEV_TYPE_STANDARD != ucInterfaceFlag)
    {
        x_WarnLog("xRtcpCtrlMsg: Invalid Interface Flag!\n");
        return XPOC_ERR_FAIL;
    }

    /*消息类型*/
    pOutRtcpMsg->eMsgType = getRtcpMsgType(pOutRtcpMsg->ulName, ucSubtype);
    
    return XPOC_ERR_SUCCESS;
}


UINT xFloorPriorityField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataPriorityS *pstFloorPriority
)
{
    UCHAR ucTempValue = 0;
    
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorPriority)
    {
        x_WarnLog("xFloorPriorityField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->length, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPriority->priorityValue, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, ucTempValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorDurationField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataDurationS *pstFloorDuration
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorDuration)
    {
        x_WarnLog("xFloorDurationField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorDuration->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorDuration->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorDuration->durationValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorRejectCauseField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataRejectCauseS *pstFloorRejectCause
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorRejectCause)
    {
        x_WarnLog("xFloorRejectCauseField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorRejectCause->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorRejectCause->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorRejectCause->eRejectCause, *pulArrLen);
    if(pstFloorRejectCause->length > 2)
    {
        memcpy((UCHAR*)pstFloorRejectCause->rejectPhrase, pByte + *pulArrLen, pstFloorRejectCause->length - sizeof(USHORT));
        *pulArrLen += pstFloorRejectCause->length - sizeof(USHORT);
        *pulArrLen += (REMAINDER_SIZE - (pstFloorRejectCause->length - sizeof(USHORT)) % REMAINDER_SIZE) % REMAINDER_SIZE;
    }
    
    return XPOC_ERR_SUCCESS;
}

UINT xQueueInfoField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataQueueInfoS *pstFloorQueueInfo
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueueInfo)
    {
        x_WarnLog("xQueueInfoField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->length, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->queuePositionInfo, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueInfo->queuePriorityLevel, *pulArrLen);

    return XPOC_ERR_SUCCESS;
}

UINT xFloorGrantedPartyIdentityField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataGrantedPartyIdentityS *pstFloorGrantedPartyIdentity
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorGrantedPartyIdentity)
    {
        x_WarnLog("xFloorGrantedPartyIdentityField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorGrantedPartyIdentity->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorGrantedPartyIdentity->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorGrantedPartyIdentity->grantedPartyIdentity, pByte + *pulArrLen, pstFloorGrantedPartyIdentity->length);
    *pulArrLen += pstFloorGrantedPartyIdentity->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorGrantedPartyIdentity->length + sizeof(UCHAR) +sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorPermissionField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataPermissionS *pstFloorPermission
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorPermission)
    {
        x_WarnLog("xFloorPermissionField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPermission->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorPermission->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorPermission->permissionValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorUserIdField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataUserIdS *pstFloorUserId
)
{ 
    if(NULL == pstFloorUserId || NULL == pByte || NULL == pulArrLen)
    {
        x_WarnLog("xFloorUserIdField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorUserId->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorUserId->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorUserId->userId, pByte + *pulArrLen, pstFloorUserId->length);
    *pulArrLen += pstFloorUserId->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorUserId->length + sizeof(UCHAR) +sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueueSizeField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     FloorDataQueueSizeS *pstFloorQueueSize
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueueSize)
    {
        x_WarnLog("xFloorQueueSizeField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueSize->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueueSize->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorQueueSize->queueSizeValue, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorMsgSeqNumField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataMsgSeqNumS *pstFloorMsgSeqNum
)
{ 
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorMsgSeqNum)
    {
        x_WarnLog("xFloorMsgSeqNumField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorMsgSeqNum->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorMsgSeqNum->length, *pulArrLen);
    Byte_Conv_U16(pByte + *pulArrLen, pstFloorMsgSeqNum->msgSeqNum, *pulArrLen);
    
    return XPOC_ERR_SUCCESS;
}

UINT xUdnField
(
     UCHAR *pByte, 
     UINT *pulArrLen, 
     RtcpDataUDNS *pstUdn
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstUdn)
    {
        x_WarnLog("Byte2UdnField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstUdn->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstUdn->length, *pulArrLen);
    memcpy((UCHAR*)pstUdn->value, pByte + *pulArrLen, pstUdn->length);
    *pulArrLen += pstUdn->length;
    *pulArrLen += (REMAINDER_SIZE - (pstUdn->length + sizeof(UCHAR) + sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;

    return XPOC_ERR_SUCCESS;
}


/*************************************************
*****************  函数说明 **********************
* 函数名    : xFloorFieldContent
* 功能说明  : 字节流转换成话权消息消息的某个域
*************************************************/
UINT xFloorFieldContent( UINT ulFileId,  UCHAR *pByte,  UINT ulMaxLen,  UINT *pulRealLen,  RtcpVoid_t* pField)
{
    UINT ulReturn = XPOC_ERR_SUCCESS;

    UINT ulBeforeFieldContentLen = 0;
    USHORT uFieldLengthValue = 0;
    UCHAR uByteFieldId = 0;

    if(NULL == pByte || NULL == pulRealLen || NULL == pField)
    {
        x_WarnLog("Invalid param: pByte[%p], pulRealLen[%p], pField[%p].",
            pByte, pulRealLen, pField);
        return XPOC_ERR_FAIL;
    }

    ulBeforeFieldContentLen = *pulRealLen + 2;
    uByteFieldId = (pByte + *pulRealLen)[0];    
    if(ulBeforeFieldContentLen >= ulMaxLen)
    {
        //已经解析到头了或域标识不一致,跳过该域的解析直接退出
        return XPOC_ERR_FAIL;
    } else if(ulFileId != (UINT)uByteFieldId)
    {
        //域标识不一致
        x_InfoLog("Different Field-id: want ulFieldId[%u], InRtcp-fieldId[%u].", 
            ulFileId, (UINT)uByteFieldId);
        return XPOC_ERR_FAIL;
    }

    uFieldLengthValue = (USHORT)(pByte + *pulRealLen)[1];  

    if((ulBeforeFieldContentLen + uFieldLengthValue) > ulMaxLen)
    {
        //域长度不合理,打印日志
        x_WarnLog("Invalid field[%u] length[%u]. With ulBeforeFieldContentLen[%u] over ulMaxLen[%u].",
            ulFileId, uFieldLengthValue, ulBeforeFieldContentLen, ulMaxLen);
        return XPOC_ERR_FAIL;
    }

    switch(ulFileId)
    {
        case D_FLOOR_DATA_ID_PRIORITY: 
        {
            xFloorPriorityField(pByte, pulRealLen, (FloorDataPriorityS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_DURATION:
        {
            xFloorDurationField(pByte, pulRealLen, (FloorDataDurationS*)pField);
            break;
        }        
        case D_FLOOR_DATA_ID_REJECT_CAUSE:
        {
            xFloorRejectCauseField(pByte, pulRealLen, (FloorDataRejectCauseS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUE_INFO:
        {
            xQueueInfoField(pByte, pulRealLen, (FloorDataQueueInfoS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_GRANTED_PARTY_IDENTITY:
        {
            xFloorGrantedPartyIdentityField(pByte, pulRealLen, (FloorDataGrantedPartyIdentityS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_PERMISSION:
        {
            xFloorPermissionField(pByte, pulRealLen, (FloorDataPermissionS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_USER_ID:
        {
            xFloorUserIdField(pByte, pulRealLen, (FloorDataUserIdS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUE_SIZE:
        {
            xFloorQueueSizeField(pByte, pulRealLen, (FloorDataQueueSizeS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_MSG_SEQ_NUM:
        {
            xFloorMsgSeqNumField(pByte, pulRealLen, (FloorDataMsgSeqNumS*)pField);
            break;
        }
        case D_FLOOR_DATA_ID_QUEUED_USER_ID:
        {
            xQueuedUserIdField(pByte, pulRealLen, (FloorDataQueuedUserIdS*)pField);
            break;
        }
        default : /* Invalid API received */
            x_WarnLog("Default case, unknow ulFileId[%u].\n", ulFileId);
            break;
    }

    return ulReturn;
}

UINT xQueuedUserIdField
(
     UCHAR *pByte,
     UINT *pulArrLen,
     FloorDataQueuedUserIdS *pstFloorQueuedUserId
)
{
    if(NULL == pByte || NULL == pulArrLen || NULL == pstFloorQueuedUserId)
    {
        x_WarnLog("xQueuedUserIdField input is null!\n");
        return XPOC_ERR_FAIL;
    }

    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueuedUserId->id, *pulArrLen);
    Byte_Conv_U8(pByte + *pulArrLen, pstFloorQueuedUserId->length, *pulArrLen);
    memcpy((UCHAR*)pstFloorQueuedUserId->queuedUserId, pByte + *pulArrLen, pstFloorQueuedUserId->length);
    *pulArrLen += pstFloorQueuedUserId->length;
    *pulArrLen += (REMAINDER_SIZE - (pstFloorQueuedUserId->length + sizeof(UCHAR) + sizeof(UCHAR)) % REMAINDER_SIZE) % REMAINDER_SIZE;
    
    return XPOC_ERR_SUCCESS;
}


UINT xFloorRequestMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    }

    xFloorFieldContent(D_FLOOR_DATA_ID_PRIORITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRequest.priorityField);
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRequest.userIdField);
    }
    
    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorGrantedMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    }

    xFloorFieldContent(D_FLOOR_DATA_ID_DURATION, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.durationField);

    
    xFloorFieldContent(D_FLOOR_DATA_ID_PRIORITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.priorityField);  
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorGranted.userIdField); 
    }

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorDenyMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }
    
    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.rejectCauseField); 
    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.userIdField);    
    }
    //xFloorFieldContent(D_FLOOR_DATA_ID_TRACK, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorDeny.trackField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorReleaseMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{

    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRelease.userIdField); 
    }
    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRelease.releaseCauseField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorIdleMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_MSG_SEQ_NUM, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorIdle.msgSeqNumField); 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorTakenMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_GRANTED_PARTY_IDENTITY, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.grantedPartyIdentityField); 
    xFloorFieldContent(D_FLOOR_DATA_ID_PERMISSION, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.permissionField); 

    xFloorFieldContent(D_FLOOR_DATA_ID_MSG_SEQ_NUM, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorTaken.msgSeqNumField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorRevokeMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    xFloorFieldContent(D_FLOOR_DATA_ID_REJECT_CAUSE, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorRevoke.rejectCauseField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueuePositionRequestMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionRequest.userIdField); 
    }
    //xFloorFieldContent(D_FLOOR_DATA_ID_TRACK, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionRequest.trackField); 
    
    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorQueuePositionInfoMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    if(RTCP_NAME_MME == pOutRtcpMsg->ulName)
    {
        xFloorFieldContent(D_FLOOR_DATA_ID_USER_ID, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionInfo.userIdField); 
    }
    
    xFloorFieldContent(D_FLOOR_DATA_ID_QUEUE_INFO, pByte, *pulByteLen, &ulRetLen, &pOutRtcpMsg->unFloorMsg.FloorQueuePositionInfo.queueInfoField); 

    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}

UINT xFloorAckMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    *pulByteLen = ulRetLen;

    return XPOC_ERR_SUCCESS;
}

UINT xFloorNotifyMsg( UCHAR *pByte,  UINT *pulByteLen,  RtcpCtrlMsgS *pOutRtcpMsg,  UCHAR ucInterfaceFlag)
{
    UINT ulRetLen = 0;
    if(NULL == pByte || NULL == pulByteLen || NULL == pOutRtcpMsg)
    {
        x_WarnLog("Invalid param: pByte[%p], pulByteLen[%p], pOutRtcpMsg[%p].",
            pByte, pulByteLen, pOutRtcpMsg);
        return XPOC_ERR_FAIL;
    }

    if(RTCP_MSG_HEAD_LEN <= *pulByteLen)   
    {
        xFloorMsgHeadParse(pByte, &ulRetLen, pOutRtcpMsg, ucInterfaceFlag);
    }
    else
    {
        x_WarnLog("pulByteLen-value[%u] less than RTCP_MSG_HEAD_LEN[%u]", 
            *pulByteLen, RTCP_MSG_HEAD_LEN);
        return XPOC_ERR_FAIL;
    } 

    *pulByteLen = ulRetLen;
    
    return XPOC_ERR_SUCCESS;
}



UINT rtcpGetInterfaceByName_dec(UINT ulName, UCHAR *ptInterface)
{
    X_NULL_POINTER_CHK_ONE_PARA(ptInterface);

    switch (ulName)
    {
         /*MCPC/MCMC属于标准RTCP消息*/
        case RTCP_NAME_MCPT:
            *ptInterface = RTCP_DEV_TYPE_STANDARD;
            break;

        /*以下属于网元间消息*/
        case RTCP_NAME_TCF:
        case RTCP_NAME_X:
        case RTCP_NAME_MME:
            *ptInterface = RTCP_DEV_TYPE_NET_UNIT;
            break;    

        default:
            x_WarnLog("Rtcp Msg error, Name=%lu\n", ulName);
            return XPOC_ERR_FAIL;
    } 

    return XPOC_ERR_SUCCESS;
}

UINT RtcpxRtcpCtrlMsg(UCHAR *pByte, UINT ulMaxLen, RtcpCtrlMsgS *pOutRtcpMsg)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_ONE_PARA(pByte);
    
    UINT ulReturn = XPOC_ERR_SUCCESS;
    SINT len = 0;
    RtcpCtrlMsgTypeE eMsgType = RTCP_CTRL_MSG_BUTT;
    UCHAR ucInterfaceFlag = 0;
    UINT ulName = 0;

    /*第一字节包含消息类型*/
    UCHAR ucSubType = (*pByte) & (RTCP_MSG_SUBTYPE_POSITION);
    Byte_Conv_U32(pByte+8, ulName, len); /*9~13字节存name*/

    /*name,subtype就能确定消息类型*/
    eMsgType = getRtcpMsgType(ulName, ucSubType);
    (void)rtcpGetInterfaceByName_dec(ulName, &ucInterfaceFlag);
    
    x_DebugLog("[FLOOR][RTCP] RtcpxRtcpCtrlMsg:name[0x%x],msgType[0x%x],interface[%d],maxLen[%d].\n", 
                ulName, eMsgType, ucInterfaceFlag, ulMaxLen);

    UINT ulByteLen = ulMaxLen;
        
    switch(eMsgType)
    {
        case D_FLOOR_REQUEST_SUBTYPE_UM:
            ulReturn = xFloorRequestMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_GRANTED_SUBTYPE_UM:
        case D_FLOOR_GRANTED_SUBTYPE_AM:
            ulReturn = xFloorGrantedMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_DENY_SUBTYPE_UM:
        case D_FLOOR_DENY_SUBTYPE_AM:
            ulReturn = xFloorDenyMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_RELEASE_SUBTYPE_UM:
        case D_FLOOR_RELEASE_SUBTYPE_AM:
            ulReturn = xFloorReleaseMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_IDLE_SUBTYPE_UM:
        case D_FLOOR_IDLE_SUBTYPE_AM:
            ulReturn = xFloorIdleMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_TAKEN_SUBTYPE_UM:
        case D_FLOOR_TAKEN_SUBTYPE_AM:
            ulReturn = xFloorTakenMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        case D_FLOOR_REVOKE_SUBTYPE_UM:
            ulReturn = xFloorRevokeMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
        
        case D_FLOOR_QUEUE_POSITION_REQUEST_SUBTYPE_UM:
            ulReturn = xFloorQueuePositionRequestMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_QUEUE_POSITION_INFO_SUBTYPE_UM:
        case D_FLOOR_QUEUE_POSITION_INFO_SUBTYPE_AM:
            ulReturn = xFloorQueuePositionInfoMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_ACK_SUBTYPE_UM:
            ulReturn = xFloorAckMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;
            
        case D_FLOOR_NOTIFY_SUBTYPE_UM:
        case D_FLOOR_NOTIFY_SUBTYPE_AM:
            ulReturn = xFloorNotifyMsg(pByte, &ulByteLen, pOutRtcpMsg, ucInterfaceFlag);
            break;

        default:
            x_ErrorLog("xRtcpCtrlMsg default subtype[%d]!\n", ucSubType);
            return XPOC_ERR_FAIL;
    }

    XPOC_TRACEFUNC_OUT;
    return ulReturn;
}






rtcp_mod_port.c



#include "rtcp_mod_proc.h"
#include "rtcp_mod_port.h"
#include "XpocRtcpMsg.h"
#include "ConfStruct_2.h"
#include "ConfFuncApi.h"
#include "XpocCommFunc.h"

extern RtcpQueueS g_sRtcpSendQueue;
extern RtcpFdS g_RtcpFd;
extern const char* g_ModuleName[XMOD_TYPE_BUTT];
RtcpModCtxS gRtcpModCtxData;

#if 0
#endif

//  TODO: !!! RTCP线程和模块没有真实使用. RTCP功能被 FLOOR / MDE 调用.

UINT rtcpModFirstStart(T_ModCtxS* ptModCtx)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
    
    memset(&gRtcpModCtxData,0,sizeof(RtcpModCtxS));
    ptModCtx->pAppData = &gRtcpModCtxData;
    
    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}

UINT rtcpModFinishStart(T_ModCtxS* ptModCtx)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptModCtx->pAppData);

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;  
}

UINT rtcpModMsgProc(const T_ModCtxS* ptModCtx, const T_PlatHead* ptPlatHdr, const T_ModMsgHead* ptXPocHdr)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_THREE_PARA(ptModCtx, ptPlatHdr, ptXPocHdr);

    if((XMOD_TYPE_FLOOR == ptPlatHdr->ucSrcMId))
    {
        x_InfoLog("--->RTCP: srcMod[%d:%s] ulMsgId[0x%0x] ulMsgLen[%d],ulSrcCbId[0x%0x] ulDstCbId[0x%0x] \n",
                    ptPlatHdr->ucSrcMId,g_ModuleName[ptPlatHdr->ucSrcMId],
                    ptXPocHdr->ulMsgId,ptXPocHdr->ulMsgLen,ptXPocHdr->ulSrcCbId,ptXPocHdr->ulDstCbId);
    }
    else
    {
        x_WarnLog("ptPlatHdr.ucSrcMId[%d:%s] error,\n", ptPlatHdr->ucSrcMId,g_ModuleName[ptPlatHdr->ucSrcMId]);
        return XPOC_ERR_INVALID_MSG;
    }

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS; 
}

UINT rtcpModTimerProc(const T_ModCtxS* ptModCtx, T_ProcTimeCtx* pTimerCtx)
{
    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, pTimerCtx);

    //

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}





rtcp_mod_proc.c


#include "XpocCommMsgStruct.h"
#include "XpocRtcpMsg.h"
#include "rtcp_mod_proc.h"
#include "rtcp_mod_port.h"
#include "rtcp_mod_encode.h"
#include "rtcp_mod_decode.h"
#include "XpocCommFunc.h"

#include "ConfStruct_2.h"
#include "ConfFuncApi.h"

//#include <sys/ioctl.h>
//#include <net/if.h>

RtcpParamS g_sRtcpPraram = {0, 0, 0, 0};
SINT g_RtcpEpollSet = -1;
RtcpFdS g_RtcpFd = {-1, 0, 0};

/*RTCP的收、发线程*/
pthread_t g_threadRecvRtcp;
pthread_t g_threadSendRtcp;

/*rtcp发送队列*/
RtcpQueueS g_sRtcpSendQueue;
extern const char* glbFloorName[32];

ULONGLONG RtcpGetCurrMilliSecondTime(void)
{
    ULONGLONG uMillSec = 0;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    uMillSec = (ULONGLONG)tv.tv_sec * 1000;
    uMillSec += tv.tv_usec / 1000;
    return uMillSec;
}


SINT rtcpOpenSocket(RtcpFdS *pFdInfo, UINT ulIP, USHORT port)
{
    SINT socketFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(socketFd < 0)
    {
        x_WarnLog("alloc socket error. port=%d, errno=%d\n", port, errno);
        return -1;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(ulIP);
    if(bind(socketFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        close(socketFd);
        x_WarnLog("bind[%lu:%d] failed, errno=%d\n", ulIP, port, errno);
        return -1;
    }
    pFdInfo->ulIP = ulIP;
    pFdInfo->port = port;
    pFdInfo->fd = socketFd;

    // int retval = 0;
    // int optval = 0;
    // socklen_t opt_len = sizeof(optval);
    // retval = getsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, (void *)&optval, &opt_len);
    // if(0!=retval)
    // {
    //     x_ErrorLog("[TCP] fd[%d]S getsockopt SO_RCVBUF fail. optval[%d],retval[%d].", socketFd, optval, retval);
    // }
    // else
    // {
    //     x_InfoLog("[TCP] fd[%d]S getsockopt SO_RCVBUF OK. optval[%d].", socketFd, optval);
    // }

    // 获取网卡发送队列大小,若小于 NETCARD_QUEUE_SIZE,修改之
    // struct ifreq ifr;
    // memset(&ifr, 0, sizeof(ifr));
    // strncpy(ifr.ifr_name, "ens192", sizeof(ifr.ifr_name));

    // if (-1 == ioctl(socketFd, SIOCGIFTXQLEN, &ifr))
    // {
    //     x_ErrorLog("Get tx queue length failed.");
    // }
    // else
    // {
    //     x_InfoLog("Get tx queue length success, len [%d]", ifr.ifr_qlen);
    // }

    // if (ifr.ifr_qlen < TX_QUEUE_SIZE)
    // {
    //     ifr.ifr_qlen = TX_QUEUE_SIZE;
    //     if (-1 == ioctl(socketFd, SIOCSIFTXQLEN, &ifr))
    //     {
    //         x_ErrorLog("Set tx queue length failed.");
    //     }
    //     else
    //     {
    //         x_InfoLog("Set dev netcard queue length success.");
    //     }
    // }
    
    return socketFd;
}

SINT rtcpOpenLocalSocket(RtcpFdS *pFdInfo, char* pcSerPath)
{
    if (strlen(pcSerPath) < 1)
    {
        x_ErrorLog("Open local socket failed, path is null.");
        return -1;
    }
    
    unlink (pcSerPath);       /*删除原有server_socket对象*/

    SINT socketFd = socket(AF_UNIX, SOCK_DGRAM, IPPROTO_IP);
    if(socketFd < 0)
    {
        x_WarnLog("alloc socket error. errno=%d\n", errno);
        return -1;
    }

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));

    addr.sun_family = AF_UNIX;
	strcpy(addr.sun_path, pcSerPath);
    if(bind(socketFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        close(socketFd);
        x_WarnLog("bind[%s] failed, errno=%d\n", pcSerPath, errno);
        return -1;
    }
    pFdInfo->ulIP = 0;
    pFdInfo->port = 0;
    pFdInfo->fd = socketFd;
    
    return socketFd;
}

/*epoll接收rtcp线程*/
void *threadRecvRtcp(void *pParam)
{
    XPOC_TRACEFUNC_IN;

    (void)pParam;
    SINT iFdNum = 0;
    SINT i = 0;
    RtcpFdS *pFdInfo = NULL;
    UCHAR btTempRecv[RTCP_PACK_DATA_LEN] = {0};
    struct sockaddr_in addrFrom;
    SINT iRecvLen = 0;
    SINT iAddrLen = sizeof(struct sockaddr_in);
    struct epoll_event evt[RTCP_MAX_EPOLL_FD];
    RtcpCtrlMsgS sRtcpCtrlMsg;

    memset(&sRtcpCtrlMsg, 0, sizeof(RtcpCtrlMsgS));

    while(1)
    {
        iFdNum = epoll_wait(g_RtcpEpollSet, evt, RTCP_MAX_EPOLL_FD, 100);
        if(iFdNum <= 0)
        {
//            x_WarnLog("epoll_wait FdNum = %d, errno=%d\r\n", iFdNum, errno); //too much log
            continue; 
        }

        for (i = 0; i < iFdNum; i++)
        {
            if(evt[i].events & EPOLLIN)
            {
                pFdInfo = (RtcpFdS*)evt[i].data.ptr;
                if(NULL == pFdInfo)
                {
                   x_WarnLog("RTCP fd data NULL\r\n");
                   continue;
                }

                iRecvLen = recvfrom(pFdInfo->fd, btTempRecv, RTCP_PACK_DATA_LEN, 0, (struct sockaddr *)&addrFrom, (socklen_t *)&iAddrLen);
                if(iRecvLen <= 0)
                {
                    continue;
                }

                /*parse rtcp msg, and callback*/
                if(XPOC_ERR_SUCCESS != RtcpxRtcpCtrlMsg(btTempRecv, iRecvLen, &sRtcpCtrlMsg))
                {
                    x_WarnLog("parse RTCP floor msg failed.\r\n");
                    continue;
                }

                x_DebugLog("[FLOOR]recv from cce. User [%s], floor type[%d],subType[%d],name[0x%x],callId[%d],nodeId[%d].",
                        sRtcpCtrlMsg.udn.value, sRtcpCtrlMsg.eMsgType, sRtcpCtrlMsg.subtype, sRtcpCtrlMsg.ulName, 
                        sRtcpCtrlMsg.callId, sRtcpCtrlMsg.nodeId);

                if(g_sRtcpPraram.fn)
                {
                    g_sRtcpPraram.fn(&sRtcpCtrlMsg, g_sRtcpPraram.pUserData);
                }
            }
        }            
    }

    XPOC_TRACEFUNC_OUT;
}

/*RTCP发送线程*/
void *threadSendRtcp(void *pParam)
{
    XPOC_TRACEFUNC_IN;

    (void)pParam;
    RtcpPaketNodeS *pRtcpPack = NULL;    
    RtcpNodeIndex_t *pPktNodeIndex = NULL;

    while(1)
    {
        pPktNodeIndex = NULL;
        /* get a PktNode to send its data */
        RtcpIndexManageGetFromHead(&g_sRtcpSendQueue.stIndexManageCtx.stSendList, &pPktNodeIndex);
        /* no data to send */
        if(NULL == pPktNodeIndex)
        {
            usleep(1000);/* FIXME: sleep 1ms */
            continue;
        }

        pRtcpPack = &g_sRtcpSendQueue.pkt[pPktNodeIndex->u32PktNodeIndex];
        x_DebugLog("[FLOOR][RTCP] ready Send PktNodeIdx[%d],msgType[%d],subType[%d],name[0x%x],callId[%d],nodeId[%d],udn[%s].",
                    pPktNodeIndex->u32PktNodeIndex, pRtcpPack->sRtcpMsg.eMsgType, pRtcpPack->sRtcpMsg.subtype, pRtcpPack->sRtcpMsg.ulName, 
                    pRtcpPack->sRtcpMsg.callId, pRtcpPack->sRtcpMsg.nodeId, pRtcpPack->sRtcpMsg.udn.value);

        /* NULL Packet */
        if(0 == pRtcpPack->sRtcpMsg.pt)
        {
            /* this pPktNodeIndex is free now */
            RtcpIndexManageInsertToTail(&g_sRtcpSendQueue.stIndexManageCtx.stFreeList, pPktNodeIndex);
            continue;
        }
        else
        {
            ULONGLONG u64CurrMiliSec = 0;
            u64CurrMiliSec = RtcpGetCurrMilliSecondTime();
            //(void)sendRtcpPacket(pRtcpPack, u64CurrMiliSec);
            (void)sendRtcpPacket1(pRtcpPack, u64CurrMiliSec);
            pRtcpPack->sRtcpMsg.pt = 0;

            /* this pPktNodeIndex is free now */
            RtcpIndexManageInsertToTail(&g_sRtcpSendQueue.stIndexManageCtx.stFreeList, pPktNodeIndex);
            continue;
        }
    }

    XPOC_TRACEFUNC_OUT;
}

SINT rtcpEpollSetAddFd(SINT iEpollSet, RtcpFdS *pFdInfo)
{    
    struct epoll_event evt;
    USHORT port = pFdInfo->port;
    SINT socketFd = pFdInfo->fd;

    /* epoll add socket, fd与ptr不可同时使用 */
    evt.data.ptr = (void*)pFdInfo;
    evt.events = EPOLLIN;
    if(epoll_ctl(iEpollSet, EPOLL_CTL_ADD, socketFd, &evt) < 0)
    {
        close(socketFd);
        x_WarnLog("epoll_ctl(ADD) socket[%lu:%d] failed, epollFd[%d],rtpFd[%d],errno=%d.\n", 
                   pFdInfo->ulIP, port, iEpollSet, socketFd, errno);
        return -1;
    }
    x_InfoLog("[RTCP] epoll_ctl(ADD). epollFd[%d],rtpFd[%d].", iEpollSet, socketFd);

    return socketFd;
}

UINT rtcpInitFloorThread(RtcpIpAddrSt *ptLocIpAddr, fnOnRecvRtcpCtrlMsg fn, void *ptData)
{
    XPOC_TRACEFUNC_IN;

    g_sRtcpPraram.ulIP = ptLocIpAddr->ulIpInt;
    g_sRtcpPraram.usRtcpPort = ptLocIpAddr->usPort;
    g_sRtcpPraram.fn = fn;
    g_sRtcpPraram.pUserData = ptData;
    
    /*create epoll*/
    g_RtcpEpollSet = epoll_create(RTCP_MAX_EPOLL_FD);
    if(g_RtcpEpollSet < 0)
    {
        x_ErrorLog("create rtcp epoll set failed.\n");
        return XPOC_ERR_FAIL;
    }
    x_InfoLog("rtcp epoll_create, epollFd[%d].", g_RtcpEpollSet);

    /*init socket*/
    if(rtcpOpenSocket(&g_RtcpFd, ptLocIpAddr->ulIpInt, ptLocIpAddr->usPort) < 0)
    {
        x_ErrorLog("open rtcp socket failed.\n");
        return XPOC_ERR_FAIL;
    }

    if(rtcpEpollSetAddFd(g_RtcpEpollSet, &g_RtcpFd) < 0)
    {
        x_ErrorLog("rtcp epoll add socket failed.\n");
        return XPOC_ERR_FAIL;            
    }

    /* initialize the PktNodeIndex array and the list */
    memset(&g_sRtcpSendQueue, 0, sizeof(RtcpQueueS));
    rtcpIndexManageInitCtx(&(g_sRtcpSendQueue.stIndexManageCtx),
                            g_sRtcpSendQueue.astPktNodeIndex,
                            (sizeof(g_sRtcpSendQueue.astPktNodeIndex)/sizeof(g_sRtcpSendQueue.astPktNodeIndex[0])));

    /*create epoll thread*/
    memset(&g_threadRecvRtcp, 0, sizeof(pthread_t));
    int ret = pthread_create(&g_threadRecvRtcp, 0, threadRecvRtcp, NULL);
    if(0 != ret)
    {
        x_ErrorLog("create rtcp recv thread failed.\n");
        return XPOC_ERR_FAIL;
    }

    /*create send thread*/
    memset(&g_threadSendRtcp, 0, sizeof(pthread_t));
    ret = pthread_create(&g_threadSendRtcp, 0, threadSendRtcp, NULL);
    if(0 != ret)
    {
        x_ErrorLog("create rtcp send thread failed.\n");
        return XPOC_ERR_FAIL;
    }

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}

// 本地套接字
UINT rtcpInitFloorThread1(RtcpIpAddrSt *ptLocIpAddr, fnOnRecvRtcpCtrlMsg fn, void *ptData)
{
    XPOC_TRACEFUNC_IN;

    g_sRtcpPraram.ulIP = ptLocIpAddr->ulIpInt;
    g_sRtcpPraram.usRtcpPort = ptLocIpAddr->usPort;
    g_sRtcpPraram.fn = fn;
    g_sRtcpPraram.pUserData = ptData;
    
    /*create epoll*/
    g_RtcpEpollSet = epoll_create(RTCP_MAX_EPOLL_FD);
    if(g_RtcpEpollSet < 0)
    {
        x_ErrorLog("create rtcp epoll set failed.\n");
        return XPOC_ERR_FAIL;
    }
    x_InfoLog("rtcp epoll_create, epollFd[%d].", g_RtcpEpollSet);

    /*init socket*/
    if(rtcpOpenLocalSocket(&g_RtcpFd, ptLocIpAddr->acLocalPath) < 0)
    {
        x_ErrorLog("open rtcp socket failed.\n");
        return XPOC_ERR_FAIL;
    }

    if(rtcpEpollSetAddFd(g_RtcpEpollSet, &g_RtcpFd) < 0)
    {
        x_ErrorLog("rtcp epoll add socket failed.\n");
        return XPOC_ERR_FAIL;            
    }

    /* initialize the PktNodeIndex array and the list */
    memset(&g_sRtcpSendQueue, 0, sizeof(RtcpQueueS));
    rtcpIndexManageInitCtx(&(g_sRtcpSendQueue.stIndexManageCtx),
                            g_sRtcpSendQueue.astPktNodeIndex,
                            (sizeof(g_sRtcpSendQueue.astPktNodeIndex)/sizeof(g_sRtcpSendQueue.astPktNodeIndex[0])));

    /*create epoll thread*/
    memset(&g_threadRecvRtcp, 0, sizeof(pthread_t));
    int ret = pthread_create(&g_threadRecvRtcp, 0, threadRecvRtcp, NULL);
    if(0 != ret)
    {
        x_ErrorLog("create rtcp recv thread failed.\n");
        return XPOC_ERR_FAIL;
    }

    /*create send thread*/
    memset(&g_threadSendRtcp, 0, sizeof(pthread_t));
    ret = pthread_create(&g_threadSendRtcp, 0, threadSendRtcp, NULL);
    if(0 != ret)
    {
        x_ErrorLog("create rtcp send thread failed.\n");
        return XPOC_ERR_FAIL;
    }

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}

SINT sendRtcpPacket(RtcpPaketNodeS *pPktNode, ULONGLONG u64NowMilliSec)
{
    XPOC_TRACEFUNC_IN;

    SINT ret = 0;
    SINT socketFd = -1;
    SINT iAddrLen = 0;
    UCHAR btPktData[RTCP_PACK_DATA_LEN] = {0};
    UINT ulPktLen = 0;
    UINT retRtcp = XPOC_ERR_FAIL;    

    if(NULL == pPktNode)
    {
        x_WarnLog("Rtcp floor packet null, send failed.\n");
        return -1;
    }
    
    iAddrLen = sizeof(struct sockaddr_in);
    socketFd = pPktNode->fd;
    ulPktLen = sizeof(btPktData);
    retRtcp = RtcpCtrlMsg2RtcpByte(&pPktNode->sRtcpMsg, btPktData, &ulPktLen);
    if(XPOC_ERR_FAIL == retRtcp)
    {
        x_WarnLog("Rtcp Msg error, FloorRtcpCtrlMsgW failed\n");
        return -1;
    }
    
    ret = sendto(socketFd, btPktData, ulPktLen, 0, (struct sockaddr*)&pPktNode->addrTo, iAddrLen);
    pPktNode->u64LastSendMilliSec = u64NowMilliSec;
    pPktNode->ucSentTimes++;

    char *ptStrIp = inet_ntoa(pPktNode->addrTo.sin_addr);
    USHORT usPort = ntohs(pPktNode->addrTo.sin_port);

    if (ret > 0)
    {
        x_DebugLog("[FLOOR][RTCP] sendto[%s:%d]. rtcp msg[%s(%d)],times[%d],callId[%d],udn[%s], Len [%d].", 
              ptStrIp, usPort, glbFloorName[pPktNode->sRtcpMsg.eMsgType], pPktNode->sRtcpMsg.eMsgType, pPktNode->ucSentTimes,
              pPktNode->sRtcpMsg.callId, pPktNode->sRtcpMsg.udn.value, ulPktLen);
        
        //usleep(10);
    }
    else
    {
        x_ErrorLog("[FLOOR][RTCP] sendto[%s:%d] Failed. rtcp msg[%s(%d)],times[%d],callId[%d],udn[%s], Len [%d].", 
              ptStrIp, usPort, glbFloorName[pPktNode->sRtcpMsg.eMsgType], pPktNode->sRtcpMsg.eMsgType, pPktNode->ucSentTimes,
              pPktNode->sRtcpMsg.callId, pPktNode->sRtcpMsg.udn.value, ulPktLen);
    }
    
    XPOC_TRACEFUNC_OUT;
    return ret;
}

SINT sendRtcpPacket1(RtcpPaketNodeS *pPktNode, ULONGLONG u64NowMilliSec)
{
    XPOC_TRACEFUNC_IN;

    SINT ret = 0;
    SINT socketFd = -1;
    SINT iAddrLen = 0;
    UCHAR btPktData[RTCP_PACK_DATA_LEN] = {0};
    UINT ulPktLen = 0;
    UINT retRtcp = XPOC_ERR_FAIL;    

    if(NULL == pPktNode)
    {
        x_WarnLog("Rtcp floor packet null, send failed.\n");
        return -1;
    }
    
    iAddrLen = sizeof(struct sockaddr_un);
    socketFd = pPktNode->fd;
    ulPktLen = sizeof(btPktData);
    retRtcp = RtcpCtrlMsg2RtcpByte(&pPktNode->sRtcpMsg, btPktData, &ulPktLen);
    if(XPOC_ERR_FAIL == retRtcp)
    {
        x_WarnLog("Rtcp Msg error, FloorRtcpCtrlMsgW failed\n");
        return -1;
    }
    
    ret = sendto(socketFd, btPktData, ulPktLen, 0, (struct sockaddr*)&pPktNode->udsAddrTo, iAddrLen);
    pPktNode->u64LastSendMilliSec = u64NowMilliSec;
    pPktNode->ucSentTimes++;

    if (ret > 0)
    {
        x_DebugLog("[FLOOR][RTCP] send success.rtcp msg[%s(%d)],times[%d],callId[%d],udn[%s], Len [%d].", 
                glbFloorName[pPktNode->sRtcpMsg.eMsgType], pPktNode->sRtcpMsg.eMsgType, pPktNode->ucSentTimes,
                pPktNode->sRtcpMsg.callId, pPktNode->sRtcpMsg.udn.value, ulPktLen);
        
        //usleep(10);
    }
    else
    {
        x_ErrorLog("[FLOOR][RTCP] send Failed. rtcp msg[%s(%d)],times[%d],callId[%d],udn[%s], Len [%d].", 
              glbFloorName[pPktNode->sRtcpMsg.eMsgType], pPktNode->sRtcpMsg.eMsgType, pPktNode->ucSentTimes,
              pPktNode->sRtcpMsg.callId, pPktNode->sRtcpMsg.udn.value, ulPktLen);
    }
    
    XPOC_TRACEFUNC_OUT;
    return ret;
}

UINT rtcpGetDstParamByMsgTye(RtcpCtrlMsgTypeE eMsgType, UINT *ptSendMsgId, UINT *ptDstModId)
{
    X_NULL_POINTER_CHK_TWO_PARA(ptSendMsgId, ptDstModId);

    UINT ulSendMsgId = 0;

    switch(eMsgType)
    {
        case D_FLOOR_REQUEST_SUBTYPE_UM:
        {
            ulSendMsgId = EV_FLOOR_REQUEST;
            break;
        }
        
        case D_FLOOR_RELEASE_SUBTYPE_UM:
        case D_FLOOR_RELEASE_SUBTYPE_AM:
        {  
            ulSendMsgId = EV_FLOOR_RELEASE;
            break;
        }
        
        case D_FLOOR_QUEUE_POSITION_REQUEST_SUBTYPE_UM:
        {
            ulSendMsgId = EV_FLOOR_QUEUE_POS_REQ;
            break;
        }
        
        case D_FLOOR_NOTIFY_SUBTYPE_UM:
        case D_FLOOR_NOTIFY_SUBTYPE_AM:
        {
            ulSendMsgId = EV_FLOOR_XXXX;
            break;
        }
        
        case D_FLOOR_ACK_SUBTYPE_UM:
        {
            ulSendMsgId = EV_FLOOR_ACK;
            break;
        }

        default:
        {
            x_WarnLog("Recv Msg Type Err,MsgType=[%u].\n", eMsgType);
            return XPOC_ERR_FAIL;
        }
    }

    *ptSendMsgId = ulSendMsgId;
    *ptDstModId = XMOD_TYPE_FLOOR;

    return XPOC_ERR_SUCCESS;

}

#if 0
#endif

UINT rtcpIndexManageInitCtx
(
     RtcpIndexManageCtx_t *pManageCtx, 
     RtcpNodeIndex_t * pastRtcpNodeIndex, 
      UINT u32NodeIndexCount
)
{
    UINT iRet = XPOC_ERR_SUCCESS;

    if(NULL == pManageCtx || NULL == pastRtcpNodeIndex || 0 == u32NodeIndexCount)
    {
        iRet = XPOC_ERR_FAIL;
        x_ErrorLog("Invalid param: pManageCtx[%p], pastRtcpNodeIndex[%p], u32NodeIndexCount[%u].",
            pManageCtx, pastRtcpNodeIndex, u32NodeIndexCount);
        return iRet;
    }

    do
    {
        /* Initialize free list of manage ctx.*/
        volatile RtcpNodeIndexList_t *pstFreeList = &pManageCtx->stFreeList;

        pstFreeList->s32Count = 0;
        pstFreeList->u32LockStatus = RTCP_LIST_UNLOCKED;
        /*------------------------------------------------------*/
        pstFreeList->EmptyNode.u32PktNodeIndex = 0xFFFFFFFF;
        pstFreeList->EmptyNode.pNext = NULL;
        pstFreeList->pHead = &pstFreeList->EmptyNode;
        pstFreeList->pTail = &pstFreeList->EmptyNode;

        /* Insert all free node. */
        UINT u32Index = 0;
        for (u32Index = 0; u32Index < u32NodeIndexCount; u32Index++)
        {
            pastRtcpNodeIndex[u32Index].u32PktNodeIndex = u32Index;
            pastRtcpNodeIndex[u32Index].pNext = NULL;
            /* Insert to freeList tail. */
            pstFreeList->pTail->pNext = (PRtcpNodeIndex_t)&pastRtcpNodeIndex[u32Index];
            pstFreeList->pTail = (RtcpNodeIndex_t*)pstFreeList->pTail->pNext;
            pstFreeList->s32Count += 1;
        }
        /*------------------------------------------------------*/

        /* Initialize free list of manage ctx.*/
        volatile RtcpNodeIndexList_t* pSendingList = &pManageCtx->stSendList;
        pSendingList->s32Count = 0;
        pSendingList->u32LockStatus = RTCP_LIST_UNLOCKED;
        /*------------------------------------------------------*/
        /* The EMPTY node */
        pSendingList->EmptyNode.u32PktNodeIndex = 0xFFFFFFFF;
        pSendingList->EmptyNode.pNext = NULL;
        pSendingList->pHead = &pSendingList->EmptyNode;
        pSendingList->pTail = &pSendingList->EmptyNode;
        /*------------------------------------------------------*/
        
    } while (0);

    return iRet;
}

UINT RtcpIndexManageGetFromHead
(
     volatile RtcpNodeIndexList_t *pIndexList, 
     RtcpNodeIndex_t** ppNodeIndex
)
{
    UINT iRet = XPOC_ERR_SUCCESS;
    X_NULL_POINTER_CHK_TWO_PARA(pIndexList, ppNodeIndex);

    do
    {
        *ppNodeIndex = NULL;
        
        while (RTCP_LIST_UNLOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RTCP_LIST_UNLOCKED, RTCP_LIST_LOCKED))
        {
            /* FIXME: 不断循环操作还是主动放弃当前 CPU 时间片? */
            /* sched_yield(); */
        }

        do
        {
            //当前队列为空
            if(pIndexList->pHead == pIndexList->pTail)
            {
                iRet = XPOC_ERR_FAIL;
                break;
            }
            
            RtcpNodeIndex_t *pSnap = (RtcpNodeIndex_t*)pIndexList->pHead->pNext;
            
            //队列最后一个结点
            if(pSnap == pIndexList->pTail)
            {
                pIndexList->pTail = pIndexList->pHead;
            }
            pIndexList->pHead->pNext = pSnap->pNext;
            
            pSnap->pNext = NULL;
            *ppNodeIndex = pSnap;
            pIndexList->s32Count -= 1;
        } while(0);
        
        /* step 3: 释放"队列操作权" */
        while (RTCP_LIST_LOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RTCP_LIST_LOCKED, RTCP_LIST_UNLOCKED))
        {
            /* FIXME: 这里一次性就能操作成功 */
        }
        
    } while(0);

    return iRet;
}

UINT RtcpIndexManageInsertToTail
(
     volatile RtcpNodeIndexList_t *pIndexList, 
     RtcpNodeIndex_t* pNodeIndex
)
{
    UINT iRet = XPOC_ERR_SUCCESS;
    X_NULL_POINTER_CHK_TWO_PARA(pIndexList, pNodeIndex);

    pNodeIndex->pNext = NULL;

    while (RTCP_LIST_UNLOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RTCP_LIST_UNLOCKED, RTCP_LIST_LOCKED))
    {
        /* FIXME: 不断循环操作还是主动放弃当前 CPU 时间片? */
        /* sched_yield(); */
    }

    /* step 2: 插入节点 */
    do
    {
        pIndexList->pTail->pNext = (PRtcpNodeIndex_t)pNodeIndex;
        pIndexList->pTail = pNodeIndex;
        pIndexList->s32Count += 1;
    
    } while(0);

    /* step 3: 释放"队列操作权" */
    while(RTCP_LIST_LOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RTCP_LIST_LOCKED, RTCP_LIST_UNLOCKED))
    {
        /* FIXME: 这里一次性就能操作成功 */
    }

    x_DebugLog("RtcpIndexManageInsertToTail 2: head[0x%d],tail[0x%d],count[%d].",
                        pIndexList->pHead, pIndexList->pTail, pIndexList->s32Count);

    return iRet;    
}

UINT insertPkt2RtcpSendQueue(UINT ulRmtIP, USHORT usRmtPort, RtcpCtrlMsgS *pRtcpCtrlMsg)
{
    SINT iWritePos = -1;
    RtcpPaketNodeS *ptNode = NULL;

    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_ONE_PARA(pRtcpCtrlMsg);

    RtcpNodeIndex_t *pPktNodeIndex = NULL;
    /* get a PktNode to receive data */
    RtcpIndexManageGetFromHead(&g_sRtcpSendQueue.stIndexManageCtx.stFreeList, &pPktNodeIndex);
    if(NULL == pPktNodeIndex)/* no free node to receive data */
    {
        x_WarnLog("get pktNode from RtcpSendQueue failed.\n");        
        return XPOC_ERR_FAIL;
    }

    iWritePos = pPktNodeIndex->u32PktNodeIndex;
    ptNode = &g_sRtcpSendQueue.pkt[iWritePos];

    /*发送地址*/
    ptNode->addrTo.sin_family = AF_INET;
    ptNode->addrTo.sin_addr.s_addr = htonl(ulRmtIP);
    ptNode->addrTo.sin_port = htons(usRmtPort);

    memcpy(&ptNode->sRtcpMsg, pRtcpCtrlMsg, sizeof(RtcpCtrlMsgS));
    
    /*消息发送时间*/
    ptNode->u64LastSendMilliSec = RtcpGetCurrMilliSecondTime();
    /*发送次数*/
    ptNode->ucSentTimes = 0;
    ptNode->fd = g_RtcpFd.fd;

    ptNode->fnTimeoutCB = NULL;
    ptNode->pUserData = NULL;

    /* ready to send */
    RtcpIndexManageInsertToTail(&g_sRtcpSendQueue.stIndexManageCtx.stSendList, pPktNodeIndex);

    char *ptStrIp = inet_ntoa(ptNode->addrTo.sin_addr);
    USHORT usPort = ntohs(ptNode->addrTo.sin_port);
    x_DebugLog("[FLOOR][RTCP]:insert 2 SendQueue.pktNodeIdx[%d],subtype[%d],name[0x%x],callid[%d],udn[%s],dstAddr[%s:%d].", 
                iWritePos, pRtcpCtrlMsg->subtype, pRtcpCtrlMsg->ulName, pRtcpCtrlMsg->callId, pRtcpCtrlMsg->udn.value, ptStrIp, usPort);

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}

UINT insertPkt2RtcpSendQueue1(char* pcSerPath, RtcpCtrlMsgS *pRtcpCtrlMsg)
{
    SINT iWritePos = -1;
    RtcpPaketNodeS *ptNode = NULL;

    XPOC_TRACEFUNC_IN;
    X_NULL_POINTER_CHK_TWO_PARA(pcSerPath, pRtcpCtrlMsg);

    RtcpNodeIndex_t *pPktNodeIndex = NULL;
    /* get a PktNode to receive data */
    RtcpIndexManageGetFromHead(&g_sRtcpSendQueue.stIndexManageCtx.stFreeList, &pPktNodeIndex);
    if(NULL == pPktNodeIndex)/* no free node to receive data */
    {
        x_WarnLog("get pktNode from RtcpSendQueue failed.\n");        
        return XPOC_ERR_FAIL;
    }

    iWritePos = pPktNodeIndex->u32PktNodeIndex;
    ptNode = &g_sRtcpSendQueue.pkt[iWritePos];

    /*发送地址*/
    ptNode->udsAddrTo.sun_family = AF_UNIX;
    strcpy(ptNode->udsAddrTo.sun_path, pcSerPath);
    memcpy(&ptNode->sRtcpMsg, pRtcpCtrlMsg, sizeof(RtcpCtrlMsgS));
    
    /*消息发送时间*/
    ptNode->u64LastSendMilliSec = RtcpGetCurrMilliSecondTime();
    /*发送次数*/
    ptNode->ucSentTimes = 0;
    ptNode->fd = g_RtcpFd.fd;

    ptNode->fnTimeoutCB = NULL;
    ptNode->pUserData = NULL;

    /* ready to send */
    RtcpIndexManageInsertToTail(&g_sRtcpSendQueue.stIndexManageCtx.stSendList, pPktNodeIndex);

    x_DebugLog("[FLOOR][RTCP]:insert 2 SendQueue.pktNodeIdx[%d],subtype[%d],name[0x%x],callid[%d],udn[%s].", 
                iWritePos, pRtcpCtrlMsg->subtype, pRtcpCtrlMsg->ulName, pRtcpCtrlMsg->callId, pRtcpCtrlMsg->udn.value);

    XPOC_TRACEFUNC_OUT;
    return XPOC_ERR_SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值