(轉)RTMP Spec中文版

Adobe's Real Time Messaging Protocol

摘要

本文檔描述了Adobe公司的實時消息協議(RTMP),RTMP是設計用於multiplexing和分組多媒體傳輸流的建立在合適傳輸協議之上(如TCP)的應用層協議。

1. 簡介

RTMP協議基於可靠的流傳輸(如TCP)層提供了一項雙向消息複用服務,目的是可以在兩節點間並行傳輸帶有時間信息的音頻、視頻和數據消息。

RTMP的實現中通常會給不同類別消息分配不同優先級,從而達到在傳輸容量被壓縮時影響進入底層傳輸流中消息的目的。

本文檔描述了RTMP的相關語法和操作。

1.1 術語

文檔中使用的關鍵詞如“MUST”,"MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" 以及 “OPTIONAL”可在[RFC2119]中找到相應的說明。

2. 定義

  • 負載Payload:分組(packet)中包含的數據,如音頻採樣點或已壓縮視頻數據。
  • 分組Packet:一個數據分組包含了固定頭(header)和payload數據。部分底層協議可能會需要定義分組的封裝。
  • 端口Port: 在給定計算機上區隔多終端的抽象,TCP/IP協議簇使用小的正整數標識不同端口,OSI模型中傳輸層的選擇器和端口有相同的效果。
  • 傳輸地址(Transport address):通過組合網絡地址和端口來標識傳輸層終端,格式如IP:TCP Port。分組總是從源傳輸地址到目的傳輸地址流動。
  • 消息流(Message stream): 消息傳輸的邏輯通道
  • 消息流ID(Message stream ID):ID用於標識消息傳輸的具體消息流
  • 塊(Chunk):消息碎片。消息通過網絡發送前分解成小塊並交錯存取。塊保證了所有消息在點對點跨流時保持時間序列傳輸。
  • 塊流(Chunk stream): 支持塊定向傳輸的邏輯通道,塊流可以從client到server,反向亦可支持
  • 塊流ID(Chunk stream ID):每個塊都有自己的ID,用以標識將在哪個塊流傳輸
  • 複用(Multiplexing):將獨立的音視頻數據整合至一個音視頻流中,從而使得可以同步傳輸多個音視頻數據
  • 解複用(DeMultiplexing):複用的逆向處理,從流中分解出獨立的音視頻數據
  • 遠程過程調用(Remote Procedure Call, RPC): 允許對端Client或Server遠程調用子程序或過程。
  • 元數據(Metadata):數據說明,如一部電影的元數據包括電影名稱、時長、創建時間等
  • 應用實例(Application Instance):位於server的應用實例,由client端發起連接請求是創建
  • 活動消息格式(Action Message Format, AMF):一種緊湊二進制格式,用於格式化活動腳本對象圖(ActionScript object graph)。AMF目前有兩個版本:AMF0 和 AMF3

3. 字節序、字節對齊和時間格式

所有的整型字段都是使用網絡字節序(big-endian)進行傳輸的,該部分在[RFC0791]中有詳細描述。另外,除特殊說明,文檔中所有常數均爲十進制格式。

同樣,如無特殊說明,RTMP中所有數據都是字節對齊(byte-aligned)的;舉個例子,一個16位的變量可能會處於奇數偏移位置。當需要補齊時,對應字節應當用用0填充。

RTMP中時間戳是一個整型值,單位爲毫秒,它是一個相對值,相對未規定的某一時間點。通常,每個流會從時間戳0開始,但也不是必須的,只要流兩端能夠協商某一起始點即可。

注意,這說明任何需要跨流(尤其是不同主機間)同步必須依賴RTMP以外的其他機制。

由於時間戳32bits長度限制,它會在每49天17時2分47.296秒循環一次。但流通常是會持續地傳輸,甚至長達數年之久,因此RTMP應用需要在處理時間戳時使用serial number arithmetic[RFC1982],而且應當支持回滾處理。

時間戳增量同樣規定爲一個無符號整形數,單位毫秒,但相對於時間爲上一時間戳。時間戳增量可使用24或32bits長度。

4. RTMP塊流

本章節制定了RTMP塊流細節,它爲更高層流媒體協議提供了複用和分組服務。

