Webrtc之SDP协议

SDP简介

SDP 最常用于 RTC 实时通话的协商过程,在 WebRTC 中,通信双方在连接阶段使用 SDP 来协商后续传输过程中使用的音视频编解码器(codec)、主机候选地址、网络传输协议等。

在实际的应用过程中,通信双方可以使用 HTTP、WebSocket、DataChannel 等传输协议来相互传送 SDP 内容,这个过程称作 offer/answer 交换,也就是发起方发送 offer,接收方收到 offer 后回复一个 answer。例如在下图的服务端架构中,客户端将 offer 发送给信令服务器,信令服务器转发给媒体服务器,媒体服务器将 offer 和自身的能力进行比较后得到 answer,信令服务器再将 answer转发给客户端,随后客户端和媒体服务器就可以进行 RTP 通信。

SDP 协议的设计可以参考 rfc4566 文档。它是一种具有特殊约定格式的纯文本描述文档,也就是它的内容都是由 UTF-8 编码的文本,有点类似于 JSON/XML。一个 SDP 会话描述包括若干行 type=value 形式的文本,其中 type 是一个区分大小写的字母,例如 v、m 等,value 是一个结构化的文本,格式不固定。通常 value 由若干分割符隔开的字段组成或者是一个字符串, 整个协议文本区分大小写。"=" 两侧不允许有空格存在。

SDP 由一个会话级描述(session level description)和多个媒体级描述(media level description)组成。会话级描述的作用域是整个会话,在 SDP 中,从 "v=" 行开始到第一个 "m=" 行之前都是属于会话级描述的内容。媒体级描述对某个媒体流的内容进行描述,例如某个音频流或者某个视频流,从某个 "m=" 行开始到下个 "m=" 行之前是属于一个媒体级描述的内容。如下图所示:

SDP 中有的字段是必须的,有的字段是可选的,可选的字段在如下的示例中都使用 * 进行标记。 SDP 中 type 出现的顺序是固定的,按照如下顺序进行排列,这样可以增强解析器错误检测的能力,另外也可以简化解析器的实现。有一个很好的网站:webrtchacks.com/sdp-anatomy... 可用于学习 SDP,这个网站里面鼠标移动到 SDP 某一行时,就会显示这一行 SDP 的具体含义。

复制代码
# 1. 会话级别的描述(及其字段)
v=  (protocol version)
o=  (originator and session identifier)
s=  (session name)
i=* (session information)
u=* (URI of description)
e=* (email address)
p=* (phone number)
c=* (connection information -- not required if included in all media)
b=* (zero or more bandwidth information lines)
# 2. 一个或多个时间描述(字段参见下文)
z=* (time zone adjustments)
k=* (encryption key)
a=* (zero or more session attribute lines)
# 3. 零个或多个媒体级别的描述(字段参见下文)

# 时间描述的字段有这些
t=  (time the session is active)
r=* (zero or more repeat times)

# 媒体级别的描述字段有这些
m=  (media name and transport address)
i=* (media title)
c=* (connection information -- optional if included at session level)
b=* (zero or more bandwidth information lines)
k=* (encryption key)
a=* (zero or more media attribute lines)

SDP示例

复制代码
// SDP 版本信息

v=0

// session 信息

// o=<username> <session-id> <session-version> <nettype> <addrtype> <unicast-address>

o=- 1873022542326151139 2 IN IP4 127.0.0.1

// s=<session name>

s=-

// t=<start-time> <stop-time>,如果不规定开始和结束时间,两个都填 0 即可

t=0 0

// 使用 "a=" 来扩展的 bundle 属性,其含义是 audio 和 video 使用同一个端口发送/接收,具体可以参考下方的 RFC 文档:

// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54

a=group:BUNDLE audio video

// 列出当前SDP中所有的 media stream id,以空格分割

// WMS 的含义是这里面的 media stream id 适配 webrtc 的 media stream

// 参考 RFC 文档: https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-msid-01#section-3

a=msid-semantic: WMS 34b34ced3c5623ea4213vx3

// m=<media> <port> <proto> <fmt> ...

// port=10 无实际含义,真正通信使用的端口由 ICE Candidate 指定

// proto=UDP/TLS/RTP/SAVP 表示用 UDP 来传输 RTP 包,并使用 DTLS 加密

// 后面的一串数字是 fmt,表示所有 codec 的 payloadtype

m=audio 10 UDP/TLS/RTP/SAVPF 111 114 115 116 123 124 125

// c=<nettype> <addrtype> <connection-address>

c=IN IP4 0.0.0.0

// a=rtcp:<port> [nettype addrtype connection-address]

a=rtcp:10 IN IP4 0.0.0.0

// ICE 信息,参考 RFC 文档: https://tools.ietf.org/html/rfc5245#section-15.4

a=ice-ufrag:aZ/b

a=ice-pwd:3tFwvgPAA2PK3pPWoJjVz4FJ

a=ice-options:trickle renomination

// DTLS 信息,参考 RFC 文档: https://tools.ietf.org/html/rfc4572#section-5

