2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
11 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
13 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_baselinefile.h"
14 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
15 #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
16 #include "webrtc/system_wrappers/interface/clock.h"
17 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
26 class TestedEstimator : public RemoteBitrateObserver {
28 static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
29 static const int kDelayPlotIntervalMs = 100;
31 TestedEstimator(const string& test_name,
32 const BweTestConfig::EstimatorConfig& config)
33 : debug_name_(config.debug_name),
35 estimate_log_prefix_(),
36 last_delay_plot_ms_(0),
37 plot_delay_(config.plot_delay),
38 plot_estimate_(config.plot_estimate),
41 latest_estimate_bps_(-1),
42 estimator_(config.estimator_factory->Create(
43 this, &clock_, config.control_type,
44 kRemoteBitrateEstimatorMinBitrateBps)),
45 baseline_(BaseLineFileInterface::Create(test_name + "_" + debug_name_,
46 config.update_baseline)) {
47 assert(estimator_.get());
48 assert(baseline_.get());
49 // Setup the prefix strings used when logging.
51 ss << "Delay_" << config.flow_id << "#2";
52 delay_log_prefix_ = ss.str();
54 ss << "Estimate_" << config.flow_id << "#1";
55 estimate_log_prefix_ = ss.str();
56 // Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
57 estimator_->OnRttUpdate(50);
60 void EatPacket(const Packet& packet) {
61 BWE_TEST_LOGGING_CONTEXT(debug_name_);
63 latest_estimate_bps_ = -1;
65 // We're treating the send time (from previous filter) as the arrival
66 // time once packet reaches the estimator.
67 int64_t packet_time_ms = (packet.send_time_us() + 500) / 1000;
68 BWE_TEST_LOGGING_TIME(packet_time_ms);
70 if (clock_.TimeInMilliseconds() - last_delay_plot_ms_ >
71 kDelayPlotIntervalMs) {
72 BWE_TEST_LOGGING_PLOT(delay_log_prefix_, clock_.TimeInMilliseconds(),
74 (packet.creation_time_us() + 500) / 1000);
75 last_delay_plot_ms_ = clock_.TimeInMilliseconds();
79 int64_t step_ms = std::max(estimator_->TimeUntilNextProcess(), 0);
80 while ((clock_.TimeInMilliseconds() + step_ms) < packet_time_ms) {
81 clock_.AdvanceTimeMilliseconds(step_ms);
82 estimator_->Process();
83 step_ms = std::max(estimator_->TimeUntilNextProcess(), 0);
85 estimator_->IncomingPacket(packet_time_ms, packet.payload_size(),
87 clock_.AdvanceTimeMilliseconds(packet_time_ms -
88 clock_.TimeInMilliseconds());
89 ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds());
92 bool CheckEstimate(PacketSender::Feedback* feedback) {
94 BWE_TEST_LOGGING_CONTEXT(debug_name_);
95 uint32_t estimated_bps = 0;
96 if (LatestEstimate(&estimated_bps)) {
97 feedback->estimated_bps = estimated_bps;
98 baseline_->Estimate(clock_.TimeInMilliseconds(), estimated_bps);
100 double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
101 stats_.Push(estimated_kbps);
102 if (plot_estimate_) {
103 BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(),
112 BWE_TEST_LOGGING_CONTEXT(debug_name_);
113 BWE_TEST_LOGGING_CONTEXT("Mean");
117 void VerifyOrWriteBaseline() {
118 EXPECT_TRUE(baseline_->VerifyOrWrite());
121 virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs,
122 unsigned int bitrate) {
126 bool LatestEstimate(uint32_t* estimate_bps) {
127 if (latest_estimate_bps_ < 0) {
128 vector<unsigned int> ssrcs;
129 unsigned int bps = 0;
130 if (!estimator_->LatestEstimate(&ssrcs, &bps)) {
133 latest_estimate_bps_ = bps;
135 *estimate_bps = latest_estimate_bps_;
140 string delay_log_prefix_;
141 string estimate_log_prefix_;
142 int64_t last_delay_plot_ms_;
145 SimulatedClock clock_;
146 Stats<double> stats_;
147 int64_t latest_estimate_bps_;
148 scoped_ptr<RemoteBitrateEstimator> estimator_;
149 scoped_ptr<BaseLineFileInterface> baseline_;
151 DISALLOW_IMPLICIT_CONSTRUCTORS(TestedEstimator);
154 class PacketProcessorRunner {
156 explicit PacketProcessorRunner(PacketProcessor* processor)
157 : processor_(processor) {}
159 bool HasProcessor(const PacketProcessor* processor) const {
160 return processor == processor_;
163 void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out) {
165 FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process);
166 processor_->RunFor(time_ms, &to_process);
167 QueuePackets(&to_process, time_now_ms * 1000);
168 if (!to_process.empty()) {
169 processor_->Plot((to_process.back().send_time_us() + 500) / 1000);
171 in_out->merge(to_process);
175 void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in,
177 assert(out->empty());
178 for (Packets::iterator it = in->begin(); it != in->end();) {
179 // TODO(holmer): Further optimize this by looking for consecutive flow ids
180 // in the packet list and only doing the binary search + splice once for a
182 if (std::binary_search(flow_ids.begin(), flow_ids.end(), it->flow_id())) {
183 Packets::iterator next = it;
185 out->splice(out->end(), *in, it);
193 void QueuePackets(Packets* batch, int64_t end_of_batch_time_us) {
194 queue_.merge(*batch);
195 if (queue_.empty()) {
198 Packets::iterator it = queue_.begin();
199 for (; it != queue_.end(); ++it) {
200 if (it->send_time_us() > end_of_batch_time_us) {
205 to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
206 batch->merge(to_transfer);
209 PacketProcessor* processor_;
216 simulation_interval_ms_(-1),
221 BweTest::~BweTest() {
222 BWE_TEST_LOGGING_GLOBAL_ENABLE(true);
223 for (EstimatorMap::iterator it = estimators_.begin(); it != estimators_.end();
225 it->second->VerifyOrWriteBaseline();
226 it->second->LogStats();
228 BWE_TEST_LOGGING_GLOBAL_CONTEXT("");
230 for (EstimatorMap::iterator it = estimators_.begin();
231 it != estimators_.end(); ++it) {
236 void BweTest::SetupTestFromConfig(const BweTestConfig& config) {
237 const ::testing::TestInfo* const test_info =
238 ::testing::UnitTest::GetInstance()->current_test_info();
240 string(test_info->test_case_name()) + "_" + string(test_info->name());
241 BWE_TEST_LOGGING_GLOBAL_CONTEXT(test_name);
242 for (vector<BweTestConfig::EstimatorConfig>::const_iterator it =
243 config.estimator_configs.begin(); it != config.estimator_configs.end();
245 estimators_.insert(std::make_pair(it->flow_id, new TestedEstimator(
248 BWE_TEST_LOGGING_GLOBAL_ENABLE(false);
251 void BweTest::AddPacketProcessor(PacketProcessor* processor, bool is_sender) {
253 processors_.push_back(PacketProcessorRunner(processor));
255 senders_.push_back(static_cast<PacketSender*>(processor));
257 const FlowIds& flow_ids = processor->flow_ids();
258 for (size_t i = 0; i < flow_ids.size(); ++i) {
259 assert(estimators_.count(flow_ids[i]) == 1);
263 void BweTest::RemovePacketProcessor(
264 PacketProcessor* processor) {
265 for (vector<PacketProcessorRunner>::iterator it = processors_.begin();
266 it != processors_.end(); ++it) {
267 if (it->HasProcessor(processor)) {
268 processors_.erase(it);
275 void BweTest::VerboseLogging(bool enable) {
276 BWE_TEST_LOGGING_GLOBAL_ENABLE(enable);
279 void BweTest::GiveFeedbackToAffectedSenders(int flow_id,
280 TestedEstimator* estimator) {
281 std::list<PacketSender*> affected_senders;
282 for (std::vector<PacketSender*>::iterator psit =
283 senders_.begin(); psit != senders_.end(); ++psit) {
284 const FlowIds& flow_ids = (*psit)->flow_ids();
285 if (std::binary_search(flow_ids.begin(), flow_ids.end(), flow_id)) {
286 affected_senders.push_back(*psit);
289 PacketSender::Feedback feedback = {0};
290 if (estimator->CheckEstimate(&feedback) && !affected_senders.empty()) {
291 // Allocate the bitrate evenly between the senders.
292 feedback.estimated_bps /= affected_senders.size();
293 for (std::list<PacketSender*>::iterator psit = affected_senders.begin();
294 psit != affected_senders.end(); ++psit) {
295 (*psit)->GiveFeedback(feedback);
300 void BweTest::RunFor(int64_t time_ms) {
301 // Set simulation interval from first packet sender.
302 // TODO(holmer): Support different feedback intervals for different flows.
303 if (!senders_.empty()) {
304 simulation_interval_ms_ = senders_[0]->GetFeedbackIntervalMs();
306 assert(simulation_interval_ms_ > 0);
307 if (time_now_ms_ == -1) {
308 time_now_ms_ = simulation_interval_ms_;
310 for (run_time_ms_ += time_ms;
311 time_now_ms_ <= run_time_ms_ - simulation_interval_ms_;
312 time_now_ms_ += simulation_interval_ms_) {
314 for (vector<PacketProcessorRunner>::iterator it =
315 processors_.begin(); it != processors_.end(); ++it) {
316 it->RunFor(simulation_interval_ms_, time_now_ms_, &packets);
319 // Verify packets are in order between batches.
320 if (!packets.empty()) {
321 if (!previous_packets_.empty()) {
322 packets.splice(packets.begin(), previous_packets_,
323 --previous_packets_.end());
324 ASSERT_TRUE(IsTimeSorted(packets));
325 packets.erase(packets.begin());
327 ASSERT_LE(packets.front().send_time_us(), time_now_ms_ * 1000);
328 ASSERT_LE(packets.back().send_time_us(), time_now_ms_ * 1000);
330 ASSERT_TRUE(IsTimeSorted(packets));
333 for (PacketsConstIt it = packets.begin(); it != packets.end(); ++it) {
334 EstimatorMap::iterator est_it = estimators_.find(it->flow_id());
335 ASSERT_TRUE(est_it != estimators_.end());
336 est_it->second->EatPacket(*it);
339 for (EstimatorMap::iterator est_it = estimators_.begin();
340 est_it != estimators_.end(); ++est_it) {
341 GiveFeedbackToAffectedSenders(est_it->first, est_it->second);
346 string BweTest::GetTestName() const {
347 const ::testing::TestInfo* const test_info =
348 ::testing::UnitTest::GetInstance()->current_test_info();
349 return string(test_info->name());
352 } // namespace testing
353 } // namespace webrtc