一、概念與摘要
RTMP協議從屬於應用層,被設計用來在適合的傳輸協議(如TCP)上復用和打包多媒體傳輸流(如音頻、視頻和互動內容)。RTMP提供了一套全雙工的可靠的多路復用消息服務,類似於TCP協議[RFC0793],用來在一對結點之間並行傳輸帶時間戳的音頻流,視頻流,數據流。通常情況下,不同類型的消息會被分配不同的優先級,當網絡傳輸能力受限時,優先級用來控制消息在網絡底層的排隊順序。
二、RTMP塊流
實時消息傳遞協議塊流(RTMP塊流)。它作為一款高級多媒體流協議提供了流的多路復用和打包服務。RTMP塊流被設計用來傳輸實時消息協議,它可以使用任何協議來發送消息流。每個消息都包含時間戳和有效類型標識。RTMP塊流和RTMP適用於各種視聽傳播的應用程序,包括一對一的,和一對多的視頻直播、點播服務、互動會議應用程序。
當使用一個可靠的傳輸協議如TCP[RFC0793]時,RTMP塊流提供了一種可以在多個流中,基於時間戳的端到端交付所有消息的方法。RTMP塊流不提供任何優先級或類似形式的控制,但可以使用更高級別的協議來提供這樣的優先級。例如,一個視頻服務器可以根據發送的時間或確認每個消息的時間,來決定為一個網絡差的用戶丟棄視頻信息,以確保音頻信息的及時接收。
RTMP塊流不僅包含了自己的協議控制信息,同時也提供了一個更高級別的協議機制,用來嵌入用戶控制信息。
消息格式
消息格式可以被分割成多個塊,用來在更高的協議中支持多路復用。在創建塊消息格式時,應該包含以下字段:
時間戳
消息的時間戳。這個字段占用4字節。
長度
消息的有效長度。如果消息頭不能被忽略,它應該包括長度。這個字段在塊頭中占用3字節。
類型ID
各種類型的協議控制消息的ID。這些消息使用RTMP塊流協議和更高級別的協議來傳輸信息。所有其他類型的ID可以用在高級協議,這對於RTMP塊流來說,是不透明的。事實上,RTMP塊流中沒有要求使用這些值作為類型;所有(無協議的)消息可能是相同的類型,或者應用程序使用這個字段來區分多個連接,而不是類型。這個字段在塊頭中占用1字節。
消息流ID
消息流ID可以是任意值。當同一個塊流被復用到不同的消息流中時,可以通過消息流ID來區分它們。另外,對於RTMP塊流而言,這是一個不透明值。該字段占用4字節,使用小端序。
握手
RTMP連接從握手開始。它包含三個固定大小的塊,不像其他的協議,是由頭部大小可變的塊組成的。
客戶端(初始化連接的一端)和服務端發送同樣的三個塊。為了方便描述,客戶端發送的三個塊命名為C0,C1,C2;服務端發送的三個塊命名為S0,S1,S2。
握手序列
客戶端通過發送C0和C1消息來啟動握手過程。客戶端必須接收到S1消息,然后發送C2消息。客戶端必須接收到S2消息,然后發送其他數據。
服務端必須接收到C0或者C1消息,然后發送S0和S1消息。服務端必須接收到C1消息,然后發送S2消息。服務端必須接收到C2消息,然后發送其他數據。
C0和S0格式
C0和S0包由一個字節組成,下面是C0/S0包內的字段:
0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ | version | +-+-+-+-+-+-+-+-+ C0 and S0 bits
版本(8比特)
在C0包內,這個字段代表客戶端請求的RTMP版本號。在S0包內,這個字段代表服務端選擇的RTMP版本號。此文檔使用的版本是3。版本0-2用在早期的產品中,現在已經被棄用;版本4-31被預留用於后續產品;版本32-255(為了區分RTMP協議和文本協議,文本協議通常以可打印字符開始)不允許使用。如果服務器無法識別客戶端的版本號,應該回復版本3。客戶端可以選擇降低到版本3,或者中止握手過程。
C1和S1格式
C1和S1包長度為1536字節,包含以下字段:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | zero (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | random bytes | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | random bytes | | (cont) | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ C1 and S1 bits
時間(4字節)
本字段包含一個時間戳,客戶端應該使用此字段來標識所有流塊的時刻。時間戳取值可以為零或其他任意值。為了同步多個塊流,客戶端可能希望多個塊流使用相同的時間戳。
零(4字節)
本字段必須為零。
隨機數據(1528字節)
本字段可以包含任意數據。由於握手的雙方需要區分另一端,此字段填充的數據必須足夠隨機(以防止與其他握手端混淆)。不過沒必要為此使用加密數據或動態數據。
C2和S2格式
C2和S2包長度為1536字節,作為C1和S1的回應,包含以下字段:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time2 (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | random echo | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | random echo | | (cont) | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ C2 and S2 bits
時間(4字節)
本字段必須包含對端發送的時間戳。
時間(4字節)
本字段必須包含時間戳,取值為接收對端發送過來的握手包的時刻。
隨機數據(1528字節)
本字段必須包含對端發送過來的隨機數據。握手的雙方可以使用時間1和時間2字段來估算網絡連接的帶寬和/或延遲,但是不一定有用。
三、RMTP握手
握手過程示意圖
+-------------+ +-------------+ | Client | TCP/IP Network | Server | +-------------+ | +-------------+ | | | Uninitialized | Uninitialized | C0 | | |------------------->| C0 | | |-------------------->| | C1 | | |------------------->| S0 | | |<--------------------| | | S1 | Version sent |<--------------------| | S0 | | |<-------------------| | | S1 | | |<-------------------| Version sent | | C1 | | |-------------------->| | C2 | | |------------------->| S2 | | |<--------------------| Ack sent | Ack Sent | S2 | | |<-------------------| | | | C2 | | |-------------------->| Handshake Done | Handshake Done | | | Pictorial Representation of Handshake 握手示意圖
下面是握手示意圖中提到的狀態:
未初始化
協議版本號在此階段發送。客戶端和服務器均處於未初始化狀態。客戶端發送攜帶協議版本號的C0包。如果服務器支持此版本,回復S0和S1包。如果服務器不支持此版本,使用適當的動作回復。在RTMP協議中,此動作是中止連接。
注: 在”C0和S0格式”章節中提及,如果服務器不支持客戶端的版本號,可以選擇降到版本3或中止。
發送版本
客戶端和服務器雙方在未初始化狀態后,會進入發送版本狀態。之后,客戶端等待S1包,服務器等待C1包。待接收到數據包,客戶端發送C2包,服務器發送S2包。然后,雙方都進入答復狀態。客戶端等待C2的答復,服務器等待S2的答復。
握手完成
客戶端和服務器交換消息。