a=fingerprint:sha-256 5F:78:37:05:D7:83:46:05:F7:3F:17:35:2A:7E:81:D3:2D:26:71:87:8B:9F:57:02:53:30:E3:3E:B6:3E:49:D5

// a=setup:<role>

// role可选active/passive/actpass/holdconn,

// 分别表示端点将发起一个传出连接、端点将接受传入连接、

// 端点愿意接受传入连接或启动传出连接、端点暂时不想建立连接

// 参考 rfc: https://tools.ietf.org/html/rfc4145#section-4

a=setup:actpass

// a=mid:<token>

// 这个 token 在 a=group 那一行中也有出现,

// 也就是说这里描述的媒体正是需要被 bundle 的

// 参考 rfc: https://tools.ietf.org/html/rfc5888#section-6

a=mid:audio

// 以下是这个媒体支持的所有 RTP 扩展头,

// 参考rfc: https://tools.ietf.org/html/rfc8285

// a=extmap:<value>["/"<direction>] <URI> <extensionattributes>

// value=ID

// direction 可选 sendonly/recvonly/sendrecv/inactive,默认值 sendrecv

// URI 就是这个扩展头的 URI,通信双方可以通过 URI 标明扩展头的含义让双方都能理解

// 这里表示 ID=1 的扩展头是 audio level 扩展头,表示 RTP 包中会携带音频包音量大小

// 参考 https://tools.ietf.org/html/rfc6464#section-4

a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level

// rtp stream 信息,参考 rfc: https://tools.ietf.org/html/draft-ietf-avtext-rid-09

a=extmap:13 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id

// 流的方向,sendrecv 表示可以收也可以发

// 参考 rfc:https://tools.ietf.org/html/rfc3264

a=sendrecv

// 这一行表示 rtcp 和 rtp 复用一个端口,

// 参考 rfc:https://tools.ietf.org/html/rfc5761 

// 和 rfc:https://tools.ietf.org/html/rfc8035

a=rtcp-mux

// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]

// opus codec 的 payload,

// 表明 fmt=111 就是用来传输 opus 数据的

// 参考 rfc: https://datatracker.ietf.org/doc/html/rfc7587

a=rtpmap:111 opus/48000/2

// a=rtcp-fb:<payload type> [...]

// 表示支持的 rtcp 反馈报文类型

// 这个反馈报文是 tcc 带宽探测用的

// 参考 https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

a=rtcp-fb:111 transport-cc

// nack,表示 fmt=111 支持 nack 重传包

a=rtcp-fb:111 nack

// a=fmtp 用来描述 codec 的一些特性,例如这里表示期望的 opus 最小打包时间是 10ms,并且使用 inbandfec

a=fmtp:111 minptime=10;useinbandfec=1

// 指明了音频 RTX 包的 payloadtype

// 参考 rfc:https://tools.ietf.org/html/rfc4588#section-8.6

a=rtpmap:114 rtx/48000/2

// apt 表示 fmt=114 的 RTX 包是用来重传 fmt=111 音频的

a=fmtp:114 apt=111

// 指明了 rsfec 包的 payloadtype

a=rtpmap:123 rsfec/48000/2

// 指明了 red 包的 payloadtype

// 参考 https://tools.ietf.org/html/rfc2198

a=rtpmap:124 red/48000/2

// 指明了音频 RTX 包的 payloadtype

a=rtpmap:125 rtx/48000/2

// apt 表示 fmt=125 的 RTX 包是用来重传 fmt=124 的 red 包的

a=fmtp:125 apt=124

// ssrc-group 指明了一组 ssrc 之间的关系,FID 表明后一个 ssrc 是前一个 ssrc 的 rtx

// https://tools.ietf.org/html/rfc5576#section-4.2

a=ssrc-group:FID 2952055605 1713037948

// cname 的内容是一个 16 位 Base64 字符串,含义是传输级的标识符,同一个 PeerConnection 的值相同

// 参考 https://datatracker.ietf.org/doc/html/rfc8834#section-4.9

a=ssrc:2952055605 cname:vqdagKn92E0lhuXn

// 这里出现了两个字符串,

// 前一个是 media stream id,后一个是 sender track id

// media stream 主要用于音视频同步,每个 track 以 media stream id 作为 sync label 进行同步

// 参考 https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-msid

a=ssrc:2952055605 msid:34b34ced3c5623ea4213vx3 34b34ced3c5623ea4213vx3a0

// media stream id

a=ssrc:2952055605 mslabel:34b34ced3c5623ea4213vx3

// sender track id

a=ssrc:2952055605 label:34b34ced3c5623ea4213vx3a0

// video media

m=video 10 UDP/TLS/RTP/SAVPF 96 97 101 102 103

c=IN IP4 0.0.0.0

a=rtcp:10 IN IP4 0.0.0.0

a=ice-ufrag:aZ/b

a=ice-pwd:3tFwvgPAA2PK3pPWoJjVz4FJ

a=ice-options:trickle renomination

a=fingerprint:sha-256 5F:78:37:05:D7:83:46:05:F7:3F:17:35:2A:7E:81:D3:2D:26:71:87:8B:9F:57:02:53:30:E3:3E:B6:3E:49:D5

