现在的位置: 首页 > 综合 > 正文

jrtplib的使用

2017年12月13日 ⁄ 综合 ⁄ 共 10576字 ⁄ 字号 评论关闭
JRTPLIB库的使用
文档:
http://research.edm.uhasselt.be/jori/jrtplib/documentation/index.html
一些介绍:

http://doserver.net/read.php?1028
http://doserver.net/read.php/1027.htm
http://doserver.net/read.php/1685.htm
现在开始对几个example分析一下,不过,就没有文档吗?
这里,详细的解释了几个例子:
http://hi.baidu.com/hanyuejun2006/blog/item/8a8ed939a9e344f53b87ce23.html
这里算一个:
http://xiyong8260.blog.163.com/blog/static/665146212008824112748499/
重要的是里面还讲了一些嵌入式方面的内容。
收和发的例子:
http://blog.chinaunix.net/u2/61880/showart_728528.html
比较详细的系列文章:http://www.cnitblog.com/tinnal/archive/2009/01/01/53342.html
PS:关于POLL的问题,发现只有调用者这个函数的时候,才会查询是否有包发过来,才会接收包。
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.

关于例程可以分为以下几个部分:


(一)BASIC USAGE:
1)SET PARAMS
    关于会话的参数
2)SET TRANSPARAMS
    关于传输层的参数
3)CREATE SESSION
    创建会话
4)SET PACKET ATTRIBUTES
    包的属性设置
5)ADD DESTINATION
    添加目的地址 
6)PREPARE DATA
    准备数据
7)SEND PACKET
    发送包
8)DATAACCESS
    数据处理(锁定操作,是指此时POLL线程不能改变正在处理的数据)
9)BYE
    退出会话
example:
#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtpipv4address.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>

void checkerror(int rtperr)
{
    if(rtperr < 0)
    {
        std::cout<<"ERROR:"<<RTPGetErrorString(rtperr)<<std::endl;
        exit(-1);
    }
}

int main()
{
    RTPSession sess;
    uint16_t portbase;
    int status;

    //set params


    RTPSessionParams sessparams;
    sessparams.SetOwnTimestampUnit(1.0/10.0);
    sessparams.SetAcceptOwnPackets(true);

    //set transparams


    RTPUDPv4TransmissionParams transparams;
    transparams.SetPortbase(8000);

    //create a session


    status = sess.Create(sessparams, &transparams);
    checkerror(status);

    //set default packet attributes


    sess.SetDefaultPayloadType(0);
    sess.SetDefaultMark(false);
    sess.SetDefaultTimestampIncrement(10);

    //destination address


    uint16_t destport;
    uint32_t destip;
    std::string ipstr;
    std::cout<<"Enter the IP: "<<std::endl;
    std::cin>>ipstr;
    destip = inet_addr(ipstr.c_str());
    if(destip == INADDR_NONE)
    {
        std::cerr<<"Bad IP"<<std::endl;
        exit(-1);
    }
    destip = ntohl(destip);
    //uint8_t localip[] = {192, 168, 0, 3};


    RTPIPv4Address addr(destip, 8000);

    //add destination


    status = sess.AddDestination(addr);
    checkerror(status);

    //prepare payload data


    uint8_t silencebuffer[160];
    for(int i = 0; i < 160; i++)
    {
        silencebuffer[i] = 128;
    }

    //for time checking


    RTPTime delay(0.020);
    RTPTime starttime = RTPTime::CurrentTime();

    bool done = false;
    sess.Poll();


    while(!done)
    {
        status = sess.SendPacket(silencebuffer, 160);
        checkerror(status);

        //receive data


        sess.BeginDataAccess();
        if(sess.GotoFirstSource())
        {
            do
            {
                RTPPacket *pack;
                while((pack = sess.GetNextPacket()) != NULL)
                {
                    std::cout<<"Got packet!"<<std::endl;
                    std::cout<<"sequence number: "<<pack->GetSequenceNumber()<<std::endl;
                    std::cout<<"Extended SN: "<<pack->GetExtendedSequenceNumber()<<std::endl;
                    std::cout<<"SSRC: "<<pack->GetSSRC()<<std::endl;
                    std::cout<<"Data: "<<pack->GetPayloadData()<<std::endl;
                    sess.DeletePacket(pack);
                }
            }while(sess.GotoNextSource());
        }
        sess.EndDataAccess();
        
        RTPTime::Wait(delay);
    
        RTPTime t = RTPTime::CurrentTime();
        t -= starttime;
        if(> RTPTime(6, 0))
        {
            done = true;
        }
    }
    
    delay = RTPTime(10.0);
    sess.BYEDestroy(delay, "Time's up", 9);
    return(0);
}


