数据流量监测工具源玛共享2[嵌入式流媒体测试工具]

  在前一篇文章 《数据流量监测工具源玛共享[视频会议/DVR]》提到编写这个一个测试的小工具的目的和实现。在最近的一段测试中,发现这个工具对发现数据走向的诊断十分有效。在shell 上输入rate_stat命令就可以全部显示数据在某模块中的所有走向;输入rate_show命令就可以知道某数据在某个检测点的数据包头信息,比如数据包长度、序列号、尾包标志等参数。
NOTE:编码及测试环境为Tornado2.0(VxWorks 5.0)
 
 
 
a.如何插入监测代码
主要在需要监测的位置添加rate_probe代码段。
 
b.如何使用rate_stat命令显示所有监测点的信息
在连接到设备的超级终端(SuperTerminal)或Telnet上,输入rate_stat命令,并带上合适的参数。比如,如果要显示视频数据的走向就输入"video"字符串。
 
 
c.如何使用rate_show打印某监测点的RTP头信息
 
RTP 头数据结构定义如下:
typedef struct _tagRtpParam
{
    IN OUT  NW_UINT32 timestamp;
    IN OUT  NW_UINT32 marker;
    IN OUT  NW_BYTE  payload;
 
    OUT     NW_UINT32 sSrc;
    OUT     NW_UINT16 sequenceNumber;
    OUT     NW_INT32 sByte;
    OUT     NW_INT32 len;
} TRtpParam;
 
如果想知道某个检测点的具体数据情况,可以使用rate_show命令来打印数据信息。
rate_show带三个参数,分别是检测点的ID(这里称caller id)、通道ID以及准备打印的数据包数目。
 
 
#ifdef _PACKET_PROBER_
#define MAX_CALLERS  100   /*流量统计监测点的最大数目*/
#define MAX_CHANNELS (MAX_CONF_ATTENDEE_NUM+2)/*监测点通道的最大数目*/
#define MAX_FUNC_NAME_LEN  50 /*监测点调用函数的函数名最大长度*/
#define MAX_HINT_INFO_LEN   80 /*监测点调用函数的函数名最大长度*/
#define TICKS_PER_SECOND  60
typedef struct _TagCallerInfo

 NW_CHAR pchFuncName[MAX_FUNC_NAME_LEN];/*调用函数的函数名*/
 NW_CHAR  nFuncLen; /*调用函数的函数名实际长度*/  
 NW_SHORT nLine; /*调用函数的调用点位置*/  
}TCallerInfo;
typedef struct _TagPacketInfo

 NW_INT32  nPackets[MAX_CHANNELS];/*监测点流经总包数*/ 
 NW_INT32  nPacketRate[MAX_CHANNELS];/*监测点流量*/ 
 NW_INT32 nPrevPackets[MAX_CHANNELS];/*该点上一次监测的累计包数*/  
 NW_INT32 nPrevTicks[MAX_CHANNELS];/*该点上一次监测的累计时间*/
 NW_INT32 nPacketShown[MAX_CHANNELS];/*显示数据包头的数目*/
 NW_INT32  nInterval[MAX_CHANNELS];/*前后两次监测的时间跨度*/
 NW_BOOL  bFrame[MAX_CHANNELS];/*如果统计单位为帧*/ 
 EChannelType eChannelType[MAX_CHANNELS];/*通道类型*/
}TPacketInfo;

static TCallerInfo  g_tCaller[MAX_CALLERS];
static TPacketInfo g_tPacket[MAX_CALLERS];
static NW_INT32 g_nCallers   = 0;
static NW_BOOL g_bActivated  = FALSE;
static NW_INT32 g_eStreamType  = 0; 
       
NW_VOID   rate_start(void);
NW_VOID   rate_stop(void);
NW_BOOL   rate_started(void);
NW_VOID   rate_print(void);
 
