jrtplib学习

jrtplib学习这是JRTPLIB@Conference系列的第三编《JRTPLIB的几个重要类说明》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过tinnal@136.com这个邮箱或博客回复(推荐)和我交

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
这是
JRTPLIB@Conference系列的第三编《JRTPLIB的几个重要类说明》,本系列的主要工作是实现一个基于JRTPLIB的,建立在RTP组播基础上的多媒体视频会议系统。这只是一个实验系统,用于学习JRTPLIB、RTP、和多媒体相关的编程,不是一个完善的软件工程。而且,我只会在业余的时间出于兴趣写一写。有志同道合的朋友可以通过
tinnal@136.com这个邮箱或博客回复(推荐)和我交流。

      上一部《
JRTPLIB@Conference DIY视频会议系统 二、基本例程分析

      这一部的主要内容是要研究一个JRTPLIB常用的几个非常重要的类,在进行JRTPLIB或RTP编程时会经常和这个几类打交道,或都从这些类中继承。

一、RTPSession

      对于大多数的RTP应用程序,RTPSession类可能是JRTPLIB唯一使用的类。它能完全处理RTCP部份的数据包,所以用户可以把精力集中在真正的数据收发。

      要知道RTPSession类在多线程下并不是安全的,因此,用户要通过某些锁同步机制来保证不会出现在不同线程当中调用同一个RTPSession实例。

      RTPSession类有如下的接口。

      • RTPSession(RTPTransmitter::TransmissionProtocol proto = RTPTransmitter::IPv4UDPProto)

      使用proto类型传输层创建一个PRTSession实例。如果proto使用用户自定义(user-defined)传输层,则相应的NewUserDefinedTransmitter()函数必须实现。
ps:这里默认就行了,默认就是IPV4网络。

      • int Create(const RTPSessionParams &sessparams, const RTPTransmissionParams*transparams = 0)

      使用RTPSession参数sessparams和RTPTransmission参数transparams 真正创建一个RTP会话。如果transparams 为NULL,则使用默认的参数。
ps:RTPSessionParams 我们可能要设得比较多,RTPTransmissionParams参数就只要设置其中的端口就行了,端口一定要设对,不然进行组播时,这个进程将不接收数据。设置方式可以看example.cpp。


      • void Destroy()

      离开一个会话但不向其它组成员发送BYE包。
ps:我不推荐用这个函数除非是错误处理,正常离开我们应该用ByeDestroy()。
     

      • void BYEDestroy(const RTPTime &maxwaittime, const void *reason,size t reasonlength)

      发送一个BYE包并且离开会话。在发送BYE包前等待maxwaittime,如果超时,会不发送BYE包直接离开,BYE包会包含你的离开原因reason。相应的reasonlength表示reason长度。
ps:因为BYE包是一个RTCP包,RTCP不是要发就发的,它的发送时间是为了平衡带宽通过计算得出来的,那就很有可能到了要发的时候以经超过了maxwaittime时间了,作者可能认一直保留个这会话这么久没意义。当然,我常常把maxwaittime设得很大

      • bool IsActive()

      看看这个RTPSession实例是否以经通过Create建立了真实的会话。

      • uint32 t GetLocalSSRC()

      返回我们的SSRC。
ps:至于什么是SSRC,去看看RFC3550吧。我说过JRTPLIB只是RTP协议的包装,并没有做任何应用的事情。

      • int AddDestination(const RTPAddress &addr)

      添加一个发送目标。
