jrtplib笔记

转自:
jrtplib 笔记(1) - CSDN博客
https://blog.csdn.net/alajl/article/details/5419489
最近要实现 non-compound rtcp(http://tools.ietf.org/html/draft-ietf-avt-rtcp-non-compound-02 )

因为我们使用的是 jrtplib 这个开源的包,这个包把 RTCP 的处理都封装好了,所以用户不用去过多的关心,但是我们要实现上述的功能,所以必须要修改这 个开源库关于 RTCP 处理部分的源代码,所以就花了一些时间,仔细的阅读了它,但是相关的文档不是很多,所以就只能靠自己去理解了啊。

在修改 RTCP 的实现时,我们有必要了解一下,原有 RTCP 的实现,所以我们就从下面开始了

在整个代码 里, RTPSession 这个对象是用户接触到最多的,在我们的实现中,我们用到了 RtpApp 这个类(这个对象是我们自己实现的,开源库是没有的) , 我们用 pollData ()轮询所有收到的数据,代码如下

void RtpApp::pollData() // 轮询所有数据
{
if(mSession == NULL)
return;

mSession->Poll();    

mSession->BeginDataAccess();

if(mSession->GotoFirstSourceWithData() == false)
{
    // if theres no data, sleep 1ms
    mSession->EndDataAccess();
    RTPTime::Wait(RTPTime(0, 1000));
}
else
{
    // process the data
    do
    {
        RTPPacket *pkt;
        while ((pkt = mSession->GetNextPacket()) != NULL)
        {
           // 处理收到的数据 
        }
    } while(mSession->GotoNextSourceWithData());  // 到下一个 source

    mSession->EndDataAccess();
}

}

其中我们用到了 mSession->Poll(); 这个方法 用于轮询所有的数据。这个方法是 RTPSession 里对数据处理的主要方法,务必要弄明白它的原理,代码如下 :

int RTPSession::Poll() {

int status;



if (!created)

    return ERR_RTP_SESSION_NOTCREATED;

if (usingpollthread)

    return ERR_RTP_SESSION_USINGPOLLTHREAD;

/*

真正的对 socket 的操作,它把接受到的 RTP 和 RTCP 数据分别放到相应的队列里( awpacketlist 队列),并在 ProcessPolledData () 里处理了对应队列里的数据

*/

if ((status = rtptrans->Poll()) < 0) 

    return status;

return ProcessPolledData();  // 处理收到的数据,对应于 RFC3550 的逻辑部分

}

ProcessPolledData ()这个东东,里面的逻辑是相当多的,因为它处理了所有收到的 RTP 和 RTCP 包,并且根据协议对一些回复 RTCP 包的处理也在这个方法里,所以要修改 RTCP 包,那么这个方法就是切入点了。

在方法里,我们看到了一个循环,毫无疑问,这个东东就是遍历 rtptrans->Poll() 所收到的包,它放在了一个队列里( RTP 和 RTCP 都在同一个队列)

while ((rawpack = rtptrans->GetNextPacket()) != 0) {

 ……

}

那我们来一一分析,这个 while 循环所干的东西 :)

