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) {} 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() RTPHeader::RTPHeader()
: markerBit(false), : markerBit(false),
payloadType(0), payloadType(0),

View File

@ -792,20 +792,14 @@ struct PacketTime {
}; };
struct RTPHeaderExtension { struct RTPHeaderExtension {
RTPHeaderExtension() RTPHeaderExtension();
: hasTransmissionTimeOffset(false),
transmissionTimeOffset(0),
hasAbsoluteSendTime(false),
absoluteSendTime(0),
hasAudioLevel(false),
audioLevel(0),
hasVideoRotation(false),
videoRotation(0) {}
bool hasTransmissionTimeOffset; bool hasTransmissionTimeOffset;
int32_t transmissionTimeOffset; int32_t transmissionTimeOffset;
bool hasAbsoluteSendTime; bool hasAbsoluteSendTime;
uint32_t absoluteSendTime; uint32_t absoluteSendTime;
bool hasTransportSequenceNumber;
uint16_t transportSequenceNumber;
// Audio Level includes both level in dBov and voiced/unvoiced bit. See: // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/ // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/

View File

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

View File

@ -12,6 +12,7 @@
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
namespace webrtc { namespace webrtc {
@ -119,6 +120,8 @@ size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
if (length > 0) { if (length > 0) {
length += kRtpOneByteHeaderLength; length += kRtpOneByteHeaderLength;
} }
// Pad up to nearest 32bit word.
length = RtpUtility::Word32Align(length);
return length; return length;
} }

View File

@ -22,9 +22,10 @@ const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
const size_t kRtpOneByteHeaderLength = 4; const size_t kRtpOneByteHeaderLength = 4;
const size_t kTransmissionTimeOffsetLength = 4; const size_t kTransmissionTimeOffsetLength = 4;
const size_t kAudioLevelLength = 4; const size_t kAudioLevelLength = 2;
const size_t kAbsoluteSendTimeLength = 4; const size_t kAbsoluteSendTimeLength = 4;
const size_t kVideoRotationLength = 4; const size_t kVideoRotationLength = 2;
const size_t kTransportSequenceNumberLength = 3;
struct HeaderExtension { struct HeaderExtension {
HeaderExtension(RTPExtensionType extension_type) HeaderExtension(RTPExtensionType extension_type)
@ -46,13 +47,16 @@ struct HeaderExtension {
case kRtpExtensionVideoRotation: case kRtpExtensionVideoRotation:
length = kVideoRotationLength; length = kVideoRotationLength;
break; break;
case kRtpExtensionTransportSequenceNumber:
length = kTransportSequenceNumberLength;
break;
default: default:
assert(false); assert(false);
} }
} }
const RTPExtensionType type; const RTPExtensionType type;
uint8_t length; uint8_t length;
}; };
class RtpHeaderExtensionMap { class RtpHeaderExtensionMap {

View File

@ -128,6 +128,7 @@ RTPSender::RTPSender(int32_t id,
transmission_time_offset_(0), transmission_time_offset_(0),
absolute_send_time_(0), absolute_send_time_(0),
rotation_(kVideoRotation_0), rotation_(kVideoRotation_0),
transport_sequence_number_(0),
// NACK. // NACK.
nack_byte_count_times_(), nack_byte_count_times_(),
nack_byte_count_(), nack_byte_count_(),
@ -255,6 +256,12 @@ void RTPSender::SetVideoRotation(VideoRotation rotation) {
rotation_ = 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, int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
uint8_t id) { uint8_t id) {
CriticalSectionScoped cs(send_critsect_.get()); CriticalSectionScoped cs(send_critsect_.get());
@ -1180,24 +1187,23 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer,
RTPExtensionType type = rtp_header_extension_map_.First(); RTPExtensionType type = rtp_header_extension_map_.First();
while (type != kRtpExtensionNone) { while (type != kRtpExtensionNone) {
uint8_t block_length = 0; uint8_t block_length = 0;
uint8_t* extension_data = &data_buffer[kHeaderLength + total_block_length];
switch (type) { switch (type) {
case kRtpExtensionTransmissionTimeOffset: case kRtpExtensionTransmissionTimeOffset:
block_length = BuildTransmissionTimeOffsetExtension( block_length = BuildTransmissionTimeOffsetExtension(extension_data);
data_buffer + kHeaderLength + total_block_length);
break; break;
case kRtpExtensionAudioLevel: case kRtpExtensionAudioLevel:
block_length = BuildAudioLevelExtension( block_length = BuildAudioLevelExtension(extension_data);
data_buffer + kHeaderLength + total_block_length);
break; break;
case kRtpExtensionAbsoluteSendTime: case kRtpExtensionAbsoluteSendTime:
block_length = BuildAbsoluteSendTimeExtension( block_length = BuildAbsoluteSendTimeExtension(extension_data);
data_buffer + kHeaderLength + total_block_length);
break; break;
case kRtpExtensionVideoRotation: case kRtpExtensionVideoRotation:
if (marker_bit) { if (marker_bit)
block_length = BuildVideoRotationExtension( block_length = BuildVideoRotationExtension(extension_data);
data_buffer + kHeaderLength + total_block_length); break;
} case kRtpExtensionTransportSequenceNumber:
block_length = BuildTransportSequenceNumberExtension(extension_data);
break; break;
default: default:
assert(false); assert(false);
@ -1209,8 +1215,14 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer,
// No extension added. // No extension added.
return 0; 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). // Set header length (in number of Word32, header excluded).
assert(total_block_length % 4 == 0);
RtpUtility::AssignUWord16ToBuffer(data_buffer + kPosLength, RtpUtility::AssignUWord16ToBuffer(data_buffer + kPosLength,
total_block_length / 4); total_block_length / 4);
// Total added length. // Total added length.
@ -1260,16 +1272,12 @@ uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const {
// //
// The form of the audio level extension block: // The form of the audio level extension block:
// //
// 0 1 2 3 // 0 1
// 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 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V| level | 0x00 | 0x00 | // | 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. // Get id defined by user.
uint8_t id; uint8_t id;
@ -1281,9 +1289,6 @@ uint8_t RTPSender::BuildAudioLevelExtension(uint8_t* data_buffer) const {
const uint8_t len = 0; const uint8_t len = 0;
data_buffer[pos++] = (id << 4) + len; data_buffer[pos++] = (id << 4) + len;
data_buffer[pos++] = (1 << 7) + 0; // Voice, 0 dBov. 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); assert(pos == kAudioLevelLength);
return 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 { uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const {
// Coordination of Video Orientation in RTP streams. // 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 // orientation of the image captured on the sender side to the receiver for
// appropriate rendering and displaying. // appropriate rendering and displaying.
// //
// 0 1 2 3 // 0 1
// 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 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V|0 0 0 0 C F R R| 0x00 | 0x00 | // | ID | len=0 |0 0 0 0 C F R R|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// 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. // Get id defined by user.
@ -1350,12 +1350,35 @@ uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const {
const uint8_t len = 0; const uint8_t len = 0;
data_buffer[pos++] = (id << 4) + len; data_buffer[pos++] = (id << 4) + len;
data_buffer[pos++] = ConvertVideoRotationToCVOByte(rotation_); data_buffer[pos++] = ConvertVideoRotationToCVOByte(rotation_);
data_buffer[pos++] = 0; // padding
data_buffer[pos++] = 0; // padding
assert(pos == kVideoRotationLength); assert(pos == kVideoRotationLength);
return 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, bool RTPSender::FindHeaderExtensionPosition(RTPExtensionType type,
const uint8_t* rtp_packet, const uint8_t* rtp_packet,
size_t rtp_packet_length, 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 SetTransmissionTimeOffset(int32_t transmission_time_offset);
int32_t SetAbsoluteSendTime(uint32_t absolute_send_time); int32_t SetAbsoluteSendTime(uint32_t absolute_send_time);
void SetVideoRotation(VideoRotation rotation); void SetVideoRotation(VideoRotation rotation);
int32_t SetTransportSequenceNumber(uint16_t sequence_number);
int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id);
virtual bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) override; virtual bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) override;
@ -166,6 +167,7 @@ class RTPSender : public RTPSenderInterface {
uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const; uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const;
uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const; uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const;
uint8_t BuildVideoRotationExtension(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, bool UpdateAudioLevel(uint8_t* rtp_packet,
size_t rtp_packet_length, size_t rtp_packet_length,
@ -376,6 +378,7 @@ class RTPSender : public RTPSenderInterface {
int32_t transmission_time_offset_; int32_t transmission_time_offset_;
uint32_t absolute_send_time_; uint32_t absolute_send_time_;
VideoRotation rotation_; VideoRotation rotation_;
uint16_t transport_sequence_number_;
// NACK // NACK
uint32_t nack_byte_count_times_[NACK_BYTECOUNT_SIZE]; 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.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
#include "webrtc/system_wrappers/interface/stl_util.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/test/mock_transport.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
@ -33,6 +34,7 @@ namespace webrtc {
namespace { namespace {
const int kTransmissionTimeOffsetExtensionId = 1; const int kTransmissionTimeOffsetExtensionId = 1;
const int kAbsoluteSendTimeExtensionId = 14; const int kAbsoluteSendTimeExtensionId = 14;
const int kTransportSequenceNumberExtensionId = 13;
const int kPayload = 100; const int kPayload = 100;
const uint32_t kTimestamp = 10; const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33; const uint16_t kSeqNum = 33;
@ -40,6 +42,7 @@ const int kTimeOffset = 22222;
const int kMaxPacketLength = 1500; const int kMaxPacketLength = 1500;
const uint32_t kAbsoluteSendTime = 0x00aabbcc; const uint32_t kAbsoluteSendTime = 0x00aabbcc;
const uint8_t kAudioLevel = 0x5a; const uint8_t kAudioLevel = 0x5a;
const uint16_t kTransportSequenceNumber = 0xaabbu;
const uint8_t kAudioLevelExtensionId = 9; const uint8_t kAudioLevelExtensionId = 9;
const int kAudioPayload = 103; const int kAudioPayload = 103;
const uint64_t kStartTime = 123456789; const uint64_t kStartTime = 123456789;
@ -210,7 +213,8 @@ TEST_F(RtpSenderTest, RegisterRtpAbsoluteSendTimeHeaderExtension) {
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength, EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kAbsoluteSendTimeLength),
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime)); kRtpExtensionAbsoluteSendTime));
@ -221,8 +225,9 @@ TEST_F(RtpSenderTest, RegisterRtpAudioLevelHeaderExtension) {
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength, EXPECT_EQ(
rtp_sender_->RtpHeaderExtensionTotalLength()); RtpUtility::Word32Align(kRtpOneByteHeaderLength + kAudioLevelLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAudioLevel)); kRtpExtensionAudioLevel));
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
@ -232,38 +237,46 @@ TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) {
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength, EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kTransmissionTimeOffsetLength),
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); kTransmissionTimeOffsetLength +
kAbsoluteSendTimeLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + EXPECT_EQ(RtpUtility::Word32Align(
kAbsoluteSendTimeLength + kAudioLevelLength, kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength +
rtp_sender_->RtpHeaderExtensionTotalLength()); kAbsoluteSendTimeLength + kAudioLevelLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionVideoRotation, kVideoRotationExtensionId)); kRtpExtensionVideoRotation, kVideoRotationExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kAbsoluteSendTimeLength + kAudioLevelLength + kTransmissionTimeOffsetLength +
kVideoRotationLength, kAbsoluteSendTimeLength +
kAudioLevelLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
// Deregister starts. // Deregister starts.
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset)); kRtpExtensionTransmissionTimeOffset));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength + EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kAudioLevelLength + kVideoRotationLength, kAbsoluteSendTimeLength +
kAudioLevelLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime)); kRtpExtensionAbsoluteSendTime));
EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength + kVideoRotationLength, EXPECT_EQ(RtpUtility::Word32Align(kRtpOneByteHeaderLength +
kAudioLevelLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength()); rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAudioLevel)); kRtpExtensionAudioLevel));
EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, EXPECT_EQ(
rtp_sender_->RtpHeaderExtensionTotalLength()); RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ( EXPECT_EQ(
0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation)); 0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation));
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
@ -273,8 +286,9 @@ TEST_F(RtpSenderTest, RegisterRtpVideoRotationHeaderExtension) {
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionVideoRotation, kVideoRotationExtensionId)); kRtpExtensionVideoRotation, kVideoRotationExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, EXPECT_EQ(
rtp_sender_->RtpHeaderExtensionTotalLength()); RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ( EXPECT_EQ(
0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation)); 0, rtp_sender_->DeregisterRtpHeaderExtension(kRtpExtensionVideoRotation));
EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength()); EXPECT_EQ(0u, rtp_sender_->RtpHeaderExtensionTotalLength());
@ -500,12 +514,17 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithAudioLevelExtension) {
TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset)); EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime)); EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime));
EXPECT_EQ(0,
rtp_sender_->SetTransportSequenceNumber(kTransportSequenceNumber));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, kAudioLevelExtensionId)); kRtpExtensionAudioLevel, kAudioLevelExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber,
kTransportSequenceNumberExtensionId));
size_t length = static_cast<size_t>(rtp_sender_->BuildRTPheader( size_t length = static_cast<size_t>(rtp_sender_->BuildRTPheader(
packet_, kPayload, kMarkerBit, kTimestamp, 0)); packet_, kPayload, kMarkerBit, kTimestamp, 0));
@ -525,6 +544,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
kTransmissionTimeOffsetExtensionId); kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
map.Register(kRtpExtensionTransportSequenceNumber,
kTransportSequenceNumberExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header); ASSERT_TRUE(valid_rtp_header);
@ -534,9 +555,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset); EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset);
EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime); EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime);
EXPECT_TRUE(rtp_header.extension.hasAudioLevel); EXPECT_TRUE(rtp_header.extension.hasAudioLevel);
EXPECT_TRUE(rtp_header.extension.hasTransportSequenceNumber);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset); EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel); EXPECT_EQ(kAudioLevel + 0x80u, rtp_header.extension.audioLevel);
EXPECT_EQ(kTransportSequenceNumber,
rtp_header.extension.transportSequenceNumber);
// Parse without map extension // Parse without map extension
webrtc::RTPHeader rtp_header2; webrtc::RTPHeader rtp_header2;
@ -548,9 +572,12 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset); EXPECT_FALSE(rtp_header2.extension.hasTransmissionTimeOffset);
EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime); EXPECT_FALSE(rtp_header2.extension.hasAbsoluteSendTime);
EXPECT_FALSE(rtp_header2.extension.hasAudioLevel); EXPECT_FALSE(rtp_header2.extension.hasAudioLevel);
EXPECT_FALSE(rtp_header2.extension.hasTransportSequenceNumber);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset); EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
EXPECT_EQ(0u, rtp_header2.extension.audioLevel); EXPECT_EQ(0u, rtp_header2.extension.audioLevel);
EXPECT_EQ(0u, rtp_header2.extension.transportSequenceNumber);
} }
TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) { TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
@ -1313,8 +1340,9 @@ TEST_F(RtpSenderVideoTest, SendVideoWithCVO) {
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionVideoRotation, kVideoRotationExtensionId)); kRtpExtensionVideoRotation, kVideoRotationExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kVideoRotationLength, EXPECT_EQ(
rtp_sender_->RtpHeaderExtensionTotalLength()); RtpUtility::Word32Align(kRtpOneByteHeaderLength + kVideoRotationLength),
rtp_sender_->RtpHeaderExtensionTotalLength());
rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload,
kTimestamp, 0, packet_, sizeof(packet_), NULL, kTimestamp, 0, packet_, sizeof(packet_), NULL,

