jrtplib笔记
轉(zhuǎn)自: 
 jrtplib 筆記(1) - CSDN博客 
 https://blog.csdn.net/alajl/article/details/5419489 
 最近要實(shí)現(xiàn) non-compound rtcp(http://tools.ietf.org/html/draft-ietf-avt-rtcp-non-compound-02 )
因?yàn)槲覀兪褂玫氖?jrtplib 這個(gè)開源的包,這個(gè)包把 RTCP 的處理都封裝好了,所以用戶不用去過多的關(guān)心,但是我們要實(shí)現(xiàn)上述的功能,所以必須要修改這 個(gè)開源庫關(guān)于 RTCP 處理部分的源代碼,所以就花了一些時(shí)間,仔細(xì)的閱讀了它,但是相關(guān)的文檔不是很多,所以就只能靠自己去理解了啊。
在修改 RTCP 的實(shí)現(xiàn)時(shí),我們有必要了解一下,原有 RTCP 的實(shí)現(xiàn),所以我們就從下面開始了
在整個(gè)代碼 里, RTPSession 這個(gè)對象是用戶接觸到最多的,在我們的實(shí)現(xiàn)中,我們用到了 RtpApp 這個(gè)類(這個(gè)對象是我們自己實(shí)現(xiàn)的,開源庫是沒有的) , 我們用 pollData ()輪詢所有收到的數(shù)據(jù),代碼如下
void RtpApp::pollData() // 輪詢所有數(shù)據(jù) 
 { 
 if(mSession == NULL) 
 return;
}
其中我們用到了 mSession->Poll(); 這個(gè)方法 用于輪詢所有的數(shù)據(jù)。這個(gè)方法是 RTPSession 里對數(shù)據(jù)處理的主要方法,務(wù)必要弄明白它的原理,代碼如下 :
int RTPSession::Poll() {
int status;if (!created)return ERR_RTP_SESSION_NOTCREATED;if (usingpollthread)return ERR_RTP_SESSION_USINGPOLLTHREAD;/*
真正的對 socket 的操作,它把接受到的 RTP 和 RTCP 數(shù)據(jù)分別放到相應(yīng)的隊(duì)列里( awpacketlist 隊(duì)列),并在 ProcessPolledData () 里處理了對應(yīng)隊(duì)列里的數(shù)據(jù)
*/
if ((status = rtptrans->Poll()) < 0) return status;return ProcessPolledData(); // 處理收到的數(shù)據(jù),對應(yīng)于 RFC3550 的邏輯部分}
ProcessPolledData ()這個(gè)東東,里面的邏輯是相當(dāng)多的,因?yàn)樗幚砹怂惺盏降?RTP 和 RTCP 包,并且根據(jù)協(xié)議對一些回復(fù) RTCP 包的處理也在這個(gè)方法里,所以要修改 RTCP 包,那么這個(gè)方法就是切入點(diǎn)了。
在方法里,我們看到了一個(gè)循環(huán),毫無疑問,這個(gè)東東就是遍歷 rtptrans->Poll() 所收到的包,它放在了一個(gè)隊(duì)列里( RTP 和 RTCP 都在同一個(gè)隊(duì)列)
while ((rawpack = rtptrans->GetNextPacket()) != 0) {
……}
那我們來一一分析,這個(gè) while 循環(huán)所干的東西 :)
int RTPSession::ProcessPolledData() {
RTPRawPacket *rawpack;int status;SOURCES_LOCKwhile ((rawpack = rtptrans->GetNextPacket()) != 0) {sources.ClearOwnCollisionFlag();// 清除了 SSRC 的沖突標(biāo)記,因?yàn)楦鶕?jù) RFC3550, 如果 SSRC 沖突的話,應(yīng)該要發(fā)送 //BYE 包的,所以,先上這個(gè)標(biāo)記回到初始值。 // since our sources instance also uses the scheduler (analysis of incoming packets)// we'll lock itSCHED_LOCK// 這東東對收到的 RTP 和 RTCP 包進(jìn)行處理,例如建立 SSRC , CCRC 隊(duì)列和
//SSRC 沖突標(biāo)記、許多變量值的設(shè)置等等。
if ((status = sources.ProcessRawPacket(rawpack, rtptrans, acceptownpackets)) < 0) {SCHED_UNLOCKSOURCES_UNLOCKRTPDelete(rawpack, GetMemoryManager());return status;}SCHED_UNLOCK// 檢查是否 SSRC 產(chǎn)生了沖突,如果檢測到的沖突,那么就應(yīng)當(dāng)發(fā)送 BYE 包了 if (sources.DetectedOwnCollision()) // collision handling!{printf("if collision/n");bool created;// created 的值決定了我們是否需要發(fā)送 BYE 包,如果沖突列表里,有了對應(yīng)// 的地址,那么將不發(fā)送 BYE 包,否則發(fā)送
if ((status = collisionlist.UpdateAddress(rawpack->GetSenderAddress(), rawpack->GetReceiveTime(), &created)) < 0) {printf("if collisionlist updateAddress/n");SOURCES_UNLOCKRTPDelete(rawpack, GetMemoryManager());return status;}// 需要生成一個(gè)新的 BYE 包 if (created){ // change our own SSRCprintf("if created/n");PACKSENT_LOCKbool hassentpackets = sentpackets;PACKSENT_UNLOCK// 如果我們已經(jīng)用沖突的 SSRC 發(fā)送了 RTP 數(shù)據(jù),那么就生成一個(gè)新的 //BYE 包,如果沒有發(fā)送 RTP 的數(shù)據(jù),那么這個(gè)時(shí)候發(fā)送 BYE 包是沒有 // 意義的 if (hassentpackets) {// Only send BYE packet if we've actually sent data using this// SSRCprintf("if hassentpackets/n");RTCPCompoundPacket *rtcpcomppack;BUILDER_LOCK// 生成一個(gè)新的 BYE 包 if ((status = rtcpbuilder.BuildBYEPacket(&rtcpcomppack, 0, 0, useSR_BYEifpossible)) < 0) {printf("buildbytpacket/n");BUILDER_UNLOCKSOURCES_UNLOCKRTPDelete(rawpack, GetMemoryManager());return status;}BUILDER_UNLOCK// 推入隊(duì)列 byepackets.push_back(rtcpcomppack);if (byepackets.size() == 1) // was the first packet, schedule a BYE packet (otherwise there's already one scheduled){printf("bytepacketssize==1/n");SCHED_LOCKrtcpsched.ScheduleBYEPacket(rtcpcomppack->GetCompoundPacketLength());SCHED_UNLOCK}}// bye packet is built and scheduled, now change our SSRC// and reset the packet count in the transmitterBUILDER_LOCK// 生成新的 SSRCuint32_t newssrc = packetbuilder.CreateNewSSRC(sources);BUILDER_UNLOCKPACKSENT_LOCKsentpackets = false;PACKSENT_UNLOCK// 刪除舊的 SSRCif ((status = sources.DeleteOwnSSRC()) < 0) {printf("sources.DeleteOwnSSRC/n");SOURCES_UNLOCKRTPDelete(rawpack, GetMemoryManager());return status;}// 綁定新的 SSRCif ((status = sources.CreateOwnSSRC(newssrc)) < 0) {printf("sources.CreateOwnSSRC/n");SOURCES_UNLOCKRTPDelete(rawpack, GetMemoryManager());return status;}}}RTPDelete(rawpack, GetMemoryManager());}//end whileSCHED_LOCKRTPTime d = rtcpsched.CalculateDeterministicInterval(false);SCHED_UNLOCKRTPTime t = RTPTime::CurrentTime();double Td = d.GetDouble();RTPTime sendertimeout = RTPTime(Td * sendermultiplier);RTPTime generaltimeout = RTPTime(Td * membermultiplier);RTPTime byetimeout = RTPTime(Td * byemultiplier);RTPTime colltimeout = RTPTime(Td * collisionmultiplier);RTPTime notetimeout = RTPTime(Td * notemultiplier);sources.MultipleTimeouts(t, sendertimeout, byetimeout, generaltimeout, notetimeout);collisionlist.Timeout(t, colltimeout);// We'll check if it's time for RTCP stuffSCHED_LOCKbool istime = rtcpsched.IsTime(); // 計(jì)算是否到了發(fā)送 RTCP 的時(shí)間SCHED_UNLOCKif (istime) {printf("istime/n");RTCPCompoundPacket *pack;// we'll check if there's a bye packet to send, or just a normal packetif (byepackets.empty()) { // 沒有 BYE 包發(fā)送就發(fā)送正常的 RTCP 包printf("byepacket empty and send RTCP packet/n");// 是否支持 non-compound 的發(fā)送
if (allowNonCompoundRTCP == false) {BUILDER_LOCKprintf("rtcpbuilder.BuildNextPacket with compound/n");// 生成一個(gè)新的 RTCP 包 if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0) {BUILDER_UNLOCKSOURCES_UNLOCKreturn status;}}else if (allowNonCompoundRTCP == true) { if (firstSendRTCP) {BUILDER_LOCKprintf("rtcpbuilder.BuildNextPacket with compound/n");// 生成一個(gè)新的 RTCP 包,根據(jù)協(xié)議,發(fā)送 non-compound 之前,必 // 須保證有一個(gè) compound 的包已經(jīng)發(fā)送
if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0) {BUILDER_UNLOCKSOURCES_UNLOCKreturn status;}}else {BUILDER_LOCKprintf("rtcpbuilder.BuildNextPacket with non-compound/n");// 生成一個(gè)新的 non compound RTCP 包if ((status = rtcpbuilder.BuildNextPacketWithNonCompound(&pack)) < 0) {BUILDER_UNLOCKSOURCES_UNLOCKreturn status;}}firstSendRTCP = false;}BUILDER_UNLOCK// 通過底層 socket ,發(fā)送出去咯 if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(), pack->GetCompoundPacketLength())) < 0) {printf("rtptrans->SendRTCPData error!/n");SOURCES_UNLOCKRTPDelete(pack, GetMemoryManager());return status;}PACKSENT_LOCKsentpackets = true;PACKSENT_UNLOCKOnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering} else { // 如果 BYE 隊(duì)列不為空,優(yōu)先發(fā)送 BYE 包printf("byepacket empty else/n");pack = *(byepackets.begin());byepackets.pop_front();if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(), pack->GetCompoundPacketLength())) < 0) {printf("rtptrans->SendRTCPData error!/n");SOURCES_UNLOCKRTPDelete(pack, GetMemoryManager());return status;}PACKSENT_LOCKsentpackets = true;PACKSENT_UNLOCKOnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tamperingif (!byepackets.empty()) // more bye packets to send, schedule them{printf("byepackets.empty/n");SCHED_LOCK rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength());SCHED_UNLOCK}}SCHED_LOCKrtcpsched.AnalyseOutgoing(*pack);SCHED_UNLOCKRTPDelete(pack, GetMemoryManager());}SOURCES_UNLOCKreturn 0;}
總結(jié)
 
                            
                        - 上一篇: 松下FP系列PLC以太网通讯
- 下一篇: AVOD CLOUD
