JRTPLIB 官方文档翻译

来源:互联网 发布:nba2k16自建球员数据 编辑:程序博客网 时间:2024/05/16 23:15

JRTPLIB v3.9.1 官方文档翻译


MainPage JRTPLIB

Author: Jori Liesenborgs
翻译: Roysin

简介

该文档是JRTPLIB的使用说明,JRTPLIB是完全面向对象(object-oriented)的。该库用C++开发,它致力于帮助开发人员更轻松的使用RTP协议(Real-time Transport Protocol)。使用JRTPLIB可以让开发者不用关心SSRC冲突,调度,以及发送RTCP数据。开发者只需要提供需要传输的负载(payload)数据即可,而且JRTPLIB同时给予开发者访问RTP和RTCP数据的权限。

设计思想

JRTPLIB提供了几个非常有用的类用来开发RTP程序,其实大部分开发者可能只能用到其中的RTPSession类。该类提供了必要的方法来发送RTP数据,同时在内部自行处理了RTCP。

与2.x版本的区别

最重要的区别之一就是该版本基于RFC 3550,而2.x基于已经废弃的RFC 1889。另外的区别是2.x版本设计之初就是让开发者只需使用RTPSession,无需使用其他的类。但该版本相反,希望更多的模块都能为开发者提供帮助。该版本中还内嵌了指定特定底层协议的代码。这部分代码继承自RTPTransimiter类。目前支持IPV4的UDP和IPv6的UDP。最好不要用RTPSession开发诸如mixer和Translator这类的应用。其他模块可以更好地实现这个功能,比如SSRC表,RTCP 调度器等等。

The library code uses the following copyright license:

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the “Software”), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
*
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
*
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Getting started with the RTPSession Class

所有的类和函数都在jrtblib 命名空间下,所以为了简化代码,我们需要使用该命名空间:
using namespace jrtplib
如要使用RTP,则需创建RTPSession对象实例。RTPSession的构造函数有两个参数:
RTPRandom
RTPMemoryManager
为了保持示例代码足够简单,使用默认的设置创建RTPSession:

RTPSession session;

实际上还需要调用RTPSession的Create成员函数才能真正创建一个会话(session)。Create函数有3个参数:
1. RTPSessionParams sessionparams;
2. RTPTransmissionParams &transparams;
3. RTPTransmitter::TransmissionProtocol protocol

第一个参数RTPSessionParams:该参数指定了会话的通用设置。这个参数中的timestamp unit (时间戳单位)值必须显式地设置,否则会话将会创建失败。时间戳单位是指意图发送的数据的频率,可以通过在一段时间间隔(一般是1秒)采样的数量除以时间间隔得到。假设发送一个8000Hz的语音数据,那么代码将会如下:

    RTPSessionParams sessionparams;    sessionparams.SetOwnTimestampUnit(1.0/8000.0);

其他的session参数可能要取决于实际需求。

第二个参数:RTPTransmissionParams & ,这是一个RTPTransmissionParams实例的引用,其值描述了传输模块的设置。
第三个参数RTPTransmitter::TransmissionProtocol protocol指定使用什么样的传输协议。默认选择的传输协议是UDP over IPv4。如果使用了该默认的protocol,那么transparams参数应为RTPUDPv4TransmissionParams类型。假设我们想要RTP端口为8000,那么可以这么做:

RTPUDPv4TransmissionParams transparams;transparams.SetPortbase(8000);

现在可以真正地调用RTPSession的Create函数了,返回值是一个int类型的status,可以用它来检查是否在创建过程中出现了什么错误。如果该值为负值,那么表明发生了错误,可以用RTPGetErrorString(status)方法得到错误的详细描述。

int status = session.Create(sessionparams,&transparams);if (status < 0){    std::cerr << RTPGetErrorString(status) << std::endl;    exit(-1);}

如果session被成功创建了,这时最好为这个会话(session)指定RTP和RTCP数据的发送目的地。可以通过调用RTPSession的成员函数AddDestination来指定发送目的地。该函数的使用一个RTPAdress类型参数。它是一个抽象类,实际值可以是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);}

如果该库编译的时候支持了JThread,那么数据处理将会在后台进行。如果在编译的时候没有开启JThread支持,或者在session参数中指定不使用poll线程(该线程为JThread线程),那么你需要定期地调用RTPSession的Poll函数来处理接收的数据,可能还要在必要的时期发送RTCP数据。在该文档中我们假设使用poll线程。
假设在1分钟的时间里,需要发送一些packet,每个packet包含20ms(也就是160次采样)的静音数据(silence),而且还想表明从其他人那里接收到了数据,同时也假设有在RFC 3551中定义的L8类型数据,负载类型为96。
首先,设置一些默认值:

session.SetDefaultPayloadType(96);session.SetDefaultMark(false);session.SetDefaultTimestampIncrement(160);

接下来创建一个包含160个静音样本的buffer,同时创建一个RTPTime实例代表20ms(或者0.020s)。还需要保存当前时间点用于判断是否到了1分钟。

