一、包发送优先级
Audio = 重传包 》视频包 = Fec包 》数据包二
int GetPriorityForType(RtpPacketMediaType type) {
// 较低的数字优先于较高的数字
switch (type) {
case RtpPacketMediaType::kAudio:
// 音频始终优先于其他数据包类型
return kFirstPriority + 1;
case RtpPacketMediaType::kRetransmission:
// 在新媒体之前发送重传
return kFirstPriority + 2;
case RtpPacketMediaType::kVideo:
case RtpPacketMediaType::kForwardErrorCorrection:
// 视频具有“正常”优先级,用老话说。同时向视频发送冗余。 如果延迟,它可能有一个有用的机会较低
return kFirstPriority + 3;
case RtpPacketMediaType::kPadding:
// 本身可能无用的数据包,仅发送以保持BWE高
return kFirstPriority + 4;
}
RTC_CHECK_NOTREACHED();
}
二、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 32位 uint8_t* buffer size_t size
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P|X| CC |M| PT | sequence number | buffer[0] buffer[1] buffer[2] buffer[3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp | buffer[4] buffer[5] buffer[6] buffer[7]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | synchronization source (SSRC) identifier | buffer[8] buffer[9] buffer[10] buffer[11]
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | Contributing source (CSRC) identifiers | buffer[12] ~ buffer[11 + CC * 4]
// | .... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | header eXtension profile id | length in 32bits | buffer[12 + CC * 4]~ buffer[12 + CC * 4 +3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Extensions | buffer[12 + CC * 4 + 4]
// | .... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | Payload |
// | .... : padding... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | padding | Padding size | buffer[size - 2] buffer[size - 1]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/* RTP header extension, RFC 3550.
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 payload_offset = 12 + CC * 4;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ id | 扩展容量
| defined by profile | length | buffer[payload_offset + 4] | buffer[payload_offset + 4 +2]
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |
*/
// 数据流
80 e0 00 1e 00 00 d2 f0 00 00 00 00 41 9b 6b 49 €?....??....A?kI
e1 0f 26 53 02 1a ff06 59 97 1d d2 2e 8c 50 01 ?.&S....Y?.?.?P.
cc 13 ec 52 77 4e e50e 7b fd 16 11 66 27 7c b4 ?.?RwN?.{?..f'|?
f6 e1 29 d5 d6 a4 ef3e 12 d8 fd 6c 97 51 e7 e9 ??)????>.??l?Q??
cfc7 5e c8 a9 51 f6 82 65 d6 48 5a 86 b0 e0 8c ??^??Q??e?HZ????
其中,
80 是V_P_X_CC
e0 是M_PT
00 1e 是SequenceNum
00 00 d2 f0 是Timestamp
00 00 00 00 是SSRC
换成二进制:
0X80 = 1000 0000
= 10|0|0|0000
v|p|x|cc
0Xe0 = 1110 0000
= |1|110000
|m|pt
前 12 个字节出现在每个 RTP 包中,仅仅在被混合器插入时,才出现 CSRC 识别符列表。这些域有以下意义: 版本(V): 2位 RTP版本。此协议定义的版本是2 解析: buffer[0] >> 6 填充(P):1位 若填料比特被设置,则此包包含一到多个附加在末端的填充比特,填充比特不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充比特。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个 RTP 包。 解析: buffer[0] & 0x20
扩展(X):占1位 若设置扩展比特,固定头(仅)后面跟随一个头扩展。 解析: buffer[0] & 0x10
CSRC计数(CC): 占4位 CSRC计数器,
标志(M): 占1位 标志的解释由具体协议规定。它用来允许在比特流中标记重要的事件,如帧边界。
负载类型(PT):有效荷载类型,占7位, 此域定义了负载的格式,由具体应用决定其解释。
序列号(sequence number): 占16位, 每发送一个 RTP 数据包,序列号加 1,接收端可以据此检测丢包和重建包序列。序列号的初始值是随机的(不可预测),以使即便在源本身不加密时(有时包要通过翻译器,它会这样做),对加密算法泛知的普通文本攻击也会更加困难。
时间戳(timestamp): 占32位,时间戳反映了RTP数据包中第一个字节的采样时间。时钟频率依赖于负载数据格式,并在描述文件(profile)中进行描述。也可以通过 RTP 方法对负载格式动态描述。 SSRC: 占32位 用以识别同步源。标识符被随机生成,以使在同一个 RTP 会话期中没有任何两个同步源有相同的 SSRC 识别符。 CSRC列表:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。
// uint8_t 0~255 0000 0000
bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
if (size < kFixedHeaderSize) {
return false;
}
// 前两位为版本号
const uint8_t version = buffer[0] >> 6;
if (version != kRtpVersion) {
return false;
}
// 0x20 = 0010 0000
const bool has_padding = (buffer[0] & 0x20) != 0;
// 0x10 = 0001 0000
const bool has_extension = (buffer[0] & 0x10) != 0;
// 0x0f = 0000 1111
const uint8_t number_of_crcs = buffer[0] & 0x0f;
// 0x80 = 1000 0000
marker_ = (buffer[1] & 0x80) != 0;
// 0x7f = 0111 1111
payload_type_ = buffer[1] & 0x7f;
// 读16位 4字节
sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
// 读32位 8字节
timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
// 读32位 8字节
ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
// 数据足够,没有丢失
if (size < kFixedHeaderSize + number_of_crcs * 4) {
return false;
}
// payload 偏移
payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
if (has_padding) {
padding_size_ = buffer[size - 1];
if (padding_size_ == 0) {
RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
return false;
}
} else {
padding_size_ = 0;
}
// 初始化extension
extensions_size_ = 0;
extension_entries_.clear();
if (has_extension) {
/* RTP header extension, RFC 3550.
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 |
| .... |
*/
// 扩展偏移
size_t extension_offset = payload_offset_ + 4;
if (extension_offset > size) {
return false;
}
// ID
uint16_t profile =
ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
// 扩展容量
size_t extensions_capacity =
ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
extensions_capacity *= 4;
// 判断扩展合法
if (extension_offset + extensions_capacity > size) {
return false;
}
// 判断是否支持rtp扩展
if (profile != kOneByteExtensionProfileId &&
profile != kTwoByteExtensionProfileId) {
RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
} else {
// 扩展头长度
size_t extension_header_length = profile == kOneByteExtensionProfileId
? kOneByteExtensionHeaderLength
: kTwoByteExtensionHeaderLength;
// 填充字节
constexpr uint8_t kPaddingByte = 0;
// 填充Id
constexpr uint8_t kPaddingId = 0;
// 一字节报头扩展保留ID
constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
// 读取extensions
while (extensions_size_ + extension_header_length < extensions_capacity) {
// 填充字节为0
if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
extensions_size_++;
continue;
}
int id;
uint8_t length;
// 例如: 0100 1000
// 单字节扩展
if (profile == kOneByteExtensionProfileId) {
// id 0100
id = buffer[extension_offset + extensions_size_] >> 4;
// 1 + 1000
length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
// id = 15 或者 id = 0 且 长度 != 1
if (id == kOneByteHeaderExtensionReservedId ||
(id == kPaddingId && length != 1)) {
break;
}
} else {
// id 0100 1000
id = buffer[extension_offset + extensions_size_];
length = buffer[extension_offset + extensions_size_ + 1];
}
// 超大的rtp标头扩展
if (extensions_size_ + extension_header_length + length >
extensions_capacity) {
RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
break;
}
// 查找或创建扩展信息
ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
if (extension_info.length != 0) {
RTC_LOG(LS_VERBOSE)
<< "Duplicate rtp header extension id " << id << ". Overwriting.";
}
// 偏移
size_t offset =
extension_offset + extensions_size_ + extension_header_length;
if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
break;
}
extension_info.offset = static_cast<uint16_t>(offset);
extension_info.length = length;
extensions_size_ += extension_header_length + length;
}
}
// 更新paload偏移
payload_offset_ = extension_offset + extensions_capacity;
}
// 判断越界错误
if (payload_offset_ + padding_size_ > size) {
return false;
}
// payload 大小
payload_size_ = size - payload_offset_ - padding_size_;
return true;
}