jrtplib接收数据包流程
接下去源码分析笔记都是基于:#ifndef RTP_SUPPORT_THREAD ,关于后台线程处理RTP包的接收,作者用了相关的类处理,不过同样会调用到以下涉及的一些接口函数,暂时还没细看。
可能会在以后作点笔记。
PS:若需转载,请注明文章来源地址
http://openregion.blog.com/2010/05/19/jrtplib接受数据包流程
RTP包的接收入口函数
int RTPSession::Poll()
{
……
㈠ if ((status = rtptrans->Poll()) < 0)
return status;
㈡ return ProcessPolledData();
}
说明:
If you’re not using the poll thread, this function must be called regularly to process incoming data and to send RTCP data when necessary.
rtptrans是RTPSession类的成员变量,它的创建过程如下:
① RTPUDPv4TransmissionParams transparams;
② status = m_rtpSession->Create(sessparams,&transparams);
int RTPSession::Create(const RTPSessionParams &sessparams,RTPTransmitter *transmitter)
{
……
③ rtptrans = transmitter;
……
}
————————————— ㈠ ————————————–
rtptrans->Poll() (rtpudpv4transmitter.cpp):
int RTPUDPv4Transmitter::Poll()
{
……
status = PollSocket(true); // poll RTP socket
if (status >= 0)
status = PollSocket(false); // poll RTCP socket
……
}
说明:
这个文件中的Rtpudpv4transmitter类实现了rtp包以及rtcp包的收发工作。
—————————————————————————–
PollSocket函数如下(rtpudpv4transmitter.cpp):
int RTPUDPv4Transmitter::PollSocket(bool rtp)
{
……
recvlen = recvfrom(sock,packetbuffer,RTPUDPV4TRANS_MAXPACKSIZE,0,(struct sockaddr *)&srcaddr,&fromlen);
……
pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET)RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager());
……
rawpacketlist.push_back(pack);
……
}
关于class RTPRawPacket 类,说明如下:
This class is used by the transmission component to store the incoming RTP and RTCP data in.
最后调用rawpacketlist.push_back(pack); 将得到的包放到队列中去。
class RTPRawPacket 类的成员变量如下:
uint8_t *packetdata; //接收到的原始包数据内容
size_t packetdatalength; //接收到的原始包数据长度
RTPTime receivetime; //接收到原始包的时间
RTPAddress *senderaddress; //发送原始数据包的发送方地址
bool isrtp; //是否是rtp包
————————————— ㈡ ————————————–
ProcessPolledData()函数代码概要如下(RTPSession.cpp):
int RTPSession::ProcessPolledData()
{
……
while ((rawpack = rtptrans->GetNextPacket()) != 0)
{
……
if ((status = sources.ProcessRawPacket(rawpack,rtptrans,acceptownpackets)) < 0)
……
}
……
status = rtcpbuilder.BuildNextPacket(&pack)
……
Status=rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength()) //发送rtcp包
}
—————————————————————————–
ProcessRawPacket (RTPSources.cpp)代码概要如下:
int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans,bool acceptownpackets)
{
……
return ProcessRawPacket(rawpack,transmitters,num,acceptownpackets);
}
注:这里两个ProcessRawPacket函数参数不一样。
—————————————————————————–
第二个ProcessRawPacket()代码概要如下:
int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans[],int numtrans,bool acceptownpackets)
{
int status;
if (rawpack->IsRTP()) // RTP packet
{
RTPPacket *rtppack;
// First, we’ll see if the packet can be parsed
rtppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPACKET) ① RTPPacket(*rawpack,GetMemoryManager());
if (rtppack == 0)
return ERR_RTP_OUTOFMEM;
……
Status =
② ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),senderaddress,&stored)
……
}
—————————————–①————————————
RTPPacket函数根据接收到的原始包RTPRawPacket &rawpack,重新组装成生成RTPPacket 类型的rtppacket信息存储单元,代码概要如下(Rtppacket.cpp):
RTPPacket::RTPPacket(RTPRawPacket &rawpack,RTPMemoryManager *mgr) : receivetime(rawpack.GetReceiveTime()),RTPMemoryObject(mgr)
{
Clear();
error = ParseRawPacket(rawpack);
}
—————————————————————————–
※(值得一看)
ParseRawPacket代码概要如下(Rtppacket.cpp):
int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack)
{
uint8_t *packetbytes;
size_t packetlen;
uint8_t payloadtype;
RTPHeader *rtpheader;
bool marker;
int csrccount;
bool hasextension;
int payloadoffset,payloadlength;
int numpadbytes;
RTPExtensionHeader *rtpextheader;
uint16_t exthdrlen;
if (!rawpack.IsRTP()) // If we didn’t receive it on the RTP port, we’ll ignore it
return ERR_RTP_PACKET_INVALIDPACKET;
// The length should be at least the size of the RTP header
packetlen = rawpack.GetDataLength();
if (packetlen < sizeof(RTPHeader))
return ERR_RTP_PACKET_INVALIDPACKET;
packetbytes = (uint8_t *)rawpack.GetData();
rtpheader = (RTPHeader *)packetbytes;
……
return 0;
}
RTPPacket类型的RTP包中,有如下成员变量:
bool hasextension,hasmarker;
int numcsrcs;
uint8_t payloadtype; //负载类型
uint32_t extseqnr,timestamp,ssrc; //rtp包序号,时间戳,同步源信息
uint8_t *packet,*payload; //包始址 负载数据始址
size_t packetlength,payloadlength; //包长度 负载数据长度
uint16_t extid;
uint8_t *extension;
size_t extensionlength;
bool externalbuffer;
RTPTime receivetime;
注:此函数提取出接收到的原始数据包中的包信息,重新组装生成了RTPPacket类型的信息存储单元,供本地使用。
—————————————–②————————————
ProcessRTPPacket(RTPSources.cpp)
int RTPSources::ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,const RTPAddress *senderaddress,bool *stored)
{
……
RTPInternalSourceData *srcdat;
//virtual function,is called when an RTP packet is about to be processed.
OnRTPPacket(rtppack,receivetime,senderaddress);
ssrc = rtppack->GetSSRC();
if ((status = ※1 ObtainSourceDataInstance (ssrc,&srcdat,&created)) < 0)
……
// The packet comes from a valid source, we can process it further now
// The following function should delete rtppack itself if something goes
// wrong
if ((status = srcdat->※2 ProcessRTPPacket(rtppack,receivetime,stored)) < 0)
……
}
说明:
Srcdat:为RTPInternalSourceData类型指针。
class RTPSources类维护着一个ssrc信息的哈希表:
RTPKeyHashTable<const uint32_t, RTPInternalSourceData*, RTPSources_GetHashIndex, RTPSOURCES_HASHSIZE> sourcelist;
列表包含参与者RTP包的SSRC信息。该类提供函数用来轮询处理每个参与者的RTP和RTCP 数据包。每次收到包都会根据该包的SSRC 把该包塞入到哈希表中,而进一步的数据处理则交给更下层的RTPInternalSourceData类。该类的设计是为了更好的管理来自不同SSRC的数据。
OnRTPPacket (rtppack, receivetime, senderaddress)
:这是Rtpsession类中的虚方法,可以在Class Rtpsession类的派生类中实现该虚函数,并在需要处理RTP包时回调该函数。
————————————※1 —————————————-
ObtainSourceDataInstance(RTPSources.cpp):
int RTPSources::ObtainSourceDataInstance(uint32_t ssrc,RTPInternalSourceData **srcdat,bool *created)
{
……
srcdat2=RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA)RTPInternalSourceData(ssrc,RTPSources::NoProbation,GetMemoryManager());
……
if ((status = sourcelist.AddElement(ssrc,srcdat2)) < 0)
……
}
说明:
RTPInternalSourceData :由参数ssrc生成管理RTP包存储的变量srcdat。变量srcdat 是RTPInternalSourceData类型,继承自RTPSourceData,具体管理RTP数据包的存储等。
AddElement :由参数ssrc和srcdat2来生成sourcelist 的元素,并将它加入到class RTPSources类维护的哈希表sourcelist 中。
bool *created :该函数参数是【out】型,如果class RTPSources类维护的哈希表sourcelist中已经存在相同的ssrc信息,则created = false;否则,调用AddElement来添加一个ssrc信息,created = true。
—————————————※2 ————————————-
ProcessRTPPacket (RTPInternalSourceData.cpp)代码如下:
int RTPSources::ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,const RTPAddress *senderaddress,bool *stored)
{
……
stats.ProcessPacket(rtppack,receivetime,tsunit,ownssrc,&accept,applyprobation,&onprobation);
……
// Now, we can place the packet in the queue
if (packetlist.empty())
{
*stored = true;
packetlist.push_back(rtppack);
return 0;
}
……
}
说明:
变量stats 是RTPSourceStats类,管理接收到包的状态参数。对它的操作被封装在RTPSourceData的接口函数中。
packetlist :属于class RTPSourceData ,定义如下:std::list<RTPPacket *> packetlist。※2调用处的srcdat为RTPInternalSourceData类型指针,具体负责RTP包数据存储。
至此,将接收到的数据包以RTPPacket为存储单元放入了队列之中。
获取接收到的RTP包过程
for (;;)
{ #ifndef RTP_SUPPORT_THREAD status = sess.Poll(); checkerror(status); #endif // RTP_SUPPORT_THREAD sess.BeginDataAccess(); // check incoming packets if (sess.GotoFirstSourceWithData()) { do { RTPPacket *pack; while ((pack = sess.GetNextPacket()) != NULL) { // You can examine the data here printf(“Got packet !\n”); // we don’t longer need the packet, so // we’ll delete it sess.DeletePacket(pack); } } while (sess.GotoNextSourceWithData()); } sess.EndDataAccess(); }
该过程首先查找获得数据源(GotoFirstSourceWithData 和GotoNextSourceWithData),然后检查该源下是否有数据包(GetNextPacket):
rtpsession.cpp 文件
RTPPacket *RTPSession::GetNextPacket()
{
if (!created)
return 0;
return sources.GetNextPacket();
}
RTPSources.cpp 文件
RTPPacket *RTPSources::GetNextPacket()
{
if (!sourcelist.HasCurrentElement())
return 0;
RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
RTPPacket *pack = srcdat->GetNextPacket();
return pack;
}
RTPSourceData.cpp 文件
inline RTPPacket *RTPSourceData::GetNextPacket()
{
if (!validated)
return 0;
RTPPacket *p;
if (packetlist.empty())
return 0;
p = *(packetlist.begin());
packetlist.pop_front();
return p;
}