最近在看 jrtplib的收包流程,看了这篇文章 jrtplib接收数据包流程 ,只是用的库老了点 V3.7 的,写的也太长了,不够简练,于是自己写一份
V3.11.1的简练点的收包流程说明,捡重点,无关的流程略过。
RTP包的接收入口函数
int RTPSession::Poll()
{
if ((status = rtptrans->Poll()) < 0) // 流程一, 默认调用 RTPUDPv4Transmitter::Poll() // 处理收到的buffer,转为元数据,存入容器
return ProcessPolledData(); // 流程二,将元数据解析为 RTP或RTCP包,分别处理之
}
————————————— 流程(一) 的剖析 ————————————–
说明: rtptrans是RTPSession类的成员变量,默认是Rtpudpv4transmitter类,它实现了rtp包以及rtcp包的收发工作
步骤1,分别从 rtpsock 和 rtcpsock 收数据
int RTPUDPv4Transmitter::Poll()
{
status = PollSocket(true); // poll RTP socket
if (rtpsock != rtcpsock) // no need to poll twice when multiplexing
{
if (status >= 0)
status = PollSocket(false); // poll RTCP socket
}
}
步骤2
int RTPUDPv4Transmitter::PollSocket(bool rtp)
{
// 收rtp或rtcp包
recvlen = recvfrom(sock,packetbuffer,RTPUDPV4TRANS_MAXPACKSIZE,0,(struct sockaddr *)&srcaddr,&fromlen);
// 收到的buffer构建元数据
pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET)RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager());
// 将元数据存入队列
rawpacketlist.push_back(pack);
}
————————————— 流程(二) 的剖析 ————————————–
步骤1
int RTPSession::ProcessPolledData()
{
while ((rawpack = rtptrans->GetNextPacket()) != 0)
{
//内部遍历并解析元数据,得到RTPPacket包
if ((status = sources.ProcessRawPacket(rawpack,rtptrans,acceptownpackets)) < 0)
}
// 下面是发送rtcp相关的,没研究过
status = rtcpbuilder.BuildNextPacket(&pack)
Status=rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength()) //发送rtcp包
}
步骤2,内部解析元数据,判断是RTP还是RTCP包,然后分别处理
int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack )
{
步骤2.1 解析源数据, 得到RTPPacket包,如果你测试发送的是字符串,就可以看到payload属性的值了"1234456789AB"
rtppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPACKET) RTPPacket(*rawpack,GetMemoryManager());
步骤2.2 处理RTP包
if ((status = ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),0,&stored)) < 0)
步骤2.3 处理RTCP包
status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),0);
{
在函数内部,根据遍历RTCP包,根据包类型分别处理
SR, /**< An RTCP sender report. */
RR, /**< An RTCP receiver report. */
SDES, /**< An RTCP source description packet. */
BYE, /**< An RTCP bye packet. */
APP, /**< An RTCP packet containing application specific data. */
Unknown /**< The type of RTCP packet was not recognized. */
}
// 注意把元数据解析成RTPpacket的函数如下
int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack)
}
步骤2.2
int RTPSources::ProcessRTPPacket(
{
// 虚函数,什么都没干,可扩展
OnRTPPacket(rtppack,receivetime,senderaddress);
// 步骤2.2.1,构建 RTPInternalSourceData对象
if ((status = ObtainSourceDataInstance(ssrc,&srcdat,&created)) < 0)
// 步骤2.2.2, 内部调用 RTPInternalSourceData::ProcessRTPPacket( ) 函数来处理 . RTP数据收包处理到此结束
if ((status = srcdat->ProcessRTPPacket(rtppack,receivetime,stored,this)) < 0)
{
//内部按序列号用容器存储,最多存32个
packetlist.push_front(rtppack);
packetlist.insert(it,rtppack);
}
// 步骤2.2.3, 内部循环处理CSRC数组,没研究过
for (i = 0 ; i < num ; i++)
{
if ((status = ObtainSourceDataInstance(CSRCs[i],&csrcdat,&createdcsrc)) < 0)
}
}
ok,到此RTPSession收RTP包后存入队列,收包流程就结束了,接下来就是处理这些收到的包了,官方示例如下:
sess.BeginDataAccess(); //同步锁
// check incoming packets
// 开始遍历参与者中第一个有RTP数据的流,如果找到了,就返回tree,否则返回false。
//在接收数据时我们常用的是这套函数,因为如果没有数据要来都没用
if (sess.GotoFirstSourceWithData())
{
//实际上是双层嵌套循环,第一层先遍历内部的RTPInternalSourceData对象,rcdat = sourcelist.GetCurrentElement();
do
{
RTPPacket *pack;
// 再遍历该RTPInternalSourceData对象内部的 RTPpacket列表
while ((pack = sess.GetNextPacket()) != NULL)
{
// You can examine the data here
// for test
char pBuffer[100] ={0};
memcpy(pBuffer,pack->GetPayloadData(),pack->GetPayloadLength());
printf("Got packet -->%s \n",pBuffer); // 界面打印收到的字符串
// we don't longer need the packet, so
// we'll delete it
sess.DeletePacket(pack);
}
} while (sess.GotoNextSourceWithData());
}
sess.EndDataAccess();