网络流媒体协议之——RTMP协议(Part II)

在上一篇网络流媒体协议之——RTMP协议(Part I)中,介绍了RMP协议的基本message结构与chunk格式,本篇我们来更深入地来了解一下RTMP中的消息交互。分成三个部分来介绍,分别是Handshake、控制消息与交互、命令消息与交互。

1. Handshake

RTMP 连接的建立首先通过握手(handshake)开始。Handshake消息不同于协议的其他消息,并非由可变大小的chunk和chunk header组成,而是由固定大小的三个chunks组成。客户端和服务器依次发送这三个同样的chunks,为了方便表述,客户端发送的三个chunks记为C0,C1和C2,服务器端发送的三个chunks记为S0,S1和S2。

1.1  Handshake Sequence

Handshake始于客户端发送C0和C1,RTMP协议并没有严格规定6个Handshake message发送顺序,但有如下几个限制:

  • 客户端必须收到S1后,才能发送C2;
  • 客户端必须收到S2后,才能发送其他数据;
  • 服务器端必须收到C0后,才能发送S0和S1;
  • 服务器端必须收到C1后,才能发送S2;
  • 服务器端必须收到C2后才能发送其他数据。

Handshake sequence如下图所示,

网络流媒体协议之——RTMP协议(Part II)

在实际使用中,一般的Handshake顺序是这样的:

client Server |

|---C0+C1->|

<--S0+S1+S2|

|---C2---->

下面是通过PC播放香港电视台直播,并通过wireshark抓包得到的RTMP握手过程,

网络流媒体协议之——RTMP协议(Part II)

1.2  C0、S0 Format

C0和S0为单字节chunk,格式如下:

网络流媒体协议之——RTMP协议(Part II)

Version表示RTMP协议的版本号,目前使用的是版本3。例如,前面抓取的香港电视台直播的handshake message,将,C0和S0的包展开如下:

网络流媒体协议之——RTMP协议(Part II)

网络流媒体协议之——RTMP协议(Part II)

1.3  C1、S1 Format

C1和S1 message长1536字节,包含如下组成:

网络流媒体协议之——RTMP协议(Part II)

Time:4 bytes的时间戳;

Zero:4 bytes的全零域;

Random bytes:1528 bytes的随机数。

1.4  C2、S2 Format

C2和S2 的包也是1536字节长,几乎分别是对S1和C1的回声,其组成如下:
网络流媒体协议之——RTMP协议(Part II)
Time:对于C2来说,该域的值与S1的time域相同;对于S2来说,该域的值与C1的time域相同。
Time2:该域存储的是对端送来的上一个packet(S1或C1)被读取的时间。
Random echo:该域的数据必须是S1(对于C2来说)和C1(对于S2来说)域中的数据。为了验证这一点,我们再来看wireshark抓取得handshake包,展开S1和C2,如下所示,发现S1的random data和C2的random echo数据是完全相同的。
网络流媒体协议之——RTMP协议(Part II)
再来看C1和S2,不一样?Why?
网络流媒体协议之——RTMP协议(Part II)

2. Protocol Control Messages

RTMP Chunk Stream将message type ID 1,2,3,5和6用于协议控制消息,这些协议控制消息必须使用message stream ID 0(即控制流ID),并在chunk stream ID (CSID) 2上发送。协议控制消息在被接收到的瞬间生效,其时间戳被接收端忽略。下面我们按照不同的message type ID来分别介绍几种不同的协议控制消息。

2.1 Set Chunk Size (message type ID = 1)

Set Chunk Size消息使用协议控制消息ID 1,用于通知对端新的最大chunk size。最大chunk size默认为128字节,但客户端和服务器都可以修改该值,并通过Set Chunk Size命令通知对端更新。例如,假如客户端要发送131 bytes大小的音频数据至服务器端,而当前的chunk size为128 bytes,那么客户端就可以通过Set Chunk Size消息告知服务器端最新的chunk size是131 bytes,从而,客户端即可在1个chunk上发送131 bytes的音频数据了。最大chunk size至少为1 byte,客户端和服务器端两方均可维护自己的最大chunk size。
下面为Set Chunk Size的message payload:

