Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Unified Diff: webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc

Issue 2632203002: Packet Loss Tracker - Stream Separation (Closed)
Patch Set: . Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
diff --git a/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc b/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
index c05b044814d9f5a2916d985d40a1a7f8da7fe9ff..ea38f149da0d61a0184ad611f8a2f4fa479ae94b 100644
--- a/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
+++ b/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
@@ -19,9 +19,6 @@
namespace {
constexpr uint16_t kSeqNumHalf = 0x8000u;
-constexpr uint16_t kSeqNumQuarter = kSeqNumHalf / 2;
-constexpr size_t kMaxConsecutiveOldReports = 4;
-
void UpdateCounter(size_t* counter, bool increment) {
if (increment) {
RTC_DCHECK_LT(*counter, std::numeric_limits<std::size_t>::max());
@@ -37,25 +34,25 @@ void UpdateCounter(size_t* counter, bool increment) {
namespace webrtc {
TransportFeedbackPacketLossTracker::TransportFeedbackPacketLossTracker(
- size_t max_window_size,
- size_t plr_min_num_packets,
- size_t rplr_min_num_pairs)
- : max_window_size_(max_window_size),
+ size_t max_acked_packets,
+ size_t plr_min_num_acked_packets,
+ size_t rplr_min_num_acked_pairs)
+ : max_acked_packets_(max_acked_packets),
ref_packet_status_(packet_status_window_.begin()),
- plr_state_(plr_min_num_packets),
- rplr_state_(rplr_min_num_pairs) {
- RTC_DCHECK_GT(plr_min_num_packets, 0);
- RTC_DCHECK_GE(max_window_size, plr_min_num_packets);
- RTC_DCHECK_LE(max_window_size, kSeqNumHalf);
- RTC_DCHECK_GT(rplr_min_num_pairs, 0);
- RTC_DCHECK_GT(max_window_size, rplr_min_num_pairs);
+ plr_state_(plr_min_num_acked_packets),
+ rplr_state_(rplr_min_num_acked_pairs) {
+ RTC_DCHECK_GT(plr_min_num_acked_packets, 0);
+ RTC_DCHECK_GE(max_acked_packets, plr_min_num_acked_packets);
+ RTC_DCHECK_LE(max_acked_packets, kSeqNumHalf);
+ RTC_DCHECK_GT(rplr_min_num_acked_pairs, 0);
+ RTC_DCHECK_GT(max_acked_packets, rplr_min_num_acked_pairs);
Reset();
}
void TransportFeedbackPacketLossTracker::Reset() {
+ acked_packets_ = 0;
plr_state_.Reset();
rplr_state_.Reset();
- num_consecutive_old_reports_ = 0;
packet_status_window_.clear();
ref_packet_status_ = packet_status_window_.begin();
}
@@ -65,13 +62,33 @@ uint16_t TransportFeedbackPacketLossTracker::ReferenceSequenceNumber() const {
return ref_packet_status_->first;
}
-bool TransportFeedbackPacketLossTracker::IsOldSequenceNumber(
- uint16_t seq_num) const {
- if (packet_status_window_.empty()) {
- return false;
+uint16_t TransportFeedbackPacketLossTracker::NewestSequenceNumber() const {
+ RTC_DCHECK(!packet_status_window_.empty());
+ return PreviousPacketStatus(packet_status_window_.end())->first;
+}
+
+void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num) {
+ if (packet_status_window_.find(seq_num) != packet_status_window_.end() ||
+ (!packet_status_window_.empty() &&
+ ForwardDiff(seq_num, NewestSequenceNumber()) <= kSeqNumHalf)) {
+ // The only way for these two to happen is when the stream lies dormant for
+ // long enough for the sequence numbers to wrap. Everything in the window in
+ // such a case would be too old to use.
+ Reset();
+ }
+
+ // Shift older packets out of window.
+ while (!packet_status_window_.empty() &&
+ ForwardDiff(ref_packet_status_->first, seq_num) >= kSeqNumHalf) {
+ RemoveOldestPacketStatus();
+ }
+
+ packet_status_window_.insert(packet_status_window_.end(),
+ std::make_pair(seq_num, PacketStatus::Unacked));
+
+ if (packet_status_window_.size() == 1) {
+ ref_packet_status_ = packet_status_window_.cbegin();
}
- const uint16_t diff = ForwardDiff(ReferenceSequenceNumber(), seq_num);
- return diff >= 3 * kSeqNumQuarter;
}
void TransportFeedbackPacketLossTracker::OnReceivedTransportFeedback(
@@ -79,41 +96,16 @@ void TransportFeedbackPacketLossTracker::OnReceivedTransportFeedback(
const auto& fb_vector = feedback.GetStatusVector();
const uint16_t base_seq_num = feedback.GetBaseSequence();
- if (IsOldSequenceNumber(base_seq_num)) {
- ++num_consecutive_old_reports_;
- if (num_consecutive_old_reports_ <= kMaxConsecutiveOldReports) {
- // If the number consecutive old reports have not exceed a threshold, we
- // consider this packet as a late arrival. We could consider adding it to
- // |packet_status_window_|, but in current implementation, we simply
- // ignore it.
- return;
- }
- // If we see several consecutive older reports, we assume that we've not
- // received reports for an exceedingly long time, and do a reset.
- Reset();
- RTC_DCHECK(!IsOldSequenceNumber(base_seq_num));
- } else {
- num_consecutive_old_reports_ = 0;
- }
-
uint16_t seq_num = base_seq_num;
for (size_t i = 0; i < fb_vector.size(); ++i, ++seq_num) {
- // Remove the oldest feedbacks so that the distance between the oldest and
- // the packet to be added does not exceed or equal to half of total sequence
- // numbers.
- while (!packet_status_window_.empty() &&
- ForwardDiff(ReferenceSequenceNumber(), seq_num) >= kSeqNumHalf) {
- RemoveOldestPacketStatus();
- }
-
- const bool received =
- fb_vector[i] !=
- webrtc::rtcp::TransportFeedback::StatusSymbol::kNotReceived;
- InsertPacketStatus(seq_num, received);
-
- while (packet_status_window_.size() > max_window_size_) {
- // Make sure that the window holds at most |max_window_size_| items.
- RemoveOldestPacketStatus();
+ const auto& it = packet_status_window_.find(seq_num);
+
+ // Packets which aren't at least marked as unacked either do not belong to
+ // this media stream, or have been shifted out of window.
+ if (it != packet_status_window_.end()) {
+ const bool received = fb_vector[i] !=
+ webrtc::rtcp::TransportFeedback::StatusSymbol::kNotReceived;
+ RecordFeedback(it, received);
}
}
}
@@ -128,25 +120,38 @@ TransportFeedbackPacketLossTracker::GetRecoverablePacketLossRate() const {
return rplr_state_.GetMetric();
}
-void TransportFeedbackPacketLossTracker::InsertPacketStatus(uint16_t seq_num,
- bool received) {
- const auto& ret =
- packet_status_window_.insert(std::make_pair(seq_num, received));
- if (!ret.second) {
- if (!ret.first->second && received) {
+void TransportFeedbackPacketLossTracker::RecordFeedback(
+ PacketStatusMap::iterator it,
+ bool received) {
+ if (it->second != PacketStatus::Unacked) {
+ // Normally, packets are sent (inserted into window as "unacked"), then we
+ // receive one feedback for them.
+ // But it is possible that a packet would receive two feedbacks. Then:
+ if (it->second == PacketStatus::Lost && received) {
// If older status said that the packet was lost but newer one says it
// is received, we take the newer one.
- UpdateMetrics(ret.first, false);
- ret.first->second = received;
+ UpdateMetrics(it, false);
+ it->second = PacketStatus::Unacked; // For clarity; overwritten shortly.
} else {
// If the value is unchanged or if older status said that the packet was
// received but the newer one says it is lost, we ignore it.
+ // The standard allows for previously-reported packets to carry
+ // no report when the reports overlap, which also looks like the
+ // packet is being reported as lost.
return;
}
}
- UpdateMetrics(ret.first, true);
- if (packet_status_window_.size() == 1)
- ref_packet_status_ = ret.first;
+
+ // Change from UNACKED to RECEIVED/LOST.
+ it->second = received ? PacketStatus::Received : PacketStatus::Lost;
+ UpdateMetrics(it, true);
+
+ // Remove packets from the beginning of the window until maximum-acked
+ // is observed again. Note that multiple sent-but-unacked packets might
+ // be removed before we reach the first acked (whether as received or as
+ // lost) packet.
+ while (acked_packets_ > max_acked_packets_)
+ RemoveOldestPacketStatus();
}
void TransportFeedbackPacketLossTracker::RemoveOldestPacketStatus() {
@@ -157,34 +162,54 @@ void TransportFeedbackPacketLossTracker::RemoveOldestPacketStatus() {
}
void TransportFeedbackPacketLossTracker::UpdateMetrics(
- PacketStatusIterator it,
+ ConstPacketStatusIterator it,
bool apply /* false = undo */) {
RTC_DCHECK(it != packet_status_window_.end());
+ // Metrics are dependent on feedbacks from the other side. We don't want
+ // to update the metrics each time a packet is sent, except for the case
+ // when it shifts old sent-but-unacked-packets out of window.
+ RTC_DCHECK(!apply || it->second != PacketStatus::Unacked);
+
+ if (it->second != PacketStatus::Unacked) {
+ UpdateCounter(&acked_packets_, apply);
+ }
+
UpdatePlr(it, apply);
UpdateRplr(it, apply);
}
void TransportFeedbackPacketLossTracker::UpdatePlr(
- PacketStatusIterator it,
+ ConstPacketStatusIterator it,
bool apply /* false = undo */) {
- // Record or undo reception status of currently handled packet.
- if (it->second) {
- UpdateCounter(&plr_state_.num_received_packets_, apply);
- } else {
- UpdateCounter(&plr_state_.num_lost_packets_, apply);
+ switch (it->second) {
+ case PacketStatus::Unacked:
+ return;
+ case PacketStatus::Received:
+ UpdateCounter(&plr_state_.num_received_packets_, apply);
+ break;
+ case PacketStatus::Lost:
+ UpdateCounter(&plr_state_.num_lost_packets_, apply);
+ break;
+ default:
+ RTC_NOTREACHED();
}
}
void TransportFeedbackPacketLossTracker::UpdateRplr(
- PacketStatusIterator it,
+ ConstPacketStatusIterator it,
bool apply /* false = undo */) {
- // Previous packet and current packet might compose a known pair.
- // If so, the RPLR state needs to be updated accordingly.
+ if (it->second == PacketStatus::Unacked) {
+ // Unacked packets cannot compose a pair.
+ return;
+ }
+
+ // Previous packet and current packet might compose a pair.
if (it != ref_packet_status_) {
const auto& prev = PreviousPacketStatus(it);
- if (prev->first == static_cast<uint16_t>(it->first - 1)) {
- UpdateCounter(&rplr_state_.num_known_pairs_, apply);
- if (!prev->second && it->second) {
+ if (prev->second != PacketStatus::Unacked) {
+ UpdateCounter(&rplr_state_.num_acked_pairs_, apply);
+ if (prev->second == PacketStatus::Lost &&
+ it->second == PacketStatus::Received) {
UpdateCounter(
&rplr_state_.num_recoverable_losses_, apply);
}
@@ -192,20 +217,20 @@ void TransportFeedbackPacketLossTracker::UpdateRplr(
}
// Current packet and next packet might compose a pair.
- // If so, the RPLR state needs to be updated accordingly.
const auto& next = NextPacketStatus(it);
if (next != packet_status_window_.end() &&
- next->first == static_cast<uint16_t>(it->first + 1)) {
- UpdateCounter(&rplr_state_.num_known_pairs_, apply);
- if (!it->second && next->second) {
+ next->second != PacketStatus::Unacked) {
+ UpdateCounter(&rplr_state_.num_acked_pairs_, apply);
+ if (it->second == PacketStatus::Lost &&
+ next->second == PacketStatus::Received) {
UpdateCounter(&rplr_state_.num_recoverable_losses_, apply);
}
}
}
-TransportFeedbackPacketLossTracker::PacketStatusIterator
+TransportFeedbackPacketLossTracker::ConstPacketStatusIterator
TransportFeedbackPacketLossTracker::PreviousPacketStatus(
- PacketStatusIterator it) {
+ ConstPacketStatusIterator it) const {
RTC_DCHECK(it != ref_packet_status_);
if (it == packet_status_window_.end()) {
// This is to make PreviousPacketStatus(packet_status_window_.end()) point
@@ -221,8 +246,9 @@ TransportFeedbackPacketLossTracker::PreviousPacketStatus(
return --it;
}
-TransportFeedbackPacketLossTracker::PacketStatusIterator
-TransportFeedbackPacketLossTracker::NextPacketStatus(PacketStatusIterator it) {
+TransportFeedbackPacketLossTracker::ConstPacketStatusIterator
+TransportFeedbackPacketLossTracker::NextPacketStatus(
+ ConstPacketStatusIterator it) const {
RTC_DCHECK(it != packet_status_window_.end());
++it;
if (it == packet_status_window_.end()) {
@@ -244,26 +270,35 @@ TransportFeedbackPacketLossTracker::NextPacketStatus(PacketStatusIterator it) {
// error after long period, we can remove the fuzzer test, and move this method
// to unit test.
void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
- RTC_CHECK_LE(packet_status_window_.size(), max_window_size_);
- RTC_CHECK_EQ(packet_status_window_.size(),
- plr_state_.num_lost_packets_ + plr_state_.num_received_packets_);
+ RTC_CHECK_EQ(plr_state_.num_received_packets_ + plr_state_.num_lost_packets_,
+ acked_packets_);
+ RTC_CHECK_LE(acked_packets_, packet_status_window_.size());
+ RTC_CHECK_LE(acked_packets_, max_acked_packets_);
RTC_CHECK_LE(rplr_state_.num_recoverable_losses_,
- rplr_state_.num_known_pairs_);
- RTC_CHECK_LE(rplr_state_.num_known_pairs_,
- packet_status_window_.size() - 1);
+ rplr_state_.num_acked_pairs_);
+ RTC_CHECK_LE(rplr_state_.num_acked_pairs_, acked_packets_ - 1);
+ size_t unacked_packets = 0;
size_t received_packets = 0;
size_t lost_packets = 0;
- size_t known_status_pairs = 0;
+ size_t acked_pairs = 0;
size_t recoverable_losses = 0;
if (!packet_status_window_.empty()) {
- PacketStatusIterator it = ref_packet_status_;
+ ConstPacketStatusIterator it = ref_packet_status_;
do {
- if (it->second) {
- ++received_packets;
- } else {
- ++lost_packets;
+ switch (it->second) {
+ case PacketStatus::Unacked:
+ ++unacked_packets;
+ break;
+ case PacketStatus::Received:
+ ++received_packets;
+ break;
+ case PacketStatus::Lost:
+ ++lost_packets;
+ break;
+ default:
+ RTC_NOTREACHED();
}
auto next = std::next(it);
@@ -271,9 +306,11 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
next = packet_status_window_.begin();
if (next != ref_packet_status_ &&
- next->first == static_cast<uint16_t>(it->first + 1)) {
- ++known_status_pairs;
- if (!it->second && next->second)
+ it->second != PacketStatus::Unacked &&
+ next->second != PacketStatus::Unacked) {
+ ++acked_pairs;
+ if (it->second == PacketStatus::Lost &&
+ next->second == PacketStatus::Received)
++recoverable_losses;
}
@@ -286,14 +323,16 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
RTC_CHECK_EQ(plr_state_.num_received_packets_, received_packets);
RTC_CHECK_EQ(plr_state_.num_lost_packets_, lost_packets);
- RTC_CHECK_EQ(rplr_state_.num_known_pairs_, known_status_pairs);
+ RTC_CHECK_EQ(packet_status_window_.size(),
+ unacked_packets + received_packets + lost_packets);
+ RTC_CHECK_EQ(rplr_state_.num_acked_pairs_, acked_pairs);
RTC_CHECK_EQ(rplr_state_.num_recoverable_losses_, recoverable_losses);
}
rtc::Optional<float>
TransportFeedbackPacketLossTracker::PlrState::GetMetric() const {
const size_t total = num_lost_packets_ + num_received_packets_;
- if (total < min_num_packets_) {
+ if (total < min_num_acked_packets_) {
return rtc::Optional<float>();
} else {
return rtc::Optional<float>(
@@ -303,11 +342,11 @@ TransportFeedbackPacketLossTracker::PlrState::GetMetric() const {
rtc::Optional<float>
TransportFeedbackPacketLossTracker::RplrState::GetMetric() const {
- if (num_known_pairs_ < min_num_pairs_) {
+ if (num_acked_pairs_ < min_num_acked_pairs_) {
return rtc::Optional<float>();
} else {
return rtc::Optional<float>(
- static_cast<float>(num_recoverable_losses_) / num_known_pairs_);
+ static_cast<float>(num_recoverable_losses_) / num_acked_pairs_);
}
}

Powered by Google App Engine
This is Rietveld 408576698