blob: 93d4e30e2c3aaaccb72484e2fc339d8295204565 [file]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "media/base/rtp_utils.h"
#include <cstdint>
#include <cstring>
#include <span>
// PacketTimeUpdateParams is defined in asyncpacketsocket.h.
// TODO(sergeyu): Find more appropriate place for PacketTimeUpdateParams.
#include "absl/strings/string_view.h"
#include "modules/rtp_rtcp/source/rtp_util.h"
#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
namespace webrtc {
static const size_t kRtcpPayloadTypeOffset = 1;
static const size_t kRtpExtensionHeaderLen = 4;
namespace {
bool GetUint8(const void* data, size_t offset, int* value) {
if (!data || !value) {
return false;
}
*value = *(static_cast<const uint8_t*>(data) + offset);
return true;
}
} // namespace
bool GetRtcpType(const void* data, size_t len, int* value) {
if (len < kMinRtcpPacketLen) {
return false;
}
return GetUint8(data, kRtcpPayloadTypeOffset, value);
}
// This method returns SSRC first of RTCP packet, except if packet is SDES.
// TODO(mallinath) - Fully implement RFC 5506. This standard doesn't restrict
// to send non-compound packets only to feedback messages.
bool GetRtcpSsrc(const void* data, size_t len, uint32_t* value) {
// Packet should be at least of 8 bytes, to get SSRC from a RTCP packet.
if (!data || len < kMinRtcpPacketLen + 4 || !value)
return false;
int pl_type;
if (!GetRtcpType(data, len, &pl_type))
return false;
// SDES packet parsing is not supported.
if (pl_type == kRtcpTypeSDES)
return false;
*value = GetBE32(
std::span<const uint8_t>(static_cast<const uint8_t*>(data) + 4, 4));
return true;
}
bool IsValidRtpPayloadType(int payload_type) {
return payload_type >= 0 && payload_type <= 127;
}
bool IsValidRtpPacketSize(RtpPacketType packet_type, size_t size) {
RTC_DCHECK_NE(RtpPacketType::kUnknown, packet_type);
size_t min_packet_length = packet_type == RtpPacketType::kRtcp
? kMinRtcpPacketLen
: kMinRtpPacketLen;
return size >= min_packet_length && size <= kMaxRtpPacketLen;
}
absl::string_view RtpPacketTypeToString(RtpPacketType packet_type) {
switch (packet_type) {
case RtpPacketType::kRtp:
return "RTP";
case RtpPacketType::kRtcp:
return "RTCP";
case RtpPacketType::kUnknown:
return "Unknown";
}
RTC_CHECK_NOTREACHED();
}
RtpPacketType InferRtpPacketType(std::span<const uint8_t> packet) {
if (IsRtcpPacket(packet)) {
return RtpPacketType::kRtcp;
}
if (IsRtpPacket(packet)) {
return RtpPacketType::kRtp;
}
return RtpPacketType::kUnknown;
}
bool ValidateRtpHeader(std::span<const uint8_t> rtp, size_t* header_length) {
size_t length = rtp.size();
if (header_length) {
*header_length = 0;
}
if (length < kMinRtpPacketLen) {
return false;
}
size_t cc_count = rtp[0] & 0x0F;
size_t header_length_without_extension = kMinRtpPacketLen + 4 * cc_count;
if (header_length_without_extension > length) {
return false;
}
// If extension bit is not set, we are done with header processing, as input
// length is verified above.
if (!(rtp[0] & 0x10)) {
if (header_length)
*header_length = header_length_without_extension;
return true;
}
if (header_length_without_extension + kRtpExtensionHeaderLen > length) {
return false;
}
// Getting extension profile length.
// Length is in 32 bit words.
uint16_t extension_length_in_32bits =
GetBE16(rtp.subspan(header_length_without_extension + 2, 2));
size_t extension_length = extension_length_in_32bits * 4;
size_t rtp_header_length = extension_length +
header_length_without_extension +
kRtpExtensionHeaderLen;
// Verify input length against total header size.
if (rtp_header_length > length) {
return false;
}
if (header_length) {
*header_length = rtp_header_length;
}
return true;
}
} // namespace webrtc