text: /*
   *  Copyright 2017 The WebRTC Project Authors. All rights reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include "p2p/base/packetlossestimator.h"
  
  #include "rtc_base/checks.h"
  
  namespace cricket {
  
  PacketLossEstimator::PacketLossEstimator(int64_t consider_lost_after_ms,
                                           int64_t forget_after_ms)
      : consider_lost_after_ms_(consider_lost_after_ms),
        forget_after_ms_(forget_after_ms) {
    RTC_DCHECK_LT(consider_lost_after_ms, forget_after_ms);
  }
  
  PacketLossEstimator::~PacketLossEstimator() = default;
  
  void PacketLossEstimator::ExpectResponse(std::string id, int64_t sent_time) {
    tracked_packets_[id] = PacketInfo{sent_time, false};
  
    // Called to free memory in case the client hasn't called UpdateResponseRate
    // in a while.
    MaybeForgetOldRequests(sent_time);
  }
  
  void PacketLossEstimator::ReceivedResponse(std::string id,
                                             int64_t received_time) {
    auto iter = tracked_packets_.find(id);
    if (iter != tracked_packets_.end()) {
      auto& packet_info = iter->second;
      packet_info.response_received = true;
    }
  
    // Called to free memory in case the client hasn't called UpdateResponseRate
    // in a while.
    MaybeForgetOldRequests(received_time);
  }
  
  void PacketLossEstimator::UpdateResponseRate(int64_t now) {
    int responses_expected = 0;
    int responses_received = 0;
  
    for (auto iter = tracked_packets_.begin(); iter != tracked_packets_.end();) {
      const auto& packet_info = iter->second;
      if (Forget(packet_info, now)) {
        iter = tracked_packets_.erase(iter);
        continue;
      }
      if (packet_info.response_received) {
        responses_expected += 1;
        responses_received += 1;
      } else if (ConsiderLost(packet_info, now)) {
        responses_expected += 1;
      }
      ++iter;
    }
  
    if (responses_expected > 0) {
      response_rate_ =
          static_cast<double>(responses_received) / responses_expected;
    } else {
      response_rate_ = 1.0;
    }
  
    last_forgot_at_ = now;
  }
  
  void PacketLossEstimator::MaybeForgetOldRequests(int64_t now) {
    if (now - last_forgot_at_ <= forget_after_ms_) {
      return;
    }
  
    for (auto iter = tracked_packets_.begin(); iter != tracked_packets_.end();) {
      const auto& packet_info = iter->second;
      if (Forget(packet_info, now)) {
        iter = tracked_packets_.erase(iter);
      } else {
        ++iter;
      }
    }
  
    last_forgot_at_ = now;
  }
  
  bool PacketLossEstimator::ConsiderLost(const PacketInfo& packet_info,
                                         int64_t now) const {
    return packet_info.sent_time < now - consider_lost_after_ms_;
  }
  
  bool PacketLossEstimator::Forget(const PacketInfo& packet_info,
                                   int64_t now) const {
    return now - packet_info.sent_time > forget_after_ms_;
  }
  
  std::size_t PacketLossEstimator::tracked_packet_count_for_testing() const {
    return tracked_packets_.size();
  }
  
  }  // namespace cricket
  