网络流媒体协议之——RTMP协议(Part II)
位必须为0。Chunk Size占31位,最大值为2147483647(0x7FFFFFFF),但实际上所有大于16777215(0xFFFFFF)的值都认为等于16777215,因为Message的最大长度为0xFFFFFF,而chunk size不可能大于Message的长度。

2.2 Abort Message (message type ID = 2)

当一个message被切分成多个chunks,接收端只接收到了部分chunks时,发送该控制消息通知对端不再传输该message的chunks,接收端在收到该消息后,会丢弃已接收到的不能组成完整message的chunks。该控制消息的payload中只有一个CSID,该CSID表示的当前消息的chunks都被丢弃。Abort Message的payload如下:
网络流媒体协议之——RTMP协议(Part II)
32 bits的CSID:该CSID的当前message不再传输后续的chunks,已接收到的chunks将被丢弃。

2.3 Acknowledgement (message type ID = 3)

当收到对端的消息大小等于窗口大小(window size)时,接收端必须返回一个ACK给发送端。窗口大小就是指收到接收端反馈的ACK前最多可以发送的字节数量。ACK中携带一个4字节的sequence number,表明目前已经接收到的字节总数。
网络流媒体协议之——RTMP协议(Part II)

2.4 Window Acknowledgement Size (message type ID = 5)

客户端和服务器端发送该消息通知对端在发送acknowledgements之间使用的window size。发送端在发送等于window size大小的数据后,会期待对端有一个确认消息(上一节的acknowledgement)返回;而接收端自从发送完上一个acknowledgement(或从会话的开始)后,若接收到指定大小的数据,则必须向发送端反馈一个acknowledgement消息。

网络流媒体协议之——RTMP协议(Part II)

2.5 Set Peer Bandwidth (message type ID = 6)

客户端或服务器通过发送该消息来限制对端的输出带宽。接收端在收到该消息后,会限制已发送但未收到ACK的数据大小至该消息指定的window size大小。接收端在收到该消息后,如果该消息指定的window size与上一次反馈给发送端的window size大小不一致,应该再次反馈一个Window Acknowledgement Size消息给发送端。
网络流媒体协议之——RTMP协议(Part II)
该消息的Payload包含5个字节,其中4字节的Acknowledgement Window Size和1字节的Limit Type,Limit Type有如下取值:
0 – Hard:对端应该限制其输出带宽至该消息指定带宽;
1 – Soft:对端应将带宽限制在该消息指定的值以内,或者按照已生效的带宽限制,以两者中较小的值为准;
2 – Dynamic:若上一个Limit Type为Hard,将当前message的Limit Type也标为Hard,否则忽略该消息。    

3. RTMP Command Messages

上一篇我们提到RTMP中的message类型,包括:audio message、video message、data message、shared object message、command message。Command message是客户端和服务器用来交换AMF编码的命令的消息。发送端发送的消息中包含:命令名称(command name)、事务ID(transaction ID)、以及包含相关参数的命令对象(command object)。接收端处理接收到的command message后,会回馈给发送端一个包含相同transaction ID的回复消息。回复的消息可能是:_result、_error或method name,其中_result表示接受该命令,对端可以继续往下执行相关流程;_error表示拒绝该命令;method name表示要在对端执行的函数或方法名称,比如verifyClient或contactExternalServer。
Command消息主要分为两类:NetConnection、NetStream。NetConnection为服务器和客户端的高层表示,用于管理两端之间的连接状态;NetStream是信息流的传输通道,也会传输一些诸如play、pause等控制信息流的命令。

3.1 NetConnection Commands

NetConnection管理服务器和客户端的双向连接,此外,它还提供异步远程方法调用(RPC)。NetConnection上可传输下列命令:
  • connect
  • call
  • close
  • createStream

3.1.1  connect