ps:当然,如果我们使用组播,这里只用调用一次,把我们的组播地址写进去。这样,这组的全部人都能收到你发的包。但是组播可因特网的上设置很烦。而且用组播测试也很烦(组播必须BIND一个端口,如果你想在同一台机器上运行两个软件实例来没试,你就会发现同一个端口BIND两次,当然,后面那次会失败,也就是说测试不了,要测?找两台机器,或用虚拟机jrtplib学习),如果组播不满足,我们就要把组播变在单播,这时就要返复调用这个函数把其它组成员的IP都加进来了。具体可以看看example3.cpp。


      • int DeleteDestination(const RTPAddress &addr)

      从发送地址列表中删除一下地址。

      • void ClearDestinations()

      清除发送地址列表。

      • bool SupportsMulticasting()

      返回JRTPLIB是否支持组播。ps:这里指JRTPLIB本身,不是你的真实网络。编译JRTPLIB库时可能指定。

.

      • int JoinMulticastGroup(const RTPAddress &addr)

      加入一个组播组addr。

      • int LeaveMulticastGroup(const RTPAddress &addr)

       离开一个组播组addr。

      • void LeaveAllMulticastGroups()

      离开所有组播组。
ps:我们可以同时加入多个组播组。.


      • int SendPacket(const void *data, size t len)

      • int SendPacket(const void *data, size t len, uint8 t pt, bool mark,uint32 t timestampinc)

      • int SendPacketEx(const void *data, size t len, uint16 t hdrextID,const void *hdrextdata, size t numhdrextwords)

      • int SendPacketEx(const void *data, size t len, uint8 t pt, boolmark, uint32 t timestampinc, uint16 t hdrextID, const void *hdrextdata,size t numhdrextwords)

     
上面的4个函数都是发送数据包的,我想如果你没有看RTP协议,我说了你也晕。如果你RTP协议看了,再看看RTPSession.h的注识,你就懂了。

      • int SetDefaultPayloadType(uint8 t pt)

      设定默认的RTP PayloadType为PT。
ps:和上面的第一个和第三个发送函数配套。至于应该设个什么数,如果你看BAIDU上乱七八糟的文章,当然的乱设就可能了。其实应该按RFC3551,根据你要传输的媒体类型来设。

      • int SetDefaultMark(bool m)

      这设RTP数据包的Mark标识。
ps:设为什么值好?这个,呵呵,连RFC3550也不能确定了。要看具体的RTP Payload规范,MPEG的,H263的都不一样。
      MPEG2

   www.ietf.org/rfc/rfc2250.txt
      MPEG4   

www.rfc-editor.org/rfc/rfc3016.txt
      H263        www.ietf.org/rfc/rfc2190.txt

      • int SetDefaultTimestampIncrement(uint32 t timestampinc)

      设置默认的时间戳的增量。
ps:也是和上的第一和第三个函数配套的。每发一个RTP数据包timestamp就会自动增加


      • int IncrementTimestamp(uint32 t inc)

      这个函数用来手工增加Timestamp。有时我这很好用,例如,一个RTP数据包因为只含有静音数据,我们没有发送,这是我们就应手工增加Timestamp以便发下一个RTP数据包时它的Timestamp是正确的。

      • int IncrementTimestampDefault()

      这个函数用于增加由SetDefaultTimestampIncrement设定的值。有时候这很有用,例如,一个RTP数据包因为只含有静音数据,我们没有发送。这时,这个函数就会被调用用来设置Timestamp以便下一个RTP包的Timestamp是正确的。

      • int SetPreTransmissionDelay(const RTPTime &delay)

      This function allows you to inform the library about the delay between

sampling the first sample of a packet and sending the packet. This delay is

taken into account when calculating the relation between RTP timestamp

and wallclock time, used for inter-media synchronization.

      • RTPTransmissionInfo *GetTransmissionInfo()

      This function returns an instance of a subclass of RTPTransmissionInfo

which will give some additional information about the transmitter (a list

of local IP addresses for example). The user has to delete the returned

instance when it is no longer needed.

     

      • int 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.

61

      • int WaitForIncomingData(const RTPTime &delay,bool *dataavailable= 0)

      Waits at most a time delay until incoming data has been detected. Only

works when you’re not using the poll thread. If dataavailable is not NULL,

it should be set to true if data was actually read and to false otherwise.

      • int AbortWait()

      If the previous function has been called, this one aborts the waiting. Only