uint8_t silencebuffer[160];for (int i = 0 ; i < 160 ; i++)    silencebuffer[i] = 128;RTPTime delay(0.020); // delay indicates 20msRTPTime starttime = RTPTime::CurrentTime();

紧接着的主循环用来发送和处理数据。在这个循环中,包含160 bytes的负载将会被发送,然后进行数据处理(这一部分稍后详细介绍),最后等待20ms检查是否已经过了60s。

bool done = false;while (!done){    status = session.SendPacket(silencebuffer,160);    if (status < 0)    {        std::cerr << RTPGetErrorString(status) << std::endl;        exit(-1);    }//// Inspect incoming data here//    RTPTime::Wait(delay);    RTPTime t = RTPTime::CurrentTime();    t -= starttime;    if (t > RTPTime(60.0))        done = true;}

获取会话参与者的信息、packet读取等等操作必须要在调用RTPSession的成员函数 BeginDataAccess()EndDataAccess()之间。调用这两个函数,保证了后台线程不会改变开发者想自己处理的这部分数据。通过调用GotoFirstSourceGotoNextSource遍历会话的参与者,用GetNextPacket获取来自于当前参与者的packets。该函数返回一个指向RTPPacket类的指针。当不需要这些packet的时候,需要将其删除。处理接收到的数据的流程如下:

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();

当前数据源的信息可以通过调用GetCurrentSourceInfo 获取,该函数返回RTPSourceData实例的指针,RTPSourceData 类包含了数据源的所有信息,比如:发送者报告、接收者报告, SDES信息等。
当主循环结束时,就要发送一个BYE packet来通知其他与会者我要离开了,然后还要清理RTPSession类。当然我们可能要等待最多10s的时间让BYE packet发送完毕,否则时间太短可能导致即使离开该会话,其他与会者也接收不到BYE信息。

delay = RTPTime(10.0);session.BYEDestroy(delay,”Time’s up”,9);

完整代码:

#include "rtpsession.h"#include "rtpsessionparams.h"#include "rtpudpv4transmitter.h"#include "rtpipv4address.h"#include "rtptimeutilities.h"#include "rtppacket.h"#include <stdlib.h>#include <iostream>using namespace jrtplib;int main(void){#ifdef WIN32    WSADATA dat;    WSAStartup(MAKEWORD(2,2),&dat);#endif // WIN32    RTPSession session;    RTPSessionParams sessionparams;    sessionparams.SetOwnTimestampUnit(1.0/8000.0);    RTPUDPv4TransmissionParams transparams;    transparams.SetPortbase(8000);    int status = session.Create(sessionparams,&transparams);    if (status < 0)    {        std::cerr << RTPGetErrorString(status) << std::endl;        exit(-1);    }    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);    }    session.SetDefaultPayloadType(96);    session.SetDefaultMark(false);    session.SetDefaultTimestampIncrement(160);    uint8_t silencebuffer[160];    for (int i = 0 ; i < 160 ; i++)        silencebuffer[i] = 128;    RTPTime delay(0.020);    RTPTime starttime = RTPTime::CurrentTime();    bool done = false;    while (!done)    {        status = session.SendPacket(silencebuffer,160);        if (status < 0)        {            std::cerr << RTPGetErrorString(status) << std::endl;            exit(-1);        }        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();        RTPTime::Wait(delay);        RTPTime t = RTPTime::CurrentTime();        t -= starttime;        if (t > RTPTime(60.0))            done = true;    }    delay = RTPTime(10.0);    session.BYEDestroy(delay,"Time's up",9);#ifdef WIN32    WSACleanup();#endif // WIN32    return 0;}

Error Codes

正常情况下,函数返回的int类型如果为负值代表有错误产生,而0或者正值则代表函数执行成功。返回错误值的error code描述可以通过调用RTPGetErrorString(int)获得,该函数在rtperrors.h中声明。

Memory Management

你可以继承RTPMemoryManager来自定义memory manager.下面的代码是一个基本示范:

class MyMemoryManager : public RTPMemoryManager{    public:    MyMemoryManager() { }    ~MyMemoryManager() { }    void *AllocateBuffer(size_t numbytes, int memtype)    {        return malloc(numbytes);    }     void FreeBuffer(void *p)    {        free(p);    }};

在RTPSession的构造函数中,你可以指定要使用的memory manager。

MyMemoryManager mgr;RTPSession session(0, &mgr);

现在,所有的内存分配和回收都将使用mgr中的AllocateBufferFreeBuffer实现。
注意到RTPMemoryManager::AllocateBuffer()函数的第二个参数int memtype,该参数用来指示该内存块(memory block)的用途,这样使得你可以用不同方式处理不同类型的数据。在RTPSession中传入了memory management system之后,RTPSession::DeletePacketRTPSession::DeleteTransmissionInfo这两个函数便使RTPSession得到扩展,这两个函数分别用于回收RTPPacket实例额RTPTransmissionInfo实例。

联系方式

有任何问题或者想法请联系jori.liesenborgs@gmail.com
jrtplib项目主页:http://research.edm.uhasselt.be/jori/jrtplib/jrtplib.html

0 0
原创粉丝点击