a=setup:actpass

a=mid:video

// 传输时间偏移扩展头

// 参考 https://datatracker.ietf.org/doc/html/rfc5450

a=extmap:2 urn:ietf:params:rtp-hdrext:toffset

// abs-send-time 扩展头,gcc 带宽探测用的

a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time

// 视频朝向扩展头

// 参考 https://datatracker.ietf.org/doc/html/rfc6184

a=extmap:4 urn:3gpp:video-orientation

// transport-cc 扩展头,tcc 带宽探测用的

a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

// 扩展头的内容是对播放延迟限制的值

a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay

// 视频内容类型扩展头

a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type

// 这个扩展头用于传输每帧的时间信息

a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing

// 视频的色域空间扩展头

a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/color-space

// 传输视频 SDES 信息的扩展头

// 参考:https://datatracker.ietf.org/doc/html/draft-ietf-avtext-rid-06

a=extmap:13 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id

a=sendrecv

a=rtcp-mux

// 支持 rtcp 压缩

// 参考 https://datatracker.ietf.org/doc/html/rfc5506#section-1

a=rtcp-rsize

// 指明 fmt=96 就是用来传输 H264 编码的视频的

a=rtpmap:96 H264/90000

// remb 反馈报文,gcc 带宽探测用的

a=rtcp-fb:96 goog-remb

a=rtcp-fb:96 transport-cc

// FIR(完整帧内请求)反馈报文

// 参考 https://datatracker.ietf.org/doc/html/rfc5104

a=rtcp-fb:96 ccm fir

a=rtcp-fb:96 nack

// PLI NACK 反馈报文

// 参考 https://datatracker.ietf.org/doc/html/rfc5104

a=rtcp-fb:96 nack pli

// 后面的是一些 H264 的参数

a=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f

a=rtpmap:97 rtx/90000

a=fmtp:97 apt=96;packetization-mode=1

a=rtpmap:101 red/90000

a=fmtp:101 packetization-mode=1

a=rtpmap:102 rtx/90000

a=fmtp:102 apt=101;packetization-mode=1

a=rtpmap:103 rsfec/90000

a=fmtp:103 packetization-mode=1

// ssrc-group:SIM 表示后面的这些 ssrc 是同一个流的 simulcast

a=ssrc-group:SIM 2955842370 1032318052

a=ssrc-group:FID 2955842370 521905126

a=ssrc-group:FID 1032318052 1492521545

a=ssrc:2955842370 cname:vqdagKn92E0lhuXn

a=ssrc:2955842370 msid:34b34ced3c5623ea4213vx3 34b34ced3c5623ea4213vx3v0

a=ssrc:2955842370 mslabel:34b34ced3c5623ea4213vx3

a=ssrc:2955842370 label:34b34ced3c5623ea4213vx3v0

a=ssrc:1032318052 cname:vqdagKn92E0lhuXn

a=ssrc:1032318052 msid:34b34ced3c5623ea4213vx3 34b34ced3c5623ea4213vx3

a=ssrc:1032318052 mslabel:34b34ced3c5623ea4213vx3

a=ssrc:1032318052 label:34b34ced3c5623ea4213vx3v0

a=ssrc:521905126 cname:vqdagKn92E0lhuXn

a=ssrc:521905126 msid:34b34ced3c5623ea4213vx3 34b34ced3c5623ea4213vx3v0

a=ssrc:521905126 mslabel:34b34ced3c5623ea4213vx3

a=ssrc:521905126 label:34b34ced3c5623ea4213vx3v0

a=ssrc:1492521545 cname:vqdagKn92E0lhuXn

a=ssrc:1492521545 msid:34b34ced3c5623ea4213vx3 34b34ced3c5623ea4213vx3v0

a=ssrc:1492521545 mslabel:34b34ced3c5623ea4213vx3

a=ssrc:1492521545 label:34b34ced3c5623ea4213vx3v0

// 使用的 rsfec 的版本

a=rsfec-version:1

参考文档

相关推荐
如意IT1 天前
指纹浏览器检测之BrowserScan的webrtc指纹检测和反检测
自动化·webrtc·chromium·浏览器开发
换个昵称都难1 天前
webrtc TURN 主要源码介绍
webrtc
换个昵称都难1 天前
webrtc RTC_P2P源码解析
asp.net·webrtc·p2p
换个昵称都难1 天前
webrtc StunServer源码介绍
webrtc
数据知道3 天前
指纹浏览器:DNS 泄漏防范与 WebRTC 本地 IP 屏蔽的底层实现
爬虫·网络协议·tcp/ip·安全·webrtc·数据采集·指纹浏览器
换个昵称都难3 天前
webrtc源码解析概要介绍
webrtc
换个昵称都难3 天前
WebRTC 完整调用流程(前端纯 JS 实现,最简可运行)
webrtc
换个昵称都难4 天前
webrtc 拥塞控制GCC 和PCC
webrtc
Cxiaomu4 天前
React接入WebRTC实时视频实践
react.js·音视频·webrtc
AndyHuang19764 天前
WebRTC 强制 Relay 模式下 TCP 重连失败深度排查与优化实战
webrtc