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
This commit is contained in:
sprang@webrtc.org 2015-03-17 14:33:12 +00:00
parent 1e6925274a
commit 3093390479
10 changed files with 178 additions and 81 deletions

View File

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

View File

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

View File

@ -79,7 +79,8 @@ enum RTPExtensionType {
kRtpExtensionTransmissionTimeOffset,
kRtpExtensionAudioLevel,
kRtpExtensionAbsoluteSendTime,
kRtpExtensionVideoRotation
kRtpExtensionVideoRotation,
kRtpExtensionTransportSequenceNumber,
};
enum RTCPAppSubTypes

View File

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

View File

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

View File

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

View File

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

View File

@ -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<size_t>(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,

View File

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

View File

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