NW_VOID  rate_probe(const NW_CHAR* pchFuncName,const NW_SHORT nLine,NW_SHORT* pCallerID,const EChannelType eChannelType,NW_SHORT nChannelID,const EStreamType eStreamType,TRtpParam* pRtpParam)
{
 NW_INT32   nCaller    = 0;
 NW_INT32   nChannel  = 0;
 NW_INT32  nCurrTicks   = 0; 
 static NW_BOOL  bInitialized   = FALSE;
 TCallerInfo*   ptCaller   = NULL;
 TPacketInfo*  ptPacket  = NULL;
 
 if (!rate_started())
 {
  return;
 }
 
 if (NULL == pchFuncName || NULL == pCallerID)
 {
  printf("invalid function name and pos pointer!");
  return;
 }
 
 if (nChannelID < 0 || nChannelID >= MAX_CHANNELS)
 {
  printf("invalid channel id %d!",nChannelID);
  return;
 } 
 
 if (CHANNEL_CALL_ID != eChannelType && CHANNEL_RING_ID != eChannelType )
 { 
  printf("invalid channel type %d!",eChannelType);
  return;
 } 
 if (!(eStreamType & g_eStreamType))
 {/*过滤不想统计的通道*/ 
  return;   
 } 
 
 if (!bInitialized)
 { /*第一次要初始化*/
  memset(&g_tCaller[0],0,sizeof(TCallerInfo)*MAX_CALLERS);
  memset(&g_tPacket[0],0,sizeof(TPacketInfo)*MAX_CALLERS);
  for (nCaller = 0; nCaller < MAX_CALLERS; nCaller++)
  { 
   for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++)
   {
    g_tPacket[nCaller].bFrame[nChannel] = FALSE;
   }
  }
  bInitialized = TRUE;
 }
 
 if (INVALID_VALUE == *pCallerID)
 { /*如果是某监测点第一次调用该函数,初始值必须为INVALID_VALUE*/
  nCaller     = g_nCallers++; 
  ptCaller     = &g_tCaller[nCaller];
  
  ptCaller->nFuncLen = strlen(pchFuncName);
  if (ptCaller->nFuncLen > MAX_FUNC_NAME_LEN)
  {
   printf("too long function name!/n");  
   return;
  }
  
  ptCaller->nFuncLen  = sprintf(ptCaller->pchFuncName,"%s",pchFuncName);
  ptCaller->nLine  = nLine;
  *pCallerID    = nCaller;/*返回当前监测点的ID,以备后用*/
 }
 else
 {
  nCaller = *pCallerID;
 }
 
 ptCaller  = &g_tCaller[nCaller];
 ptPacket  = &g_tPacket[nCaller];
 
 if (nCaller >= 0 && nCaller < MAX_CALLERS)
 {
  if (CHANNEL_CALL_ID != ptPacket->eChannelType[nChannelID]
  && CHANNEL_RING_ID != ptPacket->eChannelType[nChannelID] ) 
  {
   ptPacket->eChannelType[nChannelID] = eChannelType;
  }
 
  if (NULL != pRtpParam && ptPacket->nPacketShown[nChannelID]>0 && ptPacket->nPacketShown[nChannelID]-->0)
  {
   printf("%s(%4d):len %4d,marker %d,seq %5d/n",ptCaller->pchFuncName,ptCaller->nLine,pRtpParam->len,pRtpParam->marker,pRtpParam->sequenceNumber);   
   return;
  } 
 
  /*等待用户设置检测时间*/
  if (1 > ptPacket->nInterval[nChannelID])
  { 
   return;
  }
 
  /*如果统计单位是帧*/
  if (STREAM_VIDEO == eStreamType)
  {
   if (NULL != pRtpParam && pRtpParam->marker && !ptPacket->bFrame[nChannelID])
   {
    ptPacket->bFrame[nChannelID] = TRUE;
   }
   
   if (NULL != pRtpParam && ptPacket->bFrame[nChannelID] && !pRtpParam->marker)
   {
    return;
   }
  }
 
  ptPacket->nPackets[nChannelID]++;
  nCurrTicks = tickGet();
 
  if (0 == ptPacket->nPrevTicks[nChannelID])
  {
   ptPacket->nPrevPackets[nChannelID]  = ptPacket->nPackets[nChannelID];
   ptPacket->nPrevTicks[nChannelID]   = nCurrTicks;
  }
  else
  {
   if (nCurrTicks != ptPacket->nPrevTicks[nChannelID]
   && nCurrTicks-ptPacket->nPrevTicks[nChannelID] >= ptPacket->nInterval[nChannelID])
   {
    ptPacket->nPacketRate[nChannelID] = TICKS_PER_SECOND*(ptPacket->nPackets[nChannelID] - ptPacket->nPrevPackets[nChannelID])
     /(nCurrTicks - ptPacket->nPrevTicks[nChannelID]);
    ptPacket->nPrevTicks[nChannelID]   = 0;
    ptPacket->nInterval[nChannelID]   = 0;
   }
  }
 }
}
 
