Adobe Flash Player 10 和 Adobe AIR 1.5 引入了一个新的通讯协议——Real-Time Media Flow Protocol 即实时媒体流协议,简称RTMFP。它具有低延迟、对等的端到端能力、安全性和可扩展性,尤其适合于开发实时协作的应用,不仅提供优秀的用户体验还降低了 操作者的开销。
早期的Flash Player版本采用RTMP并且需要FMS 对于交互式的协作应用(例如:adobe Acrobat Connect Pro)或者音/视频流服务。虽然RTMP是一很优秀的选择,对于流媒体、共享对象或远程操作,限定于实时交互式的音视频通讯需求
为了使用RTMFP,Flash Player终端必须连接到支持RTMFP的服务器,如:代号Cirrus(以前称为Stratus)的服务或FMS4,Cirrus是一个提供集合点服 务的主机,并辅助Flash Player终端之间建立通信帐号。不像FMS,Cirrus不支持媒体中继(media relay)、共享对象、脚本等。所以使用Cirrus,只能开发Flash Player终端之间直接通信的应用。
Flash Player已经是WEB在线视频分发市场的领袖。在引入RTMFP和高级媒体压缩技术后,Flash Player成为实时通信领域的领袖。
这篇文章,首先强调了在实时通信应用程序中采用RTMFP的好处。之后,叙述了管理直接端到端RTMFP连接的AS3 API。最后,介绍了VideoPhone 应用样例。
RTMFP的优势:
RTMFP是一个在Flash Player 10 和AIR 1.5 中引入的全新通信协议。与RTMP的主要不同在于:RTMP是基于TCP并专门用于以前的Flash Player版本,而RTMFP建立于UDP之上。
虽然TCP提供了可靠的数据传送(对文件传输、电子邮件等非常适合),但它不能提供丝毫的端到端延迟保证。TCP通过在指定时间内重发丢失数据实 现可靠的数据传送。因为实时通信最重要的目标之一是最小化端到端的延迟(100ms的延迟可能致使会话不能使用),TCP并不适合。传送错误适应能力和恢 复能力是绝大多数高级音频视频压缩技术的必需的构成部分,例如已经在Flash Player 10中支持的Speex音频和H.264视频编码。因此不需要TCP提供的可靠传输。因此将提供高效而快速的数据传送的UDP,用于严格追求最小化端到端 延迟的实时协作应用,是为人所受的。另外UDP优于TCP的地方在于,它让端到端对等,它可以让位于NATs之后的两个客户端直接传送数据。
与RTMP比较,RTMFP在实时通讯方面具有以下优势:
低延迟:由于RTMFP建立于UDP之上,它为实时通信提供了最小的延迟。最重要的是RTMFP同时提供了可靠和不可靠两种传输服务。当在两个 Flash Player实例之间发送数据时(如:用NetStream.send()方法),采用可靠传输。当发送Speex音频实例时,采用不可靠传输,提供最小 化的延迟。
端到端的媒体传输:不需要通过中转服务器,即可在两个Flash Playerp实例之间发送媒体。RTMP会将所有数据发送到Flash Medai Server,RTMFP不仅最大限度地降低了端到端的延迟,而且还省掉了连接到中间数据转接的环节,以至于具有极强的可扩展部署能力。
优化数据:传送音频数据具有比视频和其他时间非关键数据更高的优先级别。这意味着可以在较紧张的带宽通信上增强用户体验。
较之前版本,这些功能为实时通信带来极大的益处,极大提升了用户体验。
防火墙穿越
RTMFP建立于UDP之上,UDP能让两个客户端直接连接,即使它们位于NAT或防火墙之后。为了能让RTMFP正常工作,你必须允许防火墙的对外UDP传送。大部分用户或SOHO防火墙、多数企业防火墙都关闭了UDP传送功能。
一种解决方案是配置Flash Player用TURN代理。Flash Player支持未经认证的IETF因特网草案。如果网管配置TURN代理为允许外出UDP,可以在mms.cfg中增加一行配置Flash Player。
RTMFPTURNProxy=ip_address_or_hostname_of_TURN_proxy
直接UDP传送总是尝试,TURN代理只是备用:用于UDP传送不能在Flash Player和Cirrus之间或Flash Player终端之间流动时。
即使你的防火墙打开了对外UDP传送,也可能由于综合防火墙不能建立端到端的对等连接。当一个终端位于“均衡防火墙”之后时,也许不能进行端对端通信。(对于分级防火墙,请参阅 )在这种情况下,你可以使用TURN代理辅助防火墙传输。
Cirrus 服务
Flash Player 实例要与另一个实例通信,就必需连接到Cirrus服务(使用rtmfp://p2p.rtmfp.net)。 Cirrus是一个帮助主持Flash Player实例之间进行联系会合的服务,即使它们都位于NATs之后。虽然连接到Cirrus服务非常类似于连接到FMS,但Cirrus不提供任何 FMS的特有功能(媒体延迟、共享对象、远程等)。Flash Player终端在通信期间必须保持与Cirrus服务的连接。为了使用Cirrus,需要一个开发key,这个可以在创建Adob Developer ID时生成。
在FMS 4中可以使用RTMFP支持。FMS可以让Flash Player 9 或早期客户端(用RTMP)与Flash Player 10 客户端通信。
安全
RTMFP提供了可靠的终端之间的通信。它采用128位AES加密Key,协商采用Diffie-Hellmann交流方式。不过,它不能提供像 SSL或RTMPS一样强的终端身份认证。为了帮助终端身份认证,RTMFP和ActionScript 对应用开发者公开安全随机数。要保证两个通讯的Flash Player终端的随机数相匹配。终端用户可通过校验这些随机数,以确保在传输过程中没有受到攻击。这些随机数也可以用于开发key连续机构。
值得注意的是Flash Player只能将你允许的麦克和摄像头发送到其他的Flash Player终端。
ActionScript 3 API supporting RTMFP
为了支持 RTMFP , Flash Player 10 中提供了一些新的 AS 3 API 。连接到 Cirrus 服务并创建类似于 FMS 下的端到端的媒体流。请注意,你必需在 Flash Professional ( CS4 或更新版本)或者 Flash Builder 4 中使用 AS 3 ,目标设置为 Flash Player 10 或 AIR 1.5 。
正如我之前所说,你需要先连接到 Cirrus 服务。
private const CirrusAddress:String = "rtmfp://p2p.rtmfp.net";
private const DeveloperKey:String = "your-developer-key";
private var netConnection:NetConnection;
netConnection = new NetConnection(); netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler); netConnection.connect(CirrusAddress + "/" + DeveloperKey);
当你用 Adobe Developer Connection 帐户登录到 Cirrus beta 服务站点上时,会分配一个开必 key 。
当成功连接到 Cirrus 上时,你获取一个 NetConnection.Connect.Success
事件。有几个连接失败的可能原因。如果你提供一个无效的开发key ,或者指定了错误的Cirrus 地址,你会收到 NetConnection.Connect.Failed 事件。如果你的防火墙锁定了对外UDP 传送,你会在90 秒超时后,收到 NetConnection.connect.Failed 事件。
在成功建立与 Cirruse 服务的连接后,将分配一个唯一的 256 位 peer ID 给你。为了接收你发布的音频、视频流,其它的 Flash Player 终端必需知道这个 peer ID 。怎样在相关 Flash Player 终端间交流这些 peer ID ,属于 Flash Player 或 Cirrus 服务范围之外。为了交换 peer ID ,可以用 XMPP 服务或一个简单的 WEB 服务,像 Video Phone 样例一般。
Flash Player 实例之间的直接通讯要使用单向 NetStream 通道。如果你想要两个音频会话,每一个 Flash Player 都必须创建一个发送 NetStream 和一个接收 NetStream 。
首先,创建一个发送流。
private var sendStream:NetStream;
sendStream = new NetStream(netConnection, NetStream.DIRECT_CONNECTIONS); sendStream.addEventListener(NetStatusEvent.NET_STATUS, netStreamHandler); sendStream.publish("media");
sendStream.attachAudio(Microphone.getMicrophone()); sendStream.attachCamera(Camera.getCamera());
这意味着媒体被发布为端到端的流。由于 Cirrus 不能中转媒体,你只能发布为端到端的流。这个流包括了本地默认设备的音频和视频,你可以通过 Settings Manager 选择默认的设备。
注意:直到有 FlashPlayer 同意接收媒体流,音频 / 视频才会被发送。
现在,创建接收流:
private var recvStream:NetStream;
recvStream = new NetStream(netConnection, id_of_publishing_client);
recvStream.addEventListener(NetStatusEvent.NET_STATUS, netStreamHandler); recvStream.play("media");
这时候,你将听到声音,你也能创建一个 Video 对象来显示视频。为了创建接收 NetStream ,你必需知道发布者的 256 位 peer ID 。为了接收音频 / 视频,你必需知道发布的流的名称。
Advanced topics
发布者可在终端之上精细控制哪些可以接收他发布的流。当一个用户试图去接收一个分发流时,在发布 NetStream 上的 onPeerConnect( ) 方法被调用(默认返回 true )。发布者可以驳回某些 Flash Player 终端接收媒体的请求。
o.onPeerConnect = function(subscriberStream:NetStream):Boolean
{
if (accept) {
return true;
}
else {
return false;
}
}
sendStream.client = o;
在发布者方面, NetStream.peerStreams 属性保存着所有订阅正在分发的 NetStream 的实例。例如,用 sendStream.send() 能发送同一数据到所有订阅者。你可以用下面的方法发送信息到指定订阅者。
sendStream.peerStreams[i].send()
NetConnection.maxPeerConnections 属性指定了允许连接到发布者的对等流的数量 。其默认值为 8 ,但实际上,是取决于你的应用程序,你必须考虑到大多数 ISP 提供非对称的互联网接入服务。 图 1 说明了三个 Flash Player 实例 直接通讯。每个 Flash Player 的客户端 发送和接收两个流,建立一个完全的连接网格。由于互联网下载的能力普遍高于上传的能力,你必须要格外小心,不要超最终用户的上行负荷。
Figure 1. End-to-end connections using the Cirrus service
图 1 ,使用 Cirrus 服务的端到端连接
NetConnection.unconnectedPeerStreams 属性是一个尚未与分发 NetStream 关联的 NetStreams 的数组。当一分发流与一个订阅流名称相同时,这个订阅 NetStream 从这个数组转移到分发的 NetStream.peerStreams 数组。
Exploring the Video Phone sample application
为了说明如何使用 Flash Player 10 的端到端功能,我们已经开发了一个 Video Phone 应用示例。它也是这份文档的一部分。
Video Phone 靠一个简单的 HTTP 服务交换 Flash Player peer ID 。该脚本作为包的一部分。此 WEB 服务不提供任何的用户身份认证。 Flash Player 在成功连接到 Cirrus 之后,注册一个 peer ID 。当拨通一个电话时, Video Phone 呼叫者通过 web 服务查找接受者的 ID 。
为了主办这个 Video Phone 样例, Adobe 专门运行这个 web 服务。在你建立自己的 Video Phone 样例时,你必须运行你自己的 web 服务,并在 VideoPhonLabs.mxml 中指定 WebServiceUrl 。你应该重写 AbstractIdManger 类去实现你自己的 peer ID 交换机制。例如, XMPP 协议、 Google 应用服务或 Facebook 框架。
建立 Video Phone 应用样例需要以下步骤:
- 使用提供的 reg.cgi Python 脚本,运行用于交换 peer ID 的 web 服务主机。
- 用 Flash Builder 4 创建一个新 Flex 项目。
- 将包中的源文件添加到项目中的 src 文件夹中。
- 在 VideoPhoneLabs.mxml 中用 DeveloperKey 指定你的 Cirrus 开发者 key 。
- 在 VideoPhoneLabs.mxml 文件中用
WebServiceUrl
指定 web 服务的 URL 。
本 Video Phone 应用示例使用了电视模型。呼叫建立过程是通过使用端到端 NetStream.send() 的信息。由于你只能在已创建的 NetStream 上使用 NetStream.send() 方法, Video Phone 发布一个所谓的“ listener stream ”(用固定名称)到其它能连接的 Flash Player 终端。当 A 用户(呼叫者)想要与 B 用户联系,他要订阅 B 用户的 listener stream 。这时候, B 用户收到呼叫者的 peer ID (用 onPeerConnect() )并订阅 A 用户的媒体流。通过这个媒体流, A 用户通知 B 用户有关他的用户友好的名字(用 NetStream.send() 方法),即用户可以选择接受或是拒绝呼叫。如果接受呼叫, B 用户发布媒体流,建立两路通讯。