跳到主要内容

5. RTP 数据传输协议 (RTP Data Transfer Protocol)

5.1 RTP 固定头部字段 (RTP Fixed Header Fields)

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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

每个 RTP 数据包都包含前十二个八位字节, 而 CSRC 标识符列表仅在由混音器插入时才存在. 各字段含义如下:

版本 (version, V): 2 bits 该字段标识 RTP 的版本. 本规范定义的版本为二 (2).

填充 (padding, P): 1 bit 如果设置了填充位, 则数据包末尾包含一个或多个不属于负载的附加填充八位字节. 填充的最后一个八位字节包含应忽略的填充八位字节数量, 包括其自身. 某些固定块大小的加密算法可能需要填充, 或者在较低层协议数据单元中承载多个 RTP 数据包时也可能需要填充.

扩展 (extension, X): 1 bit 如果设置了扩展位, 固定头部后必须紧跟且仅跟一个头部扩展, 其格式定义见第 5.3.1 节.

CSRC 计数 (CSRC count, CC): 4 bits CSRC 计数包含固定头部之后 CSRC 标识符的数量.

标记 (marker, M): 1 bit 标记的解释由配置文件定义. 它旨在允许在数据包流中标记重要事件, 例如帧边界. 配置文件可以定义额外的标记位, 或通过改变负载类型字段中的位数来规定不存在标记位 (见第 5.3 节).

负载类型 (payload type, PT): 7 bits 该字段标识 RTP 负载的格式, 并决定应用程序如何解释该负载. 配置文件可以规定负载类型代码到负载格式的默认静态映射. 也可以通过非 RTP 手段动态定义额外的负载类型代码 (见第 3 节). 音频和视频的一组默认映射在配套 RFC 3551 [1] 中规定. RTP 源可以在会话期间改变负载类型, 但该字段不应被用于复用独立媒体流 (见第 5.2 节).

接收者必须忽略其不理解的负载类型的数据包.

序列号 (sequence number): 16 bits 每发送一个 RTP 数据包, 序列号递增一, 接收者可以用它检测丢包并恢复数据包顺序. 序列号初始值应为随机值 (不可预测), 以便让针对加密的已知明文攻击更加困难; 即使源本身不按第 9.1 节的方法加密, 这些数据包也可能经过会进行加密的转换器. [17] 讨论了选择不可预测数字的技术.

时间戳 (timestamp): 32 bits 时间戳反映 RTP 数据包中第一个八位字节的采样时刻. 采样时刻必须来自一个随时间单调且线性递增的时钟, 以便进行同步和抖动计算 (见第 6.4.1 节). 该时钟的分辨率必须足以达到所需的同步精度, 并足以测量数据包到达抖动 (每个视频帧一个时钟滴答通常不足够). 时钟频率取决于作为负载承载的数据格式, 并由定义该格式的配置文件或负载格式规范静态规定; 对于通过非 RTP 手段定义的负载格式, 也可以动态规定. 如果 RTP 数据包周期性生成, 应使用由采样时钟确定的标称采样时刻, 而不是系统时钟读数. 例如, 对于固定速率音频, 时间戳时钟很可能在每个采样周期递增一. 如果音频应用程序从输入设备读取覆盖 160 个采样周期的块, 则每个这样的块都会使时间戳增加 160, 无论该块是作为数据包传输还是作为静音被丢弃.

与序列号一样, 时间戳初始值也应为随机值. 如果若干连续 RTP 数据包在逻辑上同时生成, 例如属于同一视频帧, 它们会具有相同的时间戳. 如果数据不是按采样顺序传输, 例如 MPEG 插值视频帧, 连续 RTP 数据包可以包含非单调的时间戳. (按传输顺序看, 数据包序列号仍会保持单调.)

