大家好,欢迎来到IT知识分享网。
1 从RTPSession类开始
所有的类和函数都是jrtplib名字空间的一部分,为了简化代码,我们声明我们使用的是如下的名字空间:
using namespace jrtplib;
为了使用RTP,首先要创建一个RTPSession对象.这个构造函数接受两个参数:一个RTPRandom类的实例,一个RTPMemoryManager类的实例.现在,我们使用最简单的默认的设置,如下:
RTPSession session;
1.1 创建Session
调用带有三个参数的Create函数.
参数1
RTPSessionParams类型.指定这个session的大概的选项.这个类里面的一个参数必须要设置好,否则session就会创建失败.就是你要发送的数据的时间戳的单位,这个参数可以用一个时间段内的采样数去除以这个时间段的长度.因此,假设我们要发送一个8000Hz的语音数据,可以用如下的代码:
RTPSessionParams sessionParams;
sessionParams.SetOwnTimestampUnit(1.0/8000.0);
参数2
这个参数就真的取决于你想要一起用的RTP profile.
它是一个指向RTPTransmissionParams实例的指针,并且为传输部分描述参数.
参数3
选择要使用的传输组件,默认情况下,使用UDP通过IPV4的transmitter,并且对于这个特定的transmitter,那么参数2中的传输参数应该设为RTPUDPv4TransmissionParams类型的.因此,假设我们使用8000端口,我们可以使用如下的代码:
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000);
现在我们可以调用RTPSession类的Create成员函数,代码如下:
int status = session.Create(sessionparams,&transparams); if (status
{
std::cerr <
exit(-1);
}
如果Create函数出错,那么返回一个负值,它指出出错了.可以用RTPGetErrorString()函数来获得.
当session创建成功了,此时,要设置RTP和RTCP数据要发送的目的地.这是通过调用RTPSession的成员函数AddDestination来实现的.这个函数带一个RTPAddress类型的参数,RTPAddress是一个抽象类,对于UDP通过IPV4的transmitter,真正的子类是RTPIPv4Address.假设把数据向运行在9000端口的进程发送,那么代码如下:
uint8_t localip[]={127,0,0,1};
RTPIPv4Address addr(localip,9000);
status = session.AddDestination(addr); if (status
{
std::cerr <
exit(-1);
}
如果这个库是用JThread支持编译的,那么收到的数据是在后台处理的.以下两种情况:
A JThread支持没有在编译时使能
B 在session参数中指定不使用poll线程
下,必须使用RTPSession的成员函数Poll来处理到达的数据并且必要时发送RTCP数据.
现在,我们先假定我们使能了poll线程.
假设在一分钟内,我们想要发送包含20ms(160个采样)的silence,并且我们想要当一个从其他地方来的包被接收的时候能够被指出来.同样假定我们有L8数据,并且要使用负荷类型为96.首先,我们将要设定一些默认值:
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
下一步,我们要创建包含160个silence采样的缓冲区,并且创建一个表示20ms的RTPTime实例.我们也保存当前时间,这样我们可以知道何时1分钟已经走完了.
uint8_t silencebuffer[160];
for (int i = 0 ; i
silencebuffer[i] = 128;
RTPTime delay(0.020);
RTPTime starttime = RTPTime::CurrentTime();
下一步,是主循环.这个循环中,要发送一个包含160字节的负载数据.然后,数据处理开始进行,这个稍后阐述.最终,我们等待20ms并检测是否60s已经过去.
bool done = false;
while (!done)
{
status = session.SendPacket(silencebuffer,160);
if (status
{
std::cerr <
exit(-1);
}
//
// Inspect incoming data here
//
RTPTime::Wait(delay);
RTPTime t = RTPTime::CurrentTime();
t -= starttime;
if (t > RTPTime(60.0))
done = true;
}
关于会话参与者的信息,以及获得包等的信息,都必须在调用成员函数BeginDataAccess和EndDataAccess之间完成.这样可以保证后台线程不会在你在访问数据的时候,同时改变你的数据.我们逐个访问会话的参与者通过GotoFirstSource和GotoNextSource成员函数.从当前选中的参与者中取得数据包,可以通过成员函数GetNextPacket,这个函数可以返回一个指向RTPPacket类的实例的指针.当你不再需要这个packet的时候,你要delete它.处理到达的数据的过程可以如下:
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
std::cout <
<GetExtendedSequenceNumber()
<GetSSRC()
<
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
当前选中的源的信息可以通过GetCurrentSourceInfo成员函数RTPSession类的来获取.这个函数返回一个指针指向RTPSourceData的指针,这个对象包括了所有的关于source的信息:从那个源来的sender reports,receiver reports,SDES信息等等.
当主循环结束的时候,我们发送一个BYE包来告诉其他参与者我们的分离,并且清理RTPSession类.同样我们需要等最多10s来让BYE包被发送出去,否则,我们只是简单地离开会话,而没有发送BYE包.
delay = RTPTime(10.0);
session.BYEDestroy(delay,”Time’s up”,9);
2 错误码
除非特地指定的,否则都是0或者正返回值表示成功,负值表示出错.可以用RTPGetErrorString获取.
3 内存管理
可以通过继承RTPMemoryManager来写自己的内存管理类.下面是一个简化的实现代码:
class MyMemoryManager : public RTPMemoryManager
{ public:
MyMemoryManager() { }
~MyMemoryManager() { }
void *AllocateBuffer(size_t numbytes, int memtype)
{ return malloc(numbytes);
} void FreeBuffer(void *p)
{
free(p);
}
};
在RTPSession类的构造函数中,可以指定想要使用这个内存管理:
MyMemoryManager mgr;
RTPSession session(0, &mgr);
此时,所有的内存分配和声明都可以通过使用mgr的AllocateBuffer和FreeBuffer来完成.
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/12399.html