jrtplib 笔记(1)

 

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体;} p {mso-margin-top-alt:auto; margin-right:0in; mso-margin-bottom-alt:auto; margin-left:0in; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体;} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

 

最近要实现 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;

}

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值