本文是爲截至發稿時止最新 Adobe 官方公佈的 RTMP 規範。本文包含 RTMP 規範的所有內容。是第一個比較全面的 RTMP 規範的中譯本。因爲成文時間倉促,加上做者知識面所限,翻譯錯誤之處在所不免,懇請各位朋友熱心指出,能夠直接在博客後面留言,先行謝過。html
rtmp_specification_1.0.pdf 官方下載地址: http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf.算法
請隨時關注官方文檔更新: http://www.adobe.com/cn/devnet/rtmp.html。緩存
如下內容來自 rtmp_specification_1.0.pdf。服務器
Adobe 公司的實時消息傳輸協議 (RTMP) 經過一個可靠地流傳輸提供了一個雙向多通道消息服務,好比 TCP [RFC0793],意圖在通訊端之間傳遞帶有時間信息的視頻、音頻和數據消息流。實現一般對不一樣類型的消息分配不一樣的優先級,當運載能力有限時,這會影響等待流傳輸的消息的次序。本文檔將對實時流傳輸協議 (Real Time Messaging Protocol) 的語法和操做進行描述。網絡
本文檔中出現的關鍵字,"MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 、"OPTIONAL",都將在 [RFC2119] 中進行解釋。併發
Rajesh Mallipeddi,Adobe Systems 原成員,起草了本文檔原始規範,並提供大部分的原始內容。app
Mohit Srivastava,Adobe Systems 成員,促成了本規範的開發。dom
Payload (有效載荷):包含於一個數據包中的數據,例如音頻採樣或者壓縮的視頻數據。payload 的格式和解釋,超出了本文檔的範圍。異步
Packet (數據包):一個數據包由一個固定頭和有效載荷數據構成。一些個底層協議可能會要求對數據包定義封裝。分佈式
Port (端口):"傳輸協議用以區分開指定一臺主機的不一樣目的地的一個抽象。TCP/IP 使用小的正整數對端口進行標識。" OSI 傳輸層使用的運輸選擇器 (TSEL) 至關於端口。
Transport address (傳輸地址):用以識別傳輸層端點的網絡地址和端口的組合,例如一個 IP 地址和一個 TCP 端口。數據包由一個源傳輸地址傳送到一個目的傳輸地址。
Message stream (消息流):通訊中消息流通的一個邏輯通道。
Message stream ID (消息流 ID):每一個消息有一個關聯的 ID,使用 ID 能夠識別出流通中的消息流。
Chunk (塊):消息的一段。消息在網絡發送以前被拆分紅不少小的部分。塊能夠確保端到端交付全部消息有序 timestamp,即便有不少不一樣的流。
Chunk stream (塊流):通訊中容許塊流向一個特定方向的邏輯通道。塊流能夠從客戶端流向服務器,也能夠從服務器流向客戶端。
Chunk stream ID (塊流 ID):每一個塊有一個關聯的 ID,使用 ID 能夠識別出流通中的塊流。
Multiplexing (合成):將獨立的音頻/視頻數據合成爲一個連續的音頻/視頻流的加工,這樣能夠同時發送幾個視頻和音頻。
DeMultiplexing (分解):Multiplexing 的逆向處理,將交叉的音頻和視頻數據還原成原始音頻和視頻數據的格式。
Remote Procedure Call (RPC 遠程方法調用):容許客戶端或服務器調用對端的一個子程序或者程序的請求。
Metadata (元數據):關於數據的一個描述。一個電影的 metadata 包括電影標題、持續時間、建立時間等等。
Application Instance (應用實例):服務器上應用的實例,客戶端能夠鏈接這個實例併發送鏈接請求。
Action Message Format (AMF 動做消息格式協議):一個用於序列化 ActionScript 對象圖的緊湊的二進制格式。AMF 有兩個版本:AMF 0 [AMF0] 和 AMF 3 [AMF3]。
全部整數型屬性以網絡字節順序傳輸,字節 0 表明第一個字節,零位是一個單詞或字段最經常使用的有效位。字節序一般是大端排序。關於傳輸順序的更多細節描述參考 IP 協議[RFC0791]。除非另外註明,本文檔中的數值常量都是十進制的 (以 10 爲基礎)。
除非另有規定,RTMP 中的全部數據都是字節對準的;例如,一個十六位的屬性可能會在一個奇字節偏移上。填充後,填充字節應該有零值。
RTMP 中的 Timestamps 以一個整數形式給出,表示一個未指明的時間點。典型地,每一個流會以一個爲 0 的 timestamp 起始,但這不是必須的,只要雙端可以就時間點達成一致。注意這意味着任意不一樣流 (尤爲是來自不一樣主機的) 的同步須要 RTMP 以外的機制。
由於 timestamp 的長度爲 32 位,每隔 49 天 17 小時 2 分鐘和 47.296 秒就要重來一次。由於容許流連續傳輸,有可能要多年,RTMP 應用在處理 timestamp 時應該使用序列碼算法 [RFC1982],而且可以處理無限循環。例如,一個應用假定全部相鄰的 timestamp 都在 2^31 - 1 毫秒以內,所以 10000 在 4000000000 以後,而 3000000000 在 4000000000 以前。
timestamp 也可使用無符整數定義,相對於前面的 timestamp。timestamp 的長度可能會是 24 位或者 32 位。
本節介紹實時消息傳輸協議的塊流 (RTMP 塊流)。 它爲上層多媒體流協議提供合併和打包的服務。
當設計 RTMP 塊流使用實時消息傳輸協議時,它能夠處理任何發送消息流的協議。每一個消息包含 timestamp 和 payload 類型標識。RTMP 塊流和 RTMP 一塊兒適合各類音頻-視頻應用,從一對一和一對多直播到點播服務,到互動會議應用。
當使用可靠傳輸協議時,好比 TCP [RFC0793],RTMP 塊流可以對於多流提供全部消息可靠的 timestamp 有序端對端傳輸。RTMP 塊流並不提供任何優先權或相似形式的控制,可是能夠被上層協議用來提供這種優先級。例如,一個直播視頻服務器可能會基於發送時間或者每一個消息的確認時間丟棄一個傳輸緩慢的客戶端的視頻消息以確保及時獲取其音頻消息。
RTMP 塊流包括其自身的帶內協議控制信息,而且提供機制爲上層協議植入用戶控制消息。
能夠被分割爲塊以支持組合的消息的格式取決於上層協議。消息格式必須包含如下建立塊所需的字段。
Timestamp:消息的 timestamp。這個字段能夠傳輸四個字節。
Length:消息的有效負載長度。若是不能省略掉消息頭,那它也被包括進這個長度。這個字段佔用了塊頭的三個字節。
Type Id:一些類型 ID 保留給協議控制消息使用。這些傳播信息的消息由 RTMP 塊流協議和上層協議共同處理。其餘的全部類型 ID 可用於上層協議,它們被 RTMP 塊流處理爲不透明值。事實上,RTMP 塊流中沒有任何地方要把這些值當作類型使用;全部消息必須是同一類型,或者應用使用這一字段來區分同步跟蹤,而不是類型。這一字段佔用了塊頭的一個字節。
Message Stream ID:message stream (消息流) ID 可使任意值。合併到同一個塊流的不一樣的消息流是根據各自的消息流 ID 進行分解。除此以外,對 RTMP 塊流而言,這是一個不透明的值。這個字段以小端格式佔用了塊頭的四個字節。
一個 RTMP 鏈接以握手開始。RTMP 的握手不一樣於其餘協議;RTMP 握手由三個固定長度的塊組成,而不是像其餘協議同樣的帶有報頭的可變長度的塊。
客戶端 (發起鏈接請求的終端) 和服務器端各自發送相同的三塊。便於演示,當發送自客戶端時這些塊被指定爲 C0、C1 和 C2;當發送自服務器端時這些塊分別被指定爲 S0、S1 和 S2。
握手以客戶端發送 C0 和 C1 塊開始。
客戶端必須等待接收到 S1 才能發送 C2。
客戶端必須等待接收到 S2 才能發送任何其餘數據。
服務器端必須等待接收到 C0 才能發送 S0 和 S1,也能夠等待接收到 C1 再發送 S0 和 S1。服務器端必須等待接收到 C1 才能發送 S2。服務器端必須等待接收到 C2 才能發送任何其餘數據。
C0 和 S0 包都是一個單一的八位字節,以一個單獨的八位整型域進行處理:
如下是 C0/S0 包中的字段:
版本號 (八位):在 C0 中,這一字段指示出客戶端要求的 RTMP 版本號。在 S0 中,這一字段指示出服務器端選擇的 RTMP 版本號。本文檔中規範的版本號爲 3。0、一、2 三個值是由早期其餘產品使用的,是廢棄值;4 - 31 被保留爲 RTMP 協議的將來實現版本使用;32 - 255 不容許使用 (以區分開 RTMP 和其餘常以一個可打印字符開始的文本協議)。沒法識別客戶端所請求版本號的服務器應該以版本 3 響應,(收到響應的) 客戶端能夠選擇下降到版本 3,或者放棄握手。
C1 和 S1 數據包的長度都是 1536 字節,包含如下字段:
Time (四個字節):這個字段包含一個 timestamp,用於本終端發送的全部後續塊的時間起點。這個值能夠是 0,或者一些任意值。要同步多個塊流,終端能夠發送其餘塊流當前的 timestamp 的值。
Zero (四個字節):這個字段必須都是 0。
Random data (1528 個字節):這個字段能夠包含任意值。終端須要區分出響應來自它發起的握手仍是對端發起的握手,這個數據應該發送一些足夠隨機的數。這個不須要對隨機數進行加密保護,也不須要動態值。
C2 和 S2 數據包長度都是 1536 字節,基本就是 S1 和 C1 的副本 (分別),包含有如下字段:
Time (四個字節):這個字段必須包含終端在 S1 (給 C2) 或者 C1 (給 S2) 發的 timestamp。
Time2 (四個字節):這個字段必須包含終端先前發出數據包 (s1 或者 c1) timestamp。
Random echo (1528 個字節):這個字段必須包含終端發的 S1 (給 C2) 或者 S2 (給 C1) 的隨機數。兩端均可以一塊兒使用 time 和 time2 字段再加當前 timestamp 以快速估算帶寬和/或者鏈接延遲,但這不太多是有多大用處。
下面描述了握手示意圖中提到的狀態:
Uninitialized (未初始化):協議的版本號在這個階段被髮送。客戶端和服務器都是 uninitialized (未初始化) 狀態。以後客戶端在數據包 C0 中將協議版本號發出。若是服務器支持這個版本,它將在迴應中發送 S0 和 S1。若是不支持呢,服務器會纔去適當的行爲進行響應。在 RTMP 協議中,這個行爲就是終止鏈接。
Version Sent (版本已發送):在未初始化狀態以後,客戶端和服務器都進入 Version Sent (版本已發送) 狀態。客戶端會等待接收數據包 S1 而服務器在等待 C1。一旦拿到期待的包,客戶端會發送數據包 C2 而服務器發送數據包 S2。(客戶端和服務器各自的)狀態隨即變爲 Ack Sent (確認已發送)。
Ack Sent (確認已發送):客戶端和服務器分別等待 S2 和 C2。
Handshake Done (握手結束):客戶端和服務器能夠開始交換消息了。
握手以後,鏈接開始對一個或多個塊流進行合併。建立的每一個塊都有一個惟一 ID 對其進行關聯,這個 ID 叫作 chunk stream ID (塊流 ID)。這些塊經過網絡進行傳輸。傳遞時,每一個塊必須被徹底發送才能夠發送下一塊。在接收端,這些塊被根據塊流 ID 被組裝成消息。
分塊容許上層協議將大的消息分解爲更小的消息,例如,防止體積大的但優先級小的消息 (好比視頻) 阻礙體積較小但優先級高的消息 (好比音頻或者控制命令)。
分塊也讓咱們可以使用較小開銷發送小消息,由於塊頭包含包含在消息內部的信息壓縮提示。
塊的大小是能夠配置的。它可使用一個設置塊大小的控制消息進行設置 (參考 5.4.1)。更大的塊大小能夠下降 CPU 開銷,但在低帶寬鏈接時由於它的大量的寫入也會延遲其餘內容的傳遞。更小的塊不利於高比特率的流化。因此塊的大小設置取決於具體狀況。
每一個塊包含一個頭和數據體。塊頭包含三個部分:
Basic Header (基本頭,1 到 3 個字節):這個字段對塊流 ID 和塊類型進行編碼。塊類型決定了消息頭的編碼格式。(這一字段的) 長度徹底取決於塊流 ID,由於塊流 ID 是一個可變長度的字段。
Message Header (消息頭,0,3,7,或者 11 個字節):這一字段對正在發送的消息 (無論是整個消息,仍是隻是一小部分) 的信息進行編碼。這一字段的長度可使用塊頭中定義的塊類型進行決定。
Extended Timestamp (擴展 timestamp,0 或 4 字節):這一字段是否出現取決於塊消息頭中的 timestamp 或者 timestamp delta 字段。更多信息參考 5.3.1.3 節。
Chunk Data (有效大小):當前塊的有效負載,至關於定義的最大塊大小。
塊基本頭對塊流 ID 和塊類型 (由下圖中的 fmt 字段表示) 進行編碼。塊基本頭字段可能會有 1,2 或者 3 個字節,取決於塊流 ID。
一個 (RTMP) 實現應該使用可以容納這個 ID 的最小的容量進行表示。
RTMP 協議最多支持 65597 個流,流 ID 範圍 3 - 65599。ID 0、一、2 被保留。0 值表示二字節形式,而且 ID 範圍 64 - 319 (第二個字節 + 64)。1 值表示三字節形式,而且 ID 範圍爲 64 - 65599 ((第三個字節) * 256 + 第二個字節 + 64)。3 - 63 範圍內的值表示整個流 ID。帶有 2 值的塊流 ID 被保留,用於下層協議控制消息和命令。
塊基本頭中的 0 - 5 位 (最低有效) 表明塊流 ID。
塊流 ID 2 - 63 能夠編進這一字段的一字節版本中。
塊流 ID 64 - 319 能夠以二字節的形式編碼在頭中。ID 計算爲 (第二個字節 + 64):
塊流 ID 64 - 65599 能夠編碼在這個字段的三字節版本中。ID 計算爲 ((第三個字節) * 256 + (第二個字節) + 64)。
cs id (六位):這一字段包含有塊流 ID,值的範圍是 2 - 63。值 0 和 1 用於指示這一字段是 2- 或者 3- 字節版本。
fmt (兩個字節):這一字段指示 'chunk message header' 使用的四種格式之一。沒中塊類型的 'chunk message header' 會在下一小節解釋。
cs id - 64 (8 或者 16 位):這一字段包含了塊流 ID 減掉 64 後的值。例如,ID 365 在 cs id 中會以一個 1 進行表示,和這裏的一個 16 位 的 301 (cs id - 64)。
塊流 ID 64 - 319 可使用 2-byte 或者 3-byte 的形式在頭中表示。
塊消息頭又四種不一樣的格式,由塊基本頭中的 "fmt" 字段進行選擇。
一個 (RTMP) 實現應該爲每一個塊消息頭使用最緊湊的表示。
類型 0 塊頭的長度是 11 個字節。這一類型必須用在塊流的起始位置,和流 timestamp 重來的時候 (好比,重置)。
timestamp (三個字節):對於 type-0 塊,當前消息的絕對 timestamp 在這裏發送。若是 timestamp 大於或者等於 16777215 (十六進制 0xFFFFFF),這一字段必須是 16777215,代表有擴展 timestamp 字段來補充完整的 32 位 timestamp。不然的話,這一字段必須是整個的 timestamp。
類型 1 塊頭長爲 7 個字節。不包含消息流 ID;這一塊使用前一塊同樣的流 ID。可變長度消息的流 (例如,一些視頻格式) 應該在第一塊以後使用這一格式表示以後的每一個新消息。
類型 2 塊頭長度爲 3 個字節。既不包含流 ID 也不包含消息長度;這一塊具備和前一塊相同的流 ID 和消息長度。具備不變長度的消息 (例如,一些音頻和數據格式) 應該在第一塊以後使用這一格式表示以後的每一個新消息。
類型 3 的塊沒有消息頭。流 ID、消息長度以及 timestamp delta 等字段都不存在;這種類型的塊使用前面塊同樣的塊流 ID。當單一一個消息被分割爲多塊時,除了第一塊的其餘塊都應該使用這種類型。參考例 2 (5.3.2.2 小節)。組成流的消息具備一樣的大小,流 ID 和時間間隔應該在類型 2 以後的全部塊都使用這一類型。參考例 1 (5.3.2.1 小節)。若是第一個消息和第二個消息之間的 delta 和第一個消息的 timestamp 同樣的話,那麼在類型 0 的塊以後要緊跟一個類型 3 的塊,由於無需再來一個類型 2 的塊來註冊 delta 了。若是一個類型 3 的塊跟着一個類型 0 的塊,那麼這個類型 3 塊的 timestamp delta 和類型 0 塊的 timestamp 是同樣的。
塊消息頭中各字段的描述以下:
timestamp delta (三個字節):對於一個類型 1 或者類型 2 的塊,前一塊的 timestamp 和當前塊的 timestamp 的區別在這裏發送。若是 delta 大於或者等於 16777215 (十六進制 0xFFFFFF),那麼這一字段必須是爲 16777215,表示具備擴展 timestamp 字段來對整個 32 位 delta 進行編碼。不然的話,這一字段應該是爲具體 delta。
message length (三個字節):對於一個類型 0 或者類型 1 的塊,消息長度在這裏進行發送。注意這一般不一樣於塊的有效載荷的長度。塊的有效載荷表明全部的除了最後一塊的最大塊大小,以及剩餘的 (也多是小消息的整個長度) 最後一塊。
message type id (消息類型 id,一個字節):對於類型 0 或者類型 1 的塊,消息的類型在這裏發送。
message stream id (四個字節):對於一個類型爲 0 的塊,保存消息流 ID。消息流 ID 以小端格式保存。全部同一個塊流下的消息都來自同一個消息流。當能夠將不一樣的消息流組合進同一個塊流時,這種方法比頭壓縮的作法要好。可是,當一個消息流被關閉而其餘的隨後另外一個是打開着的,就沒有理由將現有塊流以發送一個新的類型 0 的塊進行復用了。
擴展 timestamp 字段用於對大於 16777215 (0xFFFFFF) 的 timestamp 或者 timestamp delta 進行編碼;也就是,對於不適合於在 24 位的類型 0、1 和 2 的塊裏的 timestamp 和 timestamp delta 編碼。這一字段包含了整個 32 位的 timestamp 或者 timestamp delta 編碼。能夠經過設置類型 0 塊的 timestamp 字段、類型 1 或者 2 塊的 timestamp delta 字段 16777215 (0xFFFFFF) 來啓用這一字段。當最近的具備同一塊流的類型 0、1 或 2 塊指示擴展 timestamp 字段出現時,這一字段纔會在類型爲 3 的塊中出現。
這個例子演示了一個簡單地音頻消息流。這個例子演示了信息的冗餘。
下一個表格演示了這個流所產生的塊。從消息 3 起,數據傳輸獲得了最佳化利用。每條消息的開銷在這一點以後都只有一個字節。
這一例子闡述了一條消息太大,沒法裝在一個 128 字節的塊裏,被分割爲若干塊。
這是傳輸的塊:
塊 1 的數據頭說明了整個消息長度是爲 307 個字節。由以上倆例子能夠得知,塊類型 3 能夠被用於兩種不一樣的方式。第一種是用於定義一條消息的配置。第二種是定義一個能夠從現有狀態數據中派生出來的新消息的起點。
RTMP 塊流使用消息類型 ID 爲 一、二、三、5 和 6 用於協議控制消息。這些消息包含有 RTMP 塊流協議所須要的信息。
這些協議控制消息必須使用消息流 ID 0 (做爲已知控制流) 並以流 ID 爲 2 的塊發送。協議控制消息一旦被接收到就當即生效;協議控制消息的 timestamp 被忽略。
協議控制消息 1,設置塊大小,以通知對端一個新的最大塊大小。
默認的最大塊大小是爲 128 字節,可是客戶端或者服務器能夠改變這個大小,並使用這一消息對對端進行更新。例如,假定一個客戶端想要發送一個 131 字節的音頻數據,當前塊大小是默認的 128。在這種狀況下,客戶端能夠發送這種消息到服務器以通知它塊大小如今是 131 字節了。這樣客戶端就能夠在單一塊中發送整個音頻數據了。
最大塊大小設置的話最少爲 128 字節,包含內容最少要一個字節。最大塊大小由每一個方面 (服務器或者客戶端) 自行維護。
0:這個位必須爲 0。
chunk size (塊大小,31 位):這一字段保存新的最大塊大小值,以字節爲單位,這將用於以後發送者發送的塊,直到有更多 (關於最大塊大小的) 通知。有效值爲 1 到 2147483647 (0x7FFFFFFF,1 和 2147483647 均可取); 可是全部大於 16777215 (0xFFFFFF) 的大小值是等價的,由於沒有一個塊比一整個消息大,而且沒有一個消息大於 16777215 字節。
協議控制消息 2,終止消息,用於通知對端,若是對端在等待去完成一個消息的塊的話,而後拋棄一個塊流中已接受到的部分消息。對端接收到塊流 ID 做爲當前協議消息的有效負載。一些程序可能會在關閉的時候使用這個消息以指示不須要進一步對這個消息的處理了。
chunk stream ID (塊流 ID,32 位):這一字段保存塊流 ID,該流的當前消息會被丟棄。
客戶端或者服務器在接收到等同於窗口大小的字節以後必需要發送給對端一個確認。窗口大小是指發送者在沒有收到接收者確認以前發送的最大數量的字節。這個消息定義了序列號,也就是目前接收到的字節數。
sequence number (序列號,32 位):這一字段保存有目前接收到的字節數。
客戶端或者服務器端發送這條消息來通知對端發送和應答之間的窗口大小。發送者在發送完窗口大小字節以後期待對端的確認。接收端在上次確認發送後接收到的指示數值後,或者會話創建以後還沒有發送確認,必須發送一個確認 (5.4.3 小節)。
客戶端或者服務器端發送這一消息來限制其對端的輸出帶寬。對端接收到這一消息後,將經過限制這一消息中窗口大小指出的已發送但未被答覆的數據的數量以限制其輸出帶寬。接收到這一消息的對端應該回復一個窗口確認大小消息,若是這個窗口大小不一樣於其發送給 (設置對端帶寬) 發送者的最後一條消息。
限制類型取如下值之一:
0 - Hard:對端應該限制其輸出帶寬到指示的窗口大小。
1 - Soft:對端應該限制其輸出帶寬到知識的窗口大小,或者已經有限制在其做用的話就取二者之間的較小值。
2 - Dynamic:若是先前的限制類型爲 Hard,處理這個消息就好像它被標記爲 Hard,不然的話忽略這個消息。
這一節定義了使用下層傳輸層 (好比 RTMP 塊流協議) 傳輸的 RTMP 消息的格式。
RTMP 協議設計使用 RTMP 塊流,可使用其餘任意傳輸協議對消息進行發送。RTMP 塊流和 RTMP 一塊兒適用於多種音頻 - 視頻應用,從一對一和一對多直播到點播服務,再到互動會議應用。
服務器端和客戶端經過網絡發送 RTMP 消息來進行彼此通訊。消息能夠包含音頻、視頻、數據,或者其餘消息。
RTMP 消息有兩部分:頭和它的有效載荷。
消息頭包含如下:
Message Type (消息類型):一個字節的字段來表示消息類型。類型 ID 1 - 6 被保留用於協議控制消息。
Length (長度):三個字節的字段來表示有效負載的字節數。以大端格式保存。
Timestamp:四個字節的字段包含了當前消息的 timestamp。四個字節也以大端格式保存。
Message Stream Id (消息流 ID):三個字節的字段以指示出當前消息的流。這三個字節以大端格式保存。
消息的另外一個部分就是有效負載,這是這個消息所包含的實際內容。例如,它能夠是一些音頻樣本或者壓縮的視頻數據。有效載荷格式和解釋不在本文檔範圍以內。
RTMP 使用消息類型 ID 4 表示用戶控制消息。這些消息包含 RTMP 流傳輸層所使用的信息。RTMP 塊流協議使用 ID 爲 一、二、三、5 和 6 (5.4 節介紹)。
用戶控制消息應該使用消息流 ID 0 (以被認爲是控制流),而且以 RTMP 塊流發送時以塊流 ID 爲 2。用戶控制消息一旦被接收立馬生效;它們的 timestamp 是被忽略的。
客戶端或者服務器端發送這個消息來通知對端用戶操做事件。這一消息攜帶有事件類型和事件數據。
消息數據的前兩個字節用於指示事件類型。事件類型被事件數據緊隨。事件數據字段的大小是可變的。可是,若是消息必須經過 RTMP 塊流層傳輸時,最大塊大小 (5.4.1 節) 應該足夠大以容許這些消息填充在一個單一塊中。
事件類型和事件數據格式將在 7.1.7 小節列出。
這一節描述了在服務器端和客戶端彼此通訊交換的消息和命令的不一樣的類型。
服務器端和客戶端交換的不一樣消息類型包括用於發送音頻數據的音頻消息、用於發送視頻數據的視頻消息、用於發送任意用戶數據的數據消息、共享對象消息以及命令消息。共享對象消息提供了一個通用的方法來管理多用戶和一臺服務器之間的分佈式數據。命令消息在客戶端和服務器端傳輸 AMF 編碼的命令。客戶端或者服務器端能夠經過使用命令消息和對端通訊的流請求遠程方法調用 (RPC)。
服務器端和客戶端經過在網絡中發送消息來進行彼此通訊。消息能夠是任何類型,包含音頻消息,視頻消息,命令消息,共享對象消息,數據消息,以及用戶控制消息。
命令消息在客戶端和服務器端傳遞 AMF 編碼的命令。這些消息被分配以消息類型值爲 20 以進行 AMF0 編碼,消息類型值爲 17 以進行 AMF3 編碼。這些消息發送以進行一些操做,好比,鏈接,建立流,發佈,播放,對端暫停。命令消息,像 onstatus、result 等等,用於通知發送者請求的命令的狀態。一個命令消息由命令名、事務 ID 和包含相關參數的命令對象組成。一個客戶端或者一個服務器端能夠經過和對端通訊的流使用這些命令消息請求遠程調用 (RPC)。
客戶端或者服務器端經過發送這些消息以發送元數據或者任何用戶數據到對端。元數據包括數據 (音頻,視頻等等) 的詳細信息,好比建立時間,時長,主題等等。這些消息被分配以消息類型爲 18 以進行 AMF0 編碼和消息類型 15 以進行 AMF3 編碼。
所謂共享對象實際上是一個 Flash 對象 (一個名值對的集合),這個對象在多個不一樣客戶端、應用實例中保持同步。消息類型 19 用於 AMF0 編碼、16 用於 AMF3 編碼都被爲共享對象事件保留。每一個消息能夠包含有不一樣事件。
支持如下事件類型:
事件 | 描述 |
Use(=1) | 客戶端發送這一事件以通知服務器端一個已命名的共享對象已建立。 |
Release(=2) | 當共享對象在客戶端被刪除時客戶端發送這一事件到服務器端。 |
Request Change (=3) | 客戶端發送給服務器端這一事件以請求共享對象的已命名的參數所關聯到的值的改變。 |
Change (=4) | 服務器端發送這一事件已通知發起這一請求以外的全部客戶端,一個已命名參數的值的改變。 |
Success (=5) | 若是請求被接受,服務器端發送這一事件給請求的客戶端,以做爲 RequestChange 事件的響應。 |
SendMessage (=6) | 客戶端發送這一事件到服務器端以廣播一條消息。一旦接收到這一事件,服務器端將會給全部的客戶端廣播這一消息,包括這一消息的發起者。 |
Status (=7) | 服務器端發送這一事件以通知客戶端異常狀況。 |
Clear (=8) | 服務器端發送這一消息到客戶端以清理一個共享對象。服務器端也會對客戶端發送的 Use 事件使用這一事件進行響應。 |
Remove (=9) | 服務器端發送這一事件有客戶端刪除一個 slot。 |
Request Remove (=10) | 客戶端發送這一事件有客戶端刪除一個 slot。 |
Use Success (=11) | 服務器端發送給客戶端這一事件表示鏈接成功。 |
客戶端或者服務器端發送這一消息以發送音頻數據到對端。消息類型 8 爲音頻消息保留。
客戶端或者服務器發送這一消息以發送視頻數據到對端。消息類型 9 爲視頻消息保留。
統計消息是一個單一的包含一系列的使用 6.1 節描述的 RTMP 子消息的消息。消息類型 22 用於統計消息。
統計消息的消息流 ID 覆蓋了統計中子消息的消息流 ID。
統計消息裏的 timestamp 和第一個子消息的 timestamp 的不一樣點在於子消息的 timestamp 被相對流時間標調整了偏移。每一個子消息的 timestamp 被加入偏移以達到一個統一流時間。第一個子消息的 timestamp 應該和統計消息的 timestamp 同樣,因此這個偏移量應該爲 0。
反向指針包含有前一個消息的大小 (包含前一個消息的頭)。這樣子匹配了 FLV 文件的格式,用於反向查找。
使用統計消息具備如下性能優點:
客戶端或者服務器端發送這一消息來通知對端用戶控制事件。關於這個的消息格式參考 6.2 節。
支持如下用戶控制事件類型:
事件 | 描述 |
Stream Begin (=0) | 服務器發送這個事件來通知客戶端一個流已就緒並能夠用來通訊。默認狀況下,這一事件在成功接收到客戶端的應用鏈接命令以後以 ID 0 發送。這一事件數據爲 4 字節,表明了已就緒流的流 ID。 |
Stream EOF (=1) | 服務器端發送這一事件來通知客戶端請求的流的回放數據已經結束。在發送額外的命令以前再也不發送任何數據。客戶端將丟棄接收到的這個流的消息。這一事件數據爲 4 字節,表明了回放已結束的流的流 ID。 |
StreamDry (=2) | 服務器端發送這一事件來通知客戶端當前流中已沒有數據。當服務器端在一段時間內沒有檢測到任何消息,它能夠通知相關客戶端當前流已經沒數據了。這一事件數據爲 4 字節,表明了已沒數據的流的流 ID。 |
SetBuffer Length (=3) | 客戶端發送這一事件來通知服務器端用於緩存流中任何數據的緩存大小 (以毫秒爲單位)。這一事件在服務器端開始處理流以前就發送。這一事件數據的前 4 個字節表明了流 ID 後 4 個字節表明了以毫秒爲單位的緩存的長度。 |
StreamIs Recorded (=4) | 服務器端發送這一事件來通知客戶端當前流是一個錄製流。這一事件數據爲 4 字節,表明了錄製流的流 ID。 |
PingRequest (=6) | 服務器端發送這一事件用於測試是否可以送達客戶端。時間數據是爲一個 4 字節的 timestamp,表明了服務器端發送這一命令時的服務器本地時間。客戶端在接收到這一消息後會當即發送 PingResponse 回覆。 |
PingResponse (=7) | 客戶端做爲對 ping 請求的回覆發送這一事件到服務器端。這一事件數據是爲一個 4 字節的 timestamp,就是接收自 PingRequest 那個。 |
客戶端和服務器端交換 AMF 編碼的命令。服務器端發送一個命令消息,這個命令消息由命令名、事務 ID 以及包含有相關參數的命令對象組成。例如,包含有 'app' 參數的鏈接命令,這個命令說明了客戶端鏈接到的服務器端的應用名。接收者處理這一命令並回發一個一樣事務 ID 的響應。回覆字符串能夠是 _result、_error 或者 一個方法名的任意一個,好比,verifyClient 或者 contactExternalServer。
命令字符串 _result 或者 _error 是響應信號。事務 ID 指示出響應所指向的命令。這和 AMAP 和其餘一些協議的標籤同樣。命令字符串中的方法名錶示發送者試圖執行接收者一端的一個方法。
如下類的對象用於發送不一樣的命令:
NetConnection 表明上層的服務器端和客戶端之間鏈接的一個對象。
NetStream 一個表明發送音頻流、視頻流和其餘相關數據的通道的對象。固然,咱們也會發送控制數據流的命令,諸如 play、pause 等等。
NetConnection 管理着一個客戶端應用和服務器端之間的雙相鏈接。此外,它還提供遠程方法的異步調用。
NetConnection 能夠發送如下命令:
客戶端發送 connect 命令到服務器端來請求鏈接到一個服務器應用的實例。
由客戶端發送到服務器端的 connect 命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令的名字。設置給 "connect"。 |
Transaction ID | 數字 | 老是設置爲 1。 |
Command Object | 對象 | 具備名值對的命令信息對象。 |
Optional User Arguments | 對象 | 任意可選信息。 |
如下是爲 connect 命令中使用的名值對對象的描述。
屬性 | 類型 | 描述 | 範例 |
app | 字符串 | 客戶端鏈接到的服務器端應用的名字。 | testapp |
flashver | 字符串 | Flash Player 版本號。和ApplicationScript getversion() 方法返回的是同一個字符串。 | FMSc/1.0 |
swfUrl | 字符串 | 進行當前鏈接的 SWF 文件源地址。 | file://C:/FlvPlayer.swf |
tcUrl | 字符串 | 服務器 URL。具備如下格式:protocol://servername:port/appName/appInstance | rtmp://localhost:1935/testapp/instance1 |
fpad | 布爾 | 若是使用了代理就是 true。 | true 或者 false。 |
audioCodecs | 數字 | 代表客戶端所支持的音頻編碼。 | SUPPORT_SND_MP3 |
videoCodecs | 數字 | 代表支持的視頻編碼。 | SUPPORT_VID_SORENSON |
videoFunction | 數字 | 代表所支持的特殊視頻方法。 | SUPPORT_VID_CLIENT_SEEK |
pageUrl | 字符串 | SWF 文件所加載的網頁 URL。 | http://somehost/sample.html |
objectEncoding | 數字 | AMF 編碼方法。 | AMF3 |
audioCodecs 屬性的標識值:
videoCodecs 屬性的標識值:
videoFunction 屬性的標識值:
encoding 屬性值:
服務器端到客戶端的命令的結構以下:
命令執行時消息流動以下:
1. 客戶端發送 connect 命令到服務器端以請求對服務器端應用實例的鏈接。
2. 收到 connect 命令後,服務器端發送協議消息 '窗口確認大小' 到客戶端。服務器端也會鏈接到 connect 命令中提到的應用。
3. 服務器端發送協議消息 '設置對端帶寬' 到客戶端。
4. 在處理完協議消息 '設置對端帶寬' 以後客戶端發送協議消息 '窗口確認大小' 到服務器端。
5. 服務器端發送另外一個用戶控制消息 (StreamBegin) 類型的協議消息到客戶端。
6. 服務器端發送結果命令消息告知客戶端鏈接狀態 (success/fail)。這一命令定義了事務 ID (經常爲 connect 命令設置爲 1)。這一消息也定義了一些屬性,好比 FMS 服務器版本 (字符串)。此外,它還定義了其餘鏈接關聯到的信息,好比 level (字符串)、code (字符串)、description (字符串)、objectencoding (數字) 等等。
7.2.1.2. call 方法
NetConnection 對象的 call 方法執行接收端遠程方法的調用 (PRC)。被調用的 PRC 名字做爲一個參數傳給調用命令。
發送端發送給接收端的命令結構以下:
字段名 | 類型 | 描述 |
Procedure Name | 字符串 | 調用的遠程方法的名字。 |
Transaction ID | 數字 | 若是指望回覆咱們要給一個事務 ID。不然咱們傳 0 值便可。 |
Command Object | 對象 | 若是存在一些命令信息要設置這個對象,不然置空。 |
Optional Arguments | 對象 | 任意要提供的可選參數。 |
回覆的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令的名字。 |
Transaction ID | 數字 | 響應所屬的命令的 ID。 |
Command Object | 對象 | 若是存在一些命令信息要設置這個對象,不然置空。 |
Response | 對象 | 調用方法的回覆。 |
客戶端發送這一命令到服務器端覺得消息鏈接建立一個邏輯通道。音頻、視頻和元數據使用 createStream 命令建立的流通道傳輸。
NetConnection 是默認的通訊通道,流 ID 爲 0。協議和一些命令消息,包括 createStream,使用默認的通訊通道。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名。設置給 "createStream"。 |
Transaction ID | 數字 | 命令的事務 ID。 |
Command Object | 對象 | 若是存在一些命令信息要設置這個對象,不然置空。 |
服務器端發送給客戶端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | _result 或者 _error;代表回覆是一個結果仍是錯誤。 |
Transaction ID | 數字 | 響應所屬的命令的 ID。 |
Command Object | 對象 | 若是存在一些命令信息要設置這個對象,不然置空。 |
Stream ID | 數字 | 返回值要麼是一個流 ID 要麼是一個錯誤信息對象。 |
NetStream 定義了傳輸通道,經過這個通道,音頻流、視頻流以及數據消息流能夠經過鏈接客戶端到服務端的 NetConnection 傳輸。
如下命令能夠由客戶端使用 NetStream 往服務器端發送:
服務器端使用 "onStatus" 命令向客戶端發送 NetStream 狀態:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名 "onStatus"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | onStatus 消息沒有命令對象。 |
Info Object | 對象 | 一個 AMF 對象至少要有如下三個屬性。"level" (字符串):這一消息的等級,"warning"、"status"、"error" 中的某個值;"code" (字符串):消息碼,例如 "NetStream.Play.Start";"description" (字符串):關於這個消息人類可讀描述。 |
7.2.2.1. play 命令
客戶端發送這一命令到服務器端以播放流。也能夠屢次使用這一命令以建立一個播放列表。
若是你想要建立一個動態的播放列表這一能夠在不一樣的直播流或者錄製流之間進行切換播放的話,屢次調用 play 方法,並在每次調用時傳遞重置爲 false。相反的,若是你想要當即播放指定流,將其餘等待播放的流清空,併爲重置設爲 true。
客戶端發送到服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名。設爲 "play"。 |
Transaction ID | 數字 | 事務 ID 設爲 0。 |
Command Object | Null | 命令信息不存在。設爲 null 類型。 |
Stream Name | 字符串 | 要播放流的名字。要播放視頻 (FLV) 文件,使用沒有文件擴展名的名字對流名進行定義 (例如,"sample")。要重播 MP3 或者 ID3,你必須在流名前加上 mp3:例如,"mp3:sample"。要播放 H.264/AAC 文件,你必須在流名前加上 mp4:並指定文件擴展名。例如,要播放 sample.m4v 文件,定義 "mp4:sample.m4v"。 |
Start | 數字 | 一個可選的參數,以秒爲單位定義開始時間。默認值爲 -2,表示用戶首先嚐試播放流名字段中定義的直播流。若是那個名字的直播流沒有找到,它將播放同名的錄製流。若是沒有那個名字的錄製流,客戶端將等待一個新的那個名字的直播流,並當其有效時進行播放。若是你在 Start 字段中傳遞 -1,那麼就只播放流名中定義的那個名字的直播流。若是你在 Start 字段中傳遞 0 或一個整數,那麼將從 Start 字段定義的時間開始播放流名中定義的那個錄製流。若是沒有找到錄製流,那麼將播放播放列表中的下一項。 |
Duration | 數字 | 一個可選的參數,以秒爲單位定義了回放的持續時間。默認值爲 -1。-1 值意味着一個直播流會一直播放直到它再也不可用或者一個錄製流一直播放直到結束。若是你傳遞 0 值,它將只播放單一一幀,由於播放時間已經在錄製流的開始的 Start 字段指定了。假定定義在 Start 字段中的值大於或者等於 0。若是你傳遞一個正數,將播放 Duration 字段定義的一段直播流。以後,變爲可播放狀態,或者播放 Duration 字段定義的一段錄製流。(若是流在 Duration 字段定義的時間段內結束,那麼流結束時回放結束)。若是你在 Duration 字段中傳遞一個 -1 之外的負數的話,它將把你給的值當作 -1 處理。 |
Reset | 布爾 | 一個可選的布爾值或者數字定義了是否對之前的播放列表進行 flush。 |
命令執行時的消息流動是爲:
1. 當客戶端從服務器端接收到 createStream 命令的結果是爲 success 時,發送 play 命令。
2. 一旦接收到 play 命令,服務器端發送一個協議消息來設置塊大小。
3. 服務器端發送另外一個協議消息 (用戶控制),這個消息中定義了 'StreamIsRecorded' 事件和流 ID。消息在前兩個字節中保存事件類型,在後四個字節中保存流 ID。
4. 服務器端發送另外一個協議消息 (用戶控制),這一消息包含 'StreamBegin' 事件,來指示發送給客戶端的流的起點。
5. 若是客戶端發送的 play 命令成功,服務器端發送一個 onStatus 命令消息 NetStream.Play.Start & NetStream.Play.Reset。只有當客戶端發送的 play 命令設置了 reset 時服務器端纔會發送 NetStream.Play.Reset。若是要播放的流沒有找到,服務器端發送 onStatus 消息 NetStream.Play.StreamNotFound。
以後,服務器端發送視頻和音頻數據,客戶端對其進行播放。
不一樣於 play 命令的是,play2 能夠在不改變播放內容時間軸的狀況下切換到不一樣的比特率。服務器端爲客戶端能夠在 play2 中請求全部支持的碼率維護了不一樣的字段。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設置爲 "play2"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | 命令信息不存在,設置爲 null 類型。 |
Parameters | 對象 | 一個 AMF 編碼的對象,該對象的屬性是爲公開的 flash.net.NetStreamPlayOptions ActionScript 對象所描述的屬性。 |
NetStreamPlayOptions 對象的公開屬性在 ActionScript 3 語言指南中 [AS3] 有所描述。
命令執行時的消息流動以下圖所示:
當 NetStream 對象消亡時 NetStream 發送 deleteStream 命令。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設置爲 "deleteStream"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | 命令信息對象不存在,設爲 null 類型。 |
Stream ID | 數字 | 服務器端消亡的流 ID。 |
服務器端再也不發送任何回覆。
NetStream 經過發送 receiveAudio 消息來通知服務器端是否發送音頻到客戶端。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設置爲 "receiveAudio"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | 命令信息對象不存在,設置爲 null 類型。 |
Bool Flag | 布爾 | true 或者 false 以代表是否接受音頻。 |
若是發送來的 receiveAudio 命令布爾字段被設爲 false 時服務器端不發送任何回覆。若是這一標識被設爲 true,服務器端以狀態消息 NetStream.Seek.Notify 和 NetStream.Play.Start 進行回覆。
7.2.2.5. receiveVideo 命令
NetStream 經過發送 receiveVideo 消息來通知服務器端是否發送視頻到客戶端。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設置爲 "receiveVideo"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | 命令信息對象不存在,設置爲 null 類型。 |
Bool Flag | 布爾 | true 或者 false 以代表是否接受視頻。 |
若是發送來的 receiveVideo 命令布爾字段被設爲 false 時服務器端不發送任何回覆。若是這一標識被設爲 true,服務器端以狀態消息 NetStream.Seek.Notify 和 NetStream.Play.Start 進行回覆。
客戶端發送給服務器端這一命令以發佈一個已命名的流。使用這個名字,任意客戶端均可以播放這個流,並接受發佈的音頻、視頻以及數據消息。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設置爲 "publish"。 |
Transaction ID | 數字 | 事務 ID 設置爲 0。 |
Command Object | Null | 命令信息對象不存在,設置爲 null 類型。 |
Publishing Name | 字符串 | 發佈的流的名字。 |
Publishing Type | 字符串 | 發佈類型。能夠設置爲 "live"、"record" 或者 "append"。record:流被髮布,數據被錄製到一個新的文件。新文件被存儲在服務器上包含服務應用目錄的子路徑。若是文件已存在,將重寫。append:流被髮布,數據被添加到一個文件。若是該文件沒找着,將新建一個。live:直播數據只被發佈,並不對其進行錄製。 |
服務器端回覆 onStatus 命令以標註發佈的起始位置。
客戶端發送 seek 命令以查找一個多媒體文件或一個播放列表的偏移量 (以毫秒爲單位)。
客戶端發送到服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令的名字,設爲 "seek"。 |
Transaction ID | 數字 | 事務 ID 設爲 0。 |
Command Object | Null | 沒有命令信息對象,設置爲 null 類型。 |
milliSeconds | 數字 | 播放列表查找的毫秒數。 |
seek 命令執行成功時服務器會發送一個狀態消息 NetStream.Seek.Notify。失敗的話,服務器端返回一個 _error 消息。
客戶端發送 pause 命令以告知服務器端是暫停仍是開始播放。
客戶端發送給服務器端的命令結構以下:
字段名 | 類型 | 描述 |
Command Name | 字符串 | 命令名,設爲 "pause"。 |
Transaction ID | 數字 | 沒有這一命令的事務 ID,設爲 0。 |
Command Object | Null | 命令信息對象不存在,設爲 null 類型。 |
Pause/Unpause Flag | 布爾 | true 或者 false,來指示暫停或者從新播放。 |
milliSeconds | 數字 | 流暫停或者從新開始所在的毫秒數。這個是客戶端暫停的當前流時間。當回放已恢復時,服務器端值發送帶有比這個值大的 timestamp 消息。 |
當流暫停時,服務器端發送一個狀態消息 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, <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>.