JRTPlib学习笔记.docx
- 文档编号:6686
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:23
- 大小:173.84KB
JRTPlib学习笔记.docx
《JRTPlib学习笔记.docx》由会员分享,可在线阅读,更多相关《JRTPlib学习笔记.docx(23页珍藏版)》请在冰点文库上搜索。
JRTPlib学习笔记
一、流媒体概念
流媒体包含广义和狭义两种内涵:
广义上的流媒体指的是使音频和视频形成稳定和连续的传输流和回放流的一系列技术、方法和协议的总称,即流媒体技术;狭义上的流媒体是相对于传统的下载-回放方式而言的,指的是一种从Internet上获取音频和视频等多媒体数据的新方法,它能够支持多媒体数据流的实时传输和实时播放。
通过运用流媒体技术,服务器能够向客户机发送稳定和连续的多媒体数据流,客户机在接收数据的同时以一个稳定的速率回放,而不用等数据全部下载完之后再进行回放。
二、流媒体协议
实时传输协议(Real-timeTransportProtocol,PRT)是在Internet上处理多媒体数据流的一种网络协议,利用它能够在一对一(unicast,单播)或者一对多(multicast,多播)的网络环境中实现传流媒体数据的实时传输。
RTP通常使用UDP来进行多媒体数据的传输,但如果需要的话可以使用TCP或者ATM等其它协议,整个RTP协议由两个密切相关的部分组成:
RTP数据协议和RTP控制协议。
实时流协议(RealTimeStreamingProtocol,RTSP)最早由RealNetworks和Netscape公司共同提出,它位于RTP和RTCP之上,其目的是希望通过IP网络有效地传输多媒体数据。
2.1RTP数据协议
RTP数据协议负责对流媒体数据进行封包并实现媒体流的实时传输,每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。
RTP数据报的头部格式如图1所示:
图1RTP头部格式
其中比较重要的几个域及其意义如下:
CSRC记数(CC) 表示CSRC标识的数目。
CSRC标识紧跟在RTP固定头部之后,用来表示RTP数据报的来源,RTP协议允许在同一个会话中存在多个数据源,它们可以通过RTP混合器合并为一个数据源。
例如,可以产生一个CSRC列表来表示一个电话会议,该会议通过一个RTP混合器将所有讲话者的语音数据组合为一个RTP数据源。
负载类型(PT) 标明RTP负载的格式,包括所采用的编码算法、采样频率、承载通道等。
例如,类型2表明该RTP数据包中承载的是用ITUG.721算法编码的语音数据,采样频率为8000Hz,并且采用单声道。
序列号 用来为接收方提供探测数据丢失的方法,但如何处理丢失的数据则是应用程序自己的事情,RTP协议本身并不负责数据的重传。
时间戳 记录了负载中第一个字节的采样时间,接收方根据时间戳能够确定数据的到达是否受到了延迟抖动的影响,但具体如何来补偿延迟抖动则是应用程序自己的事情。
从RTP数据报的格式不难看出,它包含了传输媒体的类型、格式、序列号、时间戳以及是否有附加数据等信息,这些都为实时的流媒体传输提供了相应的基础。
RTP协议的目的是提供实时数据(如交互式的音频和视频)的端到端传输服务,因此在RTP中没有连接的概念,它可以建立在底层的面向连接或面向非连接的传输协议之上;RTP也不依赖于特别的网络地址格式,而仅仅只需要底层传输协议支持组帧(Framing)和分段(Segmentation)就足够了;另外RTP本身还不提供任何可靠性机制,这些都要由传输协议或者应用程序自己来保证。
在典型的应用场合下,RTP一般是在传输协议之上作为应用程序的一部分加以实现的,如图2所示:
图2RTP与各种网络协议的关系
2.2RTCP控制协议
RTCP控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用。
RTP本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。
通常RTCP会采用与RTP相同的分发机制,向会话中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质量进行控制或者对网络状况进行诊断。
RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:
SR 发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
RR 接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。
SDES 源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。
BYE 通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。
APP 由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。
RTCP数据报携带有服务质量监控的必要信息,能够对服务质量进行动态的调整,并能够对网络拥塞进行有效的控制。
由于RTCP数据报采用的是多播方式,因此会话中的所有成员都可以通过RTCP数据报返回的控制信息,来了解其他参与者的当前情况。
在一个典型的应用场合下,发送媒体流的应用程序将周期性地产生发送端报告SR,该RTCP数据报含有不同媒体流间的同步信息,以及已经发送的数据报和字节的计数,接收端根据这些信息可以估计出实际的数据传输速率。
另一方面,接收端会向所有已知的发送端发送接收端报告RR,该RTCP数据报含有已接收数据报的最大序列号、丢失的数据报数目、延时抖动和时间戳等重要信息,发送端应用根据这些信息可以估计出往返时延,并且可以根据数据报丢失概率和时延抖动情况动态调整发送速率,以改善网络拥塞状况,或者根据网络状况平滑地调整应用程序的服务质量。
2.3RTSP实时流协议
作为一个应用层协议,RTSP提供了一个可供扩展的框架,它的意义在于使得实时流媒体数据的受控和点播变得可能。
总的说来,RTSP是一个流媒体表示协议,主要用来控制具有实时特性的数据发送,但它本身并不传输数据,而是必须依赖于下层传输协议所提供的某些服务。
RTSP可以对流媒体提供诸如播放、暂停、快进等操作,它负责定义具体的控制消息、操作方法、状态码等,此外还描述了与RTP间的交互操作。
RTSP在制定时较多地参考了HTTP/1.1协议,甚至许多描述与HTTP/1.1完全相同。
RTSP之所以特意使用与HTTP/1.1类似的语法和操作,在很大程度上是为了兼容现有的Web基础结构,正因如此,HTTP/1.1的扩展机制大都可以直接引入到RTSP中。
由RTSP控制的媒体流集合可以用表示描述(PresentationDescription)来定义,所谓表示是指流媒体服务器提供给客户机的一个或者多个媒体流的集合,而表示描述则包含了一个表示中各个媒体流的相关信息,如数据编码/解码算法、网络地址、媒体流的内容等。
虽然RTSP服务器同样也使用标识符来区别每一流连接会话(Session),但RTSP连接并没有被绑定到传输层连接(如TCP等),也就是说在整个RTSP连接期间,RTSP用户可打开或者关闭多个对RTSP服务器的可靠传输连接以发出RTSP请求。
此外,RTSP连接也可以基于面向无连接的传输协议(如UDP等)。
RTSP协议目前支持以下操作:
检索媒体 允许用户通过HTTP或者其它方法向媒体服务器提交一个表示描述。
如表示是组播的,则表示描述就包含用于该媒体流的组播地址和端口号;如果表示是单播的,为了安全在表示描述中应该只提供目的地址。
邀请加入 媒体服务器可以被邀请参加正在进行的会议,或者在表示中回放媒体,或者在表示中录制全部媒体或其子集,非常适合于分布式教学。
添加媒体 通知用户新加入的可利用媒体流,这对现场讲座来讲显得尤其有用。
与HTTP/1.1类似,RTSP请求也可以交由代理、通道或者缓存来进行处理。
参考文档
三、JRTPlib3.7.1在windows下的编译步骤
编译设置过程:
1.解压jrtplib-3.7.1和jthread-1.2.1
2.用VC打开工程文件jthread.dsw
3.编译jrtplib.lib和jthread.lib需要注意VC6要求安装Vs6sp6,在编译jrtplib.lib和jthread.lib前,在project——settings——C/C++——Codegeneration:
userun-timelibrary中,对于debug,选择:
DebugMultithreadedDLL,对于release,则选择:
MultithreadedDLL。
4.首先编译jthread库,然后将jthread-1.2.1\src内的"jmutex.h"和"jthread.h"两个头文件放入jrtplib-3.7.1\src目录下,然后将jrtplib-3.7.1\src文件夹下所有头文件中的
编译时注意编译方式和jthread.lib一致。
5.编译生成的jthread.lib和jrtplib.lib拷贝到系统目录:
C:
\ProgramFiles\MicrosoftVisualStudio\VC98\Lib下,将jrtplib-3.7.1\src下所有的.h头文件复制到C:
\ProgramFiles\MicrosoftVisualStudio\VC98\Include,以便以后使用。
6.现在我们就可以编译jrtplib-3.7.1\examples下的实例程序了。
建立VC工程,打开example1.c,在ProjectSettings的link页添加jthread.libjrtplib.libws2_32.lib,在project——settings——C/C++——Codegeneration:
userun-timelibrary中,对于debug,选择:
DebugMultithreadedDLL,对于release,则选择:
MultithreadedDLL。
7.编译源程序,运行就OK啦
四、JRTPLIB库的使用方法及程序实现
(1)JRTPLIB函数的使用
a、在使用JRTPLIB进行实时流媒体数据传输之前,首先应该生成RTPSession类的一个实例来表示此次RTP会话,然后调用Create()方法来对其进行初始化操作。
JRTPLIB-3.7中的Create方法为
Create(sessparams,&transparams)。
其中的两个参数需要如下先定义:
RTPUDPv4TransmissionParamstransparams;
RTPSessionParamssessparams;
sessparams.SetOwnTimestampUnit(1.0/8000.0);/*设置时间戳,1/8000表示1秒钟采样8000次,即录音时的8KHz*/
sessparams.SetAcceptOwnPackets(true);
transparams.SetPortbase(portbase);/*本地通讯端口*/
b、设置恰当的时戳单元,是RTP会话初始化过程所要进行的另外一项重要工作,这是通过调用RTPSession类的SetTimestampUnit()方法来实现的,前面已经提过。
c、当RTP会话成功建立起来之后,接下去就可以开始进行流媒体数据的实时传输了。
首先需要设置好数据发送的目标地址,RTP协议允许同一会话存在多个目标地址,这可以通过调用RTPSession类的AddDestination()、DeleteDestination()和ClearDestinations()方法来完成。
例如,下面的语句表示的是让RTP会话将数据发送到本地主机的6000端口:
unsignedlongaddr=ntohl(inet_addr("127.0.0.1"));
sess.AddDestination(addr,6000);
d、目标地址全部指定之后,接着就可以调用RTPSession类的SendPacket()方法,向所有的目标地址发送流媒体数据。
SendPacket()是RTPSession类提供的一个重载函数对于同一个RTP会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB允许将它们设置为会话的默认参数,这是通过调用RTPSession类的SetDefaultPayloadType()、SetDefaultMark()和SetDefaultTimeStampIncrement()方法来完成的。
为RTP会话设置这些默认参数的好处是可以简化数据的发送,例如,如果为RTP会话设置了默认参数:
sess.SetDefaultPayloadType(0);
sess.SetDefaultMark(false);
sess.SetDefaultTimeStampIncrement(10);
之后在进行数据发送时只需指明要发送的数据及其长度就可以了:
sess.SendPacket(buffer,5);
在真正的语音传输中,上面的buffer就是我们录音时所得到的buffer。
使用上面的函数可以简单的发送,但无法真正的实现RTP传输,我们需要调用另一个接口:
sess.SendPacket((void*)buffer,sizeof(buffer),0,false,8000);详细的说明可以查看JRTPLIB的说明文档。
e、对于流媒体数据的接收端,首先需要调用RTPSession类的Poll()方法来接收发送过来的RTP或者RTCP数据报。
由于同一个RTP会话中允许有多个参与者(源),你既可以通过调用RTPSession类的GotoFirstSource()和GotoNextSource()方法来遍历所有的源,也可以通过调用RTPSession类的GotoFirstSourceWithData()和GotoNextSourceWithData()方法来遍历那些携带有数据的源。
在从RTP会话中检测出有效的数据源之后,接下去就可以调用RTPSession类的GetNextPacket()方法从中抽取RTP数据报,当接收到的RTP数据报处理完之后,一定要记得及时释放。
JRTPLIB为RTP数据报定义了三种接收模式,其中每种接收模式都具体规定了哪些到达的RTP数据报将会被接受,而哪些到达的RTP数据报将会被拒绝。
通过调用RTPSession类的SetReceiveMode()方法可以设置下列这些接收模式:
RECEIVEMODE_ALL 缺省的接收模式,所有到达的RTP数据报都将被接受;
RECEIVEMODE_IGNORESOME 除了某些特定的发送者之外,所有到达的RTP数据报都将被接受,而被拒绝的发送者列表可以通过调用AddToIgnoreList()、DeleteFromIgnoreList()和ClearIgnoreList()方法来进行设置;
RECEIVEMODE_ACCEPTSOME 除了某些特定的发送者之外,所有到达的RTP数据报都将被拒绝,而被接受的发送者列表可以通过调用AddToAcceptList()、DeleteFromAcceptList和ClearAcceptList()方法来进行设置。
下面是采用第三种接收模式的程序示例。
if(sess.GotoFirstSourceWithData()){
do{
sess.AddToAcceptList(remoteIP,allports,portbase);
sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
RTPPacket*pack;
pack=sess.GetNextPacket(); //处理接收到的数据
deletepack; }
while(sess.GotoNextSourceWithData());
}
完整的代码中,首先需调用Poll()方法接收RTP数据报,然后在BeginDataAccess()和EndDataAccess()之间进行数据接收的操作。
此时,我们设定程序一直do-while等待并处理数据
(2)程序流程
发送:
获得接收端的IP地址和端口号 创建RTP会话 指定RTP数据接收端设置RTP会话默认参数 发送流媒体数据
接收:
获得用户指定的端口号创建RTP会话设置接收模式接受RTP数据检索RTP数据源获取RTP数据报删除RTP数据报
五、RTPSession类介绍
对于大多数的RTP应用程序,RTPSession类可能是JRTPLIB唯一使用的类。
它能完全处理RTCP部份的数据包,所以用户可以把精力集中在真正的数据收发。
要知道RTPSession类在多线程下并不是安全的,因此,用户要通过某些锁同步机制来保证不会出现在不同线程当中调用同一个RTPSession实例。
RTPSession类有如下的接口。
•RTPSession(RTPTransmitter:
:
TransmissionProtocolproto=RTPTransmitter:
:
IPv4UDPProto)
使用proto类型传输层创建一个PRTSession实例。
如果proto使用用户自定义(user-defined)传输层,则相应的NewUserDefinedTransmitter()函数必须实现。
ps:
这里默认就行了,默认就是IPV4网络。
•intCreate(constRTPSessionParams&sessparams,constRTPTransmissionParams*transparams=0)
使用RTPSession参数sessparams和RTPTransmission参数transparams真正创建一个RTP会话。
如果transparams为NULL,则使用默认的参数。
ps:
RTPSessionParams我们可能要设得比较多,RTPTransmissionParams参数就只要设置其中的端口就行了,端口一定要设对,不然进行组播时,这个进程将不接收数据。
设置方式可以看example.cpp。
•voidDestroy()
离开一个会话但不向其它组成员发送BYE包。
ps:
我不推荐用这个函数除非是错误处理,正常离开我们应该用ByeDestroy()。
•voidBYEDestroy(constRTPTime&maxwaittime,constvoid*reason,sizetreasonlength)
发送一个BYE包并且离开会话。
在发送BYE包前等待maxwaittime,如果超时,会不发送BYE包直接离开,BYE包会包含你的离开原因reason。
相应的reasonlength表示reason长度。
ps:
因为BYE包是一个RTCP包,RTCP不是要发就发的,它的发送时间是为了平衡带宽通过计算得出来的,那就很有可能到了要发的时候以经超过了maxwaittime时间了,作者可能认一直保留个这会话这么久没意义。
当然,我常常把maxwaittime设得很大。
•boolIsActive()
看看这个RTPSession实例是否以经通过Create建立了真实的会话。
•uint32tGetLocalSSRC()
返回我们的SSRC。
ps:
至于什么是SSRC,去看看RFC3550吧。
我说过JRTPLIB只是RTP协议的包装,并没有做任何应用的事情。
•intAddDestination(constRTPAddress&addr)
添加一个发送目标。
ps:
当然,如果我们使用组播,这里只用调用一次,把我们的组播地址写进去。
这样,这组的全部人都能收到你发的包。
但是组播可因特网的上设置很烦。
而且用组播测试也很烦(组播必须BIND一个端口,如果你想在同一台机器上运行两个软件实例来没试,你就会发现同一个端口BIND两次,当然,后面那次会失败,也就是说测试不了,要测?
找两台机器,或用虚拟机
),如果组播不满足,我们就要把组播变在单播,这时就要返复调用这个函数把其它组成员的IP都加进来了。
具体可以看看example3.cpp。
•intDeleteDestination(constRTPAddress&addr)
从发送地址列表中删除一下地址。
•voidClearDestinations()
清除发送地址列表。
•boolSupportsMulticasting()
返回JRTPLIB是否支持组播。
ps:
这里指JRTPLIB本身,不是你的真实网络。
编译JRTPLIB库时可能指定。
.
•intJoinMulticastGroup(constRTPAddress&addr)
加入一个组播组addr。
•intLeaveMulticastGroup(constRTPAddress&addr)
离开一个组播组addr。
•voidLeaveAllMulticastGroups()
离开所有组播组。
ps:
我们可以同时加入多个组播组。
.
•intSendPacket(constvoid*data,sizetlen)
•intSendPacket(constvoid*data,sizetlen,uint8tpt,boolmark,uint32ttimestampinc)
•intSendPacketEx(constvoid*data,sizetlen,uint16thdrextID,constvoid*hdrextdata,sizetnumhdrextwords)
•intSendPacketEx(constvoid*data,sizetlen,uint8tpt,boolmark,uint32ttimestampinc,uint16thdrextID,constvoid*hdrextdata,sizetnumhdrextwords)
上面的4个函数都是发送数据包的,我想如果你没有看RTP协议,我说了你也晕。
如果你RTP协议看了,再看看RTPSession.h的注识,你就懂了。
•intSetDefaultPayloadType(uint8tpt)
设定默认的RTPPay
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JRTPlib 学习 笔记
![提示](https://static.bingdoc.com/images/bang_tan.gif)