雖然RTMP塊流設計用於協同RTMP協議工作,但它同樣適用於其他發送消息流的協議。每條消息由時間戳和負載類型標識構成。RTMP塊流和RTMP廣泛適用於各種音視頻應用,既支持“一對一”或“一對多”實時廣播,也支持爲會議交互系統提供視頻點播(video-on-demand)服務。

當配合可靠傳輸協議如TCP時,RTMP塊流提供了有保證的時間戳序列的對端跨流消息傳輸。RTMP塊流並未提供任何優先級或相關形式的控制,但可被高層協議用於提供類似功能。例如,一個實時視頻服務器可能會參考每條消息發送和響應的時間,來決定是否要丟棄部分視頻消息以滿足較慢客戶端能夠流暢地接收音頻數據。

RTMP塊流集成了帶內(in-band)協議控制消息,而且爲高層協議提供了嵌入自定義控制消息的機制。

4.1 消息格式

消息格式可劃分爲塊來支持不同高層協議進行復用。但無論如何,下列字段都是創建塊時所必須的:

  • 時間戳Timestamp:消息時間戳,該字段爲4個字節
  • 長度Length: 消息負載長度,如果消息頭(header)不能被省略,其長度也應計入其中。該字段佔用塊頭中的3個字節
  • 類型Id:一些類型ID預留用於協議控制消息,這些傳遞信息的消息會同時被RTMP塊流協議和高層協議處理。所有其他的類型ID則由高層協議使用,RTMP塊流會直接忽略這些值。實際上,RTMP塊流並不需要類型ID,所有消息都可以是同一類型,有時候應用可以通過該字段來區隔同步軌。該字段佔用塊頭中的1個字節
  • 消息流ID:消息流ID可以是任意值,不同的消息流複用到同一塊流,然後再根據各自消息流ID進行解複用。除此之外,別無用處。該字段佔用塊頭中的4字節,使用小端法(little-endian)格式。

4.2 握手

RTMP連接始於握手,與其他協議握手不一樣的是,它一共包含了3次固定大小的塊,而不是類似的帶有頭信息的可變大小塊。

客戶端和服務器都會發送同樣的三個塊,具體而言,客戶端發送的三個塊分別爲C0, C1和C2;而服務器會發送對應的S0, S1和S2。

4.2.1 握手次序

握手次序是以客戶端發送C0和C1塊開始的。

客戶端必須成功接收到S1後才發送C2,且必須成功接收S2後纔可以發送其他數據。

服務器必須成功接收C0後(也可以選擇C1後才發送)纔可以發送S0和S1。對S2而言,服務器必須成功接收C1後纔可以,最後服務器必須成功接收到C2纔可以開始發送其他數據。

4.2.2 C0和S0格式

C0和S0分組都是一個八位數(octet)字段:

 

 
 

各字段含義如下所述:

 

  • Version (8 bits): 在C0中,該字段標識客戶端請求使用的RTMP版本;在S0中,該字段標識服務器選擇使用的RTMP版本。如果服務器不能識別客戶端所請求的版本時,應該回復3。相應的,客戶端可以選擇使用版本3,也可以放棄握手。

本文檔多對應的版本值爲3,0 ~ 2是早期產品值,現已不推薦使用。4 ~ 31預留用於將來的實現版本使用;32 ~ 255則爲禁止使用值(以便區分RTMP和基於文本的協議,它們總是會以可打印字符開始)。

4.2.3 C1和S1格式

C1和S1分組均長1536個字節,由如下字段組成:

 
 

 

  • Time (4 bytes): 該字段包含一個時間戳,它是所有之後發出塊的起始點。它既可以是0值,也可以是其他任意數字。爲了同步多個塊流,斷點可能會希望發送其他塊流的當前時間戳。
  • Zero (4 bytes):該字段必須爲0s
  • Random data (1528 bytes):該字段可以包含任意數值。由於每個終端需要區分自身發起的握手還是對端發起的,該字段應當用於發送一些充分隨機數以做標識。但也沒有必要因此而選擇一些加密等級的隨機數,甚至動態數值。

4.2.4 C2和S2格式

C2和S2同樣是1536字節,相當於是S1和C1的迴應,均包含如下字段:

 
 
  • Time (4 bytes): 該字段必須爲對端先前發送的塊時間戳,C2中填寫S1的,S2中填寫C1的
  • Time2 (4 bytes): 該字段必須包含讀取到前一塊(S1或C1)的時間戳
  • Random echo (1528 bytes): 該字段必須爲對端發送的隨機數。兩端均可通過time和time2以及當前時間來快速估計出當前連接的帶寬和延時,只有這個字段看起來毫無用處。

