1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 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. 9 */ 10 11 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h" 12 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" 18 19 using std::string; 20 using std::vector; 21 22 namespace webrtc { 23 namespace testing { 24 namespace bwe { 25 26 class TestedEstimator : public RemoteBitrateObserver { 27 public: 28 static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000; 29 static const int kDelayPlotIntervalMs = 100; 30 31 TestedEstimator(const string& test_name, 32 const BweTestConfig::EstimatorConfig& config) 33 : debug_name_(config.debug_name), 34 delay_log_prefix_(), 35 estimate_log_prefix_(), 36 last_delay_plot_ms_(0), 37 plot_delay_(config.plot_delay), 38 plot_estimate_(config.plot_estimate), 39 clock_(0), 40 stats_(), 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. 50 std::stringstream ss; 51 ss << "Delay_" << config.flow_id << "#2"; 52 delay_log_prefix_ = ss.str(); 53 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); 58 } 59 60 void EatPacket(const Packet& packet) { 61 BWE_TEST_LOGGING_CONTEXT(debug_name_); 62 63 latest_estimate_bps_ = -1; 64 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); 69 if (plot_delay_) { 70 if (clock_.TimeInMilliseconds() - last_delay_plot_ms_ > 71 kDelayPlotIntervalMs) { 72 BWE_TEST_LOGGING_PLOT(delay_log_prefix_, clock_.TimeInMilliseconds(), 73 packet_time_ms - 74 (packet.creation_time_us() + 500) / 1000); 75 last_delay_plot_ms_ = clock_.TimeInMilliseconds(); 76 } 77 } 78 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); 84 } 85 estimator_->IncomingPacket(packet_time_ms, packet.payload_size(), 86 packet.header()); 87 clock_.AdvanceTimeMilliseconds(packet_time_ms - 88 clock_.TimeInMilliseconds()); 89 ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds()); 90 } 91 92 bool CheckEstimate(PacketSender::Feedback* feedback) { 93 assert(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); 99 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(), 104 estimated_kbps); 105 } 106 return true; 107 } 108 return false; 109 } 110 111 void LogStats() { 112 BWE_TEST_LOGGING_CONTEXT(debug_name_); 113 BWE_TEST_LOGGING_CONTEXT("Mean"); 114 stats_.Log("kbps"); 115 } 116 117 void VerifyOrWriteBaseline() { 118 EXPECT_TRUE(baseline_->VerifyOrWrite()); 119 } 120 121 virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs, 122 unsigned int bitrate) { 123 } 124 125 private: 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)) { 131 return false; 132 } 133 latest_estimate_bps_ = bps; 134 } 135 *estimate_bps = latest_estimate_bps_; 136 return true; 137 } 138 139 string debug_name_; 140 string delay_log_prefix_; 141 string estimate_log_prefix_; 142 int64_t last_delay_plot_ms_; 143 bool plot_delay_; 144 bool plot_estimate_; 145 SimulatedClock clock_; 146 Stats<double> stats_; 147 int64_t latest_estimate_bps_; 148 scoped_ptr<RemoteBitrateEstimator> estimator_; 149 scoped_ptr<BaseLineFileInterface> baseline_; 150 151 DISALLOW_IMPLICIT_CONSTRUCTORS(TestedEstimator); 152 }; 153 154 class PacketProcessorRunner { 155 public: 156 explicit PacketProcessorRunner(PacketProcessor* processor) 157 : processor_(processor) {} 158 159 bool HasProcessor(const PacketProcessor* processor) const { 160 return processor == processor_; 161 } 162 163 void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out) { 164 Packets to_process; 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); 170 } 171 in_out->merge(to_process); 172 } 173 174 private: 175 void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in, 176 Packets* out) { 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 181 // sequence. 182 if (std::binary_search(flow_ids.begin(), flow_ids.end(), it->flow_id())) { 183 Packets::iterator next = it; 184 ++next; 185 out->splice(out->end(), *in, it); 186 it = next; 187 } else { 188 ++it; 189 } 190 } 191 } 192 193 void QueuePackets(Packets* batch, int64_t end_of_batch_time_us) { 194 queue_.merge(*batch); 195 if (queue_.empty()) { 196 return; 197 } 198 Packets::iterator it = queue_.begin(); 199 for (; it != queue_.end(); ++it) { 200 if (it->send_time_us() > end_of_batch_time_us) { 201 break; 202 } 203 } 204 Packets to_transfer; 205 to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it); 206 batch->merge(to_transfer); 207 } 208 209 PacketProcessor* processor_; 210 Packets queue_; 211 }; 212 213 BweTest::BweTest() 214 : run_time_ms_(0), 215 time_now_ms_(-1), 216 simulation_interval_ms_(-1), 217 estimators_(), 218 processors_() { 219 } 220 221 BweTest::~BweTest() { 222 BWE_TEST_LOGGING_GLOBAL_ENABLE(true); 223 for (EstimatorMap::iterator it = estimators_.begin(); it != estimators_.end(); 224 ++it) { 225 it->second->VerifyOrWriteBaseline(); 226 it->second->LogStats(); 227 } 228 BWE_TEST_LOGGING_GLOBAL_CONTEXT(""); 229 230 for (EstimatorMap::iterator it = estimators_.begin(); 231 it != estimators_.end(); ++it) { 232 delete it->second; 233 } 234 } 235 236 void BweTest::SetupTestFromConfig(const BweTestConfig& config) { 237 const ::testing::TestInfo* const test_info = 238 ::testing::UnitTest::GetInstance()->current_test_info(); 239 string test_name = 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(); 244 ++it) { 245 estimators_.insert(std::make_pair(it->flow_id, new TestedEstimator( 246 test_name, *it))); 247 } 248 BWE_TEST_LOGGING_GLOBAL_ENABLE(false); 249 } 250 251 void BweTest::AddPacketProcessor(PacketProcessor* processor, bool is_sender) { 252 assert(processor); 253 processors_.push_back(PacketProcessorRunner(processor)); 254 if (is_sender) { 255 senders_.push_back(static_cast<PacketSender*>(processor)); 256 } 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); 260 } 261 } 262 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); 269 return; 270 } 271 } 272 assert(false); 273 } 274 275 void BweTest::VerboseLogging(bool enable) { 276 BWE_TEST_LOGGING_GLOBAL_ENABLE(enable); 277 } 278 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); 287 } 288 } 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); 296 } 297 } 298 } 299 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(); 305 } 306 assert(simulation_interval_ms_ > 0); 307 if (time_now_ms_ == -1) { 308 time_now_ms_ = simulation_interval_ms_; 309 } 310 for (run_time_ms_ += time_ms; 311 time_now_ms_ <= run_time_ms_ - simulation_interval_ms_; 312 time_now_ms_ += simulation_interval_ms_) { 313 Packets packets; 314 for (vector<PacketProcessorRunner>::iterator it = 315 processors_.begin(); it != processors_.end(); ++it) { 316 it->RunFor(simulation_interval_ms_, time_now_ms_, &packets); 317 } 318 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()); 326 } 327 ASSERT_LE(packets.front().send_time_us(), time_now_ms_ * 1000); 328 ASSERT_LE(packets.back().send_time_us(), time_now_ms_ * 1000); 329 } else { 330 ASSERT_TRUE(IsTimeSorted(packets)); 331 } 332 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); 337 } 338 339 for (EstimatorMap::iterator est_it = estimators_.begin(); 340 est_it != estimators_.end(); ++est_it) { 341 GiveFeedbackToAffectedSenders(est_it->first, est_it->second); 342 } 343 } 344 } 345 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()); 350 } 351 } // namespace bwe 352 } // namespace testing 353 } // namespace webrtc 354