上篇我们对消息的格式和大部分的消息类型进行了梳理,本编主要对命令消息其中的定义进行梳理。
命令消息(Command Message
) 用于在客户端和服务器端传输AMF
编码的数据交换命令,客户端或者服务端可以通过命令消息和对端通信的流完成请求远程方法调用(RPC
)。当消息使用 AMF0
编码时,消息类型为20
,使用AMF3
编码时为17
。
命令消息使用场景基本都是——客户端请求,服务端响应
按来源分类
命令消息在客户端和服务端中来回传递,为了方便区分,我根据请求和响应根据场景将两端为区分请求者和响应者者。因此,请求者发出的就是请求命令信息,响应者发出的就是响应命令信息。
请求命令信息
请求者通过发送请求命令消息到对端,命令对端根据命令名执行远程方法调用。例如发送connect
(连接)、createStream
(创建流)、pulish
(发布)、play
(播放)和pause
(暂停)等命令。由于其消息数据进行了 AMF 编码,因此下面表格通过字段展示的是请求命令的结构:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名称,设置为指定的命令,取值为 connect 、 createStream 、 pulish 、play 和pause 等等 |
Transaction ID | Number | 事务ID,该命令需要响应则有指定ID,若不需要响应填 0 即可 |
Command Object | Object / Null | 命令对象,如果一些命令消息需要就用,否则置空即可 |
Others | Unknow | 额外的参数值或对象,根据特定的命令来配置。若不需要,则省略整个字段即可。 |
响应命令信息
响应者接收到请求命令消息后,会对其消息进行解析,并做相应的处理。根据不同命令的要求,响应者可能需要对请求者的请求进行响应。因此响应者将发送相应命令信息来完成响应操作。响应消息和请求消息类型,都是使用 AMF 编码,因此通过字段来表示其命令的结构:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名称,取值为_result 、_error 或onStatus |
Transaction ID | Number | 事务ID,响应的目标请求的事务 ID |
Command Object | Object / Null | 命令对象,如果一些命令消息需要就用,否则置空即可 |
Others | Unknow | 额外的参数值或对象,根据特定的命令来配置。如果这个是结果命令,则该字段是指定的结果;如果这个是错误命令,则该字段就是错误信息。 |
由此可见,响应命令其实就是一个结果命令、错误命令或状态命令。
小结:命令消息通过
Command Name
进行区分,响应命令通过Transaction ID
与请求命令进行关联。
发送命令消息的类对象
NetConnection
和NetStream
是命令中常用的类对象,其含义如下:
- NetConnection:网络连接,服务端和客户端之间进行网络连接的一种高级表示形式。
- NetStream:网络流,代表了发送音频流,视频流,或其他相关数据的频道。当然还有一些像播放,暂停之类的命令,用来控制数据流。
NetConnection 命令
NetConnection
(网络连接)管理着客户端和服务端之间的双向连接,另外,它也支持远程方法的异步调用。NetConnection
允许使用的命令如下:
-
connect
(连接) -
call
(调用) -
createStrem
(创建流) -
close
(关闭)
对于
NetConnection Command
,其响应请求命令为结果命令(_result
)和错误命令(_error
)。
connect 命令
客户端发送connect
命令给服务器,来获取一个服务端应用实例的连接(connection
)。
请求命令结构
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名称,设置为connect |
Transaction ID | Number | 总是设置为 1 |
Command Object | Object | 具有键值对(name-value pairs )的命令信息对象,其结构见表格下方的ConnectInfo |
Optional User Arguments | Object | 任意可选信息 |
ConnectInfo
connect
命令的命令对象(Command Object
)中的键值对说明:
属性(Property ) |
类型(Type ) |
描述(Description ) |
范例(Example Value ) |
---|---|---|---|
app | String | 客户端连接到服务端应用的名字 | live |
flashver | String | Flash Player 版本号,和 ApplicationScript getversion ()方法返回的是用一个字符串 | FMSc/1.0 |
swfUrl | String | 进行当前连接的 SWF 文件源地址 | file://C:/FlvPlayer.swf |
tcUrl | String | 服务器 URL,具有以下格式:protocol://servername:port/ appName/appInstance | rtmp://localhost:1935/ testapp/instance1 |
fpad | Boolean | 如果使用了代理就为true |
true or 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
audioCodecs
(音频编码属性)的可选值:原始 PCM,ADPCM,MP3,NellyMoser(5,8,11,16,22,44kHz),AAC,Speex
Codec Flag | Usage | Value |
---|---|---|
SUPPORT_SND_NONE | Raw sound, no compression | 0x0001 |
SUPPORT_SND_ADPCM | ADPCM compression | 0x0002 |
SUPPORT_SND_MP3 | mp3 compression | 0x0004 |
SUPPORT_SND_INTEL | Not used | 0x0008 |
SUPPORT_SND_UNUSED | Not used | 0x0010 |
SUPPORT_SND_NELLY8 | NellyMoser at 8-kHz compression | 0x0020 |
SUPPORT_SND_NELLY | NellyMoser compression(5, 11, 22, and 44 kHz) | 0x0040 |
SUPPORT_SND_G711A | G711A sound compression(Flash Media Server only) | 0x0080 |
SUPPORT_SND_G711U | G711U sound compression(Flash Media Server only) | 0x0100 |
SUPPORT_SND_NELLY16 | NellyMouser at 16-kHz compression | 0x0200 |
SUPPORT_SND_AAC | Advanced audio coding (AAC) codec | 0x0400 |
SUPPORT_SND_SPEEX | Speex Audio | 0x0800 |
SUPPORT_SND_ALL | All RTMP-supported audio codecs | 0x0FFF |
videoCodecs
videoCodecs
(视频编码属性)的可选值:Sorenson,V1,On2,V2,H264
Codec Flag | Usage | Value |
---|---|---|
SUPPORT_VID_UNUSED | Obsolete value | 0x0001 |
SUPPORT_VID_JPEG | Obsolete value | 0x0002 |
SUPPORT_VID_SORENSON | Sorenson Flash video | 0x0004 |
SUPPORT_VID_HOMEBREW | V1 screen sharing | 0x0008 |
SUPPORT_VID_VP6 (On2) | On2 video (Flash 8+) | 0x0010 |
SUPPORT_VID_VP6ALPHA(On2 with alpha channel) | On2 video with alpha channel | 0x0020 |
SUPPORT_VID_HOMEBREWV(screensharing v2) | Screen sharing version 2 (Flash 8+) | 0x0040 |
SUPPORT_VID_H264 | H264 video | 0x0080 |
SUPPORT_VID_ALL | All RTMP-supported video codecs | 0x00FF |
videoFunction
videoFunction
(视频函数属性)的可选值:
Function Flag | Usage | Value |
---|---|---|
SUPPORT_VID_CLIENT_SEEK | Indicates that the client can perform frame-accurate seeks. | 1 |
objectEncoding
objectEncoding
(编码属性)的可选值:
Encoding Type | Usage | Value |
---|---|---|
AMF0 | AMF0 object encoding supported by Flash 6 and later | 0 |
AMF3 | AMF3 encoding from Flash 9 (AS3) | 3 |
响应命令结构
即服务器到客户端的命令结构:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 表示响应的是结果(result )还是错误(error ),取值为_result 或_error |
Transaction ID | Number | 对于connect 响应,取值为 1 |
Properties | Object | 描述连接属性的键值对,其结构见表格下方的ConnectResp |
Information | Object | 描述来自服务端的响应的键值对,即连接事件。包code ,level ,description ,ObjectEncoding 信息 |
ConnectResp
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
fmsVer | String | Flash Media Server 版本号 |
capabilities | Number | 功能数量? |
(※)命令执行消息流
connect
命令执行过程中的消息流如下:
+--------------+ +-------------+
| Client | | | Server |
+------+-------+ | +------+------+
| Handshaking done |
| | |
| | |
| | |
| | |
|-----------1.Command Message(connect)------->|
| |
|<-------2.Window Acknowledgement Size--------|
| |
|<-----------3.Set Peer Bandwidth-------------|
| |
|-------- Window Acknowledgement Size ------->|
| |
|<------ User Control Message(StreamBegin) ---|
| |
|<------------ Command Message ---------------|
| (_result- connect response) |
| |
Message flow in the connect command
- 客户端发送
connect
命令到服务端以请求对服务端应用实例的连接 - 收到
connect
命令后,服务端发送协议消息“窗口确认大小”到客户端。同时,服务端也会连接到connect
命令中提到的应用 - 服务端发送协议消息“设置对端宽带”到客户端
- 客户端在处理完协议消息“设置对端宽带”之后,发送协议消息“窗口确认大小”到服务端。
- 服务端发送用户控制消息(
StreamBegin
)类型的协议消息到客户端 - 服器端发送结果命令消息告知客户端连接状态 (success/fail),并携带指定信息。
call 方法
NetConnection
对象的call
方法执行接收端远程方法的调用(RPC),被调用的 RPC 名字作为一个参数传给调用命令。
请求命令结构
发送端发给接收端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Procedure Name | String | 被调用远程程序的名字 |
Transaction ID | Number | 如果需要远程程序给予回复我们需要传递一个transaction Id ,否则传0 即可 |
Command Object | Object | 如果一些命令消息需要就用,否则置空即可 |
Optional Arguments | Object | 任意要提供的可选参数 |
响应命令结构
接收端回复的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令的名字 |
Transaction ID | Number | 响应所属的命令的ID |
Command Object | Object | 如果一些命令消息需要就用,否则置空即可 |
Response | Object | 调用方法的回复 |
createStream 命令
客户端发送这一命令到服务端为消息连接创建一条逻辑通道——消息流。音频、视频和元数据使用createStream
命令创建的流通道传输。
NetConnection
是默认的通信通道,信息流ID为0。协议消息和一些命令消息,包括createStream
,使用默认的通信通道。
请求命令结构
客户端发送给服务器端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名,这里取值为createStream |
Transaction ID | Number | 命令的事务 ID |
Command Object | Object | 如果一些命令消息需要就用,否则置空即可 |
响应命令结构
服务端回复客户端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 表示响应的是结果(result )还是错误(error ),取值为_result 或_error |
Transaction ID | Number | 响应所属的命令的 ID |
Command Object | Object | 如果一些命令消息需要就用,否则置空即可 |
Stream ID | Number | 返回值要么是一个流 ID,要么是一个错误信息对象 |
该处的流ID(
Stream ID
)表示的是NetConnection
的流ID,与块流和消息流没有直接关系
NetStream 命令
NetStream
(网络流)命令定义了传输通道,通过这个通道,音频流、视频流以及数据消息流可以通过连接客户端到服务端的NetConnection
传输。以下命令可以由客户端使用 NetStream 往服务端发送:
-
play
(播放) -
play2
(播放2) -
deleteStream
(删除流) -
closeStream
(关闭流) -
receiveAudio
(接收音频) -
receiveVideo
(接收视频) -
publish
(发布) -
seek
(定位) -
pause
(暂停)
对于
NetStream Command
,其响应请求命令为状态命令(onStatus
)
状态命令(响应)
对于NetStream
命令,服务端使用onStatus
命令向客户端发送NetStream
状态:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名,取值为onStatus |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | onStatus 消息没有命令对象 |
Info Object | Object | 一个 AMF 对象至少要有“level”、“code”和“description”三个属性 |
AMF 对象属性字段要求:
-
level
(String):消息等级,取值为“warning”、“status”、“error”; -
code
(String):消息码,例如"NetStream.Play.Start";- 构成:类名.方法名.状态
-
description
(String):关于这个消息的可读描述。
play 命令
客户端发送这一命令到服务端用来播放流,也可以多次使用这一命令创建一个播放列表。
如果你想要创建一个可以在不同的直播流或者录制流之间进行切换播放的动态的播放列表,那么你就需要多次调用
play
方法,并在每次调用时传递重置字段为false
。相反的,如果你想要立即播放指定流,则需要将其他等待播放的流清空,并用true
进行重置。
请求命令结构
客户端发送到服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名,取值为“play” |
Transaction ID | Number | 事务 ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Stream Name | String | 播放流的名字,其命名规则见表格下方 |
Start | Number | 表示开始的时间,以秒为单位,是一个可选参数。默认值为 -2,其值含义见表格下方 |
Duration | Number | 表示回放的持续时间,以秒为单位,是一个可选参数,默认值为 -1,其值含义见表格下方 |
Reset | Boolean | 表示重置操作,即是否对之前的播放列表进行flush 操作,是一个可选参数。 |
Stream Name 规范
根据不同的文件播放需求,会有不同的 Stream 命名规范,如下:
- 对于 FLV 文件(
sample.flv
):不需要文件扩展名,例如:sample
- 对于 MP3 或 ID3 文件(
sample.mp3
):需要在名字前添加mp3:
,例如:mp3:sample
- 对于 H.264/ACC 文件(
sample.m4v
):需要在名字前添加mp4:
,并且在名字后面指定文件扩展名,例如:mp4:sample.m4v
Start 含义
Start 表示流名(Stream Name
)的播放方式,主要用于区分播放的是直播流还是录制流。
-
start = -2
:表示用户首次尝试播放流名字段中定义的直播流- 如果没有此名的直播流,则会播放流名相同的录制流;
- 如果没有此名的录制流,则会等待此名新的直播流。
-
start = 0
:表示播放此流名指定的录制流- 如果没有此名的录制流,则会播放播放列表的下一项
-
start = -1
:表示播放此流名指定的直播流
Duration 含义
默认值为 -1,表示直播流会播放至不可用,录制流会播放到结束;如果
Duration
值为 0,那么只会播放从录制流开始时间的一帧;如果Duration
值为大于 0 的正数,那么NetStream将会变为可播放状态,或者播放指定的时间段内的录制流。(如果流在赋值的时间段内结束,那么回放也会随之结束);如果Duration
为 -1 以外的负数,将会被当成 -1 处理。
Duration 表示回放的持续时间,其值的含义如下:
-
Duration = -1
:表示直播流播到没有了,或录制流播放结束; -
Duration = 0
:表示只会播放从录制流开始时间的一帧; -
Duration > 0
:表示在指定的时间内播放直播流,或在指定的时间内播放录制流。- 如果该流在指定时间内结束,那么播放也会随之结束
-
Duration < 0 && Duration != -1
:都会当作-1
的情况处理
play 命令执行消息流
+-------------+ +----------+
| Play Client | | | Server |
+------+------+ | +-----+----+
| Handshaking and Application |
| connect done |
| | |
| | |
| | |
| | |
---+---- |-----1.Command Message(createStream) ---->|
Create| | |
Stream| | |
---+---- |<---------- Command Message --------------|
| (_result- createStream response) |
| |
---+---- |------2.Command Message (play)----------->|
| | |
| |<------------3.SetChunkSize --------------|
| | |
| |<----4.User Control (StreamIsRecorded)----|
Play | | |
| |<----5.User Control (StreamBegin)---------|
| | |
| |<--6.Command Message(onStatus-play reset)-|
| | |
| |<--6.Command Message(onStatus-play start)-|
| | |
| |<-------------Audio Message---------------|
| | |
| |<-------------Video Message---------------|
| | | |
|
Keep receiving audio and video stream till finishes
Message flow in the play command
- 当客户端与服务端握手完成,并进行了连接建立后,客户端便发送
createStream
到客户端,请求创建一条新的块流。 - 当客户端从服务端接收到
createStream
命令的结果是success
后,则发送play
命令,请求后端开始播放。 - 一旦接收到
play
命令,服务端会先发送一个协议消息来设置块大小。 - 服务端随后发送用户控制消息,这个消息中定义了
StreamIsRecorded
事件和流ID。消息在前两个字节中保存事件类型,在后四个字节中保存流 ID。 - 服务端发送另一个用户控制消息,这一消息包含
StreamBegin
事件,用于发送给客户端的流的起点。 - 如果客户端
play
命令执行成功,服务端则发送两个onStatus
命令消息,分别是NetStream.Play.Start
和NetStream.Play.Reset
。- 当客户端发送的
play
命令设置了reset
时服务端才会发送NetStream.Play.Reset
状态。 - 如果要播放的流没有找到,服务端发送
onStatus
消息为NetStream.Play.StreamNotFound
状态
- 当客户端发送的
之后,服务端开始发送视频和音频数据,客户端对其进行播放。
play2 命令(码表应用)
不同于play
命令,play2
命令可以在不改变播放的时间轴的情况下切换不同的比特率(即码率)。服务端维护了多个不同码率的文件,客户端可以通过play2
命令来使用。
请求命令结构
客户端发给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名,取值为play2 |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Command Object | Object | 一个 AMF 编码的对象,该对象的属性是为公开的flash.net.NetStreamPlayOptions ActionScript 对象所描述的属性。 |
NetStreamPlayOptions
对象的公开属性在ActionScript 3
语言指南[AS3]中有所描述
play2 命令执行消息流
+--------------+ +-------------+
| Play2 Client | | | Server |
+--------+-----+ | +------+------+
| Handshaking and Application |
| connect done |
| | |
| | |
| | |
| | |
---+---- |---- Command Message(createStream) --->|
Create | | |
Stream | | |
---+---- |<---- Command Message (_result) -------|
| |
---+---- |------ Command Message (play) -------->|
| | |
| |<------------ SetChunkSize ------------|
| | |
| |<--- UserControl (StreamIsRecorded)----|
Play | | |
| |<------- UserControl (StreamBegin)-----|
| | |
| |<--Command Message(onStatus-playstart)-|
| | |
| |<---------- Audio Message -------------|
| | |
| |<---------- Video Message -------------|
| | |
| |
---+---- |-------- Command Message(play2) ------>|
| | |
| |<------- Audio Message (new rate) -----|
Play2 | | |
| |<------- Video Message (new rate) -----|
| | | |
| | | |
| Keep receiving audio and video stream till finishes
|
Message flow in the play2 command
deleteStream 命令
当 NetStream 对象销毁时,NetStream 发送 deleteStream 命令。
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令字,取值为“deleteStream” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Stream ID | Number | 服务端需要销毁的流 ID |
服务端不会发送任何回复
receiveAudio 命令
NetStream 通过发送 receiveAudio 消息来通知服务端是否发送音频到客户端
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令字,取值为“receiveAudio” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Bool Flag | Boolean | 表明客户端是否接受音频数据,取值 true 或 false |
- 如果发送来的
receiveAudio
命令Bool Flag
为false
时,服务端不发送任何回复。 - 如果发送来的
receiveAudio
命令Bool Flag
为true
时,服务端会以状态消息NetStream.Seek.Notify
和NetStream.Play.Start
进行回复
NetStream.Seek.Notify:进度通知
NetStream.Play.Start:播放状态(是否开始)
receiveVideo 命令
NetStream 通过发送 receiveVideo 消息来通知服务端是否发送视频到客户端
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令字,取值为“receiveVideo” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Bool Flag | Boolean | 表明客户端是否接受视频数据,取值 true 或 false |
- 如果发送来的
receiveVideo
命令Bool Flag
为false
时,服务端不发送任何回复。 - 如果发送来的
receiveVideo
命令Bool Flag
为true
时,服务端会以状态消息NetStream.Seek.Notify
和NetStream.Play.Start
进行回复
publish 命令
客户端通过发送给服务端这一命令来发布一个已命名的流。使用这个名字,任意客户端都可以播放这个流,并接受发布的音频、视频和数据消息。
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令名,取值为“publish” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Publishing Name | String | 发布的流的名字 |
Publishing Type | String | 表示发布类型,取值为“live”、“record”或者“append” |
发布类型:
- live:直播数据只被发布,并不对其进行录制
- record:流被发布后,数据被录制到一个新的文件,新文件被存储在服务器上包含服务应用目录的子路径。如果文件已存在,则覆盖。
- append:流被发布后,则添加数据到指定文件。如果文件不存在,则新建一个。
服务端回复onStatus
命令以标注发布的起始位置
seek 命令
客户端通过发送seek
命令查找一个多媒体文件或一个播放列表的偏移量,以毫秒为单位。
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令字,取值为“seek” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
milliSeconds | Number | 查找的毫秒数 |
seek
命令执行成功时服务端会发送一个状态消息NetStream.Seek.Notify
,失败的话,服务端返回一个_error
消息。
pause 命令
客户端通过发送pause
命令告知服务端当前流是暂停还是重新播放。
客户端发送给服务端的命令结构如下:
字段名(Field Name ) |
类型(Type ) |
描述(Description ) |
---|---|---|
Command Name | String | 命令字,取值为“命令字,取值为“pause” |
Transaction ID | Number | 事务ID,取值为 0 |
Command Object | Null | 该命令不存在命令信息,取值为“null” |
Pause/Unpause Flag | Boolean | 表示暂停或重新播放,取值为"true"或"false" |
milliSeconds | Number | 表示流暂停或者重新开始流所处的毫秒数。该值是客户端暂停的当前流时间,服务端会在重新播放的时候传"timestamps"更大的消息出来 |
- 当流暂停时,服器端发一个
NetStream.Pause.Notify
状态消息 - 当流重新播放时,服器端发一个NetStream.Unpause.Notify` 状态消息
- 失败的话,服器端返回一个
_error
消息