You need to enable JavaScript to run this app.
导航

附录

最近更新时间2022.03.14 14:12:09

首次发布时间2022.03.11 19:36:52

SDP 和 RTP 的对应关系

SDP 和 RTP 的对应关系如下图所示。

其中关键映射关系如下所示。

rtpmap  <-->  PT(payload type)
extmap  <-->  Extension ID
SSRC    <-->  SSRC

extension 有 0XBEDE0x1000 2 种 profile。

  • 0XBEDE

0XBEDE 只有 4bits 来指定 Extension ID,所以最多支持 14 种,其中 0 和 0xFF 为特殊 ID。

0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|  ID   |  len  |
+-+-+-+-+-+-+-+-+
  • Len=0:表示之后有 1 个字节数据;
  • Len=1:表示之后有 2 个字节数据。

示例如下所示。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      0xBE     |     0xDE      |          length=3             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  ID   | L=0   |     data      |  ID   |  L=1  |   data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      ...data   |    0 (pad)    |    0 (pad)    |  ID   | L=3   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 0x1000

使用 8bits,即 1 个 byte 来指定 Extension ID,可以支持 255 种。

0                   1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       ID      |     length    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • length=0:表示之后有 0 个字节数据;
  • length=1:表示之后有 1 个字节数据。

示例如下所示。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      0x10     |     0x00      |          length=3             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      ID       |     L=0       |     ID        |     L=1       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       data    |    0 (pad)    |       ID      |     L=4       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          data                                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

下列为常见的几个 Extension。

  • Audio Level:表示音量大小;
  • TCC:用于带宽估计;
  • Video Orientation:视频旋转。

QoS 控制手段 FEC/NACK 选择

RTC 对抗网络丢包主要使用了 FEC 和 NACK 两种技术,两者使用的场景如下。

  • 当 RTT < 20ms(建议参考平均值),建议关闭 FEC 功能;
  • 当 RTT >=20ms(建议参考平均值),FEC 功能可选开启;

WebRTC 维护了一个 FEC Rate 一维的冗余表,其实相当一个二维表 kFecRateTable[rate_i][loss_j],行代表单帧码率,列代表丢包率 loss_ratio * 256,理论上丢包率是能支持的最大值 50%。

当 RTT 过大,使用 NACK 会引入延时,例如,重传包到达时间过长导致卡顿劣化,如果使用 FEC,通过冗余包与源数据包,能恢复丢失的包,弱网丢包延时问题可以得到缓解。

说明

腾讯云、阿里云和火山引擎都已支持 NACK。

STUN 协定

请求意见稿 RFC 请参见 Session Traversal Utilities for NAT (STUN)

STUN(Session Traversal Utilities for NAT)是 NAT 环境下的会话传输工具, 是一种处理 NAT 传输的协议,但主要作为一个工具来服务于其他协议。STUN 协议是用来获取内网地址对应在 NAT 上的外网地址,NAT 穿越。STUN 是 C/S 模式的协议,由客户端发送 STUN 请求;STUN 服务响应,告知由 NAT 分配给主机的 IP 地址和端口号。

TURN 协定

请求意见稿 RFC 请参见 Traversal Using Relays around NAT (TURN)

ICE 应用 TURN(RFC 5766)协定作为 STUN 的辅助,在点对点穿梭失败的状况下,借助于 TURN 服务的转发性能,来实现互通。端口与 STUN 保持一致。

说明

除了 ChannelData 音讯,其他 TURN 音讯都遵循 STUN 的音讯格局。

AAC 打包方式

AAC 打包成网络传输流通常有两种方式,具体为打包成 ADTS 或 LATM。ADTS 的每一帧都有个帧头,在每个帧头信息都一样的状况下,会有很大的冗余。LATM 格式具有很大的灵活性,每帧的音频配置单元既可以带内传输,又可以带外传输。正因为如此,LATM 不仅适用于流传输还可以用于 RTP 传输。

RTP 传输时,若音频数据配置信息是保持不变,可以先通过 SDP 会话先传输 StreamMuxConfig(AudioSpecificConfig)信息,由于 LATM 流由一个包含了一个或多个音频帧的 audioMuxElements(音频复用元素)序列组成。

一个完整或部分完整的 audioMuxElement 可直接映射到一个 RTP 负载上。

ADTS 原始帧转化为 LATM 帧过程

读取 ADTS 帧头信息,获得采样率、声道数、aac 算法参数、帧长等信息生成音频特定配置单元 AudioSpecficConfig。

  • 提取并保存原始帧数据;
  • 根据原始帧长度信息生成 PayloadLengthInfo,再由 PayloadLengthInfo 与原始帧数据生成 LATM 音频负载,最后与 AudioSpecficConfig 组成 LATM 帧。

私有编解码器支持