int RTPSession::ProcessPolledData() {

RTPRawPacket *rawpack;

int status;



SOURCES_LOCK

while ((rawpack = rtptrans->GetNextPacket()) != 0) {



    sources.ClearOwnCollisionFlag();

    // 清除了 SSRC 的冲突标记,因为根据 RFC3550, 如果 SSRC 冲突的话,应该要发送  

    //BYE 包的,所以,先上这个标记回到初始值。 



    // since our sources instance also uses the scheduler (analysis of incoming packets)

    // we'll lock it

    SCHED_LOCK

// 这东东对收到的 RTP 和 RTCP 包进行处理,例如建立 SSRC , CCRC 队列和

//SSRC 冲突标记、许多变量值的设置等等。

    if ((status = sources.ProcessRawPacket(rawpack, rtptrans, acceptownpackets)) < 0) {

        SCHED_UNLOCK

        SOURCES_UNLOCK

         RTPDelete(rawpack, GetMemoryManager());

        return status;

    }

    SCHED_UNLOCK

    // 检查是否 SSRC 产生了冲突,如果检测到的冲突,那么就应当发送 BYE 包了 

    if (sources.DetectedOwnCollision()) // collision handling!

    {

        printf("if collision/n");

        bool created;

        // created 的值决定了我们是否需要发送 BYE 包,如果冲突列表里,有了对应 

// 的地址,那么将不发送 BYE 包,否则发送

        if ((status = collisionlist.UpdateAddress(rawpack->GetSenderAddress(), rawpack->GetReceiveTime(), &created)) < 0) {

             printf("if collisionlist updateAddress/n");

            SOURCES_UNLOCK

            RTPDelete(rawpack, GetMemoryManager());

            return status;

        }

        // 需要生成一个新的 BYE 包 

        if (created)

        { // change our own SSRC

            printf("if created/n");

            PACKSENT_LOCK

                    bool hassentpackets = sentpackets;

            PACKSENT_UNLOCK

             // 如果我们已经用冲突的 SSRC 发送了 RTP 数据,那么就生成一个新的 

 //BYE 包,如果没有发送 RTP 的数据,那么这个时候发送 BYE 包是没有 

 // 意义的 

            if (hassentpackets) {

                // Only send BYE packet if we've actually sent data using this

                // SSRC

                printf("if hassentpackets/n");

                RTCPCompoundPacket *rtcpcomppack;



                BUILDER_LOCK

                // 生成一个新的 BYE 包 

                if ((status = rtcpbuilder.BuildBYEPacket(&rtcpcomppack, 0, 0, useSR_BYEifpossible)) < 0) {

                    printf("buildbytpacket/n");

                    BUILDER_UNLOCK

                     SOURCES_UNLOCK

                    RTPDelete(rawpack, GetMemoryManager());

                    return status;

                }

                BUILDER_UNLOCK

                // 推入队列 

                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_LOCK

                     rtcpsched.ScheduleBYEPacket(rtcpcomppack->GetCompoundPacketLength());

                    SCHED_UNLOCK

                }

            }

            // bye packet is built and scheduled, now change our SSRC

            // and reset the packet count in the transmitter



            BUILDER_LOCK

            // 生成新的 SSRC

            uint32_t newssrc = packetbuilder.CreateNewSSRC(sources);

            BUILDER_UNLOCK



            PACKSENT_LOCK

            sentpackets = false;

             PACKSENT_UNLOCK



             // 删除旧的 SSRC

            if ((status = sources.DeleteOwnSSRC()) < 0) {

                printf("sources.DeleteOwnSSRC/n");

                SOURCES_UNLOCK

                 RTPDelete(rawpack, GetMemoryManager());

                return status;

            }

             // 绑定新的 SSRC

            if ((status = sources.CreateOwnSSRC(newssrc)) < 0) {

                printf("sources.CreateOwnSSRC/n");

                SOURCES_UNLOCK

                RTPDelete(rawpack, GetMemoryManager());

                return status;

            }

        }

    }

    RTPDelete(rawpack, GetMemoryManager());

}//end while



SCHED_LOCK

RTPTime d = rtcpsched.CalculateDeterministicInterval(false);

SCHED_UNLOCK



RTPTime 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 stuff



SCHED_LOCK

        bool istime = rtcpsched.IsTime(); // 计算是否到了发送 RTCP 的时间

SCHED_UNLOCK



if (istime) {

    printf("istime/n");

    RTCPCompoundPacket *pack;

     // we'll check if there's a bye packet to send, or just a normal packet

    if (byepackets.empty()) {  // 没有 BYE 包发送就发送正常的 RTCP 包

        printf("byepacket empty and send RTCP packet/n");

// 是否支持 non-compound 的发送

        if (allowNonCompoundRTCP == false) {

            BUILDER_LOCK

             printf("rtcpbuilder.BuildNextPacket with compound/n");

            // 生成一个新的 RTCP 包 

            if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0) {

                BUILDER_UNLOCK

                SOURCES_UNLOCK

                return status;

             }

        }else if (allowNonCompoundRTCP == true) { 

            if (firstSendRTCP) {

                BUILDER_LOCK

                printf("rtcpbuilder.BuildNextPacket with compound/n");

// 生成一个新的 RTCP 包,根据协议,发送 non-compound 之前,必 // 须保证有一个 compound 的包已经发送

                if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0) {

                    BUILDER_UNLOCK

                    SOURCES_UNLOCK

                    return status;

                }

            }else {

                BUILDER_LOCK

                printf("rtcpbuilder.BuildNextPacket with non-compound/n");

               // 生成一个新的 non compound RTCP 包

                if ((status = rtcpbuilder.BuildNextPacketWithNonCompound(&pack)) < 0) {

                    BUILDER_UNLOCK

                    SOURCES_UNLOCK

                    return status;

                 }

            }

            firstSendRTCP = false;

        }



        BUILDER_UNLOCK

        // 通过底层 socket ,发送出去咯 

        if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(), pack->GetCompoundPacketLength())) < 0) {

            printf("rtptrans->SendRTCPData error!/n");

            SOURCES_UNLOCK

            RTPDelete(pack, GetMemoryManager());

            return status;

        }



        PACKSENT_LOCK

        sentpackets = true;

        PACKSENT_UNLOCK



        OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering

    } else { // 如果 BYE 队列不为空,优先发送 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_UNLOCK

            RTPDelete(pack, GetMemoryManager());

            return status;

        }



        PACKSENT_LOCK

        sentpackets = true;

        PACKSENT_UNLOCK



        OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering



        if (!byepackets.empty()) // more bye packets to send, schedule them

        {

            printf("byepackets.empty/n");

            SCHED_LOCK    

            rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength());

             SCHED_UNLOCK

        }

    }



    SCHED_LOCK

    rtcpsched.AnalyseOutgoing(*pack);

    SCHED_UNLOCK



    RTPDelete(pack, GetMemoryManager());

}

SOURCES_UNLOCK

return 0;

}

猜你喜欢

转载自blog.csdn.net/qq_17368865/article/details/80489563