来自不同媒体流的 RTP 时间戳可能以不同速率前进, 并且通常具有独立的随机偏移. 因此, 虽然这些时间戳足以重建单个流的定时, 但直接比较不同媒体的 RTP 时间戳并不能有效实现同步. 相反, 对于每种媒体, RTP 时间戳会通过与参考时钟 (挂钟) 的时间戳配对, 与采样时刻关联起来; 该参考时钟时间戳表示与该 RTP 时间戳对应的数据被采样的时间. 参考时钟由所有需要同步的媒体共享. 时间戳对不会在每个数据包中传输, 而是如第 6.4 节所述, 以较低速率在 RTCP SR 数据包中传输.

选择采样时刻作为 RTP 时间戳的参考点, 是因为发送端点知道该时刻, 并且它对所有媒体都有共同定义, 不依赖编码时延或其他处理. 其目的是允许对同一时间采样的所有媒体进行同步呈现.

传输存储数据而非实时采样数据的应用程序通常使用从挂钟时间派生的虚拟呈现时间线, 来确定存储数据中每种媒体的下一帧或其他单元何时应被呈现. 在这种情况下, RTP 时间戳会反映每个单元的呈现时间. 也就是说, 每个单元的 RTP 时间戳会与该单元在虚拟呈现时间线上成为当前单元的挂钟时间相关联. 实际呈现会在稍后的某个时间发生, 该时间由接收者决定.

一个关于预录视频的实时音频解说示例可以说明选择采样时刻作为参考点的重要性. 在该场景中, 视频会在本地呈现给解说者观看, 同时使用 RTP 传输. 通过把 RTP 中传输的视频帧的时间戳关联到该视频帧呈现给解说者时的挂钟时间, 即可确定该视频帧的"采样时刻". 包含解说者语音的音频 RTP 数据包的采样时刻, 则通过关联到音频被采样时的同一挂钟时间来确定. 如果两台主机上的参考时钟通过 NTP 等某种方式同步, 音频和视频甚至可以由不同主机传输. 接收者随后可以使用 RTCP SR 数据包中的时间戳对关联音频和视频数据包的 RTP 时间戳, 从而同步呈现音频和视频.

SSRC: 32 bits SSRC 字段标识同步源. 该标识符应随机选择, 目标是同一 RTP 会话中的任意两个同步源不会拥有相同的 SSRC 标识符. 附录 A.6 给出了生成随机标识符的示例算法. 虽然多个源选择相同标识符的概率很低, 所有 RTP 实现都必须准备检测并解决冲突. 第 8 节描述了冲突概率, 以及基于 SSRC 标识符唯一性解决冲突和检测 RTP 层转发环路的机制. 如果源改变其源传输地址, 它也必须选择新的 SSRC 标识符, 以避免被解释为环回源 (见第 8.2 节).

CSRC 列表 (CSRC list): 0 to 15 items, 32 bits each CSRC 列表标识对该数据包所含负载做出贡献的源. 标识符数量由 CC 字段给出. 如果贡献源超过 15 个, 则只能标识其中 15 个. CSRC 标识符由混音器插入 (见第 7.1 节), 使用贡献源的 SSRC 标识符. 例如, 对于音频数据包, 会列出所有被混合在一起以创建该数据包的源的 SSRC 标识符, 从而允许接收者正确指示说话者.

5.2 RTP 会话的复用 (Multiplexing RTP Sessions)

为实现高效的协议处理, 应尽量减少复用点的数量, 如集成层处理设计原则 [10] 所述. 在 RTP 中, 复用由目标传输地址 (网络地址和端口号) 提供, 每个 RTP 会话的目标传输地址都不同. 例如, 在一个由分别编码的音频和视频媒体组成的电话会议中, 每种媒体都应在单独的 RTP 会话中承载, 并具有自己的目标传输地址.