4.2.5 握手圖例

 

 
 

下面將主要說明握手圖例中提到的不同狀態:

 

  • Unintialized: 未初始化,協議版本在該階段發送,此時客戶端和服務器均爲“未初始化狀態”。客戶端在C0塊中發送協議版本,如果服務器支持該版本號,則返回S0和S1作爲響應。如果不支持,則服務器採取合適的行爲作爲響應。在RTMP中,該行爲通常是關閉連接。
  • Version Sent: 版本號已發出,客戶端和服務器的“未初始化狀態”的下一階段都是“版本號已發出”階段。此時客戶端在等待S1塊,而服務器在等待C1塊。一旦成功接收後,客戶端迴應C2塊,而服務器迴應S2塊。之後便進入了“響應已發出”狀態。
  • Ack Sent: 響應已發出,客戶端和服務器均在分別等待S2和C2塊。
  • Handshake Done: 握手成功,客戶端和服務器交換消息。

4.3 分塊

握手成功後,連接將會複用一至多個塊流。每個塊流攜帶源自一個消息流中的一類消息。每個塊創建時賦予獨特ID,稱爲塊流ID(chunk stream ID)。這些塊經由網絡傳輸,在傳輸時,每個塊必須依次逐個傳遞,接收端收到塊後,會基於塊流ID將塊重組成消息。

分塊機制允許高層協議中的長消息分解爲短消息,這樣可以防止長的短優先級消息(如視頻)阻塞高優先級消息(如音頻或控制操作)。

分塊機制還通過將本應包含在消息中的信息壓縮至塊頭中以減小發送短消息的開銷。

塊的大小是可配置的,它還支持通過一系列“塊大小設置消息(Chunk Size control message, section 4.4.1)”進行設置。設置塊長度較大時可以降低CPU使用率,但同樣會由於大量數據寫入而造成低帶寬環境下其他內容的延時。設置塊長度較小時不利於高比特率流傳輸。

塊的大小由兩端單獨控制。

4.3.1 塊格式

每個塊均由頭(header)和數據(data)構成,頭本身又包括下面三部分:

 
 
  • Basic Header(1 to 3 bytes):基礎頭,該字段編碼了塊流ID和塊類型。塊類型決定了編碼後的消息頭格式,而長度則完全由可變長塊流ID決定。
  • Message Header(0, 3, 7 or 11 bytes):該字段編碼了要發送的消息的信息(無論整個發送還是切分後發送)。它的長度由塊頭中的塊類型決定
  • Extended Timestamp (0 or 4 bytes):擴展時間戳,該字段是否出現由塊消息頭中的時間戳或時間戳增量字段決定,更多內容可閱讀 Section 4.3.1.3
  • Chunk Data(variable size): 塊數據,是快的真正負載,長度最大可爲已配置的塊長最大值

4.3.1.1 塊基礎頭

塊基礎頭編碼了塊流ID和塊類型(如下圖的fmt字段所示)。塊類型決定了編碼後消息頭的格式,塊基礎頭長度根據塊流ID可爲1,2,或3字節。

塊基礎頭中的0 ~ 5 bit (least significant)代表塊流ID。

實現時應該使用最短的長度來表示ID。

協議最多支持65597個流,流ID分別爲3 ~ 65599. ID 0、1和2暫時預留。

  • 0值表示2字節格式,其ID值範圍爲64 ~ 319 (第二字節+64)
  • 1值表示3字節格式,其ID值範圍爲64 ~ 65599 (第三字節*256 + 第二字節 + 64)。
  • 2值預留給低層協議發送控制消息或命令

值爲 3 ~ 63的表示完整流ID。

塊流ID爲2 ~ 63時,可編碼入1字節版本:

 
 

塊流ID爲 64 ~ 319時,可編碼入2字節版本,ID計算式爲(第二字節+64):

 
 

塊流ID爲 64 ~ 65599時,可編碼入3字節版本,ID計算式爲(第三字節*256 + 第二字節 + 64):

 
 

