Remove time constraint on first retransmit of a packet.

We don't allow more than one retransmission within one RTT, but the RTT
estimate might be off. Reasonably, the remote end will not send a NACK
until the packet after has been received - so always resend on first
request.

Review URL: https://codereview.webrtc.org/1414563003

Cr-Commit-Position: refs/heads/master@{#10362}
This commit is contained in:
sprang
2015-10-21 13:46:33 -07:00
committed by Commit bot
parent c96df779b0
commit affa39cb39
3 changed files with 62 additions and 19 deletions

View File

@ -16,6 +16,7 @@
#include <limits> #include <limits>
#include <set> #include <set>
#include "webrtc/base/checks.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/logging.h"
@ -118,6 +119,7 @@ int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
(capture_time_ms > 0) ? capture_time_ms : clock_->TimeInMilliseconds(); (capture_time_ms > 0) ? capture_time_ms : clock_->TimeInMilliseconds();
stored_packets_[prev_index_].send_time = 0; // Packet not sent. stored_packets_[prev_index_].send_time = 0; // Packet not sent.
stored_packets_[prev_index_].storage_type = type; stored_packets_[prev_index_].storage_type = type;
stored_packets_[prev_index_].has_been_retransmitted = false;
++prev_index_; ++prev_index_;
if (prev_index_ >= stored_packets_.size()) { if (prev_index_ >= stored_packets_.size()) {
@ -173,10 +175,9 @@ bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
size_t* packet_length, size_t* packet_length,
int64_t* stored_time_ms) { int64_t* stored_time_ms) {
CriticalSectionScoped cs(critsect_.get()); CriticalSectionScoped cs(critsect_.get());
assert(*packet_length >= IP_PACKET_SIZE); RTC_CHECK_GE(*packet_length, static_cast<size_t>(IP_PACKET_SIZE));
if (!store_) { if (!store_)
return false; return false;
}
int32_t index = 0; int32_t index = 0;
bool found = FindSeqNum(sequence_number, &index); bool found = FindSeqNum(sequence_number, &index);
@ -193,18 +194,23 @@ bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
return false; return false;
} }
// Verify elapsed time since last retrieve. // Verify elapsed time since last retrieve, but only for retransmissions and
// always send packet upon first retransmission request.
int64_t now = clock_->TimeInMilliseconds(); int64_t now = clock_->TimeInMilliseconds();
if (min_elapsed_time_ms > 0 && if (min_elapsed_time_ms > 0 && retransmit &&
stored_packets_[index].has_been_retransmitted &&
((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) { ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) {
return false; return false;
} }
if (retransmit && stored_packets_[index].storage_type == kDontRetransmit) { if (retransmit) {
if (stored_packets_[index].storage_type == kDontRetransmit) {
// No bytes copied since this packet shouldn't be retransmitted or is // No bytes copied since this packet shouldn't be retransmitted or is
// of zero size. // of zero size.
return false; return false;
} }
stored_packets_[index].has_been_retransmitted = true;
}
stored_packets_[index].send_time = clock_->TimeInMilliseconds(); stored_packets_[index].send_time = clock_->TimeInMilliseconds();
GetPacket(index, packet, packet_length, stored_time_ms); GetPacket(index, packet, packet_length, stored_time_ms);
return true; return true;

View File

@ -46,13 +46,12 @@ class RTPPacketHistory {
// The packet is copied to the buffer pointed to by ptr_rtp_packet. // The packet is copied to the buffer pointed to by ptr_rtp_packet.
// The rtp_packet_length should show the available buffer size. // The rtp_packet_length should show the available buffer size.
// Returns true if packet is found. // Returns true if packet is found.
// rtp_packet_length: returns the copied packet length on success. // packet_length: returns the copied packet length on success.
// min_elapsed_time_ms: the minimum time that must have elapsed since the last // min_elapsed_time_ms: the minimum time that must have elapsed since the last
// time the packet was resent (parameter is ignored if set to zero). // time the packet was resent (parameter is ignored if set to zero).
// If the packet is found but the minimum time has not elaped, no bytes are // If the packet is found but the minimum time has not elapsed, no bytes are
// copied. // copied.
// stored_time_ms: returns the time when the packet was stored. // stored_time_ms: returns the time when the packet was stored.
// type: returns the storage type set in PutRTPPacket.
bool GetPacketAndSetSendTime(uint16_t sequence_number, bool GetPacketAndSetSendTime(uint16_t sequence_number,
int64_t min_elapsed_time_ms, int64_t min_elapsed_time_ms,
bool retransmit, bool retransmit,
@ -94,6 +93,7 @@ class RTPPacketHistory {
int64_t time_ms = 0; int64_t time_ms = 0;
int64_t send_time = 0; int64_t send_time = 0;
StorageType storage_type = kDontRetransmit; StorageType storage_type = kDontRetransmit;
bool has_been_retransmitted = false;
uint8_t data[IP_PACKET_SIZE]; uint8_t data[IP_PACKET_SIZE];
size_t length = 0; size_t length = 0;

View File

@ -161,6 +161,8 @@ TEST_F(RtpPacketHistoryTest, DontRetransmit) {
} }
TEST_F(RtpPacketHistoryTest, MinResendTime) { TEST_F(RtpPacketHistoryTest, MinResendTime) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_->SetStorePacketsStatus(true, 10); hist_->SetStorePacketsStatus(true, 10);
size_t len = 0; size_t len = 0;
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
@ -168,22 +170,57 @@ TEST_F(RtpPacketHistoryTest, MinResendTime) {
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms, EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission)); kAllowRetransmission));
// First transmission: TimeToSendPacket() call from pacer.
int64_t time; int64_t time;
len = kMaxPacketLength; len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, 100, false, packet_, &len, EXPECT_TRUE(
&time)); hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_, &len, &time));
fake_clock_.AdvanceTimeMilliseconds(100);
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs);
// Time has elapsed. // Time has elapsed.
len = kMaxPacketLength; len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, 100, false, packet_, &len, EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
&time)); true, packet_, &len, &time));
EXPECT_GT(len, 0u); EXPECT_GT(len, 0u);
EXPECT_EQ(capture_time_ms, time); EXPECT_EQ(capture_time_ms, time);
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied. // Time has not elapsed. Packet should be found, but no bytes copied.
len = kMaxPacketLength; len = kMaxPacketLength;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, 101, false, packet_, EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
&len, &time)); true, packet_, &len, &time));
}
TEST_F(RtpPacketHistoryTest, EarlyFirstResend) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
// First transmission: TimeToSendPacket() call from pacer.
int64_t time;
len = kMaxPacketLength;
EXPECT_TRUE(
hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_, &len, &time));
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed, but this is the first retransmission request so
// allow anyway.
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
EXPECT_GT(len, 0u);
EXPECT_EQ(capture_time_ms, time);
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied.
len = kMaxPacketLength;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
} }
TEST_F(RtpPacketHistoryTest, DynamicExpansion) { TEST_F(RtpPacketHistoryTest, DynamicExpansion) {