RTMP协议规范_1.0

译注

本文档主要翻译于rtmp specification 1.0

绝大部分使用直译,小部分使用意译。专有名词基本不翻译,既保留规范的原意,又不会感觉翻译起来怪怪的。

Introduction

Adobe’s Real Time Messaging Protocol (RTMP)通过一个可靠的流传输通道提供双向的消息复用服务,流传输通道类似于 TCP [RFC0793],目的是在通信双方之间并行传输带有关联时间信息的音视频流和数据消息。实现通常按不同类型的消息分配不同的优先级,从而在传输带宽受限时可以影响消息在底层流传输通道的入队顺序。
本文档描述了实时消息传递协议的语法和操作。

Terminology

本文档中的关键词,”MUST”、”MUST NOT”、”REQUIRED”、”SHALL”、”SHALL NOT”、
“SHOULD”、”SHOULD NOT”、”RECOMMENDED”、”NOT
RECOMMENDED”、”MAY”和”OPTIONAL”,都在[RFC2119]中解释描述。

Contributors

Rajesh Mallipeddi,Adobe System 原成员,起草了本文档原始规范,并提供大部分的原始内容。
Mohit Srivastava,Adobe System 成员,推动了本规范的发展。

Definitions

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]。

Byte Order, Alignment, and Time Format

所有的整型字段都使用网络字节序传输,字节 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 Chunk Stream

本节详述实时消息协议块流(RTMP 流块)。它为更高层次的多媒体流协议提供了复用和打包服务。
虽然 RTMP 块流设计工作于实时消息协议(第 6 节),但它可以处理任何发送一个消息流的协议。每个消息包含时间戳和 payload 类型识别。RTMP Chunk
Stream 和 RTMP 是适合多种音视频应用,包括一对一和一对多的直播点播服务, 交互式视频会议应用。
当使用一个可靠的传输协议如 TCP [RFC0793],RTMP Chunk Stream 提供有保障的,按时间戳顺序的,端到端的,跨多个流的所有消息传输。RTMP Chunk Stream 不提供任何优先级控制或类似的形式,但可以通过更高级别的协议提供这样的优先级顺序。例如,基于每一个消息的发送或确认时间,一个实时视频服务器可能会选择放弃一个缓慢的客户端视频消息,以确保音频消息是及时收到的。
RTMP Chunk Stream 包括自带的协议控制信息,并且还为更高级别的协议嵌入用户控制消息提供了一种机制。

Message Format

消息可以分割成多个 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 个字节。

Handshake

RTMP 连接以握手为开始。握手不同于协议的其余部分,它由三个静态大小的 chunk,而不是由可变大小的带有头的 chunk 组成。
客户端(已启动连接的端点)和服务器每方都分别发送相同的三个 chunk。为了方便表达,当由客户端发送时,这些 chunk 将被命名为 C0,C1 和 C2;当由服务器发送时,它们被命名为 S0,S1,S2。

Handshake Sequence

握手开始,客户端发送 C0,C1 chunk。
客户端必须等到 S1 收到之后才能发送 C2。
客户端必须等到 S2 收到之后才能发送其他数据。

服务器必须等到 C0 或可能 C1 收到之后才能发送 S0 和 S1。服务器必须等到 C1 收到之后才能发送 S2。服务器必须等到 C2 收到之后才能发送其他数据。

C0 and S0 Format

C0 和 S0 包是一个单字节,视为一个单一的 8 位整数字段:
C0_S0_bits
以下是 C0/S0 包的字段:
Version(8 位):在 C0,此字段标识客户端所请求的 RTMP 协议版本。在
S0,此字段标识服务器选择的 RTMP 协议版本。本规范定义的版本号为 3。值0-2 由先前专有产品使用,现已弃用;4-31 留待将来实现;32-255 不允许使用(以区分 RTMP 和文本协议,因为它总是以一个可打印字符为开始)。当识别不出客户端请求的版本时,服务器应该响应版本号 3。客户端可能会选择降级到版本3,或放弃握手。

