| 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 ea38f149da0d61a0184ad611f8a2f4fa479ae94b..637794398e2fe8edffc1a9c2e3bdbd34bd970df5 100644
|
| --- a/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
|
| +++ b/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc
|
| @@ -28,24 +28,21 @@ void UpdateCounter(size_t* counter, bool increment) {
|
| --(*counter);
|
| }
|
| }
|
| -
|
| } // namespace
|
|
|
| namespace webrtc {
|
|
|
| TransportFeedbackPacketLossTracker::TransportFeedbackPacketLossTracker(
|
| - size_t max_acked_packets,
|
| + int64_t max_window_size_ms,
|
| size_t plr_min_num_acked_packets,
|
| size_t rplr_min_num_acked_pairs)
|
| - : max_acked_packets_(max_acked_packets),
|
| + : max_window_size_ms_(max_window_size_ms),
|
| ref_packet_status_(packet_status_window_.begin()),
|
| plr_state_(plr_min_num_acked_packets),
|
| rplr_state_(rplr_min_num_acked_pairs) {
|
| + RTC_DCHECK_GT(max_window_size_ms, 0);
|
| 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();
|
| }
|
|
|
| @@ -67,7 +64,14 @@ uint16_t TransportFeedbackPacketLossTracker::NewestSequenceNumber() const {
|
| return PreviousPacketStatus(packet_status_window_.end())->first;
|
| }
|
|
|
| -void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num) {
|
| +void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num,
|
| + int64_t send_time_ms) {
|
| + // Sanity - time can't flow backwards.
|
| + RTC_DCHECK(
|
| + packet_status_window_.empty() ||
|
| + PreviousPacketStatus(packet_status_window_.end())->second.send_time_ms <=
|
| + send_time_ms);
|
| +
|
| if (packet_status_window_.find(seq_num) != packet_status_window_.end() ||
|
| (!packet_status_window_.empty() &&
|
| ForwardDiff(seq_num, NewestSequenceNumber()) <= kSeqNumHalf)) {
|
| @@ -77,14 +81,16 @@ void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num) {
|
| Reset();
|
| }
|
|
|
| - // Shift older packets out of window.
|
| + // Maintain a window where the newest sequence number is at most 0x7fff away
|
| + // from the oldest, so that would could still distinguish old/new.
|
| while (!packet_status_window_.empty() &&
|
| ForwardDiff(ref_packet_status_->first, seq_num) >= kSeqNumHalf) {
|
| RemoveOldestPacketStatus();
|
| }
|
|
|
| + SentPacket sent_packet(send_time_ms, PacketStatus::Unacked);
|
| packet_status_window_.insert(packet_status_window_.end(),
|
| - std::make_pair(seq_num, PacketStatus::Unacked));
|
| + std::make_pair(seq_num, sent_packet));
|
|
|
| if (packet_status_window_.size() == 1) {
|
| ref_packet_status_ = packet_status_window_.cbegin();
|
| @@ -93,20 +99,25 @@ void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num) {
|
|
|
| void TransportFeedbackPacketLossTracker::OnReceivedTransportFeedback(
|
| const rtcp::TransportFeedback& feedback) {
|
| - const auto& fb_vector = feedback.GetStatusVector();
|
| + const auto& status_vector = feedback.GetStatusVector();
|
| const uint16_t base_seq_num = feedback.GetBaseSequence();
|
|
|
| uint16_t seq_num = base_seq_num;
|
| - for (size_t i = 0; i < fb_vector.size(); ++i, ++seq_num) {
|
| + for (size_t i = 0; i < status_vector.size(); ++i, ++seq_num) {
|
| 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);
|
| - }
|
| + if (it == packet_status_window_.end())
|
| + continue;
|
| +
|
| + const bool lost =
|
| + status_vector[i] ==
|
| + webrtc::rtcp::TransportFeedback::StatusSymbol::kNotReceived;
|
| + const PacketStatus packet_status =
|
| + lost ? PacketStatus::Lost : PacketStatus::Received;
|
| +
|
| + UpdatePacketStatus(it, packet_status);
|
| }
|
| }
|
|
|
| @@ -120,18 +131,20 @@ TransportFeedbackPacketLossTracker::GetRecoverablePacketLossRate() const {
|
| return rplr_state_.GetMetric();
|
| }
|
|
|
| -void TransportFeedbackPacketLossTracker::RecordFeedback(
|
| - PacketStatusMap::iterator it,
|
| - bool received) {
|
| - if (it->second != PacketStatus::Unacked) {
|
| +void TransportFeedbackPacketLossTracker::UpdatePacketStatus(
|
| + SentPacketStatusMap::iterator it,
|
| + PacketStatus new_status) {
|
| + if (it->second.status != 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 (it->second.status == PacketStatus::Lost &&
|
| + new_status == PacketStatus::Received) {
|
| // If older status said that the packet was lost but newer one says it
|
| // is received, we take the newer one.
|
| UpdateMetrics(it, false);
|
| - it->second = PacketStatus::Unacked; // For clarity; overwritten shortly.
|
| + it->second.status =
|
| + 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.
|
| @@ -143,15 +156,19 @@ void TransportFeedbackPacketLossTracker::RecordFeedback(
|
| }
|
|
|
| // Change from UNACKED to RECEIVED/LOST.
|
| - it->second = received ? PacketStatus::Received : PacketStatus::Lost;
|
| + it->second.status = new_status;
|
| 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_)
|
| + // Remove packets from the beginning of the window until we only hold packets,
|
| + // be they acked or unacked, which are not more than |max_window_size_ms|
|
| + // older from the newest packet. (If the packet we're now inserting into the
|
| + // window isn't the newest, it would not trigger any removals; the newest
|
| + // already removed all relevant.)
|
| + while (ref_packet_status_ != packet_status_window_.end() &&
|
| + (it->second.send_time_ms - ref_packet_status_->second.send_time_ms) >
|
| + max_window_size_ms_) {
|
| RemoveOldestPacketStatus();
|
| + }
|
| }
|
|
|
| void TransportFeedbackPacketLossTracker::RemoveOldestPacketStatus() {
|
| @@ -168,9 +185,9 @@ void TransportFeedbackPacketLossTracker::UpdateMetrics(
|
| // 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);
|
| + RTC_DCHECK(!apply || it->second.status != PacketStatus::Unacked);
|
|
|
| - if (it->second != PacketStatus::Unacked) {
|
| + if (it->second.status != PacketStatus::Unacked) {
|
| UpdateCounter(&acked_packets_, apply);
|
| }
|
|
|
| @@ -181,7 +198,7 @@ void TransportFeedbackPacketLossTracker::UpdateMetrics(
|
| void TransportFeedbackPacketLossTracker::UpdatePlr(
|
| ConstPacketStatusIterator it,
|
| bool apply /* false = undo */) {
|
| - switch (it->second) {
|
| + switch (it->second.status) {
|
| case PacketStatus::Unacked:
|
| return;
|
| case PacketStatus::Received:
|
| @@ -198,7 +215,7 @@ void TransportFeedbackPacketLossTracker::UpdatePlr(
|
| void TransportFeedbackPacketLossTracker::UpdateRplr(
|
| ConstPacketStatusIterator it,
|
| bool apply /* false = undo */) {
|
| - if (it->second == PacketStatus::Unacked) {
|
| + if (it->second.status == PacketStatus::Unacked) {
|
| // Unacked packets cannot compose a pair.
|
| return;
|
| }
|
| @@ -206,10 +223,10 @@ void TransportFeedbackPacketLossTracker::UpdateRplr(
|
| // Previous packet and current packet might compose a pair.
|
| if (it != ref_packet_status_) {
|
| const auto& prev = PreviousPacketStatus(it);
|
| - if (prev->second != PacketStatus::Unacked) {
|
| + if (prev->second.status != PacketStatus::Unacked) {
|
| UpdateCounter(&rplr_state_.num_acked_pairs_, apply);
|
| - if (prev->second == PacketStatus::Lost &&
|
| - it->second == PacketStatus::Received) {
|
| + if (prev->second.status == PacketStatus::Lost &&
|
| + it->second.status == PacketStatus::Received) {
|
| UpdateCounter(
|
| &rplr_state_.num_recoverable_losses_, apply);
|
| }
|
| @@ -219,10 +236,10 @@ void TransportFeedbackPacketLossTracker::UpdateRplr(
|
| // Current packet and next packet might compose a pair.
|
| const auto& next = NextPacketStatus(it);
|
| if (next != packet_status_window_.end() &&
|
| - next->second != PacketStatus::Unacked) {
|
| + next->second.status != PacketStatus::Unacked) {
|
| UpdateCounter(&rplr_state_.num_acked_pairs_, apply);
|
| - if (it->second == PacketStatus::Lost &&
|
| - next->second == PacketStatus::Received) {
|
| + if (it->second.status == PacketStatus::Lost &&
|
| + next->second.status == PacketStatus::Received) {
|
| UpdateCounter(&rplr_state_.num_recoverable_losses_, apply);
|
| }
|
| }
|
| @@ -273,7 +290,6 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
|
| 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_acked_pairs_);
|
| RTC_CHECK_LE(rplr_state_.num_acked_pairs_, acked_packets_ - 1);
|
| @@ -287,7 +303,7 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
|
| if (!packet_status_window_.empty()) {
|
| ConstPacketStatusIterator it = ref_packet_status_;
|
| do {
|
| - switch (it->second) {
|
| + switch (it->second.status) {
|
| case PacketStatus::Unacked:
|
| ++unacked_packets;
|
| break;
|
| @@ -305,13 +321,17 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only!
|
| if (next == packet_status_window_.end())
|
| next = packet_status_window_.begin();
|
|
|
| - if (next != ref_packet_status_ &&
|
| - it->second != PacketStatus::Unacked &&
|
| - next->second != PacketStatus::Unacked) {
|
| - ++acked_pairs;
|
| - if (it->second == PacketStatus::Lost &&
|
| - next->second == PacketStatus::Received)
|
| - ++recoverable_losses;
|
| + if (next != ref_packet_status_) { // If we have a next packet...
|
| + RTC_CHECK_GE(next->second.send_time_ms, it->second.send_time_ms);
|
| +
|
| + if (it->second.status != PacketStatus::Unacked &&
|
| + next->second.status != PacketStatus::Unacked) {
|
| + ++acked_pairs;
|
| + if (it->second.status == PacketStatus::Lost &&
|
| + next->second.status == PacketStatus::Received) {
|
| + ++recoverable_losses;
|
| + }
|
| + }
|
| }
|
|
|
| RTC_CHECK_LT(ForwardDiff(ReferenceSequenceNumber(), it->first),
|
|
|