一:瀏覽器協議棧
左側為http協議的協議棧,右側為WebRTC協議棧
(一)http協議棧
API層:提供了XHR、SSE、WebSocket
應用層:提供了http1.x/2.0https協議
會話層:使用了TLS協議(可選),對於https需要這個協議,對於http並不需要
傳輸層:底層使用TCP傳輸,流傳輸
網絡層:IP協議
(二)WebRTC協議棧
API層:提供了RTCPeerConnection和DataChannel
應用層:對於PeerConnection使用了SRTP協議,對於DataChannel使用了SCTP協議(流控傳輸協議)
會話層:使用了DTLS協議(仿照TLS),對於SRTP可選,對於SCTP為必須
鏈路檢測層:ICE/STUN/TURN檢測端到端之間的通路,進行連通性檢測
傳輸層:底層使用UDP傳輸,報文傳輸
網絡層:IP協議
二:WebRTC傳輸協議分析
1.RTP/SRTP:區別在於傳輸內容是否加密,同樣對於RTCP/SRTCP一樣。
2.RTP/RTCP:RTP協議定義流媒體數據在互聯網上傳輸的數據包格式,而RTCP協議則負責可靠傳輸、流量控制和擁塞控制等服務質量保證。
3.DTLS:在對SRTP/SRTCP數據進行加密之前,需要對證書進行檢測,算法協商,通過DTLS實現。
(一)RTP協議
在FFmpeg學習(六)H264流媒體協議解析中提及過
前12字節固定 + (0~15)個32位的CSRC標識符
V (2bits): RTP協議的版本號,當前協議版本號為2。 P (1bit): 填充標志,如果設置填充位P=1,在包尾將包含附加填充字節,它不屬於有效載荷。填充的最后一個八進制包含應該忽略的八進制計數。某些加密算法需要固定大小的填充字節,或為在底層協議數據單元中攜帶幾個RTP包。 X (1bit): 擴展標志,如果X=1,則在RTP報頭后跟有一個擴展報頭 CC(4bits): CSRC計數器,指示CSRC 標識符的個數。 M (1bit): 標記位(不同載荷含義不同,視頻標記一幀的最后一個分片slice則=1,其他=0)標識幀邊界 PT (7bits): 載荷類型RTP_PAYLOAD_RTSP,記錄后面資料使用哪種 Codec , receiver 端找出相應的 decoder 解碼出來。例如H264=96---用於區分不同的編解碼器 序列號(16bits): 用於標識發送者所發送的 RTP 報文的序列號(初始值隨機),每發送一個報文,序號增加 1
時間戳(32bits): 時間戳反映了該 RTP 報文的第一個八位組的采樣時刻。 接受者使用時間戳來計算延遲和抖動, 並進行同步控制。如果幀分包后,如何組合?通過時間戳和序列號判斷,同一個幀的timestamp相同,並且序列號連續。還可以通過M標記位
SSRC(32bits): 區分是在和誰通信。值隨機選擇,參加同一視頻會議的兩個同步信源的SSRC要相同。音視頻源各有自己的ssrc,如果已經存在一個SSRC,則后面產生的不允許重復,后面的需要重新更改SSRC
貢獻源(CSRC)標識符(32bits):每個CSRC標識符占32位,可以有0~15個。每個CSRC標識了包含在該RTP報文有效載荷中的所有特約信源。
應用場景:多路混音、混流時使用,多人通信時,將音頻進行混音后,其貢獻者有多人,每一個的ssrc都放入一個CSRC當中去
注意:P填充標志,為1表示后面有填充字節,那么具體填充了多少字節呢?由填充的字節數中的最后一個字節來計算,比如最后一個字節數為5,則填充了5個字節(包含了最后一個字節本身)!!
RTP 協議實際上是由實時傳輸協議RTP(Real-time Transport Protocol)和實時傳輸控制協議RTCP(Real-time Transport Control Protocol)兩部分組成。
RTP 協議基於多播或單播網絡為用戶提供連續媒體數據的實時傳輸服務; RTCP 協議是 RTP 協議的控制部分,用於實時監控數據傳輸質量,為系統提供擁塞控制和流控制。
(二)RTCP協議:https://winddoing.github.io/post/32277.html
1.RTCP包格式如下(與RTP格式一致):
一般情況下:RTP端口為偶數
RTCP也是用UDP來傳送的,但RTCP封裝的僅僅是一些控制信息,因而分組很短,所以可以將多個RTCP分組封裝在一個UDP包中。類似於RTP信息包,每個RTCP信息包以固定部分開始,緊接着的是可變長結構單元,最后以一個32位邊界結束。
注意:在WebRTC中,需要進行NAT穿越。為了簡便,一般使用單個端口,所以一般情況下RTP與RTCP會復用同一個端口
2.RTCP負載類型:根據所攜帶的控制信息不同RTCP信息包可分為RR(接收者報告包)、SR(源報告包)、SEDS(源描述包)、BYE(離開申明)和APP(特殊應用包)五類:
1、SR:發送端報告包,用於發送和接收活動源的統計信息;本身即是發送者也是接收者,在發送數據的時候發送接收到的報文報告給對端,一個報文兼顧了兩個功能
2、RR:接收者報告包,用於接收非活動站的統計信息;
3、SDES:源描述包,用於報告和站點相關的信息,包括CNAME(可識別),同一個CNAME可以對應多個SSRC,因為SSRC可能產生沖突,SSRC會更改,但是CNAME不會修改;
4、BYE:斷開RTCP包,是站點離開系統的報告,表示結束;關閉隊員路徑,不再發送RTP數據
5、APP:應用特定函數。
除了以上5種之外,在WebRTC中還經常使用其他類型,比如FIR關鍵幀請求、NACK丟包重傳處理...見:https://blog.csdn.net/wanglf1986/article/details/52674378
1.FIR:請求一個完整的I幀,防止花屏
2.NACK:丟包重傳(廢棄)
3.RTPFB:RTP反饋包(傳輸層對RTP數據控制、payload內容編解碼器、應用層3種反饋包),這里是傳輸層反饋包
4.PSFB:編解碼器反饋包
3.RTCP Header
字段說明:
P:填充字節,同RTP的P填充標識字段!
RC:Receiver Report Block的個數,當負載類型為SDES時,可以為0
PT:負載類型
length:包長度,由於存放時為N-1,所以我們讀取以后使用N+1變為真實長度進行計算
SSRC of sender:接收者收到之后,知道是誰發送過來的
4.SR類型 RTCP Sender Report:包含以下兩部分:發送者自己的信息塊以及接收者信息塊(前提是自己既是發送者,又是接收者)
Sender Information block:記錄了發送者發送了多少報文,多少字節
NTP timestamp, most significant word:64位時間戳的前32位高字節 NTP timestamp, least significant word:64位時間戳的后32位低字節,NTP用於不同源之間的同步,比如音視頻同步。 RTP timestamp:RTP數據包的相對時間戳 sender's packet count:發送者發送包數,當SSRC發生變化時會被重置 sender's octet count:發送者發送的字節數,接受方會進行對比,檢查是否數據丟失
Receiver Report block: (多個)因為作為多方通訊的一方來說,很可能接受到好幾路音視頻流(最少一個音頻、一個視頻,音視頻不共用),對於每一個SSRC都會收到一個Report Block
其中jitter字段可以用於檢測網絡擁塞!
Sender Information block與Receiver Report block在RTCP協議中的表現:
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header |V=2|P| RC | PT=SR=200 | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of sender | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ sender | NTP timestamp, most significant word | info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NTP timestamp, least significant word | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RTP timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sender's packet count | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sender's octet count | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ report | SSRC_1 (SSRC of first source) | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 | fraction lost | cumulative number of packets lost | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ report | SSRC_2 (SSRC of second source) | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 : ... : +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | profile-specific extensions | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5.RR類型 RTCP Receiver Report:只包含Receiver Report block這一個部分
Receiver Report block在RTCP協議中的表現:
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header |V=2|P| RC | PT=RR=201 | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of packet sender | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ report | SSRC_1 (SSRC of first source) | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 | fraction lost | cumulative number of packets lost | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ report | SSRC_2 (SSRC of second source) | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 : ... : +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | profile-specific extensions | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6.RTCP SR/RR發送時機:SR/RR都是為了上報數據
7.RTCP SDES:包含頭部(與前面類似)與內容,詳見:https://blog.csdn.net/wanglf1986/article/details/52674378
SDES源描述包提供了直觀的文本信息來描述會話的參加者,包括CNAME、NAME、EMAIL、PHONE、LOC等源描述項,這些為接收方獲取發送方的有關信息提供了方便。
SDES 包由包頭與數據塊組成,數據塊可以沒有,也可有多個。包頭由版本(V)、填充(P)、長度指示、包類型(PT)和源計數(SC)組成。
PT占8位,用於識別RTCP的SDES包,SC占5位,指示包含在SDES包中的SSRC/CSRC塊數量,零值有效,但沒有意義。
數據塊由源描述項組成,Item使用TLV(type,length,value)存放數據,源描述項的內容如下:
SDES item結構:下面用CNAME舉例
CNAME: 規范終端標識SDES項,在RTP會話中唯一。
類似SSRC標識,RTCP為RTP連接中每一個參加者賦予唯一一個CNAME標識。在發生沖突或重啟程序時,由於隨機分配的SSRC標識可能發生變化,CNAME項可以提供從SSRC標識到仍為常量的源標識的綁定。為方便第三方監控,CNAME應適合程序或人員定位源。
length:長度字段,大小可變,因為后面value存儲大小可變
user and domain name:可變長度,詳見:https://blog.csdn.net/wanglf1986/article/details/52674378
8.RTCP BYE:包含頭部(與前面類似)與內容,詳見:https://blog.csdn.net/wanglf1986/article/details/52674378
其中SC代表SSRC的個數,表示都有哪些源停止發送數據了,對於每個客戶端一般會有兩個:音頻和視頻,還有其他...
如混合器接收到一個BYE包,混合器轉發BYE包,而不改變SSRC/CSRC 標識。
如混合器關閉,在關閉之前它應該發出一個BYE包,列出混合器處理的所有源(省略號中表示),而不只是自己的SSRC標識。
作為可選項,BYE包可包括一個8位八進制計數,后跟文本信息,表示離開原因,如:"cameramalfunction"或"RTPloop detected"。
字符串的編碼與在SDES 項中所描述的相同。
如字符串信息至BYE包下32位邊界結束處,字符串就不以空結尾;否則,BYE包以空八進制填充。
9.RTCP APP
APP包用於開發新應用和新特征的實驗,不要求注冊包類型值。帶有不可識別名稱的APP包應被忽略掉。測試后,如確定應用廣泛,推薦重新定義每個APP包,而不用向IANA注冊子類型和名稱段。
10.FB反饋包:RTPFB:傳輸層反饋包,PSFB:payload-specific具體編解碼類型反饋包
其中RTCP FB Header如下:
SSRC of packet sender:發送這個包的發送者的ssrc
SSRC of media source:發送的FB是針對哪個媒體源的(一般和上面是一致的)
Feedback Control Information:一些控制信息
其中傳輸層的RTPFB分為以下3類:
NACK:丟包重傳
TMMBR/TMMBN: 最大媒體流比特率請求TMMBR,通過TMMBN響應最大帶寬
其中負載層的PsPFB分為以下6類:
PLI:圖片丟失標識,有一幀圖片丟失
SLI:在H264中,一幀圖像會分片為多個slice,每個slice會分成一個包,如果slice丟失,則發送標識
PRSI:參考幀丟失標識,參考幀P、I都可以作為參考幀
FIR:請求一個完整的IDR幀
TSTR/TSTN:時間空間交換請求
補充:TLS協議(結合OpenSSL),基於TCP
1.OpenSSL==SSL==TLS
OpenSSL:開源的SSL
SSL:在原來的網絡套接字的基礎上,加上了安全機制,比如對稱加密、非對稱加密加在原來的socket之上,就變成了OpenSSL
TLS:在SSL3.0之后,標准化為TLS(重命名)
2.TLS協議(兩大塊)
TLS握手協議:交換證書以及其他加密信息
TLS記錄協議:使用握手協議中獲取的信息進行加密解密
3.OpenSSL原理
SSL_CTX:上下文,存放版本、證書、密鑰...
SSL:SSL連接實例,與socket對應,基於socket傳輸
SSL_Write/SSL_Read:從socket中寫入、讀取 數據
4.OpenSSL的使用
(三)DTLS協議:基於UDP的TLS
https://blog.51cto.com/u_15087084/2598254
https://blog.csdn.net/alwaysrun/article/details/89076492
DTLS協議在UDP提供的socket之上實現了客戶機與服務器雙方的握手連接,並且在握手過程中通過使用PSK或ECC實現了加密,並且利用cookie驗證機制和證書實現了通信雙方的身份認證,並且用在報文段頭部加上序號,緩存亂序到達的報文段和重傳機制實現了可靠傳送。
握手過程如上圖所示,大體來說分成三個過程:明文通信過程、非對成加密通信過程、對稱加密通信過程;
-
明文通信過程:在通信兩端首次向對方發送 Hello 消息時,由於雙方都沒有協商好要使用哪種加密方式,因此這個過程中的消息都是使用明文進行發送的。
a. Client Hello:客戶端首先向服務端發起握手,在握手消息中告訴對方自己支持的 SSL/TLS 版本、加密套件(包括非對稱加密時使用的算法與、非對稱加密時使用的算法、產生密鑰的偽隨機函數 PRF)與數據壓縮算法(TLS1.3之后就已經沒有這個字段)等;還會攜帶一個 Session ID,因為握手流程的開銷比較大,使用 Session ID 可以在下一次與 TLS 握手的過程跳過后續繁瑣的握手流程,重用之前的握手結果(如版本號、加密算法套件、master-key 等);並產生一個隨機數 A,也告訴給對方;
b. Server Hello:服務端響應一個 Server Hello 消息,攜帶協商出來的 TLS/SSL 版本號、加密套件和數據壓縮算法,如果服務端同意客戶端重用上次的會話,就返回一個相同的 Session ID,否則就填入一個全新的 Session ID;
c. Server Certificate(可選):攜帶服務端數字證書(CA)以驗證服務端身份,里面攜帶了服務端非對稱加密所使用的公鑰;這步雖然是可選的,但是一般來說客戶端都會要求驗證服務端的身份,在大多數情況下這步都會執行;
d. Server Key Exchange(可選):在使用某些非對稱加密算法(例如 DH 算法)的情況下,Server Certificate 里的信息是不足夠的,或者 Server Certificate 在某些通信過程中直接被省略了(沒有驗證服務端身份),需要 Server Key Exchange 里的額外信息來幫助客戶端生成 pre-master key;
e. Client Sertificate Request(可選):在有些安全性要求高的場景,例如銀行支付等,不僅需要驗證服務端的身份,還需要驗證客戶端的身份,這時候服務端就會要求客戶端提供客戶端的身份證書;
f. Server Hello Done:表明 Server Hello 結束;
g. Client Certificate(可選):如果服務端要求客戶端提供數字證書以驗證身份,則客戶端發送自己的身份證書給服務端;
-
非對稱加密通信過程:由於非對稱加密通信的性能較差,在實際的通信過程中其實使用的是對稱加密通信,為了保證對稱加密通信過程的安全性,也就是需要避免對稱加密密鑰被竊取,這個密鑰在協商過程中使用非對稱加密來進行加密。
a. Client Key Exchange:客戶端在驗證服務端的身份證書后,會取出其中的服務端公鑰,產生一個隨機數 C,作為 pre-master key,在本地使用之前的隨機數 A、B 和這次生成的 C 共同生成對稱加密密鑰 master-key;使用服務端公鑰對 pre-master key 加密后發送給服務端;
b. Certificate Verify(可選):如果服務端要求客戶端提供客戶端證書,那么客戶端在發送 Client Key Exchange 之后必須馬上發送 Certificate Verify,其中的內容是客戶端使用自己的私鑰加密的一段數據,提供給服務端用客戶端的公鑰來進行解密驗證。之所以需要這一步是為了確保客戶端發送的證書確實是它自己的證書;
c. Client Change Cipher Spec:提示服務端隨后使用 master key 來進行對稱加密通信;
d. Client Handshake Finished: 表明客戶端側 SSL/TLS 握手結束;
e. Server Change Cipher Spec:提示客戶端隨后使用 master key 來進行對稱加密通信;
f. Server Handshake Finished:表明服務端側 SSL/TLS 握手結束;
-
對稱加密通信過程:通過上述握手過程協商出對稱加密算法及使用的對稱加密密鑰之后,隨后的通信過程,也就是實際的應用通信過程,都使用的是對稱加密。
補充:常見加密算法
DTLS時序圖:
1.SDP交換,媒體協商。SDP內容十分重要,交換了ICE需要的Username,Password,以及后面的DTLS需要的證書的驗證指紋,用來驗證證書是否被中間人替換。部分SDP內容如下:
a=fingerprint也就是指紋,那指紋是用來干什么的呢?
指紋就是用來我們進行數據加密的時候,來驗證這個證書的。那它首先通過信令層將SDP中的證書的指紋下發給對方,那么下次對數據加密前的它進行一下數據證書的交換,交換證書是通過DPLS進行,那么通過DPLS進行證書交換的時候,通過這個指紋去驗證你這個證書的有效性,那如果這個證書驗證是有效性的,然后后面你才能進行數據加密然后進行傳輸。如果通過指紋這個證書不匹配,那說明你這個連接也是有問題的。那這個時候就不能進行傳輸。通過以上這個種種方式呢,在打通的時候進行一次驗證,在傳數據的時候在交換證書的時候也要進行驗證,那么通過這個層層的安全的驗證,才能保證整個webRTC傳輸的安全性。以上就是安全性相關的一些描述。當然最后進行算法加密的時候你可以使用這個a=crypto指定的加密算法,也可以通過DPLS交換的證書里的指定的加密算法進行加密。
2.STUN/TURN服務,獲取Candidate(TURN服務需要username與password),驗證連通性,獲取Candidate對
3.DTLS握手
4.傳輸加密后的數據
(四)SRTP:基於DTLS獲取了對稱加密所需要的密鑰和對應的加密算法,使用在SRTP中,以此來對RTP數據進行加密保證安全和完整性
頭部與普通RTP頭一樣,頭部不進行加密,只有數據進行加密(黃色部分),最后的部分:
SRTP MKI:主鍵標識符(可選),webrtc不使用,為0
Authentication Tag:完整性驗證,RTP頭與加密數據進行做一次hash函數運算,得到摘要。對端通過同樣方式進行驗證,用來保證完整性
(五)libsrtp:開源庫,可以解決大數據吞吐
創建Session:是在DTLS握手之后,獲取了雙方信息,比如協商后的加密算法、密鑰...,之后可以進行加解密。
另外,session包含兩個,分別對於輸出流和輸入流,不能共用。
三:協議數據捕獲---wireshark
(一)UDP轉RTP
見:http://www.360doc.com/content/18/0904/11/8335678_783756276.shtml
(二)RTP查看
可以看出,上面RTP數據序號連續,時間戳相同,是來自同一個幀的連續分包
(三)RTCP查看