jrtplib接收資料包流程

來源:互聯網
上載者:User

近來接觸RTP,自然涉及到jrtplib庫,閱讀3.7.1代碼,片餘時間,做點摘記,望今後可以快速回憶起來,也希望朋友閱讀,指出不當之處,奉上您們的寶貴建議,一起學習進步。
接下去源碼分析筆記都是基於:#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;

}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.