View File

@ -184,6 +184,13 @@ uint32_t BufferToUWord32(const uint8_t* dataBuffer) {
#endif #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) { uint32_t pow2(uint8_t exp) {
return 1 << exp; return 1 << exp;
} }
@ -480,11 +487,11 @@ void RtpHeaderParser::ParseOneByteExtensionHeader(
LOG(LS_WARNING) << "Incorrect audio level len: " << len; LOG(LS_WARNING) << "Incorrect audio level len: " << len;
return; return;
} }
// 0 1 2 3 // 0 1
// 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 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V| level | 0x00 | 0x00 | // | ID | len=0 |V| level |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// //
// Parse out the fields but only use it for debugging for now. // 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; << "Incorrect coordination of video coordination len: " << len;
return; return;
} }
// 0 1 2 3 // 0 1
// 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 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V|0 0 0 0 C F R R| 0x00 | 0x00 | // | ID | len=0 |0 0 0 0 C F R R|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header.extension.hasVideoRotation = true; header.extension.hasVideoRotation = true;
header.extension.videoRotation = ptr[0]; header.extension.videoRotation = ptr[0];
break; 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: { default: {
LOG(LS_WARNING) << "Extension type not implemented: " << type; LOG(LS_WARNING) << "Extension type not implemented: " << type;
return; return;

View File

@ -91,6 +91,9 @@ namespace RtpUtility {
*/ */
uint32_t BufferToUWord32(const uint8_t* dataBuffer); 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 { class RtpHeaderParser {
public: public:
RtpHeaderParser(const uint8_t* rtpData, size_t rtpDataLength); RtpHeaderParser(const uint8_t* rtpData, size_t rtpDataLength);