针对不同厂商的私有 Codec 能力拓展,客户端与服务端都需要遵循同样的编解码器实现规则,同时明确 Codec 类型在 SDP 中的拓展;以火山引擎的 ByteVC1 编码器为例进行说明(SDP 文本描述中以 ByteVC1 占位符号描述私有视频编码器格式)。

a=rtpmap:98 ByteVC1/90000
a=fmtp:98 BFrame-enabled=1;

RTP 时间戳

对于低延时(WebRTC)直播系统来说,基于 RTP 协议打包传输的时间戳与传统直播技术不同。每一个打包成 RTP 的数据都会被打一个时间戳放在当前 RTP 的头中,其计量单位依赖于音视频数据自身的采样率(不同于标准 RTMP、FLV、HLS 直播协议中,对于每一个独立的音视频数据包,我们通常用一个 32 位无符号整型数表示时间戳单位,一般记为毫秒)。

视频时间戳的单位为 1/90000秒,90000 是用于视频同步的时间尺度(TimeScale),即每秒 90k 个时钟 tick。目前视频的帧速率主要有 25fps、29.97fps、30fps 等,而 90k 刚好是它们的倍数,所以就采用了 90k。帧率(frame rate)是视频源的采样率;不同的视频码流具有不同的时间戳打包方式(以 H.264 和 H.265 为例)。

  • Single Nalu:如果一个视频帧包含 1 个 NALU,可以单独打包成一个 RTP 包,那么 RTP 时间戳就对应这个帧的采集时间;
  • FU-A:如果一个视频帧的 NALU 过大(超过 MTU)需要拆分成多个包,可以使用 FU-A 方式来拆分并打到不同的 RTP 包里,那么这几个包的 RTP 时间戳是一样的;
  • STAP-A:如果某帧较大不能单独打包,但是该帧内部单独的 NALU 比较小,可以使用 STAP-A 方式合并多个 NALU 打包发送,但是这些 NALU 的时间戳必须一致,打包后的 RTP 时间戳也必须一致。

音频时间戳的单位就是采样率的倒数。例如,采样率 48000,那么 1 秒就有48000 个采样,每个采样 1/48ms,每个采样对应一个时间戳。RTP 音频包一般打包 20ms 的数据,对应的采样数为 48000 * 20 / 1000 = 960,也就是说每个音频包里携带 960 个音频采样,因为 1 个采样对应 1 个时间戳,那么相邻两个音频 RTP 包的时间戳之差就是 960。

RTP 扩展头

请求意见稿 RFC 请参见 A General Mechanism for RTP Header Extensions

RTP 定义中,一个通用的 RTP 头部如下所示。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       sequence number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           synchronization source (SSRC) identifier            |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|            contributing source (CSRC) identifiers             |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中 X 位如果为 1,表示 CSRC 后面还有一些额外的 RTP 扩展头,其形式如下。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      defined by profile       |           length              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       header extension                        |
|                             ....                               |

但是这种形式只能够附加一个扩展头,为了支持多个扩展头,RFC5285 以 defined by profile 进行了扩展。

单字节扩展

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      0xBE     |    0xDE   |            length =3              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  ID   |  L=0  |   data    |   ID  |  L=1  |    data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     ...data    |  0 (pad)  |    0 (pad)    |   ID   |   L=3    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              data                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

RTP 头后的第一个 16 为固定为 0XBEDE 标志,意味着这是一个 one-byte 扩展,length = 3说明后面有三个扩展头,每个扩展头首先以一个 byte 开始,前 4 位是这个扩展头的 ID,后四位是 data 的长度 -1,譬如说 L=0 意味着后面有 1 个 byte 的 data,同理第二个扩展头的 L=1 说明后面还有 2 个 byte 的 data,但是注意,其后没有紧跟第三个扩展头,而是添加了 2 个 byte 大小的全 0 的 data,这是为了作填充对齐,因为扩展头是以为 32bit 作填充对齐的。

双字节扩展

扩展头为 one-byte 的情况下,RTP 头后的第一个 16 为如下所示,一个 0x100 + appbits,appbits 可以用来填充应用层级别的数据。

0                   1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         0x100         |appbits|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

例如在下列示例中,可以看到开头为 0x100 + 0x0,接下来的为 length=3 表示接下来有 3 个头,接下来的就是扩展头和数据,扩展头除了 ID 和 L 相对于 one-byte header 从 4bits 变成了 8bits,其余内容一致。

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      0x10     |      0x00     |           length=3            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       ID      |      L=0      |      ID      |      L=1       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      data     |    0 (pad)    |      ID      |      L=4       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

SSRC 说明

SSRC 相当于一个 RTP 传输 session 的 ID,每一个 Session 的 ID 就是一个独立不重复的标识符:即每一个 RTP 传输也都有一个名字。这个数字是随机产生,并且要保证唯一。当 RTP session 改变(如 IP等)时,这个 ID 也要改变。