了解JMF RTP API
JMF通过定义在javax.media.rtp
, javax.media.rtp.event
, 和 javax.media.rtp.rtcp
包中的API来回放和传输RTP流。
注意:可适应的JMF实现不是必须要支持javax.media.rtp, javax.media.rtp.event,和javax.media.rtp.rtcp中的RTP API的。涉及到JMF的实现APIs全部由Sun Microsystems,Inc. 和IBM Corporation提供。
你可以本地播放引入的RTP流,将它们保存进一个文件。
例如,RTP APIs能够被用于实现一个电话应用程序,就像一个应答机器一样响应呼叫并记录信息。
类似的,你可以在网络中使用RTP APIs传输拍摄或存储的媒体流。输出的RTP 流能够从一个文件或拍摄装置里取得。输出流也能够在本地播放或存储进一个文件。
例如,你可以实现视频会议应用程序,用来拍摄活动中的音视频,并且在网络使用一个单独的RTP session为每一种媒体类型传输。
类似的,你可以为随后的广播记录一个会议,或者在一个会议应用程序中使用事先录好的音频流如“hold music”。
RTP 体系结构
JMF RTP APIs 被设计成与拍摄、播放和JMF处理能力的无缝的整合。播放器和处理机常常处理和操纵RTP媒体流就像其它媒体内容。你可以传输已拍摄的媒体流,从一个本地摄像机置中使用一个摄影DataSource拍摄的视频,或者用一个DataSink存储的一个文件。类似的,JMF可以被扩展去支持额外的RTP格式,并通过标准的插件机置装载。
Figure 8-3: High-level JMF RTP architecture.
在JMF中,用一个SessionManager来整理一个RTP session. Session manager 保留session参与者的轨迹和已经传输的流。
Session管理器维护session的状态,就像从一个本地参与者中观察一样。有效的是,一个session 管理器是一个分布式实体----RTP session的本地描述。Session管理器也操作RTCP控制管道,并且支持所有的发送端和接收端的RTCP。
SessionManager接口定义了一些方法,使得应用程序可以初始化,并且在一个session中启动多个参与者,移除通过应用程序单独创建的流,并且关闭整个session。
Session 统计表
在Session中,所有发送和接收的RTP和RTCP包上,session管理器上都包含统计表。在每个流基础上,统计表被记录到整个session。Session管理器提供访问全局接收和传输统计表:
l GlobalReceptionStats: 为session维护全局接收统计表。
l GlobalTransmissionSats:为所有本地发送端维护累积的传输统计表。
对于一个特殊的容器或输出流,统计是有用的:
l ReceptionStats:为每个单独的参与者维护源接收统计表。
l TransmissionStats:为每个单独的发送流维护传输统计表。
Session 参与者
Session管理器保留在一个session中的所有参与者的轨迹。每个参与者都通过一个实现了Participant接口的类的实例来放映。只要一个包含了源描述(SDES)的RTCP包到达,(这个SDES用一个之前在session中规范好的名字), SessionManagers就创建一个Participant。参与者可以被动的(只发送控制包)或者主动的(也发送一个或多个RTP数据流)。
一个本地参与者正确的播放本地客户/服务器参与者。一个本地参与者声明它将开始发送RTCP控制信息或数据,并且维护输入数据的状态,通过开始一个session来控制消息。
一个参与者能够拥有多个流,每一个都通过同步源标识符(SSRC)来确定,这个SSRC通过流的源来使用。
Session 流
SessionManager为每个session中RTP数据包的流维护一个RTPStream对象。有两种类型的RTP流:
l ReceiveStream重放一个来自远程参与者的正在被接收的流。
l SendStream重放一个来自于Processor的数据流或在网络中正在被发送的输入流。
只要session管理器探测到一个新的RTP数据源,就自动创建一个ReceiveStream。要创建一个新的SendStream,你可以调用SessionManager createSendStream方法。
RTP 事件
一些特殊的RTP事件被定义在javax.media.rtp.event包中。这些事件被用于通知RTP session和流的状态。
Figure 8-4: RTP events.
要接收RTP事件的通知,用session管理器实现适当的RTP监听和注册:
l SessionListener: 接收session状态改变的通知。
l SendStreamListener: 接收一个正在被传输的RTP流的状态改变的通知。
l ReceiveStreamListener: 接收一个正在被发送的RTP流的状态改变的通知。
l RemoteListener: 接收从一个事件的通知或远程参与者发送的RTP控制消息。
Session监听者
你可以实现SessionListener发送关于事件的通知,这些事件适合将RTP session作为一个整体,就像附加的新的参与者。
Session-wide 有两类事件:
l NewParticipantEvent: 声明一个新的已经加入session的参与者。
l LocalCollisionEvent: 声明参与者的同步源已经被占用。
发送流监听者
你可以实现SendStreamListener随时接收通知:
l 通过本地参与者创建新的发送流。
l 来自数据源中数据的转换用于创建开始或停止的发送流。
l 发送流的格式或负载均衡改变。
联合一个SendStream 有五种事件类型:
l NewSendStreamEvent:声明通过本地参与者创建一个新的发送流。
l ActiveSendStreamEvent:声明来自数据源中数据的转换用于创建已开始的发送流。
l InactiveSendStreamEvent:声明来自数据源中数据的转换用于创建已停止的发送流。
l LocalPayloadChangeEvent:声明流的格式或已改变的负载均衡。
l StreamClosedEvent:声明流已关闭.
接收流监听者
你可实现ReceiveStramListener随时接收通知:
l 创建新的接收流.
l 开始或停止数据的转换.
l 数据转换超时.
l 用一个Paticipant关联一个重前丢失的ReceiveStream。
l 接收一个RTCP APP包。
l 接收流的格式或负载均衡改变。
你也可以使用这个接口得到一个流上的句柄,然后访问RTP数据源,所以你可创建一个MediaHandler。
有七种事件的类型与ReceiveStream关联:
l NewReceiveStreamEvent:声明session管理器已经为一个新近探测到的源创建了一个新的接收流。
l ActiveReceiveStreamEvent:声明数据的转换已经开始。
l InactiveReceiveStreamEvent:声明数据的转换已经结束。
l TimeoutEvent:声明数据的转换超时。
l RemotePayloadChangeEvent:声明格式或接收的负载均衡已经改变。
l StreamMappedEvent:声明一个先前丢失的接收流已经关联到一个参与者。
l ApplicationEvent:声明一个RTCP APP包已经接收。
远程监听者
你可实现RemoteListener接收事件的通知或一个远程参与者接收到的RTP控制消息。你可能想在一个应用程序中实现RemoteListener用于监控session――-它让你能接收RTCP汇报,并监控接收的session的质量,而不用在每一个流上都拥有接收数据或信息。
一个远程参与者关联三种事件的类型:
l ReceiverReportEvent:声明一个RTP接收端汇报已经接收。
l SenderReportEvent:声明一个RTP发送端汇报已经接收。
l RemoteCollisionEvent:声明两个远程参与者被用于同一个同步源ID(SSRC)。
RTP数据
一个RTP内部的流通过一个RTPStream对象被重放。RTStream有两种类型:ReceiveStream和SendStream。每个RTP流都关联一个缓冲数据源。像ReceiveStreams,这个数据源总有一个PushBufferDataSource。
Session管理器自动创建新的接收流就像它探测到从远程参与者处到达的附加流一样。你通过在session管理器上调用createSendStream创建新的发送流。
数据句柄
JMF RTP APIs被设计成不依赖传输端口。创建一个定制的RTP数据句柄能使JMF通过一个特殊的传输端口来工作。数据端口是一个数据源,被用于一个Player的数据源。
抽象类RTPPushDataSource定义了一个JMF RTP 数据句柄的基本元素。一个数据句柄包括输入数据流(PushSourceStream)和一个输出数据流(OutputDataStream ).一个数据句柄不仅能用于数据通道,也能用于RTP session的控制通道。如果它用于数据通道,数据句柄实现DataChannel接口。
一个RTPSocket是一个RTPPushDataSource,拥有数据和控制通道。每个通道都有一个网络中的输入和输出流数据。一个RTPSocket能输出RTPControls添加动态的有效载荷信息到session管理器。
因为定制的RTPSocket能被用于通过管理器创建一个Player,JMF为RTPSocket实现定义了名字和位置:
<protocol package-prefix>.media.protocol.rtpraw.DataSource
RTP数据格式
所有特殊的RTP数据都用一种特殊的RTP格式编码,定义在AudioFormat和VideoFormat类中。例如,数字通RTP压缩包编码设置在AudioFormat.GSM_RTP中,而jpeg-encoded 视频格式编码设置在VideoFormat.JPEG_RTP中。
AudioFormat定义了四种标准RTP-specific编码字符串:
public static final String ULAW_RTP = “JAUDIO_G711_ULAW/rtp";
public static final String DVI_RTP = "dvi/rtp";
public static final String G723_RTP = "g723/rtp";
public static final String GSM_RTP = "gsm/rtp";
VideoFormat定义了三种标准RTP-specific编码字符串:
public static final String JPEG_RTP = "jpeg/rtp";
public static final String H261_RTP = "h261/rtp";
public static final String H263_RTP = "h263/rtp";
RTP控制
RTP API 定义了一个RTP-specific控制,RTPControl.RTPControl是典型的通过RTP-specific数据源实现的。它提供一种添加一个映射在动态有效载荷和Format.RTPControl提供的方法之间,为访问session统计表和得到当前的有效载荷格式。
SessionManager也扩展了Controls 接口,使一个session管理器通过getControl和getControls方法扩充额外的Controls。例如,session管理器能扩展一个BufferControl使你能够指定缓冲的长度和开始。
Reception
一个输入RTP流的播放通过一个Player控制。要从一个RTP session中接收和播放一个单独的流,你可以使用一个描述了session创建一个Player的MediaLocator。一个RTP session的媒体定位器是下面的形式:
rtp://address:port[:ssrc]/content-type/[ttl]
Player 被创建并且连接到session中的第一个流。
如果session中有多个你想播放的流,你需要使用一个session管理器。只要一个流被加入到session中,你就可以从session管理器中接收通知,并且为每个新流创建一个Player。使用session管理器也使你能直接地侦测和控制session。
Transmission
一个session管理器能够被用于初始化和控制一个session,以便你可以通过网络流化数据。被流化的数据是从一个Processor中得到的。
例如,要从一个摄影源中创建一个发送流来传输数据,你应该:
1.创建,初始化,然后为session开始一个SessionManager。
2.使用适当的拍摄数据源创建一个Processor。
3.设置Processor的输出格式为一个RTP-specific格式。一个适当的RTP包的编码器必须能在你想传输的数据格式中是可用的。
4.找回在session管理器上的createSendStream并在数据源中传递。
通过SendStream start和stop方法控制传输。
当它第一次启动时,SessionManager的表现就像是一个接收器(发出RTCP接收器报告)。一旦创建了一个SendStream,它就开始发出RTCP发送端报告,并且在一个或多个发送流存在时,它的表现就像一个发送主机一样。如果所有的SendStreams都被关闭(不止是停止),session管理器回复为一个被动的接收器。
扩充
像JMF的其他部分一样,RTP的性能是可以被提高和扩展的。RTP APIs支持一个基本的RTP设置格式和有效载荷。高级开发者和技术提供商能够实现JMF插件来支持动态的有效载荷和额外的RTP格式。
实现定制的封包和解包
要实现一个定制的封包或解包,你实现JMF Codec接口。