works when you’re not using the poll thread.

      • RTPTime GetRTCPDelay()

      Returns the time interval after which an RTCP compound packet may have

to be sent. Only works when you’re not using the poll thread.

      • int BeginDataAccess()

      下面的函数(直到EndDataAccess)要在BeginDataAccess 和EndDataAccess之间被调用,BeginDataAccess确保轮询(poll)线程不会在这期间访问source table 。EndDataAccess 调用完成后,轮询(poll)线程会得到锁而继续访问。
ps:首先,你里的source table中的每一个source表示参与会议中的每一个参与者的每一个独立的媒体流。我们会在下面用到他们,但同时,poll线程也会轮询它们以正确处理和RTCP有关的内容。
 

      • bool GotoFirstSource()

      开始递归参与者的第一个流,如果找到了,就返回tree,否则返回false。
ps:我们通过这个函数和下面的GotoNextSource遍历source table中的每一个source。
     

      • bool GotoNextSource()

      设置当前的源(source)为source table中的下一个源。如果已经到尾部了就返回false.

    

      • bool GotoPreviousSource()

      设置当前的源(source)为source table中上一个源。如果已经到头部了就返回false.

      • bool GotoFirstSourceWithData()

      开始递归参与者中第一个有RTP数据的流,如果找到了,就返回tree,否则返回false。
PS:在接收数据是我们常用的是这套函数,因为如果没有数据要来都没用。


      • bool GotoNextSourceWithData()

      设置当前的源(source)为source table中有RTP数据的下一个源。如果已经到尾部了就返回false.

      • bool GotoPreviousSourceWithData()

      设置当前的源(source)为source table中有RTP数据的上一个源。如果已经到头部了就返回false.

      • RTPSourceData *GetCurrentSourceInfo()

      返回当前参与者的当前源(source)的RTPSourceData 实列。
ps:返回的这个RTPSourceData 就是本进程从期它参与者的RTCP数据包中收集得到的信息,对我们来说其实很有用,只是作者的例程没有用上,国内的网络也没有提到。在RFC3550中有关RTCP的东西都在这了,看过RFC3550的人都知到,里头谈得最多的就是RTCP。这个类我们以后会专门说。
     

     

      • RTPSourceData *GetSourceInfo(uint32 t ssrc)

      返回由ssrc指定的RTPSourceData ,或都NULL(当这个条目不存在)。
ps:这个函数也很有用。因为GetCurrentSourceInfo只有在GotoFirstSource等上下文当中才能用。如果我们是在RTPSource子类的成员函数中,我们没有这个上下文,就只能用这个函数。

      • RTPPacket *GetNextPacket()

      得到当前参与者当前媒体流的下一个RTP数据包。

      • int EndDataAccess()

      请看BeginDataAccess

      • int SetReceiveMode(RTPTransmitter::ReceiveMode m)

      Sets the receive mode to m, which can be one of the following:

      – RTPTransmitter::AcceptAll

            All incoming data is accepted, no matter where it originated from.

      – RTPTransmitter::AcceptSome

            Only data coming from specific sources will be accepted.

      – RTPTransmitter::IgnoreSome

            All incoming data is accepted, except for data coming from a specificset of sources.

        Note that when the receive mode is changed, the list of addressed to be ignored or accepted will be cleared.

      • int AddToIgnoreList(const RTPAddress &addr)

      Adds addr to the list of addresses to ignore.

      • int DeleteFromIgnoreList(const RTPAddress &addr)

      Deletes addr from the list of addresses to ignore.

      • void ClearIgnoreList()

      Clears the list of addresses to ignore.

      • int AddToAcceptList(const RTPAddress &addr)

      Adds addr to the list of addresses to accept.

      • int DeleteFromAcceptList(const RTPAddress &addr)

      Deletes addr from the list of addresses to accept.

      • void ClearAcceptList()

      Clears the list of addresses to accept.

      • int SetMaximumPacketSize(size t s)

      Sets the maximum allowed packet size to s.

      • int SetSessionBandwidth(double bw)

      Sets the session bandwidth to bw, which is specified in bytes per second.

      • int SetTimestampUnit(double u)

      Sets our own timestamp unit to u. The timestamp unit is defined as a time

