From 30933904797ab220a7a1532a535904f9d8ee3149 Mon Sep 17 00:00:00 2001 From: "sprang@webrtc.org" Date: Tue, 17 Mar 2015 14:33:12 +0000 Subject: [PATCH] Parsing of transport wide sequence number rtp extension header. Plus some refactoring to correctly handle padding. BUG=4311 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/45429004 Cr-Commit-Position: refs/heads/master@{#8757} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8757 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/common_types.cc | 13 +++ webrtc/common_types.h | 12 +-- .../rtp_rtcp/interface/rtp_rtcp_defines.h | 3 +- .../rtp_rtcp/source/rtp_header_extension.cc | 3 + .../rtp_rtcp/source/rtp_header_extension.h | 12 ++- webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 95 ++++++++++++------- webrtc/modules/rtp_rtcp/source/rtp_sender.h | 3 + .../rtp_rtcp/source/rtp_sender_unittest.cc | 70 ++++++++++---- webrtc/modules/rtp_rtcp/source/rtp_utility.cc | 45 +++++++-- webrtc/modules/rtp_rtcp/source/rtp_utility.h | 3 + 10 files changed, 178 insertions(+), 81 deletions(-) diff --git a/webrtc/common_types.cc b/webrtc/common_types.cc index bffc3ee515..b67c18c986 100644 --- a/webrtc/common_types.cc +++ b/webrtc/common_types.cc @@ -20,6 +20,19 @@ int OutStream::Rewind() { return -1; } StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {} +RTPHeaderExtension::RTPHeaderExtension() + : hasTransmissionTimeOffset(false), + transmissionTimeOffset(0), + hasAbsoluteSendTime(false), + absoluteSendTime(0), + hasTransportSequenceNumber(false), + transportSequenceNumber(0), + hasAudioLevel(false), + audioLevel(0), + hasVideoRotation(false), + videoRotation(0) { +} + RTPHeader::RTPHeader() : markerBit(false), payloadType(0), diff --git a/webrtc/common_types.h b/webrtc/common_types.h index f3f84dee40..d8317efd31 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -792,20 +792,14 @@ struct PacketTime { }; struct RTPHeaderExtension { - RTPHeaderExtension() - : hasTransmissionTimeOffset(false), - transmissionTimeOffset(0), - hasAbsoluteSendTime(false), - absoluteSendTime(0), - hasAudioLevel(false), - audioLevel(0), - hasVideoRotation(false), - videoRotation(0) {} + RTPHeaderExtension(); bool hasTransmissionTimeOffset; int32_t transmissionTimeOffset; bool hasAbsoluteSendTime; uint32_t absoluteSendTime; + bool hasTransportSequenceNumber; + uint16_t transportSequenceNumber; // Audio Level includes both level in dBov and voiced/unvoiced bit. See: // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/ diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index d15f31d2e3..8431fe3b50 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -79,7 +79,8 @@ enum RTPExtensionType { kRtpExtensionTransmissionTimeOffset, kRtpExtensionAudioLevel, kRtpExtensionAbsoluteSendTime, - kRtpExtensionVideoRotation + kRtpExtensionVideoRotation, + kRtpExtensionTransportSequenceNumber, }; enum RTCPAppSubTypes diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc index a19eeaa805..e8109fad5f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc @@ -12,6 +12,7 @@ #include "webrtc/common_types.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" namespace webrtc { @@ -119,6 +120,8 @@ size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const { if (length > 0) { length += kRtpOneByteHeaderLength; } + // Pad up to nearest 32bit word. + length = RtpUtility::Word32Align(length); return length; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h index 36c2f73031..cb49ea74cc 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h @@ -22,9 +22,10 @@ const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE; const size_t kRtpOneByteHeaderLength = 4; const size_t kTransmissionTimeOffsetLength = 4; -const size_t kAudioLevelLength = 4; +const size_t kAudioLevelLength = 2; const size_t kAbsoluteSendTimeLength = 4; -const size_t kVideoRotationLength = 4; +const size_t kVideoRotationLength = 2; +const size_t kTransportSequenceNumberLength = 3; struct HeaderExtension { HeaderExtension(RTPExtensionType extension_type) @@ -46,13 +47,16 @@ struct HeaderExtension { case kRtpExtensionVideoRotation: length = kVideoRotationLength; break; + case kRtpExtensionTransportSequenceNumber: + length = kTransportSequenceNumberLength; + break; default: assert(false); } } - const RTPExtensionType type; - uint8_t length; + const RTPExtensionType type; + uint8_t length; }; class RtpHeaderExtensionMap { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index c01cb361d7..30804f9ce0 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -128,6 +128,7 @@ RTPSender::RTPSender(int32_t id, transmission_time_offset_(0), absolute_send_time_(0), rotation_(kVideoRotation_0), + transport_sequence_number_(0), // NACK. nack_byte_count_times_(), nack_byte_count_(), @@ -255,6 +256,12 @@ void RTPSender::SetVideoRotation(VideoRotation rotation) { rotation_ = rotation; } +int32_t RTPSender::SetTransportSequenceNumber(uint16_t sequence_number) { + CriticalSectionScoped cs(send_critsect_.get()); + transport_sequence_number_ = sequence_number; + return 0; +} + int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id) { CriticalSectionScoped cs(send_critsect_.get()); @@ -1180,24 +1187,23 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, RTPExtensionType type = rtp_header_extension_map_.First(); while (type != kRtpExtensionNone) { uint8_t block_length = 0; + uint8_t* extension_data = &data_buffer[kHeaderLength + total_block_length]; switch (type) { case kRtpExtensionTransmissionTimeOffset: - block_length = BuildTransmissionTimeOffsetExtension( - data_buffer + kHeaderLength + total_block_length); + block_length = BuildTransmissionTimeOffsetExtension(extension_data); break; case kRtpExtensionAudioLevel: - block_length = BuildAudioLevelExtension( - data_buffer + kHeaderLength + total_block_length); + block_length = BuildAudioLevelExtension(extension_data); break; case kRtpExtensionAbsoluteSendTime: - block_length = BuildAbsoluteSendTimeExtension( - data_buffer + kHeaderLength + total_block_length); + block_length = BuildAbsoluteSendTimeExtension(extension_data); break; case kRtpExtensionVideoRotation: - if (marker_bit) { - block_length = BuildVideoRotationExtension( - data_buffer + kHeaderLength + total_block_length); - } + if (marker_bit) + block_length = BuildVideoRotationExtension(extension_data); + break; + case kRtpExtensionTransportSequenceNumber: + block_length = BuildTransportSequenceNumberExtension(extension_data); break; default: assert(false); @@ -1209,8 +1215,14 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, // No extension added. return 0; } + // Add padding elements until we've filled a 32 bit block. + size_t padding_bytes = + RtpUtility::Word32Align(total_block_length) - total_block_length; + if (padding_bytes > 0) { + memset(&data_buffer[kHeaderLength + total_block_length], 0, padding_bytes); + total_block_length += padding_bytes; + } // Set header length (in number of Word32, header excluded). - assert(total_block_length % 4 == 0); RtpUtility::AssignUWord16ToBuffer(data_buffer + kPosLength, total_block_length / 4); // Total added length. @@ -1260,16 +1272,12 @@ uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const { // // The form of the audio level extension block: // - // 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 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | len=0 |V| level | 0x00 | 0x00 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |V| level | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // - // Note that we always include 2 pad bytes, which will result in legal and - // correctly parsed RTP, but may be a bit wasteful if more short extensions - // are implemented. Right now the pad bytes would anyway be required at end - // of the extension block, so it makes no difference. // Get id defined by user. uint8_t id; @@ -1281,9 +1289,6 @@ uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const { const uint8_t len = 0; data_buffer[pos++] = (id << 4) + len; data_buffer[pos++] = (1 << 7) + 0; // Voice, 0 dBov. - data_buffer[pos++] = 0; // Padding. - data_buffer[pos++] = 0; // Padding. - // kAudioLevelLength is including pad bytes. assert(pos == kAudioLevelLength); return kAudioLevelLength; } @@ -1324,20 +1329,15 @@ uint8_t RTPSender::BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const { uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const { // Coordination of Video Orientation in RTP streams. // - // Coordination of Video Orientation consists in signalling of the current + // Coordination of Video Orientation consists in signaling of the current // orientation of the image captured on the sender side to the receiver for // appropriate rendering and displaying. // - // 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 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | len=0 |V|0 0 0 0 C F R R| 0x00 | 0x00 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // - // Note that we always include 2 pad bytes, which will result in legal and - // correctly parsed RTP, but may be a bit wasteful if more short extensions - // are implemented. Right now the pad bytes would anyway be required at end - // of the extension block, so it makes no difference. + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |0 0 0 0 C F R R| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Get id defined by user. @@ -1350,12 +1350,35 @@ uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const { const uint8_t len = 0; data_buffer[pos++] = (id << 4) + len; data_buffer[pos++] = ConvertVideoRotationToCVOByte(rotation_); - data_buffer[pos++] = 0; // padding - data_buffer[pos++] = 0; // padding assert(pos == kVideoRotationLength); return kVideoRotationLength; } +uint8_t RTPSender::BuildTransportSequenceNumberExtension( + uint8_t* data_buffer) const { + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=1 |transport wide sequence number | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Get id defined by user. + uint8_t id; + if (rtp_header_extension_map_.GetId(kRtpExtensionTransportSequenceNumber, + &id) != 0) { + // Not registered. + return 0; + } + size_t pos = 0; + const uint8_t len = 1; + data_buffer[pos++] = (id << 4) + len; + RtpUtility::AssignUWord16ToBuffer(data_buffer + pos, + transport_sequence_number_); + pos += 2; + assert(pos == kTransportSequenceNumberLength); + return kTransportSequenceNumberLength; +} + bool RTPSender::FindHeaderExtensionPosition(RTPExtensionType type, const uint8_t* rtp_packet, size_t rtp_packet_length, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 72763edf9d..baa067c5c0 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -153,6 +153,7 @@ class RTPSender : public RTPSenderInterface { int32_t SetTransmissionTimeOffset(int32_t transmission_time_offset); int32_t SetAbsoluteSendTime(uint32_t absolute_send_time); void SetVideoRotation(VideoRotation rotation); + int32_t SetTransportSequenceNumber(uint16_t sequence_number); int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); virtual bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) override; @@ -166,6 +167,7 @@ class RTPSender : public RTPSenderInterface { uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const; uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const; uint8_t BuildVideoRotationExtension(uint8_t* data_buffer) const; + uint8_t BuildTransportSequenceNumberExtension(uint8_t* data_buffer) const; bool UpdateAudioLevel(uint8_t* rtp_packet, size_t rtp_packet_length, @@ -376,6 +378,7 @@ class RTPSender : public RTPSenderInterface { int32_t transmission_time_offset_; uint32_t absolute_send_time_; VideoRotation rotation_; + uint16_t transport_sequence_number_; // NACK uint32_t nack_byte_count_times_[NACK_BYTECOUNT_SIZE]; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index e5c3b6fee1..fa9fca5e38 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -25,6 +25,7 @@ #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" #include "webrtc/system_wrappers/interface/stl_util.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" #include "webrtc/test/mock_transport.h" #include "webrtc/typedefs.h" @@ -33,6 +34,7 @@ namespace webrtc { namespace { const int kTransmissionTimeOffsetExtensionId = 1; const int kAbsoluteSendTimeExtensionId = 14; +const int kTransportSequenceNumberExtensionId = 13; const int kPayload = 100; const uint32_t kTimestamp = 10; const uint16_t kSeqNum = 33; @@ -40,6 +42,7 @@ const int kTimeOffset = 22222; const int kMaxPacketLength = 1500; const uint32_t kAbsoluteSendTime = 0x00aabbcc; const uint8_t kAudioLevel = 0x5a; +const uint16_t kTransportSequenceNumber = 0xaabbu; const uint8_t kAudioLevelExtensionId = 9; const int kAudioPayload = 103; const uint64_t kStartTime = 123456789; @@ -210,7 +213,8 @@ TEST_F(RtpSenderTest, RegisterRtpAbsoluteSendTimeHeaderExtension) { EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength, + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kAbsoluteSendTimeLength), rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime)); @@ -221,8 +225,9 @@ TEST_F(RtpSenderTest, RegisterRtpAudioLevelHeaderExtension) { EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAudioLevel, kAudioLevelExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength, - rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ( + RtpUtility::Word32Align(kRtpOneByteHeaderLength + kAudioLevelLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionAudioLevel)); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); @@ -232,38 +237,46 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) { EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength, + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kTransmissionTimeOffsetLength), rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + - kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kTransmissionTimeOffsetLength + + kAbsoluteSendTimeLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAudioLevel, kAudioLevelExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + - kAbsoluteSendTimeLength + kAudioLevelLength, - rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ(RtpUtility::Word32Align( + kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + + kAbsoluteSendTimeLength + kAudioLevelLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionVideoRotation, kVideoRotationExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + - kAbsoluteSendTimeLength + kAudioLevelLength + - kVideoRotationLength, + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kTransmissionTimeOffsetLength + + kAbsoluteSendTimeLength + + kAudioLevelLength + kVideoRotationLength), rtp_sender_->RtpHeaderExtensionTotalLength()); // Deregister starts. EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset)); - EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength + - kAudioLevelLength + kVideoRotationLength, + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kAbsoluteSendTimeLength + + kAudioLevelLength + kVideoRotationLength), rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime)); - EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength + kVideoRotationLength, + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength + + kAudioLevelLength + kVideoRotationLength), rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( kRtpExtensionAudioLevel)); - EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, - rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ( + RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ( 0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation)); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); @@ -273,8 +286,9 @@ TEST_F(RtpSenderTest, RegisterRtpVideoRotationHeaderExtension) { EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionVideoRotation, kVideoRotationExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, - rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ( + RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ( 0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation)); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); @@ -500,12 +514,17 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAudioLevelExtension) { TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset)); EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime)); + EXPECT_EQ(0, + rtp_sender_->SetTransportSequenceNumber(kTransportSequenceNumber)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAudioLevel, kAudioLevelExtensionId)); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); size_t length = static_cast(rtp_sender_->BuildRTPheader( packet_, kPayload, kMarkerBit, kTimestamp, 0)); @@ -525,6 +544,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { kTransmissionTimeOffsetExtensionId); map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); + map.Register(kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); ASSERT_TRUE(valid_rtp_header); @@ -534,9 +555,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset); EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime); EXPECT_TRUE(rtp_header.extension.hasAudioLevel); + EXPECT_TRUE(rtp_header.extension.hasTransportSequenceNumber); EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset); EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel); + EXPECT_EQ(kTransportSequenceNumber, + rtp_header.extension.transportSequenceNumber); // Parse without map extension webrtc::RTPHeader rtp_header2; @@ -548,9 +572,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset); EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime); EXPECT_FALSE(rtp_header2.extension.hasAudioLevel); + EXPECT_FALSE(rtp_header2.extension.hasTransportSequenceNumber); + EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset); EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); EXPECT_EQ(0u, rtp_header2.extension.audioLevel); + EXPECT_EQ(0u, rtp_header2.extension.transportSequenceNumber); } TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) { @@ -1313,8 +1340,9 @@ TEST_F(RtpSenderVideoTest, SendVideoWithCVO) { EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionVideoRotation, kVideoRotationExtensionId)); - EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, - rtp_sender_->RtpHeaderExtensionTotalLength()); + EXPECT_EQ( + RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength), + rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, packet_, sizeof(packet_), NULL, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc index d26ceda3cf..e3be42663a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc @@ -184,6 +184,13 @@ uint32_t BufferToUWord32(const uint8_t* dataBuffer) { #endif } +size_t Word32Align(size_t size) { + uint32_t remainder = size % 4; + if (remainder != 0) + return size + 4 - remainder; + return size; +} + uint32_t pow2(uint8_t exp) { return 1 << exp; } @@ -480,11 +487,11 @@ void RtpHeaderParser::ParseOneByteExtensionHeader( LOG(LS_WARNING) << "Incorrect audio level len: " << len; return; } - // 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 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | len=0 |V| level | 0x00 | 0x00 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |V| level | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Parse out the fields but only use it for debugging for now. @@ -521,15 +528,33 @@ void RtpHeaderParser::ParseOneByteExtensionHeader( << "Incorrect coordination of video coordination len: " << len; return; } - // 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 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | len=0 |V|0 0 0 0 C F R R| 0x00 | 0x00 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |0 0 0 0 C F R R| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header.extension.hasVideoRotation = true; header.extension.videoRotation = ptr[0]; break; } + case kRtpExtensionTransportSequenceNumber: { + if (len != 1) { + LOG(LS_WARNING) + << "Incorrect peer connection sequence number len: " << len; + return; + } + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=1 |transport wide sequence number | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + uint16_t sequence_number = ptr[0] << 8; + sequence_number += ptr[1]; + header.extension.transportSequenceNumber = sequence_number; + header.extension.hasTransportSequenceNumber = true; + break; + } default: { LOG(LS_WARNING) << "Extension type not implemented: " << type; return; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_utility.h b/webrtc/modules/rtp_rtcp/source/rtp_utility.h index 3a3ad5ee36..4c8e3825cd 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_utility.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_utility.h @@ -91,6 +91,9 @@ namespace RtpUtility { */ uint32_t BufferToUWord32(const uint8_t* dataBuffer); + // Round up to the nearest size that is a multiple of 4. + size_t Word32Align(size_t size); + class RtpHeaderParser { public: RtpHeaderParser(const uint8_t* rtpData, size_t rtpDataLength);