4

SDP 会话描述介绍

 3 years ago
source link: https://mthli.xyz/sdp-introduction/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Yet another blog of Matthew Lee 👀Full-Stack Developer, good at Android 🤖️

SDP 会话描述介绍

March 28, 2021

最新内容和勘误请参见笔者撰写的线上书籍《WebRTC 学习指南》

SDP 全称 Session Description Protocol,即会话描述协议。SDP 是一份具有特殊约定格式的纯文本描述文档(类似 JSON / XML),其中包含了 WebRTC 建立连接所需的 ICE 服务器信息、音视频编码信息等,而开发者可以使用 WebSocket 等传输协议将其发送到信令服务器。

格式和字段

SDP 遵循 <type>=<value> 这样的格式,其中 <type><value> 均大小写敏感,且 = 之间不能有空格。SDP 由会话级别(session-level)描述和其后零至多个媒体级别(media-level)描述组成。会话级别从 v= 开始,并持续到第一行媒体级别 m= 所在的位置。每个媒体级别描述均以 m= 开始,并且持续到下一个 m= 开始的位置,或者 SDP 末尾。

SDP 中有的字段是必须的(REQUIRED);有的字段是可选的(OPTIONAL),可选的字段在如下示例中使用 * 标记。所有字段必须遵循如下顺序排列,这样既可以增强错误检测能力,并且解析器(parser)实现起来也简单很多:

# 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 的字段名 <type> 故意设计得十分简短,因为其本意便是不可随意扩展的,解析器遇到不可识别的字段名可以直接忽略之。如果想要针对特定类型的媒体或应用做扩展,可以使用专为扩展而设计的 a 字段。

会话级别的描述中的 ca 的值默认适用于所有媒体级别的描述。不过如果某个媒体级别的描述具有相同名称的字段,则可复写之(类似父类和子类的复写)。

以下是一个典型的 SDP 描述,大家可以有一个感性的认识:

v=0
o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.example.com/seminars/sdp.pdf
[email protected] (Jane Doe)
c=IN IP4 224.2.17.12/127
t=2873397496 2873404696
a=recvonly
m=audio 49170 RTP/AVP 0
m=video 51372 RTP/AVP 99
a=rtpmap:99 h263-1998/90000

关于 SDP 格式和字段的更多内容,本文就不继续展开了,建议读者直接查阅 RFC 4566 - SDP: Session Description Protocol。SDP 通常是 WebRTC 根据代码配置生成的,开发者不需要刻意去手动修改 SDP。并且我们通常接触的 SDP 字段并不多,笔者会在后续文章中提及。

信令服务器

WebRTC 设备之间建立连接先需要获得彼此的 SDP。而设备是无穷无尽的,我们不可能凭空知道任意设备的 SDP,因此需要借助一台第三方服务器交换彼此的 SDP,而这台服务器我们便称之为信令(Signaling)服务器。

通常来说,我们使用 WebSocket 与信令服务器之间进行连接。由于 WebSocket 是双向通信协议,服务器可以很轻易地发送数据给客户端。而「信令」这个词虽然听起来有点拗口,但其实就是一系列 WebSocket 请求,开发者可以自定义 RequestBody 的内容(比如使用 JSON),只要能表达自己想表达的意思就好。

信令服务器除了被用来交换 SDP,还会被用来维护进房逻辑、传递用户的状态(比如开关摄像头)等。饶是如此,信令服务器并不是 WebRTC 的一部分,你可以使用自己喜欢的 Web 后端框架实现它,比如 DjangoGin 或者 Koa

此外,在 ICE 交互流程介绍 中我们提到,WebRTC 需要借助 ICE 服务器进行 P2P 打洞连接。那么这里的 ICE 服务器可以和信令服务器是同一个服务,也可以是分别独立的服务。独立的服务可能有利于后端横向扩容,不过这超出了本文的讨论范围。笔者在实际项目中使用的 WebRTC 框架是 mediasoup,它同时集成了 ICE 和信令两个功能,即同一个服务(简单)。

WebRTC 使用 PeerConnection 这个类创建连接,它包含两个生成 SDP 的方法,分别是 CreateOffer()CreateAnswer(),前者由会话发起方调用生成 offerSdp 并发送到信令服务器;后者在应答方在收到信令服务器消息后被调用生成 answerSdp,然后也发送回信令服务器。

PeerConnection 还包含两个设置 SDP 的方法,分别是 SetLocalDescription()SetRemoteDescription(),前者用来设置本地(自己)的 localSdp,后者用来设置接收到的对端 remoteSdp。对于会话发起方而言,localSdp 即是 offerSdp,remoteSdp 即是 answerSdp;对于应答方而言,localSdp 即是 answerSdp,而 remoteSdp 即是接收到的 offerSdp。

上述四个方法的有序组合即可构成 WebRTC 设备之间的 SDP 交换过程。其实这也是一种协商过程,因为应答方需要根据发起方提供的 SDP(ICE 服务器信息、音视频编码信息等)决定如何回复。因为与后续的「连接流程」章节的内容有重合,这里只是简单地给出示意图:

sdp

以上。相信读者已经对 SDP 及其交换过程有了比较清晰的了解。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK