Non-RTP means:为了让 RTP 提供可用服务而加入的协议或者机制。特别是在多媒体会议中,需要一种控制协议来分发组播地址和加密密钥,协调加密算法,定义 RTP payload 格式和 RTP payload 类型的动态映射。
字节序,数据对齐,时间格式所有的整数字段都使用网络字节序(大端序),除了特别声明,数字常量由十进制表示。
所有头部数据都会根据其数据的原始长度进行对齐,比如,16-bit 的数据会对齐到偶数偏移,32-bit 的数据会对齐到可被 4 整除的偏移。此外,用 0 来作为填充字节。
Wallclock time(绝对日期和时间)是用网络时间协议(NTP)的时间格式来表示,即从 1900 年一月一日 0 点到现在的秒数。NTP 的时间戳使用了 64-bit 的无符号固定小数点的形式表示,其中头 32-bit 用来表示整数部分,后 32-bit 用来表示小数部分。RTP 的时间格式采用了 NTP 的简化版,他只用了 NTP 的 64-bit 数据的中间 32-bit,即前 16-bit 表示整数,后 16-bit 表示小数。
NTP 时间戳到 2036 年就会循环回 0,但是因为 RTP 只会使用不同 NTP 时间的差值,所以这不会有什么影响。只要一对时间戳都在同一个循环周期里,直接用模块化的架构相减或者比较就可以,NTP 的循环问题就不重要了。
RTP 数据传输协议 RTP 的定长头字段RTP 头的格式如下:
上图中前 96-bit 的数据是每个 RTP 包都有的部分,CSRC 部分只有 Mixer 发送的报文才会有。这些字段的意义如下:
Version(V):2 bits,RTP 版本号,现在用的是 2。(第一个 RTP 草案用的 1)
Padding(P):1 bit,如果设置了该字段,报文的末尾会包含一个或多个填充字节,这些填充字节不是 payload 的内容。最后一个填充字节标识了总共需要忽略多少个填充字节(包括自己)。Padding 可能会被一些加密算法使用,因为有些加密算法需要定长的数据块。Padding 也可能被一些更下层的协议使用,用来一次发送多个 RTP 包。
Extension(X):1 bit,如果设置了该字段,那么头数据后跟着一个拓展数据。
CSRC count(CC):4 bits,CSRC 列表的长度。
Marker(M):1 bit,Marker 会在预设中进行定义(预设和 RTP 的关系可以参考 rfc3551,我的理解是预设是对 RTP 的补充,以达到某一类实际使用场景的需要),在报文流中用它来划分每一帧的边界。预设中可能会定义附加的 marker,或者移除 Marker 来拓展 payload type 字段的长度。
Payload type(PT): 7bits,该字段定义 RTP payload 的格式和他在预设中的意义。上层应用可能会定义一个(静态的类型码 <->payload 格式)映射关系。也可以用 RTP 协议外的方式来动态地定义 payload 类型。在一个 RTP Session 中 payload 类型可能会改变,但是不应该用 payload 类型来区分不同的媒体流,正如之前所说,不同的媒体流应该通过不同 Session 分别传输。
Sequence number:16 bits,每发送一个 RTP 包该序列号 + 1,RTP 包的接收者可以通过它来确定丢包情况并且利用它来重排包的顺序。这个字段的初始值应该是随机的,这会让 known-plaintext 更加困难。
Timestamp:32 bits,时间戳反映了 RTP 数据包生成第一块数据时的时刻。这个时间戳必须恒定地线性增长,因为它会被用来同步数据包和计算网络抖动,此外这个时钟解决方案必须有足够的精度,像是一个视频帧只有一个时钟嘀嗒这样是肯定不够的。如果 RTP 包是周期性的生成的话,通常会使用采样时钟而不是系统时钟,例如音频传输中每个 RTP 报文包含 20ms 的音频数据,那么相邻的下一个 RTP 报文的时间戳就是增加 20ms 而不是获取系统时间。和序列号一样时间戳的初始值也应该是随机的,而且如果多个 RTP 包是一次性生成的,那它们就会有相同的时间戳。不同媒体流的时间戳可能以不同的步幅增长,它们通常都是独立的,具有随机的偏移。这些时间戳虽然足以重建单一媒体流的时序,但是直接比较多个媒体流的时间戳是没办法进行同步的。每一时间戳都会和参考时钟(wallclock)组成时间对,而且需要同步的不同流会共用同一个参考时钟,通过对比不同流的时间对,就能计算出不同流的时间戳偏移量。这个时间对并不是和每个 RTP 包一同发送,而是通过 RTCP 协议,以一个相对较低的频率进行共享。