NW_VOID  rate_stat(NW_CHAR* pchMediaType)
{
 TCallerInfo*    ptCaller   = NULL;
 TPacketInfo*   ptPacket  = NULL;
 NW_INT32    nCaller   = 0;
 NW_INT32    nChannel  = 0;
 static const NW_INT32  nInterval  = 4*TICKS_PER_SECOND;/*second*/
 static const NW_INT32  nErrorPercentage = 5;/*误差占整个计时的百分比*/
 
 if (NULL == pchMediaType)
 {
  if (g_eStreamType > 0)
  {
   rate_print();
   return;
  }
  printf("NW_VOID rate_stat(NW_CHAR* pchMediaType)/n");    
  printf("please enter string 'audio' or 'video'.");
  return;
 }
 
 if (1 > nInterval || 1 > nErrorPercentage)
 {
  printf("invalid param,interval %d,error %d!/n",nInterval,nErrorPercentage);
  return;
 }
 
 g_eStreamType = 0;
  
 if (0 == strcmp(pchMediaType,"audio"))
 {
  g_eStreamType |= STREAM_AUDIO;
 }
 else if (0 == strcmp(pchMediaType,"video"))
 {
  g_eStreamType |= STREAM_VIDEO;  
 }
 else
 {
  printf("please enter string 'audio' or 'video'.");
  return;
 }
 
 /*等待初始化完毕*/
 if (!rate_started())
 {
  rate_start();
  
  taskDelay(TICKS_PER_SECOND/10); 
  /*试探一下有没有数据流*/
  if (1 > g_nCallers)
  {
   printf("no stream coming!/n");
   rate_stop();
   return;
  }
  else
  {
   /*如果有数据流,设置统计时间*/
   for (nCaller = 0; nCaller < MAX_CALLERS; nCaller++)
   { 
    for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++)
    {
     g_tPacket[nCaller].nInterval[nChannel]   = nInterval;
     g_tPacket[nCaller].nPackets[nChannel]  = 0;      
     g_tPacket[nCaller].nPacketRate[nChannel] = 0;
    }
   }
  }
 }
 
 printf("please wait for %d seconds.../n",((TICKS_PER_SECOND/10)+nInterval+nInterval/(100/nErrorPercentage))/TICKS_PER_SECOND);
 taskDelay(nInterval);/*统计时间*/ 
 taskDelay(nInterval/(100/nErrorPercentage));/*考虑大概%20 的偏差*/ 
 
 rate_print();
 
 rate_stop();
}
 
