一、RTP
1.1 RTP协议介绍
在 WebRTC 中,RTP(Real-time Transport Protocol,实时传输协议)是音视频媒体数据传输的核心协议,负责实时数据的封装、传输与解封装,为实时交互提供时序、同步、分片重组等关键能力。它基于 UDP 传输(兼顾实时性),但自身不保证可靠性,而是通过与 RTCP(实时传输控制协议)配合,实现丢包反馈、码率调整等功能。
WebRTC 的实时音视频通话(如 P2P 通话、多人会议)中,音视频数据(经编码后,如 VP8/VP9/H.264 视频、OPUS 音频)需通过 RTP 封装后再由 UDP 传输,核心作用包括:
- 分片与重组:解决大帧(如视频 I 帧)超过以太网 MTU(约 1500 字节)的问题,通过分片传输,接收端重组为完整帧;
- 时序与排序:通过序号和时间戳保证数据的正确顺序和播放时序;
- 媒体类型区分:通过载荷类型标识音频 / 视频及具体编解码器;
- 流标识:通过同步源(SSRC)区分同一端的不同媒体流(如音频流和视频流)。
1.2 RTP报文格式
RTP 协议头遵循 RFC 3550 标准,WebRTC 使用版本 2(V=2),核心字段如下(按功能分类):
1. 基础控制字段
- V(版本):2 位,固定为 2(WebRTC 唯一支持的版本)。
- P(填充位):1 位,标识载荷末尾是否有填充数据(用于加密时对齐块大小,如 AES 加密)。
- X(扩展位):1 位,标识是否有扩展头部。WebRTC 广泛使用扩展头部传输额外信息(如音频电平、视频方向等)。
- CC(CSRC 计数):4 位,标识后续 CSRC 列表的长度(用于混音场景,如多方通话中标识音频来源)。
2. 媒体标识与边界字段
- M(标记位):1 位,用于标识帧的边界。例如:
- 视频中,M=1 表示当前 RTP 包是一帧的最后一个分片;
- 音频中,M=1 表示一个完整音频帧的结束(如 OPUS 帧的边界)。
- PT(载荷类型):7 位,标识载荷的媒体类型及编解码器。WebRTC 中多为动态值(96-127),需通过 SDP 协商确定具体映射:
- 例如:
a=rtpmap:96 VP8/90000
表示 PT=96 对应 VP8 视频,时钟频率 90000Hz(视频常用); a=rtpmap:111 OPUS/48000/2
表示 PT=111 对应 OPUS 音频,48kHz 采样率,双声道。
- 例如:
3. 时序与排序字段
- Sequence Number(序号):16 位,按发送顺序递增,用于:
- 接收端检测丢包(序号不连续则可能丢包);
- 分片重组(同一帧的分片序号连续)。
- Timestamp(时间戳):32 位,用于同步和时序控制:
- 同一帧的所有分片时间戳相同(区分帧边界);
- 不同帧的时间戳不同(按编解码器时钟频率递增,如视频 90kHz:每 1/90000 秒递增 1);
- 接收端通过时间戳计算播放顺序(解决网络乱序问题)。
4. 流标识字段
- SSRC(同步源):32 位,唯一标识一个媒体流(如同一设备的视频流或音频流)。例如:
- 视频流可能用 SSRC=2345,音频流用 SSRC=888(如用户提供的示例),接收端通过 SSRC 区分音视频流;
- 若流中断重连,SSRC 会重新生成,避免冲突。
- CSRC(贡献源):0-15 个 32 位字段,标识混音场景中参与混音的原始音频源(如多方通话中,一个音频包可能包含多个说话人的 CSRC)。
1.3 RTP协议重点特性
1. 动态 PT 的协商(SDP 交互)
WebRTC 支持多种编解码器(如 VP8/VP9/H.264 视频,OPUS/G.711 音频),但 RTP 的 PT 值(尤其是 96-127)是动态分配的,需通过 SDP(会话描述协议)协商:
- 发送端在 SDP 的
m=video
或m=audio
行中列出支持的 PT 值; - 通过
a=rtpmap
属性映射 PT 值与编解码器(如a=rtpmap:96 VP8/90000
); - 双方协商后,确定本次通话使用的 PT 与编解码器对应关系。
2. 大帧分片与重组
视频 I 帧(关键帧)数据量大(可达几十 KB),远超 MTU(1500 字节),WebRTC 通过 RTP 分片传输:
- 发送端将 I 帧拆分为多个 RTP 包,每个包的时间戳相同,序号连续,最后一个包的
M=1
(标记帧结束); - 接收端收集相同时间戳的 RTP 包,按序号排序重组为完整 I 帧,再交给解码器。
3. RTP 扩展头部(WebRTC 增强功能)
WebRTC 通过 RTP 扩展头部传输额外控制信息,提升实时性和用户体验,常见扩展包括:
- 绝对发送时间(Absolute Send Time):标识包的发送时间,辅助接收端计算网络延迟;
- 音频电平(Audio Level):标识音频能量,用于说话人检测(如会议中高亮当前说话人);
- 视频方向(Video Orientation):标识视频帧的旋转角度(如手机横屏 / 竖屏切换);
- 扩展通过 SDP 的
a=extmap
字段协商(如a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
)。
4. 安全性:SRTP 加密
WebRTC 要求媒体传输加密,使用SRTP(Secure RTP) 对 RTP 包进行加密和认证:
- 加密算法:通常用 AES-128,防止数据被窃听;
- 认证算法:HMAC-SHA1,防止数据被篡改;
- 密钥通过 DTLS(数据报传输层安全)协议协商,确保密钥安全交换。
5. 与 RTCP 的协同
RTP 负责传输媒体数据,RTCP 负责控制与反馈,两者协同保证传输质量:
- 接收端通过 RTCP 的 RR(接收报告)反馈丢包率、抖动等信息;
- 发送端根据 RTCP 反馈调整码率(如丢包率高则降低视频码率)、重传策略等,实现自适应比特率(ABR)。
1.4 RTP协议解析
知道了上面这些字段的含义后,下面我们还是来看一个具体的例子吧!假设你从网上接收到一组音视频数据,假设 PT=98 是视频数据,PT=111 是音频数据,如下:
{V=2,P=0,X=0,CC=0,M=0,PT:98,seq:13,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:14,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:14,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:15,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:15,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:16,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:16,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:17,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:17,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:18,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:18,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:19,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:19,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:20,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=1,PT:98,seq:20,ts:1122334455,ssrc=2345},
解析结果如下:
V=2
:版本号为 2,符合 WebRTC 唯一支持的 RTP 版本标准;P=0
:无填充数据(载荷末尾没有额外填充字节);X=0
:无扩展头部(未携带额外扩展信息,如音频电平、绝对发送时间等);CC=0
:无 CSRC 列表(非混音场景,媒体流来自单一源)。- PT=98:标识为视频数据(根据前提,PT=98 对应视频);
- ssrc=2345:唯一标识该视频流(同一设备的视频源);
- ts=1122334455:所有包的时间戳相同,说明它们属于同一视频帧的分片;
- seq=13~20:序号连续递增,说明是同一帧的连续分片(无丢包,按顺序传输);
- M=0→M=1:前 7 个包
M=0
(非帧末尾),最后一个包M=1
(标记为该视频帧的最后一个分片)。
RTP更多资料参考我的博客: RTP协议介绍
二、RTCP
2.1 RTCP协议介绍
RTCP(RTP 控制协议)是 WebRTC 实现实时音视频传输的核心控制协议,其核心目标是通过网络质量反馈和传输策略优化,确保在复杂网络环境下的流畅通信:
- 网络状态监控:通过周期性交换 SR(发送方报告)和 RR(接收方报告),实时统计丢包率、抖动、往返时间(RTT)等关键指标。
- 媒体同步:利用 SR 报文中的 NTP 时间戳,实现音频与视频流的精确同步。
- 传输优化:根据 RTCP 反馈动态调整编码参数(如分辨率、帧率)、重传策略(如 NACK、FEC)和拥塞控制算法(如 GCC)。
- 会话管理:支持 BYE 报文结束会话、SDES 报文描述参与者信息,以及 FIR 报文请求关键帧同步。
2.2 RTCP报文格式
RTCP 有两个最重要的报文:RR(Reciever Report)和 SR(Sender Report),通过这两个报文的交换,各端就知道自己的网络质量到底如何了
RTCP 报文基于 UDP 传输,通常以复合包形式发送(多个 RTCP 报文合并为一个 UDP 包),且第一个报文必须为 SR 或 RR
1. SR
用途:发送方周期性发送(默认 5 秒一次),报告自身发送数据的统计信息,同时包含作为接收方时的网络质量反馈。
结构与字段:
- Header:包含版本(V=2)、填充位(P)、接收报告块数(RC)、报文类型(PT=200)和长度。
- Sender Info:
- NTP 时间戳:绝对时间(1900 年 1 月 1 日起的秒数),用于音视频同步。
- RTP 时间戳:与媒体时钟对齐,用于计算帧率和时间偏移。
- Packet Count:会话开始后发送的 RTP 包总数。
- Octet Count:会话开始后发送的负载字节总数。
- Report Block(多个):
- SSRC:报告对应的媒体流源。
- 丢包率:累计丢包数与期望接收包数的比值(24 位有符号整数)。
- Interarrival Jitter:相邻包到达时间的差异,反映网络抖动。
- LSR/DLSR:最后一次收到对端 SR 的时间及间隔,用于计算 RTT。
示例场景:发送方通过 SR 报文告知接收方:“我已发送 1000 个视频包,总大小 2MB,当前接收对端音频流的丢包率为 5%,抖动为 20ms。”
SR的报文由四部分组成:
SR 报文 = Header (8B) + Sender Info (20B) + [Report Block (24B) × RC] + [Padding]
(1)Header 头部(8 字节)
字段 | 长度 | 说明 |
---|---|---|
V | 2 bit | 版本号,固定为 2 (WebRTC 唯一支持的版本)。 |
P | 1 bit | 填充位,若为 1 ,报文末尾包含填充字节(最后一个字节的值表示填充数)。 |
RC | 5 bit | 接收报告块(Report Block)的数量(最多 31 个)。 |
PT | 8 bit | 报文类型,固定为 200 (SR 报文标识)。 |
Length | 16 bit | 报文总长度(以 32 位字为单位,含头部和填充,需减 1)。 |
SSRC | 32 bit | 发送者的同步源标识符(唯一标识该媒体流)。 |
(2)Sender Info 发送者信息(20 字节)
字段 | 长度 | 说明 |
---|---|---|
NTP Timestamp | 64 bit | 绝对时间戳(1900 年 1 月 1 日起的秒数),用于音视频同步。 |
RTP Timestamp | 32 bit | 与 NTP 时间戳对应的 RTP 时间戳(媒体时钟对齐)。 |
Packet Count | 32 bit | 会话开始后发送的 RTP 包总数(SSRC 变更时重置)。 |
Octet Count | 32 bit | 会话开始后发送的负载字节总数(不含 RTP 头和填充)。 |
(3)Report Block 接收报告块(每个 24 字节)
字段 | 长度 | 说明 |
---|---|---|
SSRC_n | 32 bit | 被报告的媒体流源的 SSRC 标识符。 |
Fraction Lost | 8 bit | 最近一个统计周期内的丢包率(0-255 ,实际值为 字段值 / 256 )。 |
Cumulative Lost | 24 bit | 累计丢包数(期望接收包数 - 实际接收包数)。 |
Extended Highest Seq | 32 bit | 接收的最大序列号(低 16 位为序列号,高 16 位为循环计数)。 |
Interarrival Jitter | 32 bit | 相邻包到达时间的抖动(方差估计值)。 |
LSR(Last SR) | 32 bit | 接收来自 SSRC_n 的最后一个 SR 报文的 NTP 时间戳中间 32 位。 |
DLSR(Delay since LSR) | 32 bit | 自接收 SSRC_n 的 SR 报文以来的延迟(单位:1/65536 秒)。 |
示例场景:
发送者通过 SR 报文告知接收者:“我已发送 1000 个视频包(Packet Count
),总大小 2MB(Octet Count
),当前接收对端音频流的丢包率为 5%(Fraction Lost = 12.8
),抖动为 20ms(Interarrival Jitter
)。”
2 RR
- 用途:接收方发送,报告从多个 SSRC 接收数据的统计信息,用于发送方评估网络质量。
- 结构与字段:
- Header:与 SR 类似,但 PT=201。
- Report Block:
- SSRC:报告对应的媒体流源。
- Extended Highest Sequence Number:接收的最大序列号,用于计算丢包数。
- Fraction Lost:最近一个统计周期内的丢包率(0-255)。
- Interarrival Jitter:与 SR 中的定义相同。
示例场景:接收方通过 RR 报文反馈:“从 SSRC=2345(视频流)接收的包中,最近 100 个包丢失 5 个,抖动为 30ms,RTT 为 150ms。”
RR报文由三部分组成:
RR 报文 = Header (8B) + [Report Block (24B) × RC] + [Padding]
(1)Header 头部(8 字节)
字段 | 长度 | 说明 |
---|---|---|
V | 2 bit | 版本号,固定为 2 。 |
P | 1 bit | 填充位,含义同 SR。 |
RC | 5 bit | 接收报告块(Report Block)的数量(最多 31 个)。 |
PT | 8 bit | 报文类型,固定为 201 (RR 报文标识)。 |
Length | 16 bit | 报文总长度(以 32 位字为单位,含头部和填充,需减 1)。 |
SSRC | 32 bit | 接收者的同步源标识符(标识该接收端)。 |
(2)Report Block 接收报告块(每个 24 字节)
字段 | 长度 | 说明 |
---|---|---|
SSRC_n | 32 bit | 被报告的媒体流源的 SSRC 标识符。 |
Fraction Lost | 8 bit | 最近一个统计周期内的丢包率(0-255 ,实际值为 字段值 / 256 )。 |
Cumulative Lost | 24 bit | 累计丢包数(期望接收包数 - 实际接收包数)。 |
Extended Highest Seq | 32 bit | 接收的最大序列号(低 16 位为序列号,高 16 位为循环计数)。 |
Interarrival Jitter | 32 bit | 相邻包到达时间的抖动(方差估计值)。 |
LSR(Last SR) | 32 bit | 接收来自 SSRC_n 的最后一个 SR 报文的 NTP 时间戳中间 32 位。 |
DLSR(Delay since LSR) | 32 bit | 自接收 SSRC_n 的 SR 报文以来的延迟(单位:1/65536 秒)。 |
示例场景:
接收者通过 RR 报文反馈:“从 SSRC=2345(视频流)接收的包中,最近 100 个包丢失 5 个(Fraction Lost = 12.8
),抖动为 30ms(Interarrival Jitter
),RTT 为 150ms(DLSR
计算得出)。”
3. FIR
- 用途:强制发送方生成关键帧(如 H.264 的 IDR 帧或 VP8 的关键帧),用于解决新用户加入时的解码初始化问题或关键帧丢失后的同步。
- 结构与字段:
- Header:PT=206(PSFB 类型),子类型 = 4。
- FCI(Feedback Control Information):
- SSRC:请求的媒体流源。
- Seq Nr:FIR 报文序列号(8 位),用于去重和排序。
- 多用户场景:FIR 可包含多个 FCI 字段,每个对应一个参与者的 SSRC,实现批量关键帧请求。
示例场景:新用户加入房间后发送 FIR 报文:“请 SSRC=2345(用户 A)、SSRC=888(用户 B)立即发送 IDR 帧。”
2.3 RTCP重点特性
网络质量评估与动态优化
带宽评估:
- 接收方通过 RR 报文反馈丢包率和抖动,发送方结合 SR 中的发送统计,使用 GCC(Google Congestion Control)算法动态调整码率。
- 例如:若丢包率超过 10%,GCC 触发降码率;若 RTT 稳定且带宽充足,则提升码率。
重传策略:
- NACK(Negative Acknowledgment):接收方通过 RTCP FB 报文请求重传丢失的包,适用于非关键帧恢复。
- FEC(Forward Error Correction):发送方预先计算冗余包(如 XOR 异或包),接收方可通过冗余数据恢复丢失的媒体帧。
关键帧同步与解码初始化
FIR 报文的触发场景:
- 新用户加入房间时,主动发送 FIR 报文请求所有参与者的 IDR 帧,确保解码器初始化。
- 接收方检测到连续丢包导致解码失败时,通过 FIR 强制发送方生成新关键帧。
IDR 帧的重要性:IDR 帧包含完整图像信息,是解码后续 P 帧、B 帧的基础。若接收方未收到 IDR 帧,后续所有帧将无法解码。
多流协同与会话管理
- SSRC 标识:每个媒体流(如视频、音频)通过唯一 SSRC 区分,RTCP 报告块通过 SSRC 关联具体流的统计信息。
- BYE 报文:参与者退出时发送 BYE 报文,其他参与者收到后释放资源并更新会话列表。
- SDES 报文:携带参与者的 CNAME(规范名),确保 SSRC 冲突或程序重启时仍能正确关联媒体流。
RTCP 与 RTP 的协作机制
- 复用 UDP 端口:RTP 和 RTCP 通常使用相邻端口(如 RTP 用 5000,RTCP 用 5001),但 WebRTC 支持通过 SDP 协商端口分配。
- 统计信息共享:
- RTP 发送模块在打包时记录序列号、时间戳等信息,供 RTCP 生成 SR 报文。
- RTP 接收模块在解包时统计丢包、抖动等数据,作为生成 RR 报文的依据。
- 周期性发送:RTCP 报文的发送频率根据参与者数量动态调整(如 10 人时每 5 秒发送一次),确保控制信息不超过总带宽的 5%。
三、SDP
3.1 SDP 协议介绍
在 WebRTC 中,两个客户端(如浏览器、移动设备)建立通信前,必须通过信令服务器交换 SDP 信息:
- 让双方知晓彼此支持的音视频编解码器(如 VP8、H.264、OPUS)、编解码参数(如采样率、声道数);
- 明确传输协议(如 RTP/RTCP over UDP)、网络信息(如 IP、端口);
- 协商安全机制(如 DTLS 加密)和服务质量策略(如丢包重传、带宽控制)。
最终通过对比双方 SDP 的 “交集”,确定实际通信中使用的参数。
SDP交换
下面是 1 对 1 WebRTC 处理过程图:
如上图所示,两个客户端 / 浏览器进行 1 对 1 通话时,首先要进行信令交互,而交互的一个重要信息就是SDP 的交换。
交换 SDP 的目的是为了让对方知道彼此具有哪些能力,然后根据双方各自的能力进行协商,协商出大家认可的音视频编解码器、编解码器相关的参数(如音频通道数,采样率等)、传输协议等信息。
如上图所示,Amy 与 Bob进行通讯,它们先各自在 SDP 中记录自己支持的音频参数、视频参数、传输协议等信息,然后再将自己的 SDP 信息通过信令服务器发送给对方。
当一方收到对端传来的 SDP 信息后,它会将接收到的 SDP 与自己的 SDP 进行比较,并取出它们之间的交集,这个交集就是它们协商的结果,也就是它们最终使用的音视频参数及传输协议了。
3.2 SDP报文格式
SDP 是纯文本协议,由一系列<type>=<value>
格式的行组成(=
两侧无空格),其中<type>
为单个字符,<value>
为具体描述内容。
例如:
v=0 // 版本号
o=- 123456 2 IN IP4 192.168.1.1 // 会话发起者信息
m=audio 9 UDP/TLS/RTP/SAVPF 111 // 音频媒体描述
a=rtpmap:111 opus/48000/2 // 负载类型111对应OPUS编码(48kHz采样率,双声道)
SDP 分为会话级描述和媒体级描述两层,层级关系决定参数的作用范围:
1. 会话级描述(Session Level)
作用域为整个会话,从首行v=
开始,到第一个m=
(媒体描述)结束。包含会话全局信息,如会话发起者、时间等。若媒体级未重新定义,会话级参数为媒体的默认值。
v=<version>
:必选,SDP 版本号(WebRTC 中固定为 0)。o=<username> <session-id> <version> <nettype> <addrtype> <address>
:必选,会话发起者信息。username
:用户名(可省略为-
);session-id
:唯一标识(通常用 NTP 时间戳);nettype
:网络类型(固定为IN
,表示互联网);addrtype
:地址类型(如IP4
);address
:发起者 IP。
s=<session-name>
:必选,会话名称(WebRTC 中常为-
)。t=<start> <stop>
:必选,会话活跃时间(0 0
表示持久会话)。
2. 媒体级描述(Media Level)
作用域为单个媒体流(如一路音频或视频),从m=
开始到下一个m=
结束。每个媒体流(音频、视频)对应一个媒体级描述。
m=<media> <port> <transport> <fmt-list>
:必选,媒体基本信息。<media>
:媒体类型(audio
/video
);<port>
:传输端口(WebRTC 中常为9
,实际通过 ICE 协商确定);<transport>
:传输协议(如UDP/TLS/RTP/SAVPF
,表示加密的 RTP 传输);<fmt-list>
:支持的负载类型列表(如111 103
,对应具体编解码器)。
a=<attribute>
:可选,媒体属性,用于补充描述媒体细节(WebRTC 中扩展了大量属性)
WebRTC 对SDP的扩展
标准 SDP 主要描述基础媒体信息,而 WebRTC 为满足实时通信的安全、网络适配和质量需求,扩展了大量专属属性,按功能分为 5 大类:
- Session Metadata,会话元数据
- Network Description,网络描述
- Stream Description,流描述
- Security Descriptions,安全描述
- Qos Grouping Descriptions, 服务质量描述
1. 会话元数据(Session Metadata)
对应标准 SDP 的会话级描述,包含v=
、o=
、s=
、t=
等,用于标识会话全局信息。
2. 网络描述(Network Description)
描述网络传输相关信息,确保双方能建立网络连接(依赖 ICE 协议)。核心属性:
c=<nettype> <addrtype> <address>
:会话级默认 IP 地址(WebRTC 中常为0.0.0.0
,实际通过 ICE 候选地址协商)。a=candidate:<foundation> <component> <transport> <priority> <ip> <port> ...
:ICE 候选地址(如本地 IP、中继服务器 IP 等,用于 NAT 穿透)。
3. 流描述(Stream Description)
描述音视频流的编解码能力,是媒体协商的核心。核心属性:
a=rtpmap:<payload> <encoding>/<clock-rate>[/<params>]
:映射负载类型到编解码器。
例:a=rtpmap:96 VP8/90000
表示负载类型 96 对应 VP8 视频编码(时钟频率 90000Hz,RTP 视频的标准时钟)。a=fmtp:<payload> <params>
:编解码器的具体参数。
例:a=fmtp:111 minptime=10;useinbandfec=1
表示 OPUS 编码(负载 111)的最小打包时长为 10ms,启用内置前向纠错。a=sendrecv
/a=sendonly
/a=recvonly
:媒体流的方向(发送、接收或双向)。
4. 安全描述(Security Descriptions)
WebRTC 强制加密传输,安全描述用于身份认证和加密协商,核心属性:
a=ice-ufrag:<value>
/a=ice-pwd:<value>
:ICE 协商的用户名和密码(用于验证 ICE 候选地址的合法性)。a=fingerprint:<hash> <value>
:DTLS 指纹(基于公钥生成,用于验证对方身份,防止中间人攻击)。a=crypto:<tag> <crypto-suite> <key-params>
:加密套件(如AES_CM_128_HMAC_SHA1_80
)。
5. 服务质量描述(QoS & Grouping Descriptions)
确保音视频传输的稳定性和质量,核心属性:
a=rtcp-fb:<payload> <feedback>
:RTCP 反馈机制(用于质量控制)。
例:a=rtcp-fb:96 nack
表示支持丢包重传;a=rtcp-fb:96 goog-remb
启用 Google 的带宽估算算法(动态调整发送码率)。a=rtcp-mux
:RTP 和 RTCP 复用同一端口(节省端口资源)。a=group:<semantics> <mid-list>
:将关联的媒体流分组(如音视频同步)。
3.3 SDP协议解析
以下是一个简化的 WebRTC SDP 示例,包含音频和视频流的完整描述:
//============= 会话描述(Session Level):作用于整个会话,包含全局信息 ====================
v=0 // SDP版本号,WebRTC中固定为0(遵循标准SDP规范)
o=- 7017624586836067756 2 IN IP4 127.0.0.1 // 会话发起者信息
// -:忽略用户名;7017624586836067756:会话唯一标识(NTP时间戳);2:会话版本(修改后递增)
// IN:网络类型(互联网);IP4:地址类型;127.0.0.1:发起者本地IP(实际通过ICE协商真实地址)
s=- // 会话名称,WebRTC中简化为“-”(无实际业务含义)
t=0 0 // 会话活跃时间,0 0表示“持久会话”(实时通信无固定结束时间)
... // 其他会话级扩展字段
//================ 媒体描述(Media Level):按音频、视频分别定义 =================
//================ 音频媒体描述 =================
/*
* 音频媒体基础信息:定义传输协议、端口和支持的负载类型
* 1024:传输端口(实际由ICE协商确定,此处为占位符)
* UDP/TLS/RTP/SAVPF:传输协议链(UDP底层,TLS建立DTLS,RTP传媒体,SRTP加密+反馈)
* 111、103...:支持的音频负载类型(对应不同编解码器)
*/
m=audio 1024 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126
//============== 音频网络描述 ==================
// 接收/发送音频的IP地址,WebRTC中被ICE候选地址覆盖,此处为占位
c=IN IP4 0.0.0.0
// RTCP控制报文的地址和端口,WebRTC中通常与RTP复用端口(a=rtcp-mux),此处无效
a=rtcp:9 IN IP4 0.0.0.0
... // 其他网络扩展字段(如ICE候选地址a=candidate)
//============== 音频安全描述 ================
// ICE协商的安全验证信息(防止恶意接入)
a=ice-ufrag:khLS // ICE用户名(用于验证候选地址合法性)
a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ // ICE密码(与用户名配合验证)
// DTLS指纹(基于公钥生成,用于对端身份验证,防止中间人攻击)
a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17
... // 其他安全扩展字段(如加密套件a=crypto)
//============== 音频流媒体描述(编解码器信息) ================
// 映射负载类型111到OPUS编码:48000=采样率(Hz);2=双声道
a=rtpmap:111 opus/48000/2
// OPUS编码参数:minptime=10(最小打包时长10ms,减少延迟);useinbandfec=1(启用内置前向纠错,抗丢包)
a=fmtp:111 minptime=10;useinbandfec=1
... // 其他OPUS扩展参数
// 映射负载类型103到ISAC编码(16kHz采样率,单声道)
a=rtpmap:103 ISAC/16000
// 映射负载类型104到ISAC编码(32kHz采样率,单声道)
a=rtpmap:104 ISAC/32000
// 映射负载类型9到G722编码(8kHz采样率)
a=rtpmap:9 G722/8000
... // 其他音频编解码器描述
//================= 视频媒体描述 =================
// 视频媒体基础信息:9=端口占位符;100、101...=支持的视频负载类型
m=video 9 UDP/TLS/RTP/SAVPF 100 101 107 116 117 96 97 99 98
... // 其他视频基础扩展字段
//================= 视频网络描述 =================
// 视频接收/发送IP地址,同音频,被ICE候选地址覆盖
c=IN IP4 0.0.0.0
// 视频RTCP地址和端口,同音频,无效
a=rtcp:9 IN IP4 0.0.0.0
... // 其他视频网络扩展字段(如ICE候选地址)
//================= 视频安全描述 =================
// 与音频共享ICE凭证和DTLS指纹(同一会话安全参数一致)
a=ice-ufrag:khLS
a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ
a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17
... // 其他视频安全扩展字段
//================ 视频流描述 ===============
a=mid:video // 媒体ID(用于区分音频/视频流,如mid:audio对应音频)
... // 其他视频流扩展字段(如方向a=sendrecv)
// 映射负载类型100到VP8视频编码:90000=时钟频率(视频RTP标准时钟,与帧率无关)
a=rtpmap:100 VP8/90000
//================ 视频服务质量描述(QoS):通过RTCP反馈控制传输质量 ===============
// 支持完整帧请求(FIR):解码器初始化或出错时,请求发送方生成关键帧(如IDR帧)
a=rtcp-fb:100 ccm fir
// 支持否定确认(NACK):接收方发现丢包时,请求重传丢失的RTP包
a=rtcp-fb:100 nack // 参考rfc4585
// 支持图片丢失指示(PLI):类似FIR,用于请求关键帧
a=rtcp-fb:100 nack pli
// 启用Google带宽估计(REMB):接收方通过RTCP告知可用带宽,发送方动态调整码率
a=rtcp-fb:100 goog-remb
// 启用传输拥塞控制(Transport-CC):通过RTCP反馈包到达时间,估算拥塞并调整发送策略
a=rtcp-fb:100 transport-cc
... // 其他视频QoS扩展字段
从上面这段 SDP 中你应该可以总结出:SDP 是由一个会话层和多个媒体层组成的,而对于每个媒体层,WebRTC 又将其细划为四部分,即媒体流、网络描述、安全描述和服务质量描述。
并且在上面的例子中有两个媒体层——音频媒体层和视频媒体层,而对于每个媒体层,也都有对应的媒体流描述、网络描述、安全描述及服务质量描述
四、Candidate
4.1 Candidate 介绍
在 WebRTC 中,ICE Candidate(ICE 候选者) 是实现端到端连接的核心网络信息载体,用于描述通信双方可能的网络连接端点(包含 IP、端口、协议等关键信息)。ICE(Interactive Connectivity Establishment,交互式连接建立)协议通过收集、排序和验证这些候选者,最终建立高效且可靠的连接
4.2 ICE Candidate 结构
ICE Candidate 是 WebRTC 用于标识 “通信端点” 的结构化信息,包含建立网络连接所需的全部关键参数
字段 | 含义 |
---|---|
IP |
通信使用的 IP 地址(IPv4 或 IPv6),如内网 IP(host 类型)、外网 IP(srflx 类型)等。 |
port |
传输端口(UDP 为主,WebRTC 默认优先 UDP)。 |
type |
候选者类型,分为host (主机)、srflx (服务器反射)、relay (中继)。 |
priority |
优先级数值(整数),用于排序连接尝试顺序(值越高优先级越高)。 |
protocol |
传输协议(通常为 UDP,部分场景支持 TCP)。 |
usernameFragment |
用于 ICE 验证的用户名片段(与ice-ufrag 配合,防止恶意连接)。 |
foundation |
候选者的基础标识(同一网络接口的候选者可能共享该值)。 |
WebRTC 将 Candidate 分为三类,按优先级从高到低排序,确保优先使用高效连接(如局域网), fallback(降级)到可靠连接(如中继)。
1. host
类型(主机候选者)
- 含义:本机内网的 IP 地址和端口,直接绑定到本地网卡(如
192.168.1.100:5000
)。 - 来源:WebRTC 启动时自动扫描本机所有网卡(有线、无线、虚拟机等),收集所有活跃的内网 IP 和随机端口(通常为 UDP 端口)。
- 优先级:最高(通常优先级数值在
1.2e9
左右)。 - 适用场景:通信双方在同一局域网(如同一 WiFi 下的两台设备),可直接通过内网 IP 建立连接,延迟最低(通常 < 10ms)。
2. srflx
类型(服务器反射候选者)
- 含义:内网主机通过 NAT(网络地址转换)映射后的外网 IP 和端口(如
203.0.113.5:6000
,对应内网192.168.1.100:5000
)。 - 来源:通过STUN 协议(RFC5389)从公网 STUN 服务器获取:
- 内网主机向 STUN 服务器发送
Binding Request
请求; - STUN 服务器收到请求后,提取其公网侧的 IP 和端口(即 NAT 映射后的地址),通过
Binding Response
返回给主机; - 主机解析响应,得到
srflx
类型候选者。
- 内网主机向 STUN 服务器发送
- 优先级:次高(通常优先级数值在
1e9
左右)。 - 适用场景:通信双方处于不同内网(跨 NAT),但可通过 NAT 打洞(P2P 穿越)直接通信。例如,家庭 WiFi 内的设备与公司内网设备通过各自的
srflx
候选者建立 P2P 连接,避免中继带来的延迟。
STUN 协议
srflx 类型的 Candidate 实际上就是内网地址和端口经NAT映射后的外网地址和端口。如下图所示:
你应该知道,如果主机没有公网地址,是无论如何都无法访问公网上的资源的。例如你要通过百度搜索一些信息,如果你的主机没有公网地址的话,百度搜索到的结果怎么传给你呢?
而一般情况下,主机都只有内网 IP 和端口,那它是如何访问外网资源的呢?实际上,在内网的网关上都有 NAT (NetAddress Transport) 功能,NAT 的作用就是进行内外网的地址转换。这样当你要访问公网上的资源时,NAT 首先会将该主机的内网地址转换成外网地址,然后才会将请求发送给要访问的服务器服务器处理好后将结果返回给主机的公网地址和端口,再通过 NAT 最终中转给内网的主机。
知道了上面的原理,你要想让内网主机获得它的外网 IP 地址也就好办了,只需要在公网上架设一台服务器,并向这台服务器发个请求说: “Hi!伙计,你看我是谁?”对方回: “你不是那 xxxx 吗?”这样你就可以知道自己的公网 IP了,是不是很简单?
实际上,上面的描述已经被定义成了一套规范,即 RFC5389 ,也就是 STUN 协议,我们只要遵守这个协议就可以拿到自己的公网 IP 了
这里我们举个例子,看看通过 STUN 协议,主机是如何获取到自己的外网 IP 地址和端口的:
首先在外网搭建一个 STUN 服务器,现在比较流行的 STUN 服务器是coturn,你可以到 GitHub 上自己下载源码编译安装。
当 STUN 服务器安装好后,从内网主机发送一个 binding request 的 STUN 消息到 STUN 服务器。
STUN 服务器收到该请求后,会将请求的 IP 地址和端口填充到 binding response 消息中,然后顺原路将该消息返回给内网主机。此时,收到 binding response 消息的内网主机就可以解析 binding response 消息了,并可以从中得到自己的外网 IP 和端口。
3. relay
类型(中继候选者)
- 含义:中继服务器(TURN 服务器)的 IP 和端口,用于中转通信数据(如
167.71.240.3:7000
)。 - 来源:通过TURN 协议(RFC5766,基于 STUN 扩展)从 TURN 服务器获取:
- 内网主机向 TURN 服务器发送
Allocation Request
请求,申请中继资源; - TURN 服务器分配一个专属端口,用于中转该主机的所有数据,并将该端口的 IP 和端口通过响应返回;
- 主机解析响应,得到
relay
类型候选者。
- 内网主机向 TURN 服务器发送
- 优先级:最低(通常优先级数值在
2e8
左右)。 - 适用场景:当
host
和srflx
候选者均无法建立连接(如对称型 NAT 之间无法打洞),则通过 TURN 服务器中转数据,确保连通性(代价是延迟较高,通常比 P2P 高 50-200ms)。
TURN 协议
这里需要说明一点,relay 服务是通过 TURN 协议实现的。所以我们经常说的 relay 服务器或 TURN 服务器它们是同一个意思,都是指中继服务器。
知道了内网主机如何通过 STUN 协议获取到 srflx 类型的候选者后,那么中继类型候选者,即 relay型的 Candidate 又是如何获取的呢?下面我们就来看一下:
首先你要清楚,relay 型候选者的优先级与其他类型相比是最低的,但在其他候选者都无法连通的情况下,relay 候选者就成了最好的选择。因为它的连通率是所有候选者中连通率最高的。
其实,relay 型候选者的获取也是通过 STUN 协议完成的,只不过它使用的 STUN 消息类型与获取 srflx 型候选者的STUN 消息的类型不一样而已。
RFC5766 的 TURN 协议描述了如何获取 relay 服务器(即 TURN 服务器)的 Candidate 过程。其中最主要的是Allocation 指令。通过向 TURN 服务器发送 Allocation 指令,relay 服务就会在服务器端分配一个新的 relay 端口,用于中转 UDP 数据报。
不过这里我只是简要描述了下,如果你对这块感兴趣的话,可以直接查看 RFC5766 以了解更多的细节。
NAT 打洞 /P2P 穿越
当收集到 Candidate 后,WebRTC 就开始按优先级顺序进行连通性检测了:
它首先会判断两台主机是否处于同一个局域网内,如果双方确实是在同一局域网内,那么就直接在它们之间建立一条连接。
但如果两台主机不在同一个内网,WebRTC 将尝试NAT 打洞,即 P2P 穿越。在 WebRTC 中,NAT 打洞是极其复杂的过程,它首先需要对 NAT 类型做判断,检测出其类型后,才能判断出是否可以打洞成功,只有存在打洞成功的可能性时才会真正尝试打洞。
WebRTC 将 NAT 分类为 4 种类型,分别是:
- 完全锥型 NAT
- IP 限制型 NAT
- 端口限制型 NAT
- 对称型 NAT
需要记住的是,对称型 NAT 与对称型 NAT 是无法进行 P2P 穿越的;而对称型 NAT 与端口限制型 NAT 也是无法进行 P2P 连接的
ICE
ICE 就是上面所讲的获取各种类型 Candidate 的过程,也就是:
- 在本机收集所有的 host 类型的 Candidate
- 通过 STUN 协议收集 srflx 类型的 Candidate
- 通过 TURN 协议收集 relay 类型的 Candidate。
在整个过程中,WebRTC 使用优先级的方法去建立连接,即局域网内的优先级最高,其次是 NAT 穿越,再次是通过中继服务器进行中转,这样就巧妙地实现了“既要高效传输,又能保证连通率”这个目标。