interval divided by the number of samples in that interval: for 8000Hz

audio this would be 1.0/8000.0.

      • void SetNameInterval(int count)

      在处理source table中的sourcese后,RTCP packet builder(我们不用理这个内部的东西)会检查是否有其它(non-CNAME)SDES项目要发送。如果count为零或负数,则不发送,如果count为正数,则在sources table处理count次后会把SDES name item加到当前RTCP包中。
ps:其实每次处理sources table都会伴随都SDES RTCP数据包的发送,在这个数据包当中CNAME是必须的,但其它的项目不是必须的,这就函数确定了NAME项目发送的频度,如果为1,则表不每个SDES RTCP数据包都带着它,如果为2则每两个SDES数据包就发送一次NAME项目,下面的SetEMailInterval、SetLocationInterval、SetPhoneInterval、SetToolInterval、SetNoteInterval都是同一原理。关于这个ITEM的描述,请看RFC3550.老版本的JRTPLIB没有使用这套函数,而是用EnableSendName()等函数。


      • void SetEMailInterval(int count)

      After all possible sources in the source table have been processed, the RTCP

packet builder will check if other (non-CNAME) SDES items need to be

sent. If count is zero or negative, nothing will happen. If count is positive,

an SDES e-mail item will be added after the sources in the source table

have been processed count times.

      • void SetLocationInterval(int count)

      After all possible sources in the source table have been processed, the RTCP

packet builder will check if other (non-CNAME) SDES items need to be

sent. If count is zero or negative, nothing will happen. If count is positive,

an SDES location item will be added after the sources in the source table

have been processed count times.

      • void SetPhoneInterval(int count)

      After all possible sources in the source table have been processed, the RTCP

packet builder will check if other (non-CNAME) SDES items need to be

sent. If count is zero or negative, nothing will happen. If count is positive,

an SDES phone item will be added after the sources in the source table

have been processed count times.

      • void SetToolInterval(int count)

      After all possible sources in the source table have been processed, the RTCP

packet builder will check if other (non-CNAME) SDES items need to be

sent. If count is zero or negative, nothing will happen. If count is positive,

an SDES tool item will be added after the sources in the source table have

been processed count times.

      • void SetNoteInterval(int count)

      After all possible sources in the source table have been processed, the RTCP

packet builder will check if other (non-CNAME) SDES items need to be

sent. If count is zero or negative, nothing will happen. If count is positive,

an SDES note item will be added after the sources in the source table have

been processed count times.

      • int SetLocalName(const void *s, size t len)

      设置NAME SDES项目,以遍会议的其它人员看到你的名称。下同。

    

      • int SetLocalEMail(const void *s, size t len)

      Sets the SDES e-mail item for the local participant to the value s with

length len.

      • int SetLocalLocation(const void *s, size t len)

Sets the SDES location item for the local participant to the value s with

length len.

      • int SetLocalPhone(const void *s, size t len)

      Sets the SDES phone item for the local participant to the value s with

length len.

      • int SetLocalTool(const void *s, size t len)

      Sets the SDES tool item for the local participant to the value s with length

len.

     

      • int SetLocalNote(const void *s, size t len)

Sets the SDES note item for the local participant to the value s with length

len.

In case you specified in the constructor that you want to use your own transmission

component, you should override the following function:

      • RTPTransmitter *NewUserDefinedTransmitter()

      The RTPTransmitter instance returned by this function will then be used to send

and receive RTP and RTCP packets. Note that when the session is destroyed,

this RTPTransmitter instance will be destroyed with a delete call.

