RTMP协议规范1.0
译注
本文档主要翻译于http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf。
绝大部分使用直译,小部分使用意译。专有名词基本不翻译,既保留规范的原意,又不会感觉翻译起来怪怪的。
Adobe’s Real Time Messaging Protocol (RTMP)通过一个可靠的流传输通道提供双向的消息复用服务,流传输通道类似于TCP [RFC0793],目的是在通信双方之间并行传输带有关联时间信息的音视频流和数据消息。实现通常按不同类型的消息分配不同的优先级,从而在传输带宽受限时可以影响消息在底层流传输通道的入队顺序。
本文档描述了实时消息传递协议的语法和操作。
本文档中的关键词,"MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、
"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY"和"OPTIONAL",都在[RFC2119]中解释描述。
Rajesh Mallipeddi,Adobe System原成员,起草了本文档原始规范,并提供大部分的原始内容。
Mohit Srivastava,Adobe System成员,推动了本规范的发展。
Payload:包含在一个包中的数据,比如音频采样数据或者视频压缩数据。有效载荷的格式和解释超出了本文档的范围。
Packet:一个数据包由固定头header和payload数据组成。一些底层的协议可能需要定义该数据包的封装。
Port:传输协议用来区分在一个给定的主机内的多个目的地的抽象。TCP/IP协议使用小正整数来识别端口。OSI传输层使用的传输选择器(TSEL)相当于端口。
Transport address:网络地址和端口的组合用来识别一个传输层级别的端点,比如一个IP地址和TCP端口。包从源Transport address传输到目标的Transport address。
Message stream:消息流的逻辑传输通道。
Message stream ID:每个消息都有一个与它相关联的ID,以确定它的流在哪个消息流中。
Chunk:一段消息。消息被拆分成小的部分并且它们在网络发出去之前被转换。
Chunk stream:允许在一个特定方向上chunk流动的通信的逻辑通道。chunk stream可以从客户端传输到服务器或者反过来传输。
Chunk stream ID:每一块chunk都有一个与它关联的ID,以标识它所在的chunk stream。
Multiplexing:使单独的音频/视频数据转换成一个连贯的音频/视频流的过程,使得有可能同时传输多个视频和音频。
DeMultiplexing:复用的反向过程,其中交错的音频和视频数据被组装成原始的音频和视频数据。
Remote Procedure Call (RPC):允许客户端或服务器在对等端调用子程序或过程的请求。
Metadata:关于数据的描述。视频的元数据包括视频名称、持续时间、创作日期等。
Application Instance:服务器上的应用程序实例,客户端连接通过它来发送连接请求。
Action Message Format (AMF):一个紧凑的二进制格式,用于序列化的ActionScript对象图。AMF有两种版本:AMF 0 [AMF0]和AMF 3 [AMF3]。
所有的整型字段都使用网络字节序传输,字节0为第一个字节,第0位在一个字或字段中是最重要的位。这种字节顺序俗称为大端模式。这种传输顺序在IP协议[RFC0791]中详细描述。如果没有另外说明,本文档中的数字常量都是十进制。
除非另有规定,RTMP的所有数据都是字节对齐的;例如,一个16位的字段可能在一个奇数的字节偏移上。该位置如果指定填充,则填充字节值应该为零。
时间戳在RTMP是作为一个相对于未知时期的毫秒整数。通常,每个流将以时间戳0作为开始,但这不是必需的,只要两端在时间基准能达成一致即可。注意,这意味着任何在多个流的同步(尤其是独立的主机)需要一些RTMP之外的机制协助。
因为时间戳是32位长,他们每过49天,17小时,2分钟,47.296秒就会轮转。因为数据流允许连续地,甚至可能多年不断地运行,一个RTMP应用在处理时间戳时应该使用序列号算法[RFC1982],并且应该能够环绕式处理。 例如,一个应用程序假定所有相邻的时间戳在2 ^ 31 - 1毫秒内都是彼此相邻的,所以10000在4000000000后面,3000000000在4000000000的前面。
相对之前提到的时间戳,时间戳增量也可以表示为无符号整数的毫秒。时间戳增量可能是24或32位长。
本节详述实时消息协议块流(RTMP流块)。它为更高层次的多媒体流协议提供了复用和打包服务。
虽然RTMP块流设计工作于实时消息协议(第6节),但它可以处理任何发送一个消息流的协议。每个消息包含时间戳和payload类型识别。RTMP Chunk Stream和RTMP是适合多种音视频应用,包括一对一和一对多的直播点播服务,交互式视频会议应用。
当使用一个可靠的传输协议如TCP [RFC0793],RTMP Chunk Stream提供有保障的,按时间戳顺序的,端到端的,跨多个流的所有消息传输。RTMP Chunk Stream不提供任何优先级控制或类似的形式,但可以通过更高级别的协议提供这样的优先级顺序。例如,基于每一个消息的发送或确认时间,一个实时视频服务器可能会选择放弃一个缓慢的客户端视频消息,以确保音频消息是及时收到的。
RTMP Chunk Stream包括自带的协议控制信息,并且还为更高级别的协议嵌入用户控制消息提供了一种机制。
消息可以分割成多个chunk的格式,以支持取决于一个更高级别协议的复用。然而,消息格式应该包含用于创建chunk的以下字段。
Timestamp:消息的时间戳。这个字段可以传输4个字节。
Length:消息payload的长度。如果消息头不能省略,它应该包括在该长度中。此字段在chunk header中占用3个字节。
Type Id:一系列的类型ID被保留用于协议控制消息。这些传播信息的消息通过RTMP Chunk Stream协议和高层协议处理。所有其他类型的ID对高级别的协议是可用的,并被RTMP Chunk Stream视为不透明数值。事实上,在RTMP Chunk Stream中没有要求这些值被用来作为一个类型;所有(非协议)消息可能是同一类型,或应用程序可以使用此字段来区分同步轨道而不是类型。此字段占用chunk header中的1个字节。
Message Stream ID:消息流ID可以是任意的值。同一Chunk Stream上的不同的多路复用消息流是基于它们的消息流ID进行多路解码的。除此之外,据RTMP Chunk Stream而言,这是一个不透明的值。这个字段以小端格式在chunk header中占用4个字节。
RTMP连接以握手为开始。握手不同于协议的其余部分,它由三个静态大小的chunk,而不是由可变大小的带有头的chunk组成。
客户端(已启动连接的端点)和服务器每方都分别发送相同的三个chunk。为了方便表达,当由客户端发送时,这些chunk将被命名为C0,C1和C2;当由服务器发送时,它们被命名为S0,S1,S2。
握手开始,客户端发送C0,C1 chunk。
客户端必须等到S1收到之后才能发送C2。
客户端必须等到S2收到之后才能发送其他数据。
服务器必须等到C0或可能C1收到之后才能发送S0和S1。服务器必须等到C1收到之后才能发送S2。服务器必须等到C2收到之后才能发送其他数据。
C0和S0包是一个单字节,视为一个单一的8位整数字段:
以下是C0/S0包的字段:
Version(8位):在C0,此字段标识客户端所请求的RTMP协议版本。在S0,此字段标识服务器选择的RTMP协议版本。本规范定义的版本号为3。值0-2由先前专有产品使用,现已弃用;4-31留待将来实现;32-255不允许使用(以区分RTMP和文本协议,因为它总是以一个可打印字符为开始)。当识别不出客户端请求的版本时,服务器应该响应版本号3。客户端可能会选择降级到版本3,或放弃握手。
C1和S1包都是1536个字节长,包括以下字段:
Time (4字节):本字段包含一个时间戳,这应该作为未来从这个端点发出的所有块的时间基准。这可能是0,或一些任意的值。为了同步多个chunkstream,此端点可能要发送其他chunkstream的时间戳的当前值。
Zero(4个字节):这个字段必须都是0。
Random data (1528个字节):此字段可以包含任何任意值。由于每个端点必须区分它发起的握手的应答和对端发起的握手,这个数据应该发送足够随机的东西。但不需要加密的安全性,甚至不需要动态值。
C2和S2包都是1536个字节长,几乎是S1和C1的复制(分别地),它们包括以下字段:
Time(4个字节):该字段必须包含对方包内的发送时间戳,它分别在S1(对于C2)或C1(对于S2)。
Time2(4个字节):该字段必须包含对方前面的包(S1或C1)被读取的时间戳。
Random echo(1528个字节):该字段必须包含对方发送的包(S1或C1)的随机数字段,分别在S1(对于C2)和C1(对于S2)。每个端都可以使用time和time2字段与当前时间戳作为连接的带宽和/或延迟的快速评估,但这不太可能有用。
下面介绍握手图中所提到的状态:
Uninitialized:协议版本号在这个阶段中发送。客户端和服务器都是未初始化。该客户端在C0包发送协议版本号。如果服务器支持该版本,它将应答S0和S1。如果没有,服务器响采取适当的行为应答。在RTMP,这个动作是终止连接。
Version Sent:在未初始化状态之后,客户端和服务器都处在发送版本号的状态。客户端正在等待包S1,而服务器等待包C1。在收到期待的包之后,客户端发送数据包C2而服务器发送数据包S2。然后状态就变成Ack Sent。
Ack Sent:客户端和服务端分别等待S2和C2。
Handshake Done:客户端和服务器可以交换消息的状态。
在握手之后,连接多路复用一个或多个chunk stream。每个chunk stream都从一个消息流中传送一个类型的消息。创建的每个chunk都有一个与它关联的唯一标识,称为块流标识(chunk stream ID)。chunk在网络上传输。在传输的过程中,每一个chunk必须在下一个chunk之前全部发送。在接收端,chunk被组装成基于chunk stream ID的消息。
chunk允许更高层协议上的大消息分解成较小的信息,例如防止大的优先级低的消息(如视频)阻塞小的高优先级的消息(如音频或控制)。
chunk也让小消息以较小的开销被发送,因为chunk header包含压缩指示的信息,否则将被包含在消息本身。
chunk大小是可配置的。它可以使用chunk大小控制消息来设置(第5.4.1节)。较大的chunk大小降低了处理器的使用率,但也导致更大的写入,在连接带宽较低时,可以延迟其他内容。较小的chunk不适合高比特率的流。chunk大小在每个方向上都是独立维护的。
每一个chunk都包含头部和数据。头本身有三个部分:
Basic Header(1到3个字节):此字段对chunk stream ID和chunk type进行编码。chunk type决定message header的编码格式。它的长度完全取决于chunk stream ID,这是一个可变长度的字段。
Message Header(0,3,7或者11个字节):该字段对发送的消息进行编码(无论是在整体还是部分)。长度可以用chunk header中指定的chunk type来确定。
Extended Timestamp(0或者4个字节):这个字段在一定情况下出现,取决于Chunk Message header中编码的时间戳或时间戳差量。更多信息见5.3.1.3节。
Chunk Data(变长大小):此chunk的有效负载,大小不超过配置的最大块大小。
5.3.1.1. Chunk Basic Header
Chunk Basic Header编码chunk stream ID和chunk类型(按下图FMT字段表示)。chunk类型决定已编码的消息头的格式。Chunk Basic Header字段可能是1,2,或3个字节,这取决于chunk stream ID。
一个实现应该使用可以保存ID的最小表示(按需编码)。
该协议使用3-65599 的ID支持多达65597个流。0,1,和2的ID是保留值。值0表示2字节的形式,并且ID在64-319的范围(第二字节+64)。值1表示3字节的形式,并且ID在64-65599的范围(第三字节×256+第二个字节+64)。值范围为3-63代表完整的chunk stream ID。值为2的chunk stream ID是为低层协议控制信息和指令保留。
位0-5(最重要的)在Chunk Basic Header中代表chunk stream ID。
chunk stream ID 2-63可在这个字段用1字节的版本编码。
chunk stream ID 64-319可以在此头部用2字节的形式编码。ID的计算方法为(第二个字节+64)。
chunk stream ID 64-65599可以在此字段用3字节版本编码。ID的计算方法为(第三字节*256+第二字节+64)。
cs id(6个字节):本字段包含chunk stream ID,值从2-36。值0和1表示此字段的2或3字节版本。
fmt(2个字节):该字段标识“chunk message header”所使用的四种格式之一。每个chunk类型的“chunk message header”在下一节中解释。
cs id - 64(8或者16个字节):此字段包含chunk stream ID减去64的值。例如,ID 365将由cs id为1,和这里(cs id - 64)的一个16位的301表示。
chunk stream ID值64-319可以由2或3字节形式的头表示。
5.3.1.2. Chunk Message Header
有四种不同格式的chunk message header,由在chunk basic header的“fmt”字段决定。
一个实现应该使用可能为每个chunk message header的最紧凑的表示。
5.3.1.2.1. Type 0
类型0的chunk header是11个字节长。这种类型必须使用在一个chunk stream的开始,必要时,流时间戳可以后退(例如,由于回退定位)。
timestamp(3个字节):对于一个类型0的chunk,消息的绝对时间戳就在这里发送。如果时间戳大于或等于16777215(十六进制0xFFFFFF),该字段必须为16777215,表明扩展时间戳(Extended Timestamp)字段编码的出现,以能够编码完整的32位时间戳。否则,这个字段应该是整个时间戳。
5.3.1.2.2. Type 1
类型1的chunk header是7个字节长。不包含message stream ID;此chunk采用与前面的chunk相同的流ID。具有可变大小的消息的流(例如,许多视频格式)应该使用这个格式作为第一个之后的每一个新消息的第一个chunk。
5.3.1.2.3. Type 2
类型2的chunk header是3个字节长。既不包含流ID,也不包含消息长度,该chunk与前面的chunk具有相同的流ID和消息长度。具有常量大小的消息流(例如,一些音频和数据格式)应该使用这个格式作为第一个之后的每一个消息的第一个chunk。
5.3.1.2.4. Type 3
类型3的chunk没有消息头。流ID、消息长度和时间戳增量字段都不存在;这种类型的chunk采用与前面chunk相同的Chunk Stream ID。当一个独立的消息被分成chunk,除了第一个chunk之外,所有的消息chunk应该使用这种类型。参考实例2(5.3.2.2节)。一个由完全相同大小,流ID和时空消息组成的流在类型2的chunk之后应该都使用该类型的chunk。参考实例1(5.3.2.1节)。如果第一消息和第二消息的差量与第一个消息的时间戳是相同的,然后类型3的chunk可以立即跟随类型0的chunk,因为无需一个类型2的chunk表示该差量。如果一个类型3的chunk跟随着类型0的chunk,然后类型3的chunk的时间戳差量与类型0的chunk的时间戳相同。
5.3.1.2.5. Common Header Fields
chunk message header中每个字段的描述:
timestamp delta(3个字节):对于类型1或类型2的chunk,前面chunk的时间戳和当前chunk之间的区别就在此发送。如果差量大于或等于16777215(十六进制0xFFFFFF),该字段必须为16777215,表明Extended Timestamp字段的出现,以编码整个32位的时间戳。否则,这个字段应该是整个时间戳。
message length(3个字节):对于一个类型0或类型1的chunk,消息的长度在此发送。请注意,这通常与chunk payload的大小是不一样的。chunk payload的长度是除了最后一个chunk的所有chunk的最大大小,剩余部分(对于小消息来说,可能是整个长度)就是最后chunk的大小。
message type id(1个字节):对于类型0或类型1的chunk,消息的类型在此发送。
message stream id(4个字节):对于一个类型0的chunk,它存储的是message stream ID。Message stream ID以小端格式存储。通常情况下,相同chunk stream中的所有消息都来自于同一个message stream。虽然将message stream多路分离成相同的chunk stream是可能的,但它的效果比头部压缩的要差。然而,如果一个message stream关闭而另一个随后打开,但决没有理由说一个现有的chunk stream不能通过发送一个新的类型0的chunk以被重用。
5.3.1.3. Extended Timestamp
Extended Timestamp字段是用来编码大于16777215(0xFFFFFF)的时间戳或时间戳增量;也就是说,它是对于类型0,1或者2的chunk中24位的时间或时间戳增量满足不了的情况而设计的。这个字段编码完整的32位时间或时间戳增量。这个字段的出现表示对于16777215(0xFFFFFF)的情况,设置类型0的chunk的时间戳或者类型1、类型2的chunk的时间戳增量。当最近相同chunk stream ID的类型0,1,或2的chunk指示存在extended timestamp字段时,这个字段在类型3的chunk中出现。
5.3.2.1. Example 1
这个例子显示了一个简单的音频信息流。这个例子演示了信息的冗余。
下一个表格演示了在该流中产生的chunk。从消息3起,数据传输优化了。过了这一点之后 ,每个消息(头)只有1个字节的开销。
5.3.2.2. Example 2
此示例说明了一个消息因为太长,以至于无法适用一个128字节的chunk,从而被分解成多个chunk。
这里是产生的chunk:
Chunk 1的头数据指定了整个消息是307个字节。
从两个例子中注意到,类型3的chunk可以用在两种不同的方式中。第一种是指定消息的继续。第二种是指定一个新的消息的开始,它的头可以来自于现有的状态数据。
RTMP Chunk Stream使用消息类型ID 1,2,3,5,和6来做协议控制消息。这些消息包含了RTMP Chunk Stream协议所需的信息。
这些协议控制消息必须有message stream ID 0(被称为控制流),并以chunk stream ID 2被发送。协议控制信息一经被收到后立马生效,它们的时间戳是被忽略的。
协议控制消息1,Set Chunk Size,用于通知对端一个新的最大chunk大小。
最大chunk大小默认为128字节,但客户端或服务器可以更改此值,并使用此消息更新其对端的状态。例如,假设一个客户端要发送131个字节的音频数据,并且chunk大小为128字节。在这种情况下,客户端可以将此消息发送到服务器,通知它,chunk大小现在为131个字节。然后,客户端可以在一个chunk中发送该音频数据。
最大chunk大小应该至少有128个字节,并且必须至少是1个字节。最大chunk大小是独立于每个方向保持的。
0:这个位必须是0。
chunk size(31个字节):此字段保存了新的最大chunk大小,以字节为单位,它将用于所有的发送端的后续chunk,直到进一步通知。有效大小为1到2147483647(0x7FFFFFFF),包括2147483647本身;然而,所有大小大于16777215(0xFFFFFF)是等价的,因为没有chunk大于一个消息,没有消息大于16777215个字节。
协议控制消息2,Abort Message,用于通知对端,如果它是等待chunk来完成一个消息,然后丢弃在一个chunk stream上收到的部分消息。该端接收chunk stream ID作为该协议消息的payload。应用程序可以在关闭时发送此消息,以指示不需要进一步处理消息。
chunk stream ID(32位):这个字段保存了当前将被丢弃消息的chunk stream ID。
客户端或服务器必须在接收到等于窗口大小的字节后向对端发送一个acknowledgment确认。窗口大小是发送端没有从接收端接收到确认前发送的最大字节数。此消息指定了序列号,它是到目前为止接收到的字节数。
sequence number(32个字节):这个字段保存到目前为止接收到的字节数。
客户端或服务器发送此消息通知对方发送Acknowledgement之间的窗口大小。该发送端希望在它发送了窗口大小的字节数之后,从对端收到Acknowledgement。自上次Acknowledgement发送后,接收端接收指定的字节数后必须发送一个Acknowledgement(第5.4.3节),否则如果Acknowledgement还没有被发送,会话得从新开始。
客户端或服务器发送此消息以限制其对端的输出带宽。该端收到此消息后,通过限制未确认数据的发送量以达到输出带宽限制的目的,直到数据量达到此消息指定的窗口大小为止。该端收到此消息后,如果窗口大小与发送端上次发送该消息的不一样,它应该应答一个Window Acknowledgement Size的消息。
Limit Type是下列值之一:
0 - Hard:该端应该限制它的输出带宽,直到指定的窗口大小为止。
1 - Soft:无论哪一个的窗口更小,该端应该限制它的输出带宽直到此消息指定的窗口大小为止或者直到该限制已经有效果为止。
2 - Dynamic:如果前一个是硬限制类型,那么此消息被认为是硬限制类型,否则忽略此消息。
此节说明RTMP消息的格式。它基于使用更低级的传输层网络在实体之间传输,例如RTMP Chunk Stream。
虽然RTMP被设计于用RTMP Chunk Stream工作,但它可以使用任何其他的传输协议发送消息。RTMP Chunk Stream和RTMP是适合多种音视频应用,包括一对一和一对多的直播点播服务,交互式视频会议应用。
服务器和客户端通过网络发送RTMP消息来彼此通信。该消息可以包括音频、视频、数据或任何其他消息。
RTMP消息有两部分,一个头部和有效载荷。
消息头包含以下部分:
Message Type:1个字节字段以表示消息类型。范围1-6的ID类型被保留用作协议控制消息。
Length:3个字节的字段,表示payload的字节大小。它被制定为大端格式。
Timestamp:4个字节的字段,它包含该消息的时间戳。这4个字节以大端字节序封包。
Message Stream Id:3个字节的字段,标识消息流。这几个字节被制定为大端格式。
消息的另一部分是有效负载payload,这是消息中包含的实际数据。例如,它可以是一些音频采样或压缩的视频数据。payload的格式和解释超出了本文档的范围。
RTMP使用ID为4的消息类型作为用户控制消息。这些消息包含了RTMP streaming层使用到的信息。ID 1,2,3,5和6的协议消息被用于RTMP Chunk Stream协议(第5.4节)。
用户控制信息应该使用message stream ID 0(称为控制流),当基于RTMP Chunk Stream发送时,它被用chunk stream ID 2来发送。用户控制信息在流中被收到时立马生效;它们的时间戳被忽略。
客户端或服务器发送此消息以通知对端用户控件事件。此消息传输事件类型Event type和事件数据Event data。
前2个字节的消息数据用于标识事件类型。事件类型之后就是事件数据。事件数据字段的大小是可变的。然而,在消息通过RTMP Chunk Stream层传输的情况下,最大chunk大小(第5.4.1节)应该足够大,以让这些消息放在一个chunk中。
事件类型和事件数据在第7.1.7节中列举。
本节介绍了服务器和客户端之间相互通信的不同类型的消息和命令。
服务器和客户端之间交换的不同类型的消息包括用于发送音频数据的音频消息audio messages、用于发送视频数据的视频消息video messages、用于发送任何用户数据的数据消息data messages、共享对象消息shared object messages和命令消息command messages。共享对象消息提供了一个通用的方式来管理多个客户端和一个服务器之间的分布式数据。命令消息携带在客户端和服务器之间的AMF编码命令。客户端或服务器可以使用命令消息请求基于流的远程过程调用(RPC)与对方交流。
服务器和客户端通过网络上的消息互相通信。该消息可以是任何类型,其中包括音频消息、视频消息、命令消息、共享对象消息、数据消息和用户控制消息。
命令消息携带客户端和服务器之间的AMF编码命令。这些消息为AMF0编码分配消息类型值20,为AMF3编码分配消息类型值17。这些消息被发送到对端执行一些操作,如连接,创建流、发布、播放,暂停。命令消息类型于状态和结果等,被用来通知发送者的请求命令状态。命令消息由命令名称command name、事务标识transaction ID和包含相关参数的命令对象command object组成。客户端或服务器可以使用命令消息请求基于流的远程过程调用(RPC)与对方交流。
客户端或服务器通过此消息发送元数据或任何用户数据给对端。元数据包括数据(音频,视频等)的详细信息,如创建时间,持续时间,主题等。这些消息为AMF0和AMF3分别被分配消息类型值18和15。
共享对象是一个在跨多个客户端,实例等同步的Flash对象(名称-值对的集合)。消息类型19(对于AMF0)和16(对于AMF3)被保留用作共享对象事件shared object events。每个消息可以包含多个事件。
下面是支持的事件类型:
事件 |
描述 |
Use(=1) |
客户端发送此事件通知服务器一个名为共享对象的创建。 |
Release(=2) |
当在客户端删除共享对象时,客户端将此事件发送到服务器上。 |
Request Change(=3) |
客户端发送此事件以请求更改与共享对象命名参数关联的值。 |
Change (=4) |
服务器发送此事件通知除了正在发起请求之外的所有客户端命名参数值的变化。 |
Success (=5) |
如果请求被受理,服务器发送此事件给正在请求的客户端,以响应RequestChange事件。 |
SendMessage(=6) |
客户端将此事件发送到服务器以广播一个消息。在接收此事件时,服务器向所有客户端广播消息,包括该发送者。 |
Status (=7) |
服务器发送此事件以通知客户端相关的错误状况。 |
Clear (=8) |
服务器将此事件发送给客户端,以清除共享对象。服务器还发送清除共享对象。服务器还发送此事件响应客户端在连接时发送的使用事件Use event。 |
Remove (=9) |
服务器发送此事件让客户端删除一个插槽。 |
Request Remove(=10) |
客户端发送此事件让服务器删除一个插槽。 |
Use Success(=11) |
成功连接时,服务器将此事件发送给客户端。 |
客户端或服务器通过发送此消息发送音频数据到对端。消息类型值8被保留用作音频消息。
客户端或服务器通过发送此消息发送视频数据到对端。消息类型值9被保留用作视频消息。
一个聚合消息是一个单一的包含了一系列RTMP子消息的消息,它们的格式在6.1节描述。消息类型22用于聚合消息。
聚合消息的stream ID优先于聚合体内子消息的stream ID。
聚合消息和第一子消息的时间戳之间的差异是时间偏移,它被用于将子消息的时间戳归一化成流的时标。偏移量被加到每个子消息的时间戳,以变成归一化后的流时间。第一次子消息的时间戳应该与聚合消息的时间戳相同,所以偏移量应为0。
后面的指针包含在它头部中前一消息的大小。它被包含以匹配FLV文件格式并用于向后定位。
使用聚合消息有几个性能优势:
l chunk stream可以在一个chunk中至多发送一个完整的消息。因此,增加chunk的大小并且使用聚合消息减少了chunk发送的数量。
l 子消息可以连续存储在内存中。当产生系统调用在网络上发送数据时,它更有效的。
客户端和服务器发送此消息把用户控制事件通知对端。有关该消息的格式,请参考第6.2节。
以下是支持的用户控制事件:
事件 |
描述 |
Stream Begin (=0) |
服务器发送此事件通知客户端流已成为功能,并可用于通信。默认情况下,在从客户端成功收到应用程序连接命令后,此事件以ID 0来发送。 |
Stream EOF (=1) |
服务器发送此事件通知客户端该流请求的数据回放结束了。若不发出额外的命令,就没有更多的数据被发送了。客户端丢弃该流收到的消息。该4个字节的事件数据代表哪个stream ID的流播放已结束。 |
StreamDry (=2) |
服务器发送此事件通知客户端,在流上没有更多的数据。如果服务器在一段时间内没有检测到任何的消息,它可以通知订阅的客户端流是结束的。该4个字节的事件数据代表结束流的stream ID。 |
SetBufferLength (=3) |
客户端发送此事件通知服务器用于缓冲从流过来的任何数据的缓冲区大小(以毫秒为单位)。此事件在服务器开始处理流之前被发送。事件数据的前4个字节表示stream ID,而下面4个字节代表每毫秒缓冲区的长度。 |
StreamIsRecorded (=4) |
服务器发送此事件来通知客户端,该流是一个记录流。4个字节的事件数据代表记录流的stream ID。 |
PingRequest (=6) |
服务器发送此事件来测试客户端是否是可到达的。事件数据是4个字节的时间戳,代表当服务器发出命令时,本地服务器的时间。客户收到PingRequest时响应PingResponse。 |
PingResponse (=7) |
客户端向服务器发送此事件响应ping请求。事件数据是当收到PingRequest时的4个字节时间戳。 |
客户端和服务器交换AMF编码的命令。发送者发送一个命令消息,该命令消息包含命令名称command name、事务标识transaction ID和相关参数的命令对象command object。例如,连接命令包含“app”参数,它告诉服务器该客户端要连接的应用程序名称。接收端处理命令并使用相同的transaction ID回应。响应字符串要么是_result,要么是_error,要么是方法名method name,例如,方法名是verifyClient或contactExternalServer。
命令字符串_result或_error表示一个应答。transaction ID指示应答相关的重要命令。它与在IMAP等多种协议的标签tag是相同的。命令字符串中的方法名表示发送端正在试图在接收端运行一个方法。
下面类型的对象用于发送各种命令:
NetConnection:一个服务器和客户端之间的连接的一个更高级别表示的对象。
NetStream:一个表示发送音频流、视频流和其他相关数据的信道对象。我们还发送如播放,暂停等控制数据流的命令。
NetConnection管理客户端和服务器之间的双向连接。此外,它为异步远程方法调用提供了支持。
下面的命令可以在NetConnection上发送:
l connect
l call
l close
l createStream
7.2.1.1. Connect
客户端向服务器发送连接命令,请求连接到服务器应用程序实例。
从客户端到服务器的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令名称,设置为“connect”。 |
Transaction ID |
Number |
通常设置为1。 |
Command Object |
Object |
包含名称-值对的命令对象。 |
Optional User Arguments |
Object |
任何可选的信息。 |
以下是连接命令对象中使用的名称-值对的描述:
属性 |
类型 |
描述 |
样例值 |
app |
String |
客户端要连接的服务器应用程序名 |
testapp |
flashver |
String |
Flash Player的版本号。它与ApplicationScript中getversion()方法返回的字符串是一样的。 |
FMSc/1.0 |
swfUrl |
String |
发起连接的SWF源文件的URL |
file://C:/FlvPlayer.swf |
tcUrl |
String |
服务器URL。它具有以下的格式。 protocol://servername:port/appName/appInstance
|
rtmp://localhost:1935/testapp/instance1 |
fpad |
Boolean |
如果使用代理,值为true。 |
true或者false |
audioCodecs |
Number |
指示客户端支持的音频编码。 |
SUPPORT_SND_MP3 |
videoCodecs |
Number |
指示支持什么视频编码。 |
SUPPORT_VID_SORENSON |
videoFunction |
Number |
指示支持什么专用的视频方法。 |
SUPPORT_VID_CLIENT_SEEK |
pageUrl |
String |
SWF文件从哪里加载的网页URL。 |
http://somehost/sample.html |
objectEncoding |
Number |
AMF编码方法。 |
AMF3 |
audioCodecs属性的标志值:
编解码标志 |
用法 |
值 |
SUPPORT_SND_NONE |
原始音频,无压缩 |
0x0001 |
SUPPORT_SND_ADPCM |
ADPCM压缩 |
0x0002 |
SUPPORT_SND_MP3 |
mp3压缩 |
0x0004 |
SUPPORT_SND_INTEL |
未使用 |
0x0008 |
SUPPORT_SND_UNUSED |
未使用 |
0x0010 |
SUPPORT_SND_NELLY8 |
8-kHz采样速率的NellyMoser压缩 |
0x0020 |
SUPPORT_SND_NELLY |
NellyMoser压缩(5,11,22,和44 kHz采样速率) |
0x0040 |
SUPPORT_SND_G711A |
G711A声音压缩(仅Flash Media Server支持) |
0x0080 |
SUPPORT_SND_G711U |
G711U声音压缩(仅Flash Media Server支持) |
0x0100 |
SUPPORT_SND_NELLY16 |
16-kHz采样速率的NellyMoser压缩 |
0x0200 |
SUPPORT_SND_AAC |
高级音频编码(AAC)编解码 |
0x0400 |
SUPPORT_SND_SPEEX |
Speex音频 |
0x0800 |
SUPPORT_SND_ALL |
所有RTMP支持的音频编解码 |
0x0FFF |
videoCodecs属性的标志值:
编解码标志 |
用法 |
值 |
SUPPORT_VID_UNUSED |
废弃值 |
0x0001 |
SUPPORT_VID_JPEG |
废弃值 |
0x0002 |
SUPPORT_VID_SORENSON |
Sorenson Flash视频 |
0x0004 |
SUPPORT_VID_HOMEBREW |
V1屏幕共享 |
0x0008 |
SUPPORT_VID_VP6 (On2) |
On2视频(Flash 8+) |
0x0010 |
SUPPORT_VID_VP6ALPHA(On2 with alpha channel) |
带有alpha通道的On2视频 |
0x0020 |
SUPPORT_VID_HOMEBREWV(screensharing v2) |
屏幕共享版本2(Flash 8+) |
0x0040 |
SUPPORT_VID_H264 |
H264视频 |
0x0080 |
SUPPORT_VID_ALL |
所有的RTMP支持的视频编解码 |
0x00FF |
videoFunction属性的标志值:
方法标志 |
用法 |
值 |
SUPPORT_VID_CLIENT_SEEK |
指示客户端可以进行帧精确控制查找 |
1 |
对象编码属性的值:
编码类型 |
用法 |
值 |
AMF0 |
AMF0对象编码,Flash 6及更新版本支持 |
0 |
AMF1 |
来自于Flash 9的AMF3编码(AS3) |
3 |
从服务器到客户端的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
_result或者_error;表示响应是否为结果或者错误。 |
Transaction ID |
Number |
对于connect的应答来说,Transaction ID是1 |
Properties |
Object |
该连接的描述属性(fmsver等)的名称-值对。 |
Information |
Object |
来自于服务器的描述应答的名称-值对。“code”,“level”,“description”是这些信息的几个名称。 |
在该命令执行期间的消息流程是:
1. 客户端发送connect命令给服务器,请求与服务器应用程序实例连接。
2. 在收到connect命令之后,服务器给客户端发送“Window Acknowledgement Size”的协议消息。服务器也会连接connect命令提到的应用程序。
3. 服务器给客户端发送“Set Peer Bandwidth”协议消息。
4. 在处理“Set Peer Bandwidth”协议消息之后,客户端给服务器发送“Window Acknowledgement Size”的协议消息。
5. 服务器给客户端发送另一个类型的协议消息,用户控制消息(StreamBegin)。
6. 服务器发送result命令消息通知客户端该连接的状态(成功或失败)。该命令指定transaction ID(对于connect命令来说,它总是等于1)。该消息也会指定一些属性,如Flash Media Server的版本(字符串)。另外,它指定了其他连接应答相关的信息,比如级别(字符串),编码(字符串),描述(字符串),对象编码(数字)等。
7.2.1.2. Call
NetConnection对象的调用方法在接收端运行远程过程调用(RPC)。RPC调用的名称作为该call命令的参数传递。
发送端到接收端的命令结构如下所示:
字符名 |
类型 |
描述 |
Procedure Name |
String |
远程过程调用的名称。 |
Transaction ID |
Number |
如果需要一个应答,我们给出一个transaction Id。否则,我们传一个0的值。 |
Command Object |
Object |
如果存在任何的命令信息,它就会被设置,否则,它被设置为null类型。 |
Optional Arguments |
Object |
任何将要提供的可选参数。 |
应答的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
命令名称。 |
Transaction ID |
Number |
命令的ID,标识它属于哪个应答的。 |
Command Object |
Object |
如果存在任何的命令信息,它就会被设置,否则,它被设置为null类型。 |
Response |
Object |
该调用方法的应答。 |
7.2.1.3. createStream
客户端发送命令到服务器创建消息通信的逻辑通道。发布的音频、视频和元数据通过使用createStream命令创建的流通道传输。
NetConnection是默认的通信通道,它的stream ID为0。协议和少量命令消息,包括createStream,使用该默认的通信通道。
客户端到服务端的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
命令名称。设置为“createStream”。 |
Transaction ID |
Number |
命令的会话ID。 |
Command Object |
Object |
如果存在任何的命令信息,它就会被设置,否则,它被设置为null类型。 |
服务器到客户端的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
_result或者_error;表示响应是否为结果或者错误。 |
Transaction ID |
Number |
命令的ID,标识它属于哪个应答的。 |
Command Object |
Object |
如果存在任何的命令信息,它就会被设置,否则,它被设置为null类型。 |
Stream ID |
Number |
该返回值要么是stream ID,要么是一个错误信息对象。 |
NetStream定义了音频,视频和数据信息流可以在连通客户端到服务器的NetConnection上流通的通道。一个NetConnection对象可以支持多种数据流的多个NetStream。
以下命令可以在NetStream上从客户端发送到服务器:
l play
l play2
l deleteStream
l closeStream
l receiveAudio
l receiveVideo
l publish
l seek
l pause
服务器使用“onStatus”命令给客户端发送NetStream状态更新:
字段名 |
类型 |
描述 |
Command Name |
String |
命令名“onStatus”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
onStatus消息没有命令对象。 |
Info Object |
Object |
一个AMF对象至少有下面3种属性: “level”(字符串):此消息的级别,“warning”、“status”或者“error”其中之一; “code”(字符串):消息代码,比如“NetStream.Play.Start”; “description”(字符串):一个可读的消息描述。 Info对象可能包含其他适合编码的属性。 |
7.2.2.1. play
客户端将此命令发送到服务器播放流。也可以多次使用此命令创建一个播放列表。
如果你想创建一个在不同直播或录制流之间切换的动态播放列表,调用play不止一次并传递false以每次都重置。相反,如果你想立即播放指定的流,传递true以重置清除任何其他播放队列的流。
从客户端到服务端的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“play”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Stream Name |
String |
播放流的名称。如果要播放视频(FLV)文件,指定不带文件扩展名(比如,“sample”)的流名称。如果要回放MP3或者ID3标签,你必须要流名称前加上mp3:的前缀(比如,“mp3:sample”)。如果要播放H.264/AAC文件,你必须在流名称前加上mp4:的前缀,并且指定文件名后缀。比如,要播放文件sample.m4v,指定“mp4:sample.m4v”。 |
Start |
Number |
一个可选的参数,指定以秒为单位的起始时间。默认值为-2,意思是,该订阅者第一次尝试播放流名称字段指定的直播流。如果该名称的直播流没有被找到,它会播放同名的录播流。如果没有该名称的录播流,该订阅者等到该名称的直播流可用时再播放。如果你在Start字段中传递-1,那么只有流名称字段指定的直播流才会被播放。如果你在Start字段传递0或者一个正数,一个在流名称字段指定的录播流会被播放,起始时间是Start字段指定的时间。如果找不到该记录流,播放列表的下一个条目会被播放。 |
Duration |
Number |
一个可选的参数,指定以秒为单位的回放时间段。默认值是-1。-1值意味着,直播流被播放直到它不可用,或者录播流被播放直到结束。如果你传递0,它会播放录播流中Start字段指定开始时间的一帧。它假定Start字段的值大于等于0。如果你指定一个正数,它会播放Duration字段指定该段时间的直播流。之后,它能够播放Duration字段指定该段时间的录播流。(如果流在Duration字段指定的时间前结束,回放随着流的结束而结束。)如果你传递一个不同于-1的负数,它会把该值解析为-1。 |
Reset |
Boolean |
一个可选的布尔值或数字,它指定是否清除之前的所有播放列表。 |
在该命令执行期间的消息流程是:
1. 客户端在收到来自于服务器的createStream命令的成功结果后,发送play命令。
2. 在收到play命令的同时,服务器发送一个协议消息设置chunk的大小。
3. 服务器发送另一个协议消息(用户控制)指定“StreamIsRecorded”的事件,并且在该消息中带上stream ID。该消息在头2个字节带上事件类型并且在最后4个字节包含stream ID。
4. 服务器发送另一个协议消息(用户控制)指定“StreamBegin”事件,以向客户端指示流的开始。
5. 如果客户端发送的play命令成功的话,该服务器发送一个onStatus的命令消息NetStream.Play.Start和NetStream.Play.Reset。只有客户端发送的play命令带有reset标志时,服务器才会发送NetStream.Play.Reset。如果要播放的流没在被找到,服务器发送NetStream.Play.StreamNotFound的onStatus消息回应。
之后,服务器发送在客户端播放的音频和视频数据。
7.2.2.2. play2
不同于play命令,play2可以切换一个不同的码率而不改变播放内容的时间轴。服务器为客户端可以在play2中请求的所有支持的码率维护多个字段。
客户端到服务器的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“play2”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Parameters |
Object |
一个AMF编码的对象,它的属性是描述flash.net.NetStreamPlayOptions ActionScript对象的公有属性。 |
NetStreamPlayOptions对象的公共属性在ActionScript 3语言参考手册中描述。
该命令的消息流程如下图所示:
7.2.2.3. deleteStream
当NetStream对象将要被销毁时,它发送该deleteStream命令。
客户端到服务器的命令结构如下所示:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“deleteStream”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Stream ID |
Number |
在服务器上销毁流的ID。 |
该服务器不需要发送任何应答。
7.2.2.4. receiveAudio
NetStream发送receiveAudio消息通知服务器是否发送或不发送音频到客户端。
客户端到服务端的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“receiveAudio”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Bool Flag |
Boolean |
true或者false表示是否接收音频。 |
如果receiveAudio命令发送带有flase的bool flag,服务器不发送任何响应。如果这个标志被设置为true,服务器应答NetStream.Seek.Notify和NetStream.Play.Start的状态消息。
7.2.2.5. receiveVideo
NetStream发送receiveVideo消息通知服务器是否发送或不发送视频到客户端。
客户端到服务端的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“receiveVideo”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Bool Flag |
Boolean |
true或者false表示是否接收视频。 |
如果receiveVideo命令发送带有flase的bool flag,服务器不发送任何响应。如果这个标志被设置为true,服务器应答NetStream.Seek.Notify和NetStream.Play.Start的状态消息。
7.2.2.6. publish
客户端发送publish命令将已命名的流发布到服务器上。使用这个名称,任何客户端都可以播放此流,并接收已发布的音频、视频和数据消息。
客户端到服务端的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“publish”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Publishing Name |
String |
发布流的名称。 |
Publishing Type |
String |
发布的类型。设置为“live”,“record”或者“append”。 record:该流已被发布并且数据被记录到一个新的文件。该文件存储在服务器的一个包含服务器应用程序目录的子目录。如果文件已经存在,则它被覆盖。 append:流已经被发布,并且该数据被追加到一个文件。如果找不到文件,则创建它。 live:直播数据被发布,而没有记录到文件。 |
服务器应答onStatus命令,以标记发布的开始。
7.2.2.7. seek
客户端发送seek命令以定位媒体文件内或者播放列表的某个位置(以毫秒为单位)。
客户端到服务端的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“seek”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
milliSeconds |
Number |
定位到播放列表的毫秒数。 |
当定位成功,服务器发送NetStream.Seek.Notify的状态消息。失败的时候,它返回一个_error的消息。
7.2.2.8. pause
客户端发送pause命令以告诉服务器暂停或者开始播放。
客户端到服务端的命令结构如下:
字段名 |
类型 |
描述 |
Command Name |
String |
命令的名称,设置为“pause”。 |
Transaction ID |
Number |
Transaction ID设置为0。 |
Command Object |
Null |
不存在命令信息,设置为null类型。 |
Pause/Unpause Flag |
Boolean |
true或者false,以表示暂停或者恢复播放。 |
milliSeconds |
Number |
毫秒数,在流的哪个位置被暂停或者恢复播放的。当流被暂停,这就是客户端的当前流的时间。当播放被恢复,该服务器仅会发送带有大于此值的时间戳的消息。 |
当流被暂停,服务器发送一个NetStream.Pause.Notify的状态消息。当一个流变成未暂停状态,NetStream.Unpause.Notify被发送。失败的时候,它返回一个_error的消息。
这里是一些样例,以解释使用RTMP的消息交换。
这个例子说明了一个发布者如何可以发布一个流,然后将视频推流到服务器上。其他客户端可以订阅这个已发布的流,并播放视频。
这个例子说明了在创建和更改共享对象时所交换的消息。它也说明了共享对象消息广播的过程。
这个例子描述了发布元数据的消息交换。
[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791,
September 1981.
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, September 1981.
[RFC1982] Elz, R. and R. Bush, "Serial Number Arithmetic", RFC 1982,
August 1996.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[AS3] Adobe Systems, Inc., "ActionScript 3.0 Reference for the
Adobe Flash Platform", 2011, actionscript/documentation.html>. [AMF0] Adobe Systems, Inc., "Action Message Format -- AMF 0", December 2007, attachments/1114283/amf0_spec_121207.pdf>. [AMF3] Adobe Systems, Inc., "Action Message Format -- AMF 3", May 2008, attachments/1114283/amf3_spec_05_05_08.pdf>. Authors’ Addresses Hardeep Singh Parmar (editor) Adobe Systems Incorporated 345 Park Ave San Jose, CA 95110-2704 US Phone: +1 408 536 6000 Email: [email protected] URI: http://www.adobe.com/ Michael C. Thornburgh (editor) Adobe Systems Incorporated 345 Park Ave San Jose, CA 95110-2704 US Phone: +1 408 536 6000 Email: [email protected] URI: http://www.adobe.com/