New ProbingCalculator class.

The ProbingCalculator class calculates and validates the results from
probing attempts.

BUG=webrtc:5859

Review-Url: https://codereview.webrtc.org/2121183002
Cr-Commit-Position: refs/heads/master@{#13589}
This commit is contained in:
philipel 2016-08-01 08:49:04 -07:00 committed by Commit bot
parent ddf3e4accd
commit 233c4ba4fd
6 changed files with 298 additions and 1 deletions

View File

@ -14,6 +14,8 @@ source_set("congestion_controller") {
"delay_based_bwe.cc",
"delay_based_bwe.h",
"include/congestion_controller.h",
"probe_bitrate_estimator.cc",
"probe_bitrate_estimator.h",
]
configs += [ "../..:common_config" ]

View File

@ -18,9 +18,11 @@
],
'sources': [
'congestion_controller.cc',
'include/congestion_controller.h',
'delay_based_bwe.cc',
'delay_based_bwe.h',
'include/congestion_controller.h',
'probe_bitrate_estimator.cc',
'probe_bitrate_estimator.h',
],
# TODO(jschuh): Bug 1348: fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016 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 "webrtc/modules/congestion_controller/probe_bitrate_estimator.h"
#include <vector>
#include <utility>
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h"
namespace webrtc {
class TestProbeBitrateEstimator : public ::testing::Test {
public:
TestProbeBitrateEstimator() : probe_bitrate_estimator_() {}
void AddPacketFeedback(int probe_cluster_id,
size_t size,
int64_t send_time_ms,
int64_t arrival_time_ms) {
PacketInfo info(arrival_time_ms, send_time_ms, 0, size, probe_cluster_id);
ProbingResult res = probe_bitrate_estimator_.PacketFeedback(info);
if (res.bps != ProbingResult::kNoEstimate)
results_.emplace_back(res.bps, res.timestamp);
}
void CheckResult(size_t index, int bps, int max_diff, int64_t timestamp) {
ASSERT_GT(results_.size(), index);
EXPECT_NEAR(results_[index].first, bps, max_diff);
EXPECT_EQ(results_[index].second, timestamp);
}
protected:
std::vector<std::pair<int, int64_t>> results_;
ProbeBitrateEstimator probe_bitrate_estimator_;
};
TEST_F(TestProbeBitrateEstimator, OneCluster) {
AddPacketFeedback(0, 1000, 0, 10);
AddPacketFeedback(0, 1000, 10, 20);
AddPacketFeedback(0, 1000, 20, 30);
AddPacketFeedback(0, 1000, 40, 50);
CheckResult(0, 100000, 10, 50);
}
TEST_F(TestProbeBitrateEstimator, FastReceive) {
AddPacketFeedback(0, 1000, 0, 15);
AddPacketFeedback(0, 1000, 10, 30);
AddPacketFeedback(0, 1000, 20, 40);
AddPacketFeedback(0, 1000, 40, 50);
CheckResult(0, 100000, 10, 50);
}
TEST_F(TestProbeBitrateEstimator, TooFastReceive) {
AddPacketFeedback(0, 1000, 0, 19);
AddPacketFeedback(0, 1000, 10, 30);
AddPacketFeedback(0, 1000, 20, 40);
AddPacketFeedback(0, 1000, 40, 50);
EXPECT_TRUE(results_.empty());
}
TEST_F(TestProbeBitrateEstimator, SlowReceive) {
AddPacketFeedback(0, 1000, 0, 10);
AddPacketFeedback(0, 1000, 10, 40);
AddPacketFeedback(0, 1000, 20, 70);
AddPacketFeedback(0, 1000, 40, 110);
CheckResult(0, 40000, 10, 110);
}
TEST_F(TestProbeBitrateEstimator, BurstReceive) {
AddPacketFeedback(0, 1000, 0, 50);
AddPacketFeedback(0, 1000, 10, 50);
AddPacketFeedback(0, 1000, 20, 50);
AddPacketFeedback(0, 1000, 40, 50);
EXPECT_TRUE(results_.empty());
}
TEST_F(TestProbeBitrateEstimator, MultipleClusters) {
AddPacketFeedback(0, 1000, 0, 10);
AddPacketFeedback(0, 1000, 10, 20);
AddPacketFeedback(0, 1000, 20, 30);
AddPacketFeedback(0, 1000, 40, 60);
AddPacketFeedback(0, 1000, 50, 60);
CheckResult(0, 80000, 10, 60);
CheckResult(1, 100000, 10, 60);
AddPacketFeedback(1, 1000, 60, 70);
AddPacketFeedback(1, 1000, 65, 77);
AddPacketFeedback(1, 1000, 70, 84);
AddPacketFeedback(1, 1000, 75, 90);
CheckResult(2, 200000, 10, 90);
}
TEST_F(TestProbeBitrateEstimator, OldProbe) {
AddPacketFeedback(0, 1000, 0, 10);
AddPacketFeedback(0, 1000, 10, 20);
AddPacketFeedback(0, 1000, 20, 30);
AddPacketFeedback(1, 1000, 60, 70);
AddPacketFeedback(1, 1000, 65, 77);
AddPacketFeedback(1, 1000, 70, 84);
AddPacketFeedback(1, 1000, 75, 90);
CheckResult(0, 200000, 10, 90);
AddPacketFeedback(0, 1000, 40, 60);
EXPECT_EQ(1ul, results_.size());
}
} // namespace webrtc

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2016 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 "webrtc/modules/congestion_controller/probe_bitrate_estimator.h"
#include <algorithm>
#include "webrtc/base/logging.h"
namespace {
// Max number of saved clusters.
constexpr size_t kMaxNumSavedClusters = 5;
// The minumum number of probes we need for a valid cluster.
constexpr int kMinNumProbesValidCluster = 4;
// The maximum (receive rate)/(send rate) ratio for a valid estimate.
constexpr float kValidRatio = 1.2f;
}
namespace webrtc {
ProbingResult::ProbingResult() : bps(kNoEstimate), timestamp(0) {}
ProbingResult::ProbingResult(int bps, int64_t timestamp)
: bps(bps), timestamp(timestamp) {}
ProbeBitrateEstimator::ProbeBitrateEstimator() : last_valid_cluster_id_(0) {}
ProbingResult ProbeBitrateEstimator::PacketFeedback(
const PacketInfo& packet_info) {
// If this is not a probing packet or if this probing packet
// belongs to an old cluster, do nothing.
if (packet_info.probe_cluster_id == PacketInfo::kNotAProbe ||
packet_info.probe_cluster_id < last_valid_cluster_id_) {
return ProbingResult();
}
AggregatedCluster* cluster = &clusters_[packet_info.probe_cluster_id];
cluster->first_send_ms =
std::min(cluster->first_send_ms, packet_info.send_time_ms);
cluster->last_send_ms =
std::max(cluster->last_send_ms, packet_info.send_time_ms);
cluster->first_receive_ms =
std::min(cluster->first_receive_ms, packet_info.arrival_time_ms);
cluster->last_receive_ms =
std::max(cluster->last_receive_ms, packet_info.arrival_time_ms);
cluster->size += packet_info.payload_size;
cluster->num_probes += 1;
// Clean up old clusters.
while (clusters_.size() > kMaxNumSavedClusters)
clusters_.erase(clusters_.begin());
if (cluster->num_probes < kMinNumProbesValidCluster)
return ProbingResult();
int send_interval_ms = cluster->last_send_ms - cluster->first_send_ms;
int receive_interval_ms =
cluster->last_receive_ms - cluster->first_receive_ms;
if (send_interval_ms == 0 || receive_interval_ms == 0) {
LOG(LS_INFO) << "Probing unsuccessful, invalid send/receive interval"
<< " [cluster id: " << packet_info.probe_cluster_id
<< "] [send interval: " << send_interval_ms << " ms]"
<< " [receive interval: " << receive_interval_ms << " ms]";
return ProbingResult();
}
float send_bps = static_cast<float>(cluster->size) / send_interval_ms * 1000;
float receive_bps =
static_cast<float>(cluster->size) / receive_interval_ms * 1000;
float ratio = receive_bps / send_bps;
if (ratio > kValidRatio) {
LOG(LS_INFO) << "Probing unsuccessful, receive/send ratio too high"
<< " [cluster id: " << packet_info.probe_cluster_id
<< "] [send: " << cluster->size << " bytes / "
<< send_interval_ms << " ms = " << send_bps / 1000 << " kb/s]"
<< " [receive: " << cluster->size << " bytes / "
<< receive_interval_ms << " ms = " << receive_bps / 1000
<< " kb/s]"
<< " [ratio: " << receive_bps / 1000 << " / "
<< send_bps / 1000 << " = " << ratio << " > kValidRatio ("
<< kValidRatio << ")]";
return ProbingResult();
}
// We have a valid estimate.
int result_bps = std::min(send_bps, receive_bps);
last_valid_cluster_id_ = packet_info.probe_cluster_id;
LOG(LS_INFO) << "Probing successful"
<< " [cluster id: " << packet_info.probe_cluster_id
<< "] [send: " << cluster->size << " bytes / "
<< send_interval_ms << " ms = " << send_bps / 1000 << " kb/s]"
<< " [receive: " << cluster->size << " bytes / "
<< receive_interval_ms << " ms = " << receive_bps / 1000
<< " kb/s]";
return ProbingResult(result_bps, packet_info.arrival_time_ms);
}
} // namespace webrtc

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016 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.
*/
#ifndef WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
#define WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
#include <map>
#include <limits>
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
struct ProbingResult {
static constexpr int kNoEstimate = -1;
ProbingResult();
ProbingResult(int bps, int64_t timestamp);
int bps;
int64_t timestamp;
};
class ProbeBitrateEstimator {
public:
ProbeBitrateEstimator();
// Should be called for every packet we receive feedback about. If the
// packet was used for probing it will validate/calculate the resulting
// bitrate and return the result.
ProbingResult PacketFeedback(const PacketInfo& packet_info);
private:
struct AggregatedCluster {
int num_probes = 0;
int64_t first_send_ms = std::numeric_limits<int64_t>::max();
int64_t last_send_ms = 0;
int64_t first_receive_ms = std::numeric_limits<int64_t>::max();
int64_t last_receive_ms = 0;
size_t size = 0;
};
std::map<int, AggregatedCluster> clusters_;
int last_valid_cluster_id_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_

View File

@ -277,6 +277,7 @@
'congestion_controller/delay_based_bwe_unittest.cc',
'congestion_controller/delay_based_bwe_unittest_helper.cc',
'congestion_controller/delay_based_bwe_unittest_helper.h',
'congestion_controller/probe_bitrate_controller_unittest.cc',
'media_file/media_file_unittest.cc',
'module_common_types_unittest.cc',
'pacing/bitrate_prober_unittest.cc',