By inheriting your own class from RTPSession and overriding one or more of the

functions below, certain events can be detected:

      • void OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, const  RTPAddress *senderaddress)

      如果有RTPPacket数据包来到,会调用这个函数处理。
ps:这个函数在我们继承RTPSession类时很可能重载,这是获取RTP数据包除了上面所说的方法以外的另外一种方法,这个方法比较适合异步的情况。默认这个是一个空虚函数。除了这个函数以外,下面的几个函数了会经常重载。

      • void OnRTCPCompoundPacket(RTCPCompoundPacket *pack, const RTPTime &receivetime, const RTPAddress *senderaddress)

      Is called when an incoming RTCP packet is about to be processed.

      • void OnSSRCCollision(RTPSourceData *srcdat, const RTPAddress *senderaddress, bool isrtp)

      Is called when an SSRC collision was detected. The instance srcdat is the

one present in the table, the address senderaddress is the one that collided

with one of the addresses and isrtp indicates against which address

of srcdat the check failed.

     

      • void OnCNAMECollision(RTPSourceData *srcdat, const RTPAddress *senderaddress, const uint8 t *cname, size t cnamelength)

      Is called when another CNAME was received than the one already present for source srcdat.

      • void OnNewSource(RTPSourceData *srcdat)

      当有一个新的条目加到source table时,调用这个函数。
ps:这也是一个比较重要的函数,因为这意味着很有可能有一个新的与会者加入。但令我很不高兴的是,这时候的RTPSourceData 里头的CNAME和NAME等字段都还是无效的,这不是RTCP的责任,因为在这个SDES RTCP数据包中所有的信息都以经有了(通过抓包证实了这一点)。我们的函数被调用后,需要延时一会才能得到有关这个Source的CNAME和NAME等相关的信息。当然,如果你不想软件死掉,不能在这个函数体内以阻塞的方式延时。


      • void OnRemoveSource(RTPSourceData *srcdat)

      当有一个条目从source table中移除时调用这个函数。
ps:这通常意味着有一个与会者离开了,和OnNewSource不一样,这时的CNAME和NAME等都是有效的。用这个函数要注意,我们的“意味着两个字”因为“加入”的可能不是一个新的与会者,而是一个现有与会者的一个新的媒体流。“离开”的也可能不是一个与会者,而只是其中一个与会者的其中一个媒体流,这两个函数只能给我们更新与会者提供一个触发条件而已。当OnNewSource调用时,我们要看看这个CNAME是不是以经在我们与会者名单中,如果不是,那就是一个新与会者。同时,如果OnRemoveSource被调用,则我们要看看这个CNAME的与会者还有没有其它的Source,如果没有了,这个与会者才是真正离开。这么很麻烦??那就对了,那就是现在的H323和SIP要做的事情--会话管理。
    

      • void OnTimeout(RTPSourceData *srcdat)

      Is called when participant srcdat is timed out.

      • void OnBYETimeout(RTPSourceData *srcdat)

      Is called when participant srcdat is timed after having sent a BYE packet.

      • void OnBYEPacket(RTPSourceData *srcdat)

      Is called when a BYE packet has been processed for source srcdat.

      • void OnAPPPacket(RTCPAPPPacket *apppacket, const RTPTime &receivetime,

const RTPAddress *senderaddress)

      In called when an RTCP APP packet apppacket has been received at time

receivetime from address senderaddress.

      • void OnUnknownPacketType(RTCPPacket *rtcppack, const RTPTime &receivetime,

const RTPAddress *senderaddress)

      Is called when an unknown RTCP packet type was detected.

      • void OnUnknownPacketFormat(RTCPPacket *rtcppack, const RTPTime &receivetime,

const RTPAddress *senderaddress)

      Is called when an unknown packet format for a known packet type was

