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:
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
Reference in New Issue
Block a user