不应在单个 RTP 会话中承载独立的音频和视频流, 再基于负载类型或 SSRC 字段进行解复用. 使用相同 SSRC 交织不同 RTP 媒体类型的数据包会引入若干问题:

  1. 例如, 如果两个音频流共享同一个 RTP 会话和相同的 SSRC 值, 其中一个流改变编码并因此获得不同的 RTP 负载类型, 将不存在通用方法来标识哪个流改变了编码.

  2. SSRC 被定义为标识单个定时空间和序列号空间. 如果媒体时钟速率不同, 交织多个负载类型将需要不同定时空间; 同时也需要不同序列号空间, 才能判断哪个负载类型发生了丢包.

  3. RTCP 发送者报告和接收者报告 (见第 6.4 节) 每个 SSRC 只能描述一个定时空间和序列号空间, 且不携带负载类型字段.

  4. RTP 混音器将无法把不兼容媒体的交织流组合为一个流.

  5. 在一个 RTP 会话中承载多种媒体会排除以下可能性: 在适当情况下使用不同网络路径或网络资源分配; 在需要时只接收媒体子集, 例如当视频会超过可用带宽时只接收音频; 以及使用独立进程处理不同媒体的接收者实现, 而使用独立 RTP 会话则允许单进程或多进程实现.

为每种媒体使用不同 SSRC, 但在同一个 RTP 会话中发送它们, 可以避免前三个问题, 但不能避免最后两个问题.

另一方面, 在一个 RTP 会话中使用不同 SSRC 值复用同一媒体的多个相关源, 是组播会话中的常规做法. 上述问题并不适用: 例如, RTP 混音器可以组合多个音频源, 且相同处理方式适用于所有这些源. 在最后两个问题不适用的其他场景中, 使用不同 SSRC 值复用同一媒体的多个流也可能是合适的.

5.3 RTP 头部的配置文件特定修改 (Profile-Specific Modifications to the RTP Header)

现有 RTP 数据包头部被认为已经完整覆盖 RTP 可能支持的各类应用所共同需要的一组功能. 但是, 为符合 ALF 设计原则, 配置文件规范可以通过定义修改或添加项来定制该头部, 同时仍允许与配置文件无关的监测和记录工具工作.

  • 标记位和负载类型字段携带配置文件特定信息, 但它们被分配在固定头部中, 因为预计许多应用会需要它们, 否则可能不得不再添加一个 32 位字来保存它们. 配置文件可以重新定义包含这些字段的八位字节以适配不同需求, 例如使用更多或更少的标记位. 如果存在任何标记位, 其中一个应位于该八位字节的最高有效位, 因为与配置文件无关的监测器可能能够观察到丢包模式与标记位之间的相关性.

  • 特定负载格式所需的附加信息, 例如视频编码所需的信息, 应承载在数据包的负载部分中. 这可以是始终出现在负载部分起始处的头部, 也可以通过数据模式中的保留值指示.

  • 如果某类特定应用需要与负载格式无关的附加功能, 这些应用所使用的配置文件应定义额外固定字段, 并让这些字段紧跟在现有固定头部的 SSRC 字段之后. 这些应用将能够快速且直接地访问这些附加字段, 同时与配置文件无关的监测器或记录器仍可通过只解释前十二个八位字节来处理 RTP 数据包.

如果后来发现所有配置文件共同需要额外功能, 则应定义 RTP 的新版本, 对固定头部进行永久性更改.

5.3.1 RTP 头部扩展 (RTP Header Extension)

本规范提供了一种扩展机制, 允许各实现试验新的, 与负载格式无关的功能, 这些功能需要在 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 |
| .... |

如果 RTP 头部中的 X 位为一, 则必须在 RTP 头部后追加一个可变长度头部扩展, 若存在 CSRC 列表, 则该扩展位于 CSRC 列表之后. 头部扩展包含一个 16 位长度字段, 该字段以 32 位字为单位统计扩展长度, 不包括四个八位字节的扩展头部 (因此零是有效长度). RTP 数据头部只能追加一个扩展. 为了允许多个可互操作的实现分别独立试验不同头部扩展, 或允许某个实现试验多种头部扩展, 头部扩展的前 16 位保留开放, 用作区分标识符或参数. 这 16 位的格式由这些实现所运行的配置文件规范定义. 本 RTP 规范本身不定义任何头部扩展.