(二)Your Own Session:
可以继承session创建MySession添加自己定制的处理, 这些处理是由session的protected methods 定义的。参考文档可以确定要定制的处理。

example:

#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

class MyRTPSession : public RTPSession
{
    protected:

//what to do on new source?
        void OnNewSource(RTPSourceData *dat)
        {
            if(dat->IsOwnSSRC())
            {
                return;
            }
            uint32_t ip;
            uint16_t port;
            if(dat->GetRTPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                (dat->GetRTPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort();
            }
            else if(dat->GetRTCPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                    (dat->GetRTCPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort()-1;
            }
            else
            {
                return;
            }
            RTPIPv4Address dest(ip, port);
            AddDestination(dest);

            struct in_addr inaddr;
            inaddr.s_addr = htonl(ip);
            std::cout<<"Adding destination"<<std::string(inet_ntoa(inaddr))
                <<":"<<port<<std::endl;
        }
//what to do on byepacket?
        void OnBYEPacket(RTPSourceData *dat)
        {
            std::cout<<"OnBYEPacket"<<std::endl;
            if(dat->IsOwnSSRC())
            {
                return;
            }
            uint32_t ip;
            uint16_t port;
            if(dat->GetRTPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                    (dat->GetRTPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort();
            }
            else if(dat->GetRTCPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                    (dat->GetRTCPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort()-1;
            }
            else
            {
                return;
            }
            RTPIPv4Address dest(ip, port);
            DeleteDestination(dest);
            
            struct in_addr inaddr;
            inaddr.s_addr = htonl(ip);
            std::cout<<"Deleting destination"
                <<std::string(inet_ntoa(inaddr))
                <<":"<<port<<std::endl;
        }
//what to do on remove source?
        void OnRemoveSource(RTPSourceData *dat)
        {
            std::cout<<"OnRemoveSource"<<std::endl;
            if(dat->IsOwnSSRC())
            {
                return;
            }
            if(dat->ReceivedBYE())
            {
                return;
            }
            uint32_t ip;
            uint16_t port;
            if(dat->GetRTPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                    (dat->GetRTPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort();
            }
            else if(dat->GetRTCPDataAddress() != 0)
            {
                const RTPIPv4Address *addr = (const RTPIPv4Address *)
                    (dat->GetRTCPDataAddress());
                ip = addr->GetIP();
                port = addr->GetPort()-1;
            }
            else
            {
                return;
            }
            RTPIPv4Address dest(ip, port);
            DeleteDestination(dest);
            
            struct in_addr inaddr;
            inaddr.s_addr = htonl(ip);
            std::cout<<"Deleting destination"
                <<std::string(inet_ntoa(inaddr))
                <<":"<<port<<std::endl;
        }
};

(三)Important Classes:
分析参数:RTPSourceData-HOW TO KNOW RTCP?
从(二)中,你可能已经了解到了On...等定义了session在收发包时的动作,而为了分析这些包的参数,你需要的是RTPSourceData这个参数。Source指的是一个会话的参与者,在本地保存了一个参与者列表,和与之相关的信息。这些信息是从该源发送的RTCP信息提取的。
为了便于和理论分析比较,现在将5中RTCP分组报告和它们的实现列出:
指的注意的是:据我目前的理解是,本地维护一个源的列表,而这些RTCP分组,并没有它们的实体,而是得到这些分组后就分析为和一个源描述符,即RTPSource关联的数据。应该是遍历这个源列表,而获得它们的信息。而如何遍历的问题,稍后讨论。

发送者报告(SR)

V| P| RC| PT=SR=200| LEN|


发送者SSRC (已关联)

 


NTP时间戳(高32位) SR_GetNTPTimestamp ()

 

NTP时间戳(低32位)

 


RTP时间戳 SR_GetRTPTimestamp () 

 

 


发送者分组计数器 SR_GetPacketCount()

 

 


发送者字节计数器 SR_GetByteCount ()

 

 


...(下面是这个发送者所发送的接收者报告,在下面和RR一起讨论)

 


附加信息:

这个源是否有发送发送者报告

SR_HasInfo ()

这个发送者报告接收的时间

SR_GetReceiveTime ()

以及以SR_Prev_开头的,获得倒数第二个发送者报告的信息。

接收者报告(RR)

V| P| RC| PT=SR=201| LEN|

 


 

SSRC1(第一个接收者报告块所关联的发送者) (已关联)


分组丢失率 | 丢失分组总数|

扩展的最高序号

间隔抖动

最新的发送者报告时间戳(LSR)

SR最新间隔(DLSR)

附加信息:
这个源是否有发送接收者报告
接收者报告接收时间
以及以RR_Prev_开头的,获得倒数第二个接收者报告的信息。

源描叙分组(SDES)

V| P| RC| PT=SR=202| LEN|

 


SSRC/CSRC1 (已关联)

 

 


SDES项

 

由SDES_Get...等描述

可以判断的是存在一种机制,可以在本地定制自己要发送的SDES包含的信息。

BYE分组(BYE)

V| P| RC| PT=SR=202| LEN|


SSRC/CSRC (已关联)


原因长度| 退出会话原因
GetBYEReason (size_t *len)


 

附加信息(见文档)

 

 

根据以上的信息,大概知道了如何获取一个源的信息;问题是如何遍历这个源列表来处理一个源?
事实上,在大多数的例子里,使用的类只是RTPSession,通过这个类可以管理会话的大部分细节。
管理会话:RTPSession-MANAGE A SESSION
对一次会话的管理,大概有以下几方面:
*创建会话
*退出会话
*管理目的地址(添加,忽略)
*发送和接收数据包(用户只需要关心RTP包),另外,APP包也是由用户负责的
*时间戳设定
*管理SDES信息项
*管理源列表
*管理广播组
...
一般来说,使用一个类都是使用它的public接口,但是你可以像(二)描述的那样,通过继承来定制自己的一些行为。On...
着重讲的是管理源列表。

bool  GotoFirstSource ()
  Starts the iteration over the participants by going to the first member in the table.
bool  GotoNextSource ()
  Sets the current source to be the next source in the table.
bool  GotoPreviousSource ()
  Sets the current source to be the previous source in the table.
bool  GotoFirstSourceWithData ()
  Sets the current source to be the first source in the table which has RTPPacket instances that we haven't extracted yet.
bool  GotoNextSourceWithData ()
  Sets the current source to be the next source in the table which has RTPPacket instances that we haven't extracted yet.
bool  GotoPreviousSourceWithData ()
  Sets the current source to be the previous source in the table which has RTPPacket instances that we haven't extracted yet.
RTPSourceData GetCurrentSourceInfo ()
  Returns the RTPSourceData instance for the currently selected participant.
RTPSourceData GetSourceInfo (uint32_t ssrc)
  Returns the RTPSourceData instance for the participant identified by ssrc, or NULL if no such entry exists. 
bool  GotEntry (uint32_t ssrc)
  Returns true if an entry for participant ssrc exists and false otherwise.
RTPSourceData GetOwnSourceInfo ()
  If present, it returns the RTPSourceData instance of the entry which was created by CreateOwnSSRC. 

迭代的例程:

很明显,这是C++风格,使用了迭代器的抽象。而GetCurrentSourceInfo ()和GetSourceInfo (uint32_t ssrc)的返回类型-RTPSourceData可以使我们得以获取源列表的RTCP信息。
使用这种迭代的例程:
 sess.BeginDataAccess();
        if(sess.GotoFirstSource())
        {
            do
            {
                RTPPacket *pack;
                while((pack = sess.GetNextPacket()) != NULL)
                {
            //deal with the packet
                    sess.DeletePacket(pack);
                }
            }while(sess.GotoNextSource());
        }
sess.EndDataAccess();
以上,我们可以获得访问源的信息的机制。

抱歉!评论已关闭.