C1 and S1 Format

C1 和 S1 包都是 1536 个字节长,包括以下字段:
C1_S1_bits
Time (4 字节):本字段包含一个时间戳,这应该作为未来从这个端点发出的所有块的时间基准。这可能是 0 , 或一些任意的值。为了同步多个chunkstream,此端点可能要发送其他 chunkstream 的时间戳的当前值。
Zero(4 个字节):这个字段必须都是 0。
Random data (1528 个字节):此字段可以包含任何任意值。由于每个端点必须区分它发起的握手的应答和对端发起的握手,这个数据应该发送足够随机的东西。但不需要加密的安全性,甚至不需要动态值。

C2 and S2 Format

C2 和 S2 包都是 1536 个字节长,几乎是 S1 和 C1 的复制(分别地),它们包括以下字段:
C2_S2_bits

Time(4 个字节):该字段必须包含对方包内的发送时间戳,它分别在 S1
( 对 于 C2) 或 C1( 对 于 S2) 。
Time2(4 个字节):该字段必须包含对方前面的包(S1 或 C1)被读取的时间戳。
Random echo(1528 个字节):该字段必须包含对方发送的包(S1 或 C1) 的随机数字段,分别在 S1(对于 C2)和 C1(对于 S2)。每个端都可以使用 time 和 time2 字段与当前时间戳作为连接的带宽和/或延迟的快速评估,但这不太可能有用。

Handshake Diagram

PictorialRepresentationHandshake

下面介绍握手图中所提到的状态:
Uninitialized:协议版本号在这个阶段中发送。客户端和服务器都是未初始化。该客户端在 C0 包发送协议版本号。如果服务器支持该版本,它将应答 S0 和 S1。如果没有,服务器响采取适当的行为应答。在 RTMP,这个动作是终止连接。
Version Sent:在未初始化状态之后,客户端和服务器都处在发送版本号的状态。客户端正在等待包 S1,而服务器等待包 C1。在收到期待的包之后,客户端发送数据包 C2 而服务器发送数据包 S2。然后状态就变成 Ack Sent。
Ack Sent:客户端和服务端分别等待 S2 和 C2。
Handshake Done:客户端和服务器可以交换消息的状态。

Chunking

在握手之后,连接多路复用一个或多个 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 Format

每一个 chunk 都包含头部和数据。头本身有三个部分:

ChunkFormat

Basic Header(1 到 3 个字节):此字段对 chunk stream ID 和 chunk type 进行编码。chunk type 决定 message header 的编码格式。它的长度完全取决于 chunk stream ID,这是一个可变长度的字段。
Message Header(0,3,7 或者 1 个字节):该字段对发送的消息进行编码
(无论是在整体还是部分)。长度可以用 chunk header 中指定的 chunk type 来确定。
Extended Timestamp(0 或者 4 个字节):这个字段在一定情况下出现,取决于 Chunk Message header 中编码的时间戳或时间戳差量。更多信息见 5.3.1.3 节。
Chunk Data(变长大小):此 chunk 的有效负载,大小不超过配置的最大块大小。

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 字节的版本编码。

ChunkBasicHeader1

chunk stream ID 64-319 可以在此头部用 2 字节的形式编码。ID 的计算方法为(第二个字节+64)。

ChunkBasicHeader2

chunk stream ID 64-65599 可以在此字段用 3 字节版本编码。ID 的计算方法为(第三字节*256+第二字节+64)。

ChunkBasicHeader3

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 字节形式的头表示。

Chunk Message Header

有四种不同格式的 chunk message header,由在 chunk basic header 的“fmt” 字段决定。
一个实现应该使用可能为每个 chunk message header 的最紧凑的表示。

Type 0

类型0 的chunk header 是11 个字节长。这种类型必须使用在一个chunk stream
的开始,必要时,流时间戳可以后退(例如,由于回退定位)。

