diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc index ce77c00b16..b3649f8a39 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.cc +++ b/modules/rtp_rtcp/source/rtp_packet_history.cc @@ -17,276 +17,228 @@ #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "rtc_base/ptr_util.h" #include "system_wrappers/include/clock.h" namespace webrtc { namespace { -// Min packet size for BestFittingPacket() to honor. constexpr size_t kMinPacketRequestBytes = 50; - -// Utility function to get the absolute difference in size between the provided -// target size and the size of packet. -size_t SizeDiff(const std::unique_ptr& packet, size_t size) { - size_t packet_size = packet->size(); - if (packet_size > size) { - return packet_size - size; - } - return size - packet_size; -} +// Don't overwrite a packet within one second, or three RTTs, after transmission +// whichever is larger. Instead try to dynamically expand history. +constexpr int64_t kMinPacketDurationMs = 1000; +constexpr int kMinPacketDurationRtt = 3; } // namespace - constexpr size_t RtpPacketHistory::kMaxCapacity; -constexpr int64_t RtpPacketHistory::kMinPacketDurationMs; -constexpr int RtpPacketHistory::kMinPacketDurationRtt; -constexpr int RtpPacketHistory::kPacketCullingDelayFactor; -RtpPacketHistory::PacketState::PacketState() = default; -RtpPacketHistory::PacketState::PacketState(const PacketState&) = default; -RtpPacketHistory::PacketState::~PacketState() = default; - -RtpPacketHistory::StoredPacket::StoredPacket( - std::unique_ptr packet) - : packet(std::move(packet)) {} +RtpPacketHistory::StoredPacket::StoredPacket() = default; RtpPacketHistory::StoredPacket::StoredPacket(StoredPacket&&) = default; RtpPacketHistory::StoredPacket& RtpPacketHistory::StoredPacket::operator=( RtpPacketHistory::StoredPacket&&) = default; RtpPacketHistory::StoredPacket::~StoredPacket() = default; RtpPacketHistory::RtpPacketHistory(Clock* clock) - : clock_(clock), - number_to_store_(0), - mode_(StorageMode::kDisabled), - rtt_ms_(-1) {} + : clock_(clock), store_(false), prev_index_(0), rtt_ms_(-1) {} RtpPacketHistory::~RtpPacketHistory() {} -void RtpPacketHistory::SetStorePacketsStatus(StorageMode mode, - size_t number_to_store) { - RTC_DCHECK_LE(number_to_store, kMaxCapacity); - rtc::CritScope cs(&lock_); - if (mode != StorageMode::kDisabled && mode_ != StorageMode::kDisabled) { - RTC_LOG(LS_WARNING) << "Purging packet history in order to re-set status."; +void RtpPacketHistory::SetStorePacketsStatus(bool enable, + uint16_t number_to_store) { + rtc::CritScope cs(&critsect_); + if (enable) { + if (store_) { + RTC_LOG(LS_WARNING) + << "Purging packet history in order to re-set status."; + Free(); + } + RTC_DCHECK(!store_); + Allocate(number_to_store); + } else { + Free(); } - Reset(); - mode_ = mode; - number_to_store_ = std::min(kMaxCapacity, number_to_store); } -RtpPacketHistory::StorageMode RtpPacketHistory::GetStorageMode() const { - rtc::CritScope cs(&lock_); - return mode_; +void RtpPacketHistory::Allocate(size_t number_to_store) { + RTC_DCHECK_GT(number_to_store, 0); + RTC_DCHECK_LE(number_to_store, kMaxCapacity); + store_ = true; + stored_packets_.resize(number_to_store); } -void RtpPacketHistory::SetRtt(int64_t rtt_ms) { - rtc::CritScope cs(&lock_); - RTC_DCHECK_GE(rtt_ms, 0); - rtt_ms_ = rtt_ms; +void RtpPacketHistory::Free() { + if (!store_) { + return; + } + + stored_packets_.clear(); + + store_ = false; + prev_index_ = 0; +} + +bool RtpPacketHistory::StorePackets() const { + rtc::CritScope cs(&critsect_); + return store_; } void RtpPacketHistory::PutRtpPacket(std::unique_ptr packet, StorageType type, - rtc::Optional send_time_ms) { + bool sent) { RTC_DCHECK(packet); - rtc::CritScope cs(&lock_); - int64_t now_ms = clock_->TimeInMilliseconds(); - if (mode_ == StorageMode::kDisabled) { + rtc::CritScope cs(&critsect_); + if (!store_) { return; } - CullOldPackets(now_ms); + int64_t now_ms = clock_->TimeInMilliseconds(); + + // If index we're about to overwrite contains a packet that has not + // yet been sent (probably pending in paced sender), or if the send time is + // less than 3 round trip times ago, expand the buffer to avoid overwriting + // valid data. + StoredPacket* stored_packet = &stored_packets_[prev_index_]; + int64_t packet_duration_ms = + std::max(kMinPacketDurationRtt * rtt_ms_, kMinPacketDurationMs); + if (stored_packet->packet && + (stored_packet->send_time == 0 || + (rtt_ms_ >= 0 && + now_ms - stored_packet->send_time <= packet_duration_ms))) { + size_t current_size = stored_packets_.size(); + if (current_size < kMaxCapacity) { + size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1); + expanded_size = std::min(expanded_size, kMaxCapacity); + Allocate(expanded_size); + // Causes discontinuity, but that's OK-ish. FindSeqNum() will still work, + // but may be slower - at least until buffer has wrapped around once. + prev_index_ = current_size; + stored_packet = &stored_packets_[prev_index_]; + } + } // Store packet. - const uint16_t rtp_seq_no = packet->SequenceNumber(); - auto packet_it = packet_history_.emplace(rtp_seq_no, std::move(packet)); - RTC_DCHECK(packet_it.second); - StoredPacket& stored_packet = packet_it.first->second; + if (packet->capture_time_ms() <= 0) + packet->set_capture_time_ms(now_ms); + stored_packet->sequence_number = packet->SequenceNumber(); + stored_packet->send_time = sent ? now_ms : 0; + stored_packet->storage_type = type; + stored_packet->has_been_retransmitted = false; + stored_packet->packet = std::move(packet); - if (stored_packet.packet->capture_time_ms() <= 0) { - stored_packet.packet->set_capture_time_ms(now_ms); - } - stored_packet.send_time_ms = send_time_ms; - stored_packet.storage_type = type; - stored_packet.times_retransmitted = 0; + prev_index_ = (prev_index_ + 1) % stored_packets_.size(); +} - if (!start_seqno_) { - start_seqno_ = rtp_seq_no; +bool RtpPacketHistory::HasRtpPacket(uint16_t sequence_number) const { + rtc::CritScope cs(&critsect_); + if (!store_) { + return false; } + + int unused_index = 0; + return FindSeqNum(sequence_number, &unused_index); } std::unique_ptr RtpPacketHistory::GetPacketAndSetSendTime( uint16_t sequence_number, - bool verify_rtt) { - rtc::CritScope cs(&lock_); - if (mode_ == StorageMode::kDisabled) { + int64_t min_elapsed_time_ms, + bool retransmit) { + rtc::CritScope cs(&critsect_); + if (!store_) { return nullptr; } - int64_t now_ms = clock_->TimeInMilliseconds(); - StoredPacketIterator rtp_it = packet_history_.find(sequence_number); - if (rtp_it == packet_history_.end()) { + int index = 0; + if (!FindSeqNum(sequence_number, &index)) { + RTC_LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number; + return nullptr; + } + RTC_DCHECK_EQ(sequence_number, + stored_packets_[index].packet->SequenceNumber()); + + // Verify elapsed time since last retrieve, but only for retransmissions and + // always send packet upon first retransmission request. + int64_t now = clock_->TimeInMilliseconds(); + if (min_elapsed_time_ms > 0 && retransmit && + stored_packets_[index].has_been_retransmitted && + ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) { return nullptr; } - StoredPacket& packet = rtp_it->second; - if (verify_rtt && !VerifyRtt(rtp_it->second, now_ms)) { - return nullptr; - } - - if (packet.send_time_ms) { - ++packet.times_retransmitted; - } - - // Update send-time and return copy of packet instance. - packet.send_time_ms = now_ms; - - if (packet.storage_type == StorageType::kDontRetransmit) { - // Non retransmittable packet, so call must come from paced sender. - // Remove from history and return actual packet instance. - return RemovePacket(rtp_it); - } - return rtc::MakeUnique(*packet.packet); -} - -rtc::Optional RtpPacketHistory::GetPacketState( - uint16_t sequence_number, - bool verify_rtt) const { - rtc::CritScope cs(&lock_); - if (mode_ == StorageMode::kDisabled) { - return rtc::nullopt; - } - - auto rtp_it = packet_history_.find(sequence_number); - if (rtp_it == packet_history_.end()) { - return rtc::nullopt; - } - - if (verify_rtt && !VerifyRtt(rtp_it->second, clock_->TimeInMilliseconds())) { - return rtc::nullopt; - } - - return StoredPacketToPacketState(rtp_it->second); -} - -bool RtpPacketHistory::VerifyRtt(const RtpPacketHistory::StoredPacket& packet, - int64_t now_ms) const { - if (packet.send_time_ms) { - // Send-time already set, this check must be for a retransmission. - if (packet.times_retransmitted > 0 && - now_ms < *packet.send_time_ms + rtt_ms_) { - // This packet has already been retransmitted once, and the time since - // that even is lower than on RTT. Ignore request as this packet is - // likely already in the network pipe. - return false; + if (retransmit) { + if (stored_packets_[index].storage_type == kDontRetransmit) { + // No bytes copied since this packet shouldn't be retransmitted. + return nullptr; } + stored_packets_[index].has_been_retransmitted = true; } + stored_packets_[index].send_time = clock_->TimeInMilliseconds(); + return GetPacket(index); +} - return true; +std::unique_ptr RtpPacketHistory::GetPacket(int index) const { + const RtpPacketToSend& stored = *stored_packets_[index].packet; + return std::unique_ptr(new RtpPacketToSend(stored)); } std::unique_ptr RtpPacketHistory::GetBestFittingPacket( size_t packet_length) const { - // TODO(sprang): Make this smarter, taking retransmit count etc into account. - rtc::CritScope cs(&lock_); - if (packet_length < kMinPacketRequestBytes || packet_history_.empty()) { + rtc::CritScope cs(&critsect_); + if (!store_) return nullptr; + int index = FindBestFittingPacket(packet_length); + if (index < 0) + return nullptr; + return GetPacket(index); +} + +bool RtpPacketHistory::FindSeqNum(uint16_t sequence_number, int* index) const { + if (prev_index_ > 0) { + *index = prev_index_ - 1; + } else { + *index = stored_packets_.size() - 1; // Wrap. + } + uint16_t temp_sequence_number = stored_packets_[*index].sequence_number; + + int idx = *index - (temp_sequence_number - sequence_number); + if (idx >= 0 && idx < static_cast(stored_packets_.size())) { + *index = idx; + temp_sequence_number = stored_packets_[*index].sequence_number; } - size_t min_diff = std::numeric_limits::max(); - RtpPacketToSend* best_packet = nullptr; - for (auto& it : packet_history_) { - size_t diff = SizeDiff(it.second.packet, packet_length); - if (!min_diff || diff < min_diff) { - min_diff = diff; - best_packet = it.second.packet.get(); - if (diff == 0) { + if (temp_sequence_number != sequence_number) { + // We did not found a match, search all. + for (uint16_t m = 0; m < stored_packets_.size(); m++) { + if (stored_packets_[m].sequence_number == sequence_number) { + *index = m; + temp_sequence_number = stored_packets_[*index].sequence_number; break; } } } - - return rtc::MakeUnique(*best_packet); + return temp_sequence_number == sequence_number && + stored_packets_[*index].packet; } -void RtpPacketHistory::Reset() { - packet_history_.clear(); - start_seqno_.reset(); -} - -void RtpPacketHistory::CullOldPackets(int64_t now_ms) { - int64_t packet_duration_ms = - std::max(kMinPacketDurationRtt * rtt_ms_, kMinPacketDurationMs); - while (!packet_history_.empty()) { - auto stored_packet_it = packet_history_.find(*start_seqno_); - RTC_DCHECK(stored_packet_it != packet_history_.end()); - - if (packet_history_.size() >= kMaxCapacity) { - // We have reached the absolute max capacity, remove one packet - // unconditionally. - RemovePacket(stored_packet_it); +int RtpPacketHistory::FindBestFittingPacket(size_t size) const { + if (size < kMinPacketRequestBytes || stored_packets_.empty()) + return -1; + size_t min_diff = std::numeric_limits::max(); + int best_index = -1; // Returned unchanged if we don't find anything. + for (size_t i = 0; i < stored_packets_.size(); ++i) { + if (!stored_packets_[i].packet) continue; - } - - const StoredPacket& stored_packet = stored_packet_it->second; - if (!stored_packet.send_time_ms) { - // Don't remove packets that have not been sent. - return; - } - - if (*stored_packet.send_time_ms + packet_duration_ms > now_ms) { - // Don't cull packets too early to avoid failed retransmission requests. - return; - } - - if (packet_history_.size() >= number_to_store_ || - (mode_ == StorageMode::kStoreAndCull && - *stored_packet.send_time_ms + - (packet_duration_ms * kPacketCullingDelayFactor) <= - now_ms)) { - // Too many packets in history, or this packet has timed out. Remove it - // and continue. - RemovePacket(stored_packet_it); - } else { - // No more packets can be removed right now. - return; + size_t stored_size = stored_packets_[i].packet->size(); + size_t diff = + (stored_size > size) ? (stored_size - size) : (size - stored_size); + if (diff < min_diff) { + min_diff = diff; + best_index = static_cast(i); } } + return best_index; } -std::unique_ptr RtpPacketHistory::RemovePacket( - StoredPacketIterator packet_it) { - // Move the packet out from the StoredPacket container. - std::unique_ptr rtp_packet = - std::move(packet_it->second.packet); - // Erase the packet from the map, and capture iterator to the next one. - StoredPacketIterator next_it = packet_history_.erase(packet_it); - - // |next_it| now points to the next element, or to the end. If the end, - // check if we can wrap around. - if (next_it == packet_history_.end()) { - next_it = packet_history_.begin(); - } - - // Update |start_seq_no| to the new oldest item. - if (next_it != packet_history_.end()) { - start_seqno_ = next_it->first; - } else { - start_seqno_.reset(); - } - - return rtp_packet; -} - -RtpPacketHistory::PacketState RtpPacketHistory::StoredPacketToPacketState( - const RtpPacketHistory::StoredPacket& stored_packet) { - RtpPacketHistory::PacketState state; - state.rtp_sequence_number = stored_packet.packet->SequenceNumber(); - state.send_time_ms = stored_packet.send_time_ms; - state.capture_time_ms = stored_packet.packet->capture_time_ms(); - state.ssrc = stored_packet.packet->Ssrc(); - state.payload_size = stored_packet.packet->size(); - state.times_retransmitted = stored_packet.times_retransmitted; - return state; +void RtpPacketHistory::SetRtt(int64_t rtt_ms) { + rtc::CritScope cs(&critsect_); + RTC_DCHECK_GE(rtt_ms, 0); + rtt_ms_ = rtt_ms; } } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h index e70383ac21..e9d5808b37 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.h +++ b/modules/rtp_rtcp/source/rtp_packet_history.h @@ -11,7 +11,6 @@ #ifndef MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ #define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ -#include #include #include @@ -28,120 +27,66 @@ class RtpPacketToSend; class RtpPacketHistory { public: - enum class StorageMode { - kDisabled, // Don't store any packets. - kStore, // Store and keep at least |number_to_store| packets. - kStoreAndCull // Store up to |number_to_store| packets, but try to remove - // packets as they time out or as signaled as received. - }; - - // Snapshot indicating the state of a packet in the history. - struct PacketState { - PacketState(); - PacketState(const PacketState&); - ~PacketState(); - - uint16_t rtp_sequence_number = 0; - rtc::Optional send_time_ms; - int64_t capture_time_ms = 0; - uint32_t ssrc = 0; - size_t payload_size = 0; - // Number of times RE-transmitted, ie not including the first transmission. - size_t times_retransmitted = 0; - }; - - // Maximum number of packets we ever allow in the history. static constexpr size_t kMaxCapacity = 9600; - // Don't remove packets within max(1000ms, 3x RTT). - static constexpr int64_t kMinPacketDurationMs = 1000; - static constexpr int kMinPacketDurationRtt = 3; - // With kStoreAndCull, always remove packets after 3x max(1000ms, 3x rtt). - static constexpr int kPacketCullingDelayFactor = 3; - explicit RtpPacketHistory(Clock* clock); ~RtpPacketHistory(); - // Set/get storage mode. Note that setting the state will clear the history, - // even if setting the same state as is currently used. - void SetStorePacketsStatus(StorageMode mode, size_t number_to_store); - StorageMode GetStorageMode() const; + void SetStorePacketsStatus(bool enable, uint16_t number_to_store); + bool StorePackets() const; + + void PutRtpPacket(std::unique_ptr packet, + StorageType type, + bool sent); // Set RTT, used to avoid premature retransmission and to prevent over-writing // a packet in the history before we are reasonably sure it has been received. void SetRtt(int64_t rtt_ms); - // If |send_time| is set, packet was sent without using pacer, so state will - // be set accordingly. - void PutRtpPacket(std::unique_ptr packet, - StorageType type, - rtc::Optional send_time_ms); - // Gets stored RTP packet corresponding to the input |sequence number|. - // Returns nullptr if packet is not found. If |verify_rtt| is true, doesn't - // return packet that was (re)sent too recently. + // Returns nullptr if packet is not found. + // |min_elapsed_time_ms| is the minimum time that must have elapsed since + // the last time the packet was resent (parameter is ignored if set to zero). + // If the packet is found but the minimum time has not elapsed, returns + // nullptr. std::unique_ptr GetPacketAndSetSendTime( uint16_t sequence_number, - bool verify_rtt); + int64_t min_elapsed_time_ms, + bool retransmit); - // Similar to GetPacketAndSetSendTime(), but only returns a snapshot of the - // current state for packet, and never updates internal state. - rtc::Optional GetPacketState(uint16_t sequence_number, - bool verify_rtt) const; - - // Get the packet (if any) from the history, with size closest to - // |packet_size|. The exact size of the packet is not guaranteed. std::unique_ptr GetBestFittingPacket( size_t packet_size) const; + bool HasRtpPacket(uint16_t sequence_number) const; + private: struct StoredPacket { - explicit StoredPacket(std::unique_ptr packet); + StoredPacket(); StoredPacket(StoredPacket&&); StoredPacket& operator=(StoredPacket&&); ~StoredPacket(); - - // The time of last transmission, including retransmissions. - rtc::Optional send_time_ms; - - // Number of times RE-transmitted, ie excluding the first transmission. - size_t times_retransmitted = 0; - - // Storing a packet with |storage_type| = kDontRetransmit indicates this is - // only used as temporary storage until sent by the pacer sender. + uint16_t sequence_number = 0; + int64_t send_time = 0; StorageType storage_type = kDontRetransmit; + bool has_been_retransmitted = false; - // The actual packet. std::unique_ptr packet; }; - using StoredPacketIterator = std::map::iterator; - - // Helper method used by GetPacketAndSetSendTime() and GetPacketState() to - // check if packet has too recently been sent. - bool VerifyRtt(const StoredPacket& packet, int64_t now_ms) const - RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); - void Reset() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); - void CullOldPackets(int64_t now_ms) RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); - // Removes the packet from the history, and context/mapping that has been - // stored. Returns the RTP packet instance contained within the StoredPacket. - std::unique_ptr RemovePacket(StoredPacketIterator packet) - RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); - static PacketState StoredPacketToPacketState( - const StoredPacket& stored_packet); - - Clock* const clock_; - rtc::CriticalSection lock_; - size_t number_to_store_ RTC_GUARDED_BY(lock_); - StorageMode mode_ RTC_GUARDED_BY(lock_); - int64_t rtt_ms_ RTC_GUARDED_BY(lock_); - - // Map from rtp sequence numbers to stored packet. - std::map packet_history_ RTC_GUARDED_BY(lock_); - - // The earliest packet in the history. This might not be the lowest sequence - // number, in case there is a wraparound. - rtc::Optional start_seqno_ RTC_GUARDED_BY(lock_); + std::unique_ptr GetPacket(int index) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + void Allocate(size_t number_to_store) RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + void Free() RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + bool FindSeqNum(uint16_t sequence_number, int* index) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + int FindBestFittingPacket(size_t size) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + Clock* clock_; + rtc::CriticalSection critsect_; + bool store_ RTC_GUARDED_BY(critsect_); + size_t prev_index_ RTC_GUARDED_BY(critsect_); + std::vector stored_packets_ RTC_GUARDED_BY(critsect_); + int64_t rtt_ms_ RTC_GUARDED_BY(critsect_); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPacketHistory); }; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc index c7cd18085a..cdfd3a0a25 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc @@ -20,20 +20,11 @@ #include "typedefs.h" // NOLINT(build/include) namespace webrtc { -namespace { -// Set a high sequence number so we'll suffer a wrap-around. -constexpr uint16_t kStartSeqNum = 65534u; - -// Utility method for truncating sequence numbers to uint16. -uint16_t To16u(size_t sequence_number) { - return static_cast(sequence_number & 0xFFFF); -} -} // namespace - -using StorageMode = RtpPacketHistory::StorageMode; class RtpPacketHistoryTest : public ::testing::Test { protected: + static constexpr uint16_t kSeqNum = 88; + RtpPacketHistoryTest() : fake_clock_(123456), hist_(&fake_clock_) {} SimulatedClock fake_clock_; @@ -49,444 +40,256 @@ class RtpPacketHistoryTest : public ::testing::Test { }; TEST_F(RtpPacketHistoryTest, SetStoreStatus) { - EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode()); - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - EXPECT_EQ(StorageMode::kStore, hist_.GetStorageMode()); - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10); - EXPECT_EQ(StorageMode::kStoreAndCull, hist_.GetStorageMode()); - hist_.SetStorePacketsStatus(StorageMode::kDisabled, 0); - EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode()); -} - -TEST_F(RtpPacketHistoryTest, ClearsHistoryAfterSetStoreStatus) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - // Store a packet, but with send-time. It should then not be removed. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - rtc::nullopt); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Changing store status, even to the current one, will clear the history. - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); -} - -TEST_F(RtpPacketHistoryTest, StartSeqResetAfterReset) { - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10); - // Store a packet, but with send-time. It should then not be removed. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - rtc::nullopt); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Changing store status, to clear the history. - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - - // Add a new packet. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission, - rtc::nullopt); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); - - // Advance time past where packet expires. - fake_clock_.AdvanceTimeMilliseconds( - RtpPacketHistory::kPacketCullingDelayFactor * - RtpPacketHistory::kMinPacketDurationMs); - - // Add one more packet and verify no state left from packet before reset. - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)), - kAllowRetransmission, rtc::nullopt); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); - EXPECT_TRUE(hist_.GetPacketState(To16u(kStartSeqNum + 2), false)); + EXPECT_FALSE(hist_.StorePackets()); + hist_.SetStorePacketsStatus(true, 10); + EXPECT_TRUE(hist_.StorePackets()); + hist_.SetStorePacketsStatus(false, 0); + EXPECT_FALSE(hist_.StorePackets()); } TEST_F(RtpPacketHistoryTest, NoStoreStatus) { - EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode()); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); + EXPECT_FALSE(hist_.StorePackets()); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); // Packet should not be stored. - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); + EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); } TEST_F(RtpPacketHistoryTest, GetRtpPacket_NotStored) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - EXPECT_FALSE(hist_.GetPacketState(0, false)); + hist_.SetStorePacketsStatus(true, 10); + EXPECT_FALSE(hist_.GetPacketAndSetSendTime(0, 0, false)); } TEST_F(RtpPacketHistoryTest, PutRtpPacket) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); + hist_.SetStorePacketsStatus(true, 10); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); + EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum)); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); } TEST_F(RtpPacketHistoryTest, GetRtpPacket) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); + hist_.SetStorePacketsStatus(true, 10); int64_t capture_time_ms = 1; - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); packet->set_capture_time_ms(capture_time_ms); rtc::CopyOnWriteBuffer buffer = packet->Buffer(); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); std::unique_ptr packet_out = - hist_.GetPacketAndSetSendTime(kStartSeqNum, false); + hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); EXPECT_TRUE(packet_out); EXPECT_EQ(buffer, packet_out->Buffer()); EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); } TEST_F(RtpPacketHistoryTest, NoCaptureTime) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); + hist_.SetStorePacketsStatus(true, 10); fake_clock_.AdvanceTimeMilliseconds(1); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); packet->set_capture_time_ms(-1); rtc::CopyOnWriteBuffer buffer = packet->Buffer(); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); std::unique_ptr packet_out = - hist_.GetPacketAndSetSendTime(kStartSeqNum, false); + hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); EXPECT_TRUE(packet_out); EXPECT_EQ(buffer, packet_out->Buffer()); EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); } TEST_F(RtpPacketHistoryTest, DontRetransmit) { - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); + hist_.SetStorePacketsStatus(true, 10); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); rtc::CopyOnWriteBuffer buffer = packet->Buffer(); - hist_.PutRtpPacket(std::move(packet), kDontRetransmit, rtc::nullopt); + hist_.PutRtpPacket(std::move(packet), kDontRetransmit, false); - // Get the packet and verify data. std::unique_ptr packet_out; - packet_out = hist_.GetPacketAndSetSendTime(kStartSeqNum, false); - ASSERT_TRUE(packet_out); + packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, true); + EXPECT_FALSE(packet_out); + + packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); + EXPECT_TRUE(packet_out); + EXPECT_EQ(buffer.size(), packet_out->size()); EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); - - // Non-retransmittable packets are immediately removed, so getting in again - // should fail. - EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false)); } -TEST_F(RtpPacketHistoryTest, PacketStateIsCorrect) { - const uint32_t kSsrc = 92384762; - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); - packet->SetSsrc(kSsrc); - packet->SetPayloadSize(1234); - const size_t packet_size = packet->size(); - - hist_.PutRtpPacket(std::move(packet), StorageType::kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - rtc::Optional state = - hist_.GetPacketState(kStartSeqNum, false); - ASSERT_TRUE(state); - EXPECT_EQ(state->rtp_sequence_number, kStartSeqNum); - EXPECT_EQ(state->send_time_ms, fake_clock_.TimeInMilliseconds()); - EXPECT_EQ(state->capture_time_ms, fake_clock_.TimeInMilliseconds()); - EXPECT_EQ(state->ssrc, kSsrc); - EXPECT_EQ(state->payload_size, packet_size); - EXPECT_EQ(state->times_retransmitted, 0u); - - fake_clock_.AdvanceTimeMilliseconds(1); - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false)); - - state = hist_.GetPacketState(kStartSeqNum, false); - ASSERT_TRUE(state); - EXPECT_EQ(state->times_retransmitted, 1u); -} - -TEST_F(RtpPacketHistoryTest, MinResendTimeWithPacer) { +TEST_F(RtpPacketHistoryTest, MinResendTime) { static const int64_t kMinRetransmitIntervalMs = 100; - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - hist_.SetRtt(kMinRetransmitIntervalMs); + hist_.SetStorePacketsStatus(true, 10); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); size_t len = packet->size(); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); // First transmission: TimeToSendPacket() call from pacer. - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false)); + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); - // First retransmission - allow early retransmission. - fake_clock_.AdvanceTimeMilliseconds(1); + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs); + // Time has elapsed. + std::unique_ptr packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true); + EXPECT_TRUE(packet_out); + EXPECT_EQ(len, packet_out->size()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); - // With pacer there's two calls to history: - // 1) When the NACK request arrived, use GetPacketState() to see if the - // packet is there and verify RTT constraints. Then we use the ssrc - // and sequence number to enqueue the retransmission in the pacer - // 2) When the pacer determines that it is time to send the packet, it calls - // GetPacketAndSetSendTime(). This time we do not need to verify RTT as - // has that has already been done. - rtc::Optional packet_state = - hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true); - EXPECT_TRUE(packet_state); - EXPECT_EQ(len, packet_state->payload_size); - EXPECT_EQ(capture_time_ms, packet_state->capture_time_ms); - - // Retransmission was allowed, next send it from pacer. - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, - /*verify_rtt=*/false)); - - // Second retransmission - advance time to just before retransmission OK. fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true)); - - // Advance time to just after retransmission OK. - fake_clock_.AdvanceTimeMilliseconds(1); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true)); - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false)); + // Time has not elapsed. Packet should be found, but no bytes copied. + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); + EXPECT_FALSE( + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true)); } -TEST_F(RtpPacketHistoryTest, MinResendTimeWithoutPacer) { +TEST_F(RtpPacketHistoryTest, EarlyFirstResend) { static const int64_t kMinRetransmitIntervalMs = 100; - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); - hist_.SetRtt(kMinRetransmitIntervalMs); + hist_.SetStorePacketsStatus(true, 10); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); - size_t len = packet->size(); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); + std::unique_ptr packet = CreateRtpPacket(kSeqNum); + rtc::CopyOnWriteBuffer buffer = packet->Buffer(); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); - // First retransmission - allow early retransmission. - fake_clock_.AdvanceTimeMilliseconds(1); - packet = hist_.GetPacketAndSetSendTime(kStartSeqNum, true); - EXPECT_TRUE(packet); - EXPECT_EQ(len, packet->size()); - EXPECT_EQ(capture_time_ms, packet->capture_time_ms()); + // First transmission: TimeToSendPacket() call from pacer. + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); - // Second retransmission - advance time to just before retransmission OK. fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); - EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kStartSeqNum, true)); + // Time has not elapsed, but this is the first retransmission request so + // allow anyway. + std::unique_ptr packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true); + EXPECT_TRUE(packet_out); + EXPECT_EQ(buffer, packet_out->Buffer()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); - // Advance time to just after retransmission OK. - fake_clock_.AdvanceTimeMilliseconds(1); - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, true)); + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); + // Time has not elapsed. Packet should be found, but no bytes copied. + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); + EXPECT_FALSE( + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true)); } -TEST_F(RtpPacketHistoryTest, RemovesOldestSentPacketWhenAtMaxSize) { - const size_t kMaxNumPackets = 10; - hist_.SetStorePacketsStatus(StorageMode::kStore, kMaxNumPackets); +TEST_F(RtpPacketHistoryTest, DynamicExpansion) { + hist_.SetStorePacketsStatus(true, 10); - // History does not allow removing packets within kMinPacketDurationMs, - // so in order to test capacity, make sure insertion spans this time. - const int64_t kPacketIntervalMs = - RtpPacketHistory::kMinPacketDurationMs / kMaxNumPackets; + // Add 4 packets, and then send them. + for (int i = 0; i < 4; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + } + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } + fake_clock_.AdvanceTimeMilliseconds(33); - // Add packets until the buffer is full. - for (size_t i = 0; i < kMaxNumPackets; ++i) { - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum + i); - // Immediate mark packet as sent. - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - fake_clock_.AdvanceTimeMilliseconds(kPacketIntervalMs); + // Add 16 packets, and then send them. History should expand to make this + // work. + for (int i = 4; i < 20; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + } + for (int i = 4; i < 20; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); } - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); + fake_clock_.AdvanceTimeMilliseconds(100); - // History is full, oldest one should be overwritten. - std::unique_ptr packet = - CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets)); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - // Oldest packet should be gone, but packet after than one still present. - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); + // Retransmit last 16 packets. + for (int i = 4; i < 20; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } } -TEST_F(RtpPacketHistoryTest, RemovesOldestPacketWhenAtMaxCapacity) { - // Tests the absolute upper bound on number of stored packets. Don't allow - // storing more than this, even if packets have not yet been sent. - const size_t kMaxNumPackets = RtpPacketHistory::kMaxCapacity; - hist_.SetStorePacketsStatus(StorageMode::kStore, - RtpPacketHistory::kMaxCapacity); - - // Add packets until the buffer is full. - for (size_t i = 0; i < kMaxNumPackets; ++i) { - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum + i); - // Don't mark packets as sent, preventing them from being removed. - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, rtc::nullopt); +TEST_F(RtpPacketHistoryTest, FullExpansion) { + static const int kSendSidePacketHistorySize = 600; + hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize); + for (size_t i = 0; i < RtpPacketHistory::kMaxCapacity + 1; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); } - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); + fake_clock_.AdvanceTimeMilliseconds(100); - // History is full, oldest one should be overwritten. - std::unique_ptr packet = - CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets)); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - // Oldest packet should be gone, but packet after than one still present. - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); -} - -TEST_F(RtpPacketHistoryTest, DontRemoveUnsentPackets) { - const size_t kMaxNumPackets = 10; - hist_.SetStorePacketsStatus(StorageMode::kStore, kMaxNumPackets); - - // Add packets until the buffer is full. - for (size_t i = 0; i < kMaxNumPackets; ++i) { - // Mark packets as unsent. - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + i)), - kAllowRetransmission, rtc::nullopt); + // Retransmit all packets currently in buffer. + for (size_t i = 1; i < RtpPacketHistory::kMaxCapacity + 1; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); } - fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs); - - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // History is full, but old packets not sent, so allow expansion. - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets)), - kAllowRetransmission, fake_clock_.TimeInMilliseconds()); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Set all packet as sent and advance time past min packet duration time, - // otherwise packets till still be prevented from being removed. - for (size_t i = 0; i <= kMaxNumPackets; ++i) { - EXPECT_TRUE(hist_.GetPacketAndSetSendTime(To16u(kStartSeqNum + i), false)); - } - fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs); - // Add a new packet, this means the two oldest ones will be culled. - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets + 1)), - kAllowRetransmission, fake_clock_.TimeInMilliseconds()); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum + 1, false)); - EXPECT_TRUE(hist_.GetPacketState(To16u(kStartSeqNum + 2), false)); } -TEST_F(RtpPacketHistoryTest, DontRemoveTooRecentlyTransmittedPackets) { - // Set size to remove old packets as soon as possible. - hist_.SetStorePacketsStatus(StorageMode::kStore, 1); - - // Add a packet, marked as send, and advance time to just before removal time. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs - - 1); - - // Add a new packet to trigger culling. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Advance time to where packet will be eligible for removal and try again. - fake_clock_.AdvanceTimeMilliseconds(1); - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)), - kAllowRetransmission, fake_clock_.TimeInMilliseconds()); - // First packet should no be gone, but next one still there. - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); -} - -TEST_F(RtpPacketHistoryTest, DontRemoveTooRecentlyTransmittedPacketsHighRtt) { - const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2; - const int64_t kPacketTimeoutMs = - kRttMs * RtpPacketHistory::kMinPacketDurationRtt; - - // Set size to remove old packets as soon as possible. - hist_.SetStorePacketsStatus(StorageMode::kStore, 1); +TEST_F(RtpPacketHistoryTest, DontExpandIfPacketIsOldEnough) { + const size_t kSendSidePacketHistorySize = 600; + const int64_t kRttMs = 334; + hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize); hist_.SetRtt(kRttMs); - // Add a packet, marked as send, and advance time to just before removal time. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - fake_clock_.AdvanceTimeMilliseconds(kPacketTimeoutMs - 1); + // Fill up the buffer with packets. + for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } - // Add a new packet to trigger culling. - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); + // Move clock forward past expiration time. + fake_clock_.AdvanceTimeMilliseconds(kRttMs * 3 + 1); - // Advance time to where packet will be eligible for removal and try again. - fake_clock_.AdvanceTimeMilliseconds(1); - hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)), - kAllowRetransmission, fake_clock_.TimeInMilliseconds()); - // First packet should no be gone, but next one still there. - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false)); + // Insert a new packet and check that the old one for this index has been + // overwritten. + std::unique_ptr packet = + CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true); + EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum)); } -TEST_F(RtpPacketHistoryTest, RemovesOldWithCulling) { - const size_t kMaxNumPackets = 10; - // Enable culling. Even without feedback, this can trigger early removal. - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, kMaxNumPackets); - - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - int64_t kMaxPacketDurationMs = RtpPacketHistory::kMinPacketDurationMs * - RtpPacketHistory::kPacketCullingDelayFactor; - fake_clock_.AdvanceTimeMilliseconds(kMaxPacketDurationMs - 1); - - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Advance to where packet can be culled, even if buffer is not full. - fake_clock_.AdvanceTimeMilliseconds(1); - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); -} - -TEST_F(RtpPacketHistoryTest, RemovesOldWithCullingHighRtt) { - const size_t kMaxNumPackets = 10; - const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2; - // Enable culling. Even without feedback, this can trigger early removal. - hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, kMaxNumPackets); +TEST_F(RtpPacketHistoryTest, ExpandIfPacketTooRecentlyTransmitted) { + const size_t kSendSidePacketHistorySize = 600; + const int64_t kRttMs = 334; + hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize); hist_.SetRtt(kRttMs); - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); + // Fill up the buffer with packets. + for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, kRttMs, false)); + } - int64_t kMaxPacketDurationMs = kRttMs * - RtpPacketHistory::kMinPacketDurationRtt * - RtpPacketHistory::kPacketCullingDelayFactor; - fake_clock_.AdvanceTimeMilliseconds(kMaxPacketDurationMs - 1); + // Move clock forward to just before expiration time. + fake_clock_.AdvanceTimeMilliseconds(kRttMs * 3); - // First packet should still be there. - EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false)); - - // Advance to where packet can be culled, even if buffer is not full. - fake_clock_.AdvanceTimeMilliseconds(1); - hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - - EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false)); + // Insert a new packet and verify that the old one for this index still + // exists - ie the buffer has been expanded. + std::unique_ptr packet = + CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true); + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); } -TEST_F(RtpPacketHistoryTest, GetBestFittingPacket) { - const size_t kTargetSize = 500; - hist_.SetStorePacketsStatus(StorageMode::kStore, 10); +TEST_F(RtpPacketHistoryTest, ExpandIfPacketTooRecentlyTransmittedOnFastLink) { + const size_t kSendSidePacketHistorySize = 600; + const int64_t kRttMs = 5; + hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize); + hist_.SetRtt(kRttMs); - // Add three packets of various sizes. - std::unique_ptr packet = CreateRtpPacket(kStartSeqNum); - packet->SetPayloadSize(kTargetSize); - const size_t target_packet_size = packet->size(); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - packet = CreateRtpPacket(kStartSeqNum + 1); - packet->SetPayloadSize(kTargetSize - 1); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); - packet = CreateRtpPacket(To16u(kStartSeqNum + 2)); - packet->SetPayloadSize(kTargetSize + 1); - hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, - fake_clock_.TimeInMilliseconds()); + // Fill up the buffer with packets. + for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) { + std::unique_ptr packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, kRttMs, false)); + } - EXPECT_EQ(target_packet_size, - hist_.GetBestFittingPacket(target_packet_size)->size()); + // Move clock forward after expiration time based on RTT, but before + // expiration time based on absolute time. + fake_clock_.AdvanceTimeMilliseconds(999); + + // Insert a new packet and verify that the old one for this index still + // exists - ie the buffer has been expanded. + std::unique_ptr packet = + CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true); + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); } } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc index 5b5a85dbcf..f8ef1300dd 100644 --- a/modules/rtp_rtcp/source/rtp_sender.cc +++ b/modules/rtp_rtcp/source/rtp_sender.cc @@ -153,8 +153,7 @@ RTPSender::RTPSender( // be found when paced. if (flexfec_sender) { flexfec_packet_history_.SetStorePacketsStatus( - RtpPacketHistory::StorageMode::kStore, - kMinFlexfecPacketsToStoreForPacing); + true, kMinFlexfecPacketsToStoreForPacing); } } @@ -601,63 +600,39 @@ size_t RTPSender::SendPadData(size_t bytes, } void RTPSender::SetStorePacketsStatus(bool enable, uint16_t number_to_store) { - RtpPacketHistory::StorageMode mode = - enable ? RtpPacketHistory::StorageMode::kStore - : RtpPacketHistory::StorageMode::kDisabled; - packet_history_.SetStorePacketsStatus(mode, number_to_store); + packet_history_.SetStorePacketsStatus(enable, number_to_store); } bool RTPSender::StorePackets() const { - return packet_history_.GetStorageMode() != - RtpPacketHistory::StorageMode::kDisabled; + return packet_history_.StorePackets(); } int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) { - // Try to find packet in RTP packet history. Also verify RTT here, so that we - // don't retransmit too often. - - RTC_DCHECK(retransmission_rate_limiter_); - if (paced_sender_) { - /// If paced sender is used, don't update send state - that will be done in - // the TimeToSendPacket() call. - rtc::Optional stored_packet = - packet_history_.GetPacketState(packet_id, true); - if (!stored_packet) { - // Packet not found. - return 0; - } - - // Check if we're overusing retransmission bitrate. - // TODO(sprang): Add histograms for nack success or failure reasons. - if (!retransmission_rate_limiter_->TryUseRate( - stored_packet->payload_size)) { - return -1; - } - - // Convert from TickTime to Clock since capture_time_ms is based on - // TickTime. - int64_t corrected_capture_tims_ms = - stored_packet->capture_time_ms + clock_delta_ms_; - paced_sender_->InsertPacket( - RtpPacketSender::kNormalPriority, stored_packet->ssrc, - stored_packet->rtp_sequence_number, corrected_capture_tims_ms, - stored_packet->payload_size, true); - - return stored_packet->payload_size; - } - std::unique_ptr packet = - packet_history_.GetPacketAndSetSendTime(packet_id, true); + packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true); if (!packet) { // Packet not found. return 0; } + // Check if we're overusing retransmission bitrate. // TODO(sprang): Add histograms for nack success or failure reasons. - if (!retransmission_rate_limiter_->TryUseRate(packet->size())) { + RTC_DCHECK(retransmission_rate_limiter_); + if (!retransmission_rate_limiter_->TryUseRate(packet->size())) return -1; - } + if (paced_sender_) { + // Convert from TickTime to Clock since capture_time_ms is based on + // TickTime. + int64_t corrected_capture_tims_ms = + packet->capture_time_ms() + clock_delta_ms_; + paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority, + packet->Ssrc(), packet->SequenceNumber(), + corrected_capture_tims_ms, + packet->payload_size(), true); + + return packet->size(); + } bool rtx = (RtxStatus() & kRtxRetransmitted) > 0; int32_t packet_size = static_cast(packet->size()); if (!PrepareAndSendPacket(std::move(packet), rtx, true, PacedPacketInfo())) @@ -735,13 +710,12 @@ bool RTPSender::TimeToSendPacket(uint32_t ssrc, return true; std::unique_ptr packet; - // No need to verify RTT here, it has already been checked before putting the - // packet into the pacer. But _do_ update the send time. if (ssrc == SSRC()) { - packet = packet_history_.GetPacketAndSetSendTime(sequence_number, false); + packet = packet_history_.GetPacketAndSetSendTime(sequence_number, 0, + retransmission); } else if (ssrc == FlexfecSsrc()) { - packet = - flexfec_packet_history_.GetPacketAndSetSendTime(sequence_number, false); + packet = flexfec_packet_history_.GetPacketAndSetSendTime(sequence_number, 0, + retransmission); } if (!packet) { @@ -920,10 +894,9 @@ bool RTPSender::SendToNetwork(std::unique_ptr packet, if (ssrc == flexfec_ssrc) { // Store FlexFEC packets in the history here, so they can be found // when the pacer calls TimeToSendPacket. - flexfec_packet_history_.PutRtpPacket(std::move(packet), storage, - rtc::nullopt); + flexfec_packet_history_.PutRtpPacket(std::move(packet), storage, false); } else { - packet_history_.PutRtpPacket(std::move(packet), storage, rtc::nullopt); + packet_history_.PutRtpPacket(std::move(packet), storage, false); } paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms, @@ -964,7 +937,7 @@ bool RTPSender::SendToNetwork(std::unique_ptr packet, // packet history (even if send failed). if (storage == kAllowRetransmission) { RTC_DCHECK_EQ(ssrc, SSRC()); - packet_history_.PutRtpPacket(std::move(packet), storage, now_ms); + packet_history_.PutRtpPacket(std::move(packet), storage, true); } return sent;