当前位置: 首页 > news >正文

WebRTC(十):RTP和SRTP

RTP(Real-time Transport Protocol)

作用

RTP 用于传输实时媒体流(如音频、视频),它不提供可靠传输,而是关注低延迟、高实时性。

报文结构

整体结构

RTP 报文由以下部分组成:

RTP Header (12 字节起始) + 可选扩展头 + Payload(负载部分)+ 可选 Padding

如果启用了扩展或 CSRC,则头部长度会超过 12 字节。

RTP Header

Bit位名称说明
0-1V (Version)RTP 版本号,占2位,当前为2
2P (Padding)是否有填充位,最后一个字节表明填充长度
3X (Extension)是否有扩展头
4-7CC (CSRC Count)CSRC 的数量(最多15个),每个4字节
8M (Marker)标志位,具体含义由应用定义(如帧结束标志)
9-15PT (Payload Type)有效负载类型,7位,如 96 表示动态类型
16-31Sequence Number序列号,每发一个 RTP 包加1,接收方可用于重排和丢包检测
32-63Timestamp时间戳,标识采样时刻,用于同步和延时计算
64-95SSRC同步源标识符,用于区分不同源(一个媒体流)
96-…CSRC List0~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)
编号编码格式采样率备注
0PCMU (G.711 μ-law)8000 Hz音频
8PCMA (G.711 A-law)8000 Hz音频
3GSM8000 Hz音频
10L1644100 Hz立体声音频
26JPEG-视频
31H.261-视频
32MPEG Audio-音频
33MPEG Video-视频
动态 Payload Type(96~127)

动态类型必须在 SDP (Session Description Protocol) 或信令(如 SIP INVITE)中协商说明。常见映射:

PT值编码格式描述
96+H.264RFC 6184 定义
97H.265RFC 7798 定义
98AACRFC 3640 定义
99OPUS音频,动态
100VP8Google 实现
101VP9Google 实现

可选扩展头(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)派生以下密钥:

  1. RTP 加密密钥
  2. RTP 认证密钥
  3. RTP 会话盐值
  4. RTCP 加密密钥
  5. RTCP 认证密钥
  6. 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传输媒体帧和反馈信息(如丢包、带宽)
SRTPRTP 加密传输(使用 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)

  1. 在 SDP 协商阶段使用 a=setup, a=fingerprint 等字段建立 DTLS 连接
  2. 建立 DTLS 通道后双方使用 Exporter 从 DTLS 会话中导出密钥(RFC 5705)
  3. 导出的密钥用于 SRTP 加密解密(分别用于加密/认证)

SRTP 加密细节

项目内容
加密算法AES-CTR (默认),也可用 AES-GCM
完整性保护HMAC-SHA1(默认10字节)
支持重放保护是(基于序列号窗口)
SRTP 不加密字段RTP Header(但用于 HMAC)

处理流程(接收端)

  1. 从网络接收 RTP 报文(可能经过 TURN relay)
  2. 使用协商好的 SRTP 密钥进行解密 + 验签
  3. 解析 RTP Header(获取序列号、时间戳等)
  4. RTP 组帧(重排序、丢包重传等)
  5. 解码器处理后播放音视频

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
ICENAT 穿透、连接检测
STUN/TURN发现公网地址 / 中继
DTLS端到端加密协商
SRTP媒体数据加密传输
RTP媒体传输
RTCP控制反馈与统计

相关文章:

  • vscode运行c++文件和插件的方法
  • 鸿蒙 SplitLayout 组件解析:折叠屏分割布局与多端适配指南
  • 【NLP】使用 LangGraph 构建 RAG 的Research Multi-Agent
  • 前端项目3-01:登录页面
  • 教程 | 一键批量下载 Dify「Markdown 转 Docx」生成的 Word 文件(附源码)
  • 服务器的安装与安全设置
  • 机器学习18-强化学习RLHF
  • Excel基础:数据编辑
  • git 多用户管理 跨平台
  • dify小用
  • Miniconda+Jupyter+PyCharm初始环境配置
  • Linux命令:内置命令与外部命令的本质区别
  • 开疆智能CCLinkIE转ModbusTCP网关连接测联无纸记录仪配置案例
  • 60% 重构项目陷 “越改越烂” 泥潭!
  • 【stm32】HAL库开发——CubeMX配置外部中断和配置PWM
  • Flink部署与应用——Flink架构概览
  • 【机器学习深度学习】线性代数
  • 爬虫简单实操2——以贴吧为例爬取“某吧”前10页的网页代码
  • 华为交换机 USG6311E 新建 vlan
  • python的银行柜台管理系统