SDP 协议详解SDPSession Description Protocol会话描述协议是一种用于描述多媒体会话参数的纯文本格式定义在 RFC 8866早期为 RFC 4566、RFC 2327中。SDP 本身不是传输协议而是一种描述格式通常嵌入在其他信令协议中传输如 WebRTC 的 HTTP/WebSocket、SIP、RTSP。在 Janus 中SDP 是 WebRTC Offer/Answer 协商的核心载体。目录整体语法规则完整语法结构会话级字段详解媒体级字段详解属性行a详解分隔符规则空格与冒号一个完整 SDP 实例逐行解析SDP 在 WebRTC 中的作用为什么不用 JSON1. 整体语法规则SDP 是纯文本协议遵循以下基本规则每一行格式为typevaluetype是单个小写字母号两边没有空格每行以\r\nCRLF结尾行的顺序有严格要求不能随意调换没有注释语法v0 ← 正确 v 0 ← 错误 两边不能有空格 artpmap:111 opus/48000/2 ← 正确2. 完整语法结构SDP 分为三个层级必须按以下顺序排列┌─────────────────────────────────────────────┐ │ Session Description必须 │ │ │ │ v (protocol version) ── 必须 │ │ o (originator/session id) ── 必须 │ │ s (session name) ── 必须 │ │ i (session information) ── 可选 │ │ u (URI of description) ── 可选 │ │ e (email address) ── 可选 │ │ p (phone number) ── 可选 │ │ c (connection information) ── 可选* │ │ b (bandwidth information) ── 可选 │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ Time Description1个或多个 │ │ │ │ │ │ │ │ t (time session active) ── 必须 │ │ │ │ r (repeat times) ── 可选 │ │ │ └─────────────────────────────────────┘ │ │ │ │ z (time zone adjustments) ── 可选 │ │ k (encryption key, 已废弃) ── 可选 │ │ a (session-level attributes) ── 可选 │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ Media Description0个或多个 │ │ │ │ │ │ │ │ m (media and transport) ── 必须 │ │ │ │ i (media title) ── 可选 │ │ │ │ c (connection info) ── 可选*│ │ │ │ b (bandwidth info) ── 可选 │ │ │ │ k (encryption key) ── 可选 │ │ │ │ a (media attributes) ── 可选 │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ * c 必须在会话级或每个媒体级中至少出现一次ABNF 形式化定义精简版session-description version-field origin-field session-name-field [information-field] [uri-field] [email-fields] [phone-fields] [connection-field] [bandwidth-fields] time-fields [key-field] [attribute-fields] [media-descriptions] media-description media-field [information-field] [connection-field] [bandwidth-fields] [key-field] [attribute-fields]3. 会话级字段详解3.1v— 版本versionv0SDP 协议版本号固定为0目前没有其他版本。3.2o— 来源origin格式ousername sess-id sess-version nettype addrtype address示例o- 4625943528 2 IN IP4 127.0.0.1子字段值含义username-用户名-表示匿名sess-id4625943528会话唯一标识符通常是随机数或 NTP 时间戳sess-version2会话版本号每次 SDP 修改后递增nettypeIN网络类型IN Internet目前唯一定义的值addrtypeIP4地址类型IP4或IP6address127.0.0.1创建会话的机器地址WebRTC 中通常不重要真实地址通过 ICE candidate 交换3.3s— 会话名称session namesJanus WebRTC GatewayRFC 规定此字段必须存在且不能为空。如果没有有意义的名称应写s一个空格或s-。3.4t— 时间timing格式tstart-time stop-time示例t0 0值为 NTP 时间戳秒0 0表示会话永久有效。WebRTC 中统一使用t0 0。3.5 其他可选会话级字段字段格式含义WebRTC 中ii描述文本人类可读的会话信息极少使用uuURL会话相关的 URI极少使用eeemail联系邮箱不使用ppphone联系电话不使用ccnettype addrtype address连接地址通常在媒体级指定bbbwtype:bandwidth带宽限制偶尔使用zztime offset ...时区调整夏令时不使用rrinterval duration offsets重复时间不使用带宽字段b的常见类型bwtype含义CTConference Total整个会议的总带宽kbpsASApplication Specific单个媒体的带宽kbpsTIASTransport Independent Application Specificbps更精确4. 媒体级字段详解4.1m— 媒体描述行这是 SDP 中最核心的行每个m开始一个新的媒体描述块。格式mmedia port proto fmt [fmt ...]示例maudio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8子字段含义media媒体类型audio、video、text、application、messageport传输端口。WebRTC 中9是占位值RFC 定义的 discard port真实端口由 ICE candidate 确定。0表示拒绝该媒体proto传输协议栈fmt一个或多个负载类型编号空格分隔顺序代表优先级越靠前越优先常见的proto值协议含义RTP/AVP标准 RTP无加密RTP/SAVPSRTP加密的 RTPRTP/AVPF带 RTCP Feedback 的 RTPRTP/SAVPF加密 FeedbackUDP/TLS/RTP/SAVPFDTLS-SRTP over UDPWebRTC 标准WebRTC 标准协议UDP/TLS/RTP/SAVPF从底到顶解读UDP 底层传输 └─ TLS 通过 DTLS 加密 └─ RTP 实时传输协议 └─ SAVPF Secure Audio Video Profile with Feedback4.2c— 连接信息媒体级cIN IP4 0.0.0.0WebRTC 中为占位地址实际连接地址由 ICE candidate 提供。5. 属性行a详解a是 SDP 中最灵活、内容最丰富的部分承载了安全、QoS、编解码等所有扩展功能。5.1 两种形式aattribute ← 标志型flag出现即表示支持 aattribute:value ← 值型附带参数5.2 标志型属性属性含义asendrecv既发送又接收双向通话asendonly只发送不接收arecvonly只接收不发送ainactive既不发送也不接收artcp-muxRTP 和 RTCP 复用同一端口WebRTC 强制要求artcp-rsize支持精简版 RTCP5.3 值型属性 — 编解码器相关artpmap— 编解码器映射格式artpmap:payload-type encoding-name/clock-rate[/channels]示例artpmap:111 opus/48000/2 ← Opus 音频48kHz2 声道 artpmap:96 VP8/90000 ← VP8 视频90kHz 时钟频率子字段含义payload-type负载类型编号动态范围 96-127对应m行中的 fmtencoding-name编解码器名称clock-rate时钟频率Hz视频统一为 90000音频因编解码器而异channels声道数可选仅音频afmtp— 编解码器参数格式afmtp:payload-type format-specific-params示例afmtp:111 minptime10;useinbandfec1具体参数的格式由每个编解码器自行定义。artcp-fb— RTCP 反馈能力格式artcp-fb:payload-type type [subtype]示例含义artcp-fb:96 nack支持丢包重传Negative ACK接收方检测到丢包时通知发送方重传artcp-fb:96 nack pli支持 PLIPicture Loss Indication视频解码失败时请求发送方生成新关键帧artcp-fb:96 ccm fir支持 FIRFull Intra Request请求发送方发送完整关键帧通常用于新参与者加入会议PLI 与 FIR 的区别特性PLIFIR触发原因丢包导致解码失败需要一个全新的解码起点典型场景网络抖动丢了几个包新用户加入、录制开始紧急程度可以稍等需要立即响应5.4 值型属性 — ICE 相关属性格式含义aice-ufragaice-ufrag:stringICE User Fragment连接认证的用户名片段aice-pwdaice-pwd:stringICE Password连接认证的密码aice-optionsaice-options:trickleICE 选项。trickle表示支持边收集边发送 candidate无需等全部收集完毕acandidateacandidate:foundation component proto priority addr port typ typeICE 候选地址用于 NAT 穿越ice-ufrag和ice-pwd配对使用用于 STUN Binding Request 中标识和验证 ICE 连接HMAC 完整性校验防止非授权的端建立连接。5.5 值型属性 — 安全相关属性格式含义afingerprintafingerprint:hash-algo hash-valueDTLS 证书指纹。DTLS 握手时验证对方证书指纹是否匹配 SDP 声明的值不匹配则说明遭遇中间人攻击asetupasetup:roleDTLS 连接角色asetup的取值值含义actpass既可以做 active 也可以做 passiveOffer 方通常使用此值active主动发起 DTLS 握手作为 DTLS 客户端Answer 方通常选择此值passive等待对方发起 DTLS 握手作为 DTLS 服务端5.6 值型属性 — 分组与标识属性格式含义agroupagroup:BUNDLE mid mid ...BUNDLE 分组将多路媒体复用到同一个传输通道减少 NAT 穿越开销amidamid:token媒体标识符与agroup:BUNDLE中的标识对应assrcassrc:id attributeRTP 同步源标识aextmapaextmap:id uriRTP 头部扩展映射5.7 属性的作用域同一个属性可以出现在会话级或媒体级。如果两级都出现媒体级覆盖会话级v0 o... s... t0 0 asendrecv ← 会话级默认双向 maudio 9 ... ← 音频未声明方向继承会话级的 sendrecv mvideo 9 ... asendonly ← 视频覆盖为仅发送6. 分隔符规则空格与冒号SDP 没有引号、括号等结构化语法所有层次的分隔都依赖几个简单的字符。6.1— 第一层分隔将每一行分为类型和值两部分artpmap:111 opus/48000/2 ^ type avalue rtpmap:111 opus/48000/26.2:— 第二层分隔仅a行将属性行的值分为属性名和属性值只取第一个冒号作为分隔符afingerprint:sha-256 4A:3B:2C:1D:... ^^^^^^^^^^^ ← 属性名fingerprint ^^^^^^^^^^^^^^^^^^^^^^^^ ← 属性值sha-256 4A:3B:2C:1D:... 后续冒号是指纹内容的一部分解析逻辑等价于attr_name,attr_valuevalue.split(:,1)# 只按第一个冒号分割标志型属性没有冒号整个值就是属性名如asendrecv、artcp-mux。6.3 空格 — 第三层分隔值内部的子字段空格在不同字段中承担不同角色固定位置的子字段分隔o- 4625943528 2 IN IP4 127.0.0.1 ^ ^ ^ ^ ^ 每个位置含义由 RFC 定义空格是子字段分隔符变长列表的分隔maudio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 ^^^^^^^^^^^^^^^^^^^ 负载类型列表个数可变顺序代表优先级属性值内部的子字段分隔artpmap:111 opus/48000/2 ^^^ ^^^^^^^^^^^^^ 冒号右边再用空格分成 payload-type 和 encoding6.4/— 第四层分隔特定属性内部某些属性值内部使用/进一步分隔参数artpmap:111 opus/48000/2 ^ ^ 编码名/时钟频率/声道数6.5 完整解析层次示意原始行: artpmap:111 opus/48000/2 第1层 分割: typea, restrtpmap:111 opus/48000/2 第2层 : 分割: attrrtpmap, value111 opus/48000/2 第3层 空格分割: pt111, encodingopus/48000/2 第4层 / 分割: codecopus, clock48000, ch27. 一个完整 SDP 实例逐行解析以下是一个典型的 Janus WebRTC SDP简化版逐行标注含义v0 协议版本固定为 0 o- 4625943528 2 IN IP4 127.0.0.1 会话来源匿名用户会话ID版本2IPv4 sJanus WebRTC Gateway 会话名称Janus 网关 t0 0 永久有效 agroup:BUNDLE audio video 音频和视频复用同一传输通道 aice-options:trickle 支持 Trickle ICE边收集边发送 candidate maudio 9 UDP/TLS/RTP/SAVPF 111 音频媒体DTLS-SRTP 加密负载类型 111 cIN IP4 0.0.0.0 连接地址占位由 ICE candidate 决定 amid:audio 媒体标识符 audio asendrecv 双向收发 artpmap:111 opus/48000/2 PT 111 → Opus 编解码器48kHz2声道 aice-ufrag:abcd ICE 认证用户名片段 aice-pwd:efghijklmnop ICE 认证密码 afingerprint:sha-256 4A:3B:2C:... DTLS 证书指纹防中间人攻击 asetup:actpass DTLS 角色由对方决定 artcp-mux RTP/RTCP 复用同一端口 mvideo 9 UDP/TLS/RTP/SAVPF 96 视频媒体负载类型 96 cIN IP4 0.0.0.0 连接地址占位 amid:video 媒体标识符 video asendrecv 双向收发 artpmap:96 VP8/90000 PT 96 → VP8 编解码器90kHz 时钟 artcp-fb:96 nack 支持丢包重传 artcp-fb:96 nack pli 支持画面丢失指示请求新关键帧 artcp-fb:96 ccm fir 支持完整关键帧请求对应的功能分区┌──────────────────────────────────────────────────┐ │ v o s t ← 会话基本信息 │ │ agroup:BUNDLE ← 传输优化媒体复用 │ │ aice-options:trickle ← 连接优化 │ ├──────────────────────────────────────────────────┤ │ maudio ... ← 音频媒体块 │ │ artpmap / afmtp ← 编解码器参数 │ │ aice-ufrag / ice-pwd ← ICE 认证 ┐ │ │ afingerprint ← DTLS 指纹 ├ 安全 │ │ asetup ← DTLS 角色 ┘ │ │ artcp-mux ← 端口复用 │ ├──────────────────────────────────────────────────┤ │ mvideo ... ← 视频媒体块 │ │ artpmap ← 编解码器参数 │ │ artcp-fb (nack) ← 丢包重传 ┐ │ │ artcp-fb (pli) ← 关键帧请求 ├ QoS │ │ artcp-fb (fir) ← 完整帧请求 ┘ │ └──────────────────────────────────────────────────┘8. SDP 在 WebRTC 中的作用8.1 Offer/Answer 模型SDP 在 WebRTC 中用于 Offer/Answer 协商这是建立连接的核心步骤呼叫方 (Caller) 被叫方 (Callee) │ │ │ createOffer() │ │ ──→ 生成 SDP Offer │ │ │ │ ──── SDP Offer ─────────────────────→ │ │ 我支持 Opus/VP8 │ │ 我的 ICE 凭据是... │ │ 我的 DTLS 指纹是... │ │ │ │ createAnswer() │ │ ──→ 生成 SDP Answer │ │ │ │ ←──── SDP Answer ─────────────────── │ │ 我也支持 Opus/VP8 │ │ 我的 ICE 凭据是... │ │ 我做 DTLS active │ │ │ │ ═══ 双方达成一致开始媒体传输 ═══ │8.2 SDP 协商的关键内容协商内容对应 SDP 字段说明编解码器m行的 fmt 列表 artpmap双方选择都支持的编解码器媒体方向asendrecv等确定每路媒体是收、发还是双向加密方式afingerprintasetupDTLS-SRTP 的证书指纹和角色分配网络地址aice-ufragaice-pwdacandidateICE 连接认证和候选地址传输复用agroup:BUNDLEartcp-mux多媒体共用一个传输通道QoS 能力artcp-fb丢包重传、关键帧请求等反馈机制8.3 在 Janus 中的流转以 EchoTest 为例SDP 在 Janus 中的流转路径浏览器 Janus Gateway EchoTest 插件 │ │ │ │ createOffer() │ │ │ 生成 SDP Offer │ │ │ │ │ │ {jsep: {type:offer, │ │ │ sdp:v0\r\n...}} │ │ │ ─────────────────────────→ │ │ │ │ 将 SDP 传给插件 │ │ │ ──────────────────────────→ │ │ │ │ │ │ 插件处理后返回 SDP Answer │ │ │ ←────────────────────────── │ │ │ │ │ {jsep: {type:answer, │ │ │ sdp:v0\r\n...}} │ │ │ ←───────────────────────── │ │ │ │ │ │ setRemoteDescription() │ │ │ ═══ 开始 ICE DTLS ═══ │ │9. 为什么不用 JSON9.1 历史原因SDP 诞生于 1998 年RFC 2327而 JSON 直到 2001 年才被发明、2006 年才标准化。SDP 设计时 JSON 根本不存在。9.2 技术优势即使抛开历史因素SDP 在某些方面仍有优势体积更紧凑同等信息量下SDP 约比 JSON 小一半。解析更简单SDP 逐行读取、按分割几乎不需要状态机。JSON 需要完整的递归下降解析器处理嵌套结构。支持流式处理SDP 可以读一行处理一行JSON 必须等整个对象接收完毕才能开始解析。9.3 生态惯性SDP 已被整个电信基础设施深度集成SIP电话系统 ──→ 使用 SDP RTSP流媒体 ──→ 使用 SDP SAP会话公告 ──→ 使用 SDP 所有 VoIP 设备 ──→ 内置 SDP 解析器WebRTC 如果换成 JSON就无法与现有电信基础设施直接互通。IETF 曾有过 ORAP、ORTC 等替代方案的讨论但最终都因迁移成本过高而未被采纳。9.4 WebRTC 的折中WebRTC 通过浏览器 API 隐藏了 SDP 的复杂性——开发者调用createOffer()/createAnswer()浏览器自动生成和解析 SDP。如果确实需要修改 SDP也有库如sdp-transform将 SDP 解析为 JSON 对象来操作。9.5 对比总结维度SDPJSON诞生时间19982001标准化 2006体积紧凑约小一半较大键名、引号、括号的开销解析复杂度逐行解析极简递归解析需处理嵌套可读性需要查 RFC 才能理解每行自描述键名即含义可扩展性通过a行扩展天然支持嵌套和新字段生态兼容所有电信设备支持需要全部替换