关于开源的RTP——jrtplib的使用(2)
这段时间在研究
RTP,好几天了,今天又来总结一下。
关于
jrtplib环境的建立,可以见我以前写的总结,现在我主要来谈谈jrtplib3.71下的几个example的学习。
一、
sample是一个简单的IPv4的列子,它实现了RTP在本机上的数据的传输。
1、初始化。
我们知道
RTP是通常是使用UDP协议来实现数据的传输,在windows环境下,当然要用到我们熟悉的套接字的使用,所以我们先要进行初始化,加载套接字库。
#ifdef WIN32 WSADATA dat; WSAStartup(MAKEWORD(2,2),&dat); #endif // WIN32 RTPSession sess; //当然在我们程序结束的时候,我们要清理套接字库。 #ifdef WIN32 WSACleanup(); #endif // WIN32 //还有关于头文件,我们需要用到以下一些: #include "rtpsession.h" //定义了RTPSession #include "rtppacket.h" //定义了RTPPacket数据包 #include "rtpudpv4transmitter.h" //定义了RTPSession的第二个参数 //RTPUDPv4TransmissionParams #include "rtpipv4address.h" //定义了rtpipv4address #include "rtpsessionparams.h" //定义了RTPSession的第一个参数 // RTPSessionParams #include "rtperrors.h" //定义了RTP中的错误信息 //获得出错信息,我们在使用时不可避免地要出错,故我们可以通过//jrtplib的函数来获得我们出错的信息,方法如下: void checkerror(int rtperr) { if (rtperr < 0) { std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl; exit(-1); } }
函数
RTPGetErrorString(…)根据出错返回的一个负数来判断,利用jrtplib采用的统一出错机制返回的是一个C++中标准的字符串std::string,表示出错的信息,比喻我们指定的Portbase不是一个偶数。(为什么,以下要讲)
2、关于
RTPSession对象设置
由于要使用套接字,故我们在使用之前一定要为我们的监听
socket指定一个监听端口,也就是这里的portbase的值。我们可以通过调用RTPSession的第二个参数RTPUDPv4TransmissionParams的成员函数来设定,
transparams.SetPortbase(portbase);
还有就是我们要通过
RTPSession的第一个参数来设定以下一些值:
sessparams.SetOwnTimestampUnit(1.0/10.0);
//注意这个值我们一定要设置,
The local timestamp unit MUST be set, otherwise
//RTCP Sender Report info will be calculated wrong, In this case, we'll be sending
//10 samples each second, so we'll put the timestamp unit to (1.0/10.0)
//设置时间戳是一件很重要的事情,是
RTP会话初始化过程所要进行的另外一项重要工
//作,他的单位是秒,如:当使用
RTP会话传输8000Hz采样的音频数据时,由于时戳
//每秒钟将递增
8000,所以时戳单元相应地应该被设置成1/8000:
sessparams.SetAcceptOwnPackets(true);
//通过这个函数我们可以设置是不是接收我们自定义的数据包。
3、数据发送
我想当我们要想建立连接的时候,我们就要让发送端知道要发送到的主机的
IP地址,在jrtplib中我们可以通过RTPSession成员函数AddDestination()、
DeleteDestination()和 ClearDestinations()来完成。如下面是将数据发送给本机的
6000号端口:
unsigned long addr = ntohl(inet_addr("127.0.0.1"));
sess.AddDestination(addr, 6000);
当然我们还可以这样来完成加入一个客户端,
RTPIPv4Address addr(destip,destport);//destip为客户端
IP地址,destport为客户端//端口号
status = sess.AddDestination(addr);
checkerror(status);
目标地址全部指定之后,接着就可以调用RTPSession类的SendPacket()方法,向所有的目标地址发送流媒体数据。SendPacket()是RTPSession类提供的一个重载函数,它具有下列多种形式:
int SendPacket(void *data,int len)
int SendPacket(void *data,int len,unsigned char pt,bool mark,
unsigned long timestampinc)
int SendPacket(void *data,int len,unsigned short hdrextID,void *hdrextdata,
int numhdrextwords)
int SendPacket(void *data,int len,unsigned char pt,bool mark,
unsigned long timestampinc,unsigned short hdrextID,
void *hdrextdata,int numhdrextwords)
SendPacket()
最典型的用法是类似于下面的语句,其中第一个参数是要被发送的数据,而第二个参数则指明将要发送数据的长度,再往后依次是RTP负载类型、标识和时戳增量。如下所示:
status = sess.SendPacket((void *)"1234567890",10,0,false,10);
checkerror(status);
对于同一个RTP会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB允许将它们设置为会话的默认参数,这是通过调用 RTPSession类的SetDefaultPayloadType()、SetDefaultMark()和 SetDefaultTimeStampIncrement()方法来完成的。为RTP会话设置这些默认参数的好处是可以简化数据的发送,例如,如果为 RTP会话设置了默认参数:
session.SetDefaultPayloadType(96);//
注意这个参数不能随便设置,参考RFC3551
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
在设置了以上的值后,我们可以这样来发送数据:
status = sess.SendPacket((void *)"1234567890",10);
3
、数据接收
对于流媒体数据的接收端,首先需要调用RTPSession类的PollData()方法来接收发送过来的RTP或者RTCP数据报。由于同一个 RTP会话中允许有多个参与者(源),你既可以通过调用RTPSession类的GotoFirstSource()和GotoNextSource() 方法来遍历所有的源,也可以通过调用RTPSession类的GotoFirstSourceWithData()和 GotoNextSourceWithData()方法来遍历那些携带有数据的源。在从RTP会话中检测出有效的数据源之后,接下去就可以调用 RTPSession类的GetNextPacket()方法从中抽取RTP数据报,当接收到的RTP数据报处理完之后,一定要记得及时释放。下面的代码示范了该如何对接收到的RTP数据报进行处理:
session.BeginDataAccess(); if (session.GotoFirstSource()){ do{ RTPPacket *packet; while ((packet = session.GetNextPacket()) != 0){ cout << "Got packet with extended sequence number " << packet->GetExtendedSequenceNumber() << " from SSRC " << packet->GetSSRC() <
JRTPLIB为RTP数据报定义了三种接收模式,其中每种接收模式都具体规定了哪些到达的RTP数据报将会被接受,而哪些到达的RTP数据报将会被拒绝。通过调用RTPSession类的SetReceiveMode()方法可以设置下列这些接收模式:
①
RECEIVEMODE_ALL 缺省的接收模式,所有到达的
RTP数据报都将被接受;
② RECEIVEMODE_IGNORESOME 除了某些特定的发送者之外,所有到达的
RTP数据报都将被接受,而被拒绝的发送者列表可以通过调用AddToIgnoreList()、ClearIgnoreList() 和DeleteFromIgnoreList()方法来进行设置;
③ RECEIVEMODE_ACCEPTSOME 除了某些特定的发送者之外,所有到达的
RTP数据报都将被拒绝,而被接受的发送者列表可以通过调用AddToAcceptList ()、ClearAcceptList ()和eleteFromAcceptList方法来进行设置。
4、运行程序
在运行程序之前,我们要知道,这是基于
UDP协议的数据报服务。我们的example1是在本机上实现的RTP传输,并且只有一个RTPSession对象,所以我们的监听和接收的端口是同一个,所以此时我们的portBase要和我们加入到RTPSession对象中的客户端的端口一致,如上面我们可以都设置成6000.但是如果是在两个线程中,我们就要注意了,服务器端口和客户端口一定不一样,这也是基本的知识,用的时候要注意,多思考。