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:
Johannes Kron 2018-09-26 13:33:35 +02:00 committed by Commit Bot
parent 78e0ac1b39
commit 07ba2b9445
14 changed files with 214 additions and 65 deletions

View File

@ -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 ||

View File

@ -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;

View File

@ -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));

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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];

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

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

View File

@ -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)));

View File

@ -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:
};

View File

@ -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());