blob: ae05ff5107c23dccfc776b98e4009d70157a4598 [file] [log] [blame]
/*
* 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 <sstream>
#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();
}
std::string PacketLossEstimator::TrackedPacketsStringForTesting(
std::size_t max) const {
std::ostringstream oss;
size_t count = 0;
for (const auto& p : tracked_packets_) {
const auto& id = p.first;
const auto& packet_info = p.second;
oss << "{ " << id << ", " << packet_info.sent_time << "}, ";
count += 1;
if (count == max) {
oss << "...";
break;
}
}
return oss.str();
}
} // namespace cricket