ChunkMessageHeaderType0

timestamp(3 个字节):对于一个类型 0 的 chunk,消息的绝对时间戳就在这里发送。如果时间戳大于或等于 16777215(十六进制 0xFFFFFF),该字段必须为 16777215,表明扩展时间戳(Extended Timestamp)字段编码的出现,以能够编码完整的 32 位时间戳。否则,这个字段应该是整个时间戳。

Type 1

类型 1 的 chunk header 是 7 个字节长。不包含 message stream ID;此 chunk 采用与前面的 chunk 相同的流 ID。具有可变大小的消息的流(例如,许多视频格式)应该使用这个格式作为第一个之后的每一个新消息的第一个 chunk。

ChunkMessageHeaderType1

Type 2

类型 2 的 chunk header 是 3 个字节长。既不包含流 ID,也不包含消息长度, 该 chunk 与前面的 chunk 具有相同的流 ID 和消息长度。具有常量大小的消息流

(例如,一些音频和数据格式)应该使用这个格式作为第一个之后的每一个消息的第一个 chunk。

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 的时间戳相同。

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 以被重用。

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 中出现。

Examples

Example 1

这个例子显示了一个简单的音频信息流。这个例子演示了信息的冗余。

下一个表格演示了在该流中产生的chunk。从消息3起,数据传输优化了。过了这一点之后 ,每个消息(头)只有1个字节的开销。

Example 2

此示例说明了一个消息因为太长,以至于无法适用一个128字节的chunk,从而被分解成多个chunk。

这里是产生的chunk:

Chunk 1的头数据指定了整个消息是307个字节。
从两个例子中注意到,类型3的chunk可以用在两种不同的方式中。第一种是指定消息的继续。第二种是指定一个新的消息的开始,它的头可以来自于现有的状态数据。

Protocol Control Messages

RTMP Chunk Stream使用消息类型ID 1,2,3,5,和6来做协议控制消息。这些消息包含了RTMP Chunk Stream协议所需的信息。
这些协议控制消息必须有message stream ID 0(被称为控制流),并以chunk stream ID 2被发送。协议控制信息一经被收到后立马生效,它们的时间戳是被忽略的。

Set Chunk Size (1)

协议控制消息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个字节。

Abort Message (2)

协议控制消息2,Abort Message,用于通知对端,如果它是等待chunk来完成一个消息,然后丢弃在一个chunk stream上收到的部分消息。该端接收chunk stream ID作为该协议消息的payload。应用程序可以在关闭时发送此消息,以指示不需要进一步处理消息。

chunk stream ID(32位):这个字段保存了当前将被丢弃消息的chunk stream ID。

Acknowledgement (3)

客户端或服务器必须在接收到等于窗口大小的字节后向对端发送一个acknowledgment确认。窗口大小是发送端没有从接收端接收到确认前发送的最大字节数。此消息指定了序列号,它是到目前为止接收到的字节数。

sequence number(32个字节):这个字段保存到目前为止接收到的字节数。

Window Acknowledgement Size (5)

客户端或服务器发送此消息通知对方发送Acknowledgement之间的窗口大小。该发送端希望在它发送了窗口大小的字节数之后,从对端收到Acknowledgement。自上次Acknowledgement发送后,接收端接收指定的字节数后必须发送一个Acknowledgement(第5.4.3节),否则如果Acknowledgement还没有被发送,会话得从新开始。

Set Peer Bandwidth (6)

客户端或服务器发送此消息以限制其对端的输出带宽。该端收到此消息后,通过限制未确认数据的发送量以达到输出带宽限制的目的,直到数据量达到此消息指定的窗口大小为止。该端收到此消息后,如果窗口大小与发送端上次发送该消息的不一样,它应该应答一个Window Acknowledgement Size的消息。

