diff --git a/api/rtpparameters.cc b/api/rtpparameters.cc index ebf595d051..af11770995 100644 --- a/api/rtpparameters.cc +++ b/api/rtpparameters.cc @@ -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 || diff --git a/api/rtpparameters.h b/api/rtpparameters.h index 70d7e007bc..d76ec9adb9 100644 --- a/api/rtpparameters.h +++ b/api/rtpparameters.h @@ -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; diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index 7a6573f7d6..9f6240cbe1 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -363,7 +363,8 @@ std::unique_ptr EventGenerator::NewRtpPacketOutgoing( RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap() { RtpHeaderExtensionMap extension_map; - std::vector id(RtpExtension::kMaxId - RtpExtension::kMinId + 1); + std::vector id(RtpExtension::kOneByteHeaderExtensionMaxId - + RtpExtension::kMinId + 1); std::iota(id.begin(), id.end(), RtpExtension::kMinId); ShuffleInPlace(&prng_, rtc::ArrayView(id)); diff --git a/media/engine/webrtcmediaengine.cc b/media/engine/webrtcmediaengine.cc index 82badc1044..e60c592a3f 100644 --- a/media/engine/webrtcmediaengine.cc +++ b/media/engine/webrtcmediaengine.cc @@ -138,18 +138,19 @@ void DiscardRedundantExtensions( bool ValidateRtpExtensions( const std::vector& 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; } diff --git a/media/engine/webrtcmediaengine_unittest.cc b/media/engine/webrtcmediaengine_unittest.cc index 446ad24e77..4fa9a6b5ee 100644 --- a/media/engine/webrtcmediaengine_unittest.cc +++ b/media/engine/webrtcmediaengine_unittest.cc @@ -29,7 +29,7 @@ std::vector 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 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 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 extensions = MakeUniqueExtensions(); - extensions.push_back(RtpExtension("foo", 14)); + extensions.push_back(RtpExtension("foo", 255)); EXPECT_FALSE(ValidateRtpExtensions(extensions)); } diff --git a/modules/rtp_rtcp/include/rtp_header_extension_map.h b/modules/rtp_rtcp/include/rtp_header_extension_map.h index f07da8bf6c..e76650d8ee 100644 --- a/modules/rtp_rtcp/include/rtp_header_extension_map.h +++ b/modules/rtp_rtcp/include/rtp_header_extension_map.h @@ -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]; diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/modules/rtp_rtcp/source/rtp_header_extension_map.cc index c756310298..093ffb3ce2 100644 --- a/modules/rtp_rtcp/source/rtp_header_extension_map.cc +++ b/modules/rtp_rtcp/source/rtp_header_extension_map.cc @@ -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 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; diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc b/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc index ad9f79c509..5dc16cec18 100644 --- a/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc @@ -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(18)); + EXPECT_TRUE(map.Register(255)); +} + TEST(RtpHeaderExtensionTest, RegisterIllegalArg) { RtpHeaderExtensionMap map; - // Valid range for id: [1-14]. + // Valid range for id: [1-255]. EXPECT_FALSE(map.Register(0)); - EXPECT_FALSE(map.Register(15)); + EXPECT_FALSE(map.Register(256)); } TEST(RtpHeaderExtensionTest, Idempotent) { diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc index e9e4d508de..f5aa38fd59 100644 --- a/modules/rtp_rtcp/source/rtp_header_extensions.cc +++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc @@ -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 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 diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc index aa8eb107f6..4df25c3d4d 100644 --- a/modules/rtp_rtcp/source/rtp_packet.cc +++ b/modules/rtp_rtcp/source/rtp_packet.cc @@ -13,8 +13,8 @@ #include #include +#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 csrcs) { } rtc::ArrayView 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 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 RtpPacket::AllocateRawExtension(int id, size_t length) { WriteAt(0, data()[0] | 0x10); // Set extension bit. // Profile specific ID always set to OneByteExtensionHeader. ByteWriter::WriteBigEndian(WriteAt(extensions_offset - 4), - kOneByteExtensionId); + kOneByteExtensionProfileId); } uint8_t one_byte_header = rtc::dchecked_cast(id) << 4; @@ -230,7 +229,7 @@ rtc::ArrayView RtpPacket::AllocateRawExtension(int id, size_t length) { WriteAt(extensions_offset + extensions_size_, one_byte_header); const uint16_t extension_info_offset = rtc::dchecked_cast( - extensions_offset + extensions_size_ + kOneByteHeaderSize); + extensions_offset + extensions_size_ + kOneByteExtensionHeaderLength); const uint8_t extension_info_length = rtc::dchecked_cast(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(offset)) { RTC_DLOG(LS_WARNING) << "Oversized rtp header extension."; break; } extension_info.offset = static_cast(offset); extension_info.length = length; - extensions_size_ += kOneByteHeaderSize + length; + extensions_size_ += extension_header_length + length; } } payload_offset_ = extension_offset + extensions_capacity; diff --git a/modules/rtp_rtcp/source/rtp_packet.h b/modules/rtp_rtcp/source/rtp_packet.h index 4a3b7e9543..ad421dc216 100644 --- a/modules/rtp_rtcp/source/rtp_packet.h +++ b/modules/rtp_rtcp/source/rtp_packet.h @@ -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. diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc index 0203cec988..67a13dc0fc 100644 --- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc @@ -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()); } +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(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + bool voice_active; + uint8_t audio_level; + EXPECT_FALSE(packet.GetExtension(&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(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + bool voice_active; + uint8_t audio_level; + EXPECT_FALSE(packet.GetExtension(&voice_active, &audio_level)); +} + TEST(RtpPacketTest, ParseWithAllFeatures) { RtpPacketToSend::ExtensionManager extensions; extensions.Register(kRtpExtensionTransmissionTimeOffset, @@ -398,6 +479,46 @@ TEST(RtpPacketTest, ParseWithAllFeatures) { EXPECT_TRUE(packet.GetExtension(&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(&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(&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(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + bool voice_active; + uint8_t audio_level; + EXPECT_TRUE(packet.GetExtension(&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))); diff --git a/pc/mediasession.cc b/pc/mediasession.cc index 29438321c2..9ae46be27c 100644 --- a/pc/mediasession.cc +++ b/pc/mediasession.cc @@ -388,12 +388,16 @@ class UsedPayloadTypes : public UsedIds { }; // 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 { public: UsedRtpHeaderExtensionIds() - : UsedIds(webrtc::RtpExtension::kMinId, - webrtc::RtpExtension::kMaxId) {} + : UsedIds( + webrtc::RtpExtension::kMinId, + webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {} private: }; diff --git a/pc/rtpparametersconversion_unittest.cc b/pc/rtpparametersconversion_unittest.cc index 649fe97191..257d26ebb5 100644 --- a/pc/rtpparametersconversion_unittest.cc +++ b/pc/rtpparametersconversion_unittest.cc @@ -279,24 +279,28 @@ TEST(RtpParametersConversionTest, ToCricketCodecsDuplicatePayloadType) { TEST(RtpParametersConversionTest, ToCricketRtpHeaderExtensions) { std::vector 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 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());