Parse two-byte header extensions.
Bug: webrtc:7990 Change-Id: I967d2065b85d6a2ca938ac0e83035cb92b45a907 Reviewed-on: https://webrtc-review.googlesource.com/98160 Reviewed-by: Björn Terelius <terelius@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Johannes Kron <kron@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24881}
This commit is contained in:
parent
78e0ac1b39
commit
07ba2b9445
@ -140,8 +140,9 @@ const int RtpExtension::kGenericFrameDescriptorDefaultId = 11;
|
||||
const char RtpExtension::kEncryptHeaderExtensionsUri[] =
|
||||
"urn:ietf:params:rtp-hdrext:encrypt";
|
||||
|
||||
const int RtpExtension::kMinId = 1;
|
||||
const int RtpExtension::kMaxId = 14;
|
||||
constexpr int RtpExtension::kMinId;
|
||||
constexpr int RtpExtension::kMaxId;
|
||||
constexpr int RtpExtension::kOneByteHeaderExtensionMaxId;
|
||||
|
||||
bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
|
||||
return uri == webrtc::RtpExtension::kAudioLevelUri ||
|
||||
|
||||
@ -201,7 +201,7 @@ struct RtpCodecCapability {
|
||||
// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)",
|
||||
// you know you're getting audio capabilities.
|
||||
struct RtpHeaderExtensionCapability {
|
||||
// URI of this extension, as defined in RFC5285.
|
||||
// URI of this extension, as defined in RFC8285.
|
||||
std::string uri;
|
||||
|
||||
// Preferred value of ID that goes in the packet.
|
||||
@ -226,7 +226,7 @@ struct RtpHeaderExtensionCapability {
|
||||
}
|
||||
};
|
||||
|
||||
// RTP header extension, see RFC 5285.
|
||||
// RTP header extension, see RFC8285.
|
||||
struct RtpExtension {
|
||||
RtpExtension();
|
||||
RtpExtension(const std::string& uri, int id);
|
||||
@ -307,9 +307,11 @@ struct RtpExtension {
|
||||
// https://tools.ietf.org/html/rfc6904
|
||||
static const char kEncryptHeaderExtensionsUri[];
|
||||
|
||||
// Inclusive min and max IDs for one-byte header extensions, per RFC5285.
|
||||
static const int kMinId;
|
||||
static const int kMaxId;
|
||||
// Inclusive min and max IDs for two-byte header extensions and one-byte
|
||||
// header extensions, per RFC8285 Section 4.2-4.3.
|
||||
static constexpr int kMinId = 1;
|
||||
static constexpr int kMaxId = 255;
|
||||
static constexpr int kOneByteHeaderExtensionMaxId = 14;
|
||||
|
||||
std::string uri;
|
||||
int id = 0;
|
||||
|
||||
@ -363,7 +363,8 @@ std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing(
|
||||
|
||||
RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap() {
|
||||
RtpHeaderExtensionMap extension_map;
|
||||
std::vector<int> id(RtpExtension::kMaxId - RtpExtension::kMinId + 1);
|
||||
std::vector<int> id(RtpExtension::kOneByteHeaderExtensionMaxId -
|
||||
RtpExtension::kMinId + 1);
|
||||
std::iota(id.begin(), id.end(), RtpExtension::kMinId);
|
||||
ShuffleInPlace(&prng_, rtc::ArrayView<int>(id));
|
||||
|
||||
|
||||
@ -138,18 +138,19 @@ void DiscardRedundantExtensions(
|
||||
|
||||
bool ValidateRtpExtensions(
|
||||
const std::vector<webrtc::RtpExtension>& extensions) {
|
||||
bool id_used[14] = {false};
|
||||
bool id_used[1 + webrtc::RtpExtension::kMaxId] = {false};
|
||||
for (const auto& extension : extensions) {
|
||||
if (extension.id <= 0 || extension.id >= 15) {
|
||||
if (extension.id < webrtc::RtpExtension::kMinId ||
|
||||
extension.id > webrtc::RtpExtension::kMaxId) {
|
||||
RTC_LOG(LS_ERROR) << "Bad RTP extension ID: " << extension.ToString();
|
||||
return false;
|
||||
}
|
||||
if (id_used[extension.id - 1]) {
|
||||
if (id_used[extension.id]) {
|
||||
RTC_LOG(LS_ERROR) << "Duplicate RTP extension ID: "
|
||||
<< extension.ToString();
|
||||
return false;
|
||||
}
|
||||
id_used[extension.id - 1] = true;
|
||||
id_used[extension.id] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ std::vector<RtpExtension> MakeUniqueExtensions() {
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
result.push_back(RtpExtension(name, 1 + i));
|
||||
name[0]++;
|
||||
result.push_back(RtpExtension(name, 14 - i));
|
||||
result.push_back(RtpExtension(name, 255 - i));
|
||||
name[0]++;
|
||||
}
|
||||
return result;
|
||||
@ -40,7 +40,7 @@ std::vector<RtpExtension> MakeRedundantExtensions() {
|
||||
char name[] = "a";
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
result.push_back(RtpExtension(name, 1 + i));
|
||||
result.push_back(RtpExtension(name, 14 - i));
|
||||
result.push_back(RtpExtension(name, 255 - i));
|
||||
name[0]++;
|
||||
}
|
||||
return result;
|
||||
@ -84,7 +84,7 @@ TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_Low) {
|
||||
|
||||
TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_High) {
|
||||
std::vector<RtpExtension> extensions = MakeUniqueExtensions();
|
||||
extensions.push_back(RtpExtension("foo", 15));
|
||||
extensions.push_back(RtpExtension("foo", 256));
|
||||
EXPECT_FALSE(ValidateRtpExtensions(extensions));
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_StartOfSet) {
|
||||
|
||||
TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_EndOfSet) {
|
||||
std::vector<RtpExtension> extensions = MakeUniqueExtensions();
|
||||
extensions.push_back(RtpExtension("foo", 14));
|
||||
extensions.push_back(RtpExtension("foo", 255));
|
||||
EXPECT_FALSE(ValidateRtpExtensions(extensions));
|
||||
}
|
||||
|
||||
|
||||
@ -62,8 +62,6 @@ class RtpHeaderExtensionMap {
|
||||
int32_t Deregister(RTPExtensionType type);
|
||||
|
||||
private:
|
||||
static constexpr int kMinId = 1;
|
||||
static constexpr int kMaxId = 14;
|
||||
bool Register(int id, RTPExtensionType type, const char* uri);
|
||||
|
||||
uint8_t ids_[kRtpExtensionNumberOfExtensions];
|
||||
|
||||
@ -55,8 +55,6 @@ static_assert(arraysize(kExtensions) ==
|
||||
|
||||
constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType;
|
||||
constexpr int RtpHeaderExtensionMap::kInvalidId;
|
||||
constexpr int RtpHeaderExtensionMap::kMinId;
|
||||
constexpr int RtpHeaderExtensionMap::kMaxId;
|
||||
|
||||
RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
|
||||
for (auto& id : ids_)
|
||||
@ -88,8 +86,8 @@ bool RtpHeaderExtensionMap::RegisterByUri(int id, const std::string& uri) {
|
||||
}
|
||||
|
||||
RTPExtensionType RtpHeaderExtensionMap::GetType(int id) const {
|
||||
RTC_DCHECK_GE(id, kMinId);
|
||||
RTC_DCHECK_LE(id, kMaxId);
|
||||
RTC_DCHECK_GE(id, RtpExtension::kMinId);
|
||||
RTC_DCHECK_LE(id, RtpExtension::kMaxId);
|
||||
for (int type = kRtpExtensionNone + 1; type < kRtpExtensionNumberOfExtensions;
|
||||
++type) {
|
||||
if (ids_[type] == id) {
|
||||
@ -101,14 +99,16 @@ RTPExtensionType RtpHeaderExtensionMap::GetType(int id) const {
|
||||
|
||||
size_t RtpHeaderExtensionMap::GetTotalLengthInBytes(
|
||||
rtc::ArrayView<const RtpExtensionSize> extensions) const {
|
||||
// TODO(webrtc:7990): This function must be updated when we start to send
|
||||
// two-byte header extensions.
|
||||
// Header size of the extension block, see RFC3550 Section 5.3.1
|
||||
static constexpr size_t kRtpOneByteHeaderLength = 4;
|
||||
// Header size of each individual extension, see RFC5285 Section 4.2
|
||||
static constexpr size_t kExtensionHeaderLength = 1;
|
||||
// Header size of each individual extension, see RFC8285 Section 4.2-4.3.
|
||||
static constexpr size_t kOneByteExtensionHeaderLength = 1;
|
||||
size_t values_size = 0;
|
||||
for (const RtpExtensionSize& extension : extensions) {
|
||||
if (IsRegistered(extension.type))
|
||||
values_size += extension.value_size + kExtensionHeaderLength;
|
||||
values_size += extension.value_size + kOneByteExtensionHeaderLength;
|
||||
}
|
||||
if (values_size == 0)
|
||||
return 0;
|
||||
@ -131,7 +131,7 @@ bool RtpHeaderExtensionMap::Register(int id,
|
||||
RTC_DCHECK_GT(type, kRtpExtensionNone);
|
||||
RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
|
||||
|
||||
if (id < kMinId || id > kMaxId) {
|
||||
if (id < RtpExtension::kMinId || id > RtpExtension::kMaxId) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
|
||||
<< "' with invalid id:" << id << ".";
|
||||
return false;
|
||||
|
||||
@ -57,11 +57,18 @@ TEST(RtpHeaderExtensionTest, RegisterDuringContruction) {
|
||||
EXPECT_EQ(3, map.GetId(AbsoluteSendTime::kId));
|
||||
}
|
||||
|
||||
TEST(RtpHeaderExtensionTest, RegisterTwoByteHeaderExtensions) {
|
||||
RtpHeaderExtensionMap map;
|
||||
// Two-byte header extension needed for id: [15-255].
|
||||
EXPECT_TRUE(map.Register<TransmissionOffset>(18));
|
||||
EXPECT_TRUE(map.Register<AbsoluteSendTime>(255));
|
||||
}
|
||||
|
||||
TEST(RtpHeaderExtensionTest, RegisterIllegalArg) {
|
||||
RtpHeaderExtensionMap map;
|
||||
// Valid range for id: [1-14].
|
||||
// Valid range for id: [1-255].
|
||||
EXPECT_FALSE(map.Register<TransmissionOffset>(0));
|
||||
EXPECT_FALSE(map.Register<TransmissionOffset>(15));
|
||||
EXPECT_FALSE(map.Register<TransmissionOffset>(256));
|
||||
}
|
||||
|
||||
TEST(RtpHeaderExtensionTest, Idempotent) {
|
||||
|
||||
@ -19,7 +19,7 @@ namespace webrtc {
|
||||
// Absolute send time in RTP streams.
|
||||
//
|
||||
// The absolute send time is signaled to the receiver in-band using the
|
||||
// general mechanism for RTP header extensions [RFC5285]. The payload
|
||||
// general mechanism for RTP header extensions [RFC8285]. The payload
|
||||
// of this extension (the transmitted value) is a 24-bit unsigned integer
|
||||
// containing the sender's current time in seconds as a fixed point number
|
||||
// with 18 bits fractional part.
|
||||
@ -89,7 +89,7 @@ bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
|
||||
// From RFC 5450: Transmission Time Offsets in RTP Streams.
|
||||
//
|
||||
// The transmission time is signaled to the receiver in-band using the
|
||||
// general mechanism for RTP header extensions [RFC5285]. The payload
|
||||
// general mechanism for RTP header extensions [RFC8285]. The payload
|
||||
// of this extension (the transmitted value) is a 24-bit signed integer.
|
||||
// When added to the RTP timestamp of the packet, it represents the
|
||||
// "effective" RTP transmission time of the packet, on the RTP
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "api/rtpparameters.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
@ -25,15 +25,13 @@ namespace webrtc {
|
||||
namespace {
|
||||
constexpr size_t kFixedHeaderSize = 12;
|
||||
constexpr uint8_t kRtpVersion = 2;
|
||||
constexpr uint16_t kOneByteExtensionId = 0xBEDE;
|
||||
constexpr size_t kOneByteHeaderSize = 1;
|
||||
constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
|
||||
constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
|
||||
constexpr size_t kOneByteExtensionHeaderLength = 1;
|
||||
constexpr size_t kTwoByteExtensionHeaderLength = 2;
|
||||
constexpr size_t kDefaultPacketSize = 1500;
|
||||
} // namespace
|
||||
|
||||
constexpr int RtpPacket::kMaxExtensionHeaders;
|
||||
constexpr int RtpPacket::kMinExtensionId;
|
||||
constexpr int RtpPacket::kMaxExtensionId;
|
||||
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@ -46,7 +44,7 @@ constexpr int RtpPacket::kMaxExtensionId;
|
||||
// | Contributing source (CSRC) identifiers |
|
||||
// | .... |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// |One-byte eXtensions id = 0xbede| length in 32bits |
|
||||
// | header eXtension profile id | length in 32bits |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Extensions |
|
||||
// | .... |
|
||||
@ -179,8 +177,8 @@ void RtpPacket::SetCsrcs(rtc::ArrayView<const uint32_t> csrcs) {
|
||||
}
|
||||
|
||||
rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
|
||||
RTC_DCHECK_GE(id, kMinExtensionId);
|
||||
RTC_DCHECK_LE(id, kMaxExtensionId);
|
||||
RTC_DCHECK_GE(id, RtpExtension::kMinId);
|
||||
RTC_DCHECK_LE(id, RtpExtension::kOneByteHeaderExtensionMaxId);
|
||||
RTC_DCHECK_GE(length, 1);
|
||||
RTC_DCHECK_LE(length, 16);
|
||||
|
||||
@ -209,7 +207,8 @@ rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
|
||||
|
||||
size_t num_csrc = data()[0] & 0x0F;
|
||||
size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
|
||||
size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
|
||||
size_t new_extensions_size =
|
||||
extensions_size_ + kOneByteExtensionHeaderLength + length;
|
||||
if (extensions_offset + new_extensions_size > capacity()) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "Extension cannot be registered: Not enough space left in buffer.";
|
||||
@ -222,7 +221,7 @@ rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
|
||||
WriteAt(0, data()[0] | 0x10); // Set extension bit.
|
||||
// Profile specific ID always set to OneByteExtensionHeader.
|
||||
ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
|
||||
kOneByteExtensionId);
|
||||
kOneByteExtensionProfileId);
|
||||
}
|
||||
|
||||
uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
|
||||
@ -230,7 +229,7 @@ rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
|
||||
WriteAt(extensions_offset + extensions_size_, one_byte_header);
|
||||
|
||||
const uint16_t extension_info_offset = rtc::dchecked_cast<uint16_t>(
|
||||
extensions_offset + extensions_size_ + kOneByteHeaderSize);
|
||||
extensions_offset + extensions_size_ + kOneByteExtensionHeaderLength);
|
||||
const uint8_t extension_info_length = rtc::dchecked_cast<uint8_t>(length);
|
||||
extension_entries_.emplace_back(id, extension_info_length,
|
||||
extension_info_offset);
|
||||
@ -366,22 +365,36 @@ bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
|
||||
if (extension_offset + extensions_capacity > size) {
|
||||
return false;
|
||||
}
|
||||
if (profile != kOneByteExtensionId) {
|
||||
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;
|
||||
constexpr uint8_t kPaddingId = 0;
|
||||
constexpr uint8_t kReservedId = 15;
|
||||
while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
|
||||
int id = buffer[extension_offset + extensions_size_] >> 4;
|
||||
if (id == kReservedId) {
|
||||
break;
|
||||
} else if (id == kPaddingId) {
|
||||
constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
|
||||
while (extensions_size_ + extension_header_length < extensions_capacity) {
|
||||
if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
|
||||
extensions_size_++;
|
||||
continue;
|
||||
}
|
||||
uint8_t length =
|
||||
1 + (buffer[extension_offset + extensions_size_] & 0xf);
|
||||
if (extensions_size_ + kOneByteHeaderSize + length >
|
||||
int id;
|
||||
uint8_t length;
|
||||
if (profile == kOneByteExtensionProfileId) {
|
||||
id = buffer[extension_offset + extensions_size_] >> 4;
|
||||
length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
|
||||
if (id == kOneByteHeaderExtensionReservedId ||
|
||||
(id == kPaddingId && length != 1)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
id = buffer[extension_offset + extensions_size_];
|
||||
length = buffer[extension_offset + extensions_size_ + 1];
|
||||
}
|
||||
|
||||
if (extensions_size_ + extension_header_length + length >
|
||||
extensions_capacity) {
|
||||
RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
|
||||
break;
|
||||
@ -394,14 +407,14 @@ bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
|
||||
}
|
||||
|
||||
size_t offset =
|
||||
extension_offset + extensions_size_ + kOneByteHeaderSize;
|
||||
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_ += kOneByteHeaderSize + length;
|
||||
extensions_size_ += extension_header_length + length;
|
||||
}
|
||||
}
|
||||
payload_offset_ = extension_offset + extensions_capacity;
|
||||
|
||||
@ -24,9 +24,6 @@ class RtpPacket {
|
||||
public:
|
||||
using ExtensionType = RTPExtensionType;
|
||||
using ExtensionManager = RtpHeaderExtensionMap;
|
||||
static constexpr int kMaxExtensionHeaders = 14;
|
||||
static constexpr int kMinExtensionId = 1;
|
||||
static constexpr int kMaxExtensionId = 14;
|
||||
|
||||
// |extensions| required for SetExtension/ReserveExtension functions during
|
||||
// packet creating and used if available in Parse function.
|
||||
|
||||
@ -33,11 +33,13 @@ constexpr uint8_t kAudioLevelExtensionId = 9;
|
||||
constexpr uint8_t kRtpStreamIdExtensionId = 0xa;
|
||||
constexpr uint8_t kRtpMidExtensionId = 0xb;
|
||||
constexpr uint8_t kVideoTimingExtensionId = 0xc;
|
||||
constexpr uint8_t kTwoByteExtensionId = 0xf0;
|
||||
constexpr int32_t kTimeOffset = 0x56ce;
|
||||
constexpr bool kVoiceActive = true;
|
||||
constexpr uint8_t kAudioLevel = 0x5a;
|
||||
constexpr char kStreamId[] = "streamid";
|
||||
constexpr char kMid[] = "mid";
|
||||
constexpr char kLongMid[] = "extra-long string to test two-byte header";
|
||||
constexpr size_t kMaxPaddingSize = 224u;
|
||||
// clang-format off
|
||||
constexpr uint8_t kMinimumPacket[] = {
|
||||
@ -60,6 +62,24 @@ constexpr uint8_t kPacketWithTOAndAL[] = {
|
||||
0x12, 0x00, 0x56, 0xce,
|
||||
0x90, 0x80|kAudioLevel, 0x00, 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithTOAndALInvalidPadding[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0xbe, 0xde, 0x00, 0x03,
|
||||
0x12, 0x00, 0x56, 0xce,
|
||||
0x00, 0x02, 0x00, 0x00, // 0x02 is invalid padding, parsing should stop.
|
||||
0x90, 0x80|kAudioLevel, 0x00, 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithTOAndALReservedExtensionId[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0xbe, 0xde, 0x00, 0x03,
|
||||
0x12, 0x00, 0x56, 0xce,
|
||||
0x00, 0xF0, 0x00, 0x00, // F is a reserved id, parsing should stop.
|
||||
0x90, 0x80|kAudioLevel, 0x00, 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithRsid[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
@ -90,6 +110,35 @@ constexpr uint8_t kPacket[] = {
|
||||
'p', 'a', 'y', 'l', 'o', 'a', 'd',
|
||||
'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
|
||||
|
||||
constexpr uint8_t kPacketWithTwoByteHeaderExtension[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0x10, 0x00, 0x00, 0x02, // Two-byte header extension profile id + length.
|
||||
kTwoByteExtensionId, 0x03, 0x00, 0x56,
|
||||
0xce, 0x00, 0x00, 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithLongTwoByteHeaderExtension[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0x10, 0x00, 0x00, 0x0B, // Two-byte header extension profile id + length.
|
||||
kTwoByteExtensionId, 0x29, 'e', 'x',
|
||||
't', 'r', 'a', '-', 'l', 'o', 'n', 'g',
|
||||
' ', 's', 't', 'r', 'i', 'n', 'g', ' ',
|
||||
't', 'o', ' ', 't', 'e', 's', 't', ' ',
|
||||
't', 'w', 'o', '-', 'b', 'y', 't', 'e',
|
||||
' ', 'h', 'e', 'a', 'd', 'e', 'r', 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithTwoByteHeaderExtensionWithPadding[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0x10, 0x00, 0x00, 0x03, // Two-byte header extension profile id + length.
|
||||
kTwoByteExtensionId, 0x03, 0x00, 0x56,
|
||||
0xce, 0x00, 0x00, 0x00, // Three padding bytes.
|
||||
kAudioLevelExtensionId, 0x01, 0x80|kAudioLevel, 0x00};
|
||||
|
||||
constexpr uint8_t kPacketWithInvalidExtension[] = {
|
||||
0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
|
||||
0x65, 0x43, 0x12, 0x78, // kTimestamp.
|
||||
@ -381,6 +430,38 @@ TEST(RtpPacketTest, ParseSecondPacketWithFewerExtensions) {
|
||||
EXPECT_FALSE(packet.HasExtension<AudioLevel>());
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseWith2ExtensionsInvalidPadding) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionTransmissionTimeOffset,
|
||||
kTransmissionOffsetExtensionId);
|
||||
extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
|
||||
RtpPacketReceived packet(&extensions);
|
||||
EXPECT_TRUE(packet.Parse(kPacketWithTOAndALInvalidPadding,
|
||||
sizeof(kPacketWithTOAndALInvalidPadding)));
|
||||
int32_t time_offset;
|
||||
EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
|
||||
EXPECT_EQ(kTimeOffset, time_offset);
|
||||
bool voice_active;
|
||||
uint8_t audio_level;
|
||||
EXPECT_FALSE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseWith2ExtensionsReservedExtensionId) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionTransmissionTimeOffset,
|
||||
kTransmissionOffsetExtensionId);
|
||||
extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
|
||||
RtpPacketReceived packet(&extensions);
|
||||
EXPECT_TRUE(packet.Parse(kPacketWithTOAndALReservedExtensionId,
|
||||
sizeof(kPacketWithTOAndALReservedExtensionId)));
|
||||
int32_t time_offset;
|
||||
EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
|
||||
EXPECT_EQ(kTimeOffset, time_offset);
|
||||
bool voice_active;
|
||||
uint8_t audio_level;
|
||||
EXPECT_FALSE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseWithAllFeatures) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionTransmissionTimeOffset,
|
||||
@ -398,6 +479,46 @@ TEST(RtpPacketTest, ParseWithAllFeatures) {
|
||||
EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseTwoByteHeaderExtension) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionTransmissionTimeOffset, kTwoByteExtensionId);
|
||||
RtpPacketReceived packet(&extensions);
|
||||
EXPECT_TRUE(packet.Parse(kPacketWithTwoByteHeaderExtension,
|
||||
sizeof(kPacketWithTwoByteHeaderExtension)));
|
||||
int32_t time_offset;
|
||||
EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
|
||||
EXPECT_EQ(kTimeOffset, time_offset);
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseLongTwoByteHeaderExtension) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionMid, kTwoByteExtensionId);
|
||||
RtpPacketReceived packet(&extensions);
|
||||
EXPECT_TRUE(packet.Parse(kPacketWithLongTwoByteHeaderExtension,
|
||||
sizeof(kPacketWithLongTwoByteHeaderExtension)));
|
||||
std::string long_rtp_mid;
|
||||
EXPECT_TRUE(packet.GetExtension<RtpMid>(&long_rtp_mid));
|
||||
EXPECT_EQ(kLongMid, long_rtp_mid);
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseTwoByteHeaderExtensionWithPadding) {
|
||||
RtpPacketToSend::ExtensionManager extensions;
|
||||
extensions.Register(kRtpExtensionTransmissionTimeOffset, kTwoByteExtensionId);
|
||||
extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
|
||||
RtpPacketReceived packet(&extensions);
|
||||
EXPECT_TRUE(
|
||||
packet.Parse(kPacketWithTwoByteHeaderExtensionWithPadding,
|
||||
sizeof(kPacketWithTwoByteHeaderExtensionWithPadding)));
|
||||
int32_t time_offset;
|
||||
EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
|
||||
EXPECT_EQ(kTimeOffset, time_offset);
|
||||
bool voice_active;
|
||||
uint8_t audio_level;
|
||||
EXPECT_TRUE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
|
||||
EXPECT_EQ(kVoiceActive, voice_active);
|
||||
EXPECT_EQ(kAudioLevel, audio_level);
|
||||
}
|
||||
|
||||
TEST(RtpPacketTest, ParseWithExtensionDelayed) {
|
||||
RtpPacketReceived packet;
|
||||
EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
|
||||
|
||||
@ -388,12 +388,16 @@ class UsedPayloadTypes : public UsedIds<Codec> {
|
||||
};
|
||||
|
||||
// Helper class used for finding duplicate RTP Header extension ids among
|
||||
// audio and video extensions.
|
||||
// audio and video extensions. Only applies to one-byte header extensions at the
|
||||
// moment. ids > 14 will always be reported as available.
|
||||
// TODO(kron): This class needs to be refactored when we start to send two-byte
|
||||
// header extensions.
|
||||
class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
|
||||
public:
|
||||
UsedRtpHeaderExtensionIds()
|
||||
: UsedIds<webrtc::RtpExtension>(webrtc::RtpExtension::kMinId,
|
||||
webrtc::RtpExtension::kMaxId) {}
|
||||
: UsedIds<webrtc::RtpExtension>(
|
||||
webrtc::RtpExtension::kMinId,
|
||||
webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
@ -279,24 +279,28 @@ TEST(RtpParametersConversionTest, ToCricketCodecsDuplicatePayloadType) {
|
||||
|
||||
TEST(RtpParametersConversionTest, ToCricketRtpHeaderExtensions) {
|
||||
std::vector<RtpHeaderExtensionParameters> extensions = {
|
||||
{"http://example.com", 1}, {"urn:foo:bar", 14}};
|
||||
{"http://example.com", 1},
|
||||
{"urn:foo:bar", 14},
|
||||
{"urn:first:two-byte-only:id", 15}};
|
||||
auto result = ToCricketRtpHeaderExtensions(extensions);
|
||||
ASSERT_TRUE(result.ok());
|
||||
ASSERT_EQ(2u, result.value().size());
|
||||
ASSERT_EQ(3u, result.value().size());
|
||||
EXPECT_EQ("http://example.com", result.value()[0].uri);
|
||||
EXPECT_EQ(1, result.value()[0].id);
|
||||
EXPECT_EQ("urn:foo:bar", result.value()[1].uri);
|
||||
EXPECT_EQ(14, result.value()[1].id);
|
||||
EXPECT_EQ("urn:first:two-byte-only:id", result.value()[2].uri);
|
||||
EXPECT_EQ(15, result.value()[2].id);
|
||||
}
|
||||
|
||||
TEST(RtpParametersConversionTest, ToCricketRtpHeaderExtensionsErrors) {
|
||||
// First, IDs outside the range 1-14.
|
||||
// First, IDs outside the range 1-255.
|
||||
std::vector<RtpHeaderExtensionParameters> extensions = {
|
||||
{"http://example.com", 0}};
|
||||
auto result = ToCricketRtpHeaderExtensions(extensions);
|
||||
EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type());
|
||||
|
||||
extensions[0].id = 15;
|
||||
extensions[0].id = 256;
|
||||
result = ToCricketRtpHeaderExtensions(extensions);
|
||||
EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.error().type());
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user