Limit Type是下列值之一:
0 - Hard:该端应该限制它的输出带宽,直到指定的窗口大小为止。
1 - Soft:无论哪一个的窗口更小,该端应该限制它的输出带宽直到此消息指定的窗口大小为止或者直到该限制已经有效果为止。
2 - Dynamic:如果前一个是硬限制类型,那么此消息被认为是硬限制类型,否则忽略此消息。

RTMP Message Formats

此节说明RTMP消息的格式。它基于使用更低级的传输层网络在实体之间传输,例如RTMP Chunk Stream。
虽然RTMP被设计于用RTMP Chunk Stream工作,但它可以使用任何其他的传输协议发送消息。RTMP Chunk Stream和RTMP是适合多种音视频应用,包括一对一和一对多的直播点播服务,交互式视频会议应用。

RTMP Message Format

服务器和客户端通过网络发送RTMP消息来彼此通信。该消息可以包括音频、视频、数据或任何其他消息。
RTMP消息有两部分,一个头部和有效载荷。

Message Header

消息头包含以下部分:
Message Type:1个字节字段以表示消息类型。范围1-6的ID类型被保留用作协议控制消息。
Length:3个字节的字段,表示payload的字节大小。它被制定为大端格式。
Timestamp:4个字节的字段,它包含该消息的时间戳。这4个字节以大端字节序封包。
Message Stream Id:3个字节的字段,标识消息流。这几个字节被制定为大端格式。

Message Payload

消息的另一部分是有效负载payload,这是消息中包含的实际数据。例如,它可以是一些音频采样或压缩的视频数据。payload的格式和解释超出了本文档的范围。

User Control Messages (4)

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节中列举。

RTMP Command Messages

本节介绍了服务器和客户端之间相互通信的不同类型的消息和命令。
服务器和客户端之间交换的不同类型的消息包括用于发送音频数据的音频消息audio messages、用于发送视频数据的视频消息video messages、用于发送任何用户数据的数据消息data messages、共享对象消息shared object messages和命令消息command messages。共享对象消息提供了一个通用的方式来管理多个客户端和一个服务器之间的分布式数据。命令消息携带在客户端和服务器之间的AMF编码命令。客户端或服务器可以使用命令消息请求基于流的远程过程调用(RPC)与对方交流。

Types of Messages

服务器和客户端通过网络上的消息互相通信。该消息可以是任何类型,其中包括音频消息、视频消息、命令消息、共享对象消息、数据消息和用户控制消息。

Command Message (20, 17)

命令消息携带客户端和服务器之间的AMF编码命令。这些消息为AMF0编码分配消息类型值20,为AMF3 编码分配消息类型值17。这些消息被发送到对端执行一些操作,如连接,创建流、发布、播放,暂停。命令消息类型于状态和结果等,被用来通知发送者的请求命令状态。命令消息由命令名称command name、事务标识transaction ID和包含相关参数的命令对象command object组成。客户端或服务器可以使用命令消息请求基于流的远程过程调用(RPC)与对方交流。

Data Message (18, 15)

客户端或服务器通过此消息发送元数据或任何用户数据给对端。元数据包括数据(音频,视频等)的详细信息,如创建时间,持续时间,主题等。这些消息为AMF0和AMF3分别被分配消息类型值18和15。

Shared Object Message (19, 16)

共享对象是一个在跨多个客户端,实例等同步的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) 成功连接时,服务器将此事件发送给客户端。

Audio Message (8)

客户端或服务器通过发送此消息发送音频数据到对端。消息类型值8被保留用作音频消息。

Video Message (9)

客户端或服务器通过发送此消息发送视频数据到对端。消息类型值9被保留用作视频消息。

Aggregate Message (22)

一个聚合消息是一个单一的包含了一系列RTMP子消息的消息,它们的格式在6.1节描述。消息类型22用于聚合消息。

