RTP(Real-time Transport Protocol)
作用
RTP 用于傳輸實時媒體流(如音頻、視頻),它不提供可靠傳輸,而是關注低延遲、高實時性。
報文結構
整體結構
RTP 報文由以下部分組成:
RTP Header (12 字節起始) + 可選擴展頭 + Payload(負載部分)+ 可選 Padding
如果啟用了擴展或 CSRC,則頭部長度會超過 12 字節。
RTP Header
Bit位 | 名稱 | 說明 |
---|---|---|
0-1 | V (Version) | RTP 版本號,占2位,當前為2 |
2 | P (Padding) | 是否有填充位,最后一個字節表明填充長度 |
3 | X (Extension) | 是否有擴展頭 |
4-7 | CC (CSRC Count) | CSRC 的數量(最多15個),每個4字節 |
8 | M (Marker) | 標志位,具體含義由應用定義(如幀結束標志) |
9-15 | PT (Payload Type) | 有效負載類型,7位,如 96 表示動態類型 |
16-31 | Sequence Number | 序列號,每發一個 RTP 包加1,接收方可用于重排和丟包檢測 |
32-63 | Timestamp | 時間戳,標識采樣時刻,用于同步和延時計算 |
64-95 | SSRC | 同步源標識符,用于區分不同源(一個媒體流) |
96-… | CSRC List | 0~15個,標識貢獻源 |
圖示(前12字節):
0 1 2 30 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+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|V=2|P|X| CC |M| PT | sequence number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| timestamp |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| synchronization source (SSRC) identifier |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| contributing source (CSRC) identifiers (可選, 每個4字節) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段說明:
字段 | 說明 |
---|---|
V(Version) | 當前為 2,必須正確解析 |
P(Padding) | 若為 1,表明數據末尾有填充,用于加密對齊 |
X(Extension) | 若為 1,RTP header 后跟擴展頭 |
CC(CSRC Count) | 表示后續跟隨幾個 CSRC,每個 4 字節 |
M(Marker) | 由應用定義,如視頻幀結束、音頻邊界等 |
PT(Payload Type) | 表示負載的類型,動態類型在 96~127 |
Sequence Number | 每發一個 RTP 包 +1,接收方可檢測丟包、重排 |
Timestamp | 用于同步,單位依賴編碼格式(如 AAC 是 90kHz) |
SSRC | 同步源的唯一 ID,通常為隨機值 |
CSRC | 多個貢獻者源(如會議中多個語音參與者) |
RTP Payload(負載部分)
- 這是實際承載音頻/視頻數據的部分,格式由 Payload Type 指定(如 H.264、AAC 等)。
- RTP 僅負責傳輸,不解析負載內容。
- 不同的編碼格式有不同的 RTP 負載封裝規則(如 H.264 的 FU-A、STAP-A 等)。
靜態 Payload Type(0~95)
編號 | 編碼格式 | 采樣率 | 備注 |
---|---|---|---|
0 | PCMU (G.711 μ-law) | 8000 Hz | 音頻 |
8 | PCMA (G.711 A-law) | 8000 Hz | 音頻 |
3 | GSM | 8000 Hz | 音頻 |
10 | L16 | 44100 Hz | 立體聲音頻 |
26 | JPEG | - | 視頻 |
31 | H.261 | - | 視頻 |
32 | MPEG Audio | - | 音頻 |
33 | MPEG Video | - | 視頻 |
動態 Payload Type(96~127)
動態類型必須在 SDP (Session Description Protocol) 或信令(如 SIP INVITE)中協商說明。常見映射:
PT值 | 編碼格式 | 描述 |
---|---|---|
96+ | H.264 | RFC 6184 定義 |
97 | H.265 | RFC 7798 定義 |
98 | AAC | RFC 3640 定義 |
99 | OPUS | 音頻,動態 |
100 | VP8 | Google 實現 |
101 | VP9 | Google 實現 |
可選擴展頭(Extension Header)
如果 X=1,表示存在擴展頭。格式如下:
0 1 2 30 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+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| defined by profile | length |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| extension data... |
-
“defined by profile”:擴展頭類型(如 WebRTC 擴展)
-
“length”:以 32 位字(4 字節)為單位的擴展長度,不含自身頭部。
-
后續緊跟擴展數據內容
工作流程
發送端:
- 將音視頻編碼成幀
- 每幀按照 RTP 規則進行分片(如 H.264 的 FU-A)
- 打包 RTP Header + Payload,發送到目標地址(UDP)
- 控制信息通過 RTCP 發送,如丟包率、RTT、抖動等
接收端:
- 接收 RTP 報文并解析頭部
- 按 SSRC 區分媒體流
- 按序列號排序、重組
- 利用時間戳做同步(音視頻同步)
- 解碼播放
RTP Header解析流程(c++)
解析函數
#include <iostream>
#include <cstdint>
#include <cstring>
#include <arpa/inet.h> // ntohs, ntohl#pragma pack(push, 1)
struct RtpHeader {uint8_t vpxcc; // Version(2) | Padding(1) | Extension(1) | CC(4)uint8_t mpt; // Marker(1) | PayloadType(7)uint16_t seq; // Sequence Numberuint32_t timestamp; // Timestampuint32_t ssrc; // SSRC
};
#pragma pack(pop)#pragma pack(push, 1)
struct RtpExtensionHeader {uint16_t profile_defined; // Profile-specific IDuint16_t length; // 以 32bit 為單位的長度
};
#pragma pack(pop)// 解析 RTP 頭部
bool parseRtpHeader(const uint8_t* data, size_t len, RtpHeader& header) {if (len < sizeof(RtpHeader)) return false;std::memcpy(&header, data, sizeof(RtpHeader));// 網絡字節序轉主機字節序header.seq = ntohs(header.seq);header.timestamp = ntohl(header.timestamp);header.ssrc = ntohl(header.ssrc);return true;
}// 解析擴展頭,返回擴展負載指針及長度
bool parseRtpExtension(const uint8_t* data, size_t len,uint8_t cc, bool extension,const uint8_t** ext_payload, size_t* ext_len) {if (!extension) return false;size_t header_offset = 12 + cc * 4; // 基礎頭 + CSRC 區if (len < header_offset + sizeof(RtpExtensionHeader)) return false;RtpExtensionHeader ext_hdr;std::memcpy(&ext_hdr, data + header_offset, sizeof(RtpExtensionHeader));ext_hdr.profile_defined = ntohs(ext_hdr.profile_defined);ext_hdr.length = ntohs(ext_hdr.length);size_t ext_payload_len = ext_hdr.length * 4;if (len < header_offset + sizeof(RtpExtensionHeader) + ext_payload_len) return false;*ext_payload = data + header_offset + sizeof(RtpExtensionHeader);*ext_len = ext_payload_len;std::cout << "RTP Extension Header:" << std::endl;std::cout << " Profile-defined ID: 0x" << std::hex << ext_hdr.profile_defined << std::dec << std::endl;std::cout << " Extension length (32-bit words): " << ext_hdr.length << std::endl;std::cout << " Extension payload size: " << ext_payload_len << " bytes" << std::endl;return true;
}// 打印 RTP 頭信息
void printRtpHeader(const RtpHeader& h) {uint8_t version = (h.vpxcc >> 6) & 0x03;uint8_t padding = (h.vpxcc >> 5) & 0x01;uint8_t extension = (h.vpxcc >> 4) & 0x01;uint8_t csrcCount = h.vpxcc & 0x0F;uint8_t marker = (h.mpt >> 7) & 0x01;uint8_t payloadType = h.mpt & 0x7F;std::cout << "RTP Header:" << std::endl;std::cout << " Version: " << (int)version << std::endl;std::cout << " Padding: " << (int)padding << std::endl;std::cout << " Extension: " << (int)extension << std::endl;std::cout << " CSRC Count: " << (int)csrcCount << std::endl;std::cout << " Marker: " << (int)marker << std::endl;std::cout << " Payload Type: " << (int)payloadType << std::endl;std::cout << " Sequence Number: " << h.seq << std::endl;std::cout << " Timestamp: " << h.timestamp << std::endl;std::cout << " SSRC: " << h.ssrc << std::endl;
}void handleRtpPacket(const uint8_t* data, size_t len) {if (len < 12) {std::cerr << "Packet too short for RTP" << std::endl;return;}RtpHeader header;if (!parseRtpHeader(data, len, header)) {std::cerr << "Failed to parse RTP header" << std::endl;return;}printRtpHeader(header);uint8_t cc = header.vpxcc & 0x0F;bool extension = (header.vpxcc >> 4) & 0x01;const uint8_t* ext_payload = nullptr;size_t ext_len = 0;if (parseRtpExtension(data, len, cc, extension, &ext_payload, &ext_len)) {std::cout << " Extension Payload (hex, first up to 16 bytes): ";for (size_t i = 0; i < std::min(ext_len, size_t(16)); ++i) {printf("%02X ", ext_payload[i]);}std::cout << std::endl;} else if (extension) {std::cerr << "Invalid RTP extension header or length" << std::endl;return;}size_t payload_offset = 12 + cc * 4 + (extension ? 4 + ext_len : 0);if (payload_offset > len) {std::cerr << "Payload offset exceeds packet length" << std::endl;return;}size_t payload_len = len - payload_offset;const uint8_t* payload = data + payload_offset;std::cout << "RTP Payload size: " << payload_len << " bytes" << std::endl;// 這里你可以繼續解析 payload 內容,例如 H264 NALU、音頻幀等
}int main() {// 構造一個測試 RTP 包(含擴展頭)uint8_t rtpPacket[] = {0x90, 0x60, 0x12, 0x34, // V=2,P=0,X=1,CC=0 | M=0,PT=96 | Seq=0x12340x00, 0x00, 0x00, 0x01, // Timestamp = 10x12, 0x34, 0x56, 0x78, // SSRC = 0x12345678// Extension header: profile=0x1000, length=1 (4 bytes extension)0x10, 0x00, 0x00, 0x01,// Extension payload (4 bytes)0xAA, 0xBB, 0xCC, 0xDD,// RTP payload (示例4字節)0x01, 0x02, 0x03, 0x04};size_t packet_len = sizeof(rtpPacket);handleRtpPacket(rtpPacket, packet_len);return 0;
}
運行結果
RTP Header:Version: 2Padding: 0Extension: 1CSRC Count: 0Marker: 0Payload Type: 96Sequence Number: 4660Timestamp: 1SSRC: 305419896
RTP Extension Header:Profile-defined ID: 0x1000Extension length (32-bit words): 1Extension payload size: 4 bytesExtension Payload (hex, first up to 16 bytes): AA BB CC DD
RTP Payload size: 4 bytes
SRTP(Secure RTP)
作用
項目 | 說明 |
---|---|
全稱 | Secure Real-time Transport Protocol |
定義 | 為 RTP 提供 加密(confidentiality)、完整性(integrity) 和 重放保護(replay protection) 的協議 |
標準 | RFC 3711 |
傳輸對象 | RTP 和 RTCP 報文 |
應用場景 | WebRTC、SIP 電話、視頻會議、安全監控、國標 GB28181(國密版本)等 |
-
設計目標
-
加密 RTP Payload,保護媒體內容
-
校驗報文完整性(Message Authentication)
-
防止重放攻擊(Replay Protection)
-
不增加過多開銷(適配實時場景)
-
-
特點
-
輕量級、低延遲(適用于 VoIP/實時視頻)
-
只加密有效載荷(Payload),頭部可解析
-
不改變 RTP 報文格式(兼容性好)
-
報文結構
SRTP 報文 = RTP 報文 + 加密/認證后的擴展字段
+-----------------------------+
| RTP Header (未加密) |
+-----------------------------+
| RTP Payload (加密) |
+-----------------------------+
| RTP padding (可選, 加密) |
+-----------------------------+
| Authentication Tag (可選) |
+-----------------------------+
RTP Header(12 字節及可選擴展)
未加密。用于 HMAC 認證計算。
RTP Payload(加密)
- SRTP 對 負載部分(即 RTP header 后面的媒體數據)進行 AES 加密,有兩種方式:
- AES Counter Mode(AES-CTR):只加密,不使用 MAC(快速)
- AES f8 模式(已不常用)
- AES-CM with HMAC-SHA1(推薦方式):加密 + 完整性保護
RTP Padding(可選)
如果 RTP 報文設置了 Padding 位,那么最后會有若干字節的填充用于對齊。SRTP 也會對填充部分進行加密。
Authentication Tag(鑒權標簽)
- 是 HMAC-SHA1 計算的一個 MAC(Message Authentication Code)
- 默認長度為 10 字節(可配置為 4~10 字節)
- 用于確保 RTP 報文未被篡改
- 計算時覆蓋:
- RTP Header + Payload(加密后) + 累加器(包括 SSRC 和 Sequence Number)
核心算法與參數
類型 | 說明 |
---|---|
加密算法 | AES-CTR 或 AES-f8 |
認證算法 | HMAC-SHA1(默認) |
MAC 長度 | 默認 80bit(10字節),也可選 32bit(4字節) |
密鑰派生 | 使用 主密鑰 + Master Salt 派生出多種密鑰(加密、認證、RTCP密鑰) |
密鑰派生機制
使用主密鑰(Master Key)和主鹽值(Master Salt)派生以下密鑰:
- RTP 加密密鑰
- RTP 認證密鑰
- RTP 會話鹽值
- RTCP 加密密鑰
- RTCP 認證密鑰
- RTCP 會話鹽值
每個密鑰長度根據加密算法而定,典型 AES-128 對應 128-bit。
Replay Protection(重放保護)
- 基于 RTP Sequence Number + ROC(rollover counter) 實現
- 接收端保存窗口(例如 64 個序列號)檢測重復報文
- 每當序列號溢出,ROC +1
RTCP 的安全擴展(SRTCP)
RTCP 也有對應的安全擴展,結構如下:
SRTCP = RTCP 原始報文 + 加密字段 + SRTCP Index + Auth Tag
- 支持選擇性加密
- 使用 Auth Tag 來保證完整性
- SRTCP Index 替代 RTP 的 ROC
SRTP 密鑰協商方式
SRTP 不定義密鑰協商方式,但常見有:
1. SDES(Session Description Protocol Security Descriptions)
-
將密鑰寫入 SDP 協議中
-
示例:
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:MTIzNDU2Nzg5MDEyMzQ1Ng==
-
優點:簡單,易實現
-
缺點:明文傳輸,安全性差,已不推薦使用
2. DTLS-SRTP(Datagram TLS)
- 使用 DTLS 握手協商密鑰(如 WebRTC)
- 端到端加密認證,符合現代安全要求
- WebRTC 和新版 SIP(使用 ICE+DTLS)都采用它
3. MIKEY(Multimedia Internet KEYing)
- 早期設計用于 SRTP,現較少使用
WebRTC中RTP/SRTP工作流程
整體流程
[Media Capture] → [Encoder] → [RTP Packetization] → [SRTP 加密] → [網絡傳輸]↓[網絡接收] ← [SRTP 解密] ← [RTP 解析] ← [Decoder] ← [Render]
工作流程:
+-------------+ +-----------+Media Input | Encoder | RTP | RTP Stack |(Camera/Mic)+----+--------+ ---> +-----------+| | RTP Packetizationv | SRTP 加密(libsrtp)+------+--------+ || DTLS Handshake | <---++------+--------+|vSRTP Key Derivation
核心模塊
模塊 | 作用 |
---|---|
RTP/RTCP | 傳輸媒體幀和反饋信息(如丟包、帶寬) |
SRTP | RTP 加密傳輸(使用 AES/HMAC) |
DTLS | 用于協商 SRTP 密鑰(DTLS-SRTP) |
ICE/STUN/TURN | 建立點對點連接、穿透 NAT |
SCTP/DTLS | 傳輸數據通道(非音視頻) |
處理流程(發送端)
1. 媒體采集與編碼
- 攝像頭/麥克風采集音視頻
- 使用 VP8/VP9/H264 等視頻編碼器,Opus/G.711 等音頻編碼器編碼為壓縮幀
2. RTP 封裝
- 編碼幀被分片打包為 RTP 包
- 每個 RTP 包頭包括:
- SSRC(同步源)
- Sequence Number(順序)
- Timestamp(采樣時間)
- Payload Type(編碼類型)
3. SRTP 加密
- RTP Payload(負載)被加密
- 附加 HMAC 鑒權標簽
- 使用密鑰來自 DTLS 握手派生的 SRTP 密鑰
4. 通過 UDP 網絡發送(可能走 STUN/TURN 服務器)
SRTP 加密流程(WebRTC 默認)
密鑰協商流程(DTLS-SRTP)
- 在 SDP 協商階段使用
a=setup
,a=fingerprint
等字段建立 DTLS 連接 - 建立 DTLS 通道后雙方使用
Exporter
從 DTLS 會話中導出密鑰(RFC 5705) - 導出的密鑰用于 SRTP 加密解密(分別用于加密/認證)
SRTP 加密細節
項目 | 內容 |
---|---|
加密算法 | AES-CTR (默認),也可用 AES-GCM |
完整性保護 | HMAC-SHA1(默認10字節) |
支持重放保護 | 是(基于序列號窗口) |
SRTP 不加密字段 | RTP Header(但用于 HMAC) |
處理流程(接收端)
- 從網絡接收 RTP 報文(可能經過 TURN relay)
- 使用協商好的 SRTP 密鑰進行解密 + 驗簽
- 解析 RTP Header(獲取序列號、時間戳等)
- RTP 組幀(重排序、丟包重傳等)
- 解碼器處理后播放音視頻
RTCP 輔助流程(反饋通道)
WebRTC 使用 RTCP 提供控制反饋:
RTCP 類型 | 用途 |
---|---|
SR (Sender Report) | 提供 RTP 發送統計,用于同步 |
RR (Receiver Report) | 丟包率、抖動、延遲等統計 |
PLI (Picture Loss Indication) | 請求關鍵幀(視頻重傳) |
FIR (Full Intra Request) | 強制全幀編碼 |
NACK | 指定丟失的 RTP 序號,建議重傳 |
RTCP 包通常也通過 SRTCP 進行加密和認證。
傳輸通道建立流程
SDP Offer/Answer → ICE 候選收集 → DTLS 握手 → SRTP 密鑰協商 → 開始傳輸 RTP/SRTP
各協議協同如下:
協議 | 功能 |
---|---|
SDP | 協商能力、媒體參數、加密 fingerprint |
ICE | NAT 穿透、連接檢測 |
STUN/TURN | 發現公網地址 / 中繼 |
DTLS | 端到端加密協商 |
SRTP | 媒體數據加密傳輸 |
RTP | 媒體傳輸 |
RTCP | 控制反饋與統計 |