/*显示数据包RTP 头信息*/
NW_VOID rate_show(NW_INT32 nCallerID,NW_INT32 nChannelID,NW_INT32 nPacketNum)
{
 TCallerInfo*    ptCaller  = NULL;
 TPacketInfo*   ptPacket = NULL;
 NW_INT32    nCaller  = 0;
 NW_INT32    nChannel = 0;
 NW_BOOL   bFound  = 0;
 
 if (0 == nCallerID && 0 == nChannelID && 0 == nPacketNum)
 {
  printf("NW_VOID rate_show(NW_INT32 nCallerID,NW_INT32 nChannelID,NW_INT32 nPacketNum)/n");  
  return;
 }
 
 if (nCallerID <0 || nCallerID >= MAX_CALLERS)
 {
  printf("please enter valid function caller ID(first param)./n");
  return;
 }
 
 if (nChannelID < 0 || nChannelID >= MAX_CHANNELS)
 {
  printf("please enter valid channel ID(second param)./n",nChannelID);
  return;
 } 
 
 if (1 > nPacketNum)
 {
  printf("please enter valid packet number to show(third param)./n");
  return; 
 }
 
 /*等待初始化完毕, 如果rate_stat 还没有使用过*/
 if (!rate_started())
 {
  for (nCaller = 0; nCaller < MAX_CALLERS; nCaller++)
  { 
   memset(&g_tPacket[nCaller].nPacketShown[0],0,MAX_CHANNELS*sizeof(NW_INT32));
  }
  rate_start();
  
  taskDelay(TICKS_PER_SECOND/10); 
 
  /*试探一下有没有数据流*/
  if (1 > g_nCallers)
  {
   printf("no stream coming!/n");
   rate_stop();
   return;
  }
  else
  {   
   ptCaller  = &g_tCaller[nCallerID];
   ptPacket  = &g_tPacket[nCallerID];
   if (1 > ptCaller->nFuncLen)
   {
    return;
   }
   ptPacket->nPacketShown[nChannelID] = nPacketNum;
  }
 }
 taskDelay(300*nPacketNum/TICKS_PER_SECOND);/*300 为一秒中可能接收到的最大包数目*/ 
 
 rate_stop();   
}
 
NW_VOID  rate_print(void)
{
 TCallerInfo*    ptCaller  = NULL;
 TPacketInfo*   ptPacket = NULL;
 NW_INT32    nCaller  = 0;
 NW_INT32    nChannel = 0;
 NW_BOOL   bFound  = 0;
 
 if (1 > g_nCallers)
 {
  printf("no stream coming!/n");
  return;
 }
 printf("-------------------------------------------------------------------------------/n");  

 for (nCaller = 0; nCaller < MAX_CALLERS; nCaller++)
 { 
  ptCaller  = &g_tCaller[nCaller];
  ptPacket  = &g_tPacket[nCaller];
  if (1 > ptCaller->nFuncLen)
  {
   continue;
  }
  
  bFound = FALSE;
   
  for (nChannel = 0; nChannel < MAX_CHANNELS; nChannel++)
  {
   if (ptPacket->nInterval[nChannel] > 0)
   {
    ptPacket->nInterval[nChannel] = 0;
   }
   if (ptPacket->nPacketRate[nChannel] > 0)
   {
    printf("%28s(%4d) caller %2d,%4s id%3d:rate %2d %s/s,%3d %7s/n",
     ptCaller->pchFuncName,ptCaller->nLine,nCaller,CHANNEL_CALL_ID != ptPacket->eChannelType[nChannel]? "ring":"call",nChannel,
      ptPacket->nPacketRate[nChannel],ptPacket->bFrame[nChannel]? "f":"p",
       ptPacket->nPackets[nChannel],ptPacket->bFrame[nChannel]? "frames":"packets");   
    bFound = TRUE;
   }
  }
  
  if (bFound)
  {
   printf("/n");  
  }
 }
 printf("-------------------------------------------------------------------------------/n");  
}
 
NW_VOID  rate_start(void)
{
 g_bActivated = TRUE;
}
 
NW_VOID  rate_stop(void)
{
 g_bActivated = FALSE;
}
 
NW_BOOL  rate_started(void)
{
 return g_bActivated;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值