jrtplib的使用
转载
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(t > 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关联的数据。应该是遍历这个源列表,而获得它们的信息。而怎样遍历的问题,稍后讨论。
|
接收者报告(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(); 以上,我们能够获得訪问源的信息的机制。
|
|
|
|
|
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。