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:
@ -43,6 +43,7 @@ struct RTPHeader
|
||||
struct RTPHeaderExtension
|
||||
{
|
||||
int32_t transmissionTimeOffset;
|
||||
uint32_t absoluteSendTime;
|
||||
};
|
||||
|
||||
struct RTPAudioHeader
|
||||
|
||||
@ -53,6 +53,7 @@ enum RTPExtensionType
|
||||
kRtpExtensionNone,
|
||||
kRtpExtensionTransmissionTimeOffset,
|
||||
kRtpExtensionAudioLevel,
|
||||
kRtpExtensionAbsoluteSendTime
|
||||
};
|
||||
|
||||
enum RTCPAppSubTypes
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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.");
|
||||
|
||||
Reference in New Issue
Block a user