https://www.cnblogs.com/wyqfighting/archive/2013/03/05/2943992.html
Getting started with the RTPSession class
=============================================
所有的类和函数是` JRTPLIB `命名空间的一部分,为例简便申明此名称空间:
using namespace jrtplib;
使用RTP协议,你必须创建一个rtpsession对象。构造函数
接受两个参数,一个rtprandom对象的实例,和一个rtpmemorymanager对象实例。
现在,我们将保持简单,并使用 默认设置,所以这是我们的代码到目前为止:
RTPSession session;
实际创建会话(session),你必须调用Create成员函数,
此函数需要三个参数:
第一个是RTPSessionParams型即指定会话的常规选项。
必须明确设置该类的一个参数,否则将不会成功创建会话。
此参数是您打算发送的数据的时间戳单位,
可以通过在该间隔中的样本数除以一定的时间间隔(秒)来计算。
因此,假设我们将发送8000 赫兹的语音数据,我们可以使用这个代码:
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0 /8000.0 );
其他会话参数可能取决于您打算使用的实际RTP配置文件。
在创建函数的第二个参数是一个指向一个rtptransmissionparams实例,
描述了该传输组件参数。第三个参数选择将使用的传输组件的类型。
默认情况下,在IPv4发射机使用UDP,对于这个特定的发射器,
传输参数类型应该是RTPUDPv4TransmissionParams。
假设我们想要我们的RTP portbase(端口形式)是8000 ,我们可以做以下:
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000 );
现在,我们准备调用Create成员函数为RTPSession。返回值存储在整数“status”中,
这样我们可以检查是否出错了。如果该值为负值,则表示出现了一些错误。
说明此错误代码可以通过调用RTPGetErrorString检索:
int status = session.Create(sessionparams,&transparams);
if (status < 0 )
{
std ::cerr << RTPGetErrorString(status) << std ::endl;
exit (-1 );
}
如果会话(session)创建成功,这可能是一个很好的点去指定RTP和RTCP数据应该发送的目的地。
这是通过调用RTPSession类成员函数adddestination去完成。RTPAddress这是一个抽象类,
UDP在IPv4发射机将实际使用的类是RTPIPv4Address。
假设我们想将数据发送到在端口9000 上运行在同一主机上的进程,
我们可以执行以下操作:
uint8_t localip[]={127 ,0 ,0 ,1 };
RTPIPv4Address addr(localip,9000 );
status = session.AddDestination(addr);
if (status < 0 )
{
std ::cerr << RTPGetErrorString(status) << std ::endl;
exit (-1 );
}
如果JRTPlib以JThread支持的情况下编译,输入的数据在后台处理。
如果jthread支持在编译时没有被启用 或 如果在会话参数中指定了不使用轮询线程的参数 ,
你将必须调用RTPSession成员函数来处理传入的数据,必要时定期发送RTCP包。
现在,我们假设轮询线程以启用。我们希望每分钟发送包含20 毫秒(或160 个样本)的数据包,
并且我们想指出何时收到了来自其他人的数据包。
又假设我们有L8数据(RFC 3551 中定义的)和要使用的负载类型96 。
首先,我们将设置一些默认值:
session.SetDefaultPayloadType(96 );
session.SetDefaultMark(false );
session.SetDefaultTimestampIncrement(160 );
下一步,
我们将创建包含160 个沉默样本缓冲区并创建一个标明20 毫秒(或0.020 秒)的RTPTime实例。
我们还将存储当前时间,这样我们就知道一分钟过去了。
uint8_t silencebuffer[160 ];
for (int i = 0 ; i < 160 ; i++)
silencebuffer[i] = 128 ;
RTPTime delay(0.020 );
RTPTime starttime = RTPTime::CurrentTime();
接下来,
将显示主循环。在这个循环中,将发送一个包含160 字节有效载荷数据的包。
然后,可以进行数据处理,但这一部分将在后面的文本中描述。
最后,我们将等待20 毫秒,并检查是否已经过了六十秒
bool done = false ;
while (!done)
{
status = session.SendPacket(silencebuffer,160 );
if (status < 0 )
{
std ::cerr << RTPGetErrorString(status) << std ::endl;
exit (-1 );
}
RTPTime::Wait(delay);
RTPTime t = RTPTime::CurrentTime();
t -= starttime;
if (t > RTPTime(60.0 ))
done = true ;
}
关于会话参与者、数据包检索等信息,
可以在调用RTPSession类成员函数RTPSession::EndDataAccess和RTPSession::BeginDataAccess之间处理。
这可以确保后台线程不试图更改您试图访问的同一数据。
我们可以使用RTPSession类成员函数RTPSession::GotoFirstSource和RTPSession::GotoNextSource遍历参与者
使用RTPSession::GetNextPacket成员函数可以取出当前选中的参与者的数据包
并返回一个指向参与者实例的指针。
当你不再需要这个包时,它必须被删除。传入数据的处理将如下:
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0 )
{
std ::cout << "Got packet with extended sequence number "
<< packet->GetExtendedSequenceNumber()
<< " from SSRC " << packet->GetSSRC()
<< std ::endl;
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
关于当前选择源的信息可以调用RTPSession类成员函数GetCurrentSourceInfo得到,
这个函数返回一个RTPSourceData实例,
此实例包含这个源所有的信息:来自这个源发送者报告,接收报告,SDES信息等。
另外,包也可以直接被处理在没有遍历这个源的情况下。
方法是:
通过重写RTPSession::OnValidatedRTPPacket成员函数.
============》》(the example code in `example6.cpp` illustrates this approach.)
当主循环完成后,我们将发送一字节数据包去通知其他的参与者程序将退出,接着清理RTPSession类。
另外,我们要等待最多10 秒,以确保此数据包完成发送,否则次数据包将可能不会被发送。
delay = RTPTime(10.0 );
session.BYEDestroy(delay,"Time's up" ,9 );
============》》The complete code of the program is given in `example2.cpp`.
除非另有说明,
当返回错误时,返回类型为“int”的函数将返回负值,并在成功时为零或正值。
可以通过使用RTPGetErrorString函数得到错误码的描述信息。
此函数被申明在 rtperrors.h 头文件中。
Memory management
===================
你可以写你自己的内存管理器从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);
现在,
所有的内存分配和释放将使用` AllocateBuffer ` 和 ` FreeBuffer ` 。
RTPMemoryManager::AllocateBuffer 成员函数的第二个参数表示次内存块的目的是什么,
这允许你处理不同类型的数据。
随着内存管理系统的引入,RTPSession类扩展了RTPSession::DeletePacket 和RTPSession::DeleteTransmissionInfo
成员函数。这些成员函数可以分别用来释放 RTPPacket实例 和 RTPTransmissionInfo实例。