Add handling of the absolute send time header extension to the rtp_rtcp module.

BUG=
R=asapersson@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1480004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4041 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
solenberg@webrtc.org
2013-05-16 11:10:31 +00:00
parent 59a06670b5
commit 7ebbea14a9
7 changed files with 328 additions and 40 deletions

View File

@ -43,6 +43,7 @@ struct RTPHeader
struct RTPHeaderExtension
{
int32_t transmissionTimeOffset;
uint32_t absoluteSendTime;
};
struct RTPAudioHeader

View File

@ -53,6 +53,7 @@ enum RTPExtensionType
kRtpExtensionNone,
kRtpExtensionTransmissionTimeOffset,
kRtpExtensionAudioLevel,
kRtpExtensionAbsoluteSendTime
};
enum RTCPAppSubTypes

View File

@ -22,15 +22,26 @@ const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
const size_t kRtpOneByteHeaderLength = 4;
const size_t kTransmissionTimeOffsetLength = 4;
const size_t kAbsoluteSendTimeLength = 4;
struct HeaderExtension {
HeaderExtension(RTPExtensionType extension_type)
: type(extension_type),
length(0) {
if (type == kRtpExtensionTransmissionTimeOffset) {
length = kTransmissionTimeOffsetLength;
}
}
// TODO(solenberg): Create handler classes for header extensions so we can
// get rid of switches like these as well as handling code spread out all
// over.
switch (type) {
case kRtpExtensionTransmissionTimeOffset:
length = kTransmissionTimeOffsetLength;
break;
case kRtpExtensionAbsoluteSendTime:
length = kAbsoluteSendTimeLength;
break;
default:
assert(false);
}
}
const RTPExtensionType type;
uint8_t length;

View File