對應字段說明如下:

  • cs id(6 bits): 該字段包含了塊流ID,值爲0或1用於標識使用2個還是3個字節來表示該字段
  • fmt (2 bits): 該字段標識了塊消息頭中使用的四個格式之一,關於塊消息頭的內容會在下一章節中講到
  • cs id - 64 (8 or 16 bits): 該字段包含了塊流ID減去64的值。例如,ID爲365時,cs id值爲1,且16bits中值爲301

塊流ID值爲 64 ~ 319可選擇使用2字節或3字節格式進行表示

4.3.1.2 塊消息頭

塊消息頭共有四種格式,由塊基礎頭中的“fmt”字段進行選擇。
實現時應該使用最緊湊的方式來表示每一個塊消息頭。

4.3.1.2.1 類型0

類型0 塊頭共11字節長,該類型必須使用在塊流的開頭和任何流時間戳回滾(如向後seek)的時候。

 
 

 

  • timestamp(3 bytes): 對於類型0的塊,這裏填寫發送消息時的絕對時間戳。如時間戳大於或等於 16777215(十六進制 0xFFFFFF)時,該字段值必須爲16777215,且擴展時間戳必須出現以編碼完整的32位時間戳。除此之外,該字段必須爲完整時間戳值。
4.3.1.2.2 類型1

類型1 塊頭長7字節,消息流ID未包含在內,該塊使用和前面塊一致的塊流ID。可變長消息的流(如許多視頻格式)應當使用本格式作爲每條新消息的第二塊:

 
 
4.3.1.2.3 類型2

類型2 塊頭長3字節,消息流ID和長度均未包含在內;該塊使用和前面塊一致的塊流ID和長度值。具有固定長度消息的流(如許多音頻和數據格式)可使用本格式作爲每條消息的第二塊:

 
 
4.3.1.2.4 類型3

類型3 塊沒有消息頭,流ID、消息長度以及時間戳增量字段都不會呈現;本類型的塊是錢前面塊的流ID。當一條消息分解成塊後,除第一塊外,所有其他塊都該使用此類型(參考示例2,Section 4.3.2.2)。由完全相同大小、流ID和時間間隔的消息流可在開頭的類型2塊後的所有塊中使用類型3塊(參考示例1,Section 4.3.2.1)。如果第二條消息和第一條消息的時間增量與第一條消息的時間戳相同,那麼可以在類型0塊後直接跟隨類型3塊,因爲沒有必要使用類型2塊說明時間增量。也就是說,如果類型3塊緊跟類型0塊,那麼該類型3塊的時間增量是和類型0塊一致的。

4.3.1.2.5 常用消息頭變量

下面列出塊消息頭中的每個變量說明:

  • 時間戳增量(3字節):用於類型1和類型2塊,標識與前一塊時間戳的差值。如果增量大於或等於16777215(十六進制 0xFFFFFF),該變量必須爲16777215,以說明將同時使用到擴展時間戳以完成32位完整增量的編碼。除此之外,該變量應該等於實際差值。
  • 消息長度(3字節):用於類型0和類型1塊,標識消息長度。注意該變量通常和塊負載長度不同。The chunk payload length is the maximum chunk size for all but the last chunk, and the remainder (which may be the entire length, for small messages) for the last chunk.
  • 消息類型ID(1字節):用於類型0和類型1塊,標識當前發送消息的類型。
  • 消息流ID(4字節):用於類型0塊,標識存儲的消息流ID。消息流ID使用little-endian格式存儲。通常,同一塊流中的所有消息消息流ID相同,但將多個消息流複用到同一塊流中也是可以的,不過這樣就會失去可使用塊頭壓縮而帶來的好處。不過當一個消息流關閉且另外一個緊接着打開時,也沒有理由不通過發送新的類型0塊對已經存在的塊流進行復用。

4.3.1.3 擴展時間戳

擴展時間戳用於編碼大於16777215(十六進制0xFFFFFF)的時間戳或時間戳增量,即用於類型0,1,2塊中不適合24位變量的時間戳或時間戳增量。該變量編碼了完整的32位時間戳或時間戳增量。該變量的出現意味着塊0中時間戳或塊1/2中時間戳增量值爲16777215(0xFFFFFF)。該變量會在當最近的具有相同塊流ID類型0/1/2塊中出現擴展時間戳變量時,出現在緊跟其後的類型3塊中。

4.3.2 示例

4.3.2.1 示例1

下面是一個簡單的音頻消息流示例,例子中示範了消息的冗餘。

 
 