聚合消息的stream ID优先于聚合体内子消息的stream ID。
聚合消息和第一子消息的时间戳之间的差异是时间偏移,它被用于将子消息的时间戳归一化成流的时标。偏移量被加到每个子消息的时间戳,以变成归一化后的流时间。第一次子消息的时间戳应该与聚合消息的时间戳相同,所以偏移量应为0。
后面的指针包含在它头部中前一消息的大小。它被包含以匹配FLV文件格式并用于向后定位。
使用聚合消息有几个性能优势:

  • chunk stream可以在一个chunk中至多发送一个完整的消息。因此,增加chunk的大小并且使用聚合消息减少了chunk发送的数量。
  • 子消息可以连续存储在内存中。当产生系统调用在网络上发送数据时,它更有效的。

User Control Message Events

客户端和服务器发送此消息把用户控制事件通知对端。有关该消息的格式,请参考第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个字节时间戳。

Types of Commands

客户端和服务器交换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 Commands

NetConnection管理客户端和服务器之间的双向连接。此外,它为异步远程方法调用提供了支持。
下面的命令可以在NetConnection上发送:

  • connect
  • call
  • close
  • createStream

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的版本(字符串)。另外,它指定了其他连接应答相关的信息,比如级别(字符串),编码(字符串),描述(字符串),对象编码(数字)等。

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 该调用方法的应答。

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 Commands

NetStream定义了音频,视频和数据信息流可以在连通客户端到服务器的NetConnection上流通的通道。一个NetConnection对象可以支持多种数据流的多个NetStream。
以下命令可以在NetStream上从客户端发送到服务器:

  • play
  • play2
  • deleteStream
  • closeStream
  • receiveAudio
  • receiveVideo
  • publish
  • seek
  • 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对象可能包含其他适合编码的属性。

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消息回应。

之后,服务器发送音频和视频数据在客户端播放。

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语言参考手册中描述。
该命令的消息流程如下图所示:

deleteStream

当NetStream对象将要被销毁时,它发送该deleteStream命令。
客户端到服务器的命令结构如下所示:

字段名 类型 描述
Command Name String 命令的名称,设置为“deleteStream”。
Transaction ID Number Transaction ID设置为0。
Command Object Null 不存在命令信息,设置为null类型。
Stream ID Number 在服务器上销毁流的ID。

该服务器不需要发送任何应答。

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的状态消息。

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的状态消息。

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命令,以标记发布的开始。

seek

客户端发送seek命令以定位媒体文件内或者播放列表的某个位置(以毫秒为单位)。
客户端到服务端的命令结构如下:

字段名 类型 描述
Command Name String 命令的名称,设置为“seek”。
Transaction ID Number Transaction ID设置为0。
Command Object Null 不存在命令信息,设置为null类型。
milliSeconds Number 定位到播放列表的毫秒数。

当定位成功,服务器发送NetStream.Seek.Notify的状态消息。失败的时候,它返回一个_error的消息。

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的消息。

Message Exchange Examples

这里是一些样例,以解释使用RTMP的消息交换。

Publish Recorded Video

这个例子说明了一个发布者如何可以发布一个流,然后将视频推流到服务器上。其他客户端可以订阅这个已发布的流,并播放视频。

Broadcast a Shared Object Message

这个例子说明了在创建和更改共享对象时所交换的消息。它也说明了共享对象消息广播的过程。

Publish Metadata from Recorded Stream

这个例子描述了发布元数据的消息交换。

References


[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, <http://www.adobe.com/devnet/
actionscript/documentation.html>.
[AMF0] Adobe Systems, Inc., “Action Message Format – AMF 0”,
December 2007, <http://opensource.adobe.com/wiki/download/
attachments/1114283/amf0_spec_121207.pdf>.
[AMF3] Adobe Systems, Inc., “Action Message Format – AMF 3”,
May 2008, <http://opensource.adobe.com/wiki/download/
attachments/1114283/amf3_spec_05_05_08.pdf>.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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/

感谢你的阅读,如果文章对你有帮助,可以请作者喝杯茶!