@ -49,7 +49,7 @@ RTPSender::RTPSender(const int32_t id, const bool audio, Clock *clock,
max_payload_length_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
target_send_bitrate_(0), packet_over_head_(28), payload_type_(-1),
payload_type_map_(), rtp_header_extension_map_(),
transmission_time_offset_(0),
transmission_time_offset_(0), absolute_send_time_(0),
// NACK.
nack_byte_count_times_(), nack_byte_count_(), nack_bitrate_(clock),
packet_history_(new RTPPacketHistory(clock)),
@ -137,6 +137,16 @@ int32_t RTPSender::SetTransmissionTimeOffset(
return 0;
}
int32_t RTPSender::SetAbsoluteSendTime(
const uint32_t absolute_send_time) {
if (absolute_send_time > 0xffffff) { // UWord24.
return -1;
}
CriticalSectionScoped cs(send_critsect_);
absolute_send_time_ = absolute_send_time;
return 0;
}
int32_t RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
const uint8_t id) {
CriticalSectionScoped cs(send_critsect_);
@ -350,7 +360,7 @@ int32_t RTPSender::SendOutgoingData(
"timestamp", capture_timestamp);
} else {
TRACE_EVENT_INSTANT2("webrtc_rtp", "SendFrame",
"timestsamp", capture_timestamp,
"timestamp", capture_timestamp,
"frame_type", FrameTypeToString(frame_type));
}
@ -675,8 +685,13 @@ void RTPSender::TimeToSendPacket(uint16_t sequence_number,
"timestamp", rtp_header.header.timestamp,
"seqnum", sequence_number);
int64_t diff_ms = clock_->TimeInMilliseconds() - capture_time_ms;
if (UpdateTransmissionTimeOffset(data_buffer, length, rtp_header, diff_ms)) {
int64_t now_ms = clock_->TimeInMilliseconds();
int64_t diff_ms = now_ms - capture_time_ms;
bool updated_transmission_time_offset =
UpdateTransmissionTimeOffset(data_buffer, length, rtp_header, diff_ms);
bool updated_abs_send_time =
UpdateAbsoluteSendTime(data_buffer, length, rtp_header, now_ms);
if (updated_transmission_time_offset || updated_abs_send_time) {
// Update stored packet in case of receiving a re-transmission request.
packet_history_->ReplaceRTPHeader(data_buffer,
rtp_header.header.sequenceNumber,
@ -694,14 +709,19 @@ int32_t RTPSender::SendToNetwork(
WebRtcRTPHeader rtp_header;
rtp_parser.Parse(rtp_header);
int64_t now_ms = clock_->TimeInMilliseconds();
// |capture_time_ms| <= 0 is considered invalid.
// TODO(holmer): This should be changed all over Video Engine so that negative
// time is consider invalid, while 0 is considered a valid time.
if (capture_time_ms > 0) {
int64_t time_now = clock_->TimeInMilliseconds();
UpdateTransmissionTimeOffset(buffer, payload_length + rtp_header_length,
rtp_header, time_now - capture_time_ms);
rtp_header, now_ms - capture_time_ms);
}
UpdateAbsoluteSendTime(buffer, payload_length + rtp_header_length,
rtp_header, now_ms);
// Used for NACK and to spread out the transmission of packets.
if (packet_history_->PutRTPPacket(buffer, rtp_header_length + payload_length,
max_payload_length_, capture_time_ms,
@ -867,9 +887,17 @@ uint16_t RTPSender::BuildRTPHeaderExtension(
RTPExtensionType type = rtp_header_extension_map_.First();
while (type != kRtpExtensionNone) {
uint8_t block_length = 0;
if (type == kRtpExtensionTransmissionTimeOffset) {
block_length = BuildTransmissionTimeOffsetExtension(
data_buffer + kHeaderLength + total_block_length);
switch (type) {
case kRtpExtensionTransmissionTimeOffset:
block_length = BuildTransmissionTimeOffsetExtension(
data_buffer + kHeaderLength + total_block_length);
break;
case kRtpExtensionAbsoluteSendTime:
block_length = BuildAbsoluteSendTimeExtension(
data_buffer + kHeaderLength + total_block_length);
break;
default:
assert(false);
}
total_block_length += block_length;
type = rtp_header_extension_map_.Next(type);
@ -922,23 +950,59 @@ uint8_t RTPSender::BuildTransmissionTimeOffsetExtension(
return kTransmissionTimeOffsetLength;
}
uint8_t RTPSender::BuildAbsoluteSendTimeExtension(
uint8_t* data_buffer) const {
// 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
// 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.
//
// The form of the absolute send time 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=2 | absolute send time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Get id defined by user.
uint8_t id;
if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime,
&id) != 0) {
// Not registered.
return 0;
}
size_t pos = 0;
const uint8_t len = 2;
data_buffer[pos++] = (id << 4) + len;
ModuleRTPUtility::AssignUWord24ToBuffer(data_buffer + pos,
absolute_send_time_);
pos += 3;
assert(pos == kAbsoluteSendTimeLength);
return kAbsoluteSendTimeLength;
}
bool RTPSender::UpdateTransmissionTimeOffset(
uint8_t *rtp_packet, const uint16_t rtp_packet_length,
const WebRtcRTPHeader &rtp_header, const int64_t time_diff_ms) const {
CriticalSectionScoped cs(send_critsect_);
// Get length until start of transmission block.
int transmission_block_pos =
// Get length until start of header extension block.
int extension_block_pos =
rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
kRtpExtensionTransmissionTimeOffset);
if (transmission_block_pos < 0) {
if (extension_block_pos < 0) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update transmission time offset, not registered.");
return false;
}
int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
if (rtp_packet_length < block_pos + 4 ||
rtp_header.header.headerLength < block_pos + 4) {
int block_pos = 12 + rtp_header.header.numCSRCs + extension_block_pos;
if (rtp_packet_length < block_pos + kTransmissionTimeOffsetLength ||
rtp_header.header.headerLength <
block_pos + kTransmissionTimeOffsetLength) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update transmission time offset, invalid length.");
return false;
@ -966,12 +1030,63 @@ bool RTPSender::UpdateTransmissionTimeOffset(
"Failed to update transmission time offset.");
return false;
}
// Update transmission offset field.
// Update transmission offset field (converting to a 90 kHz timestamp).
ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
time_diff_ms * 90); // RTP timestamp.
return true;
}
bool RTPSender::UpdateAbsoluteSendTime(
uint8_t *rtp_packet, const uint16_t rtp_packet_length,
const WebRtcRTPHeader &rtp_header, const int64_t now_ms) const {
CriticalSectionScoped cs(send_critsect_);
// Get length until start of header extension block.
int extension_block_pos =
rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
kRtpExtensionAbsoluteSendTime);
if (extension_block_pos < 0) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update absolute send time, not registered.");
return false;
}
int block_pos = 12 + rtp_header.header.numCSRCs + extension_block_pos;
if (rtp_packet_length < block_pos + kAbsoluteSendTimeLength ||
rtp_header.header.headerLength < block_pos + kAbsoluteSendTimeLength) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update absolute send time, invalid length.");
return false;
}
// Verify that header contains extension.
if (!((rtp_packet[12 + rtp_header.header.numCSRCs] == 0xBE) &&
(rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
WEBRTC_TRACE(
kTraceStream, kTraceRtpRtcp, id_,
"Failed to update absolute send time, hdr extension not found.");
return false;
}
// Get id.
uint8_t id = 0;
if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime,
&id) != 0) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update absolute send time, no id.");
return false;
}
// Verify first byte in block.
const uint8_t first_block_byte = (id << 4) + 2;
if (rtp_packet[block_pos] != first_block_byte) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
"Failed to update absolute send time.");
return false;
}
// Update absolute send time field (convert ms to 24-bit unsigned with 18 bit
// fractional part).
ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
((now_ms << 18) / 1000) & 0x00ffffff);
return true;
}
void RTPSender::SetSendingStatus(const bool enabled) {
if (enabled) {
uint32_t frequency_hz;

View File

@ -136,6 +136,8 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
// RTP header extension
int32_t SetTransmissionTimeOffset(
const int32_t transmission_time_offset);
int32_t SetAbsoluteSendTime(
const uint32_t absolute_send_time);
int32_t RegisterRtpHeaderExtension(const RTPExtensionType type,
const uint8_t id);
@ -148,11 +150,17 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
uint8_t BuildTransmissionTimeOffsetExtension(
uint8_t *data_buffer) const;
uint8_t BuildAbsoluteSendTimeExtension(
uint8_t* data_buffer) const;
bool UpdateTransmissionTimeOffset(uint8_t *rtp_packet,
const uint16_t rtp_packet_length,
const WebRtcRTPHeader &rtp_header,
const int64_t time_diff_ms) const;
bool UpdateAbsoluteSendTime(uint8_t *rtp_packet,
const uint16_t rtp_packet_length,
const WebRtcRTPHeader &rtp_header,
const int64_t now_ms) const;
void TimeToSendPacket(uint16_t sequence_number, int64_t capture_time_ms);
@ -283,6 +291,7 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
RtpHeaderExtensionMap rtp_header_extension_map_;
int32_t transmission_time_offset_;
uint32_t absolute_send_time_;
// NACK
uint32_t nack_byte_count_times_[NACK_BYTECOUNT_SIZE];

View File

@ -26,13 +26,14 @@
namespace webrtc {
namespace {
const int kId = 1;
const int kTypeLength = kTransmissionTimeOffsetLength;
const int kTransmissionTimeOffsetExtensionId = 1;
const int kAbsoluteSendTimeExtensionId = 14;
const int kPayload = 100;
const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33;
const int kTimeOffset = 22222;
const int kMaxPacketLength = 1500;
const uint32_t kAbsoluteSendTime = 0x00aabbcc;
} // namespace
using testing::_;
@ -60,12 +61,11 @@ class LoopbackTransportTest : public webrtc::Transport {
class RtpSenderTest : public ::testing::Test {
protected:
RtpSenderTest()
: fake_clock_(123456),
: fake_clock_(123456789),
mock_paced_sender_(),
rtp_sender_(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
&mock_paced_sender_)),
kMarkerBit(true),
kType(kRtpExtensionTransmissionTimeOffset) {
kMarkerBit(true) {
rtp_sender_->SetSequenceNumber(kSeqNum);
EXPECT_CALL(mock_paced_sender_,
SendPacket(_, _, _, _, _)).WillRepeatedly(testing::Return(true));
@ -75,7 +75,6 @@ class RtpSenderTest : public ::testing::Test {
scoped_ptr<RTPSender> rtp_sender_;
LoopbackTransportTest transport_;
const bool kMarkerBit;
RTPExtensionType kType;
uint8_t packet_[kMaxPacketLength];
void VerifyRTPHeaderCommon(const WebRtcRTPHeader& rtp_header) {
@ -89,12 +88,44 @@ class RtpSenderTest : public ::testing::Test {
}
};
TEST_F(RtpSenderTest, RegisterRtpHeaderExtension) {
TEST_F(RtpSenderTest, RegisterRtpTransmissionTimeOffsetHeaderExtension) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTypeLength,
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(kType));
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
}
TEST_F(RtpSenderTest, RegisterRtpAbsoluteSendTimeHeaderExtension) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
}
TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength +
kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset));
EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
}
@ -110,7 +141,8 @@ TEST_F(RtpSenderTest, BuildRTPPacket) {
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
@ -118,11 +150,13 @@ TEST_F(RtpSenderTest, BuildRTPPacket) {
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header.extension.absoluteSendTime);
}
TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -135,7 +169,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
@ -157,7 +192,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) {
TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
const int kNegTimeOffset = -500;
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kNegTimeOffset));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -170,7 +206,8 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
@ -180,13 +217,93 @@ TEST_F(RtpSenderTest, BuildRTPPacketWithNegativeTransmissionOffsetExtension) {
EXPECT_EQ(kNegTimeOffset, rtp_header.extension.transmissionTimeOffset);
}
TEST_F(RtpSenderTest, TrafficSmoothingWithTimeOffset) {
TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) {
EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
// Parse without map extension
webrtc::WebRtcRTPHeader rtp_header2;
const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.header.headerLength);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
}
TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
int32_t length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime);
// Parse without map extension
webrtc::WebRtcRTPHeader rtp_header2;
const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.header.headerLength);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime);
}
TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
EXPECT_CALL(mock_paced_sender_,
SendPacket(PacedSender::kNormalPriority, _, kSeqNum, _, _)).
WillOnce(testing::Return(false));
rtp_sender_->SetStorePacketsStatus(true, 10);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_sender_->SetTargetSendBitrate(300000);
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -217,12 +334,17 @@ TEST_F(RtpSenderTest, TrafficSmoothingWithTimeOffset) {
transport_.last_sent_packet_, rtp_length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
// Verify transmission time offset.
EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset);
uint64_t expected_send_time =
0x00fffffful & ((fake_clock_.TimeInMilliseconds() << 18) / 1000);
EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
}
TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
@ -231,7 +353,10 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
WillOnce(testing::Return(false));
rtp_sender_->SetStorePacketsStatus(true, 10);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_sender_->SetTargetSendBitrate(300000);
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -270,12 +395,17 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
transport_.last_sent_packet_, rtp_length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
map.Register(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId);
const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
// Verify transmission time offset.
EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset);
uint64_t expected_send_time =
0x00fffffful & ((fake_clock_.TimeInMilliseconds() << 18) / 1000);
EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
}
TEST_F(RtpSenderTest, SendGenericVideo) {

View File

@ -355,6 +355,9 @@ bool RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket,
// is zero.
parsedPacket.extension.transmissionTimeOffset = 0;
// May not be present in packet.
parsedPacket.extension.absoluteSendTime = 0;
if (X) {
/* RTP header extension, RFC 3550.
0 1 2 3
@ -466,6 +469,24 @@ void RTPHeaderParser::ParseOneByteExtensionHeader(
// level=%u", ID, len, V, level);
break;
}
case kRtpExtensionAbsoluteSendTime: {
if (len != 2) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Incorrect absolute send time len: %d", 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=2 | absolute send time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
uint32_t absoluteSendTime = *ptr++ << 16;
absoluteSendTime += *ptr++ << 8;
absoluteSendTime += *ptr++;
parsedPacket.extension.absoluteSendTime = absoluteSendTime;
break;
}
default: {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"Extension type not implemented.");