下表中顯示流中對應產生的塊,從消息3開始,數據傳輸做了最優化,每條消息前僅添加了一個字節:
 
 

 

4.3.2.2 示例2

下面舉例說明了當消息太長而無法放入一個128字節的塊時,分解成多個塊進行傳輸。

 
 

下面是對應產生的塊:
 
 

塊1消息頭中指明瞭消息總長307字節。

 

注意:
在上面兩個示例中,類型3塊可被用於兩種用途。

  • 標識爲一個消息的連續
  • 標識一個新消息的開始,該塊沿用已存在的頭信息

4.4 協議控制消息

RTMP塊流可使用消息類型ID爲1,2,3,5和6來發送協議控制消息,這些消息包含了RTMP塊流協議所必需的信息。

這些協議控制消息必須使用消息流ID 0(又稱爲控制流)且在塊流ID 2中發送。協議控制消息收到時立即生效,他們的時間戳會被直接忽略。

4.4.1 設置塊大小(1)

協議控制消息1是設置塊大小,用於通知對端更新最大塊大小。

最大塊大小默認爲128字節,但是客戶端或服務器都可以修改該值,然後通過消息通知對端更新。例如,假設一個客戶端希望發送131字節的音頻數據,而此時塊大小爲128字節,這時候客戶端就可以發送消息1修改塊大小爲131字節,然後客戶端就可以在單個塊中發送音頻數據了。

最大塊大小應當至少爲128字節,極端情況下,必須大於1字節。最大塊字節可由任意方向單獨維護。

 
 

 

0: 該位必須爲0
塊大小(31位):該處保存最大塊大小值,單位爲字節,將用於之後所有發送的塊直到有新的通知位置。有效大小是1到2147483647(0x7FFFFFFF),事實上,所有大於16777215(0xFFFFFF)的值都是等價的,因爲沒有塊可以大於消息長度。

4.4.2 取消消息(2)

協議控制消息2是取消消息,用於通知對端如在等待某一消息的剩餘塊,請忽略該消息中所有已收到塊。對端接收作爲協議消息負載的塊流ID值。應用可能在關閉時發送該消息來告知對端該消息的無需進行後續處理。

 
 

 

塊流ID(32位):該變量保存塊流ID,標識那條消息將被丟棄

4.4.3 確認(3)

客戶端或服務器必須在接收窗口大小(window size)的數據後發送確認消息,窗口大小是發送端在收到接收端確認前可發送的最大數據字節數。該消息指明瞭序列數值,標識當前所收到字節數。

 
 

 

序列數值(32位):該變量保存目前收到所有字節數

4.4.4 窗口確認大小(5)

客戶端或服務器通過發送該消息來通知對端發送確認消息的間隔窗口大小。發送端會在發送窗口大小的字節數後等待確認消息,而接收端必須在繼最近一次發送確認消息後收到指定數值的字節後再次發送確認消息。

 
 

 

4.4.5 設置對端帶寬(6)

客戶端或服務器發送該消息來限制對端輸出帶寬,對端接收到該消息後會通過限制窗口大小來實現限制帶寬。如對端窗口大小與帶寬值不同,則需響應一條窗口確認大小消息。

 
 

 

限制類型是下列值之一:

  • 0 - 硬限制:對端必須限制輸出帶寬爲所述窗口大小
  • 1 - 軟限制:對端必須限制輸出帶寬爲所述窗口大小或已生效窗口大小中的更小值
  • 2 - 動態:除非上一條消息中限制類型爲應限制,則需要把該消息視爲硬限制,否則可直接忽略

5. RTMP消息格式

本章節指明通過底層傳輸層(如RTMP塊流)在網絡端點間傳輸的RTMP消息格式。

雖然RTMP設計用於RTMP塊流,但它也可使用其他傳輸協議發送消息。RTMP塊流和RTMP廣泛適用於音視頻應用,如一對一、一對多的實時廣播、點播以及交互會以應用。

5.1 RTMP消息格式

客戶端和服務器通過在網絡中發送RTMP消息來進行交互,這些消息可包含音頻、視頻、數據或其他消息。

RTMP消息分爲兩部分,分別爲頭和負載。

5.1.1 消息頭

