From 14b0279416c4916534c1e76939b0b8927a208a04 Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Mon, 16 Feb 2015 12:02:20 +0000 Subject: [PATCH] Break out code from bloated files in the BWE simulator. No changes to functionality. BUG=4173 R=pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/34209004 Cr-Commit-Position: refs/heads/master@{#8374} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8374 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/modules.gyp | 7 + .../bwe_simulations.cc | 2 + .../remote_bitrate_estimators_test.cc | 2 + .../remote_bitrate_estimator/test/bwe.cc | 354 ++++++++++++++++++ .../remote_bitrate_estimator/test/bwe.h | 66 ++++ .../remote_bitrate_estimator/test/bwe_test.cc | 329 +++------------- .../remote_bitrate_estimator/test/bwe_test.h | 41 +- .../test/bwe_test_framework.cc | 350 ----------------- .../test/bwe_test_framework.h | 256 +------------ .../test/bwe_test_framework_unittest.cc | 1 + .../remote_bitrate_estimator/test/packet.h | 116 ++++++ .../test/packet_receiver.cc | 92 +++++ .../test/packet_receiver.h | 54 +++ .../test/packet_sender.cc | 264 +++++++++++++ .../test/packet_sender.h | 117 ++++++ 15 files changed, 1142 insertions(+), 909 deletions(-) create mode 100644 webrtc/modules/remote_bitrate_estimator/test/bwe.cc create mode 100644 webrtc/modules/remote_bitrate_estimator/test/bwe.h create mode 100644 webrtc/modules/remote_bitrate_estimator/test/packet.h create mode 100644 webrtc/modules/remote_bitrate_estimator/test/packet_receiver.cc create mode 100644 webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h create mode 100644 webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc create mode 100644 webrtc/modules/remote_bitrate_estimator/test/packet_sender.h diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 8379a039e..27cb363e8 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -211,6 +211,8 @@ 'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc', 'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h', 'remote_bitrate_estimator/remote_bitrate_estimators_test.cc', + 'remote_bitrate_estimator/test/bwe.cc', + 'remote_bitrate_estimator/test/bwe.h', 'remote_bitrate_estimator/test/bwe_test.cc', 'remote_bitrate_estimator/test/bwe_test.h', 'remote_bitrate_estimator/test/bwe_test_baselinefile.cc', @@ -222,6 +224,11 @@ 'remote_bitrate_estimator/test/bwe_test_framework_unittest.cc', 'remote_bitrate_estimator/test/bwe_test_logging.cc', 'remote_bitrate_estimator/test/bwe_test_logging.h', + 'remote_bitrate_estimator/test/packet_receiver.cc', + 'remote_bitrate_estimator/test/packet_receiver.h', + 'remote_bitrate_estimator/test/packet_sender.cc', + 'remote_bitrate_estimator/test/packet_sender.h', + 'remote_bitrate_estimator/test/packets.h', 'rtp_rtcp/source/mock/mock_rtp_payload_strategy.h', 'rtp_rtcp/source/byte_io_unittest.cc', 'rtp_rtcp/source/fec_receiver_unittest.cc', diff --git a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc index 7ba9437aa..2a92b901c 100644 --- a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc +++ b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc @@ -11,6 +11,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h" #include "webrtc/test/testsupport/fileutils.h" using std::string; diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc index b21d13912..c81764ede 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc @@ -12,6 +12,8 @@ #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h" #include "webrtc/test/testsupport/fileutils.h" #include "webrtc/test/testsupport/perf_test.h" diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe.cc new file mode 100644 index 000000000..55846dbf2 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe.cc @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2015 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/remote_bitrate_estimator/test/bwe.h" + +#include +#include +#include +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/common.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h" +#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +const int kMinBitrateKbps = 30; +const int kMaxBitrateKbps = 20000; + +class NullSendSideBwe : public SendSideBwe { + public: + NullSendSideBwe() {} + virtual ~NullSendSideBwe() {} + + virtual int GetFeedbackIntervalMs() const OVERRIDE { return 1000; } + virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE {} + virtual int64_t TimeUntilNextProcess() OVERRIDE { + return std::numeric_limits::max(); + } + virtual int Process() OVERRIDE { return 0; } + + private: + DISALLOW_COPY_AND_ASSIGN(NullSendSideBwe); +}; + +class RembSendSideBwe : public SendSideBwe { + public: + RembSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock); + virtual ~RembSendSideBwe(); + + virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; } + virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE; + virtual int64_t TimeUntilNextProcess() OVERRIDE; + virtual int Process() OVERRIDE; + + protected: + scoped_ptr bitrate_controller_; + scoped_ptr feedback_observer_; + + private: + Clock* clock_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(RembSendSideBwe); +}; + +class FullSendSideBwe : public SendSideBwe, public RemoteBitrateObserver { + public: + FullSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock); + virtual ~FullSendSideBwe(); + + virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; } + virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE; + virtual void OnReceiveBitrateChanged(const std::vector& ssrcs, + unsigned int bitrate) OVERRIDE; + virtual int64_t TimeUntilNextProcess() OVERRIDE; + virtual int Process() OVERRIDE; + + protected: + scoped_ptr bitrate_controller_; + scoped_ptr rbe_; + scoped_ptr feedback_observer_; + + private: + Clock* const clock_; + RTCPReportBlock report_block_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(FullSendSideBwe); +}; + +RembSendSideBwe::RembSendSideBwe(int kbps, + BitrateObserver* observer, + Clock* clock) + : bitrate_controller_( + BitrateController::CreateBitrateController(clock, false)), + feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()), + clock_(clock) { + assert(kbps >= kMinBitrateKbps); + assert(kbps <= kMaxBitrateKbps); + bitrate_controller_->SetBitrateObserver( + observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps); +} + +RembSendSideBwe::~RembSendSideBwe() { +} + +void RembSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) { + const RembFeedback& remb_feedback = + static_cast(feedback); + feedback_observer_->OnReceivedEstimatedBitrate(remb_feedback.estimated_bps()); + ReportBlockList report_blocks; + report_blocks.push_back(remb_feedback.report_block()); + feedback_observer_->OnReceivedRtcpReceiverReport( + report_blocks, 0, clock_->TimeInMilliseconds()); + bitrate_controller_->Process(); +} + +int64_t RembSendSideBwe::TimeUntilNextProcess() { + return bitrate_controller_->TimeUntilNextProcess(); +} + +int RembSendSideBwe::Process() { + return bitrate_controller_->Process(); +} + +FullSendSideBwe::FullSendSideBwe(int kbps, + BitrateObserver* observer, + Clock* clock) + : bitrate_controller_( + BitrateController::CreateBitrateController(clock, false)), + rbe_(AbsoluteSendTimeRemoteBitrateEstimatorFactory() + .Create(this, clock, kAimdControl, 1000 * kMinBitrateKbps)), + feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()), + clock_(clock) { + assert(kbps >= kMinBitrateKbps); + assert(kbps <= kMaxBitrateKbps); + bitrate_controller_->SetBitrateObserver( + observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps); +} + +FullSendSideBwe::~FullSendSideBwe() { +} + +void FullSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) { + const SendSideBweFeedback& fb = + static_cast(feedback); + if (fb.packet_feedback_vector().empty()) + return; + rbe_->IncomingPacketFeedbackVector(fb.packet_feedback_vector()); + // TODO(holmer): Handle losses in between feedback packets. + int expected_packets = fb.packet_feedback_vector().back().sequence_number - + fb.packet_feedback_vector().front().sequence_number + + 1; + // Assuming no reordering for now. + if (expected_packets <= 0) + return; + int lost_packets = expected_packets - fb.packet_feedback_vector().size(); + report_block_.fractionLost = (lost_packets << 8) / expected_packets; + report_block_.cumulativeLost += lost_packets; + ReportBlockList report_blocks; + report_blocks.push_back(report_block_); + feedback_observer_->OnReceivedRtcpReceiverReport( + report_blocks, 0, clock_->TimeInMilliseconds()); + bitrate_controller_->Process(); +} + +void FullSendSideBwe::OnReceiveBitrateChanged( + const std::vector& ssrcs, + unsigned int bitrate) { + feedback_observer_->OnReceivedEstimatedBitrate(bitrate); +} + +int64_t FullSendSideBwe::TimeUntilNextProcess() { + return bitrate_controller_->TimeUntilNextProcess(); +} + +int FullSendSideBwe::Process() { + rbe_->Process(); + return bitrate_controller_->Process(); +} + +int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) { + const int kInterArrivalShift = 26; + const int kAbsSendTimeInterArrivalUpshift = 8; + const double kTimestampToMs = + 1000.0 / static_cast(1 << kInterArrivalShift); + uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift; + return static_cast(timestamp) * kTimestampToMs; +} + +class SendSideBweReceiver : public BweReceiver { + public: + explicit SendSideBweReceiver(int flow_id) + : BweReceiver(flow_id), last_feedback_ms_(0) {} + virtual void ReceivePacket(int64_t arrival_time_ms, + size_t payload_size, + const RTPHeader& header) OVERRIDE { + packet_feedback_vector_.push_back(PacketInfo( + arrival_time_ms, GetAbsSendTimeInMs(header.extension.absoluteSendTime), + header.sequenceNumber, payload_size)); + } + + virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE { + if (now_ms - last_feedback_ms_ < 100) + return NULL; + last_feedback_ms_ = now_ms; + FeedbackPacket* fb = new SendSideBweFeedback(flow_id_, now_ms * 1000, + packet_feedback_vector_); + packet_feedback_vector_.clear(); + return fb; + } + + private: + int64_t last_feedback_ms_; + std::vector packet_feedback_vector_; +}; + +class RembReceiver : public BweReceiver, public RemoteBitrateObserver { + public: + static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000; + + RembReceiver(int flow_id, bool plot) + : BweReceiver(flow_id), + estimate_log_prefix_(), + plot_estimate_(plot), + clock_(0), + recv_stats_(ReceiveStatistics::Create(&clock_)), + latest_estimate_bps_(-1), + estimator_(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create( + this, + &clock_, + kAimdControl, + kRemoteBitrateEstimatorMinBitrateBps)) { + std::stringstream ss; + ss << "Estimate_" << flow_id_ << "#1"; + estimate_log_prefix_ = ss.str(); + // Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic. + estimator_->OnRttUpdate(50); + } + + virtual void ReceivePacket(int64_t arrival_time_ms, + size_t payload_size, + const RTPHeader& header) { + recv_stats_->IncomingPacket(header, payload_size, false); + + latest_estimate_bps_ = -1; + + int64_t step_ms = std::max(estimator_->TimeUntilNextProcess(), 0); + while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) { + clock_.AdvanceTimeMilliseconds(step_ms); + estimator_->Process(); + step_ms = std::max(estimator_->TimeUntilNextProcess(), 0); + } + estimator_->IncomingPacket(arrival_time_ms, payload_size, header); + clock_.AdvanceTimeMilliseconds(arrival_time_ms - + clock_.TimeInMilliseconds()); + ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds()); + } + + virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE { + BWE_TEST_LOGGING_CONTEXT("Remb"); + uint32_t estimated_bps = 0; + RembFeedback* feedback = NULL; + if (LatestEstimate(&estimated_bps)) { + StatisticianMap statisticians = recv_stats_->GetActiveStatisticians(); + RTCPReportBlock report_block; + if (!statisticians.empty()) { + report_block = BuildReportBlock(statisticians.begin()->second); + } + feedback = new RembFeedback(flow_id_, now_ms * 1000, estimated_bps, + report_block); + + double estimated_kbps = static_cast(estimated_bps) / 1000.0; + RTC_UNUSED(estimated_kbps); + if (plot_estimate_) { + BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(), + estimated_kbps); + } + } + return feedback; + } + + // Implements RemoteBitrateObserver. + virtual void OnReceiveBitrateChanged(const std::vector& ssrcs, + unsigned int bitrate) OVERRIDE {} + + private: + static RTCPReportBlock BuildReportBlock(StreamStatistician* statistician) { + RTCPReportBlock report_block; + RtcpStatistics stats; + if (!statistician->GetStatistics(&stats, true)) + return report_block; + report_block.fractionLost = stats.fraction_lost; + report_block.cumulativeLost = stats.cumulative_lost; + report_block.extendedHighSeqNum = stats.extended_max_sequence_number; + report_block.jitter = stats.jitter; + return report_block; + } + + bool LatestEstimate(uint32_t* estimate_bps) { + if (latest_estimate_bps_ < 0) { + std::vector ssrcs; + unsigned int bps = 0; + if (!estimator_->LatestEstimate(&ssrcs, &bps)) { + return false; + } + latest_estimate_bps_ = bps; + } + *estimate_bps = latest_estimate_bps_; + return true; + } + + std::string estimate_log_prefix_; + bool plot_estimate_; + SimulatedClock clock_; + scoped_ptr recv_stats_; + int64_t latest_estimate_bps_; + scoped_ptr estimator_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(RembReceiver); +}; + +SendSideBwe* CreateBweSender(BandwidthEstimatorType estimator, + int kbps, + BitrateObserver* observer, + Clock* clock) { + switch (estimator) { + case kRembEstimator: + return new RembSendSideBwe(kbps, observer, clock); + case kFullSendSideEstimator: + return new FullSendSideBwe(kbps, observer, clock); + case kNullEstimator: + return new NullSendSideBwe(); + } + assert(false); + return NULL; +} + +BweReceiver* CreateBweReceiver(BandwidthEstimatorType type, + int flow_id, + bool plot) { + switch (type) { + case kRembEstimator: + return new RembReceiver(flow_id, plot); + case kFullSendSideEstimator: + return new SendSideBweReceiver(flow_id); + case kNullEstimator: + return new BweReceiver(flow_id); + } + assert(false); + return NULL; +} +} // namespace bwe +} // namespace testing +} // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe.h b/webrtc/modules/remote_bitrate_estimator/test/bwe.h new file mode 100644 index 000000000..b3b44ec01 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 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_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_ + +#include + +#include "webrtc/modules/remote_bitrate_estimator/test/packet.h" +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +class SendSideBwe : public Module { + public: + SendSideBwe() {} + virtual ~SendSideBwe() {} + + virtual int GetFeedbackIntervalMs() const = 0; + virtual void GiveFeedback(const FeedbackPacket& feedback) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SendSideBwe); +}; + +class BweReceiver { + public: + explicit BweReceiver(int flow_id) : flow_id_(flow_id) {} + virtual ~BweReceiver() {} + + virtual void ReceivePacket(int64_t arrival_time_ms, + size_t payload_size, + const RTPHeader& header) {} + virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; } + + protected: + int flow_id_; +}; + +enum BandwidthEstimatorType { + kNullEstimator, + kRembEstimator, + kFullSendSideEstimator +}; + +SendSideBwe* CreateBweSender(BandwidthEstimatorType estimator, + int kbps, + BitrateObserver* observer, + Clock* clock); + +BweReceiver* CreateBweReceiver(BandwidthEstimatorType type, + int flow_id, + bool plot); +} // namespace bwe +} // namespace testing +} // namespace webrtc +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_ diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc index 8be28561a..384fa9481 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc @@ -12,10 +12,9 @@ #include "webrtc/base/common.h" #include "webrtc/modules/interface/module_common_types.h" -#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_baselinefile.h" #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h" -#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" -#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" @@ -25,304 +24,70 @@ using std::vector; namespace webrtc { namespace testing { namespace bwe { -class BweReceiver { - public: - explicit BweReceiver(int flow_id) : flow_id_(flow_id) {} - virtual ~BweReceiver() {} - virtual void ReceivePacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header) {} - virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; } - - protected: - int flow_id_; -}; - -int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) { - const int kInterArrivalShift = 26; - const int kAbsSendTimeInterArrivalUpshift = 8; - const double kTimestampToMs = - 1000.0 / static_cast(1 << kInterArrivalShift); - uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift; - return static_cast(timestamp) * kTimestampToMs; +PacketProcessorRunner::PacketProcessorRunner(PacketProcessor* processor) + : processor_(processor) { } -class SendSideBweReceiver : public BweReceiver { - public: - explicit SendSideBweReceiver(int flow_id) - : BweReceiver(flow_id), last_feedback_ms_(0) {} - virtual void ReceivePacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header) OVERRIDE { - packet_feedback_vector_.push_back(PacketInfo( - arrival_time_ms, GetAbsSendTimeInMs(header.extension.absoluteSendTime), - header.sequenceNumber, payload_size)); - } - - virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE { - if (now_ms - last_feedback_ms_ < 100) - return NULL; - last_feedback_ms_ = now_ms; - FeedbackPacket* fb = new SendSideBweFeedback(flow_id_, now_ms * 1000, - packet_feedback_vector_); - packet_feedback_vector_.clear(); - return fb; - } - - private: - int64_t last_feedback_ms_; - std::vector packet_feedback_vector_; -}; - -class RembReceiver : public BweReceiver, public RemoteBitrateObserver { - public: - static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000; - - RembReceiver(int flow_id, bool plot) - : BweReceiver(flow_id), - estimate_log_prefix_(), - plot_estimate_(plot), - clock_(0), - recv_stats_(ReceiveStatistics::Create(&clock_)), - latest_estimate_bps_(-1), - estimator_(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create( - this, - &clock_, - kAimdControl, - kRemoteBitrateEstimatorMinBitrateBps)) { - std::stringstream ss; - ss << "Estimate_" << flow_id_ << "#1"; - estimate_log_prefix_ = ss.str(); - // Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic. - estimator_->OnRttUpdate(50); - } - - virtual void ReceivePacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header) { - recv_stats_->IncomingPacket(header, payload_size, false); - - latest_estimate_bps_ = -1; - - int64_t step_ms = std::max(estimator_->TimeUntilNextProcess(), 0); - while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) { - clock_.AdvanceTimeMilliseconds(step_ms); - estimator_->Process(); - step_ms = std::max(estimator_->TimeUntilNextProcess(), 0); - } - estimator_->IncomingPacket(arrival_time_ms, payload_size, header); - clock_.AdvanceTimeMilliseconds(arrival_time_ms - - clock_.TimeInMilliseconds()); - ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds()); - } - - virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE { - BWE_TEST_LOGGING_CONTEXT("Remb"); - uint32_t estimated_bps = 0; - RembFeedback* feedback = NULL; - if (LatestEstimate(&estimated_bps)) { - StatisticianMap statisticians = recv_stats_->GetActiveStatisticians(); - RTCPReportBlock report_block; - if (!statisticians.empty()) { - report_block = BuildReportBlock(statisticians.begin()->second); - } - feedback = new RembFeedback(flow_id_, now_ms * 1000, estimated_bps, - report_block); - - double estimated_kbps = static_cast(estimated_bps) / 1000.0; - RTC_UNUSED(estimated_kbps); - if (plot_estimate_) { - BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(), - estimated_kbps); - } - } - return feedback; - } - - // Implements RemoteBitrateObserver. - virtual void OnReceiveBitrateChanged(const vector& ssrcs, - unsigned int bitrate) OVERRIDE {} - - private: - static RTCPReportBlock BuildReportBlock(StreamStatistician* statistician) { - RTCPReportBlock report_block; - RtcpStatistics stats; - if (!statistician->GetStatistics(&stats, true)) - return report_block; - report_block.fractionLost = stats.fraction_lost; - report_block.cumulativeLost = stats.cumulative_lost; - report_block.extendedHighSeqNum = stats.extended_max_sequence_number; - report_block.jitter = stats.jitter; - return report_block; - } - - bool LatestEstimate(uint32_t* estimate_bps) { - if (latest_estimate_bps_ < 0) { - vector ssrcs; - unsigned int bps = 0; - if (!estimator_->LatestEstimate(&ssrcs, &bps)) { - return false; - } - latest_estimate_bps_ = bps; - } - *estimate_bps = latest_estimate_bps_; - return true; - } - - string estimate_log_prefix_; - bool plot_estimate_; - SimulatedClock clock_; - scoped_ptr recv_stats_; - int64_t latest_estimate_bps_; - scoped_ptr estimator_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(RembReceiver); -}; - -BweReceiver* CreateBweReceiver(BandwidthEstimatorType type, - int flow_id, - bool plot) { - switch (type) { - case kRembEstimator: - return new RembReceiver(flow_id, plot); - case kFullSendSideEstimator: - return new SendSideBweReceiver(flow_id); - case kNullEstimator: - return new BweReceiver(flow_id); - } - assert(false); - return NULL; +PacketProcessorRunner::~PacketProcessorRunner() { + for (Packet* packet : queue_) + delete packet; } -PacketReceiver::PacketReceiver(PacketProcessorListener* listener, - int flow_id, - BandwidthEstimatorType bwe_type, - bool plot_delay, - bool plot_bwe) - : PacketProcessor(listener, flow_id, kReceiver), - delay_log_prefix_(), - last_delay_plot_ms_(0), - plot_delay_(plot_delay), - bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) { - // Setup the prefix strings used when logging. - std::stringstream ss; - ss << "Delay_" << flow_id << "#2"; - delay_log_prefix_ = ss.str(); +bool PacketProcessorRunner::RunsProcessor( + const PacketProcessor* processor) const { + return processor == processor_; } -PacketReceiver::~PacketReceiver() { +void PacketProcessorRunner::RunFor(int64_t time_ms, + int64_t time_now_ms, + Packets* in_out) { + Packets to_process; + FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process); + processor_->RunFor(time_ms, &to_process); + QueuePackets(&to_process, time_now_ms * 1000); + if (!to_process.empty()) { + processor_->Plot((to_process.back()->send_time_us() + 500) / 1000); + } + in_out->merge(to_process, DereferencingComparator); } -void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) { - Packets feedback; - for (auto it = in_out->begin(); it != in_out->end();) { - // PacketReceivers are only associated with a single stream, and therefore - // should only process a single flow id. - // TODO(holmer): Break this out into a Demuxer which implements both - // PacketProcessorListener and PacketProcessor. - if ((*it)->GetPacketType() == Packet::kMedia && - (*it)->flow_id() == *flow_ids().begin()) { - BWE_TEST_LOGGING_CONTEXT("Receiver"); - const MediaPacket* media_packet = static_cast(*it); - // We're treating the send time (from previous filter) as the arrival - // time once packet reaches the estimator. - int64_t arrival_time_ms = (media_packet->send_time_us() + 500) / 1000; - BWE_TEST_LOGGING_TIME(arrival_time_ms); - PlotDelay(arrival_time_ms, - (media_packet->creation_time_us() + 500) / 1000); - - bwe_receiver_->ReceivePacket(arrival_time_ms, - media_packet->payload_size(), - media_packet->header()); - FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms); - if (fb) - feedback.push_back(fb); - delete media_packet; - it = in_out->erase(it); +void PacketProcessorRunner::FindPacketsToProcess(const FlowIds& flow_ids, + Packets* in, + Packets* out) { + assert(out->empty()); + for (Packets::iterator it = in->begin(); it != in->end();) { + // TODO(holmer): Further optimize this by looking for consecutive flow ids + // in the packet list and only doing the binary search + splice once for a + // sequence. + if (flow_ids.find((*it)->flow_id()) != flow_ids.end()) { + Packets::iterator next = it; + ++next; + out->splice(out->end(), *in, it); + it = next; } else { ++it; } } - // Insert feedback packets to be sent back to the sender. - in_out->merge(feedback, DereferencingComparator); } -void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) { - static const int kDelayPlotIntervalMs = 100; - if (!plot_delay_) +void PacketProcessorRunner::QueuePackets(Packets* batch, + int64_t end_of_batch_time_us) { + queue_.merge(*batch, DereferencingComparator); + if (queue_.empty()) { return; - if (arrival_time_ms - last_delay_plot_ms_ > kDelayPlotIntervalMs) { - BWE_TEST_LOGGING_PLOT(delay_log_prefix_, arrival_time_ms, - arrival_time_ms - send_time_ms); - last_delay_plot_ms_ = arrival_time_ms; } + Packets::iterator it = queue_.begin(); + for (; it != queue_.end(); ++it) { + if ((*it)->send_time_us() > end_of_batch_time_us) { + break; + } + } + Packets to_transfer; + to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it); + batch->merge(to_transfer, DereferencingComparator); } -class PacketProcessorRunner { - public: - explicit PacketProcessorRunner(PacketProcessor* processor) - : processor_(processor) {} - - ~PacketProcessorRunner() { - for (Packet* packet : queue_) - delete packet; - } - - bool RunsProcessor(const PacketProcessor* processor) const { - return processor == processor_; - } - - void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out) { - Packets to_process; - FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process); - processor_->RunFor(time_ms, &to_process); - QueuePackets(&to_process, time_now_ms * 1000); - if (!to_process.empty()) { - processor_->Plot((to_process.back()->send_time_us() + 500) / 1000); - } - in_out->merge(to_process, DereferencingComparator); - } - - private: - void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in, - Packets* out) { - assert(out->empty()); - for (Packets::iterator it = in->begin(); it != in->end();) { - // TODO(holmer): Further optimize this by looking for consecutive flow ids - // in the packet list and only doing the binary search + splice once for a - // sequence. - if (flow_ids.find((*it)->flow_id()) != flow_ids.end()) { - Packets::iterator next = it; - ++next; - out->splice(out->end(), *in, it); - it = next; - } else { - ++it; - } - } - } - - void QueuePackets(Packets* batch, int64_t end_of_batch_time_us) { - queue_.merge(*batch, DereferencingComparator); - if (queue_.empty()) { - return; - } - Packets::iterator it = queue_.begin(); - for (; it != queue_.end(); ++it) { - if ((*it)->send_time_us() > end_of_batch_time_us) { - break; - } - } - Packets to_transfer; - to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it); - batch->merge(to_transfer, DereferencingComparator); - } - - PacketProcessor* processor_; - Packets queue_; -}; - BweTest::BweTest() : run_time_ms_(0), time_now_ms_(-1), simulation_interval_ms_(-1) { links_.push_back(&uplink_); diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h index 5cc5b3063..9dcb6bcb8 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h @@ -8,6 +8,9 @@ * be found in the AUTHORS file in the root of the source tree. */ +#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_ + #include #include #include @@ -22,37 +25,29 @@ namespace testing { namespace bwe { class BweReceiver; -class PacketProcessorRunner; +class PacketReceiver; +class PacketSender; -class PacketReceiver : public PacketProcessor { +class PacketProcessorRunner { public: - PacketReceiver(PacketProcessorListener* listener, - int flow_id, - BandwidthEstimatorType bwe_type, - bool plot_delay, - bool plot_bwe); - ~PacketReceiver(); + explicit PacketProcessorRunner(PacketProcessor* processor); + ~PacketProcessorRunner(); - // Implements PacketProcessor. - virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; - - void LogStats(); - - protected: - void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms); - - int64_t now_ms_; - std::string delay_log_prefix_; - int64_t last_delay_plot_ms_; - bool plot_delay_; - scoped_ptr bwe_receiver_; + bool RunsProcessor(const PacketProcessor* processor) const; + void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out); private: - DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver); + void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in, Packets* out); + void QueuePackets(Packets* batch, int64_t end_of_batch_time_us); + + PacketProcessor* processor_; + Packets queue_; }; class Link : public PacketProcessorListener { public: + virtual ~Link() {} + virtual void AddPacketProcessor(PacketProcessor* processor, ProcessorType type); virtual void RemovePacketProcessor(PacketProcessor* processor); @@ -99,3 +94,5 @@ class BweTest { } // namespace bwe } // namespace testing } // namespace webrtc + +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_ diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc index 768ff93ec..d5a95066c 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc @@ -18,9 +18,6 @@ namespace webrtc { namespace testing { namespace bwe { -const int kMinBitrateKbps = 10; -const int kMaxBitrateKbps = 20000; - class DelayCapHelper { public: DelayCapHelper() : max_delay_us_(0), delay_stats_() {} @@ -730,353 +727,6 @@ uint32_t PeriodicKeyFrameSource::NextPacketSize(uint32_t frame_size, uint32_t avg_size = (frame_size + fragments - 1) / fragments; return std::min(avg_size, remaining_payload); } - -RembSendSideBwe::RembSendSideBwe(int kbps, - BitrateObserver* observer, - Clock* clock) - : bitrate_controller_( - BitrateController::CreateBitrateController(clock, false)), - feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()), - clock_(clock) { - assert(kbps >= kMinBitrateKbps); - assert(kbps <= kMaxBitrateKbps); - bitrate_controller_->SetBitrateObserver( - observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps); -} - -RembSendSideBwe::~RembSendSideBwe() { -} - -void RembSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) { - const RembFeedback& remb_feedback = - static_cast(feedback); - feedback_observer_->OnReceivedEstimatedBitrate(remb_feedback.estimated_bps()); - ReportBlockList report_blocks; - report_blocks.push_back(remb_feedback.report_block()); - feedback_observer_->OnReceivedRtcpReceiverReport( - report_blocks, 0, clock_->TimeInMilliseconds()); - bitrate_controller_->Process(); -} - -int64_t RembSendSideBwe::TimeUntilNextProcess() { - return bitrate_controller_->TimeUntilNextProcess(); -} - -int RembSendSideBwe::Process() { - return bitrate_controller_->Process(); -} - -FullSendSideBwe::FullSendSideBwe(int kbps, - BitrateObserver* observer, - Clock* clock) - : bitrate_controller_( - BitrateController::CreateBitrateController(clock, false)), - rbe_(AbsoluteSendTimeRemoteBitrateEstimatorFactory() - .Create(this, clock, kAimdControl, 1000 * kMinBitrateKbps)), - feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()), - clock_(clock) { - assert(kbps >= kMinBitrateKbps); - assert(kbps <= kMaxBitrateKbps); - bitrate_controller_->SetBitrateObserver( - observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps); -} - -FullSendSideBwe::~FullSendSideBwe() { -} - -void FullSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) { - const SendSideBweFeedback& fb = - static_cast(feedback); - if (fb.packet_feedback_vector().empty()) - return; - rbe_->IncomingPacketFeedbackVector(fb.packet_feedback_vector()); - // TODO(holmer): Handle losses in between feedback packets. - int expected_packets = fb.packet_feedback_vector().back().sequence_number - - fb.packet_feedback_vector().front().sequence_number + - 1; - // Assuming no reordering for now. - if (expected_packets <= 0) - return; - int lost_packets = expected_packets - fb.packet_feedback_vector().size(); - report_block_.fractionLost = (lost_packets << 8) / expected_packets; - report_block_.cumulativeLost += lost_packets; - ReportBlockList report_blocks; - report_blocks.push_back(report_block_); - feedback_observer_->OnReceivedRtcpReceiverReport( - report_blocks, 0, clock_->TimeInMilliseconds()); - bitrate_controller_->Process(); -} - -void FullSendSideBwe::OnReceiveBitrateChanged( - const std::vector& ssrcs, - unsigned int bitrate) { - feedback_observer_->OnReceivedEstimatedBitrate(bitrate); -} - -int64_t FullSendSideBwe::TimeUntilNextProcess() { - return bitrate_controller_->TimeUntilNextProcess(); -} - -int FullSendSideBwe::Process() { - rbe_->Process(); - return bitrate_controller_->Process(); -} - -SendSideBwe* CreateEstimator(BandwidthEstimatorType estimator, - int kbps, - BitrateObserver* observer, - Clock* clock) { - switch (estimator) { - case kRembEstimator: - return new RembSendSideBwe(kbps, observer, clock); - case kFullSendSideEstimator: - return new FullSendSideBwe(kbps, observer, clock); - case kNullEstimator: - return new NullSendSideBwe(); - } - assert(false); - return NULL; -} - -PacketSender::PacketSender(PacketProcessorListener* listener, - VideoSource* source, - BandwidthEstimatorType estimator) - : PacketProcessor(listener, source->flow_id(), kSender), - // For Packet::send_time_us() to be comparable with timestamps from - // clock_, the clock of the PacketSender and the Source must be aligned. - // We assume that both start at time 0. - clock_(0), - source_(source), - bwe_(CreateEstimator(estimator, - source_->bits_per_second() / 1000, - this, - &clock_)) { - modules_.push_back(bwe_.get()); -} - -PacketSender::~PacketSender() { -} - -void PacketSender::RunFor(int64_t time_ms, Packets* in_out) { - int64_t now_ms = clock_.TimeInMilliseconds(); - std::list feedbacks = - GetFeedbackPackets(in_out, now_ms + time_ms); - ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out); -} - -void PacketSender::ProcessFeedbackAndGeneratePackets( - int64_t time_ms, - std::list* feedbacks, - Packets* generated) { - do { - // Make sure to at least run Process() below every 100 ms. - int64_t time_to_run_ms = std::min(time_ms, 100); - if (!feedbacks->empty()) { - int64_t time_until_feedback_ms = - feedbacks->front()->send_time_us() / 1000 - - clock_.TimeInMilliseconds(); - time_to_run_ms = - std::max(std::min(time_ms, time_until_feedback_ms), 0); - } - source_->RunFor(time_to_run_ms, generated); - clock_.AdvanceTimeMilliseconds(time_to_run_ms); - if (!feedbacks->empty()) { - bwe_->GiveFeedback(*feedbacks->front()); - delete feedbacks->front(); - feedbacks->pop_front(); - } - bwe_->Process(); - time_ms -= time_to_run_ms; - } while (time_ms > 0); - assert(feedbacks->empty()); -} - -int PacketSender::GetFeedbackIntervalMs() const { - return bwe_->GetFeedbackIntervalMs(); -} - -std::list PacketSender::GetFeedbackPackets( - Packets* in_out, - int64_t end_time_ms) { - std::list fb_packets; - for (auto it = in_out->begin(); it != in_out->end();) { - if ((*it)->send_time_us() > 1000 * end_time_ms) - break; - if ((*it)->GetPacketType() == Packet::kFeedback && - source()->flow_id() == (*it)->flow_id()) { - fb_packets.push_back(static_cast(*it)); - it = in_out->erase(it); - } else { - ++it; - } - } - return fb_packets; -} - -void PacketSender::OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_lost, - int64_t rtt) { - source_->SetBitrateBps(target_bitrate_bps); - std::stringstream ss; - ss << "SendEstimate_" << source_->flow_id() << "#1"; - BWE_TEST_LOGGING_PLOT(ss.str(), clock_.TimeInMilliseconds(), - target_bitrate_bps / 1000); -} - -PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener, - VideoSource* source, - BandwidthEstimatorType estimator) - : PacketSender(listener, source, estimator), - pacer_(&clock_, - this, - source->bits_per_second() / 1000, - PacedSender::kDefaultPaceMultiplier * source->bits_per_second() / - 1000, - 0) { - modules_.push_back(&pacer_); -} - -PacedVideoSender::~PacedVideoSender() { - for (Packet* packet : pacer_queue_) - delete packet; - for (Packet* packet : queue_) - delete packet; -} - -void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) { - int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms; - // Run process periodically to allow the packets to be paced out. - std::list feedbacks = - GetFeedbackPackets(in_out, end_time_ms); - int64_t last_run_time_ms = -1; - do { - int64_t time_until_process_ms = TimeUntilNextProcess(modules_); - int64_t time_until_feedback_ms = time_ms; - if (!feedbacks.empty()) - time_until_feedback_ms = feedbacks.front()->send_time_us() / 1000 - - clock_.TimeInMilliseconds(); - - int64_t time_until_next_event_ms = - std::min(time_until_feedback_ms, time_until_process_ms); - - time_until_next_event_ms = - std::min(source_->GetTimeUntilNextFrameMs(), time_until_next_event_ms); - - // Never run for longer than we have been asked for. - if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) - time_until_next_event_ms = end_time_ms - clock_.TimeInMilliseconds(); - - // Make sure we don't get stuck if an event doesn't trigger. This typically - // happens if the prober wants to probe, but there's no packet to send. - if (time_until_next_event_ms == 0 && last_run_time_ms == 0) - time_until_next_event_ms = 1; - last_run_time_ms = time_until_next_event_ms; - - Packets generated_packets; - source_->RunFor(time_until_next_event_ms, &generated_packets); - if (!generated_packets.empty()) { - for (Packet* packet : generated_packets) { - MediaPacket* media_packet = static_cast(packet); - pacer_.SendPacket(PacedSender::kNormalPriority, - media_packet->header().ssrc, - media_packet->header().sequenceNumber, - (media_packet->send_time_us() + 500) / 1000, - media_packet->payload_size(), false); - pacer_queue_.push_back(packet); - assert(pacer_queue_.size() < 10000); - } - } - - clock_.AdvanceTimeMilliseconds(time_until_next_event_ms); - - if (time_until_next_event_ms == time_until_feedback_ms) { - if (!feedbacks.empty()) { - bwe_->GiveFeedback(*feedbacks.front()); - delete feedbacks.front(); - feedbacks.pop_front(); - } - bwe_->Process(); - } - - if (time_until_next_event_ms == time_until_process_ms) { - CallProcess(modules_); - } - } while (clock_.TimeInMilliseconds() < end_time_ms); - QueuePackets(in_out, end_time_ms * 1000); -} - -int64_t PacedVideoSender::TimeUntilNextProcess( - const std::list& modules) { - int64_t time_until_next_process_ms = 10; - for (Module* module : modules) { - int64_t next_process_ms = module->TimeUntilNextProcess(); - if (next_process_ms < time_until_next_process_ms) - time_until_next_process_ms = next_process_ms; - } - if (time_until_next_process_ms < 0) - time_until_next_process_ms = 0; - return time_until_next_process_ms; -} - -void PacedVideoSender::CallProcess(const std::list& modules) { - for (Module* module : modules) { - if (module->TimeUntilNextProcess() <= 0) { - module->Process(); - } - } -} - -void PacedVideoSender::QueuePackets(Packets* batch, - int64_t end_of_batch_time_us) { - queue_.merge(*batch, DereferencingComparator); - if (queue_.empty()) { - return; - } - Packets::iterator it = queue_.begin(); - for (; it != queue_.end(); ++it) { - if ((*it)->send_time_us() > end_of_batch_time_us) { - break; - } - } - Packets to_transfer; - to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it); - batch->merge(to_transfer, DereferencingComparator); -} - -bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc, - uint16_t sequence_number, - int64_t capture_time_ms, - bool retransmission) { - for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end(); - ++it) { - MediaPacket* media_packet = static_cast(*it); - if (media_packet->header().sequenceNumber == sequence_number) { - int64_t pace_out_time_ms = clock_.TimeInMilliseconds(); - // Make sure a packet is never paced out earlier than when it was put into - // the pacer. - assert(pace_out_time_ms >= (media_packet->send_time_us() + 500) / 1000); - media_packet->SetAbsSendTimeMs(pace_out_time_ms); - media_packet->set_send_time_us(1000 * pace_out_time_ms); - queue_.push_back(media_packet); - pacer_queue_.erase(it); - return true; - } - } - return false; -} - -size_t PacedVideoSender::TimeToSendPadding(size_t bytes) { - return 0; -} - -void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_lost, - int64_t rtt) { - PacketSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt); - pacer_.UpdateBitrate( - target_bitrate_bps / 1000, - PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, 0); -} } // namespace bwe } // namespace testing } // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h index 2543d6f9f..f03597ebb 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include "webrtc/modules/pacing/include/paced_sender.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" @@ -162,94 +162,6 @@ class Random { DISALLOW_IMPLICIT_CONSTRUCTORS(Random); }; -class Packet { - public: - enum Type { kMedia, kFeedback }; - - Packet(); - Packet(int flow_id, int64_t send_time_us, size_t payload_size); - virtual ~Packet(); - - virtual bool operator<(const Packet& rhs) const; - - virtual int flow_id() const { return flow_id_; } - virtual int64_t creation_time_us() const { return creation_time_us_; } - virtual void set_send_time_us(int64_t send_time_us); - virtual int64_t send_time_us() const { return send_time_us_; } - virtual size_t payload_size() const { return payload_size_; } - virtual Packet::Type GetPacketType() const = 0; - - private: - int flow_id_; - int64_t creation_time_us_; // Time when the packet was created. - int64_t send_time_us_; // Time the packet left last processor touching it. - size_t payload_size_; // Size of the (non-existent, simulated) payload. -}; - -class MediaPacket : public Packet { - public: - MediaPacket(); - MediaPacket(int flow_id, - int64_t send_time_us, - size_t payload_size, - const RTPHeader& header); - MediaPacket(int64_t send_time_us, uint32_t sequence_number); - virtual ~MediaPacket() {} - - int64_t GetAbsSendTimeInMs() const; - void SetAbsSendTimeMs(int64_t abs_send_time_ms); - const RTPHeader& header() const { return header_; } - virtual Packet::Type GetPacketType() const { return kMedia; } - - private: - RTPHeader header_; -}; - -class FeedbackPacket : public Packet { - public: - FeedbackPacket(int flow_id, int64_t send_time_us) - : Packet(flow_id, send_time_us, 0) {} - virtual ~FeedbackPacket() {} - - virtual Packet::Type GetPacketType() const { return kFeedback; } -}; - -class RembFeedback : public FeedbackPacket { - public: - RembFeedback(int flow_id, - int64_t send_time_us, - uint32_t estimated_bps, - RTCPReportBlock report_block); - virtual ~RembFeedback() {} - - uint32_t estimated_bps() const { return estimated_bps_; } - RTCPReportBlock report_block() const { return report_block_; } - - private: - const uint32_t estimated_bps_; - const RTCPReportBlock report_block_; -}; - -class SendSideBweFeedback : public FeedbackPacket { - public: - typedef std::map ArrivalTimesMap; - SendSideBweFeedback(int flow_id, - int64_t send_time_us, - const std::vector& packet_feedback_vector); - virtual ~SendSideBweFeedback() {} - - const std::vector& packet_feedback_vector() const { - return packet_feedback_vector_; - } - - private: - const std::vector packet_feedback_vector_; -}; - -typedef std::list Packets; -typedef std::list::iterator PacketsIt; -typedef std::list::const_iterator PacketsConstIt; - bool IsTimeSorted(const Packets& packets); class PacketProcessor; @@ -519,172 +431,6 @@ class PeriodicKeyFrameSource : public AdaptiveVideoSource { int compensation_per_frame_; DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSource); }; - -class SendSideBwe : public Module { - public: - SendSideBwe() {} - virtual ~SendSideBwe() {} - - virtual int GetFeedbackIntervalMs() const = 0; - virtual void GiveFeedback(const FeedbackPacket& feedback) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(SendSideBwe); -}; - -class NullSendSideBwe : public SendSideBwe { - public: - NullSendSideBwe() {} - virtual ~NullSendSideBwe() {} - - virtual int GetFeedbackIntervalMs() const OVERRIDE { return 1000; } - virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE {} - virtual int64_t TimeUntilNextProcess() OVERRIDE { - return std::numeric_limits::max(); - } - virtual int Process() OVERRIDE { return 0; } - - private: - DISALLOW_COPY_AND_ASSIGN(NullSendSideBwe); -}; - -class RembSendSideBwe : public SendSideBwe { - public: - RembSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock); - virtual ~RembSendSideBwe(); - - virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; } - virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE; - virtual int64_t TimeUntilNextProcess() OVERRIDE; - virtual int Process() OVERRIDE; - - protected: - scoped_ptr bitrate_controller_; - scoped_ptr feedback_observer_; - - private: - Clock* clock_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(RembSendSideBwe); -}; - -class FullSendSideBwe : public SendSideBwe, public RemoteBitrateObserver { - public: - FullSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock); - virtual ~FullSendSideBwe(); - - virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; } - virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE; - virtual void OnReceiveBitrateChanged(const std::vector& ssrcs, - unsigned int bitrate) OVERRIDE; - virtual int64_t TimeUntilNextProcess() OVERRIDE; - virtual int Process() OVERRIDE; - - protected: - scoped_ptr bitrate_controller_; - scoped_ptr rbe_; - scoped_ptr feedback_observer_; - - private: - Clock* const clock_; - RTCPReportBlock report_block_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(FullSendSideBwe); -}; - -enum BandwidthEstimatorType { - kNullEstimator, - kRembEstimator, - kFullSendSideEstimator -}; - -class PacketSender : public PacketProcessor, public BitrateObserver { - public: - PacketSender(PacketProcessorListener* listener, - VideoSource* source, - BandwidthEstimatorType estimator); - virtual ~PacketSender(); - - // Call GiveFeedback() with the returned interval in milliseconds, provided - // there is a new estimate available. - // Note that changing the feedback interval affects the timing of when the - // output of the estimators is sampled and therefore the baseline files may - // have to be regenerated. - virtual int GetFeedbackIntervalMs() const; - virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; - - virtual VideoSource* source() const { return source_; } - - // Implements BitrateObserver. - virtual void OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_lost, - int64_t rtt) OVERRIDE; - - protected: - void ProcessFeedbackAndGeneratePackets(int64_t time_ms, - std::list* feedbacks, - Packets* generated); - std::list GetFeedbackPackets(Packets* in_out, - int64_t end_time_ms); - - SimulatedClock clock_; - VideoSource* source_; - scoped_ptr bwe_; - int64_t start_of_run_ms_; - std::list modules_; - - private: - DISALLOW_COPY_AND_ASSIGN(PacketSender); -}; - -class PacedVideoSender : public PacketSender, public PacedSender::Callback { - public: - PacedVideoSender(PacketProcessorListener* listener, - VideoSource* source, - BandwidthEstimatorType estimator); - virtual ~PacedVideoSender(); - - virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; - - // Implements PacedSender::Callback. - virtual bool TimeToSendPacket(uint32_t ssrc, - uint16_t sequence_number, - int64_t capture_time_ms, - bool retransmission) OVERRIDE; - virtual size_t TimeToSendPadding(size_t bytes) OVERRIDE; - - // Implements BitrateObserver. - virtual void OnNetworkChanged(uint32_t target_bitrate_bps, - uint8_t fraction_lost, - int64_t rtt) OVERRIDE; - - private: - class ProbingPacedSender : public PacedSender { - public: - ProbingPacedSender(Clock* clock, - Callback* callback, - int bitrate_kbps, - int max_bitrate_kbps, - int min_bitrate_kbps) - : PacedSender(clock, - callback, - bitrate_kbps, - max_bitrate_kbps, - min_bitrate_kbps) {} - - virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; } - }; - - int64_t TimeUntilNextProcess(const std::list& modules); - void CallProcess(const std::list& modules); - void QueuePackets(Packets* batch, int64_t end_of_batch_time_us); - - ProbingPacedSender pacer_; - Packets queue_; - Packets pacer_queue_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender); -}; } // namespace bwe } // namespace testing } // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc index ace2f5b76..c611b073b 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc @@ -14,6 +14,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/constructormagic.h" +#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h" #include "webrtc/test/testsupport/fileutils.h" using std::vector; diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet.h b/webrtc/modules/remote_bitrate_estimator/test/packet.h new file mode 100644 index 000000000..c0bb94b26 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/packet.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015 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_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_ + +#include +#include +#include + +#include "webrtc/common_types.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" +#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +class Packet { + public: + enum Type { kMedia, kFeedback }; + + Packet(); + Packet(int flow_id, int64_t send_time_us, size_t payload_size); + virtual ~Packet(); + + virtual bool operator<(const Packet& rhs) const; + + virtual int flow_id() const { return flow_id_; } + virtual int64_t creation_time_us() const { return creation_time_us_; } + virtual void set_send_time_us(int64_t send_time_us); + virtual int64_t send_time_us() const { return send_time_us_; } + virtual size_t payload_size() const { return payload_size_; } + virtual Packet::Type GetPacketType() const = 0; + + private: + int flow_id_; + int64_t creation_time_us_; // Time when the packet was created. + int64_t send_time_us_; // Time the packet left last processor touching it. + size_t payload_size_; // Size of the (non-existent, simulated) payload. +}; + +class MediaPacket : public Packet { + public: + MediaPacket(); + MediaPacket(int flow_id, + int64_t send_time_us, + size_t payload_size, + const RTPHeader& header); + MediaPacket(int64_t send_time_us, uint32_t sequence_number); + virtual ~MediaPacket() {} + + int64_t GetAbsSendTimeInMs() const; + void SetAbsSendTimeMs(int64_t abs_send_time_ms); + const RTPHeader& header() const { return header_; } + virtual Packet::Type GetPacketType() const { return kMedia; } + + private: + RTPHeader header_; +}; + +class FeedbackPacket : public Packet { + public: + FeedbackPacket(int flow_id, int64_t send_time_us) + : Packet(flow_id, send_time_us, 0) {} + virtual ~FeedbackPacket() {} + + virtual Packet::Type GetPacketType() const { return kFeedback; } +}; + +class RembFeedback : public FeedbackPacket { + public: + RembFeedback(int flow_id, + int64_t send_time_us, + uint32_t estimated_bps, + RTCPReportBlock report_block); + virtual ~RembFeedback() {} + + uint32_t estimated_bps() const { return estimated_bps_; } + RTCPReportBlock report_block() const { return report_block_; } + + private: + const uint32_t estimated_bps_; + const RTCPReportBlock report_block_; +}; + +class SendSideBweFeedback : public FeedbackPacket { + public: + typedef std::map ArrivalTimesMap; + SendSideBweFeedback(int flow_id, + int64_t send_time_us, + const std::vector& packet_feedback_vector); + virtual ~SendSideBweFeedback() {} + + const std::vector& packet_feedback_vector() const { + return packet_feedback_vector_; + } + + private: + const std::vector packet_feedback_vector_; +}; + +typedef std::list Packets; +typedef std::list::iterator PacketsIt; +typedef std::list::const_iterator PacketsConstIt; +} // namespace bwe +} // namespace testing +} // namespace webrtc +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_ diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.cc b/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.cc new file mode 100644 index 000000000..bf579d6e9 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 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/remote_bitrate_estimator/test/packet_receiver.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/common.h" +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h" +#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h" +#include "webrtc/system_wrappers/interface/clock.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +PacketReceiver::PacketReceiver(PacketProcessorListener* listener, + int flow_id, + BandwidthEstimatorType bwe_type, + bool plot_delay, + bool plot_bwe) + : PacketProcessor(listener, flow_id, kReceiver), + delay_log_prefix_(), + last_delay_plot_ms_(0), + plot_delay_(plot_delay), + bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) { + // Setup the prefix ststd::rings used when logging. + std::stringstream ss; + ss << "Delay_" << flow_id << "#2"; + delay_log_prefix_ = ss.str(); +} + +PacketReceiver::~PacketReceiver() { +} + +void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) { + Packets feedback; + for (auto it = in_out->begin(); it != in_out->end();) { + // PacketReceivers are only associated with a single stream, and therefore + // should only process a single flow id. + // TODO(holmer): Break this out into a Demuxer which implements both + // PacketProcessorListener and PacketProcessor. + if ((*it)->GetPacketType() == Packet::kMedia && + (*it)->flow_id() == *flow_ids().begin()) { + BWE_TEST_LOGGING_CONTEXT("Receiver"); + const MediaPacket* media_packet = static_cast(*it); + // We're treating the send time (from previous filter) as the arrival + // time once packet reaches the estimator. + int64_t arrival_time_ms = (media_packet->send_time_us() + 500) / 1000; + BWE_TEST_LOGGING_TIME(arrival_time_ms); + PlotDelay(arrival_time_ms, + (media_packet->creation_time_us() + 500) / 1000); + + bwe_receiver_->ReceivePacket(arrival_time_ms, + media_packet->payload_size(), + media_packet->header()); + FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms); + if (fb) + feedback.push_back(fb); + delete media_packet; + it = in_out->erase(it); + } else { + ++it; + } + } + // Insert feedback packets to be sent back to the sender. + in_out->merge(feedback, DereferencingComparator); +} + +void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) { + static const int kDelayPlotIntervalMs = 100; + if (!plot_delay_) + return; + if (arrival_time_ms - last_delay_plot_ms_ > kDelayPlotIntervalMs) { + BWE_TEST_LOGGING_PLOT(delay_log_prefix_, arrival_time_ms, + arrival_time_ms - send_time_ms); + last_delay_plot_ms_ = arrival_time_ms; + } +} +} // namespace bwe +} // namespace testing +} // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h b/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h new file mode 100644 index 000000000..50d177094 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 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_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_ + +#include + +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +class PacketReceiver : public PacketProcessor { + public: + PacketReceiver(PacketProcessorListener* listener, + int flow_id, + BandwidthEstimatorType bwe_type, + bool plot_delay, + bool plot_bwe); + ~PacketReceiver(); + + // Implements PacketProcessor. + virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; + + void LogStats(); + + protected: + void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms); + + int64_t now_ms_; + std::string delay_log_prefix_; + int64_t last_delay_plot_ms_; + bool plot_delay_; + scoped_ptr bwe_receiver_; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver); +}; +} // namespace bwe +} // namespace testing +} // namespace webrtc +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_ diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc new file mode 100644 index 000000000..36690b608 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2015 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/remote_bitrate_estimator/test/packet_sender.h" + +#include +#include +#include + +#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +PacketSender::PacketSender(PacketProcessorListener* listener, + VideoSource* source, + BandwidthEstimatorType estimator) + : PacketProcessor(listener, source->flow_id(), kSender), + // For Packet::send_time_us() to be comparable with timestamps from + // clock_, the clock of the PacketSender and the Source must be aligned. + // We assume that both start at time 0. + clock_(0), + source_(source), + bwe_(CreateBweSender(estimator, + source_->bits_per_second() / 1000, + this, + &clock_)) { + modules_.push_back(bwe_.get()); +} + +PacketSender::~PacketSender() { +} + +void PacketSender::RunFor(int64_t time_ms, Packets* in_out) { + int64_t now_ms = clock_.TimeInMilliseconds(); + std::list feedbacks = + GetFeedbackPackets(in_out, now_ms + time_ms); + ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out); +} + +void PacketSender::ProcessFeedbackAndGeneratePackets( + int64_t time_ms, + std::list* feedbacks, + Packets* generated) { + do { + // Make sure to at least run Process() below every 100 ms. + int64_t time_to_run_ms = std::min(time_ms, 100); + if (!feedbacks->empty()) { + int64_t time_until_feedback_ms = + feedbacks->front()->send_time_us() / 1000 - + clock_.TimeInMilliseconds(); + time_to_run_ms = + std::max(std::min(time_ms, time_until_feedback_ms), 0); + } + source_->RunFor(time_to_run_ms, generated); + clock_.AdvanceTimeMilliseconds(time_to_run_ms); + if (!feedbacks->empty()) { + bwe_->GiveFeedback(*feedbacks->front()); + delete feedbacks->front(); + feedbacks->pop_front(); + } + bwe_->Process(); + time_ms -= time_to_run_ms; + } while (time_ms > 0); + assert(feedbacks->empty()); +} + +int PacketSender::GetFeedbackIntervalMs() const { + return bwe_->GetFeedbackIntervalMs(); +} + +std::list PacketSender::GetFeedbackPackets( + Packets* in_out, + int64_t end_time_ms) { + std::list fb_packets; + for (auto it = in_out->begin(); it != in_out->end();) { + if ((*it)->send_time_us() > 1000 * end_time_ms) + break; + if ((*it)->GetPacketType() == Packet::kFeedback && + source()->flow_id() == (*it)->flow_id()) { + fb_packets.push_back(static_cast(*it)); + it = in_out->erase(it); + } else { + ++it; + } + } + return fb_packets; +} + +void PacketSender::OnNetworkChanged(uint32_t target_bitrate_bps, + uint8_t fraction_lost, + int64_t rtt) { + source_->SetBitrateBps(target_bitrate_bps); + std::stringstream ss; + ss << "SendEstimate_" << source_->flow_id() << "#1"; + BWE_TEST_LOGGING_PLOT(ss.str(), clock_.TimeInMilliseconds(), + target_bitrate_bps / 1000); +} + +PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener, + VideoSource* source, + BandwidthEstimatorType estimator) + : PacketSender(listener, source, estimator), + pacer_(&clock_, + this, + source->bits_per_second() / 1000, + PacedSender::kDefaultPaceMultiplier * source->bits_per_second() / + 1000, + 0) { + modules_.push_back(&pacer_); +} + +PacedVideoSender::~PacedVideoSender() { + for (Packet* packet : pacer_queue_) + delete packet; + for (Packet* packet : queue_) + delete packet; +} + +void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) { + int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms; + // Run process periodically to allow the packets to be paced out. + std::list feedbacks = + GetFeedbackPackets(in_out, end_time_ms); + int64_t last_run_time_ms = -1; + do { + int64_t time_until_process_ms = TimeUntilNextProcess(modules_); + int64_t time_until_feedback_ms = time_ms; + if (!feedbacks.empty()) + time_until_feedback_ms = feedbacks.front()->send_time_us() / 1000 - + clock_.TimeInMilliseconds(); + + int64_t time_until_next_event_ms = + std::min(time_until_feedback_ms, time_until_process_ms); + + time_until_next_event_ms = + std::min(source_->GetTimeUntilNextFrameMs(), time_until_next_event_ms); + + // Never run for longer than we have been asked for. + if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) + time_until_next_event_ms = end_time_ms - clock_.TimeInMilliseconds(); + + // Make sure we don't get stuck if an event doesn't trigger. This typically + // happens if the prober wants to probe, but there's no packet to send. + if (time_until_next_event_ms == 0 && last_run_time_ms == 0) + time_until_next_event_ms = 1; + last_run_time_ms = time_until_next_event_ms; + + Packets generated_packets; + source_->RunFor(time_until_next_event_ms, &generated_packets); + if (!generated_packets.empty()) { + for (Packet* packet : generated_packets) { + MediaPacket* media_packet = static_cast(packet); + pacer_.SendPacket(PacedSender::kNormalPriority, + media_packet->header().ssrc, + media_packet->header().sequenceNumber, + (media_packet->send_time_us() + 500) / 1000, + media_packet->payload_size(), false); + pacer_queue_.push_back(packet); + assert(pacer_queue_.size() < 10000); + } + } + + clock_.AdvanceTimeMilliseconds(time_until_next_event_ms); + + if (time_until_next_event_ms == time_until_feedback_ms) { + if (!feedbacks.empty()) { + bwe_->GiveFeedback(*feedbacks.front()); + delete feedbacks.front(); + feedbacks.pop_front(); + } + bwe_->Process(); + } + + if (time_until_next_event_ms == time_until_process_ms) { + CallProcess(modules_); + } + } while (clock_.TimeInMilliseconds() < end_time_ms); + QueuePackets(in_out, end_time_ms * 1000); +} + +int64_t PacedVideoSender::TimeUntilNextProcess( + const std::list& modules) { + int64_t time_until_next_process_ms = 10; + for (Module* module : modules) { + int64_t next_process_ms = module->TimeUntilNextProcess(); + if (next_process_ms < time_until_next_process_ms) + time_until_next_process_ms = next_process_ms; + } + if (time_until_next_process_ms < 0) + time_until_next_process_ms = 0; + return time_until_next_process_ms; +} + +void PacedVideoSender::CallProcess(const std::list& modules) { + for (Module* module : modules) { + if (module->TimeUntilNextProcess() <= 0) { + module->Process(); + } + } +} + +void PacedVideoSender::QueuePackets(Packets* batch, + int64_t end_of_batch_time_us) { + queue_.merge(*batch, DereferencingComparator); + if (queue_.empty()) { + return; + } + Packets::iterator it = queue_.begin(); + for (; it != queue_.end(); ++it) { + if ((*it)->send_time_us() > end_of_batch_time_us) { + break; + } + } + Packets to_transfer; + to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it); + batch->merge(to_transfer, DereferencingComparator); +} + +bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission) { + for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end(); + ++it) { + MediaPacket* media_packet = static_cast(*it); + if (media_packet->header().sequenceNumber == sequence_number) { + int64_t pace_out_time_ms = clock_.TimeInMilliseconds(); + // Make sure a packet is never paced out earlier than when it was put into + // the pacer. + assert(pace_out_time_ms >= (media_packet->send_time_us() + 500) / 1000); + media_packet->SetAbsSendTimeMs(pace_out_time_ms); + media_packet->set_send_time_us(1000 * pace_out_time_ms); + queue_.push_back(media_packet); + pacer_queue_.erase(it); + return true; + } + } + return false; +} + +size_t PacedVideoSender::TimeToSendPadding(size_t bytes) { + return 0; +} + +void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps, + uint8_t fraction_lost, + int64_t rtt) { + PacketSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt); + pacer_.UpdateBitrate( + target_bitrate_bps / 1000, + PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, 0); +} +} // namespace bwe +} // namespace testing +} // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h new file mode 100644 index 000000000..d5ea3e8b4 --- /dev/null +++ b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015 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_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_ + +#include +#include + +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/interface/module.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h" +#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { +namespace testing { +namespace bwe { + +class PacketSender : public PacketProcessor, public BitrateObserver { + public: + PacketSender(PacketProcessorListener* listener, + VideoSource* source, + BandwidthEstimatorType estimator); + virtual ~PacketSender(); + + // Call GiveFeedback() with the returned interval in milliseconds, provided + // there is a new estimate available. + // Note that changing the feedback interval affects the timing of when the + // output of the estimators is sampled and therefore the baseline files may + // have to be regenerated. + virtual int GetFeedbackIntervalMs() const; + virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; + + virtual VideoSource* source() const { return source_; } + + // Implements BitrateObserver. + virtual void OnNetworkChanged(uint32_t target_bitrate_bps, + uint8_t fraction_lost, + int64_t rtt) OVERRIDE; + + protected: + void ProcessFeedbackAndGeneratePackets(int64_t time_ms, + std::list* feedbacks, + Packets* generated); + std::list GetFeedbackPackets(Packets* in_out, + int64_t end_time_ms); + + SimulatedClock clock_; + VideoSource* source_; + scoped_ptr bwe_; + int64_t start_of_run_ms_; + std::list modules_; + + private: + DISALLOW_COPY_AND_ASSIGN(PacketSender); +}; + +class PacedVideoSender : public PacketSender, public PacedSender::Callback { + public: + PacedVideoSender(PacketProcessorListener* listener, + VideoSource* source, + BandwidthEstimatorType estimator); + virtual ~PacedVideoSender(); + + virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; + + // Implements PacedSender::Callback. + virtual bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission) OVERRIDE; + virtual size_t TimeToSendPadding(size_t bytes) OVERRIDE; + + // Implements BitrateObserver. + virtual void OnNetworkChanged(uint32_t target_bitrate_bps, + uint8_t fraction_lost, + int64_t rtt) OVERRIDE; + + private: + class ProbingPacedSender : public PacedSender { + public: + ProbingPacedSender(Clock* clock, + Callback* callback, + int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps) + : PacedSender(clock, + callback, + bitrate_kbps, + max_bitrate_kbps, + min_bitrate_kbps) {} + + virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; } + }; + + int64_t TimeUntilNextProcess(const std::list& modules); + void CallProcess(const std::list& modules); + void QueuePackets(Packets* batch, int64_t end_of_batch_time_us); + + ProbingPacedSender pacer_; + Packets queue_; + Packets pacer_queue_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender); +}; +} // namespace bwe +} // namespace testing +} // namespace webrtc +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_