客户端向服务器端发送connect请求来建立连接。请求和回复的消息结构如下面两图:
网络流媒体协议之——RTMP协议(Part II)
网络流媒体协议之——RTMP协议(Part II)

其中,command information中的name-value键值对有很多,不一一列举,感兴趣的朋友可以去翻看原始协议查询。Connect命令的消息流如下:

网络流媒体协议之——RTMP协议(Part II)

3.1.2  call

Call方法用于接收端的远程过程调用(RPC),被调用的RPC名称作为参数在Call命令中传输。Call请求和反馈的消息结构如下:
网络流媒体协议之——RTMP协议(Part II)
网络流媒体协议之——RTMP协议(Part II)

3.1.3  createStream

客户端向服务器端发送该消息以创建message通信的逻辑通道。音频、视频和元数据的发布都是通过该命令创建的流通道来传输的。该命令的请求和回复消息结构如下:
网络流媒体协议之——RTMP协议(Part II)
网络流媒体协议之——RTMP协议(Part II)

3.2 NetStream Commands

NetStream定义了NetConnection连接的客户端和服务器之间用于传输音频、视频和数据的通道。一个netConnection可支持不同数据流的多个netStreams。netStream上可传输的从client到server方向的命令有:play,play2,deleteStream,closeStream,receiveAudio,receiveVideo,publish,seek,pause;在server到client方向,有”onStatus”命令,用于更新netStream的状态。
onStatus命令消息结构如下:
网络流媒体协议之——RTMP协议(Part II)
实例:
网络流媒体协议之——RTMP协议(Part II)

3.2.1 play

客户端向服务器发送该命令来实现一个流的播放。也可以通过多次执行该命令来形成一个播放列表。命令结构如下:
网络流媒体协议之——RTMP协议(Part II)
客户端与服务器之间的play命令交互流程如下:
网络流媒体协议之——RTMP协议(Part II)

3.2.2 play2

与play命令不同,play2可以将正在播放的流切换到相同内容的不同比特率的流上。服务器端维护了不同比特率的文件供客户端发送play2请求切换。命令结构如下:
网络流媒体协议之——RTMP协议(Part II)
客户端和服务器之间play2命令的交互流程如下:
网络流媒体协议之——RTMP协议(Part II)

3.2.3 deleteStream

客户端发送该命令告知服务器本地的某个流被销毁,不需要再传输此路流;服务器不需要回复该命令。该命令的结构如下:
网络流媒体协议之——RTMP协议(Part II)

3.2.4 receiveAudio

客户端发送该消息通知服务器是否接收Audio数据。
网络流媒体协议之——RTMP协议(Part II)
如果Bool Flag设为false,表示客户端不接收audio数据,服务器端无需回复该消息;如果Bool Flag为true,表示客户端要接收audio数据,则服务器端会回复NetStream.Seek.Notify和NetStream.Play.Start的状态消息。

3.2.5 receiveVideo

与receiveAudio类似,该消息用于通知服务器端是否接收视频数据,除了Command Name字段为“receiveVideo”,其他字段都与receiveAudio相同,不再赘述。

 3.2.6 publish

客户端通过该命令向服务器发布某个名称的流(推流),发布成功后,其他客户端都可通过该名称来访问服务器上已发布的音频、视频或数据流。服务器会向客户端回复一个表示发布开始的onStatus命令。
网络流媒体协议之——RTMP协议(Part II)

3.2.7 seek

定位到视频或音频的某个位置,以毫秒为单位。若seek成功,服务器回复一个NetStream.Seek.Notify状态消息;若seek失败,回复_error消息。
网络流媒体协议之——RTMP协议(Part II)

3.2.8 pause

暂停命令。若暂停,服务器回复NetStream.Pause.Notify状态;若取消暂停,回复NetStream.Unpause.Notify;若失败,返回_error消息。
网络流媒体协议之——RTMP协议(Part II)
内容太多,总算是整理完了,希望能帮到需要的小伙伴~