消息頭包含如下部分:

  • 消息類型:一個字節變量,用於標識消息類型。消息類型1-6預留用於協議控制消息
  • 長度:3字節變量,用於標識負載字節數。設置爲big-endian格式
  • 時間戳:4字節變量,包含消息時間戳。以big-endian格式打包
  • 消息流ID:3字節變量,標識消息流。設置爲big-endian格式
 
 

5.1.2 消息負載

消息的另一部分,是消息的真正數據。如可爲音頻樣本或壓縮後視頻數據。負載格式和解釋不在本文檔討論範圍內。

5.2 用戶控制消息(4)

RTMP中息類型ID 4爲用戶控制消息,這些消息包含了RTMP流傳輸層使用的信息,協議消息ID爲1/2/3/5/6則用於RTMP塊流協議(Section 4.4)。

用戶控制消息應該使用消息流ID 0(又稱爲控制流),且通過RTMP塊流傳輸時使用塊流ID 2。用戶控制消息收到時立即生效,可直接忽略其時間戳。

客戶端或服務器發送該消息來通知對端用戶控制事件,該消息將攜帶事件類型和事件內容。

 
 

 

消息內容中的前兩個字節表示事件類型,事件內容緊跟其後。事件內容長度是可變的,因此,爲了讓這些消息順利通過RTMP塊流層進行傳輸,最大塊大小(Section 4.4.1)應當足夠大以使得該消息可以單塊傳輸。

事件類型和事件內容格式將在Section 6.1.7中列出。

6. RTMP命令消息

本章節討論了服務器和客戶端通過網絡進行通訊中使用的不同類型的消息和命令。

不同類型的消息被服務器和客戶端進行交換,主要有用於發送音頻數據的音頻消息,發送視頻數據的視頻消息,發送任何用戶數據的數據消息,共享對象消息,以及命令消息。共享對象消息提供了在多個客戶端和服務器間管理分佈式數據的通用方法。命令消息在客戶端和服務器間攜帶AMF編碼命令。一個客戶端或服務器可通過在流中發送命令消息向對端申請RPC(Remote Procedure Calls)。

6.1 消息類型

服務器和客戶端通過網絡發送消息進行通訊,消息類型可以使音頻消息、視頻消息、命令消息、共享對象消息、數據消息和用戶控制消息的任意一種。

6.1.1 命令消息(20, 17)

命令消息在客戶端和服務期間攜帶AMF編碼命令,這些消息中AMF0編碼已被指定類型爲20,AMF3編碼已被指定消息類型爲17。這些消息發送用於在對端執行一些操作如連接、創建流、發佈publish、播放、暫停。命令消息如onstatus, result等用於通知發送端所請求命令的狀態。一個命令消息包含命令名稱、辦理transaction ID,以及包含相關參數的命令對象。客戶端或服務器可以通過發送命令消息至對端以請求RPC。

6.1.2 數據消息(18,15)

客戶端或服務器通過該消息發送任何元數據Metadata或其他用戶數據到對端。元數據包含數據(音視頻等)細節如創建時間、時長、主題等等。這些消息中AFM0編碼的被指定類型值爲18,AMF3編碼的指定類型爲15。

6.1.3 共享對象消息(19, 16)

共享對象是一個Flash對象(一系列名字-值對),它用於多客戶端、實例間同步。預留給共享對象事件中AMF0編碼的爲類型19,AMF3編碼的爲類型16。每條消息可包含多個事件。

 
 

目前支持如下事件類型:
 
 

 

6.1.4 音頻消息(8)

客戶端或服務器通過發送該消息來發送音頻數據到對端,音頻消息對應消息類型爲8。

6.1.5 視頻消息(9)

客戶端或服務器通過發送該消息來發送視頻數據到對端,視頻消息對應消息類型爲9。

6.1.6 聚合消息(22)

聚合消息時指一條消息中包含了一系列使用Section5.1中描述格式RTMP子消息,對應消息類型爲22。

 
 

聚合消息的消息流ID覆蓋了內部子消息的消息流ID。

 

聚合消息和第一條子消息在時間戳上的區別在於用於歸一化至流時間stream timescale的偏移量offset。偏移量會被加至每條子消息的時間戳來達成歸一化,第一條子消息的時間戳應該和聚合消息時間戳是一致的,所以偏移量應當是0。

後置指針處包含了前一條消息(包括頭)的大小,主要用於支持FLV的逆向seek操作。