detected.

      • void OnNoteTimeout(RTPSourceData *srcdat)

      Is called when the SDES NOTE item for source srcdat has been timed out.

      • void OnSendRTCPCompoundPacket(RTCPCompoundPacket *pack)

      Is called when an RTCP compound packet has just been sent. Useful to

inspect outgoing RTCP data.

      • void OnPollThreadError(int errcode)

      Is called when error errcode was detected in the poll thread.

      • void OnPollThreadStep()

      Is called each time the poll thread loops. This happens when incoming data

was detected or when its time to send an RTCP compound packet.

      原来想全部翻译的,翻译真的累,后我我只翻译了一部份,其它有时间我会慢慢翻译的。
PS后面的话是原文没有的,是我加上去的。其它是原文有的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/164752.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • SwipeRefreshLayout实现上滑加载更多[通俗易懂]

    SwipeRefreshLayout实现上滑加载更多[通俗易懂]SwipeRefreshLayout实现上滑加载更多在我们的项目中,需要用到许多下拉刷新和上滑加载的操作,不说什么没用的,直接来介绍SwipeRefreshLayout的扩展用法。后面会简单的介绍SwipeRefreshLayout的用法。在这里我们对谷歌官方的控件进行拓展,使得SwipeRefreshLayout具有上滑加载更多的功能。下面是正文首先我们新建文件(文件名自己定义,在…

  • docker mysql日志查看_MySQL查看版本

    docker mysql日志查看_MySQL查看版本查询DockerMySQL的版本号1.查找到当前正在运行的容器#dockerps2.进入mysql容器(命令中不带小括号)#dockerexec-it(mysql的名字,或id)bash3.登录mysql,输入账号密码登录(命令中不带小括号)#mysql-u(root)-p(abcd)登录成功以后,会显示该mysql的详细信息,其中包含版本号…

  • QueryInterface 的实现规则

    QueryInterface 的实现规则本节将给出一些QueryInterface既的所有实现都必须遵循的一些规则,以便客户能够获取关于组件的足够多的知识并对之施实一些控制和其他有用的处理。如果没有这些规则,是不可能编写出组件的,因为在这种情况下,QueryInterface的行为将是不确定的。具体来讲,这些规则是:QueryInterface返回的总是同一IUnknown指针。若客户曾经获取过某个接口,那么它将总能获取此接口。客户可

  • 食物链3_食物链条数计算公式

    食物链3_食物链条数计算公式动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B 吃 C,C 吃 A。现有 N 个动物,以 1∼N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这 N 个动物所构成的食物链关系进行描述:第一种说法是 1 X Y,表示 X 和 Y 是同类。第二种说法是 2 X Y,表示 X 吃 Y。此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句

  • 激光SLAM原理_激光打标机

    激光SLAM原理_激光打标机在机器人运动控制系统架构中,可分为最底层、中间通信层和决策层三大层面,最底层包含了机器人本身的电机驱动和控制部分,中间通信层是底层部分和决策层的通信通路,而决策层则是实现机器人的定位建图及导航。在机器人定位导航中,目前主要涉及到激光SLAM与视觉SLAM,激光SLAM在理论、技术和产品落地上都较为成熟,因而成为现下最为主流的定位导航方式,在家用扫地机器人及商用送餐机器人等服务机器人中普遍采用了…

  • 计算机弹歌曲乐谱大全绿色_小精灵钢琴谱简易版

    计算机弹歌曲乐谱大全绿色_小精灵钢琴谱简易版【小Z键盘钢琴】以下歌谱对应的键是跟默认键是不一样的,我已经打包了,只要把歌谱.ini改成系统.ini然后重启软件,这样就改好了,然后可以按照以下歌谱试弹一下!海阔天空就是此键盘钢琴的第一首钢琴曲(对不起,弹的时候是边看琴谱,边弹的,所以听起来太纠结了.)请到软件安装的目录查找!1.播放录音功能:点击播放按钮,会提示打开录音文件(XZ格式的文件)2.记录功能:点记录,会显示状态:”正在记录…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号