0 前言
SDP会话描述协议是一种很有历史的格式,在 20 世纪的会议系统中通常都是使用 SDP 格式的文本来交互多媒体通信双方的连接属性信息和媒体属性信息。
在今天 JSON 这种对象化和可拓展的格式面前确实显得不够通用,尤其是在进行 RPC 通信时通常要将 SDP 信息解析成模块化的格式,ORTC 就是基于这个出发点创建的。
但是 SDP 在传统流媒体通信设备上的通用度还是比较高,熟练的理解并分析 SDP 信息对于系统功能开发和调试都是大有裨益的。本文主要通过参考 2006, RFC4566 文档和 ORTC 思维模式来阐述一套系统化的分析 WebRTC 中 SDP 信息的方法。
1 SDP协议规范简介
- SDP 会话描述由一个会话级别的部分后跟零个或多个媒体级别的部分组成。
- 会话级部分从 “v=” 行开始,持续到第一个媒体级部分。
- 每个媒体级部分以 “m=” 行开始,并继续到下一个媒体级部分或整个会话描述的末尾。
- 通常,会话级值是所有媒体的默认值,除非被等效的媒体级值覆盖。
- 一个 SDP 会话描述由若干行文本组成,形式:
= - 其中
<type>
必须是一个区分大小写的字符,<value>
是结构化文本,其格式取决于<type>。 - 通常,<value> 是由单个空格字符或自由格式字符串分隔的多个字段,并且是区分大小写的,除非特定字段另有定义。
- “=” 符号的两边不能有空格。
- 对于比较复杂的行还会在空格等级的基础上继续拓展使用
分号 ;
作为各个参数之间的分隔符,例如:a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
,按照分级的思路可以记忆为行等分空冒
。
- 其中
- SDP会话描述信息包括:
- 会话名称和意图
- 会话持续时间
- 构成会话的媒体
- 接收这些媒体所需要的信息(地址、端口、格式等)
- SDP会话描述具体内容:
- m= (媒体名称和传输地址)
- i=* (媒体标题)
- c=* (连接信息 — 如果包含在会话层级则该字段可选)
- b=* (0个或多个带宽信息)
- k=* (加密密钥)
- a=* (0 个或多个会话属性行)
- t= (会话活动时间)
- r=* (0或多次重复次数)
- v= (协议版本)
- o= (所有者/创建者和会话标识符)
- s= (会话名称)
- i=* (会话信息)
- u=* (URI 描述)
- e=* (Email 地址)
- p=* (电话号码)
- c=* (连接信息 ― 如果包含在所有媒体中,则不需要该字段)
- b=* (0个或多个带宽信息)
- 一个或多个时间描述(”t=”、”r=”如下ii所示)
- z=* (时区调整)
- k=* (加密密钥)
- a=* (0个或多个会话属性行)
- 0个或多个媒体描述(”m=”、如下iii所示)
- 加*号的是可选项
- 所有描述符必须按如下给定的顺序出现,因为固定的顺序可以更好的发现错误和进行解析
- 会话描述
- 时间描述
- 媒体描述
- 官方示例:
2 WebRTC SDP 内容解析
- 对于一些很专业严谨的系统或者设备而言,SDP 完全体现了它们所拥有的能力,也可以让我们发现其不具备的能力。SDP 的每一个属性都是有其存在意义的,万万不可忽略。
2.1 WebRTC-SDP介绍
- WebRTC 的 SDP 内容要求相对宽松一些,只要满足
v o s t m c b a
行即可,即Version/Owner/Session/Timing/Media/Connection/Bandwidth/Attributes
- 完整例子:
v=0
o=mozilla...THIS_IS_SDPARTA-82.0.3 485627351772987711 0 IN IP4 0.0.0.0
s=-
t=0 0
m=video 9 UDP/TLS/RTP/SAVPF 120 124 121 125 126 127 97 98
c=IN IP4 0.0.0.0
b=AS:1000
a=sendrecv
...
- 媒体描述例子:
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:audio
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
m=video 9 UDP/TLS/RTP/SAVPF 96 97
a=mid:video
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
- 格式字段介绍
- 用于扩展SDP
- 格式:
c=<nettype> <addrtype> <connection-address>
- 携带了会话的连接信息,其实就是 IP 地址
- SDP 的会话级别描述可以包含该字段,每一个媒体级别的描述也可以包含该字段,如果会话级别和媒体级别都有 c line,那么以媒体级别的 c line 为准
- 因为 WebRTC 使用 ICE candidate 交换地址信息,所以不会用到 c line,不过这并不代表 c line 没有用,在 SIP 视频会议场景中,c line 就必不可少了
- nettype:网络类型,比如IN,表示 Internet
- addrtype:地址类型,比如IP4、IP6
- connection-address:如果是广播,则为广播地址组;如果是单播,则为单播地址
- 格式:
m=<media> <port> <proto> <fmt> ...
- 上面例子中,后面一串数字(如111和96 97)就是fmt,代表音频和视频的Media Codec,后面会跟rtpmap、rtcp-fb、fmtp等属性进行解释
- media:表示媒体类型,目前支持audio、video、application、text、message等几种类型
- port:传输端口,因为webrtc使用ICE candidate的地址进行传输,所以该port并没有用过;不过,在 SIP 的场景下,M line 的 port 就十分重要了,此时,port 代表 RTP 端口,而且必须是偶数。结合 SDP 会话级别描述中的 C line 中的 IP 地址,我们就可以知道 SIP 的这路媒体流的传输地址
- proto:采用的传输协议
- fmt:媒体格式描述,后面的
...
表示可以有多个,具体的解释依赖于<proto>,例如如果<proto>有”RTP/AVP” 或 “RTP/SAVP”字段,那么<fmt>子项需要包含RTP payload类型号 - RTP/AVP:应用场景为视频/音频的 RTP 协议。参考 RFC 3551
- RTP/SAVP:应用场景为视频/音频的 SRTP 协议。参考 RFC 3711
- RTP/AVPF: 应用场景为视频/音频的 RTP 协议,支持 RTCP-based Feedback。参考 RFC 4585
- RTP/SAVPF: 应用场景为视频/音频的 SRTP 协议,支持 RTCP-based Feedback。参考 RFC 5124
- 格式:
t=<start-time> <stop-time>
- 会话开始/结束时间,如果<stop-time>是0,表示会话没有结束的边界,但是需要在<start-time>之后会话才是活跃(active)的。如果<start-time>是0,表示会话是永久的
- 格式:
s=<session name>
- 会话的名称,每个 SDP 中有且仅能有一个 s line,而且其值不能为空,没有可以用”-“代替
- 格式:
o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
- 代表会话的发起者
- username:发起者的用户名,不允许存在空格,如果应用不支持用户名,则为-
- sess-id:会话id,由应用自行定义,规范的建议是NTP(Network Time Protocol)时间戳
- sess-version:会话版本,用途由应用自行定义,只要会话数据发生变化时(比如编码),sess-version随着递增就行。同样的,规范的建议是NTP时间戳
- nettype:网络类型,比如IN表示Internet
- addrtype:地址类型,比如IP4、IV6
- unicast-address:域名,或者IP地址
- 格式:
v=0
- 值固定为0,没有子版本号
- 版本协议 (“v=”)
- 来源 (“o=”)
- 会话名称 (“s=”)
- 会话活动时间 (“t=”)
- 媒体描述 (“m=”)
- 连接数据 (“c=”)
- 带宽 (“b=”)
- 属性 (“a=) 用于扩展SDP
2.2 Plan B 和 Unified Plan
- 会话描述中媒体描述的Audio 和 Video 可以有多个流(SSRC),每个流(SSRC)的编码可能相同但也可能不同。比如互联网视频会议,用移动端接入时,编码可能都是 H.264,但是和其他终端接入时可能会有其他编码。
- 随着 WebRTC 的发展 SDP 衍生出两种风格:
Plan B
和Unified Plan
。这两种风格的主要区别在于一个 M line是否携带多个 track 信息。
2.2.1 Plan B 风格
早期的 WebRTC 中一次会话描述通常只包含一个m(audio) 和一个m(video),基于这种需求衍生出来的 SDP 比较简单,即一个 Session 和两个 m-line 。但随着业务复杂度的发展可能一次会话需要包含多个 Audio 和 Video,早期的解决方案是在 m-line 中增加媒体信息,也就是 Plan B
的风格
2.2.2 Unified Plan 风格
使用Plan B风格使 SDP 的解析增加了难度,尤其是当多个 Audio 或 Video 在 同一个 m-line 中存在属性冲突的场景下,Plan B风格的缺点也就彰显了出来,于是又衍生出了Unified Plan
风格的 SDP 会话描述,将每个 media 记录到独立的 m-line 当中。
2.2.3 扩展
上文描述了随着 WebRTC 的发展同一个回话中出现了更多的 media,下面我们要说的是随着 Simulcast 的引入,WebRTC 中每个 media 的内容也进行了拓展。传统的基于 RTP 的会议系统中一个 media 通常只包含一对 RTP stream (即媒体 RTP stream 和 重传 RTP Stream)但是当引入 Simulcast 概念后,一个 media 中便包含了多对 RTP stream,这种拓展也同时要求我们在解析 SDP 信息时要更新观念,由传统的Session Level
和Media Level
模式拓展为三段式,即:
- Session Level
- Media Level
- Track Level
WebRTC 中 answer SDP 中 m-line 不能随意增加和删除,顺序不能随意变更,需要和 Offer SDP 中保持一致,Offer SDP 的 m-line 顺序应遵循先 audio 后 video 的原则。
2.3 SDP扩展信息
WebRTC 的 SDP 信息中的 a-line 承载了大多数的信息,主要包括 媒体信息 和 连接信息 :
- 媒体信息 (RTP Parameters)
- Codec Parameters
- Header Extension Parameters
- Encoding Parameters
- RTCP Parameters
- 连接信息
- ICE Candidate
- ICE Parameters
- DTLS Parameters
下文将基于上面的分类方式详细的描述 WebRTC 中 SDP 常见 a-line 的属性信息。
a-line 有两种组成形式:
a=<flag>
只用来标记开关类型的属性,例如 “a=recvonly”.a=<attribute>:<field1> <field2>
用来标记具有值的属性,例如 “a=orient:landscape”
2.3.1 Codec Parameters
Attribute | Illustrate |
---|---|
a=rtpmap | a=rtpmap:108 H264/90000 |
a=fmtp | a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f |
a=rtcp-fb | a=rtcp-fb:108 goog-remb |
a=rtpmap
的 value 对应 RTP 头部的 Payload Type,长度 8 位,也就是取值范围 0-255,95-127 为自定义,通过 rtpmap 字段进行定义并通过跟随其后的 fmtp 字段来定义属性信息。举例:a=rtpmap:108 H264/90000
定义了 Payload Type 为 108 的 RTP 用来传输 H.264 格式的媒体,媒体采样频率为 90kHz 。a=fmtp
为对应 codec 的参数信息 (Format Parameters),常见的几种 codec 的 fmtp 举例:opus a=fmtp:111 minptime=10;stereo=0;useinbandfec=1
这个 fmtp 描述了一个 Payload Type 为 111 的 opus 媒体编码参数H.264 a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
这个 fmtp 描述了一个 Payload Type 为 102 的 H.264 媒体编码参数RTX a=fmtp:120 apt=102
这个 fmtp 描述了重传的参数,APT (Associated Payload Type),将重传 Payload Tpye 与媒体 Payload Type 进行关联,即 Payload Type 为 120 的 RTP 用于重传 Payload Type 为 102 的媒体信息。
a=rtcp-fb
用于描述一个 Codec 支持的 RTCP Feedback 的类型a=rtcp-fb:120 nack
支持 nack 重传,nack (Negative-Acknowledgment) 。a=rtcp-fb:120 nack pli
支持 nack 关键帧重传,PLI (Picture Loss Indication) 。a=rtcp-fb:120 ccm fir
支持编码层关键帧请求,CCM (Codec Control Message),FIR (Full Intra Request ),通常与 nack pli 有同样的效果,但是 nack pli 是用于重传时的关键帧请求。a=rtcp-fb:120 goog-remb
支持 REMB (Receiver Estimated Maximum Bitrate) 。a=rtcp-fb:120 transport-cc
支持 TCC (Transport Congest Control) 。- rtcp-fb 不能用于会话级别的描述中,只能用于媒体级别的描述,而且其 M 描述的 proto 字段一定要指定 AVPF
- 常见的有:
2.3.2 Header Extension Parameters
Attribute | Illustrate |
---|---|
a=extmap | a=extmap:14 urn:ietf:params:rtp-hdrext:toffset |
a=extmap
描述了拓展头部 ID 与实际传输的 RTP 头部拓展内容的映射关系。详细内容请参考 WebRTC RTP Header Extension 分析[2]
2.3.3 Encoding Parameters
Attribute | Illustrate |
---|---|
a=ssrc | a=ssrc:2430709021 cname:nYAodpnTebS8lziR |
a=ssrc-group | a=ssrc-group:FID 2430709021 3715850271 |
- a=ssrc 用于描述 RTP packet 中 SSRC (Synchronization sources) 字段对应的媒体信息,既用于描述当前 media 中存在该 SSRC ,又用于描述该 SSRC 的属性信息,早期的 Chrome 产生的 SDP 中每个 SSRC 通常有 4 行,例如:
a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7
a=ssrc:3245185839 msid:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9 0cf7e597-36a2-4480-9796-69bf0955eef5
a=ssrc:3245185839 mslabel:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9
a=ssrc:3245185839 label:0cf7e597-36a2-4480-9796-69bf0955eef5
这么繁杂的信息是有历史原因的,cname 是必须的,msid/mslabel/label 这三个属性都是 WebRTC 自创的,或者说 Google 自创的,可以参考https://tools.ietf.org/html/draft-ietf-mmusic-msid-17,理解它们三者的关系需要先了解三个概念:RTP stream
/ MediaStreamTrack
/ MediaStream
:
- 一个 a=ssrc 代表一个 RTP stream
- 一个 MediaStreamTrack 通常包含一个或多个 RTP stream,例如一个视频 MediaStreamTrack 中通常包含两个 RTP stream,一个用于常规传输,一个用于 nack 重传
- 一个 MediaStream 通常包含一个或多个 MediaStreamTrack ,例如 simulcast 场景下,一个 MediaStream 通常会包含三个不同编码质量的 MediaStreamTrack
上面的示例中: label 对应 MediaStreamTrack ID
,mslabel 对应 MediaStream ID
,msid 将 MediaStream ID
和 MediaStreamTrack ID
组合在一起。这种标记方式并不被 Firefox 认可,在 Firefox 生成的 SDP 中一个 a=ssrc 通常只有一行,例如:
a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7
用于描述该 RTP stream 对应的 RTCP 协议中的 CNAME。
RTCP 为每个 RTP 用户提供了一个全局唯一的规范名称标识符 CNAME (Canonical Name) ,接收者使用它来追踪一个 RTP stream。当发现冲突或程序重新启动时,RTP 中的 SSRC (同步源标识符) 可能会发生改变,接收者可利用 CNAME 来索引 RTP stream。同时,接收者也需要利用 CNAME 在相关 RTP 连接中多个 RTP stream 之间建立联系。当 RTP 需要进行音视频同步的时候,接受者就需要使用 CNAME 来使得同一发送者的音视频数据相关联,然后根据 RTCP 包中的 NTP (Network Time Protocol) 来实现音频和视频的同步。
a=ssrc-group
定义参考 RFC 5576[3] ,用于描述多个 ssrc 之间的关联,常见的有两种:a=ssrc-group:FID 2430709021 3715850271
FID (Flow Identification) 最初用在 FEC 的关联中,WebRTC 中通常用于关联一组常规 RTP stream 和 重传 RTP stream 。a=ssrc-group:SIM 360918977 360918978 360918980
在 Chrome 独有的 SDP munging 风格的 simulcast 中使用,将三组编码质量由低到高的 MediaStreamTrack 关联在一起。
2.3.4 RTCP Parameters
Attribute | Illustrate |
---|---|
a=rtcp | a=rtcp:51472 IN IP4 127.0.0.1 |
a=rtcp-mux | a=rtcp-mux |
a=rtcp-rsize | a=rtcp-rsize |
a=rtcp
用于描述 RTCP 的通信地址,在 WebRTC 已经不常用到,因为 WebRTC 通常会使用 rtcp-mux 方式,也就是 RTP 和 RTCP 使用同一个连接地址。同时因为 ICE 在 WebRTC 中是强制性的,所以 a=rtcp 和 c-line 一般都不会被使用。a=rtcp-mux
在 RFC 5761[4]中定义,用于标示当前会话将 RTP 和 RTCP 绑定在同一连接地址和端口中。a=rtcp-rsize
在RFC 5506[5]中定义,用于标示当前会话支持 reduced-size RTCP packets 。
2.3.5 ICE Candidate
Attribute | Illustrate |
---|---|
a=candidate | a=candidate:0 1 UDP 2122252543 192.168.0.111 56774 typ host |
a=end-of-candidates | a=end-of-candidates |
- a=candidate 用于描述 ICE 交互时的一个连接候选者的参数,需要注意 UDP 类型和 TCP 类型的 candidate 定义上是有区别的。
- UDP 类型定义:RFC 8445[6]
- TCP 类型定义: RFC 6544[7]
//UDP
<foundation> <component-id> <transport> <priority> <conn-addr> <conn-port> <cand-type> <candidate-types>
a=candidate:1 1 UDP 2130706431 fe80::6676:baff:fe9c:ee4a 8998 typ host
//TCP
<foundation> <component-id> <transport> <priority> <conn-addr> <conn-port> <cand-type> <candidate-types> <tcp-type-ext> <tcp-type>
a=candidate:2 1 TCP 2124414975 192.0.2.1 3478 typ host tcptype passive
component-id 1:RTP 2:RTCP
ICE Candidate 的 4 种类型 https://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-39
- host 该 candidate 是一个真实的主机,参数中的地址和端口对应一个真实的主机地址
- srflx (server reflexive) 该 candidate 是通过 Cone NAT 反射的类型,参数中的地址和端口是端发送 Binding 请求到 STUN/TURN server 经过 NAT 时,NAT 上分配的地址和端口
- prflx (peer reflexive) 该 candidate 是通过 Symmetric NAT 反射的类型,参数中的地址和端口是端发送 Binding 请求到 STUN/TURN server 经过 NAT 时,NAT 上分配的地址和端口
- relay 该 candidate 是通过 TURN 服务中继的类型,参数中的地址和端口是 TURN 服务用于在两个对等点之间转发数据的地址和端口
a=end-of-candidates
在Trickle ICE
模式时,用于显示声明 candidate 信息的结束,在 https://tools.ietf.org/html/draft-ietf-mmusic-trickle-ice-sip-18 中定义。
2.3.6 ICE Parameters
Attribute | Illustrate |
---|---|
a=ice-options | a=ice-options:trickle |
a=ice-lite | a=ice-lite |
a=ice-ufrag | a=ice-ufrag:3e1029a1 |
a=ice-pwd | a=ice-pwd:143a54b37278247c66e93088f767c62d |
a=ice-options
用于描述 ICE 连接的属性信息,ice-options 的定义有很多种,WebRTC 中常见的有:a=ice-options:trickle
client 一边收集 candidate 一边发送给对端并开始连通性检查,可以缩短 ICE 建立连接的时间。a=ice-options:renomination
允许 ICE controlling 一方动态重新提名新的 candidate 。
a=ice-lite
用于描述使用 ICE lite 实现。
ICE 的实现分为 Full ICE 和 Lite ICE:
- Full ICE 参与连接的两端都要进行连通性检查。
- Lite ICE 在 FULL ICE 和 Lite ICE 连接时,只需要 Full ICE 一方进行连通性检查, Lite ICE 一方只需回应 Response 消息。这种模式对于部署在公网的设备比较常用。
a=ice-ufrag
(ICE Username Fragment),描述当前 ICE 连接临时凭证的用户名部分。a=ice-pwd
(ICE Password),描述当前 ICE 连接临时凭证的密码部分。
2.3.7 DTLS Parameters
Attribute | Illustrate |
---|---|
a=setup | a=setup:actpass |
a=fingerprint | a=fingerprint:sha-256 9D:58:00:00:00:00:FF:FF:00:00:00:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00:00:00 |
a=setup
合法值包括actpass
/active
/passive
。在 WebRTC 中 DTLS 主要是为了交换 SRTP 的密钥,定义参考 RFC 5763[8] 。一次 DTLS 通信的角色通常需要协商指定,通常发起 Offer 一方都会设置为actpass
,即由对方来定,这时 Answer 回复active
或者passive
即完成了角色的协商,当然如果 Offer 一方指定了active
或者passive
,Answer 一方就只能选择剩下的那个角色了。a=fingerprint
DTLS 通信开始前上方都需要校验证书是否被篡改,检验的依据就是协商阶段的证书指纹信息。常见的指纹校验算法有:sha-1
/sha-224
/sha-256
/sha-384
/sha-512
2.3.8 Miscellaneous
Attribute | Illustrate |
---|---|
a=sendrecv/sendonly/recvonly/inactive | a=sendrecv |
a=group | a=group:BUNDLE 0 1 |
a=mid | a=mid:0 |
a=rid | a=rid:1 send pt=98;max-width=1280;max-height=720 |
a=simulcast | a=simulcast:send hi;mid;lo |
a=bundle-only | a=bundle-only |
a=msid-semantic | a=msid-semantic:WMS * |
a=sendrecv/sendonly/recvonly/inactive
用于描述当前 m-line 媒体的流动方向。- sendonly 表示只发送数据,比如客户端推流到 SFU,那么会在自己的 Offer(or Answer) 中携带 senonly 属性
- revonly 表示只接收数据,比如客户端向 SFU 订阅流,那么会在自己的 Offer(or Answer) 中携带 recvonly 属性
- sendrecv 表示可以双向传输,比如客户端加入到视频会议中,既要发布自己的流又要订阅别人的流,那么就需要在自己的 Offer(or Answer) 中携带 sendrecv 属性
- inactive 表示禁止发送数据,比如在基于 RTP 的视频会议中,主持人暂时禁掉用户 A 的语音,那么用户 A 的关于音频的媒体级别描述应该携带 inactive 属性,表示不能再发送音频数据。
a=group
属于会话级别的参数,用于描述将当前会话中的多个媒体绑定在一个连接中,以 mid 作为描述对象。参考 https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54a=mid
用于标识 MediaStream ID , 定义参考RFC 5888[9]a=rid
用于标识每个 RTP Stream ,定义参考 https://tools.ietf.org/html/draft-ietf-mmusic-rid-15a=simulcast
这是 Firefox 风格的 simulcast 喜欢的开启 simulcast 的模式,需要 RTP Header Extension 同时开启 rid 支持,具体参考 https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-14a=bundle-only
用于 Answer 时 显式声明为 BUNDLE 传输,定义参考 https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54a=msid-semantic
显示声明当前会话的 msid,在多个 Media Stream 的场景中通常被置为 * ,WMS (WebRTC Media Stream) ,定义参考 https://tools.ietf.org/html/draft-ietf-mmusic-msid-17
2.3.9 例子
- Plan B风格
References
[1]
2006, RFC4566: https://datatracker.ietf.org/doc/html/rfc4566[2]
WebRTC RTP Header Extension 分析: https://aggresss.blog.csdn.net/article/details/106436703[3]
RFC 5576: https://tools.ietf.org/html/rfc5576[4]
RFC 5761: https://tools.ietf.org/html/rfc5761[5]
RFC 5506: https://tools.ietf.org/html/rfc5506[6]
RFC 8445: https://tools.ietf.org/html/rfc8445[7]
RFC 6544: https://tools.ietf.org/html/rfc6544[8]
RFC 5763: https://tools.ietf.org/html/rfc5763[9]
RFC 5888: https://tools.ietf.org/html/rfc5888
作者:李超
审稿:何绍富 斗鱼流媒体技术委员会
原文:https://mp.weixin.qq.com/s/KH4PNK3x3qQjjbwfyOtUTw
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。