使用聚合消息有如下好處:

  • 塊流可在一塊中發送至少一條完整消息,這樣一來,增加塊大小並使用聚合消息就可減少需發送的塊數
  • 子消息可在內存中連續存儲,這在系統調用通過網絡發送數據時會更加高效

6.1.7 用戶控制消息事件

客戶端和服務器發送該消息來通知對端用戶控制事件。關於該消息格式可參照Section 5.2。

目前支持如下用戶控制事件類型:

 
 

 

6.2 命令類型

客戶端和服務器交換AMF編碼的命令。發送端發送一條命令消息,其中包含了命令名稱、處理ID、以及含有相關參數的命令對象。例如,連接命令消息包含了’app'參數,以告知服務器客戶端希望連接的目標程序。接收端處理這條命令並回復含有同樣處理ID的響應。回覆的字符串可能爲_result、_error或方法名。如verifyClient或contactExternalServer.

_result或_error的命令字符創代表一條響應,處理ID則表明回覆是針對哪條命令的,這在IMAP或其他協議中是完全相同的。命令字符串中的方法名錶明發送端希望運行接收端上的一個方法。

下列類對象通常用於發送各種不同的命令:

  • NetConnection 一個服務器和客戶端之間連接的高層表現對象
  • NetStream 一個音頻流、視頻流及其他相關數據傳輸同感到的表現對象,我們也會發送如播放、暫停等命令來控制數據流動

6.2.1 NetConnection命令

NetConection管理着一個客戶端程序和服務器之間的雙向連接,除此之外,它還提供了對異步遠程方法調用的支持。

下列命令可通過NetConnection進行發送:

  • connect
  • call
  • close
  • createStream

6.2.1.1 connect

客戶端發送connect命令至服務器端以請求連接至某一服務器程序實例。
該由客戶端發送至服務器的命令結構如下:

 
 

下面是connect命令中命令對象所使用到的名-值對:
 
 

audioCodecs屬性有如下標誌值:
 
 

videoCodecs屬性有如下標誌值:
 
 

videoFunction屬性有如下標誌值:
 
 

object Encoding屬性有如下標誌值:
 
 

 

由服務器發送至客戶端的命令結構如下:

 
 

命令執行期間消息流動如下:
 
 

 

  1. 客戶端發送connect命令至服務器以請求連接至服務器端程序實例
  2. 在收到連接命令後,服務器端發送協議消息'Window Acknowledgement Size'給客戶端。同時,服務器端還會連接收到connect命令中提到的應用
  3. 服務器端發送協議消息‘Set Peer Bandwidth’至客戶端
  4. 客戶端成功處理‘Set Peer Bandwidth’後發送協議消息‘Window Acknowledgement Size'給服務器端
  5. 服務器端發送另一類型爲用戶控制消息(StreamBegin)協議消息給客戶端
  6. 服務器端發送命令消息以通知客戶端連接狀態(success/fail)。該命令中含有處理ID(與1中收到相同),該消息同時還制定了部分屬性,如Flash Media Server版本(string)。除此之外,它還指定了連接響應相關的信息如level(string),code(string),description(string),objectencoding(number),等

6.2.1.2 Call

NetConnection對象的call方法用於遠程調用接收端上的程序。需要遠程調用的程序名稱通過一個參數傳遞給call命令。

發送端至接收端的命令結構如下:

 
 

響應的命令結構如下:
 
 

 

6.2.1.3 createStream

客戶端發送該命令至服務器端以創建一條邏輯通道用於傳遞消息,從而可以利用已創建的流通道發佈音頻、視頻和元數據。

NetConnection是默認的通訊通道,流ID爲0。協議和一些命令消息,包括createStream,使用默認通訊通道。

從客戶端至服務器的命令結構如下:

 
 

從服務器至客戶端的命令結構如下:
 
 

 

6.2.2 NetStream命令

NetStream定義了一條基於NetConnection的客戶端至服務器間連接的,可以傳遞音頻流、視頻流以及消息流的通道。NetConnection對象支持多個NetStreams以傳輸多個數據流。

客戶端可在NetStream中發送下列命令至服務器:

  • play
  • play2
  • deleteStream
  • closeStream
  • receiveAudio
  • receiveVideo
  • publish
  • seek
  • pause

服務器端通過“onStatus"命令發送NetStream的狀態更新至客戶端:

 
 

 

6.2.2.1 play

客戶端發送該命令值服務器端以播放一個流。多次調用該命令也可創建一個播放清單。

如果你希望創建一個在不同live或recorded流間切換的動態播放清單,需要多次調用play並傳遞false以避免每次reset。相反地,如果你希望立即播放某一指定流,傳遞true以清除等待播放嘟列中的所有其他流。

客戶端發送至服務器的命令結構如下:

 
 

命令執行期間消息流動如下:
 
 

 

  1. 客戶端在接收到來自服務器createStream成功回覆後發送play命令
  2. 收到play命令後,服務器發送一條協議消息來設置塊大小
  3. 服務器發送另一條協議消息(用戶控制)來指定事件“StreamIsRecord”和流ID。該消息在前2字節中攜帶事件類型,並在最後4字節中攜帶流ID
  4. 服務器發送另一條協議消息(用戶控制)來指定事件“StreamBegin”來告知客戶端流狀態的開始
  5. 如客戶端請求的play命令成功執行後,服務器發送一條onStatus命令消息NetStream.Play.Start和NetStream.Play.Reset。只有客戶端發送的play命令中包含reset標誌時服務器纔會回覆NetStream.Play.Reset。如未查找到客戶端請求play的流,服務器將在onStatus消息中返回NetStream.Play.StreamNotFound.

6.2.2.2 Play2

與play命令不同的是,Play可以在不改變正在播放內容的時間線情況下切換至不同比特率流。實質上是服務器端維護了所支持的所有不同比特率的文件,這些文件都可被客戶端通過play2進行請求。

從客戶端到服務器的命令結構如下:

 
 

NetStreamPlayOptions對象的公共屬性在ActionScript3 Language Reference[AS3]中有詳細描述。

 

該命令的具體消息流如下:

 
 

 

6.2.2.3 deleteStream

NetStream對象銷燬前會發出deleteStream命令。
客戶端至服務器的命令結構如下:

 
 

服務器端不會進行任何回覆。

 

6.2.2.4 receiveAudio

NetStream發送receiveAudioMessage以告知服務器是否需要發送音頻至客戶端。

由客戶端發送至服務器的命令結構如下:

 
 

當receiveAudio命令中bool標誌爲false時,服務器不會進行任何響應;如該標誌爲true,服務器會響應以狀態消息NetStream.Seek.Notify和NetStream.Play.Start

 

6.2.2.5 receiveVideo

NetStream發送receiveVideo消息來告知服務器是否需要發送視頻至客戶端。

由客戶端發送至服務器端的命令結構如下:

 
 

如receiveVideo命令中bool標誌爲false時,服務器不進行任何響應;如該標誌爲true,服務器會響應以NetStream.Seek.Notify和NetStream.Play.Start

 

6.2.2.6 publish

客戶端發送publish命令以發佈一個命名流至服務器。通過這個名字,任何客戶端可以播放該流並接收已發佈的音頻、視頻及數據消息。

從客戶端至服務器的命令結構如下:

 
 

服務器響應onStatus命令以標識發佈的開始。

 

6.2.2.7 seek

客戶端發送seek命令以在媒體文件或播放列表中查找指定偏移量(單位爲毫秒)。

從客戶端至服務器的命令結構如下:

 
 

當seek成功後,服務器響應以一條status消息NetStream.Seek.Notify。如失敗則返回一條_error消息。

 

6.2.2.8 pause

客戶端發送pause命令來告知服務器暫停或開始播放。
從客戶端至服務器的命令結構如下:

 
 

操作成功後,如流爲停止狀態,服務器響應以一條狀態消息NetStream.Pause.Notify;如流爲未停止狀態,則返回NetStream.UnPause.Notify。如操作失敗,則返回_error消息。

 

6.3 消息交換示例

下面是一些使用RTMP進行消息交換的示例。

6.3.1 發佈錄製的視頻

本示例演示了一個publisher如何發佈一個流並傳輸視頻至服務器,其他客戶端可進行訂閱至已發佈流並播放視頻。

 
 

 

6.3.2 廣播一個共享對象消息

本示例演示了一個共享對象創建和改變期間的消息交換過程,它同樣描述了共享對象消息廣播的處理過程。

 
 

 

7.3.3 發佈已錄製流中元數據

本示例描述了發佈元數據時消息交換。

 


作者:SniperPan
鏈接:https://www.jianshu.com/p/0f8354a53d5b
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章