最近在看 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();