rceDef.h
#ifndef __RCEDEF_H__
#define __RCEDEF_H__
#include <getopt.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "XpocModStruct.h"
#include "XpocProcTimer.h"
#include "eXosip2/eXosip.h"
#include "XpocCommStruct.h"
#include "XpocCommFunc.h"
#include "XpocDBInit.h"
extern char* g_rootDir;
extern char g_rceDir[128];
#define RCE_TIMER_FILES_CLEAR 1
#define RCE_TIMER_SEND_UDP_TEST_PKT_FIRST 2 /* 0.1s, 首次发送链路协商包传递SSRC, 在TCP链路建立后||UDP链路分配成功后 启动 */
#define RCE_TIMER_SEND_TCP_TEST_PKT_FIRST 3 /* 0.1s, 首次发送链路协商包传递SSRC, 在TCP链路建立后||UDP链路分配成功后 启动 */
#define RCE_TIMER_SEND_UDP_TEST_PKT 4 /* 20s, 定时发送链路协商包传递SSRC */
#define RCE_TIMER_SEND_TCP_TEST_PKT 5 /* 20s, 定时发送链路协商包传递SSRC */
typedef struct
{
UINT ulUCallCtxId;
}StreamInfoS;
typedef struct
{
UCHAR aucFleetId[STR_LEN32];
UINT ulCurrMsgId;
UINT ulCBId;
UCHAR StreamNum;
StreamInfoS StreamInfoArray[MEDIA_TYPE_MAX];
//eXosip_event_t *ptSpSipHandle; /* sip addr */
}RceCtrlBlockS;
#define RTP_HEADER_LEN (12)
#define RTP_HEADER_EXT_LEN (8)
typedef struct
{
/**//* byte 0 */
UCHAR data1;
UCHAR data2;
USHORT seq_no;
UINT timestamp;
UINT ssrc;
}RTP_FIXED_HEADER;
#define MAX_RTP_SOCKET_NUM 3000
typedef struct
{
USHORT udpFdNum;
MediaFdS *udpRtpFdList;
MediaFdS *udpRtcpFdList;
SINT udpEpollFd; // udp epoll
ThreadInfo_t *ptSendThread;
}UdpAddrInfoS;
typedef struct
{
MediaFdS tcpListenFd;
USHORT tcpFdNum;
MediaFdS *tcpRtpFdList;
SINT tcpEpollFd; // tcp epoll
ThreadInfo_t *ptSendThread;
}TcpAddrInfoS;
typedef struct
{
UCHAR rtpWorkerThreadNum; // 2
USHORT udpStartPort; // 20000
USHORT udpEndPort; // 20199
/* 约定 : 本地保存的IP为主机字节序 */
UINT ulLocalIp;
UINT ulAceRmtIp;
} RceCfgInfoS;
typedef struct
{
RceCfgInfoS stCfgInfo; /* static config: local IP+PORT, remote IP+PORT, dataArea max num, etc */
UdpAddrInfoS stUdpAddrInfo;
TcpAddrInfoS stTcpAddrInfo;
} RceGlbData_S;
#endif /* __RCEDEF_H__ */
rceProc.h
#ifndef __RCE_PROC_H__
#define __RCE_PROC_H__
#include "ConfSQLApi.h"
#include "httpuafunc.h"
#include "httpuasrvfunc.h"
#include "rceDef.h"
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
UINT rceLoadCfg(T_ModCtxS *ptModCtx);
UINT rceGetCBConfig(T_ModCtxS *ptModCtx);
void Mem_Add(char dst[260], char *a1, char*a2, char*a3);
int get_file_size(int f);//获取文件的大小
void DownFile(struct evhttp_request *req, void *arg);
#if 0
#endif
UINT rceModFirstStart(T_ModCtxS *ptModCtx);
UINT rceModFinishStart(T_ModCtxS *ptModCtx);
UINT rceModMsgProc(T_ModCtxS *ptModCtx, T_PlatHead *ptPlatHeadInfo, T_ModMsgHead *ptXPOCHeader);
UINT rceModTimerProc(T_ModCtxS *ptModCtx, T_ProcTimeCtx *pTimerCtxt);
UINT rceSendFleetCfg2Http();
UINT rceReceiveCfgMsgFromHttp(T_ModCtxS* ptModCtx, T_ModMsgHead* ptXPocHdr);
#if 0
#endif
UINT rceHttpusFirstStart(T_ModCtxS *ptModCtx);
UINT rceHttpusFinishStart(T_ModCtxS *ptModCtx);
UINT rceHttpusMsgProc(T_ModCtxS *ptModCtx, T_PlatHead *ptPlatHeadInfo, T_ModMsgHead *ptXPOCHeader);
UINT rceHttpusTimerProc(T_ModCtxS *ptModCtx, T_ProcTimeCtx *pTimerCtxt);
typedef struct {
struct evhttp_request *req;
int fd;
long chunksize;
long long filesize;
long long offset;
int count;
}ChunkReqStateS ;
UINT httpSendChunk(ChunkReqStateS *crs);
void ChunkedTrickleCb(struct evhttp_connection *conn, void *arg);
#ifdef __cplusplus
}
#endif /*__cplusplus*/
#endif /* __RCE_PROC_H__ */
rceProc.c
#include "XpocCommDefine.h"
#include "XpocCommFunc.h"
#include "XpocCommMsgStruct.h"
#include "XpocDBInterface.h"
#include "event2/event_compat.h"
#include "event2/http_compat.h"
#include "event2/http.h"
#include "rceCommFunc.h"
#include "rceSignalFunc.h"
#include "rceMediaFunc.h"
#include "rceProc.h"
#include <dirent.h>
#define RCE_FILE_DOWNLOAD_MAX_3M 3*1024*1024
extern MYSQL *mysql_connect;
extern char glb_neLocIp[STR_LEN32];
extern int glb_RceDelTime;
extern T_ModuleCBCtx g_RceCBCtxSTable[];
extern T_TableCfg g_tTableCfg;
extern T_ServerCfg g_tServerCfg;
UINT delUserRecord(char *aucFleetId, time_t delTime, FileTypeE enFileType);
UINT getFileType(char *filename);
UINT rceDeleteFile(char *dir, FileTypeE enFileType);
static int rceMkdirMultilevel(const char *muldir)
{
char str[512];
strncpy(str, muldir, 512);
int len = strlen(str);
if (len < 1 || str[0] != '/')
{
return -1;
}
int i;
for(i=1; i<len; i++)
{
if(str[i]=='/')
{
str[i] = '\0';
if(access(str,0) != 0)
{
mkdir(str, 0777);
}
str[i]='/';
}
}
if(access(str,0) != 0)
{
mkdir(str, 0777);
}
return 0;
}
UINT rceModFirstStart(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
RceGlbData_S* ptGlbData = (RceGlbData_S*)Fplat_Malloc(sizeof(RceGlbData_S), 0);
if (NULL == ptGlbData)
{
x_ErrorLog("SP module global data alloc failed.\n");
return XPOC_ERR_FAIL;
}
memset(ptGlbData, 0, sizeof(RceGlbData_S));
ptModCtx->pAppData = (void *)ptGlbData;
//申请udp tcp socket数组空间, 数组大小设为同时处于呼叫中的最大用户数
ptGlbData->stUdpAddrInfo.udpRtpFdList = (MediaFdS *)calloc(g_tServerCfg.uConcurrCallMaxNum, sizeof(MediaFdS));
if (NULL == ptGlbData->stUdpAddrInfo.udpRtpFdList)
{
x_ErrorLog("udpRtpFdList calloc failed.\n");
return XPOC_ERR_FAIL;
}
ptGlbData->stUdpAddrInfo.udpRtcpFdList = (MediaFdS *)calloc(g_tServerCfg.uConcurrCallMaxNum, sizeof(MediaFdS));
if (NULL == ptGlbData->stUdpAddrInfo.udpRtcpFdList)
{
x_ErrorLog("udpRtcpFdList calloc failed.\n");
return XPOC_ERR_FAIL;
}
ptGlbData->stTcpAddrInfo.tcpRtpFdList = (MediaFdS *)calloc(g_tServerCfg.uConcurrCallMaxNum, sizeof(MediaFdS));
if (NULL == ptGlbData->stTcpAddrInfo.tcpRtpFdList)
{
x_ErrorLog("tcpRtpFdList calloc failed.\n");
return XPOC_ERR_FAIL;
}
/* connfd 有可能分配的是0, 会造成消息转发到非预期的fd上. 因此fd不能初始化为0. */
UINT i = 0;
for (i = 0; i < g_tServerCfg.uConcurrCallMaxNum; i++)
{
ptGlbData->stUdpAddrInfo.udpRtpFdList[i].iSocketFd = INVALID_VALUE_UINT;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[i].iSocketFd = INVALID_VALUE_UINT;
ptGlbData->stTcpAddrInfo.tcpRtpFdList[i].iSocketFd = INVALID_VALUE_UINT;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceModFinishStart(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
if (XPOC_ERR_SUCCESS != rceLoadCfg(ptModCtx))
{
x_ErrorLog("rceLoadCfg failed.\n");
return XPOC_ERR_FAIL;
}
if (XPOC_ERR_SUCCESS != rceGetCBConfig(ptModCtx))
{
x_ErrorLog("rceGetCBConfig failed.\n");
return XPOC_ERR_FAIL;
}
if (XPOC_ERR_SUCCESS != rceInitMediaSocket(ptModCtx))
{
x_ErrorLog("rceInitMediaSocket failed.\n");
return XPOC_ERR_FAIL;
}
if (XPOC_ERR_SUCCESS != rceInitDpThread(ptModCtx))
{
x_ErrorLog("rceInitDpThread failed!\n");
return XPOC_ERR_FAIL;
}
XPOCStartPeriodTimer(RCE_TIMER_FILES_CLEAR, CLEAR_TIME_LEN * 60, 0); // 定时检查是否清理文件,默认设置十分钟
// added by shm, 发送上线通知短信
// SdsWarnning stSds;
// memset(&stSds, 0, sizeof(stSds));
// strcpy(stSds.acParam1, "AR_XPOC_SERVER");
// strcpy(stSds.acParam2, g_ModuleName[ptModCtx->ucModuleId]);
// sprintf(stSds.acParam3, "Online notification -- rce has started.");
// sedSdsWarnReq2Http(&stSds);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceModMsgProc(T_ModCtxS *ptModCtx, T_PlatHead *ptPlatHdr, T_ModMsgHead *ptXPocHdr)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_THREE_PARA(ptModCtx, ptPlatHdr, ptXPocHdr);
UINT ulRetCode = XPOC_ERR_SUCCESS;
if(EV_SIP_INVITE_IND == ptXPocHdr->ulMsgId)
{
ulRetCode = rceHandleSipInvite(ptModCtx, ptXPocHdr);
}
else if(EV_SIP_BYE_IND == ptXPocHdr->ulMsgId)
{
ulRetCode = rceHandleSipBye(ptModCtx, ptXPocHdr);
}
else if(EV_SIP_ACK_IND == ptXPocHdr->ulMsgId)
{
x_DebugLog("recv EV_SIP_ACK_IND. do nothing.");
}
else if (EV_RCE_RECEIVE_FLEETCONFIG == ptXPocHdr->ulMsgId) // modify by lkf
{
x_InfoLog("recv EV_RCE_RECEIVE_FLEETCONFIG.\n");
(void)rceReceiveCfgMsgFromHttp(ptModCtx, ptXPocHdr);
}
else
{
x_WarnLog("recv unexpected msgId[0x%x].\n", ptXPocHdr->ulMsgId);
}
/// free osip ev
if(EV_SIP_INVITE_IND == ptXPocHdr->ulMsgId
|| EV_SIP_BYE_IND == ptXPocHdr->ulMsgId
|| EV_SIP_ACK_IND == ptXPocHdr->ulMsgId)
{
SipMsgIndS *ptSipMsgInd = (SipMsgIndS*)ptXPocHdr->stMsgBody;
if (ptSipMsgInd)
{
eXosip_event_free(ptSipMsgInd->ulSipHandle);
}
}
XPOC_TRACEFUNC_OUT;
return ulRetCode;
}
UINT rceModTimerProc(T_ModCtxS *ptModCtx, T_ProcTimeCtx *pTimerCtxt)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, pTimerCtxt);
UINT ulReturn = XPOC_ERR_SUCCESS;
// modify by lkf
if (RCE_TIMER_FILES_CLEAR == pTimerCtxt->TimerType)
{
if (XPOC_ERR_SUCCESS == isClearFile(CLEAR_TIME_LEN))
{
(void)rceSendFleetCfg2Http();
}
return ulReturn;
}
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
UINT RtpFdIndex = pTimerCtxt->uiParam2;
MediaFdS *ptRtpFd = NULL;
T_RceUCallCtxTable stUCC;
UINT ulSec = 10;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
// if(Record_WORK != ptRtpFd->iRceRecordState)
// {
// x_WarnLog("rtpFd.recordState[%d] is not WORK.", ptRtpFd->iRceRecordState);
// return XPOC_ERR_FAIL;
// }
if(RCE_TIMER_SEND_UDP_TEST_PKT_FIRST == pTimerCtxt->TimerType
|| RCE_TIMER_SEND_UDP_TEST_PKT == pTimerCtxt->TimerType)
{
ptRtpFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[RtpFdIndex];
}
else if(RCE_TIMER_SEND_TCP_TEST_PKT_FIRST == pTimerCtxt->TimerType
|| RCE_TIMER_SEND_TCP_TEST_PKT == pTimerCtxt->TimerType)
{
ptRtpFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[RtpFdIndex];
}
if(!ptRtpFd)
{
x_ErrorLog("ptRtpFd is NULL.");
return XPOC_ERR_FAIL;
}
stUCC.ulRecordIdx = ptRtpFd->ulUCCId;
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, NULL, (MediaTypeE)0, NULL, &stUCC.ulRecordIdx, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("get UCC by recordIx[%d] failed.", stUCC.ulRecordIdx);
return ulReturn;
}
switch (pTimerCtxt->TimerType)
{
case RCE_TIMER_SEND_UDP_TEST_PKT_FIRST:
(void)rceSendUdpTestPktWithSsrc(ptModCtx, &stUCC);
pTimerCtxt->TimerType = RCE_TIMER_SEND_UDP_TEST_PKT;
XPOCStartTimer(ulSec, 0, pTimerCtxt, TIME_FLAG_POOL);
x_InfoLog("rce timer start: timeType[%d],timerId[%lld],timeLen[%d].",
pTimerCtxt->TimerType, pTimerCtxt->TimerId, ulSec);
break;
case RCE_TIMER_SEND_TCP_TEST_PKT_FIRST:
(void)rceSendTcpTestPktWithSsrc(ptRtpFd->iSocketFd, stUCC.ulSsrc);
pTimerCtxt->TimerType = RCE_TIMER_SEND_TCP_TEST_PKT;
XPOCStartTimer(ulSec, 0, pTimerCtxt, TIME_FLAG_POOL);
x_InfoLog("rce timer start: timeType[%d],timerId[%lld],timeLen[%d].",
pTimerCtxt->TimerType, pTimerCtxt->TimerId, ulSec);
break;
case RCE_TIMER_SEND_UDP_TEST_PKT:
(void)rceSendUdpTestPktWithSsrc(ptModCtx, &stUCC);
break;
case RCE_TIMER_SEND_TCP_TEST_PKT:
(void)rceSendTcpTestPktWithSsrc(ptRtpFd->iSocketFd, stUCC.ulSsrc);
break;
default:
break;
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
// // modify by lkf
UINT rceSendFleetCfg2Http()
{
XPOC_TRACEFUNC_IN;
UINT ulReturn = XPOC_ERR_SUCCESS;
UINT ulMsgLen = sizeof(FleetConfigReqS);
UCHAR* ptPlatHdr = (UCHAR*)XPOCAllocMsg(ulMsgLen);
if (NULL == ptPlatHdr)
{
x_ErrorLog("Alloc Plat message header error, ulMsgLen[%d]!\n", ulMsgLen);
return XPOC_ERR_INVALID_PTR;
}
T_ModMsgHead* ptXPOCHeader = (T_ModMsgHead*)XPOCGetXpocHeaderPtr(ptPlatHdr);
if (NULL == ptXPOCHeader)
{
XPOCFreeMsg(ptPlatHdr);
return XPOC_ERR_INVALID_PTR;
}
//fill in the message header
ptXPOCHeader->ulMsgId = EV_RCE_GET_FLEETCONFIG;
ptXPOCHeader->ulMsgLen = ulMsgLen;
FleetConfigReqS *ptReq = (FleetConfigReqS *)ptXPOCHeader->stMsgBody;
memset(ptReq, 0, sizeof(FleetConfigReqS));
strncpy(ptReq->aucServIP, glb_neLocIp, strlen(glb_neLocIp));
//x_DebugLog("get all fleet config from [%s]", ptReq->aucServIP);
SendDstInfoS stDstModInfo;
memset(&stDstModInfo, 0, sizeof(SendDstInfoS));
stDstModInfo.dstModId = XMOD_TYPE_HTTP;
stDstModInfo.apiId = ptXPOCHeader->ulMsgId;
stDstModInfo.prio = 0;
stDstModInfo.dstPID = 0;
//begin to send message
ulReturn = XPOCDispatchMsg(&stDstModInfo, ptPlatHdr);
if (XPOC_ERR_SUCCESS == ulReturn)
{
x_InfoLog("RCE--->HTTP:EV_RCE_GET_FLEETCONFIG[0x%x] OK!\n", EV_RCE_GET_FLEETCONFIG);
}
else
{
x_ErrorLog("RCE--->HTTP:EV_RCE_GET_FLEETCONFIG[0x%x] failed!\n", EV_RCE_GET_FLEETCONFIG);
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
// modify by lkf, 接收http消息,打开定时器,对不同集团文件夹做处理;表数据处理也在这里执行
UINT rceReceiveCfgMsgFromHttp(T_ModCtxS* ptModCtx, T_ModMsgHead* ptXPocHdr)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptXPocHdr);
time_t cfgTime = getCleanTime(glb_RceDelTime); // 获取配置文件设置的对应当天时间戳
AllFleetConfigS* ptFleetCfg = NULL;
ptFleetCfg = (AllFleetConfigS*)ptXPocHdr->stMsgBody;
if (access(g_rceDir, 0) == -1)
{
x_ErrorLog("path[%s] unexist!", g_rceDir);
return XPOC_ERR_SUCCESS;
}
time_t delTime;
UINT i;
for(i = 0; i < (ptFleetCfg->ulFleetNum); i++)
{
/* 录音录像分开删除 */
char tmp[STR_LEN256] = {0};
sprintf(tmp, "%s/%s", g_rceDir, ptFleetCfg->stCfgList[i].aucFleetId);
if (access(tmp, 0) == -1)
{
continue;
}
x_InfoLog("fleet[%s] prepare to delete audio before [%d] days and video before [%d] days.", ptFleetCfg->stCfgList[i].aucFleetId,
ptFleetCfg->stCfgList[i].ulAudioStorageTime, ptFleetCfg->stCfgList[i].ulVideoStorageTime);
if(ptFleetCfg->stCfgList[i].ulAudioStorageTime != 0)
{
delTime = cfgTime - ptFleetCfg->stCfgList[i].ulAudioStorageTime * 86400;
delUserRecord(ptFleetCfg->stCfgList[i].aucFleetId, delTime, FILE_AUDIO);
}
if(ptFleetCfg->stCfgList[i].ulVideoStorageTime != 0)
{
delTime = cfgTime - ptFleetCfg->stCfgList[i].ulVideoStorageTime * 86400;
delUserRecord(ptFleetCfg->stCfgList[i].aucFleetId, delTime, FILE_VIDEO);
}
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
#if 0
#endif
UINT rceHttpusFirstStart(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
//todo
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceHttpusFinishStart(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
struct evhttp *http_server = NULL;
char *http_addr = glb_neLocIp;
short http_port = RCE_HTTP_PORT;
//初始化
event_init();
//启动http服务端
http_server = evhttp_start(http_addr, http_port);
if (http_server == NULL)
{
x_ErrorLog("http server start failed.");
return XPOC_ERR_FAIL;
}
//设置请求超时时间(s)
evhttp_set_timeout(http_server, HTTP_REQUEST_MAX_TIMELEN);
//设置事件处理函数,evhttp_set_cb针对每一个事件(请求)注册一个处理函数,
//区别于evhttp_set_gencb函数,是对所有请求设置一个统一的处理函数
//文件服务器
rceMkdirMultilevel(g_rceDir);
// modified by shm at 20210203
//evhttp_set_cb(http_server, "/xpoc/dc-rce-downloadfd", DownFile, NULL);
evhttp_set_gencb(http_server, DownFile, NULL);
//循环监听. //此处处理http_handler_msg
event_dispatch();
//实际上不会释放,代码不会运行到这一步
evhttp_free(http_server);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceHttpusMsgProc(T_ModCtxS *ptModCtx, T_PlatHead *ptPlatHdr, T_ModMsgHead *ptXPocHdr)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_THREE_PARA(ptModCtx, ptPlatHdr, ptXPocHdr);
UINT ulReturn = XPOC_ERR_SUCCESS;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceHttpusTimerProc(T_ModCtxS *ptModCtx, T_ProcTimeCtx *pTimerCtxt)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, pTimerCtxt);
UINT ulReturn = XPOC_ERR_SUCCESS;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
#if 0
#endif
void Mem_Add(char dst[260], char *a1, char*a2, char*a3)
{
memset(dst, 0, 260);
strcat(dst, a1);
strcat(dst, a2);
strcat(dst, a3);
}
//获取文件的大小
int get_file_size(int f)
{
struct stat st;
fstat(f, &st);
return st.st_size;
}
UINT httpSendChunk(ChunkReqStateS *crs)
{
lseek(crs->fd, crs->offset, SEEK_SET);
long length = crs->filesize - crs->offset;
if(length > crs->chunksize)
{
length = crs->chunksize;
}
char *Buffer = (char *)malloc(length + 1);
if(Buffer != NULL)
{
memset(Buffer, 0, length+1);
}
else
{
x_ErrorLog("malloc buffer fail !");
if(crs->fd != -1) close(crs->fd);
return XPOC_ERR_FAIL;
}
int iread = read(crs->fd, Buffer, length);
//x_InfoLog("[httpSendChunk] Count[%d], fileLength[%d], fileOffset[%d], iread[%d].", crs->count, crs->filesize, crs->offset, iread);
if(iread > 0)
{
struct evbuffer *evb = evbuffer_new();
evbuffer_add(evb, Buffer, iread);
if (crs->offset < crs->filesize)
{
evhttp_send_reply_chunk_with_cb(crs->req, evb, ChunkedTrickleCb, crs);
crs->offset += iread;
crs->count++;
}
else
{
x_InfoLog("evhttp_send_reply_end, fd[%d], fileSize[%d], iread[%d]", crs->fd, crs->filesize, iread);
evhttp_send_reply_end(crs->req);
if(crs->fd != -1) close(crs->fd);
free(crs);
crs = NULL;
}
evbuffer_free(evb);
}
else
{
x_InfoLog("download file success, fd[%d], fileSize[%d], iread[%d]", crs->fd, crs->filesize, iread);
evhttp_send_reply_end(crs->req);
if(crs->fd != -1) close(crs->fd);
free(crs);
crs = NULL;
}
free(Buffer);
return XPOC_ERR_SUCCESS;
}
void ChunkedTrickleCb(struct evhttp_connection *conn, void *arg)
{
ChunkReqStateS *state = (ChunkReqStateS *)arg;
//x_InfoLog("[ChunkedTrickleCb] Count[%d], fileLength[%d], fileOffset[%d].", state->count, state->filesize, state->offset);
httpSendChunk(state);
}
// modified by shm at 20210203, http请求类型修改为get,并去除json消息体,文件名在uri中携带
void DownFile(struct evhttp_request *req, void *arg)
{
if (!req)
{
x_ErrorLog("http request is null.");
return;
}
if ((!req->uri) || (strlen(req->uri) <= 90) || (!strstr(req->uri, "-Cur-"))) // modify by lkf, the length of uri is more than 90 and the -Cur- is contained in uri
{
x_ErrorLog("http uri[%s] is unexpected!", req->uri);
return send_rsp_message(req, HTTP_EXPECTATIONFAILED);
}
if(strncmp(req->uri, "/xpoc/", 6))
{
x_ErrorLog("http uri[%s] is invalid.", req->uri);
return send_rsp_message(req, HTTP_EXPECTATIONFAILED);
}
print_http_event(req, arg); /* [/xpoc/dc-rce-downloadfd/file] */
int fd = -1;
char strtemp[260];
if (EVHTTP_REQ_GET == req->type)
{
if (req->uri)
{
char intfName[128] = {0};
char* pcFileName = req->uri+1; // 加2是避免字符串起始的'/'
char* pcTmp = NULL;
do
{
pcTmp = strchr(pcFileName, '/');
if (pcTmp)
{
memset(intfName, 0, 128); // added by shm, 解决循环后pcFileName不以 '\0' 结尾的问题
memcpy(intfName, pcFileName, pcTmp-pcFileName);
pcFileName = pcTmp + 1; // 加1是避免字符串起始的'/'
}
else
{
// modify by lkf
char fleetId[STR_LEN16] = {0}; // 集团号文件夹
char folderName[STR_LEN16] = {0}; // 日期文件夹名称
char filePath[STR_LEN256] = {0};
char* pos = strstr(pcFileName, "-Cur-");
if(!pos)
{
x_ErrorLog("[%s] is abnormal, [-Cur-] is not substring!", pcFileName);
break;
}
strncpy(fleetId, pos + 5, STR_LEN8); // 集团号是八位
strncpy(folderName, pos + 23, STR_LEN10); // 日期文件夹10位
sprintf(filePath, "%s/%s/%s", g_rceDir, fleetId, folderName);
Mem_Add(strtemp, filePath, "/", pcFileName);
x_InfoLog("down file[%s], intfName[%s].", strtemp, intfName);
if(strcmp(intfName, "dc-rce-downloadfd") == 0) // 在libevent uri区分接口的话,这里实际用不上
{
// open file
if ((fd = open(strtemp, O_RDONLY)) >= 0)
{
int filelen = get_file_size(fd);
// check range
const char *pRange = evhttp_find_header(req->input_headers, "Range");
UINT rangbeg = 0, rangend = 0;
if(pRange) // play
{
char *pBeg = (char*)strstr(pRange, "bytes=");
if(pBeg)
{
pBeg += 6;
char *pEnd = strchr(pBeg, '-');
if(pEnd)
{
char strTmp[64] = {0};
memcpy(strTmp, pBeg, pEnd-pBeg);
rangbeg = atoi(strTmp);
pBeg = pEnd+1;
rangend = atoi(pBeg);
}
}
// modified by shm, 解决大文件不能播放问题;解决大文件拖拽播放异常问题
struct evbuffer *retbuff = evbuffer_new();
if (retbuff != NULL)
{
char contRange[64] = {0};
sprintf(contRange, "bytes %d-%d/%d", rangbeg, rangend>0?rangend:filelen-1, filelen);
evhttp_add_header(req->output_headers, "Content-Type", "video/mp4");
evhttp_add_header(req->output_headers, "Connection", "Keep-alive");
evhttp_add_header(req->output_headers, "Content-Range", contRange);
struct evbuffer_file_segment *pstSeg = NULL;
int nCurrFileEndPos = (rangend>0?rangend:filelen - 1) - rangbeg + 1;
pstSeg = evbuffer_file_segment_new(fd, rangbeg, nCurrFileEndPos, 0);
if (!pstSeg)
return;
int r = evbuffer_add_file_segment(retbuff, pstSeg, 0, nCurrFileEndPos);
if (r == 0)
evbuffer_file_segment_free(pstSeg);
evhttp_send_reply(req, 206, "Partial Content", retbuff);
evbuffer_free(retbuff);
if (-1 != fd) close(fd);
return;
}
}
else
{
ChunkReqStateS *state = (ChunkReqStateS *)malloc(sizeof(ChunkReqStateS));
if(state != NULL)
{
memset(state, 0, sizeof(ChunkReqStateS));
}
else
{
x_ErrorLog("ChunkReqStateS malloc fail!");
if (-1 != fd) close(fd);
return send_rsp_message(req, HTTP_EXPECTATIONFAILED);
}
char fileSize[STR_LEN16] = {0};
sprintf(fileSize, "%d", filelen);
evhttp_add_header(req->output_headers, "Content-Type", "application/octet-stream");
evhttp_add_header(req->output_headers, "Connection", "Keep-alive");
evhttp_add_header(req->output_headers, "Content-Length", fileSize);
state->req = req;
state->fd = fd;
state->chunksize = RCE_FILE_DOWNLOAD_MAX_3M;
state->count = 0;
state->filesize = filelen;
state->offset = 0;
evhttp_send_reply_start(req, HTTP_OK, "OK");
httpSendChunk(state);
//x_InfoLog("Count[%d], fileLength[%d], fileOffset[%d].", state->count, state->filesize, state->offset);
x_InfoLog("Start download file[%s], fd[%d], fileSize[%d].", strtemp, fd, state->filesize);
return;
}
}
else
{
x_ErrorLog("Open [%s] failed.", strtemp);
}
}
}
} while (pcTmp);
}
}
if (-1 != fd) close(fd);
return send_rsp_message(req, HTTP_EXPECTATIONFAILED);
}
UINT rceLoadCfg(T_ModCtxS *ptModCtx)
{
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
RceCfgInfoS *ptCfg = &ptGlbData->stCfgInfo;
ptCfg->rtpWorkerThreadNum = 2;
ptCfg->udpStartPort = 30000;
ptCfg->udpEndPort = ptCfg->udpStartPort + g_tServerCfg.uConcurrCallMaxNum * 2 - 1; //调整为最大呼叫人数的2倍 lxh 20210610
x_InfoLog("glbCfgInfo:threadNum[%d],udpPort[%d--%d].",
ptCfg->rtpWorkerThreadNum, ptCfg->udpStartPort, ptCfg->udpEndPort);
UINT Addr = inet_addr((char*)(glb_neLocIp));
ptCfg->ulLocalIp = ntohl(Addr);
x_InfoLog("udp localIP[0x%x],aceRmtIp[0x%x].\n", ptCfg->ulLocalIp, ptCfg->ulAceRmtIp);
return XPOC_ERR_SUCCESS;
}
UINT rceGetCBConfig(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
UINT ulReturn = XPOC_ERR_SUCCESS;
g_RceCBCtxSTable[X_CB_TRANSACTION].ulMaxCtrNum = g_tServerCfg.uConcurrCallMaxNum;
g_RceCBCtxSTable[X_CB_TRANSACTION].ulMinBufInPool = g_tServerCfg.uConcurrCallMaxNum;
g_RceCBCtxSTable[X_CB_TRANSACTION].ulMaxBufInPool = g_tServerCfg.uConcurrCallMaxNum;
g_RceCBCtxSTable[X_CB_TRANSACTION].ulExtStepBufInPool = 200;
ulReturn = XPOCCBMemoryCreate(ptModCtx,
X_CB_TRANSACTION,
g_RceCBCtxSTable[X_CB_TRANSACTION].ulMaxBufInPool,
sizeof(RceCtrlBlockS), &ulReturn);
if (FAILURE == ulReturn)
{
x_ErrorLog("Create Transaction CB Memory Error.\n");
ulReturn = XPOC_ERR_ALLOC_CB;
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT delUserRecord(char *aucFleetId, time_t delTime, FileTypeE enFileType)
{
XPOC_TRACEFUNC_IN;
char aucDelTime[STR_LEN32] = {0};
char aucDelFolder[STR_LEN32] = {0};
strftime((char*)aucDelTime, STR_LEN32, "%Y-%m-%d %H:%M:%S", localtime(&delTime));
strftime((char*)aucDelFolder, STR_LEN32, "%Y-%m-%d", localtime(&delTime));
H_USER_Record_Delete_S ptRecord;
memset(&ptRecord, 0 , sizeof(H_USER_Record_Delete_S));
strcpy(ptRecord.aucFleetId, aucFleetId);
strcpy(ptRecord.aucDeleteTime, aucDelTime);
if(enFileType == FILE_AUDIO)
{
x_InfoLog("fleet[%s] delete audio record before time[%s].", ptRecord.aucFleetId, ptRecord.aucDeleteTime);
(void)MYSQL_UserAudioRecord_Delete(mysql_connect, &ptRecord);
}
else if(enFileType == FILE_VIDEO)
{
x_InfoLog("fleet[%s] delete video record before time[%s].", ptRecord.aucFleetId, ptRecord.aucDeleteTime);
(void)MYSQL_UserVideoRecord_Delete(mysql_connect, &ptRecord);
}
char fleetPath[STR_LEN256] = {0};
sprintf(fleetPath, "%s/%s", g_rceDir, aucFleetId);
struct dirent* pdirent;
DIR* d_info = NULL;
if ((d_info = opendir(fleetPath)) == NULL) // 进入集团目录
{
x_ErrorLog("folder[%s] open fail.", fleetPath);
return XPOC_ERR_SUCCESS;
}
while ((pdirent = readdir(d_info)) != NULL) // 读取的是类似2019-03-26文件夹
{
if (pdirent->d_type & DT_DIR) // 读取文件夹名
{
if (strcmp(pdirent->d_name, ".") == 0 || strcmp(pdirent->d_name, "..") == 0) // 忽略. 和 .. 文件夹
{
continue;
}
if (strcmp(pdirent->d_name, aucDelFolder) <= 0)
{
char rmDir[STR_LEN256] = {0};
sprintf(rmDir, "%s/%s", fleetPath, pdirent->d_name);
if(enFileType == FILE_AUDIO)
{
(void)rceDeleteFile(rmDir, FILE_AUDIO);
}
else if(enFileType == FILE_VIDEO)
{
(void)rceDeleteFile(rmDir, FILE_VIDEO);
}
}
}
}
closedir(d_info);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
//区分录音(.amr)还是录像(.mp4)文件
UINT getFileType(char *filename)
{
if(strncmp(filename, "VideoPri", 8) == 0)
{
return FILE_VIDEO;
}
else
{
const char *pFile = strrchr(filename, '.'); // 判断输入的文件名最后输出.的位置
if (pFile != NULL)
{
if (strcmp(pFile, ".amr") == 0)
{
return FILE_AUDIO;
}
else if (strcmp(pFile, ".mp4") == 0)
{
return FILE_VIDEO;
}
}
}
x_ErrorLog("do not known file type, fileName[%s].", filename);
return 0;
}
UINT rceDeleteFile(char *dir, FileTypeE enFileType)
{
char filename[256] = {0};
DIR *dirp;
struct dirent *dp;
// 参数传递进来的目录不存在,直接返回
if ( 0 != access(dir, F_OK) )
{
return 0;
}
dirp = opendir(dir);
while ( (dp=readdir(dirp)) != NULL )
{
// 忽略 . 和 ..
if ( (0 == strcmp(".", dp->d_name)) || (0 == strcmp("..", dp->d_name)) )
{
continue;
}
sprintf(filename, "%s/%s", dir, dp->d_name);
if(enFileType == getFileType(filename))
{
XPOCRemoveFile(filename);
}
}
closedir(dirp);
if (isDirEmpty(dir) == TRUE)
{
(void)XPOCRemoveFile(dir);
}
return XPOC_ERR_SUCCESS;
}
rceResourceFunc.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h> /* for TCP_XXX defines */
#include <sys/timeb.h>
#include "rceSignalFunc.h"
#include "rceMediaFunc.h"
#include "rceResourceFunc.h"
extern T_ServerCfg g_tServerCfg;
extern ThreadInfo_t g_threadDpSendRtp[MAX_NUM_OF_DP_THREAD];
static UINT rceGetSsrc(MediaTypeE enType, USHORT ulFdIndex);
#if 0
#endif
UINT rceEpollCreate(UINT ulMaxFdNum, SINT *ptEpollFd, char *ptExt)
{
if((*ptEpollFd = epoll_create(ulMaxFdNum)) < 0)
{
x_FatalLog("[X][EPOLL] create failed for DP mod. errno=[%d]-[%s].", errno, strerror(errno));
abort();
}
x_InfoLog("[X][EPOLL] create OK, epollFd[%d],ext[%s].", *ptEpollFd, ptExt);
return XPOC_ERR_SUCCESS;
}
UINT recEpollAddFd(SINT epollFd, SINT sockFd, void *ptr, char *ptExt)
{
struct epoll_event Event;
Event.events = EPOLLIN; /* fd can read, level trigger mode(default) */
Event.data.ptr = ptr;
if(epoll_ctl(epollFd, EPOLL_CTL_ADD, sockFd, &Event) < 0)
{
x_ErrorLog("[X][EPOLL] ctl(ADD) failed. epollFd[%d],[sockFd][%d],errno[%d].", epollFd, sockFd, errno);
return XPOC_ERR_FAIL;
}
x_InfoLog("[X][EPOLL] ctl(ADD) OK. epollFd[%d],[sockFd][%d],ext[%s].", epollFd, sockFd, ptExt);
return XPOC_ERR_SUCCESS;
}
UINT rceEpollDelFd(SINT epollFd, SINT sockFd, char *ptExt)
{
/* remove the rtp socket from epoll set */
struct epoll_event Event;
if(epoll_ctl(epollFd, EPOLL_CTL_DEL, sockFd, &Event) < 0)
{
x_ErrorLog("[X][EPOLL] ctl(DEL) failed. epollFd[%d],[sockFd][%d],errno[%d].", epollFd, sockFd, errno);
return XPOC_ERR_FAIL;
}
x_InfoLog("[X][EPOLL] ctl(DEL) OK. epollFd[%d],[sockFd][%d],ext[%s].", epollFd, sockFd, ptExt);
return XPOC_ERR_SUCCESS;
}
#if 0
#endif
SINT rceSetTcpBuff(int sockFd)
{
// SOL_TCP SOL_SOCKET
int retval = 0;
int optval = 0;
socklen_t opt_len = sizeof(optval);
retval = getsockopt(sockFd, 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].", sockFd, optval, retval);
}
else
{
x_DebugLog("[TCP] fd[%d]S getsockopt SO_RCVBUF OK. optval[%d].", sockFd, optval);
}
optval = 0;
retval = getsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, (void *)&optval, &opt_len);
if(0!=retval)
{
x_ErrorLog("[TCP] fd[%d]S getsockopt SO_SNDBUF fail. optval[%d],retval[%d].", sockFd, optval, retval);
}
else
{
x_DebugLog("[TCP] fd[%d]S getsockopt SO_SNDBUF OK. optval[%d].", sockFd, optval);
}
int nRcvBuffLen = 1*1024*1024;
int nSndBuffLen = 1*1024*1024;
retval = setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (void*)&nRcvBuffLen, (socklen_t)sizeof(int));
if(0 != retval)
{
x_ErrorLog("[TCP] fd[%d] setsockopt SO_RCVBUF failed.", sockFd);
}
else
{
x_DebugLog("[TCP] fd[%d] setsockopt SO_RCVBUF[%d] OK.", sockFd, nRcvBuffLen);
}
retval = setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, (void*)&nSndBuffLen, (socklen_t)sizeof(int));
if(0 != retval)
{
x_ErrorLog("[TCP] fd[%d] setsockopt SO_SNDBUF failed.", sockFd);
}
else
{
x_DebugLog("[TCP] fd[%d] setsockopt SO_SNDBUF[%d] OK.", sockFd, nSndBuffLen);
}
// int optval;
// socklen_t opt_len = sizeof(opt_val);
optval = 0;
retval = getsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (void *)&optval, &opt_len);
if(0!=retval)
{
x_ErrorLog("[TCP] fd[%d]E getsockopt SO_RCVBUF fail. optval[%d],retval[%d].", sockFd, optval, retval);
}
else
{
x_DebugLog("[TCP] fd[%d]E getsockopt SO_RCVBUF OK. optval[%d].", sockFd, optval);
}
optval = 0;
retval = getsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, (void *)&optval, &opt_len);
if(0!=retval)
{
x_ErrorLog("[TCP] fd[%d]E getsockopt SO_SNDBUF fail. optval[%d],retval[%d].", sockFd, optval, retval);
}
else
{
x_DebugLog("[TCP] fd[%d]E getsockopt SO_SNDBUF OK. optval[%d].", sockFd, optval);
}
int opt1val = 0;
socklen_t opt1_len = sizeof(opt1val);
retval = getsockopt(sockFd,SOL_TCP, SO_RCVBUF, (void *)&opt1val, &opt1_len);
if(0!=retval)
{
x_ErrorLog("[TCP] fd[%d] getsockopt SOL_TCP SO_RCVBUF fail. optval[%d],retval[%d].", sockFd, opt1val, retval);
}
else
{
x_DebugLog("[TCP] fd[%d] getsockopt SOL_TCP SO_RCVBUF OK. optval[%d].", sockFd, opt1val);
}
opt1val = 0;
retval = getsockopt(sockFd,SOL_TCP, SO_SNDBUF, (void *)&opt1val, &opt1_len);
if(0!=retval)
{
x_ErrorLog("[TCP] fd[%d] getsockopt SOL_TCP SO_SNDBUF fail. optval[%d],retval[%d].", sockFd, opt1val, retval);
}
else
{
x_DebugLog("[TCP] fd[%d] getsockopt SOL_TCP SO_SNDBUF OK. optval[%d].", sockFd, opt1val);
}
return retval;
}
/*创建socket,bind端口*/
SINT rceCreateUdpSocketPort(UINT IpV4, USHORT Port, FDTypeE fdType)
{
SINT sockFd = -1;
/* Opening UDP sockets */
if((sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
x_ErrorLog("[UDP][Socket] open udp socket failed. port [%d], errno = %d, err [%s].\n", Port, errno, strerror(errno));
return -1;
}
struct sockaddr_in Address;
memset(&Address, 0, sizeof(Address));
Address.sin_family = AF_INET;
Address.sin_port = htons(Port);
Address.sin_addr.s_addr = htonl(IpV4);
char *ptStrIp = inet_ntoa(Address.sin_addr);
USHORT usPort = ntohs(Address.sin_port);
/* Binding the socket */
if(bind(sockFd, (struct sockaddr *)&Address, sizeof(Address)) < 0)
{
close(sockFd);
x_ErrorLog("[UDP][Socket] bind udp socket failed. addr[%s:%d]. errno = %d.\n", ptStrIp, usPort, errno);
return -1;
}
x_DebugLog("[UDP][Socket] bind udp socket OK. sockFd[%d], addr[%s:%d], fdType[%d].\n", sockFd, ptStrIp, usPort, fdType);
return sockFd;
}
//int ioctlsocket( int s, long cmd, u_long * argp);
SINT rceCreateTcpSocketPort(void)
{
SINT sockFd = -1;
/* Opening TCP sockets */
if((sockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
x_ErrorLog("[TCP][Socket] open tcp socket failed. errno = %d.\n", errno);
return -1;
}
(void)rceSetTcpBuff(sockFd);
x_DebugLog("[TCP][Socket] tcp socket OK. sockFd[%d].\n", sockFd);
return sockFd;
}
UINT rceInitUdpSocket(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
/* create UDP port */
SINT iRtpFd = -1, iRtcpFd = -1;
USHORT usRtpPort = 0, usRtcpPort = 0;
MediaFdS *ptRtpFd = NULL;
MediaFdS *ptRtcpFd = NULL;
int i = ptGlbData->stCfgInfo.udpStartPort;
UINT j=0;
while(i < ptGlbData->stCfgInfo.udpEndPort && j < g_tServerCfg.uConcurrCallMaxNum)
{
usRtpPort = i;
iRtpFd = rceCreateUdpSocketPort(ptGlbData->stCfgInfo.ulLocalIp, i, FD_TYPE_UDP_RTP);
if(-1 == iRtpFd)
{
i = i+2;
continue;
}
ptRtpFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[j];
ptRtpFd->recordIdx = j;
ptRtpFd->fdType = FD_TYPE_UDP_RTP;
ptRtpFd->usPort = usRtpPort;
ptRtpFd->iSocketFd = iRtpFd;
ptRtpFd->ulUCCId = 0;
ptRtpFd->ulUCCIdbak = 0;
ptRtpFd->fd_record = -1;
ptRtpFd->iRceRecordState = Record_IDLE;
pthread_rwlock_init(&ptRtpFd->mtxUseFg, NULL);
pthread_rwlock_init(&ptRtpFd->mtxWrMp4, NULL);
i++;
usRtcpPort = i;
iRtcpFd = rceCreateUdpSocketPort(ptGlbData->stCfgInfo.ulLocalIp, i, FD_TYPE_UDP_RTCP);
if(-1 == iRtcpFd)
{
close(iRtpFd);
continue;
}
ptRtcpFd = &ptGlbData->stUdpAddrInfo.udpRtcpFdList[j];
ptRtcpFd->recordIdx = j;
ptRtcpFd->fdType = FD_TYPE_UDP_RTCP;
ptRtcpFd->usPort = usRtcpPort;
ptRtcpFd->iSocketFd = iRtcpFd;
ptRtcpFd->ulUCCId = 0;
ptRtcpFd->ulUCCIdbak = 0;
pthread_rwlock_init(&ptRtcpFd->mtxUseFg, NULL);
pthread_rwlock_init(&ptRtcpFd->mtxWrMp4, NULL);
ptRtcpFd->fd_record = -1;
ptRtcpFd->iRceRecordState = Record_IDLE;
i++;
ptGlbData->stUdpAddrInfo.udpFdNum++;
j++;
}
ptGlbData->stUdpAddrInfo.ptSendThread = &g_threadDpSendRtp[0];
x_InfoLog("[X][UDP]udp socket create ok. fdNum[%d].\n", ptGlbData->stUdpAddrInfo.udpFdNum);
(void)rceEpollCreate(MAX_RTP_SD_NUM, &ptGlbData->stUdpAddrInfo.udpEpollFd, (char *)"udp");
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceInitTcpSocket(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
/* create UDP port */
//SINT iRtpFd = -1;
MediaFdS *ptRtpFd = NULL;
UINT i = 0;
for (i = 0; i < g_tServerCfg.uConcurrCallMaxNum; i++)
{
ptRtpFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[i];
if(!ptRtpFd)
{
x_ErrorLog("ptRtpFd is NULL for i[%d].", i);
return XPOC_ERR_FAIL;
}
ptRtpFd->recordIdx = i;
ptRtpFd->fdType = FD_TYPE_TCP_RTP;
ptRtpFd->iSocketFd = -1;
ptRtpFd->fd_record = -1;
ptRtpFd->iRceRecordState = Record_IDLE;
ptRtpFd->ulUCCId = 0;
ptRtpFd->ulUCCIdbak = 0;
pthread_rwlock_init(&ptRtpFd->mtxUseFg, NULL);
pthread_rwlock_init(&ptRtpFd->mtxWrMp4, NULL);
}
ptGlbData->stTcpAddrInfo.tcpFdNum = g_tServerCfg.uConcurrCallMaxNum;
ptGlbData->stTcpAddrInfo.ptSendThread = &g_threadDpSendRtp[1];
x_InfoLog("[X][TCP]tcp socket create ok. fdNum[%d].\n", ptGlbData->stTcpAddrInfo.tcpFdNum);
(void)rceEpollCreate(MAX_RTP_SD_NUM, &ptGlbData->stTcpAddrInfo.tcpEpollFd, (char *)"tcp");
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceInitMediaSocket(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
rceInitUdpSocket(ptModCtx);
/* 现在TCP socket 创建和listen在不同的线程中,据说有可能会有丢包现象.
后需可根据实际测试结果把此过程放到mdeInitDpThread的tcp接收线程中执行 */
rceInitTcpSocket(ptModCtx);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceGetSsrc(MediaTypeE enType, USHORT ulFdIndex)
{
struct timeb timer;
ftime(&timer);
srand(timer.time * 1000 + timer.millitm);
int num = rand()%255;
int tmp = (num << 16);
unsigned int nSsrc = 0;
if (enType == MEDIA_AUDIO)
{
nSsrc = 0xA0000000 + tmp + ulFdIndex;
}
else if (enType == MEDIA_VIDEO)
{
nSsrc = 0xB0000000 + tmp + ulFdIndex;
}
x_DebugLog("get ssrc[%u:%x], mediaType[%d], fdIndex[%d].", nSsrc, nSsrc, enType, ulFdIndex);
return nSsrc;
}
/* 占用一个 socket */
static USHORT g_UdpSocketIndex = 0;
UINT rceAllocUdpSocket(T_ModCtxS *ptModCtx, T_RceUCallCtxTable *ptUCC)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptUCC);
UINT ulReturn = XPOC_ERR_SUCCESS;
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
USHORT i = g_UdpSocketIndex;
UCHAR ubFirst = TRUE;
USHORT j = 0;
for(j = 0; j <= ptGlbData->stUdpAddrInfo.udpFdNum; j++) //确保轮询一遍,且避免死循环
{
if (ubFirst == FALSE && i == g_UdpSocketIndex)
{
x_ErrorLog("All udpSockets are in use!");
ulReturn = XPOC_ERR_FAIL;
break;
}
ubFirst = FALSE;
if(TRUE != ptGlbData->stUdpAddrInfo.udpRtpFdList[i].ubUsedFg)
{
MediaFdS *ptRtpFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[i];
ptRtpFd->ubUsedFg = TRUE;
ptRtpFd->ubFirstProc = TRUE; ///
ptRtpFd->tcpFdIdx = -1;
ptRtpFd->ulUCCId = ptUCC->ulRecordIdx;
ptUCC->usRtpFdIdx = i;
ptUCC->ulSsrc = rceGetSsrc(MEDIA_AUDIO, ptUCC->usRtpFdIdx);
ptRtpFd->iRceMediaType = ptUCC->enMediaType;
ptRtpFd->enRcrdServType = ptUCC->tCallInfoS.enRcrdServType;
(void)recEpollAddFd(ptGlbData->stUdpAddrInfo.udpEpollFd, ptRtpFd->iSocketFd, (void*)ptRtpFd, (char *)"rtpfd");
x_DebugLog("[UDP]Alloc rtpFd:fd[%d:%d],UCCId[%d],addr[0x%x:%d],ptGlbData[%p],ssrc[0x%x],RcrdServType[%d].\n",
i, ptRtpFd->iSocketFd, ptRtpFd->ulUCCId, ptGlbData->stCfgInfo.ulLocalIp, ptRtpFd->usPort,
ptGlbData, ptUCC->ulSsrc, ptRtpFd->enRcrdServType);
MediaFdS *ptRtcpFd = &ptGlbData->stUdpAddrInfo.udpRtcpFdList[i];
ptRtcpFd->ubUsedFg = TRUE;
ptRtcpFd->ulUCCId = ptUCC->ulRecordIdx;
ptRtcpFd->enRcrdServType = ptUCC->tCallInfoS.enRcrdServType;
ptUCC->usRtcpFdIdx = i;
(void)recEpollAddFd(ptGlbData->stUdpAddrInfo.udpEpollFd, ptRtcpFd->iSocketFd, (void*)ptRtcpFd, (char *)"rtcpfd");
x_DebugLog("[UDP]Alloc rtcpFd:fd[%d:%d],UCCId[%d],addr[0x%x:%d],ptGlbData[%p],ssrc[0x%x],RcrdServType[%d].\n",
i, ptRtcpFd->iSocketFd, ptRtcpFd->ulUCCId, ptGlbData->stCfgInfo.ulLocalIp, ptRtcpFd->usPort,
ptGlbData, ptUCC->ulSsrc, ptRtpFd->enRcrdServType);
break;
}
i++;
if (i == ptGlbData->stUdpAddrInfo.udpFdNum)
{
i = 0;
}
}
g_UdpSocketIndex = (i + 1) % ptGlbData->stUdpAddrInfo.udpFdNum;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceFreeUdpSocket(USHORT usRtpFdIdx, USHORT usRtcpFdIdx)
{
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
pthread_rwlock_wrlock(&ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].mtxUseFg); // added by shm
SINT iRtpFd = ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].iSocketFd;
SINT iRtcpFd = ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].iSocketFd;
SINT iEpollFd = ptGlbData->stUdpAddrInfo.udpEpollFd;
(void)rceEpollDelFd(iEpollFd, iRtpFd, (char *)"rtpfd");
(void)rceEpollDelFd(iEpollFd, iRtcpFd, (char *)"rtcpfd");
ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].ubUsedFg = FALSE;
CloseRecordFile(&ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx]);
ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].ulUCCId = 0;
ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].ulCliIp = 0;
ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].rtpCliPort = 0;
ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].rtcpCliPort = 0;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].ubUsedFg = FALSE;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].ulUCCId = 0;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].ulCliIp = 0;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].rtpCliPort = 0;
ptGlbData->stUdpAddrInfo.udpRtcpFdList[usRtcpFdIdx].rtcpCliPort = 0;
//ptGlbData->stUdpAddrInfo.udpFdNum --;
XPOCStopTimer(ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].stTimer.TimerId);
pthread_rwlock_unlock(&ptGlbData->stUdpAddrInfo.udpRtpFdList[usRtpFdIdx].mtxUseFg); // added by shm
return XPOC_ERR_SUCCESS;
}
/* 占用一个 socket */
static USHORT g_TcpSocketIndex = 0;
UINT rceAllocTcpSocket(T_ModCtxS *ptModCtx, T_RceUCallCtxTable *ptUCC)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptUCC);
UINT ulReturn = XPOC_ERR_SUCCESS;
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
USHORT i = g_TcpSocketIndex;
UCHAR ubFirst = TRUE;
USHORT j = 0;
for(j = 0; j <= ptGlbData->stTcpAddrInfo.tcpFdNum; j++) //确保轮询一遍,且避免死循环
{
if (ubFirst == FALSE && i == g_TcpSocketIndex)
{
x_ErrorLog("All tcpSockets are in use!");
ulReturn = XPOC_ERR_FAIL;
break;
}
ubFirst = FALSE;
if (TRUE != ptGlbData->stTcpAddrInfo.tcpRtpFdList[i].ubUsedFg)
{
MediaFdS *ptRtpFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[i];
ptRtpFd->ubUsedFg = TRUE;
ptRtpFd->ubClosingFd = FALSE; ///
ptRtpFd->tcpFdIdx = -1;
ptRtpFd->ulUCCId = ptUCC->ulRecordIdx;
ptUCC->usTcpRtpFdIdx = i;
ptUCC->ulSsrc = rceGetSsrc(MEDIA_VIDEO, ptUCC->usTcpRtpFdIdx);
ptRtpFd->iRceMediaType = ptUCC->enMediaType;
ptRtpFd->iRecvBufferLen = 0;
ptRtpFd->enRcrdServType = ptUCC->tCallInfoS.enRcrdServType;
int num = 0; //防止创建 tcp socket 一直失败,限定尝试5次
while (-1 == ptRtpFd->iSocketFd)
{
ptRtpFd->iSocketFd = rceCreateTcpSocketPort();
if (-1 == ptRtpFd->iSocketFd)
{
x_ErrorLog("rceCreateTcpSocketPort failed : %s(errno: %d))\n", strerror(errno), errno);
num++;
if(num >= 5)
{
break;
}
continue;
}
}
/*设置服务器ip*/
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(ptUCC->stMediaInfo.rtpPort);
s_addr.sin_addr.s_addr = htonl(ptUCC->stMediaInfo.ulIpAddr);
/*开始连接服务器*/
if (connect(ptRtpFd->iSocketFd, (struct sockaddr*)&s_addr, sizeof(struct sockaddr)) == -1) {
x_ErrorLog("[TCP]connect failed:fd[%d:%d],UCCId[%d],addr[%d-%d],ptGlbData[%p],ssrc[0x%x].\n",
i, ptRtpFd->iSocketFd, ptRtpFd->ulUCCId, ptUCC->stMediaInfo.ulIpAddr,
ptUCC->stMediaInfo.rtpPort, ptGlbData, ptUCC->ulSsrc);
return XPOC_ERR_FAIL;
}
struct sockaddr_in client;
int clientAddrLen = sizeof(client);
if (getsockname(ptRtpFd->iSocketFd, (struct sockaddr*)&client, (socklen_t*)&clientAddrLen) != 0)
{
x_ErrorLog("client get port error: %s(errno: %d))\n", strerror(errno), errno);
return XPOC_ERR_FAIL;
}
ptRtpFd->usPort = ntohs(client.sin_port);
(void)recEpollAddFd(ptGlbData->stTcpAddrInfo.tcpEpollFd, ptRtpFd->iSocketFd, (void*)ptRtpFd, (char *)"tcprtpfd");
x_DebugLog("[TCP]Alloc TcprtpFd:fd[%d:%d],UCCId[%d],addr[0x%x:%d],ptGlbData[%p],ssrc[0x%x].\n",
i, ptRtpFd->iSocketFd, ptRtpFd->ulUCCId, ptGlbData->stCfgInfo.ulLocalIp,
ptRtpFd->usPort, ptGlbData, ptUCC->ulSsrc);
break;
}
i++;
if (i == ptGlbData->stTcpAddrInfo.tcpFdNum)
{
i = 0;
}
}
g_TcpSocketIndex = (i + 1) % ptGlbData->stTcpAddrInfo.tcpFdNum;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceFreeTcpSocket(USHORT usRtpFdIdx)
{
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
MediaFdS *ptMediaFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[usRtpFdIdx];
pthread_rwlock_wrlock(&ptMediaFd->mtxUseFg); // added by shm
ptMediaFd->ubClosingFd = TRUE; ///
SINT iRtpFd = ptGlbData->stTcpAddrInfo.tcpRtpFdList[usRtpFdIdx].iSocketFd;
SINT iEpollFd = ptGlbData->stTcpAddrInfo.tcpEpollFd;
(void)rceEpollDelFd(iEpollFd, iRtpFd, (char *)"tcprtpfd");
close(iRtpFd);
x_DebugLog("[X]close tcp socket. tcprtpfd[%d].\n", iRtpFd);
ptGlbData->stTcpAddrInfo.tcpRtpFdList[usRtpFdIdx].iSocketFd = -1;
ptMediaFd->ubUsedFg = FALSE;
CloseRecordFile(ptMediaFd);
ptMediaFd->ulUCCId = 0;
ptMediaFd->ulCliIp = 0;
ptMediaFd->rtpCliPort = 0;
ptMediaFd->rtcpCliPort = 0;
ptMediaFd->iRecvBufferLen = 0;
memset(ptMediaFd->szRecordFileName, 0, STR_LEN512); // added by shm
XPOCStopTimer(ptMediaFd->stTimer.TimerId);
pthread_rwlock_unlock(&ptMediaFd->mtxUseFg); // added by shm
return XPOC_ERR_SUCCESS;
}
UINT rceCloseMediaSocket(T_RceUCallCtxTable *ptUCC)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptUCC);
if(MEDIA_AUDIO == ptUCC->enMediaType)
{
rceFreeUdpSocket(ptUCC->usRtpFdIdx, ptUCC->usRtcpFdIdx);
}
else if(MEDIA_VIDEO == ptUCC->enMediaType)
{
rceFreeTcpSocket(ptUCC->usTcpRtpFdIdx);
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
#if 0
#endif
UINT rceGetCB(T_ModMsgHead* ptXPocHdr, UINT *ptCBId, RceCtrlBlockS **pptCB)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_THREE_PARA(ptCBId, ptXPocHdr, ptXPocHdr->stMsgBody);
UINT ulReturn = XPOC_ERR_SUCCESS;
/* get CB */
if(EV_SIP_INVITE_IND == ptXPocHdr->ulMsgId)
{
*pptCB = (RceCtrlBlockS*)XPOCAllocCtrlBlock(ptCBId);
if(NULL == *pptCB)
{
x_ErrorLog(" Call Alloc CB failed.\n");
return XPOC_ERR_LOCATE_CB;
}
memset(*pptCB, 0, sizeof(RceCtrlBlockS));
(*pptCB)->ulCBId = *ptCBId;
}
else if(EV_SIP_BYE_IND == ptXPocHdr->ulMsgId)
{
x_InfoLog("get cbid[%d] while recv EV_SIP_BYE_IND.\n", *ptCBId);
*pptCB = (RceCtrlBlockS*)XPOCLocateCtrlBlock(*ptCBId);
if(NULL == *pptCB)
{
return XPOC_ERR_LOCATE_CB;
}
}
else
{
x_WarnLog("unexpected MsgId[0x%x].\n", ptXPocHdr->ulMsgId);
return XPOC_ERR_LOCATE_CB;
}
(*pptCB)->ulCurrMsgId = ptXPocHdr->ulMsgId;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
/***************** 函数说明 **********************
* 函数名 : MrIdxMangePoolInit
* 功能说明 : 初始化队列索引管理上下文
*************************************************/
UINT rceRmIdxManageInitCtx(
OUT MrIdxMangeCtx_t *pManageCtx,
OUT NodeIndex_S * patMrNodeIndex,
IN UINT u32NodeIndexCount)
{
UINT iRet = XPOC_ERR_SUCCESS;
if(NULL == pManageCtx || NULL == patMrNodeIndex || 0 == u32NodeIndexCount)
{
iRet = XPOC_ERR_FAIL;
x_ErrorLog("Invalid param: pManageCtx[%p], patMrNodeIndex[%p], u32NodeIndexCount[%u].",
pManageCtx, patMrNodeIndex, u32NodeIndexCount);
return iRet;
}
do
{
/* Initialize free list of manage ctx.*/
volatile MrNodeIndexList_t *pstFreeList = &pManageCtx->stFreeList;
pstFreeList->s32Count = 0;
pstFreeList->u32LockStatus = RM_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++)
{
patMrNodeIndex[u32Index].u32PktNodeIndex = u32Index;
patMrNodeIndex[u32Index].pNext = NULL;
/* Insert to freeList tail. */
pstFreeList->pTail->pNext = (PNodeIndex_S)&patMrNodeIndex[u32Index];
pstFreeList->pTail = (NodeIndex_S*)pstFreeList->pTail->pNext;
pstFreeList->s32Count += 1;
}
/*------------------------------------------------------*/
/* Initialize free list of manage ctx.*/
volatile MrNodeIndexList_t* pSendingList = &pManageCtx->stSendList;
pSendingList->s32Count = 0;
pSendingList->u32LockStatus = RM_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;
}
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageGetFromHead
* 功能说明 : 从头部开始获取结点,获取后队列跳过结点(注,FIFO,从队尾插入)
*************************************************/
UINT rceRmIdxManageGetFromHead
(
INOUT volatile MrNodeIndexList_t *pIndexList,
OUT NodeIndex_S** ppNodeIndex
)
{
UINT iRet = XPOC_ERR_SUCCESS;
if(NULL == pIndexList || NULL == ppNodeIndex)
{
iRet = XPOC_ERR_FAIL;
x_ErrorLog("Invalid param: pIndexList[%p], ppNodeIndex[%p].",
pIndexList, ppNodeIndex);
return iRet;
}
do
{
*ppNodeIndex = NULL;
/* step 1: 获取"队列操作权" */
while (RM_LIST_UNLOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RM_LIST_UNLOCKED, RM_LIST_LOCKED))
{
/* FIXME: 不断循环操作还是主动放弃当前 CPU 时间片? */
/* sched_yield(); */
}
/* step 2: 获取节点 */
do
{
//当前队列为空
if(pIndexList->pHead == pIndexList->pTail)
{
iRet = XPOC_ERR_FAIL;
break;
}
NodeIndex_S *pSnap = (NodeIndex_S*)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 (RM_LIST_LOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RM_LIST_LOCKED, RM_LIST_UNLOCKED))
{
/* FIXME: 这里一次性就能操作成功 */
}
} while(0);
return iRet;
}
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageGetFromHead
* 功能说明 : 插入结点到尾部(注,FIFO,从头部开始获取结点)
*************************************************/
UINT rceRmIdxManageInsertToTail(volatile MrNodeIndexList_t *pIndexList, NodeIndex_S* pNodeIndex)
{
UINT iRet = XPOC_ERR_SUCCESS;
X_NULL_POINTER_CHK_TWO_PARA(pIndexList, pNodeIndex);
do
{
pNodeIndex->pNext = NULL;
/* step 1: 获取"队列操作权" */
while (RM_LIST_UNLOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RM_LIST_UNLOCKED, RM_LIST_LOCKED))
{
/* FIXME: 不断循环操作还是主动放弃当前 CPU 时间片? */
/* sched_yield(); */
}
/* step 2: 插入节点 */
do
{
pIndexList->pTail->pNext = (PNodeIndex_S)pNodeIndex;
pIndexList->pTail = pNodeIndex;
pIndexList->s32Count += 1;
} while(0);
/* step 3: 释放"队列操作权" */
while(RM_LIST_LOCKED != __sync_val_compare_and_swap(&pIndexList->u32LockStatus, RM_LIST_LOCKED, RM_LIST_UNLOCKED))
{
/* FIXME: 这里一次性就能操作成功 */
}
} while(0);
return iRet;
}
///End: 链表操作/支持函数
///Bigin: 队列索引管理函数
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageGetFreeNode
* 功能说明 : 获取可以接收数据(空闲)的结点
*************************************************/
UINT rceRmIdxManageGetFreeNode(MrIdxMangeCtx_t* pManageCtx, NodeIndex_S **ppNodeIndex)
{
X_NULL_POINTER_CHK_TWO_PARA(pManageCtx, ppNodeIndex);
return rceRmIdxManageGetFromHead(&pManageCtx->stFreeList, ppNodeIndex);
}
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageInsertToFreeList
* 功能说明 : 将空闲结点插入空闲列表
*************************************************/
UINT rceRmIdxManageInsertToFreeList(MrIdxMangeCtx_t* pManageCtx, NodeIndex_S* pNodeIndex)
{
X_NULL_POINTER_CHK_TWO_PARA(pManageCtx, pNodeIndex);
return rceRmIdxManageInsertToTail(&pManageCtx->stFreeList, pNodeIndex);
}
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageGetSendNode
* 功能说明 : 获取要发送的结点
*************************************************/
UINT rceRmIdxManageGetSendNode(MrIdxMangeCtx_t* pManageCtx, NodeIndex_S **ppNodeIndex)
{
X_NULL_POINTER_CHK_TWO_PARA(pManageCtx, ppNodeIndex);
return rceRmIdxManageGetFromHead(&pManageCtx->stSendList, ppNodeIndex);
}
/*************************************************
***************** 函数说明 **********************
* 函数名 : rceRmIdxManageInsertToFreeList
* 功能说明 : 将要发送的结点插入发送列表
*************************************************/
UINT rceRmIdxManageInsertToSendingList(MrIdxMangeCtx_t* pManageCtx, NodeIndex_S* pNodeIndex)
{
X_NULL_POINTER_CHK_TWO_PARA(pManageCtx, pNodeIndex);
return rceRmIdxManageInsertToTail(&pManageCtx->stSendList, pNodeIndex);
}
///End: 队列索引管理函数
rceSignalFunc.c
#include <math.h>
#include "rceResourceFunc.h"
#include "rceSignalFunc.h"
#if 0
#endif
extern T_ServerCfg g_tServerCfg;
/*从请求行获取CallId*/
UINT rceGetCallIdFromSipHeader(osip_message_t *ptOsipMessage, char *ptCallId)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptOsipMessage, ptCallId);
UINT ulReturn = XPOC_ERR_SUCCESS;
osip_call_id_t *ptCall_Id = osip_message_get_call_id(ptOsipMessage);
if (ptCall_Id)
{
char *tmp = NULL;
osip_call_id_to_str(ptCall_Id, &tmp);
sprintf(ptCallId, "%s", tmp);
osip_free(tmp);
}
else
{
x_ErrorLog("get callId from sip.from failed.");
ulReturn = XPOC_ERR_FAIL;
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceGetServIdFromSipHeader(osip_message_t *ptOsipMessage, char *ptServId)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptOsipMessage, ptServId);
UINT ulReturn = XPOC_ERR_SUCCESS;
osip_from_t *ptFrom = osip_message_get_from(ptOsipMessage);
if(ptFrom)
{
sprintf(ptServId, "%s", ptFrom->url->username);
}
else
{
x_ErrorLog("get servId from sip.from failed.");
ulReturn = XPOC_ERR_FAIL;
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT RceSetSdpAudioMedia(T_RceUCallCtxTable *ptUCC, sdp_message_t *ptSdpMessage)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptUCC, ptSdpMessage);
sdp_media_t *ptSdpMedia = eXosip_get_audio_media(ptSdpMessage);
if(!ptSdpMedia)
{
x_ErrorLog("ptSdpMedia is NULL.");
return XPOC_ERR_INVALID_PTR;
}
int pos = MdeGetMediaPos(ptSdpMessage, (char*)"audio");
if(-1 == pos)
{
x_ErrorLog("get audio media pos from sdp failed.");
return XPOC_ERR_INVALID_PTR;
}
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
SdpCodecS *ptSdpCodec = &ptUCC->stMediaInfo.stSdpCodec[0];
char *payload = (char*)osip_malloc(4*sizeof(UCHAR));
sprintf(payload,"%d", ptSdpCodec->ulCodecNo);
osip_list_add(&ptSdpMedia->m_payloads, payload, 0);
char *att_field = (char*)osip_malloc(STR_LEN128 * sizeof(UCHAR));
char *att_value = (char*)osip_malloc(STR_LEN128 * sizeof(UCHAR));
// /* 对audio增加a行: a=rtcp:40001 IN IP4 192.168.101.254 */
// UINT sdpIp4 = ptGlbData->stCfgInfo.ulLocalIp;
//
// char addr[STR_LEN32] = {0};
// memset(addr, 0, STR_LEN32);
// sprintf(addr, "%d.%d.%d.%d", sdpIp4>>24&0xFF, sdpIp4>>16&0xFF, sdpIp4>>8&0xFF, sdpIp4&0xFF);
// att_field = osip_malloc(STR_LEN128*sizeof(UCHAR));
// att_value = osip_malloc(STR_LEN128*sizeof(UCHAR));
// sprintf(att_field,"rtcp");
// sprintf(att_value,"%d IN IP4 %s", ptGlbData->stUdpAddrInfo.udpRtcpFdList[ptUCC->usRtcpFdIdx].usPort, addr);
// sdp_message_a_attribute_add (ptSdpMessage, pos, att_field, att_value);
sprintf(att_field,"rtpmap");
sprintf(att_value,"%d %s/%d ",ptSdpCodec->ulCodecNo, ptSdpCodec->aucRtpMap, ptSdpCodec->ulClockRate);
sdp_message_a_attribute_add (ptSdpMessage, pos, att_field, att_value);
if(0 != strlen(ptSdpCodec->aucFrmPm))
{
att_field = (char*)osip_malloc(128*sizeof(UCHAR));
att_value = (char*)osip_malloc(128*sizeof(UCHAR));
sprintf(att_field,"fmtp");
sprintf(att_value,"%s ",ptSdpCodec->aucFrmPm);
sdp_message_a_attribute_add (ptSdpMessage, pos, att_field, att_value);
}
//m=audio 20400 ...
char *sPort = (char*)osip_malloc(8*sizeof(UCHAR));
sprintf(sPort, "%d", ptGlbData->stUdpAddrInfo.udpRtpFdList[ptUCC->usRtpFdIdx].usPort);
sdp_message_m_port_set(ptSdpMessage, pos, sPort);
//a=recvonly
att_field = (char*)osip_malloc(16*sizeof(UCHAR));
mdeTopoly2Str(SDP_MODE_RECVONLY, att_field);
sdp_message_a_attribute_add(ptSdpMessage, pos, att_field, NULL);
att_field = (char*)osip_malloc(128 * sizeof(UCHAR));
sprintf(att_field, "ssrc:%d", ptUCC->ulSsrc);
sdp_message_a_attribute_add(ptSdpMessage, pos, att_field, NULL);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT RceSetSdpVideoMedia(T_RceUCallCtxTable *ptUCC, sdp_message_t *ptSdpMessage)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptUCC, ptSdpMessage);
sdp_media_t *ptSdpMedia = eXosip_get_video_media(ptSdpMessage);
if(!ptSdpMedia)
{
x_ErrorLog("ptSdpMedia is NULL.");
return XPOC_ERR_INVALID_PTR;
}
int pos = MdeGetMediaPos(ptSdpMessage, (char*)"video");
if(-1 == pos)
{
x_ErrorLog("get video media pos from sdp failed.");
return XPOC_ERR_INVALID_PTR;
}
SdpCodecS *ptSdpCodec = &ptUCC->stMediaInfo.stSdpCodec[0];
char *payload = (char*)osip_malloc(4*sizeof(UCHAR));
sprintf(payload,"%d", ptSdpCodec->ulCodecNo);
osip_list_add(&ptSdpMedia->m_payloads, payload, 0);
char *att_field = (char*)osip_malloc(STR_LEN128 * sizeof(UCHAR));
char *att_value = (char*)osip_malloc(STR_LEN128 * sizeof(UCHAR));
sprintf(att_field,"rtpmap");
sprintf(att_value,"%d %s/%d ",ptSdpCodec->ulCodecNo, ptSdpCodec->aucRtpMap, ptSdpCodec->ulClockRate);
sdp_message_a_attribute_add (ptSdpMessage, pos, att_field, att_value);
if(0 != strlen(ptSdpCodec->aucFrmPm))
{
att_field = (char*)osip_malloc(128*sizeof(UCHAR));
att_value = (char*)osip_malloc(128*sizeof(UCHAR));
sprintf(att_field,"fmtp");
sprintf(att_value,"%s ",ptSdpCodec->aucFrmPm);
sdp_message_a_attribute_add (ptSdpMessage, pos, att_field, att_value);
}
//m=video 29000 ...
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
char *sPort = (char*)osip_malloc(8*sizeof(UCHAR));
sprintf(sPort, "%d", ptGlbData->stTcpAddrInfo.tcpRtpFdList[ptUCC->usTcpRtpFdIdx].usPort);
sdp_message_m_port_set(ptSdpMessage, pos, sPort);
//a=recvonly
att_field = (char*)osip_malloc(16*sizeof(UCHAR));
mdeTopoly2Str(SDP_MODE_RECVONLY, att_field);
sdp_message_a_attribute_add(ptSdpMessage, pos, att_field, NULL);
att_field = (char*)osip_malloc(128 * sizeof(UCHAR));
sprintf(att_field, "ssrc:%d", ptUCC->ulSsrc);
sdp_message_a_attribute_add(ptSdpMessage, pos, att_field, NULL);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceBuildSdpCommInfo(sdp_message_t *pSendSdpMsg, UINT Ip4, UINT ulMediaNum)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(pSendSdpMsg);
//set sdp.v
char *v = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(v, "0");
sdp_message_v_version_set(pSendSdpMsg, v);
//set sdp.o
char *o_username = (char*)osip_malloc(32*sizeof(UCHAR));
char *o_sess_id = (char*)osip_malloc(32*sizeof(UCHAR));
char *sess_version = (char*)osip_malloc(32*sizeof(UCHAR));
char *o_nettype = (char*)osip_malloc(32*sizeof(UCHAR));
char *o_addrtype = (char*)osip_malloc(32*sizeof(UCHAR));
sprintf(o_username, "user");
sprintf(o_sess_id, "53655765");
sprintf(sess_version, "2853687637");
sprintf(o_nettype, "IN");
sprintf(o_addrtype, "IP4");
char *addr = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(addr, "%d.%d.%d.%d", Ip4>>24&0xFF, Ip4>>16&0xFF, Ip4>>8&0xFF, Ip4&0xFF);
sdp_message_o_origin_set(pSendSdpMsg, o_username, o_sess_id, sess_version, o_nettype, o_addrtype, addr);
//set sdp.connection
char *c_nettype0 = (char*)osip_malloc(32*sizeof(UCHAR));
char *c_addrtype0 = (char*)osip_malloc(32*sizeof(UCHAR));
sprintf(c_nettype0, "IN");
sprintf(c_addrtype0, "IP4");
char *addr0 = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(addr0, "%d.%d.%d.%d", Ip4>>24&0xFF, Ip4>>16&0xFF, Ip4>>8&0xFF, Ip4&0xFF);
sdp_message_c_connection_add(pSendSdpMsg, -1, c_nettype0, c_addrtype0, addr0, NULL, NULL);
char *c_nettype1 = (char*)osip_malloc(16*sizeof(UCHAR));
char *c_addrtype1 = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(c_nettype1, "IN");
sprintf(c_addrtype1, "IP4");
char *addr1 = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(addr1, "%d.%d.%d.%d", Ip4>>24&0xFF, Ip4>>16&0xFF, Ip4>>8&0xFF, Ip4&0xFF);
sdp_message_c_connection_add(pSendSdpMsg, 0, c_nettype1, c_addrtype1, addr1, NULL, NULL);
if(2 == ulMediaNum)
{
char *c_nettype2 = (char*)osip_malloc(16*sizeof(UCHAR));
char *c_addrtype2 = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(c_nettype2, "IN");
sprintf(c_addrtype2, "IP4");
char *addr2 = (char*)osip_malloc(16*sizeof(UCHAR));
sprintf(addr2, "%d.%d.%d.%d", Ip4>>24&0xFF, Ip4>>16&0xFF, Ip4>>8&0xFF, Ip4&0xFF);
sdp_message_c_connection_add(pSendSdpMsg, 1, c_nettype2, c_addrtype2, addr2, NULL, NULL);
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceGetMediaInfoFromSipInvite(T_ModMsgHead* ptXpocMsgHdr, MediaDescriptionS *ptAudio, MediaDescriptionS *ptVideo)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_THREE_PARA(ptXpocMsgHdr, ptAudio, ptVideo);
SipMsgIndS *ptSipInd = (SipMsgIndS*)ptXpocMsgHdr->stMsgBody;
sdp_message_t *ptSdp = eXosip_get_sdp_info(ptSipInd->ulSipHandle->request);
if(!ptSdp)
{
x_ErrorLog("get sdp from invite failed.");
return XPOC_ERR_FAIL;
}
char aucSipCallId[STR_LEN32] = {0};
(void)rceGetCallIdFromSipHeader(ptSipInd->ulSipHandle->request, aucSipCallId);
UINT IPv4 = inet_addr(ptSdp->c_connection->c_addr);
sdp_media_t *ptAudioMedia = eXosip_get_audio_media(ptSdp);
if(ptAudioMedia)
{
ptAudio->ulIpAddr = ntohl(IPv4);
ptAudio->rtpPort = atoi(ptAudioMedia->m_port);
ptAudio->rtcpPort = ptAudio->rtpPort + 1;
ptAudio->bCodecNum = 1;
(void)MdeGetFirstMediaCodec(ptAudioMedia, &ptAudio->stSdpCodec[0]);
(void)MdeGetMediaTopoly(ptAudioMedia, &ptAudio->enTopoly);
(void)MdeGetMediaSsrc(ptAudioMedia, &ptAudio->ulSsrc);
x_InfoLog("Invite call-id [%s], sdp.audio:ipAddr[0x%x:%d],codec[%d],topoly[%d],ssrc[0x%x(%u)].",
aucSipCallId, ptAudio->ulIpAddr, ptAudio->rtpPort, ptAudio->stSdpCodec[0].ulCodecNo, ptAudio->enTopoly, ptAudio->ulSsrc);
}
sdp_media_t *ptVideoMedia = eXosip_get_video_media(ptSdp);
if(ptVideoMedia)
{
ptVideo->ulIpAddr = ntohl(IPv4);
ptVideo->rtpPort = atoi(ptVideoMedia->m_port);
ptVideo->rtcpPort = ptVideo->rtpPort + 1;
ptVideo->bCodecNum = 1;
(void)MdeGetFirstMediaCodec(ptVideoMedia, &ptVideo->stSdpCodec[0]);
(void)MdeGetMediaTopoly(ptVideoMedia, &ptVideo->enTopoly);
(void)MdeGetMediaSsrc(ptVideoMedia, &ptVideo->ulSsrc);
x_InfoLog("Invite call-id [%s], sdp.video:ipAddr[0x%x:%d],codec[%d],topoly[%d],ssrc[0x%x].",
aucSipCallId, ptVideo->ulIpAddr, ptVideo->rtpPort, ptVideo->stSdpCodec[0].ulCodecNo, ptVideo->enTopoly, ptVideo->ulSsrc);
}
if (ptSdp)
{
sdp_message_free(ptSdp);
ptSdp = NULL;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceSaveMediaInfo2UCC(MediaDescriptionS *ptAudio, MediaDescriptionS *ptVideo, T_RceUCallCtxTable *ptUCC)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptUCC);
if (MEDIA_AUDIO == ptUCC->enMediaType && ptAudio)
{
ptUCC->enMediaType = MEDIA_AUDIO;
memcpy(&ptUCC->stMediaInfo, ptAudio, sizeof(MediaDescriptionS));
}
else if (MEDIA_VIDEO == ptUCC->enMediaType && ptVideo)
{
ptUCC->enMediaType = MEDIA_VIDEO;
memcpy(&ptUCC->stMediaInfo, ptVideo, sizeof(MediaDescriptionS));
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceBuildSendSdpOnRecvSdp
(
sdp_media_t *ptAudioSdp,
sdp_media_t *ptVideoSdp,
T_RceUCallCtxTable *ptUCC_Audio,
T_RceUCallCtxTable *ptUCC_Video,
sdp_message_t *pSendSdpMsg
)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(pSendSdpMsg);
x_DebugLog("input:ptAudioSdp[%p],ptVideoSdp[%p],ptUCC_Audio[%p],ptUCC_Video[%p].",
ptAudioSdp, ptVideoSdp, ptUCC_Audio, ptUCC_Video);
if(ptAudioSdp && ptUCC_Audio)
{
while(ptAudioSdp->a_attributes.nb_elt)
osip_list_remove(&ptAudioSdp->a_attributes, 0);
while(ptAudioSdp->m_payloads.nb_elt)
osip_list_remove(&ptAudioSdp->m_payloads, 0);
while(ptAudioSdp->c_connections.nb_elt)
osip_list_remove(&ptAudioSdp->c_connections, 0);
/* set audio|video media info for 200-invite */
(void)RceSetSdpAudioMedia(ptUCC_Audio, pSendSdpMsg);
}
if(ptVideoSdp && ptUCC_Video)
{
while(ptVideoSdp->a_attributes.nb_elt)
osip_list_remove(&ptVideoSdp->a_attributes, 0);
while(ptVideoSdp->m_payloads.nb_elt)
osip_list_remove(&ptVideoSdp->m_payloads, 0);
while(ptVideoSdp->c_connections.nb_elt)
osip_list_remove(&ptVideoSdp->c_connections, 0);
/* set audio|video media info for 200-invite */
(void)RceSetSdpVideoMedia(ptUCC_Video, pSendSdpMsg);
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceBuildSdpForInviteRsp
(
T_ModCtxS *ptModCtx,
T_ModMsgHead *ptXpocMsgHdr,
T_RceUCallCtxTable *ptUCC_Audio,
T_RceUCallCtxTable *ptUCC_Video,
sdp_message_t **pptSendSdp
)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptXpocMsgHdr);
UINT ulReturn = XPOC_ERR_SUCCESS;
sdp_message_t *ptSendSdpTmp = NULL;
SipMsgIndS *ptSipMsgInd = (SipMsgIndS*)ptXpocMsgHdr->stMsgBody;
sdp_message_t *ptRecvSdp = eXosip_get_sdp_info(ptSipMsgInd->ulSipHandle->request);
if(!ptRecvSdp)
{
x_ErrorLog("recv invite without sdp.");
return XPOC_ERR_FAIL;
}
sdp_message_clone(ptRecvSdp, &ptSendSdpTmp);
if (ptRecvSdp)
{
sdp_message_free(ptRecvSdp);
ptRecvSdp = NULL;
}
sdp_media_t *ptAudioSdp = eXosip_get_audio_media(ptSendSdpTmp);
sdp_media_t *ptVideoSdp = eXosip_get_video_media(ptSendSdpTmp);
if((ptAudioSdp && ptUCC_Audio) || (ptVideoSdp && ptUCC_Video))
{
ulReturn = rceBuildSendSdpOnRecvSdp(ptAudioSdp, ptVideoSdp, ptUCC_Audio, ptUCC_Video, ptSendSdpTmp);
}
else
{
return XPOC_ERR_FAIL;
}
UINT ulMediaNum = 0;
if (ptAudioSdp && ptUCC_Audio)
{
ulMediaNum++;
}
if (ptVideoSdp && ptUCC_Video)
{
ulMediaNum++;
}
RceGlbData_S *ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
(void)rceBuildSdpCommInfo(ptSendSdpTmp, ptGlbData->stCfgInfo.ulLocalIp, ulMediaNum);
*pptSendSdp = ptSendSdpTmp;
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
#if 0
#endif
UINT rceSendInviteRsp(SipMsgIndS *pRcvSipMsg, sdp_message_t *SdpSession, RceCtrlBlockS *ptCB, UINT StatusCode)
{
UINT ulReturn = XPOC_ERR_SUCCESS;
char *ptNewBody = NULL;
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(pRcvSipMsg, ptCB);
SipMsgRspS stSipRsp;
memset(&stSipRsp, 0, sizeof(SipMsgRspS));
stSipRsp.sipMsgId = EV_SIP_INVITE_REQ;
stSipRsp.nTid = pRcvSipMsg->ulSipHandle->tid;
stSipRsp.ulSrcCbId = ptCB->ulCBId; //pRcvSipMsg->ulDstCbId;
stSipRsp.statusCode = StatusCode;
stSipRsp.stSipHeader.ulServType = Service_audio;
if (NULL != SdpSession)
{
/*x_InfoLog("SDP:v[%p],o_u[%p],o_s_id[%p],o_s_ver[%p],o_net[%p],o_adrtype[%p],o_adr[%p].",
SdpSession->v_version, SdpSession->o_username, SdpSession->o_sess_id, SdpSession->o_sess_version,
SdpSession->o_nettype, SdpSession->o_addrtype, SdpSession->o_addr);*/
sdp_message_to_str(SdpSession, &ptNewBody);
x_InfoLog("Invite response sdp:%s.", ptNewBody);
if (ptNewBody)
{
UINT ret = XPOCGetSipHeaderContentType(pRcvSipMsg->ulSipHandle->response, stSipRsp.stSipBodyPart.aucContentType);
if (XPOC_ERR_SUCCESS != ret)
{
sprintf(stSipRsp.stSipBodyPart.aucContentType, "application/sdp");
}
stSipRsp.stSipBodyPart.ulXmlBodyLen = strlen(ptNewBody);
memcpy((char*)stSipRsp.stSipBodyPart.xmlBody, ptNewBody, stSipRsp.stSipBodyPart.ulXmlBodyLen);
}
}
else
{
x_ErrorLog("pSendSdpMsg is NULL.");
}
ulReturn = XPOCSendSipRspMsg(&stSipRsp, 0, SIP_THREAD_ONE);
if (ptNewBody)
{
osip_free(ptNewBody);
sdp_message_free(SdpSession);
}
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceSendByeRsp(SipMsgIndS *pRcvSipMsg, RceCtrlBlockS *ptCB, UINT StatusCode)
{
UINT ulReturn = XPOC_ERR_SUCCESS;
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(pRcvSipMsg, ptCB);
SipMsgRspS stSipRsp;
memset(&stSipRsp, 0, sizeof(SipMsgRspS));
stSipRsp.sipMsgId = EV_SIP_BYE_REQ;
stSipRsp.nTid = pRcvSipMsg->ulSipHandle->tid;
stSipRsp.ulSrcCbId = ptCB->ulCBId; //pRcvSipMsg->ulDstCbId;
stSipRsp.statusCode = StatusCode;
ulReturn = XPOCSendSipRspMsg(&stSipRsp, 0, SIP_THREAD_ONE);
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
UINT rceHandleSipInvite(T_ModCtxS *ptModCtx, T_ModMsgHead* ptXpocMsgHdr)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptXpocMsgHdr);
UINT ulReturn = XPOC_ERR_SUCCESS;
UINT ulCBId = 0;
RceCtrlBlockS *ptCB = NULL;
T_RceUCallCtxTable stUCC;
SipMsgIndS *ptSipMsgInd = (SipMsgIndS*)ptXpocMsgHdr->stMsgBody;
sdp_message_t *ptSendSdp = NULL;
char aucServId[STR_LEN32] = {0};
char aucSipCallId[STR_LEN32] = {0};
T_RceUCallCtxTable *ptUCC_Audio = NULL;
T_RceUCallCtxTable *ptUCC_Video = NULL;
T_RceUCallCtxTable stUCC_Audio;
T_RceUCallCtxTable stUCC_Video;
memset(&stUCC_Audio, 0, sizeof(T_RceUCallCtxTable));
memset(&stUCC_Video, 0, sizeof(T_RceUCallCtxTable));
MediaDescriptionS stAudio;
MediaDescriptionS stVideo;
memset(&stAudio, 0, sizeof(MediaDescriptionS));
memset(&stVideo, 0, sizeof(MediaDescriptionS));
stAudio.bCodecNum = INVALID_VALUE_UCHAR;
stVideo.bCodecNum = INVALID_VALUE_UCHAR;
CallInfoS stCallInfo;
/*
MDE收到invite要做的事情:
1. get CB
2. alloc/get CallCtx;
3. alloc/get UCallCtx;
4. get media codec from src invite.sdp;
5. save media codec para into UCallCtx;
6. construct sdp for 200-invite;
7. send 200-invite to CCE;
*/
do
{
memset(aucSipCallId, 0, STR_LEN32);
(void)rceGetCallIdFromSipHeader(ptSipMsgInd->ulSipHandle->request, aucSipCallId);
memset(aucServId, 0, STR_LEN32);
(void)rceGetServIdFromSipHeader(ptSipMsgInd->ulSipHandle->request, aucServId);
memset(&stCallInfo, 0, sizeof(CallInfoS));
(void)XPOCGetCallnfoSipHeader(ptSipMsgInd->ulSipHandle->request, &stCallInfo);/* vidgrptrans,vidpritrans,record 时使用来传递mediaCCId */
if (Serv_AudioRcrdPri != stCallInfo.enServType
&& Serv_VideoRcrdPri != stCallInfo.enServType
&& Serv_AudioRcrdGrp != stCallInfo.enServType
&& Serv_VideoRcrdGrp != stCallInfo.enServType)
{
x_ErrorLog("rce get CallInfo enServType failed, call-id [%s].\n", aucSipCallId);
ulReturn = XPOC_ERR_INVALID_MSG;
break;
}
ulReturn = rceGetCB(ptXpocMsgHdr, &ulCBId, &ptCB);
if(XPOC_ERR_SUCCESS != ulReturn || NULL == ptCB)
{
x_ErrorLog("rce get CtrlBlock failed, retcode[%d],ptCB[%p], sip call-id[%s].\n", ulReturn, ptCB, aucSipCallId);
break;
}
ptCB->ulCurrMsgId = ptXpocMsgHdr->ulMsgId;
//ptCB->ptSpSipHandle = ptSipMsgInd->ulSipHandle;
(void)rceGetMediaInfoFromSipInvite(ptXpocMsgHdr, &stAudio, &stVideo);
if (INVALID_VALUE_UCHAR == stAudio.bCodecNum && INVALID_VALUE_UCHAR == stVideo.bCodecNum)
{
x_WarnLog("get media info from caller.invite.sdp failed. sip call-id [%s]", aucSipCallId);
break;
}
int rtpFdIdx = -1;
if (INVALID_VALUE_UCHAR != stAudio.bCodecNum)
{
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
stUCC.enMediaType = MEDIA_AUDIO;
(void)rceSaveMediaInfo2UCC(&stAudio, &stVideo, &stUCC);
// alloc UCC
memcpy(&(stUCC.tCallInfoS), &stCallInfo, sizeof(CallInfoS));
memcpy(stUCC.aucServId, aucServId, strlen(aucServId));
memcpy(stUCC.aucCallId, aucSipCallId, strlen(aucSipCallId));
ulReturn = XRceUCallCtxOpr(XDB_OPR_ADD, stUCC.aucServId, stUCC.aucCallId, stUCC.enMediaType, NULL, NULL, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Qry UCallCtx fail.");
break;
}
// open udp socket
ulReturn = rceAllocUdpSocket(ptModCtx, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("rceAllocUdpSocket failed -- udp audio connect failed -- aucServId[%s] call-id[%s] ipAddr[0x%x:%d]",
stUCC.aucServId, stUCC.aucCallId, stUCC.stMediaInfo.ulIpAddr, stUCC.stMediaInfo.rtpPort);
(void)XRceUCallCtxOpr(XDB_OPR_DEL, NULL, 0, (MediaTypeE)0, NULL, &stUCC.ulRecordIdx, &stUCC);
break;
}
///
rtpFdIdx = stUCC.usRtpFdIdx;
stUCC.ulCBId = ptCB->ulCBId;
ulReturn = XRceUCallCtxOpr(XDB_OPR_MOD, NULL, 0, (MediaTypeE)0, NULL, &stUCC.ulRecordIdx, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Modify UCallCtx fail.");
break;
}
// update CB info
if (ptCB->StreamNum >= MEDIA_TYPE_MAX)
{
x_WarnLog("CB StreamInfoArray Index[%u] over MAX_STREAM_NUM[%u]", ptCB->StreamNum, MEDIA_TYPE_MAX);
ptCB->StreamNum = 0;
}
ptCB->StreamInfoArray[ptCB->StreamNum].ulUCallCtxId = stUCC.ulRecordIdx;
ptCB->StreamNum++;
memcpy(&stUCC_Audio, &stUCC, sizeof(T_RceUCallCtxTable));
ptUCC_Audio = &stUCC_Audio;
x_InfoLog("Audio media:sip call-id [%s], servId [%s], servType [%d], cbId [%d], ucc id [%d]",
aucSipCallId, stUCC.aucServId, stCallInfo.enServType, ptCB->ulCBId, stUCC.ulRecordIdx);
}
if (INVALID_VALUE_UCHAR != stVideo.bCodecNum)
{
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
stUCC.enMediaType = MEDIA_VIDEO;
(void)rceSaveMediaInfo2UCC(&stAudio, &stVideo, &stUCC);
// alloc UCC
memcpy(&(stUCC.tCallInfoS), &stCallInfo, sizeof(CallInfoS));
memcpy(stUCC.aucServId, aucServId, strlen(aucServId));
memcpy(stUCC.aucCallId, aucSipCallId, strlen(aucSipCallId));
ulReturn = XRceUCallCtxOpr(XDB_OPR_ADD, stUCC.aucServId, stUCC.aucCallId, stUCC.enMediaType, NULL, NULL, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Add UCallCtx fail.");
break;
}
// open tcp socket
ulReturn = rceAllocTcpSocket(ptModCtx, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("rceAllocTcpSocket failed -- tcp video connect failed -- aucServId[%s] call-id[%s] ipAddr[0x%x:%d]",
stUCC.aucServId, stUCC.aucCallId, stUCC.stMediaInfo.ulIpAddr, stUCC.stMediaInfo.rtpPort);
(void)XRceUCallCtxOpr(XDB_OPR_DEL, NULL, 0, (MediaTypeE)0, NULL, &stUCC.ulRecordIdx, &stUCC);
break;
}
stUCC.ulCBId = ptCB->ulCBId;
ulReturn = XRceUCallCtxOpr(XDB_OPR_MOD, NULL, 0, (MediaTypeE)0, NULL, &stUCC.ulRecordIdx, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Modify UCallCtx fail.");
break;
}
// update CB info
if (ptCB->StreamNum >= MEDIA_TYPE_MAX)
{
x_WarnLog("CB StreamInfoArray Index[%u] over MAX_STREAM_NUM[%u]", ptCB->StreamNum, MEDIA_TYPE_MAX);
ptCB->StreamNum = 0;
}
ptCB->StreamInfoArray[ptCB->StreamNum].ulUCallCtxId = stUCC.ulRecordIdx;
ptCB->StreamNum++;
memcpy(&stUCC_Video, &stUCC, sizeof(T_RceUCallCtxTable));
ptUCC_Video = &stUCC_Video;/* video UCC */
///
if(rtpFdIdx != -1) {
MediaFdS *ptRtpFd = NULL;
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
ptRtpFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[rtpFdIdx];
ptRtpFd->tcpFdIdx = stUCC.usTcpRtpFdIdx;
}
x_InfoLog("Vedio media:sip call-id [%s], servId [%s], servType [%d], cbId [%d], ucc id [%d]",
aucSipCallId, stUCC.aucServId, stCallInfo.enServType, ptCB->ulCBId, stUCC.ulRecordIdx);
}
ulReturn = rceBuildSdpForInviteRsp(ptModCtx, ptXpocMsgHdr, ptUCC_Audio, ptUCC_Video, &ptSendSdp);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("rceAllocTcpSocket failed -- tcp video connect failed -- aucServId[%s] call-id[%s] ipAddr[0x%x:%d]",
stUCC.aucServId, stUCC.aucCallId, stUCC.stMediaInfo.ulIpAddr, stUCC.stMediaInfo.rtpPort);
ptSendSdp = NULL;
}
}while(0);
SipStatusCodeE enSipStatus = (SipStatusCodeE)((XPOC_ERR_SUCCESS == ulReturn) ? 200 : 403);
(void)rceSendInviteRsp(ptSipMsgInd, ptSendSdp, ptCB, enSipStatus);
/* 失败处理,要回收控制块资源和对应的UCallCtx资源 */
if(XPOC_ERR_SUCCESS != ulReturn)
{
if(ptCB)
{
UCHAR i = 0;
T_RceUCallCtxTable stUCCTmp;
for(i = 0; i < ptCB->StreamNum; i++)
{
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptCB->StreamInfoArray[i].ulUCallCtxId, &stUCCTmp);
if(XPOC_ERR_SUCCESS != ulReturn)
{
rceCloseMediaSocket(&stUCCTmp);
(void)XRceUCallCtxOpr(XDB_OPR_DEL, NULL, 0, (MediaTypeE)0, NULL, &stUCCTmp.ulRecordIdx, &stUCCTmp);
}
}
(void)XPOCFreeCtrlBlock(ptCB->ulCBId, 0);
}
}
else
{
if((INVALID_VALUE_UCHAR != stVideo.bCodecNum) || (INVALID_VALUE_UCHAR != stAudio.bCodecNum))
{
MediaFdS *ptRtpFd = NULL;
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
if(INVALID_VALUE_UCHAR != stVideo.bCodecNum)
{
ptRtpFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[stUCC.usTcpRtpFdIdx];
ptRtpFd->stTimer.TimerType = RCE_TIMER_SEND_TCP_TEST_PKT_FIRST;
ptRtpFd->stTimer.uiParam2 = stUCC.usTcpRtpFdIdx;
}
else if(INVALID_VALUE_UCHAR != stAudio.bCodecNum)
{
ptRtpFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx];
ptRtpFd->stTimer.TimerType = RCE_TIMER_SEND_UDP_TEST_PKT_FIRST;
ptRtpFd->stTimer.uiParam2 = stUCC.usRtpFdIdx;
}
XPOCStartTimer(0, 100000, &ptRtpFd->stTimer, TIME_FLAG_ONCE);/* 延迟 0.1s */
x_InfoLog("rce timer start: timeType[%d],timerId[%lld],timeLen[0.1].",
ptRtpFd->stTimer.TimerType, ptRtpFd->stTimer.TimerId);
}
/* 对于audio-record, 向h-user-voice中插入一条记录 */
if (Serv_AudioRcrdPri == stCallInfo.enServType
|| Serv_AudioRcrdGrp == stCallInfo.enServType
/*|| (Serv_VideoRcrdPri == stCallInfo.enServType
&& Serv_VideoPri == stCallInfo.enRcrdServType
&& (INVALID_VALUE_UCHAR == stVideo.bCodecNum))*/)
{
(void)rceAddVoiceCallInfo2DB(stUCC.ulRecordIdx);
}
if ((Serv_VideoRcrdPri == stCallInfo.enServType) /*&& (INVALID_VALUE_UCHAR != stVideo.bCodecNum)*/
|| Serv_VideoRcrdGrp == stCallInfo.enServType)
{
(void)rceAddVideoCallInfo2DB(stUCC.ulRecordIdx);
}
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceHandleSipBye(T_ModCtxS *ptModCtx, T_ModMsgHead* ptXpocMsgHdr)
{
UINT ulReturn= XPOC_ERR_SUCCESS;
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptModCtx, ptXpocMsgHdr);
SipMsgIndS *ptSipMsgInd = (SipMsgIndS*)ptXpocMsgHdr->stMsgBody;
UINT ulCBId = ptSipMsgInd->ulDstCbId;
UINT ulUCallCtxId = 0;
char aucSipCallId[32] = {0};
(void)rceGetCallIdFromSipHeader(ptSipMsgInd->ulSipHandle->request, aucSipCallId);
x_InfoLog("Recv sip bye, call-id [%s], cbid [%d]", aucSipCallId, ulCBId);
RceCtrlBlockS *ptCB = NULL;
T_RceUCallCtxTable stUCC;
T_RceUCallCtxTable stUCCTmp;
do
{
ulReturn = rceGetCB(ptXpocMsgHdr, &ulCBId, &ptCB);
if (XPOC_ERR_SUCCESS != ulReturn || NULL == ptCB)
{
x_ErrorLog("rce get CtrlBlock failed, retcode[%d],ptCB[%p].\n", ulReturn, ptCB);
break;
}
UINT i = 0;
for (i = 0; i < ptCB->StreamNum && i < MEDIA_TYPE_MAX; i++)
{
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulUCallCtxId = ptCB->StreamInfoArray[i].ulUCallCtxId;
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ulUCallCtxId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
continue;
}
memset(&stUCCTmp, 0, sizeof(T_RceUCallCtxTable));
memcpy(&stUCCTmp, &stUCC, sizeof(T_RceUCallCtxTable));
/// upd db before del
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
{
if(MEDIA_AUDIO == stUCC.enMediaType && stUCC.usRtpFdIdx < g_tServerCfg.uConcurrCallMaxNum)
{
MediaFdS *ptMediaFd = &ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx];
if(ptMediaFd->iRceRecordState == Record_WORK)
{
///
if(Serv_VideoPri == stUCC.tCallInfoS.enRcrdServType && ptMediaFd->tcpFdIdx == -1) {
// update db
(void)rceAddVideoRecord2DB(ptMediaFd);
(void)rceUptUserVideoEndTime2DB(ptMediaFd);
} else {
// update db
(void)rceAddVoiceRecord2DB(&ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx]);
/* 关闭文件说明是写完一个文件, 需要把record的当前结束时间写道h_user_voice中 */
(void)rceUptUserVoiceEndTime2DB(&ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx]);
}
}
}
else if(MEDIA_VIDEO == stUCC.enMediaType && stUCC.usTcpRtpFdIdx < g_tServerCfg.uConcurrCallMaxNum)
{
MediaFdS *ptMediaFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[stUCCTmp.usTcpRtpFdIdx];
if(ptMediaFd->iRceRecordState == Record_WORK)
{
ULONGLONG dur = MP4GetDuration(ptMediaFd->pvMp4HFile);
//printf("-------~~~~~~~dur: %lu\n", dur);
// update db
(void)rceAddVideoRecord2DB(ptMediaFd);
/* 关闭文件说明是写完一个文件, 需要把record的当前结束时间写道h_user_video中 */
//(void)rceUptUserVideoEndTime2DB(&ptGlbData->stTcpAddrInfo.tcpRtpFdList[stUCCTmp.usTcpRtpFdIdx]);
(void)rceUptUserVideoEndTime2DB_2(&ptGlbData->stTcpAddrInfo.tcpRtpFdList[stUCCTmp.usTcpRtpFdIdx], dur/1000);
}
}
}
ulReturn = XRceUCallCtxOpr(XDB_OPR_DEL, NULL, 0, (MediaTypeE)0, NULL, &ulUCallCtxId, &stUCC);
if (stUCCTmp.usRtpFdIdx < g_tServerCfg.uConcurrCallMaxNum || stUCCTmp.usTcpRtpFdIdx < g_tServerCfg.uConcurrCallMaxNum)
{
ulReturn = rceCloseMediaSocket(&stUCCTmp);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Close RTP socket failed. UCCId=%d, SockfdIdx=%d.\n", ulUCallCtxId, stUCCTmp.usRtpFdIdx);
}
}
}
(void)XPOCFreeCtrlBlock(ptCB->ulCBId, ulReturn);
} while (0);
SipStatusCodeE enSipStatus = (SipStatusCodeE)((XPOC_ERR_SUCCESS == ulReturn) ? 200 : 403);
(void)rceSendByeRsp(ptSipMsgInd, ptCB, enSipStatus);
XPOC_TRACEFUNC_OUT;
return ulReturn;
}
rceMediaFunc.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h> /* for TCP_XXX defines */
#include "rceResourceFunc.h"
#include "rceMediaFunc.h"
#include "rceCommFunc.h"
#include "rceProc.h"
extern T_ServerCfg g_tServerCfg;
extern MYSQL *mysql_connect;
extern const char *glbFDType[FD_TYPE_BUTT];
ThreadInfo_t g_threadDpSendRtp[MAX_NUM_OF_DP_THREAD];/* 媒体处理线程,现在UDP,TCP 分别用一个. 其他的未用到. */
#define PCM_SAMPLE_LEN 500
#define AMR_NB_HEADER_LEN 6
#define AMR_WB_HEADER_LEN 9
char audio_record_type = AUDIOTYPE_AMR_NB;
#if 0
#endif
//
static time_t GetCurrMsTime(void)
{
time_t uMillSec = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
uMillSec = (time_t)tv.tv_sec * 1000;
uMillSec += tv.tv_usec / 1000;
return uMillSec;
}
#if 0
#endif
/* RCE主要创建如下几个线程:
1. UDP接收线程 and TCP接收线程;
2. audio|floor 发送线程;
3. video 发送线程;
*/
UINT rceInitDpThread(T_ModCtxS *ptModCtx)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptModCtx);
UINT ulReturn = XPOC_ERR_SUCCESS;
/* [1] create epoll recv thread */
pthread_t threadId;
ulReturn = pthread_create(&threadId, 0, rceDpRecvUdpPacket, NULL);
if(0 != ulReturn)
{
x_ErrorLog("[X][UDP] main recv thread create failed. mainThreadId[%lu], result[%lu].\n", threadId, ulReturn);
return ulReturn;
}
x_InfoLog("[X][UDP] main recv thread create OK. mainThreadId[%lu].\n", threadId);
ulReturn = pthread_create(&threadId, 0, rceDpRecvTcpPacket, NULL);
if(0 != ulReturn)
{
x_ErrorLog("[X][TCP] main recv thread create failed. mainThreadId[%lu], result[%lu].\n", threadId, ulReturn);
return ulReturn;
}
x_InfoLog("[X][TCP] main recv thread create OK. mainThreadId[%lu].\n", threadId);
/*[2] Create number of RTP Worker threads */
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
PktQueue_S *ptBuff = NULL;
UCHAR i = 0;
for (i = 0; i < ptGlbData->stCfgInfo.rtpWorkerThreadNum; i++)
{
ptBuff = (PktQueue_S*)Fplat_Malloc(sizeof(PktQueue_S), 0);
if(!ptBuff)
{
x_ErrorLog("RTP packet data buffer queue alloc failed.\n");
return XPOC_ERR_FAIL;
}
memset(ptBuff, 0x00, sizeof(PktQueue_S));
memset(&g_threadDpSendRtp[i], 0x00, sizeof(ThreadInfo_t));
ptBuff->PktNode = (PktNode_S*)Fplat_Malloc(sizeof(PktNode_S) * g_tServerCfg.nMediaQueueSize, 0);
ptBuff->astPktNodeIndex = (NodeIndex_S*)Fplat_Malloc(sizeof(NodeIndex_S) * g_tServerCfg.nMediaQueueSize, 0);
if (!ptBuff->PktNode || !ptBuff->astPktNodeIndex)
{
x_ErrorLog("Alloc pkt node or node idex failed.\n");
exit(-1);
}
/******************************************************************************/
/* 初始化队列索引管理上下文 */
rceRmIdxManageInitCtx(&ptBuff->stIndexManageCtx, ptBuff->astPktNodeIndex, g_tServerCfg.nMediaQueueSize);
/******************************************************************************/
g_threadDpSendRtp[i].pPktQueue = (PktQueue_S*)ptBuff;
g_threadDpSendRtp[i].enThreadType = (1==i) ? PROTO_TCP : PROTO_UDP; /* 记录当前线程处理的协议类型. 0--用于UDP处理, 1--用于TCP处理 */
ulReturn = pthread_create(&(g_threadDpSendRtp[i].ThreadId), 0, rceDpHandlePktFromQueue, (void*)&g_threadDpSendRtp[i]);
if(0 != ulReturn)
{
Fplat_Free(ptBuff);
x_ErrorLog("[X]RTP worker thread create failed. thread[%d:%lu], result[%d].\n",
i, g_threadDpSendRtp[i].ThreadId, ulReturn);
return XPOC_ERR_FAIL;
}
else
{
x_InfoLog("[X]RTP worker thread create OK. thread[%d:%lu], pktQueue[%p], queue size [%d].\n",
i, g_threadDpSendRtp[i].ThreadId, g_threadDpSendRtp[i].pPktQueue, g_tServerCfg.nMediaQueueSize);
}
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT generateRecordFileName(MediaFdS *ptMediaFd, CallInfoS *ptCallInfo, char *ptCreatTime)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_THREE_PARA(ptMediaFd, ptCallInfo, ptCreatTime);
if (MEDIA_VIDEO == ptMediaFd->iRceMediaType)
{
if (Serv_VideoPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPri-MO-%s-MT-%s-Cur-%s-%s.mp4",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_VideoPullPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPullPri-MO-%s-MT-%s-Cur-%s-%s.mp4",
ptCallInfo->aucRelatNum, ptCallInfo->aucRcrdNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_VideoPushPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPushPri-MO-%s-MT-%s-Cur-%s-%s.mp4",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_VideoTransPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoTransPri-MO-%s-MT-%s-Cur-%s-%s.mp4",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_VideoPushGrp == ptCallInfo->enRcrdServType)
{
if(0==strlen(ptMediaFd->aucGroupSpkNum))/* 首次默认话权时会没有取到groupSpkNum */
{
strcpy(ptMediaFd->aucGroupSpkNum, ptCallInfo->aucOrigNum);
}
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPushGrp-MO-%s-Group-%s-Cur-%s-%s.mp4",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdGrpNum, ptMediaFd->aucGroupSpkNum, ptCreatTime);
}
else if (Serv_VideoTransGrp == ptCallInfo->enRcrdServType)
{
if(0==strlen(ptMediaFd->aucGroupSpkNum))/* 首次默认话权时会没有取到groupSpkNum */
{
strcpy(ptMediaFd->aucGroupSpkNum, ptCallInfo->aucOrigNum);
}
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoTransGrp-MO-%s-Group-%s-Cur-%s-%s.mp4",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdGrpNum, ptMediaFd->aucGroupSpkNum, ptCreatTime);
}
else
{
x_ErrorLog("ptCallInfo->enRcrdServType[%d] is error for video.\n", ptCallInfo->enRcrdServType);
return XPOC_ERR_FAIL;
}
}
if (MEDIA_AUDIO == ptMediaFd->iRceMediaType)
{
if (AUDIOTYPE_AMR_NB == audio_record_type || AUDIOTYPE_AMR_WB == audio_record_type)
{
if (Serv_AudioPri == ptCallInfo->enRcrdServType)
{
/* snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);*/
if (0 == strcmp(ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdNum))
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucOrigNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
}
else if (Serv_AudioHalfPri == ptCallInfo->enRcrdServType)
{
// modified by shm, 解决被叫录音文件名不正确问题*/
//char acCalleeNum[STR_LEN32] = {0};
if (0 == strcmp(ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdNum))
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioHalfPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucOrigNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioHalfPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
}
else if (Serv_AudioGroup == ptCallInfo->enRcrdServType)
{
if(0 == strlen(ptMediaFd->aucGroupSpkNum))/* 首次默认话权时会没有取到groupSpkNum */
{
strcpy(ptMediaFd->aucGroupSpkNum, ptCallInfo->aucOrigNum);
}
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioGroup-MO-%s-Group-%s-Cur-%s-%s.amr",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdGrpNum, ptMediaFd->aucGroupSpkNum, ptCreatTime);
}
else if (Serv_VideoPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPri-MO-%s-MT-%s-Cur-%s-%s.amr",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else
{
x_ErrorLog("ptCallInfo->enRcrdServType[%d] is error for audio.\n", ptCallInfo->enRcrdServType);
return XPOC_ERR_FAIL;
}
}
else if( AUDIOTYPE_G711 == audio_record_type)
{
if (Serv_AudioPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioPri-MO-%s-MT-%s-Cur-%s-%s.wav",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_AudioHalfPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioHalfPri-MO-%s-MT-%s-Cur-%s-%s.wav",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else if (Serv_AudioGroup == ptCallInfo->enRcrdServType)
{
if (0 == strlen(ptMediaFd->aucGroupSpkNum))/* 首次默认话权时会没有取到groupSpkNum */
{
strcpy(ptMediaFd->aucGroupSpkNum, ptCallInfo->aucOrigNum);
}
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "AudioGroup-MO-%s-Group-%s-Cur-%s-%s.wav",
ptCallInfo->aucOrigNum, ptCallInfo->aucRcrdGrpNum, ptMediaFd->aucGroupSpkNum, ptCreatTime);
}
else if (Serv_VideoPri == ptCallInfo->enRcrdServType)
{
snprintf(ptMediaFd->szRecordFileName, STR_LEN512, "VideoPri-MO-%s-MT-%s-Cur-%s-%s.wav",
ptCallInfo->aucRcrdNum, ptCallInfo->aucRelatNum, ptCallInfo->aucSpkNum, ptCreatTime);
}
else
{
x_ErrorLog("ptCallInfo->enRcrdServType[%d] is error for audio.\n", ptCallInfo->enRcrdServType);
return XPOC_ERR_FAIL;
}
}
}
x_InfoLog("generate RecordFileName[%s],servType[%d],mediaType[%d], spk num [%s], grp spk num [%s].",
ptMediaFd->szRecordFileName, ptCallInfo->enRcrdServType, ptMediaFd->iRceMediaType
, ptCallInfo->aucSpkNum, ptMediaFd->aucGroupSpkNum);
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT AddWaveFileHeader(int fd_record, int totalAudioLen)
{
unsigned char header[56] = {0x52,0x49,0x46,0x46,0x00,0x00,0x00,0x00,
0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,
0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
0x40,0x1F,0x00,0x00,0x80,0x3E,0x00,0x00,
0x02,0x00,0x10,0x00,0x66,0x61,0x63,0x74,
0x04,0x00,0x00,0x00,0x00,0xBE,0x00,0x00,
0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00 };
int totalDataLen = totalAudioLen + 48;
header[4] = (unsigned char)(totalDataLen & 0xff);
header[5] = (unsigned char)((totalDataLen >> 8) & 0xff);
header[6] = (unsigned char)((totalDataLen >> 16) & 0xff);
header[7] = (unsigned char)((totalDataLen >> 24) & 0xff);
header[52] = (unsigned char)(totalAudioLen & 0xff);
header[53] = (unsigned char)((totalAudioLen >> 8) & 0xff);
header[54] = (unsigned char)((totalAudioLen >> 16) & 0xff);
header[55] = (unsigned char)((totalAudioLen >> 24) & 0xff);
if (-1 != write(fd_record, header, 56))
{
return XPOC_ERR_SUCCESS;
}
else
{
return XPOC_ERR_FAIL;
}
}
UINT AddAMRFileHeader(int fd_record, int totalAudioLen)
{
(void)totalAudioLen;
const char header[] = "#!AMR-WB\n";
if (-1 != write(fd_record, header, AMR_WB_HEADER_LEN))
{
return XPOC_ERR_SUCCESS;
}
else
{
return XPOC_ERR_FAIL;
}
}
// added by shm
UINT AddAMRNBFileHeader(int fd_record, int totalAudioLen)
{
(void)totalAudioLen;
const char header[] = "#!AMR\n";
if (-1 != write(fd_record, header, AMR_NB_HEADER_LEN))
{
return XPOC_ERR_SUCCESS;
}
else
{
return XPOC_ERR_FAIL;
}
}
UINT UnpackRTPH264(unsigned char * bufIn, int len, unsigned char ** pBufOut, int * pOutLen)
{
*pOutLen = 0;
if (len <= RTP_HEADER_LEN)
{
return XPOC_ERR_FAIL;
}
const int hdrLen = (bufIn[0]&0x10)?RTP_HEADER_LEN+RTP_HEADER_EXT_LEN:RTP_HEADER_LEN;
unsigned char * src = bufIn + hdrLen;
unsigned char head1 = *src; // 获取第一个字节
unsigned char head2 = *(src + 1); // 获取第二个字节
unsigned char nal = head1 & 0x1f; // 获取FU indicator的类型域,
unsigned char flag = head2 & 0xe0; // 获取FU header的前三位,判断当前是分包的开始、中间或结束
unsigned char nal_fua = (head1 & 0xe0) | (head2 & 0x1f); // FU_A nal
UINT ulReturn = XPOC_ERR_FAIL;
if (nal == 0x1c) // 判断NAL的类型为0x1c=28,说明是FU-A分片
{ // fu-a
if (flag == 0x80) // 开始
{
*pBufOut = src - 3;
*((int *)(*pBufOut)) = 0x01000000; // zyf:大模式会有问题
*((char *)(*pBufOut) + 4) = nal_fua;
*pOutLen = len - hdrLen + 3;
}
else if (flag == 0x40) // 结束
{
*pBufOut = src + 2;
*pOutLen = len - hdrLen - 2;
}
else // 中间
{
*pBufOut = src + 2;
*pOutLen = len - hdrLen - 2;
}
ulReturn = XPOC_ERR_SUCCESS;
}
else // 单包数据
{
*pBufOut = src - 4;
*((int *)(*pBufOut)) = 0x01000000; // zyf:大模式会有问题
*pOutLen = len - hdrLen + 4;
ulReturn = XPOC_ERR_SUCCESS;
}
// 本来应该在这的,因为我们现在是RTP头固定的,且是单包数据
// unsigned char * bufTmp = (unsigned char *)bufIn;
// if (bufTmp[1] & 0x80)
// {
// bFinishFrame = true; // rtp mark
// }
// else
// {
// bFinishFrame = false;
// }
return ulReturn;
}
short decode(unsigned char alaw)
{
alaw ^= 0xD5;
int sign = alaw & 0x80;
int exponent = (alaw & 0x70) >> 4;
int data = alaw & 0x0f;
data <<= 4;
data += 8;
if (exponent != 0)
data += 0x100;
if (exponent > 1)
data <<= (exponent - 1);
return (short)(sign == 0 ? data : -data);
}
/** 个人理解
* bitsize 应该为16, pBuffer(pcm数据) 两个char 合成一个 short ,长度自然就是原来的一半(nBufferSize/2),
* 通过编码后short类型的数据变为char类型,让后复制给pCodecBits
*/
int g711_decode(char* pRawData, const unsigned char* pBuffer, int nBufferSize)
{
short *out_data = (short*)pRawData;
int i;
for (i = 0; i < nBufferSize; i++)
{
out_data[i] = decode(pBuffer[i]);
}
// if (g_AudioConfig.g_PCM_SoundRaiseEnabled)
// {
// RaiseVolume(pRawData, nBufferSize * 2, 1, g_AudioConfig.g_PCM_SoundRaiseVolume);
// }
return nBufferSize * 2;
}
#if 0
#endif
UINT rceAddVideoCallInfo2DB(UINT ulUCCId)
{
XPOC_TRACEFUNC_IN;
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
return XPOC_ERR_FAIL;
}
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
ulReturn = MYSQL_UserVideo_Qry_Id_By_SipCallId(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS == ulReturn)
{
return ulReturn;/* 已经存在了则不需要再ADD */
}
memcpy(stUserVideo.company_no, stUCC.tCallInfoS.aucSpkNum, 8);
x_InfoLog("aucSpkNum[%s],aucCompanyNo[%s].", stUCC.tCallInfoS.aucSpkNum, stUserVideo.company_no);
char biz_type[STR_LEN16];
memset(biz_type, 0, STR_LEN16);
ulReturn = rceGetBizTypeByServType(stUCC.tCallInfoS.enRcrdServType, biz_type);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
strcpy(stUserVideo.biz_type, biz_type);
if(Serv_AudioRcrdPri == stUCC.tCallInfoS.enServType
|| Serv_VideoRcrdPri == stUCC.tCallInfoS.enServType)
{
if (Serv_VideoPullPri == stUCC.tCallInfoS.enRcrdServType) // added by shm at 20210204, 视频上拉,主叫为aucRelatNum,被叫为aucRcrdNum
{
strncpy(stUserVideo.from_user_no, stUCC.tCallInfoS.aucRelatNum, STR_LEN32);
strncpy(stUserVideo.to_user_no, stUCC.tCallInfoS.aucRcrdNum, STR_LEN32);
}
else
{
strncpy(stUserVideo.from_user_no, stUCC.tCallInfoS.aucRcrdNum, STR_LEN32);
strncpy(stUserVideo.to_user_no, stUCC.tCallInfoS.aucRelatNum, STR_LEN32);
}
}
else if(Serv_AudioRcrdGrp == stUCC.tCallInfoS.enServType
|| Serv_VideoRcrdGrp == stUCC.tCallInfoS.enServType)
{
strncpy(stUserVideo.from_user_no, stUCC.tCallInfoS.aucOrigNum, STR_LEN32);
strncpy(stUserVideo.to_user_no, stUCC.tCallInfoS.aucRcrdGrpNum, STR_LEN32);
}
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVideo.start_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
strftime(stUserVideo.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVideo_Add(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceUptUserVideoStartTime2DB(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
///
int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
now_ms = tv.tv_usec/1000;
if(now_ms>500) now_sec += 1;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVideo.start_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVideo_Upt_StartTime(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceUptUserVideoEndTime2DB(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVideo.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVideo_Upt_EndTime(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceUptUserVideoStartTime2DB_2(MediaFdS *ptMediaFd, UINT dur)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
///
time_t now_sec;
now_sec = ptMediaFd->tmRecordStartTime+dur;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVideo.start_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVideo_Upt_StartTime(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceUptUserVideoEndTime2DB_2(MediaFdS *ptMediaFd, UINT dur)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
///
struct tm tmInfo;
time_t now_sec;
now_sec = ptMediaFd->tmRecordStartTime+dur;
char createTime[32] = {0};
localtime_r(&ptMediaFd->tmRecordStartTime, &tmInfo);
strftime(createTime, STR_LEN32, "%Y-%m-%d-%H-%M-%S", &tmInfo);
localtime_r(&now_sec, &tmInfo);
strftime(stUserVideo.end_time, 20, "%Y-%m-%d %H:%M:%S", &tmInfo);
//printf("--------%s---------stUserVideo.end_time: %s\n", createTime, stUserVideo.end_time);
ulReturn = MYSQL_UserVideo_Upt_EndTime(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceGetUserVideoIdBySipCallId(T_RceUCallCtxTable *ptUCC, long long *ptUserVideoId)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptUCC, ptUserVideoId);
UINT ulReturn = XPOC_ERR_SUCCESS;
H_User_Video_S stUserVideo;
memset(&stUserVideo, 0, sizeof(H_User_Video_S));
strcpy(stUserVideo.call_id, (Serv_VideoPri==ptUCC->tCallInfoS.enRcrdServType)?ptUCC->aucCallId:ptUCC->tCallInfoS.aucCceSipCallId);
ulReturn = MYSQL_UserVideo_Qry_Id_By_SipCallId(mysql_connect, &stUserVideo);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
*ptUserVideoId = stUserVideo.id;
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceAddVideoRecord2DB(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
char szFromUrl[STR_LEN128];
char szToUrl[STR_LEN128];
memset(szFromUrl, 0, STR_LEN128);
memset(szToUrl, 0, STR_LEN128);
if (Serv_VideoPri == stUCC.tCallInfoS.enRcrdServType
|| Serv_VideoPullPri == stUCC.tCallInfoS.enRcrdServType
|| Serv_VideoPushPri == stUCC.tCallInfoS.enRcrdServType
|| Serv_VideoTransPri == stUCC.tCallInfoS.enRcrdServType)
{
if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRcrdNum) == 0)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRelatNum) == 0)
{
memcpy(szToUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else
{
x_ErrorLog("Error Serv_AudioPri speak is not FAILED!!");
return XPOC_ERR_FAIL;
}
}
else if (Serv_VideoPushGrp == stUCC.tCallInfoS.enRcrdServType
|| Serv_VideoTransGrp == stUCC.tCallInfoS.enRcrdServType)
{
if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucOrigNum) == 0)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else
{
x_ErrorLog("Error Serv_AudioGroup speak is not FAILED!!");
return XPOC_ERR_FAIL;
}
}
else
{
x_ErrorLog("ptUCC->tCallInfoS.enRcrdServType[%d] is error for video.\n", stUCC.tCallInfoS.enRcrdServType);
return XPOC_ERR_FAIL;
}
x_InfoLog("RcrdServType[%d],fromurl[%s],tourl[%s].", stUCC.tCallInfoS.enRcrdServType, szFromUrl, szToUrl);
H_User_Video_Item_S stUserVideoItem;
memset(&stUserVideoItem, 0, sizeof(H_User_Video_Item_S));
memcpy(stUserVideoItem.company_no, stUCC.tCallInfoS.aucSpkNum, 8);
/* get h_user_Video.id */
ulReturn = rceGetUserVideoIdBySipCallId(&stUCC, &stUserVideoItem.user_video_no);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
strncpy(stUserVideoItem.user_no, stUCC.tCallInfoS.aucSpkNum, STR_LEN32);
strcpy(stUserVideoItem.call_id, (Serv_VideoPri==stUCC.tCallInfoS.enRcrdServType)?stUCC.aucCallId:stUCC.tCallInfoS.aucCceSipCallId);
strcpy(stUserVideoItem.start_time, ptMediaFd->aucRecordStartTime);
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVideoItem.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
strcpy(stUserVideoItem.from_video_url, szFromUrl);
strcpy(stUserVideoItem.to_video_url, szToUrl);
strcpy(stUserVideoItem.floor_url, "");
strcpy(stUserVideoItem.record_time, stUserVideoItem.start_time);
ULONGLONG dur = MP4GetDuration(ptMediaFd->pvMp4HFile) / 1000; // 录像时长,单位秒
UINT hour = dur / 3600;
UINT min = (dur - hour * 3600) / 60;
UINT sec = dur - hour * 3600 - min * 60;
char tmp[STR_LEN32] = {0};
sprintf(tmp, "%02d:%02d:%02d", hour, min, sec);
strcpy(stUserVideoItem.duration_time, tmp);
ulReturn = MYSQL_UserVideoItem_Add(mysql_connect, &stUserVideoItem);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceAddVoiceCallInfo2DB(UINT ulUCCId)
{
XPOC_TRACEFUNC_IN;
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
return XPOC_ERR_FAIL;
}
H_User_Voice_S stUserVoice;
memset(&stUserVoice, 0, sizeof(H_User_Voice_S));
strcpy(stUserVoice.call_id, stUCC.tCallInfoS.aucCceSipCallId);
ulReturn = MYSQL_UserVoice_Qry_Id_By_SipCallId(mysql_connect, &stUserVoice);
if(XPOC_ERR_SUCCESS == ulReturn)
{
return ulReturn;/* 已经存在了则不需要再ADD */
}
memcpy(stUserVoice.company_no, stUCC.tCallInfoS.aucSpkNum, 8);
x_DebugLog("aucSpkNum[%s],aucCompanyNo[%s].", stUCC.tCallInfoS.aucSpkNum, stUserVoice.company_no);
char biz_type[STR_LEN16];
memset(biz_type, 0, STR_LEN16);
ulReturn = rceGetBizTypeByServType(stUCC.tCallInfoS.enRcrdServType, biz_type);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
strcpy(stUserVoice.biz_type, biz_type);
if(Serv_AudioRcrdPri == stUCC.tCallInfoS.enServType
|| Serv_VideoRcrdPri == stUCC.tCallInfoS.enServType)
{
strncpy(stUserVoice.from_user_no, stUCC.tCallInfoS.aucRcrdNum, STR_LEN32);
strncpy(stUserVoice.to_user_no, stUCC.tCallInfoS.aucRelatNum, STR_LEN32);
}
else if(Serv_AudioRcrdGrp == stUCC.tCallInfoS.enServType
|| Serv_VideoRcrdGrp == stUCC.tCallInfoS.enServType)
{
strncpy(stUserVoice.from_user_no, stUCC.tCallInfoS.aucOrigNum, STR_LEN32);
strncpy(stUserVoice.to_user_no, stUCC.tCallInfoS.aucRcrdGrpNum, STR_LEN32);
}
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVoice.start_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
strftime(stUserVoice.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVoice_Add(mysql_connect, &stUserVoice);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceUptUserVoiceEndTime2DB(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
H_User_Voice_S stUserVoice;
memset(&stUserVoice, 0, sizeof(H_User_Voice_S));
strcpy(stUserVoice.call_id, stUCC.tCallInfoS.aucCceSipCallId);
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVoice.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
ulReturn = MYSQL_UserVoice_Upt_EndTime(mysql_connect, &stUserVoice);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceGetUserVoiceIdBySipCallId(T_RceUCallCtxTable *ptUCC, long long *ptUserVoiceId)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptUCC, ptUserVoiceId);
UINT ulReturn = XPOC_ERR_SUCCESS;
H_User_Voice_S stUserVoice;
memset(&stUserVoice, 0, sizeof(H_User_Voice_S));
strcpy(stUserVoice.call_id, ptUCC->tCallInfoS.aucCceSipCallId);
ulReturn = MYSQL_UserVoice_Qry_Id_By_SipCallId(mysql_connect, &stUserVoice);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
*ptUserVoiceId = stUserVoice.id;
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT rceAddVoiceRecord2DB(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
UINT ulReturn = XPOC_ERR_SUCCESS;
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
char szFromUrl[STR_LEN128];
char szToUrl[STR_LEN128];
memset(szFromUrl, 0, STR_LEN128);
memset(szToUrl, 0, STR_LEN128);
if (Serv_AudioPri == stUCC.tCallInfoS.enRcrdServType
|| Serv_VideoPri == stUCC.tCallInfoS.enRcrdServType)
{
if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRcrdNum) == 0)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRelatNum) == 0)
{
memcpy(szToUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else
{
x_ErrorLog("Error Serv_AudioPri speak is not FAILED!!");
return XPOC_ERR_FAIL;
}
}
else if (Serv_AudioHalfPri == stUCC.tCallInfoS.enRcrdServType)
{
if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRcrdNum) == 0)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRelatNum) == 0)
{
memcpy(szToUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else
{
x_ErrorLog("Error Serv_AudioPri speak is not FAILED!!");
return XPOC_ERR_FAIL;
}
}
else if (Serv_AudioGroup == stUCC.tCallInfoS.enRcrdServType)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
/*if (strcmp(stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.aucRcrdNum) == 0)
{
memcpy(szFromUrl, ptMediaFd->szRecordFileName, MIN(strlen(ptMediaFd->szRecordFileName), STR_LEN128));
}
else
{
x_ErrorLog("Error Serv_AudioGroup speak is not FAILED!!");
return XPOC_ERR_FAIL;
}*/
}
else
{
x_ErrorLog("ptUCC->tCallInfoS.enRcrdServType[%d] is error for voice.\n", stUCC.tCallInfoS.enRcrdServType);
return XPOC_ERR_FAIL;
}
x_InfoLog("UCCId[%d],aucSpkNum[%s],RcrdServType[%d],fromurl[%s],tourl[%s].", ptMediaFd->ulUCCId,
stUCC.tCallInfoS.aucSpkNum, stUCC.tCallInfoS.enRcrdServType, szFromUrl, szToUrl);
H_User_Voice_Item_S stUserVoiceItem;
memset(&stUserVoiceItem, 0, sizeof(H_User_Voice_Item_S));
memcpy(stUserVoiceItem.company_no, stUCC.tCallInfoS.aucSpkNum, 8);
/* get h_user_voice.id */
ulReturn = rceGetUserVoiceIdBySipCallId(&stUCC, &stUserVoiceItem.user_voice_no);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
strncpy(stUserVoiceItem.user_no, stUCC.tCallInfoS.aucSpkNum, STR_LEN32);
strcpy(stUserVoiceItem.call_id, stUCC.tCallInfoS.aucCceSipCallId);
strcpy(stUserVoiceItem.start_time, ptMediaFd->aucRecordStartTime);
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
struct tm *tmInfo = localtime(&now_sec);
strftime(stUserVoiceItem.end_time, 20, "%Y-%m-%d %H:%M:%S", tmInfo);
strcpy(stUserVoiceItem.from_voice_url, szFromUrl);
strcpy(stUserVoiceItem.to_voice_url, szToUrl);
strcpy(stUserVoiceItem.floor_url, "");
strcpy(stUserVoiceItem.record_time, stUserVoiceItem.start_time);
ulReturn = MYSQL_UserVoiceItem_Add(mysql_connect, &stUserVoiceItem);
if(XPOC_ERR_SUCCESS != ulReturn)
{
return ulReturn;
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
#if 0
#endif
UINT CreateRecordFile(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
//(void)CloseRecordFile(ptMediaFd);
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
UINT ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
// /* 在存储报文到文件的时候,增加检查当前报文的ssrc与ucc.ssrc是否一致. */
// UINT ulRtpSsrc = 0;
// UINT ulRtpSsrcLen = 0;
// if (MEDIA_AUDIO == ptMediaFd->iRceMediaType)
// {
// Byte_2_U32(ptNode->PktBuf+8, ulRtpSsrc, ulRtpSsrcLen);
// }
// else if (MEDIA_VIDEO == ptMediaFd->iRceMediaType)
// {
// Byte_2_U32(ptNode->PktBuf+10+7, ulRtpSsrc, ulRtpSsrcLen);
// }
// /* rtp.ssrc 与ucc.mediainfo.ssrc 不一致,说明当前的rtp不是该ucc的报文, 丢弃. */
// x_InfoLog("ucc.ssrc[%d(0x%x)],rtp.ssrc[%d(0x%x)].",
// stUCC.stMediaInfo.ulSsrc, stUCC.stMediaInfo.ulSsrc, ulRtpSsrc, ulRtpSsrc);
// if((0 != stUCC.stMediaInfo.ulSsrc) && (ulRtpSsrc != stUCC.stMediaInfo.ulSsrc))
// {
// return XPOC_ERR_FAIL;
// }
///
//int now_ms = 0;
struct timeval tv;
//struct tm now_tm;
time_t now_sec;
gettimeofday(&tv, NULL);
now_sec = tv.tv_sec;
//now_ms = tv.tv_usec/1000;
///
MediaFdS oldMedFds = *ptMediaFd;
char createTime[STR_LEN512];
time(&(ptMediaFd->tmRecordStartTime));
memset(ptMediaFd->szRecordFileName, 0, STR_LEN512);
memset(createTime, 0, STR_LEN32);
strftime(createTime, STR_LEN32, "%Y-%m-%d-%H-%M-%S", localtime(&now_sec));
strcpy(ptMediaFd->aucRecordStartTime, createTime);
(void)generateRecordFileName(ptMediaFd, &stUCC.tCallInfoS, createTime);
/// avoid open the same file
if (MEDIA_AUDIO == ptMediaFd->iRceMediaType)
{
if(oldMedFds.fd_record != -1 && !strcmp(oldMedFds.szRecordFileName, ptMediaFd->szRecordFileName))
{
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
else
{
(void)CloseRecordFile(&oldMedFds);
}
}
// upd starttime endtime
rceUptUserVideoStartTime2DB_2(ptMediaFd, 0);
rceUptUserVideoEndTime2DB_2(ptMediaFd, 0);
// modify by lkf
char fleetIdFolder[STR_LEN10];
memset(fleetIdFolder, 0, STR_LEN10);
memcpy(fleetIdFolder, &stUCC.tCallInfoS.aucSpkNum, STR_LEN8); // modify by lkf, 获取8位集团号
char fleetPath[STR_LEN256]; // modify by lkf, 临时变量,检查是否存在子文件夹
memset(fleetPath, 0, STR_LEN256);
sprintf(fleetPath, "%s/%s", g_rceDir, fleetIdFolder);
if (access(fleetPath, 0) == -1) // 集团文件夹是否建立
{
mkdir(fleetPath, 0777); /* 如果不存在就用mkdir函数来创建 */
x_InfoLog("Make fleet dir:[%s].", fleetPath);
}
char dateFolder[STR_LEN16];
memset(dateFolder, 0, STR_LEN16);
memcpy(dateFolder, createTime, STR_LEN10); // modify by lkf, 获取年月日
char datePath[STR_LEN256]; // modify by lkf, 临时变量,检查是否存在子文件夹
memset(datePath, 0, STR_LEN256);
sprintf(datePath, "%s/%s", fleetPath, dateFolder);
if (access(datePath, 0) == -1)
{
mkdir(datePath, 0777);
x_InfoLog("Make date dir:[%s].", datePath);
}
/* 每次生成新文件时才确定文件名 */
char tempPath[STR_LEN512];
memset(tempPath, 0, STR_LEN512);
sprintf(tempPath, "%s/%s", datePath, ptMediaFd->szRecordFileName); // modify by lkf
if (MEDIA_AUDIO == ptMediaFd->iRceMediaType) //todo: why???
{
//printf("--------ptMediaFd->tcpFdIdx: %d\n", ptMediaFd->tcpFdIdx);
// use video fd
if(ptMediaFd->tcpFdIdx != -1)
{
ptMediaFd->ulSsrc = 0;
ptMediaFd->waitVideoSPS = 1;
ptMediaFd->iRceRecordState = Record_WORK;
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
// open file
if ((ptMediaFd->fd_record = open(tempPath, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE)) < 0)
{
x_WarnLog("open record afile failed.errno [%d]-[%s]", errno, strerror(errno));
ptMediaFd->fd_record = -1;
return XPOC_ERR_FAIL;
}
x_InfoLog("Create audio file : %s", tempPath);
if (AUDIOTYPE_AMR_NB == audio_record_type)
{
char header[AMR_NB_HEADER_LEN] = {0};
if (-1 == write(ptMediaFd->fd_record, header, AMR_NB_HEADER_LEN))
{
return XPOC_ERR_FAIL;
}
}
else if (AUDIOTYPE_AMR_WB == audio_record_type)
{
char header[AMR_WB_HEADER_LEN] = {0};
if (-1 == write(ptMediaFd->fd_record, header, AMR_WB_HEADER_LEN))
{
return XPOC_ERR_FAIL;
}
}
else if (AUDIOTYPE_G711 == audio_record_type)
{
char header[56];
memset(header, 0, 56);
if (-1 == write(ptMediaFd->fd_record, header, 56))
{
return XPOC_ERR_FAIL;
}
}
else
{
return XPOC_ERR_FAIL;
}
}
else if(MEDIA_VIDEO == ptMediaFd->iRceMediaType)
{
// open file
ptMediaFd->pvMp4HFile = MP4Create(tempPath);
if (ptMediaFd->pvMp4HFile == MP4_INVALID_FILE_HANDLE)
{
x_WarnLog("open record vfile failed.\n");
ptMediaFd->pvMp4HFile = NULL;
ptMediaFd->ulMp4Vid = 0;
ptMediaFd->ulMp4Aud = 0;
ptMediaFd->waitVideoSPS = 0;
ptMediaFd->ulAudRemainDura = 0;
return XPOC_ERR_FAIL;
}
//printf("..ptMediaFd->pvMp4HFile:%p\n", ptMediaFd->pvMp4HFile);
x_InfoLog("Create mp4 file : %s", tempPath);
//
ptMediaFd->pFrameBuf = (UCHAR*)malloc(800*1024);
ptMediaFd->ulFrameLen = 0;
ptMediaFd->ulLastVRtpTs = 0;
ptMediaFd->ulLastARtpTs = 0;
ptMediaFd->ulAvgVRtpTs = 0;
ptMediaFd->tmLastWriteSmpTime = GetCurrMsTime();
}
ptMediaFd->ulSsrc = 0;
ptMediaFd->waitVideoSPS = 1;
ptMediaFd->iRceRecordState = Record_WORK;
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT CloseRecordFile(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
ptMediaFd->iRceRecordState = Record_IDLE;
if(ptMediaFd->fd_record != -1 && ptMediaFd->iRceMediaType != 0)
x_InfoLog("mediaFd: fd_record[%d],mediaType[%d].", ptMediaFd->fd_record, ptMediaFd->iRceMediaType);
///
ptMediaFd->tcpFdIdx = -1;
if (MEDIA_AUDIO == ptMediaFd->iRceMediaType) /*音频 */
{
if(-1 == ptMediaFd->fd_record) /* 如果本来就没有文件, do nothing. */
{
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
int file_len = lseek(ptMediaFd->fd_record, 0, SEEK_END);/* 返回值为文件大小+offset */
lseek(ptMediaFd->fd_record, 0, SEEK_SET); /* 重定位文件开始 */
if (AUDIOTYPE_AMR_NB == audio_record_type)
{
AddAMRNBFileHeader(ptMediaFd->fd_record, file_len);
}
else if (AUDIOTYPE_AMR_WB == audio_record_type)
{
AddAMRFileHeader(ptMediaFd->fd_record, file_len);
}
else if (AUDIOTYPE_G711 == audio_record_type)
{
AddWaveFileHeader(ptMediaFd->fd_record, file_len);
}
// close file
close(ptMediaFd->fd_record);
ptMediaFd->fd_record = -1;
// update db
(void)rceAddVoiceRecord2DB(ptMediaFd);
/* 关闭文件说明是写完一个文件, 需要把record的当前结束时间写道h_user_voice中 */
(void)rceUptUserVoiceEndTime2DB(ptMediaFd);
}
else if (MEDIA_VIDEO == ptMediaFd->iRceMediaType)
{
if(NULL == ptMediaFd->pvMp4HFile) /* 如果本来就没有文件, do nothing. */
{
return XPOC_ERR_SUCCESS;
}
// close file
//printf("ptMediaFd->pvMp4HFile:%p\n", ptMediaFd->pvMp4HFile);
ULONGLONG dur = MP4GetDuration(ptMediaFd->pvMp4HFile);
if(ptMediaFd->ulMp4Aud != MP4_INVALID_TRACK_ID) {
ULONGLONG adur = MP4GetTrackDuration(ptMediaFd->pvMp4HFile, ptMediaFd->ulMp4Aud);
if(adur+500 < dur) { // 500 ms
WriteSilentDataToMp4File(ptMediaFd, dur-adur);
}
}
//printf("................dur: %lu\n", dur);
MP4Close(ptMediaFd->pvMp4HFile);
ptMediaFd->pvMp4HFile = NULL;
ptMediaFd->ulMp4Vid = 0;
ptMediaFd->ulMp4Aud = 0;
//
if(ptMediaFd->pFrameBuf)
{
free(ptMediaFd->pFrameBuf);
ptMediaFd->pFrameBuf = NULL;
}
ptMediaFd->ulFrameLen = 0;
ptMediaFd->ulLastVRtpTs = 0;
ptMediaFd->ulAvgVRtpTs = 0;
ptMediaFd->tmLastWriteSmpTime = 0;
// update db
(void)rceAddVideoRecord2DB(ptMediaFd);
/* 关闭文件说明是写完一个文件, 需要把record的当前结束时间写道h_user_video中 */
//(void)rceUptUserVideoEndTime2DB(ptMediaFd);
(void)rceUptUserVideoEndTime2DB_2(ptMediaFd, dur/1000);
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
UINT WriteG711AudioDataToFile(int fd_record, char*pdata, int len)
{
char AudioData_PCM_sample[PCM_SAMPLE_LEN];
memset(AudioData_PCM_sample, 0, PCM_SAMPLE_LEN);
int voicelen = g711_decode(AudioData_PCM_sample, (unsigned char*)pdata, len);
if (-1 != write(fd_record, AudioData_PCM_sample, voicelen))
{
return XPOC_ERR_SUCCESS;
}
return XPOC_ERR_FAIL;
}
//AMR-WB 帧格式长度
static const int amr_frame_sizes[] = { 17, 23, 32, 36, 40, 46, 50, 58, 60, 5 };
#define MAX_FRAME_TYPE 9
int amrwb_read_bytes(int nMode)
{
if ((nMode >= 0) && (nMode < MAX_FRAME_TYPE))
{
return amr_frame_sizes[nMode];
}
return 0;
}
UINT WriteAMRWBAudioDataToFile(int fd_record, char*pdata, int len)
{
int FT = ((pdata[0] & 0x07) << 1) | ((pdata[1] & 0x80) >> 7);
int nAmrSize = amrwb_read_bytes(FT);
if (len != nAmrSize + 1 ) return XPOC_ERR_FAIL;
int i = 0;
//移位
//添加文件帧头,位分布如下,其中P固定为0, Q置为1
/* | 0 | 1 2 3 4 | 5 6 7 |
| P | FT | Q P P | */
pdata[0] = ((FT & 0X0F) << 3) | 0x04;
for (i = 1; i < nAmrSize; i++) // AMR rtp负载格式转换成文件格式
{
pdata[i] = ((pdata[i] << 2) & 0xFC) | ((pdata[i + 1] >> 6) & 0x03);
}
pdata[nAmrSize] = (pdata[nAmrSize] << 2) & 0xFC;
if (-1 != write(fd_record, pdata, nAmrSize+1))
{
return XPOC_ERR_SUCCESS;
}
return XPOC_ERR_FAIL;
}
//AMR-NB 帧格式长度
static const int amr_nb_frame_sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
static const int amrnb_framelenbits[9] = { 95, 103, 118, 134, 148, 159, 204, 244, 39 };
int amrnb_read_bytes(int nMode)
{
if ((nMode >= 0) && (nMode < MAX_FRAME_TYPE))
{
return amr_nb_frame_sizes[nMode];
}
return 0;
}
UINT WriteAMRNBAudioDataToFile(int fd_record, char*pdata, int len)
{
int FT = ((pdata[0] & 0x07) << 1) | ((pdata[1] & 0x80) >> 7);
int nAmrSize = amrnb_read_bytes(FT);
if (len != nAmrSize + 1 ) return XPOC_ERR_FAIL;
int i = 0;
//移位
//添加文件帧头,位分布如下,其中P固定为0, Q置为1
/* | 0 | 1 2 3 4 | 5 6 7 |
| P | FT | Q P P | */
pdata[0] = ((FT & 0X0F) << 3) | 0x04;
for (i = 1; i < nAmrSize; i++) // AMR rtp负载格式转换成文件格式
{
pdata[i] = ((pdata[i] << 2) & 0xFC) | ((pdata[i + 1] >> 6) & 0x03);
}
pdata[nAmrSize] = (pdata[nAmrSize] << 2) & 0xFC;
if (-1 != write(fd_record, pdata, nAmrSize+1))
{
return XPOC_ERR_SUCCESS;
}
return XPOC_ERR_FAIL;
}
UCHAR unpackByteField(UCHAR *pBitString, int* pBitPosition, int byBitLength)
{
int iByteIndex; /*特定字段所在的字节位置*/
int iBitIndex; /*该字段在字节中的比特起始位*/
unsigned short wTempWord = 0;
if(NULL == pBitString || byBitLength > 8)
{
return 0;
}
iByteIndex = *pBitPosition / 8;
iBitIndex = *pBitPosition % 8;
*pBitPosition += byBitLength;
wTempWord = *(pBitString + iByteIndex);
wTempWord <<= 8;
wTempWord += *(pBitString + iByteIndex + 1);
wTempWord <<= iBitIndex;
wTempWord >>= (16 - byBitLength);
return (UCHAR)(wTempWord);
}
#define AMR_FRAME_QUALITY_BAD 0
#define AMR_FRAME_QUALITY_GOOD 1
#define AMR_TOC_FRAME_QUALITY_MASK 0x01
#define VOICE_FRAME_PACK_MAX 12 //最大12帧数据,实际上只是用了10帧
// add by shm,多帧传输格式数据
/* rfc3267中多帧样例:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CMR=1 |1| FT=0 |1|1| FT=9 |1|1| FT=15 |1|0| FT=1 |1|d(0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| d(131)|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|g(0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| g(39)|h(0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| h(176)|P|P|P|P|P|P|P|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/* typedef struct
{
int nFT;
int nFrameSize;
}T_AmrNbMf; */
#if 0
UINT WriteAMRNBMFAudioDataToFile(int fd_record, UCHAR* pdata, int len)
{
if (pdata == NULL)
return XPOC_ERR_FAIL;
UCHAR acTOC[VOICE_FRAME_PACK_MAX] = {0};
/* 解码偏移量 */
int wPos = 0;
int wBitPosition = 0;
//get CMR
unpackByteField(pdata, &wBitPosition, 4);
//判断尾帧
int tocPos = wBitPosition;
int nFrameCount = 0;
UCHAR bHasNextFT = 1; // 是否有下一个ft头
while (bHasNextFT)
{
acTOC[nFrameCount] = unpackByteField(pdata, &wBitPosition, 6);
bHasNextFT = (UCHAR)(acTOC[nFrameCount] >> 5);
if (++nFrameCount >= VOICE_FRAME_PACK_MAX)
{
bHasNextFT = 0;
}
}
for (int i = 0; i < nFrameCount; i++)
{
switch (acTOC[i] & AMR_TOC_FRAME_QUALITY_MASK)
{
case AMR_FRAME_QUALITY_BAD: //bad frame ingnore
x_WarnLog("bit align Decode [%d] frame error, TOC [%d]", i, acTOC[i]);
break;
case AMR_FRAME_QUALITY_GOOD: // valid,get the frame bits
int nFT = (acTOC[i] >> 1) & 0x0f;
int nFrameLen = amr_nb_frame_sizes[nFT];
char acFrame[32] = {0}; // 最多32个字节, nFrameLen 最大为31
acFrame[0] = ((nFT & 0X0F) << 3) | 0x04;
for (int k = 0; k < nFrameLen; k++)
{
if (nFrameLen - 1 == k)
{
int nLastbitOff = amrnb_framelenbits[nFT] % 8;
// 最后一个字节只有nLastbitOff位,这里要特别注意
acFrame[k + 1] = unpackByteField(pdata, &wBitPosition, nLastbitOff);
acFrame[k + 1] = acFrame[k + 1] << (8 - nLastbitOff);
}
else
{ // 其它bit都按字节进行填充
acFrame[k + 1] = unpackByteField(pdata, &wBitPosition, 8);
}
}
if (-1 == write(fd_record, acFrame, nFrameLen + 1))
{
x_ErrorLog("Write a amr frame failed.");
}
break;
}
}
// int nLen = (wBitPosition + 7) / 8;
// if (nLen != len)
// {
// amrForDecode.bUsedNum = 0;
// x_InfoLog("payload data size is invalid [%d], bitOff [%d]", len, wBitPosition);
// return XPOC_ERR_FAIL;
// }
return XPOC_ERR_SUCCESS;
}
#endif
UINT tokAMRNBMFAudioData(UCHAR* pdata, int len,
UCHAR outdat[VOICE_FRAME_PACK_MAX][32],
UCHAR outlen[VOICE_FRAME_PACK_MAX])
{
UCHAR acTOC[VOICE_FRAME_PACK_MAX] = {0};
/* 解码偏移量 */
int wPos = 0;
int wBitPosition = 0;
//get CMR
unpackByteField(pdata, &wBitPosition, 4);
//判断尾帧
int tocPos = wBitPosition;
int nFrameCount = 0;
UCHAR bHasNextFT = 1; // 是否有下一个ft头
while (bHasNextFT)
{
acTOC[nFrameCount] = unpackByteField(pdata, &wBitPosition, 6);
bHasNextFT = (UCHAR)(acTOC[nFrameCount] >> 5);
if (++nFrameCount >= VOICE_FRAME_PACK_MAX)
{
bHasNextFT = 0;
}
}
for (int i = 0; i < nFrameCount; i++)
{
outlen[i] = 0;
switch (acTOC[i] & AMR_TOC_FRAME_QUALITY_MASK)
{
case AMR_FRAME_QUALITY_BAD: //bad frame ingnore
//printf("bad frame....%d\n", (acTOC[i] >> 1) & 0x0f);
x_WarnLog("bit align Decode [%d] frame error, TOC [%d]", i, acTOC[i]);
break;
case AMR_FRAME_QUALITY_GOOD: // valid,get the frame bits
int nFT = (acTOC[i] >> 1) & 0x0f;
int nFrameLen = amr_nb_frame_sizes[nFT];
memset(outdat[i], 0, 32);
outdat[i][0] = ((nFT & 0X0F) << 3) | 0x04;
//if(nFT >= 8 && nFT < 15)
// printf(".................nFT: %d\n", nFT);
for (int k = 0; k < nFrameLen; k++)
{
if (nFrameLen - 1 == k)
{
int nLastbitOff = amrnb_framelenbits[nFT] % 8;
// 最后一个字节只有nLastbitOff位,这里要特别注意
outdat[i][k + 1] = unpackByteField(pdata, &wBitPosition, nLastbitOff);
outdat[i][k + 1] = outdat[i][k + 1] << (8 - nLastbitOff);
}
else
{ // 其它bit都按字节进行填充
outdat[i][k + 1] = unpackByteField(pdata, &wBitPosition, 8);
}
}
if (nFrameLen > 0)
outlen[i] = nFrameLen+1;
///
break;
}
}
return nFrameCount;
}
UINT WriteAMRNBMFAudioDataToFile(int fd_record, UCHAR* pdata, int len)
{
if (pdata == NULL)
return XPOC_ERR_FAIL;
UCHAR frames[VOICE_FRAME_PACK_MAX][32] = {0};
UCHAR frameLen[VOICE_FRAME_PACK_MAX] = {0};
UINT frameCnt = 0;
frameCnt = tokAMRNBMFAudioData(pdata, len, frames, frameLen);
UINT n = 0;
for(; n < frameCnt; n++) {
if (-1 == write(fd_record, frames[n], frameLen[n]))
{
x_ErrorLog("Write a amr frame failed.");
return XPOC_ERR_FAIL;
}
}
return XPOC_ERR_SUCCESS;
}
static UINT Ue(UCHAR *pBuff, UINT nLen, UINT *pStartBit)
{
//计算0bit的个数
UINT nZeroNum = 0;
while ((*pStartBit) < nLen * 8)
{
if (pBuff[(*pStartBit) / 8] & (0x80 >> ((*pStartBit) % 8))) //&:按位与,%取余
{
break;
}
nZeroNum++;
(*pStartBit)++;
}
(*pStartBit)++;
//计算结果
UINT ret = 0;
for (UINT i=0; i<nZeroNum; i++)
{
ret <<= 1;
if (pBuff[(*pStartBit) / 8] & (0x80 >> ((*pStartBit) % 8)))
{
ret += 1;
}
(*pStartBit)++;
}
return (1 << nZeroNum) - 1 + ret;
}
static int Se(UCHAR *pBuff, UINT nLen, UINT *pStartBit)
{
int UeVal=Ue(pBuff,nLen,pStartBit);
double k=UeVal;
int nValue=ceil(k/2);
if (UeVal % 2==0)
nValue=-nValue;
return nValue;
}
static UINT u(UINT BitCount,UCHAR *buf,UINT *pStartBit)
{
UINT ret = 0;
for (UINT i=0; i<BitCount; i++)
{
ret <<= 1;
if (buf[(*pStartBit) / 8] & (0x80 >> ((*pStartBit) % 8)))
{
ret += 1;
}
(*pStartBit)++;
}
return ret;
}
static void DecodeH264SPS(UCHAR *buf, UINT nLen, int *pWid, int *pHei)
{
UINT StartBit = 8;
int profile_idc=u(8,buf,&StartBit);
int constraint_set0_flag=u(1,buf,&StartBit);//(buf[1] & 0x80)>>7;
int constraint_set1_flag=u(1,buf,&StartBit);//(buf[1] & 0x40)>>6;
int constraint_set2_flag=u(1,buf,&StartBit);//(buf[1] & 0x20)>>5;
int constraint_set3_flag=u(1,buf,&StartBit);//(buf[1] & 0x10)>>4;
int reserved_zero_4bits=u(4,buf,&StartBit);
int level_idc=u(8,buf,&StartBit);
int seq_parameter_set_id=Ue(buf,nLen,&StartBit);
if( profile_idc == 100 || profile_idc == 110 ||
profile_idc == 122 || profile_idc == 144 )
{
int chroma_format_idc=Ue(buf,nLen,&StartBit);
if( chroma_format_idc == 3 )
int residual_colour_transform_flag=u(1,buf,&StartBit);
int bit_depth_luma_minus8=Ue(buf,nLen,&StartBit);
int bit_depth_chroma_minus8=Ue(buf,nLen,&StartBit);
int qpprime_y_zero_transform_bypass_flag=u(1,buf,&StartBit);
int seq_scaling_matrix_present_flag=u(1,buf,&StartBit);
int seq_scaling_list_present_flag[8];
if( seq_scaling_matrix_present_flag )
{
for( int i = 0; i < 8; i++ ) {
seq_scaling_list_present_flag[i]=u(1,buf,&StartBit);
}
}
}
int log2_max_frame_num_minus4=Ue(buf,nLen,&StartBit);
int pic_order_cnt_type=Ue(buf,nLen,&StartBit);
if( pic_order_cnt_type == 0 )
Ue(buf,nLen,&StartBit);
else if( pic_order_cnt_type == 1 )
{
int delta_pic_order_always_zero_flag=u(1,buf,&StartBit);
int offset_for_non_ref_pic=Se(buf,nLen,&StartBit);
int offset_for_top_to_bottom_field=Se(buf,nLen,&StartBit);
int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,&StartBit);
for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
Se(buf,nLen,&StartBit);
}
int num_ref_frames=Ue(buf,nLen,&StartBit);
int gaps_in_frame_num_value_allowed_flag=u(1,buf,&StartBit);
int pic_width_in_mbs_minus1=Ue(buf,nLen,&StartBit);
int pic_height_in_map_units_minus1=Ue(buf,nLen,&StartBit);
if(pWid && pHei)
{
*pWid=(pic_width_in_mbs_minus1+1)*16;
*pHei=(pic_height_in_map_units_minus1+1)*16;
}
}
UINT SetAddMp4VidTrack(void *hFile, UCHAR *pSps, UINT len)
{
if(hFile && pSps)
{
int w = 0, h = 0;
DecodeH264SPS(pSps, len, &w, &h);
//printf("w: %d, h: %d\n", w, h);
//printf(".........MP4AddH264VideoTrack..........\n");
const UINT ulTimeScale = 1000;
//MP4SetTimeScale(hFile, 90000);
MP4SetTimeScale(hFile, ulTimeScale);
UINT trackId = MP4AddH264VideoTrack(hFile, ulTimeScale, MP4_INVALID_DURATION, // MP4_INVALID_DURATION
w, h, pSps[1], pSps[2], pSps[3], 3); // 4 bytes length before each NAL unit
if (trackId == MP4_INVALID_TRACK_ID)
{
//printf("add video track failed.\n");
x_InfoLog("add video track failed.\n");
}
return trackId;
}
return MP4_INVALID_TRACK_ID;
}
UINT SetAddMp4AudTrack(void *hFile, char type)
{
if(hFile)
{
UINT trackId = MP4_INVALID_TRACK_ID;
if(AUDIOTYPE_AMR_NB == type)
{
trackId = MP4AddAmrAudioTrack(hFile, 8000, 0, 0, 1, FALSE);
}
else if(AUDIOTYPE_AMR_WB == type)
{
trackId = MP4AddAmrAudioTrack(hFile, 16000, 0, 0, 1, TRUE);
}
if (trackId == MP4_INVALID_TRACK_ID)
{
//printf("add audio track failed.\n");
x_InfoLog("add audio track failed.\n");
}
return trackId;
}
return MP4_INVALID_TRACK_ID;
}
void SetMp4VidAvcCfg(void *hFile, UINT trackId, AvcCfg *pAvcCfg)
{
// set metadata
MP4SetVideoProfileLevel(hFile, 0x7f);
const int hdrLen = (pAvcCfg->ucSps[0]&0x10)?RTP_HEADER_LEN+RTP_HEADER_EXT_LEN:RTP_HEADER_LEN;
MP4AddH264SequenceParameterSet(hFile, trackId, pAvcCfg->ucSps+hdrLen, pAvcCfg->ulSpsLen-hdrLen);
MP4AddH264PictureParameterSet(hFile, trackId, pAvcCfg->ucPps+hdrLen, pAvcCfg->ulPpsLen-hdrLen);
}
UINT CheckNeedVideoSPS(char waitVideoSPS, UCHAR *pdata, int len, MediaFdS *pMediaFd)
{
if (waitVideoSPS != 1) return XPOC_ERR_SUCCESS;
if (!pMediaFd) return XPOC_ERR_FAIL;
const int hdrLen = (pdata[0]&0x10)?RTP_HEADER_LEN+RTP_HEADER_EXT_LEN:RTP_HEADER_LEN;
unsigned char * src = (unsigned char*)pdata + hdrLen;
unsigned char head1 = *src; // 获取第一个字节
unsigned char nal = head1 & 0x1f; // 获取FU indicator的类型域,
//printf(".%llu........nal: %d..........marker: %d.\n", GetCurrMsTime()/1000, nal, (pdata[1]&0x80)>>7);
if (nal == 7) // SPS
{//人为修改SPS的帧率,不然VLC播放录像会很快,码流是30 修改成9,计算方式是0x12 / 2
/*unsigned char ctmp = *(src + 18);
*(src + 18) = (ctmp & 0xF0) + 1;
ctmp = *(src + 19);
*(src + 19) = (ctmp & 0x0F) | ( 0x20);
return XPOC_ERR_SUCCESS;*/
//
if(pMediaFd->ulMp4Vid == MP4_INVALID_TRACK_ID)
{
pMediaFd->ulMp4Vid = SetAddMp4VidTrack(pMediaFd->pvMp4HFile, src, len-hdrLen);
if (pMediaFd->ulMp4Vid == MP4_INVALID_TRACK_ID)
{
return XPOC_ERR_FAIL;
}
}
//
//printf(".....enRcrdServType...%d ...ulMp4Aud...%d....\n", pMediaFd->enRcrdServType, pMediaFd->ulMp4Aud);
if(/*pMediaFd->enRcrdServType == Serv_VideoPri && */pMediaFd->ulMp4Aud == MP4_INVALID_TRACK_ID)
{
pMediaFd->ulMp4Aud = SetAddMp4AudTrack(pMediaFd->pvMp4HFile, audio_record_type);
if (pMediaFd->ulMp4Aud == MP4_INVALID_TRACK_ID)
{
return XPOC_ERR_FAIL;
}
}
//
pMediaFd->stAvcCfg.ulSpsLen = len;
memcpy(pMediaFd->stAvcCfg.ucSps, pdata, pMediaFd->stAvcCfg.ulSpsLen);
return XPOC_ERR_FAIL;
}
else if (nal == 8) // PPS
{
//
pMediaFd->stAvcCfg.ulPpsLen = len;
memcpy(pMediaFd->stAvcCfg.ucPps, pdata, pMediaFd->stAvcCfg.ulPpsLen);
return XPOC_ERR_FAIL;
}
else if (nal == 5 || nal == 6 || nal == 28) //
{
if(nal == 28)
{
if(pMediaFd->ulMp4Vid && ((src[1]&0x1f)==5 || (src[1]&0x1f)==6))
return XPOC_ERR_SUCCESS;
}
else
{
if(pMediaFd->ulMp4Vid)
return XPOC_ERR_SUCCESS;
}
}
return XPOC_ERR_FAIL;
}
UINT WriteVideoDataToFile(int fd_record, UCHAR *pdata, int len)
{
unsigned char *pBufOut = NULL;
int BufOutLen = 0;
if (XPOC_ERR_SUCCESS == UnpackRTPH264(pdata, len, &pBufOut, &BufOutLen))
{
if (-1 != write(fd_record, pBufOut, BufOutLen))
{
return XPOC_ERR_SUCCESS;
}
}
return XPOC_ERR_FAIL;
}
UINT WriteVideoDataToMp4File(MediaFdS *pMediaFd, UCHAR *pdata, int len)
{
unsigned char *pBufOut = NULL;
int BufOutLen = 0;
if(pMediaFd->pvMp4HFile && pMediaFd->ulMp4Vid)
{
UINT ulTs = 0;
UCHAR ucTsLen = 0;
Byte_2_U32(pdata+4, ulTs, ucTsLen);
const int hdrLen = (pdata[0]&0x10)?RTP_HEADER_LEN+RTP_HEADER_EXT_LEN:RTP_HEADER_LEN;
UCHAR tp = pdata[hdrLen]&0x1f;
//printf(".%llu...ulTs: %u...............%d......marker: %d.\n", GetCurrMsTime()/1000, ulTs, tp, (pdata[1]&0x80)>>7);
if (XPOC_ERR_SUCCESS == UnpackRTPH264(pdata, len, &pBufOut, &BufOutLen))
{
#if 0
// test
{
static FILE *fp = NULL;
if(!fp)
{
fp = fopen("tou1.h264", "wb");
char prc[4] = {0,0,0,1};
fwrite(prc, 1, 4, fp);
fwrite(pMediaFd->stAvcCfg.ucSps+RTP_HEADER_LEN, 1, pMediaFd->stAvcCfg.ulSpsLen-RTP_HEADER_LEN, fp);
fwrite(prc, 1, 4, fp);
fwrite(pMediaFd->stAvcCfg.ucPps+RTP_HEADER_LEN, 1, pMediaFd->stAvcCfg.ulPpsLen-RTP_HEADER_LEN, fp);
}
if(fp)
{
/
/*if(tp == 5 && (ulTs != pMediaFd->ulLastRtpTs))
{
char prc[4] = {0,0,0,1};
fwrite(prc, 1, 4, fp);
fwrite(pMediaFd->stAvcCfg.ucSps+RTP_HEADER_LEN, 1, pMediaFd->stAvcCfg.ulSpsLen-RTP_HEADER_LEN, fp);
fwrite(prc, 1, 4, fp);
fwrite(pMediaFd->stAvcCfg.ucPps+RTP_HEADER_LEN, 1, pMediaFd->stAvcCfg.ulPpsLen-RTP_HEADER_LEN, fp);
}*/
fwrite(pBufOut, 1, BufOutLen, fp);
}
}
#endif
#if 1
//printf("...ulTs: %u, ulLastVRtpTs: %u\n", ulTs, pMediaFd->ulLastVRtpTs);
if(ulTs != pMediaFd->ulLastVRtpTs && pMediaFd->ulLastVRtpTs)
{
//*((UINT*)pMediaFd->pFrameBuf) = htonl(pMediaFd->ulFrameLen-4);
if(*((int *)(pMediaFd->pFrameBuf)) == 0x01000000)
{
*((UINT*)pMediaFd->pFrameBuf) = htonl(pMediaFd->ulFrameLen-4);
}
time_t cur = GetCurrMsTime();
UINT dura = (cur-pMediaFd->tmLastWriteSmpTime);//*90;
///UINT dura = (ulTs-pMediaFd->ulLastVRtpTs)/90;
pMediaFd->tmLastWriteSmpTime = cur;
if(dura >= 1000) dura /= 2;
///dura = pMediaFd->ulAvgVRtpTs?(pMediaFd->ulAvgVRtpTs+dura)/2:dura;
UCHAR wTp = pMediaFd->pFrameBuf[4]&0x1f;
//printf("pMediaFd->ulFrameLen: %u, ulTs: %u, dura: %u, wTp: %d\n", pMediaFd->ulFrameLen, ulTs, dura, wTp);
pthread_rwlock_wrlock(&pMediaFd->mtxWrMp4); // added by shm
bool ret = MP4WriteSample(pMediaFd->pvMp4HFile, pMediaFd->ulMp4Vid, pMediaFd->pFrameBuf, pMediaFd->ulFrameLen, dura, 0, (wTp==7||wTp==6||wTp==5));
pthread_rwlock_unlock(&pMediaFd->mtxWrMp4); // added by shm
//printf("....ulTs: %u...dura: %u...0x%02x 0x%02x 0x%02x 0x%02x..........%d.\n", ulTs, dura, pMediaFd->pFrameBuf[2], pMediaFd->pFrameBuf[3], pMediaFd->pFrameBuf[4], pMediaFd->pFrameBuf[5], ret);
pMediaFd->ulFrameLen = 0;
/// fill null
if(pMediaFd->enRcrdServType != Serv_VideoPri) {
WriteSilentDataToMp4File(pMediaFd, dura+pMediaFd->ulAudRemainDura);
pMediaFd->ulAudRemainDura = (dura+pMediaFd->ulAudRemainDura)%20;
}
}
if(pMediaFd->pFrameBuf)
{
if(tp < 24)
*((UINT*)pBufOut) = htonl(BufOutLen-4);
memcpy(pMediaFd->pFrameBuf+pMediaFd->ulFrameLen, pBufOut, BufOutLen);
pMediaFd->ulFrameLen += BufOutLen;
}
#endif
//
pMediaFd->ulLastVRtpTs = ulTs;
return XPOC_ERR_SUCCESS;
}
}
return XPOC_ERR_FAIL;
}
UINT WriteSilentDataToMp4File(MediaFdS *pMediaFd, int dura)
{
if(pMediaFd->pvMp4HFile && pMediaFd->ulMp4Aud) {
UCHAR sdat[6] = { 0x44 };
int k = (dura)/20;
while(k)
{
pthread_rwlock_wrlock(&pMediaFd->mtxWrMp4); // added by shm
MP4WriteSample(pMediaFd->pvMp4HFile, pMediaFd->ulMp4Aud,
sdat, 6, 160, 0, TRUE);
pthread_rwlock_unlock(&pMediaFd->mtxWrMp4); // added by shm
usleep(1);
k--;
}
}
return XPOC_ERR_SUCCESS;
}
UINT WriteAudioDataToMp4File(MediaFdS *pMediaFd, UCHAR *pdata, int len, UINT ts)
{
if(pMediaFd->pvMp4HFile && pMediaFd->ulMp4Aud) {
UCHAR frames[VOICE_FRAME_PACK_MAX][32] = {0};
UCHAR frameLen[VOICE_FRAME_PACK_MAX] = {0};
UINT frameCnt = 0;
frameCnt = tokAMRNBMFAudioData(pdata, len, frames, frameLen);
UINT n = 0;
for(; n < frameCnt; n++) {
//printf("--%d-- ts %u, pMediaFd->ulLastARtpTs %u, -- %d\n", n, ts, pMediaFd->ulLastARtpTs, (ts-pMediaFd->ulLastARtpTs));
UINT dura = 160;
dura = (n==0&&pMediaFd->ulLastARtpTs)?(ts-pMediaFd->ulLastARtpTs):dura;
pthread_rwlock_wrlock(&pMediaFd->mtxWrMp4); // added by shm
bool ret = MP4WriteSample(pMediaFd->pvMp4HFile, pMediaFd->ulMp4Aud,
frames[n], frameLen[n], dura, 0, TRUE);
//bool ret = MP4WriteSample(pMediaFd->pvMp4HFile, pMediaFd->ulMp4Aud,
// frames[n], frameLen[n], 160, 0, TRUE);
pthread_rwlock_unlock(&pMediaFd->mtxWrMp4); // added by shm
if(!ret)
{
//printf("Write a amr frame to mp4 failed.\n");
x_ErrorLog("Write a amr frame to mp4 failed.");
return XPOC_ERR_FAIL;
}
pMediaFd->ulLastARtpTs = ts+160*n;
}
}
return XPOC_ERR_SUCCESS;
}
/* 5分钟生成一个新文件 */
UINT CreateNewRecordFileOrNot(MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptMediaFd);
if (Record_WORK == ptMediaFd->iRceRecordState)
{
time_t tmRecordEndTime;
time(&tmRecordEndTime);
time_t duration = tmRecordEndTime - ptMediaFd->tmRecordStartTime;
//x_InfoLog("Time[%lld--%lld],duration[%d].", ptMediaFd->tmRecordStartTime, tmRecordEndTime, duration);
// added by shm, annotated
// if(duration >= 300)
// {
// return CreateRecordFile(ptMediaFd);
// }
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_FAIL;
}
/* 收到floor消息,对于话权申请 create recordFile; 话权空闲 close recordFile. */
UINT HandleRecordFileForFloorMsg(PktNode_S *ptNode)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptNode);
//x_InfoLog("deal rtcp param for record.");
UCHAR *ptBuf = ptNode->PktBuf;
x_DebugLog("rtcp buf[%x %x %x %x %x %x %x %x].", ptBuf[0],ptBuf[1],ptBuf[2],ptBuf[3],ptBuf[4],ptBuf[5],ptBuf[6],ptBuf[7]);
x_DebugLog("rtcp buf8[%c %c %c %c].", ptBuf[8],ptBuf[9],ptBuf[10],ptBuf[11]);
x_DebugLog("rtcp buf8[%x %x %x %x].", ptBuf[8],ptBuf[9],ptBuf[10],ptBuf[11]);
MediaFdS *ptMediaFd = (MediaFdS*)ptNode->pNodeData;
if(NULL == ptMediaFd)
{
x_ErrorLog("node data null.\n");
return XPOC_ERR_FAIL;
}
x_DebugLog("ptMediaFd:UCCId[%d],mediatype[%d],grpspknum[%s],rcrdstate[%d],rcrdservtype[%d].",
ptMediaFd->ulUCCId, ptMediaFd->iRceMediaType, ptMediaFd->aucGroupSpkNum, ptMediaFd->iRceRecordState, ptMediaFd->enRcrdServType);
/* 收到话权创建文件时:
对于语音组呼, CCE--RCE之间只有一个录音通道, 在收到 floor_taken 时创建文件, spknum 从消息中解码得到. 所有的语音媒体都从该通道传给 RCE.
对于半双工语音单呼, CCE--RCE之间对主叫和被叫分别有一个录音通道, 在收到floor_granted时创建文件, spknum 为该通道对应的servid. 该用户发出的语音媒体都从该通道传给 RCE. */
if (strncmp((char*)(ptBuf + 8), "MCPT", 4) == 0) /* 音频话权 */
{
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
//获取音频通道
MediaFdS *ptRtpFd = &(ptGlbData->stUdpAddrInfo.udpRtpFdList[ptMediaFd->recordIdx]);
if((0x81 == ptBuf[0]) && (Serv_AudioHalfPri == ptMediaFd->enRcrdServType)) /* Floor Granted, 半双工单呼时创建文件 */
{
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
UINT ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
if(Record_IDLE == ptRtpFd->iRceRecordState)
{
memcpy(ptRtpFd->aucGroupSpkNum, stUCC.aucServId, strlen(stUCC.aucServId));
x_InfoLog("floor - caller [%s], spknum[%s].", stUCC.tCallInfoS.aucOrigNum, ptRtpFd->aucGroupSpkNum);
CreateRecordFile(ptRtpFd);
if(ptRtpFd->ubFirstProc) ptRtpFd->ubFirstProc = FALSE;
//printf("CreateRecordFile: %s\n", ptRtpFd->szRecordFileName);
}
}
else if((0x82 == ptBuf[0]) && (Serv_AudioGroup == ptMediaFd->enRcrdServType))/* Floor Taken, groupcall时创建文件 */
{
UCHAR len = *(ptBuf + 13);
memset(ptRtpFd->aucGroupSpkNum, 0, STR_LEN32);
memcpy(ptRtpFd->aucGroupSpkNum, ptBuf + 14, MIN(len, STR_LEN32));
//避免迟后接入产生两个文件 add by lxh 20210414
if (Record_IDLE == ptRtpFd->iRceRecordState)
{
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
UINT ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
x_InfoLog("floor - grp [%s], Spknum[%s].", stUCC.tCallInfoS.aucRcrdGrpNum, ptRtpFd->aucGroupSpkNum);
strcpy(stUCC.tCallInfoS.aucSpkNum, ptRtpFd->aucGroupSpkNum);
ulReturn = XRceUCallCtxOpr(XDB_OPR_MOD, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
CreateRecordFile(ptRtpFd);
if(ptRtpFd->ubFirstProc) ptRtpFd->ubFirstProc = FALSE;
}
}
else if(ptBuf[0] == 0x83)//Floor Deny //申请话权拒绝
{
}
else if(ptBuf[0] == 0x85)//Floor Idle//空闲
{
CloseRecordFile(ptRtpFd);
}
else if (ptBuf[0] == 0x86)//Floor Revoke
{
}
}
else if (strncmp((char*)(ptBuf + 8), "MCV0", 4) == 0)//视频话权
{
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
#if 0
#endif
UINT rceDpDispatchPkt(PktNode_S *ptNode)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_ONE_PARA(ptNode);
UINT ulReturn = XPOC_ERR_SUCCESS;
MediaFdS *ptMediaFd = (MediaFdS*)ptNode->pNodeData;
if(NULL == ptMediaFd)
{
x_ErrorLog("node data null.\n");
return XPOC_ERR_FAIL;
}
// x_DebugLog("mediaFd:usedFg[%d],recordIdx[%d],usPort[%d],fdType[%d],iSocketFd[%d],ulUCCId[%d],rtpPort[%d],rtcpPort[%d].",
// ptMediaFd->ubUsedFg,ptMediaFd->recordIdx,ptMediaFd->usPort,ptMediaFd->fdType,ptMediaFd->iSocketFd,ptMediaFd->ulUCCId,
// ptMediaFd->rtpCliPort,ptMediaFd->rtcpCliPort);
/* rtcp包处理完毕后直接退出. 后面的是rtp包的处理 */
if(FD_TYPE_UDP_RTCP == ptMediaFd->fdType) /*rtcp*/
{
(void)HandleRecordFileForFloorMsg(ptNode);
return XPOC_ERR_SUCCESS;
}
else if(FD_TYPE_TCP_RTP == ptMediaFd->fdType)
{
if(ptMediaFd->ubClosingFd)
return XPOC_ERR_SUCCESS;
}
/* 下面为处理 rtp包 的过程. audHalfPri|| audGrp record 不在收到媒体报文时创建文件. recv floor-granted 时创建. */
x_DebugLog("mediaFd:uccid[%d],mediatype[%d],grpspknum[%s],rcrdstate[%d],rcrdservtype[%d].",
ptMediaFd->ulUCCId, ptMediaFd->iRceMediaType, ptMediaFd->aucGroupSpkNum, ptMediaFd->iRceRecordState, ptMediaFd->enRcrdServType);
if((Record_WORK == ptMediaFd->iRceRecordState))
{
if(MEDIA_AUDIO == ptMediaFd->iRceMediaType)
CreateNewRecordFileOrNot(ptMediaFd);
}
/*else if(Serv_AudioHalfPri != ptMediaFd->enRcrdServType && Serv_AudioGroup != ptMediaFd->enRcrdServType)
{
CreateRecordFile(ptMediaFd);
printf("..CreateRecordFile: %s, %d\n", ptMediaFd->szRecordFileName, ptNode->BufLen);
}*/
else /* audHalfPri|| audGrp record 第一个录音文件任由rtp包创建 */
{
if (Serv_AudioHalfPri == ptMediaFd->enRcrdServType)
{
if(ptMediaFd->ubFirstProc)
{
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("ucc data null.\n");
return XPOC_ERR_FAIL;
}
if (0 != strcmp(stUCC.tCallInfoS.aucOrigNum, stUCC.tCallInfoS.aucRcrdNum)) //被叫
{
x_ErrorLog("recv rtp from callee[%s] first, do no need create recordfile.", stUCC.tCallInfoS.aucRcrdNum);
return XPOC_ERR_FAIL;
}
else
{
ptMediaFd->ubFirstProc = FALSE;
}
}
else
{
x_ErrorLog("AudioHalfPri: ptMediaFd->ubFirstProc is false.\n");
return XPOC_ERR_FAIL;
}
}
//暂时添加,避免组呼时部分rtp消息迟后于rtcp导致产生多个文件 add by lxh 20210414
else if (Serv_AudioGroup == ptMediaFd->enRcrdServType)
{
if(ptMediaFd->ubFirstProc)
{
ptMediaFd->ubFirstProc = FALSE;
}
else
{
x_ErrorLog("AudioGroup: ptMediaFd->ubFirstProc is false.\n");
return XPOC_ERR_FAIL;
}
}
CreateRecordFile(ptMediaFd);
}
if(Record_WORK != ptMediaFd->iRceRecordState)
{
x_ErrorLog("record file does not exist. recordState[%d].", ptMediaFd->iRceRecordState);
return XPOC_ERR_FAIL;
}
if(FD_TYPE_UDP_RTP == ptMediaFd->fdType)
{
UCHAR* pAudioBuffer = (UCHAR*)(ptNode->PktBuf + RTP_HEADER_LEN);
int iAudioBufferLen = ptNode->BufLen - RTP_HEADER_LEN;
UINT ulTs = 0, ulTsLen = 0;
Byte_2_U32(ptNode->PktBuf+4, ulTs, ulTsLen);
if (AUDIOTYPE_AMR_NB == audio_record_type)
{
// ptMediaFd->tcpFdIdx为-1,表示没有视频文件,此时即使是视频单呼,也创建amr文件
if (Serv_VideoPri == ptMediaFd->enRcrdServType && ptMediaFd->tcpFdIdx != -1) {
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
MediaFdS *ptTcpFd = &ptGlbData->stTcpAddrInfo.tcpRtpFdList[ptMediaFd->tcpFdIdx];
if(XPOC_ERR_FAIL == (ulReturn=WriteAudioDataToMp4File(ptTcpFd, pAudioBuffer, iAudioBufferLen, ulTs)))
{
x_ErrorLog("WriteAudioDataToMp4File err...\n");
}
} else {
ulReturn = WriteAMRNBMFAudioDataToFile(ptMediaFd->fd_record, pAudioBuffer, iAudioBufferLen);
}
}
else if (AUDIOTYPE_AMR_WB == audio_record_type)
{
ulReturn = WriteAMRWBAudioDataToFile(ptMediaFd->fd_record, (char *)pAudioBuffer, iAudioBufferLen);
}
else if (AUDIOTYPE_G711 == audio_record_type)
{
ulReturn = WriteG711AudioDataToFile(ptMediaFd->fd_record, (char *)pAudioBuffer, iAudioBufferLen);
}
else
{
x_WarnLog("Unexpected audio_record_type[%d].\n", audio_record_type);
ulReturn = XPOC_ERR_FAIL;
}
if (XPOC_ERR_SUCCESS != ulReturn)
{
x_ErrorLog("Write file [%s] failed.", ptMediaFd->szRecordFileName);
return XPOC_ERR_FAIL;
}
}
else if (FD_TYPE_TCP_RTP == ptMediaFd->fdType) /*rtp*/
{
/* ptMediaFd->iRecvBufferLen 保存的是可能存在的上一次分包后残留的最后一个非完整的包数据. */
if((ptMediaFd->iRecvBufferLen+ptNode->BufLen) >= RCE_MAX_VIDEO_RECV_BUFFER_LEN)/* 如果数据包超长则不保存,丢弃. */
{
x_ErrorLog("handle tcp pkt:ptMediaFd->iRecvBufferLen[%d],ptNode->BufLen[%d].", ptMediaFd->iRecvBufferLen, ptNode->BufLen);
return XPOC_ERR_FAIL;
}
memcpy(ptMediaFd->pRecvBuffer + ptMediaFd->iRecvBufferLen, ptNode->PktBuf, ptNode->BufLen);
ptMediaFd->iRecvBufferLen += ptNode->BufLen;
PREbegin:
//拆组包
int iDrop = 0;
for (iDrop = 0; (iDrop + 14) <= ptMediaFd->iRecvBufferLen; iDrop++)
{
unsigned char fl1 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop)[0]);
unsigned char fl2 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop)[1]);
unsigned char h1 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop)[2]);
unsigned char h2 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop)[3]);
if ((h1 & 0xEF) == 0x80 && (h2 & 0X7F) == 98)
{
UINT ulSsrc = 0;
UCHAR ucSsrcLen = 0;
Byte_2_U32(ptMediaFd->pRecvBuffer+iDrop+10, ulSsrc, ucSsrcLen);
if (!ptMediaFd->ulSsrc) {
ptMediaFd->ulSsrc = ulSsrc;
}
int RtpLen = fl1 << 8 | fl2;
if(RtpLen > 4000 || ptMediaFd->ulSsrc != ulSsrc)
{
iDrop += 3; // skip first fll,fl2 and h1,h2
continue;
}
if (iDrop + 2 + RtpLen + 14 <= ptMediaFd->iRecvBufferLen)
{
fl1 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop + 2 + RtpLen)[0]);
fl2 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop + 2 + RtpLen)[1]);
h1 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop + 2 + RtpLen)[2]);
h2 = (unsigned char)((ptMediaFd->pRecvBuffer + iDrop + 2 + RtpLen)[3]);
Byte_2_U32(ptMediaFd->pRecvBuffer+iDrop+2+RtpLen+10, ulSsrc, ucSsrcLen);
if ((h1 & 0xEF) == 0x80 && (h2 & 0X7F) == 98 && ulSsrc == ptMediaFd->ulSsrc) //通过看下包也是RTP来判断这一包是完全的
{
UCHAR *pPlayBuffer = (UCHAR*)(ptMediaFd->pRecvBuffer + iDrop + 2);
if (XPOC_ERR_SUCCESS == CheckNeedVideoSPS(ptMediaFd->waitVideoSPS, pPlayBuffer, RtpLen, ptMediaFd))
{
if(ptMediaFd->waitVideoSPS)
{
///
/*if(!ptMediaFd->pvMp4HFile)
{
rceUptUserVideoStartTime2DB(ptMediaFd);
}*/
// set metadata
SetMp4VidAvcCfg(ptMediaFd->pvMp4HFile, ptMediaFd->ulMp4Vid, &ptMediaFd->stAvcCfg);
/*if(ptMediaFd->pFrameBuf)
{
char prc[4] = {0,0,0,1};
*((UINT*)prc) = htonl(ptMediaFd->stAvcCfg.ulSpsLen-RTP_HEADER_LEN);
memcpy(ptMediaFd->pFrameBuf+ptMediaFd->ulFrameLen, prc, 4);
ptMediaFd->ulFrameLen += 4;
memcpy(ptMediaFd->pFrameBuf+ptMediaFd->ulFrameLen, ptMediaFd->stAvcCfg.ucSps+RTP_HEADER_LEN, ptMediaFd->stAvcCfg.ulSpsLen-RTP_HEADER_LEN);
ptMediaFd->ulFrameLen += ptMediaFd->stAvcCfg.ulSpsLen-RTP_HEADER_LEN;
*((UINT*)prc) = htonl(ptMediaFd->stAvcCfg.ulPpsLen-RTP_HEADER_LEN);
memcpy(ptMediaFd->pFrameBuf+ptMediaFd->ulFrameLen, prc, 4);
ptMediaFd->ulFrameLen += 4;
memcpy(ptMediaFd->pFrameBuf+ptMediaFd->ulFrameLen, ptMediaFd->stAvcCfg.ucPps+RTP_HEADER_LEN, ptMediaFd->stAvcCfg.ulPpsLen-RTP_HEADER_LEN);
ptMediaFd->ulFrameLen += ptMediaFd->stAvcCfg.ulPpsLen-RTP_HEADER_LEN;
ptMediaFd->ulLastRtpTs = 0;
}*/
ptMediaFd->waitVideoSPS = 0;
}
/
const int hdrLen = (pPlayBuffer[0]&0x10)?RTP_HEADER_LEN+RTP_HEADER_EXT_LEN:RTP_HEADER_LEN;
UCHAR tp = pPlayBuffer[hdrLen]&0x1f;
if(tp == 7)
{
//
ptMediaFd->stAvcCfg.ulSpsLen = RtpLen;
memcpy(ptMediaFd->stAvcCfg.ucSps, pPlayBuffer, ptMediaFd->stAvcCfg.ulSpsLen);
}
else if(tp == 8)
{
//
ptMediaFd->stAvcCfg.ulPpsLen = RtpLen;
memcpy(ptMediaFd->stAvcCfg.ucPps, pPlayBuffer, ptMediaFd->stAvcCfg.ulPpsLen);
// set metadata
//SetMp4VidAvcCfg(ptMediaFd->pvMp4HFile, ptMediaFd->ulMp4Vid, &ptMediaFd->stAvcCfg);
}
else
{
if(tp == 5 && XPOC_ERR_SUCCESS == CreateNewRecordFileOrNot(ptMediaFd))
{
//
ptMediaFd->ulMp4Vid = SetAddMp4VidTrack(ptMediaFd->pvMp4HFile, ptMediaFd->stAvcCfg.ucSps+hdrLen, ptMediaFd->stAvcCfg.ulSpsLen-hdrLen);
if (ptMediaFd->ulMp4Vid == MP4_INVALID_TRACK_ID)
{
iDrop = ptMediaFd->iRecvBufferLen;
break;
}
else
{
iDrop--;
continue;
}
}
///
if(XPOC_ERR_FAIL == WriteVideoDataToMp4File(ptMediaFd, pPlayBuffer, RtpLen))
{
x_ErrorLog("WriteVideoDataToMp4File err...\n");
iDrop = ptMediaFd->iRecvBufferLen;
break;
}
}
}
ptMediaFd->iRecvBufferLen = ptMediaFd->iRecvBufferLen - iDrop - 2 - RtpLen;
memmove(ptMediaFd->pRecvBuffer, ptMediaFd->pRecvBuffer + iDrop + 2 + RtpLen, ptMediaFd->iRecvBufferLen);
//printf("..after skip rtp....ptMediaFd->iRecvBufferLen: %d....\n", ptMediaFd->iRecvBufferLen);
//memset(ptMediaFd->pRecvBuffer + ptMediaFd->iRecvBufferLen, 0, RCE_MAX_VIDEO_RECV_BUFFER_LEN - ptMediaFd->iRecvBufferLen);
goto PREbegin;
}
else
{
//printf("uncompleted data frame....RtpLen: %d..fl1: 0x%02x, fl2: 0x%02x, h1: 0x%02x, h2: 0x%02x..iDrop: %d..ptMediaFd->iRecvBufferLen: %d\n", RtpLen, fl1, fl2, h1, h2, iDrop, ptMediaFd->iRecvBufferLen);
iDrop += 3; // skip first fll,fl2 and h1,h2
ptMediaFd->waitVideoSPS = 1;
continue;
}
}
else
{
ptMediaFd->iRecvBufferLen -= iDrop;
memmove(ptMediaFd->pRecvBuffer, ptMediaFd->pRecvBuffer + iDrop, ptMediaFd->iRecvBufferLen);
return XPOC_ERR_SUCCESS;
}
}
}
ptMediaFd->iRecvBufferLen -= iDrop;
//printf("ptMediaFd->iRecvBufferLen: %d, iDrop: %d\n", ptMediaFd->iRecvBufferLen, iDrop);
memmove(ptMediaFd->pRecvBuffer, ptMediaFd->pRecvBuffer + iDrop, ptMediaFd->iRecvBufferLen);
//memset(ptMediaFd->pRecvBuffer + ptMediaFd->iRecvBufferLen, 0, RCE_MAX_VIDEO_RECV_BUFFER_LEN - ptMediaFd->iRecvBufferLen);
}
XPOC_TRACEFUNC_OUT;
return XPOC_ERR_SUCCESS;
}
/*UINT rceDpSendPktOnly(PktNode_S *ptNode)
{
(void)ptNode;
return XPOC_ERR_SUCCESS;
}*/
#if 0
#endif
/*向接收队列插入新数据包*/
UINT rceDpSavePktIntoQueue(UCHAR *ptPktBuf, SINT buffLen, MediaFdS *ptMediaFd)
{
XPOC_TRACEFUNC_IN;
X_NULL_POINTER_CHK_TWO_PARA(ptPktBuf, ptMediaFd);
T_RceUCallCtxTable stUCC;
memset(&stUCC, 0, sizeof(T_RceUCallCtxTable));
UINT ulReturn = XRceUCallCtxOpr(XDB_OPR_QRY, NULL, 0, (MediaTypeE)0, NULL, &ptMediaFd->ulUCCId, &stUCC);
if(XPOC_ERR_SUCCESS != ulReturn)
return ulReturn;
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
ThreadInfo_t *ptSendThread = NULL;
PktQueue_S *ptQueue = NULL;
if(FD_TYPE_UDP_RTP == ptMediaFd->fdType || FD_TYPE_UDP_RTCP == ptMediaFd->fdType)
{
ptSendThread = ptGlbData->stUdpAddrInfo.ptSendThread;
}
else if(FD_TYPE_TCP_RTP == ptMediaFd->fdType)
{
ptSendThread = ptGlbData->stTcpAddrInfo.ptSendThread;
}
/*数据直接送到发送队列,省去中间的内存拷贝*/
if(!ptSendThread)
{
x_ErrorLog("UCCId[%d],servId[%s],fdRtp[%d] ptSendThread is NULL.",
stUCC.ulRecordIdx, stUCC.aucServId, ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx].iSocketFd);
return XPOC_ERR_FAIL;
}
ptQueue = ptSendThread->pPktQueue;
if(!ptQueue)
{
x_ErrorLog("UCCId[%d],servId[%s],fdRtp[%d] ptQueue is NULL.",
stUCC.ulRecordIdx, stUCC.aucServId, ptGlbData->stUdpAddrInfo.udpRtpFdList[stUCC.usRtpFdIdx].iSocketFd);
return XPOC_ERR_FAIL;
}
//无锁机制保护多线程读写情况
NodeIndex_S *pstNodeIndex = NULL;
rceRmIdxManageGetFreeNode(&ptQueue->stIndexManageCtx, &pstNodeIndex);
if(NULL == pstNodeIndex)
{
x_ErrorLog("rceRmIdxManageGetFreeNode failure. No free node to receive data.");
return XPOC_ERR_INVALID_PTR;
}
PktNode_S *ptNode = &ptQueue->PktNode[pstNodeIndex->u32PktNodeIndex];
//ptNode->bDistributePkt = TRUE;
ptNode->ulPktNodeIdx = pstNodeIndex->u32PktNodeIndex;
memcpy(&ptNode->PktFrom, ptQueue, sizeof(ptNode->PktFrom));
ptNode->BufLen = buffLen;
memcpy(ptNode->PktBuf, ptPktBuf, MIN(buffLen, DP_BUFFER_SIZE));
ptNode->pNodeData = (void*)ptMediaFd;
ptNode->eCodecType = (SdpCodecE)stUCC.stMediaInfo.stSdpCodec[0].enCodecName;
ptMediaFd->ulUCCIdbak = ptMediaFd->ulUCCId; // add by lxh 20210419
/* ready to send */
rceRmIdxManageInsertToSendingList(&ptQueue->stIndexManageCtx, pstNodeIndex);
if(FD_TYPE_TCP_RTP == ptMediaFd->fdType)
{
x_DebugLog("[PKT][TCP][RTP]pkt recv ok.NodIdx[%d],bufflen[%d],src[FD][%d:%d].UCCId[%d].",
ptNode->ulPktNodeIdx, buffLen, ptMediaFd->recordIdx, ptMediaFd->iSocketFd, ptMediaFd->ulUCCId);
x_DebugLog("[PKT][TCP][RTP]pkt insrt in send queue. NodeCount:[send:%d,free:%d].",
ptQueue->stIndexManageCtx.stSendList.s32Count, ptQueue->stIndexManageCtx.stFreeList.s32Count);
}
XPOC_TRACEFUNC_OUT;
return buffLen;
}
void *rceDpHandlePktFromQueue(void *ptr)
{
XPOC_TRACEFUNC_IN;
if(!ptr)
{
x_ErrorLog("input para is NULL.\n");
return NULL;
}
ThreadInfo_t *ptThread = (ThreadInfo_t*)ptr;
if(PROTO_UDP != ptThread->enThreadType && PROTO_TCP != ptThread->enThreadType)
{
x_ErrorLog("Thread type[%d] is invalid, threadId[%lu].\n",ptThread->enThreadType, ptThread->ThreadId);
return NULL;
}
x_DebugLog("[RCE][PKT] handle recv pkt, threadType[%d],threadId[%lu],queue[%p].",
ptThread->enThreadType, ptThread->ThreadId, ptThread->pPktQueue);
PktQueue_S *ptQueue = ptThread->pPktQueue;
NodeIndex_S *ptNodeIdx = NULL;
PktNode_S *ptNode = NULL;
for( ; ; )
{
rceRmIdxManageGetSendNode(&ptQueue->stIndexManageCtx, &ptNodeIdx);
if(!ptNodeIdx)/* no data to send */
{
usleep(1000); /* FIXME: sleep 1ms is OK? */
continue;
}
ptNode = &ptQueue->PktNode[ptNodeIdx->u32PktNodeIndex];
if(0 == ptNode->BufLen)/* NULL Packet */
{
x_InfoLog("node bufflen is 0.NodeIdx[%d],codecType[%d],free node.", ptNode->ulPktNodeIdx, ptNode->eCodecType);
/* this pPktNodeIndex is free now */
rceRmIdxManageInsertToFreeList(&ptQueue->stIndexManageCtx, ptNodeIdx);
continue;
}
if(PROTO_UDP == ptThread->enThreadType)
{
}
else if(PROTO_TCP == ptThread->enThreadType)
{
x_DebugLog("[PKT][TCP][RTP]pkt get from send queue. NodeCount[send:%d,free:%d].",
ptQueue->stIndexManageCtx.stSendList.s32Count, ptQueue->stIndexManageCtx.stFreeList.s32Count);
}
// modified by shm, 增加读锁
MediaFdS *ptMediaFd = (MediaFdS*)ptNode->pNodeData;
pthread_rwlock_rdlock(&ptMediaFd->mtxUseFg);
if (ptMediaFd->ubUsedFg && ptMediaFd->ulUCCId == ptMediaFd->ulUCCIdbak)
{
(void)rceDpDispatchPkt(ptNode);
}
pthread_rwlock_unlock(&ptMediaFd->mtxUseFg);
/* this pPktNodeIndex is free now */
ptNode->ulPktNodeIdx = 0;
rceRmIdxManageInsertToFreeList(&ptQueue->stIndexManageCtx, ptNodeIdx);
}
XPOC_TRACEFUNC_OUT;
}
void *rceDpRecvUdpPacket(void *ptr)
{
XPOC_TRACEFUNC_IN;
(void)ptr;
UCHAR recvbuff[DP_BUFFER_SIZE];
MediaFdS *ptUdpFd = NULL;
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(struct sockaddr_in);
struct epoll_event rcvevent[MAX_RTP_SD_NUM];
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
/* get the thread info */
for ( ; ; )
{
int fdnum = epoll_wait(ptGlbData->stUdpAddrInfo.udpEpollFd, rcvevent, MAX_RTP_SD_NUM, -1);
if(fdnum < 0)
{
// x_WarnLog("invalid fdnum[%d]", fdnum);
continue;
}
int i = 0;
for(i = 0; i < fdnum; i++)
{
if(!(rcvevent[i].events & EPOLLIN))
continue;
ptUdpFd = (MediaFdS*)rcvevent[i].data.ptr;
if(!ptUdpFd)
{
x_InfoLog("ptUdpFd is NULL. fdnum[%d].\n", fdnum);
continue;
}
if(0 == ptUdpFd->ulUCCId)
continue;
SINT recvlen = recvfrom(ptUdpFd->iSocketFd, recvbuff, DP_BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
if(recvlen <= 0)
{
x_InfoLog("Call recvfrom() failure. SockFd=%d. RecvLen=%d.\n", ptUdpFd->iSocketFd, recvlen);
//abort();
continue;
}
(void)rceDpSavePktIntoQueue(recvbuff, recvlen, ptUdpFd);
}
}
XPOC_TRACEFUNC_OUT;
return NULL;
}
void *rceDpRecvTcpPacket(void *ptr)
{
XPOC_TRACEFUNC_IN;
(void)ptr;
UCHAR recvbuff[DP_BUFFER_SIZE];
MediaFdS *ptTcpFd = NULL;
struct epoll_event rcvevent[MAX_RTP_SD_NUM];
T_ModCtxS *ptModCtx = (T_ModCtxS*)Fplat_GetModuleCtx(XMOD_TYPE_RCE);
RceGlbData_S* ptGlbData = (RceGlbData_S*)ptModCtx->pAppData;
/* 从实际效果上看, 网卡上抓到包了,但是server貌似没有收到。考虑是socket的建立和使用在不同线程导致.
因此把 socket 建立和连接放在同一个线程中 */
//mdeInitTcpSocket(ptModCtx);
/* get the thread info */
for ( ; ; )
{
int fdnum = epoll_wait(ptGlbData->stTcpAddrInfo.tcpEpollFd, rcvevent, MAX_RTP_SD_NUM, -1);
if(fdnum <= 0)
{
// x_WarnLog("invalid fdnum[%d]", fdnum);
continue;
}
int i = 0;
for (i = 0; i < fdnum; i++)
{
if (!(rcvevent[i].events & EPOLLIN))
continue;
ptTcpFd = (MediaFdS*)rcvevent[i].data.ptr;
if (!ptTcpFd)
{
x_ErrorLog("ptTcpFd is NULL. fdnum[%d].\n", fdnum);
continue;
}
if (0 == ptTcpFd->ulUCCId)
continue;
SINT recvlen = recv(ptTcpFd->iSocketFd, recvbuff, DP_BUFFER_SIZE, 0);
if (recvlen <= 0)
{
if(recvlen < 0)
x_ErrorLog("Call recv() failure. SockFd=%d. RecvLen=%d.\n", ptTcpFd->iSocketFd, recvlen);
//abort();
continue;
}
(void)rceDpSavePktIntoQueue(recvbuff, recvlen, ptTcpFd);
}
}
XPOC_TRACEFUNC_OUT;
return NULL;
}