Integrate send-side BWE into simulation framework.

BUG=4173
R=mflodman@webrtc.org, tommi@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/34699004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8123 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2015-01-22 10:10:53 +00:00
parent cfd82dfc11
commit e5251ad63c
4 changed files with 188 additions and 47 deletions

View File

@ -10,9 +10,11 @@
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.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/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
@ -23,13 +25,13 @@ namespace webrtc {
namespace testing {
namespace bwe {
class TestedEstimator : public RemoteBitrateObserver {
class PacketReceiver : public RemoteBitrateObserver {
public:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
static const int kDelayPlotIntervalMs = 100;
TestedEstimator(const string& test_name,
const BweTestConfig::EstimatorConfig& config)
PacketReceiver(const string& test_name,
const BweTestConfig::EstimatorConfig& config)
: debug_name_(config.debug_name),
delay_log_prefix_(),
estimate_log_prefix_(),
@ -38,9 +40,12 @@ class TestedEstimator : public RemoteBitrateObserver {
plot_estimate_(config.plot_estimate),
clock_(0),
stats_(),
recv_stats_(ReceiveStatistics::Create(&clock_)),
latest_estimate_bps_(-1),
estimator_(config.estimator_factory->Create(
this, &clock_, config.control_type,
this,
&clock_,
config.control_type,
kRemoteBitrateEstimatorMinBitrateBps)),
baseline_(BaseLineFileInterface::Create(test_name + "_" + debug_name_,
config.update_baseline)) {
@ -60,6 +65,8 @@ class TestedEstimator : public RemoteBitrateObserver {
void EatPacket(const Packet& packet) {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
recv_stats_->IncomingPacket(packet.header(), packet.payload_size(), false);
latest_estimate_bps_ = -1;
// We're treating the send time (from previous filter) as the arrival
@ -89,12 +96,19 @@ class TestedEstimator : public RemoteBitrateObserver {
ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds());
}
bool CheckEstimate(PacketSender::Feedback* feedback) {
bool GetFeedback(PacketSender::Feedback* feedback) {
assert(feedback);
BWE_TEST_LOGGING_CONTEXT(debug_name_);
uint32_t estimated_bps = 0;
if (LatestEstimate(&estimated_bps)) {
feedback->estimated_bps = estimated_bps;
StatisticianMap statisticians = recv_stats_->GetActiveStatisticians();
if (statisticians.empty()) {
feedback->report_block = RTCPReportBlock();
} else {
feedback->report_block =
BuildReportBlock(statisticians.begin()->second);
}
baseline_->Estimate(clock_.TimeInMilliseconds(), estimated_bps);
double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
@ -123,6 +137,18 @@ class TestedEstimator : public RemoteBitrateObserver {
}
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<unsigned int> ssrcs;
@ -144,11 +170,12 @@ class TestedEstimator : public RemoteBitrateObserver {
bool plot_estimate_;
SimulatedClock clock_;
Stats<double> stats_;
scoped_ptr<ReceiveStatistics> recv_stats_;
int64_t latest_estimate_bps_;
scoped_ptr<RemoteBitrateEstimator> estimator_;
scoped_ptr<BaseLineFileInterface> baseline_;
DISALLOW_IMPLICIT_CONSTRUCTORS(TestedEstimator);
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
};
class PacketProcessorRunner {
@ -242,8 +269,8 @@ void BweTest::SetupTestFromConfig(const BweTestConfig& config) {
for (vector<BweTestConfig::EstimatorConfig>::const_iterator it =
config.estimator_configs.begin(); it != config.estimator_configs.end();
++it) {
estimators_.insert(std::make_pair(it->flow_id, new TestedEstimator(
test_name, *it)));
estimators_.insert(
std::make_pair(it->flow_id, new PacketReceiver(test_name, *it)));
}
BWE_TEST_LOGGING_GLOBAL_ENABLE(false);
}
@ -277,7 +304,7 @@ void BweTest::VerboseLogging(bool enable) {
}
void BweTest::GiveFeedbackToAffectedSenders(int flow_id,
TestedEstimator* estimator) {
PacketReceiver* estimator) {
std::list<PacketSender*> affected_senders;
for (std::vector<PacketSender*>::iterator psit =
senders_.begin(); psit != senders_.end(); ++psit) {
@ -287,7 +314,7 @@ void BweTest::GiveFeedbackToAffectedSenders(int flow_id,
}
}
PacketSender::Feedback feedback = {0};
if (estimator->CheckEstimate(&feedback) && !affected_senders.empty()) {
if (estimator->GetFeedback(&feedback) && !affected_senders.empty()) {
// Allocate the bitrate evenly between the senders.
feedback.estimated_bps /= affected_senders.size();
for (std::list<PacketSender*>::iterator psit = affected_senders.begin();

View File

@ -86,7 +86,7 @@ struct BweTestConfig {
std::vector<EstimatorConfig> estimator_configs;
};
class TestedEstimator;
class PacketReceiver;
class PacketProcessorRunner;
class BweTest : public PacketProcessorListener {
@ -104,11 +104,11 @@ class BweTest : public PacketProcessorListener {
std::string GetTestName() const;
private:
typedef std::map<int, TestedEstimator*> EstimatorMap;
typedef std::map<int, PacketReceiver*> EstimatorMap;
void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in,
Packets* out);
void GiveFeedbackToAffectedSenders(int flow_id, TestedEstimator* estimator);
void GiveFeedbackToAffectedSenders(int flow_id, PacketReceiver* estimator);
int64_t run_time_ms_;
int64_t time_now_ms_;

View File

@ -538,10 +538,8 @@ void TraceBasedDeliveryFilter::ProceedToNextSlot() {
PacketSender::PacketSender(PacketProcessorListener* listener)
: PacketProcessor(listener, true) {}
PacketSender::PacketSender(PacketProcessorListener* listener,
const FlowIds& flow_ids)
: PacketProcessor(listener, flow_ids, true) {
PacketSender::PacketSender(PacketProcessorListener* listener, int flow_id)
: PacketProcessor(listener, FlowIds(1, flow_id), true) {
}
VideoSender::VideoSender(int flow_id,
@ -550,7 +548,7 @@ VideoSender::VideoSender(int flow_id,
uint32_t kbps,
uint32_t ssrc,
int64_t first_frame_offset_ms)
: PacketSender(listener, FlowIds(1, flow_id)),
: PacketSender(listener, flow_id),
kMaxPayloadSizeBytes(1200),
kTimestampBase(0xff80ff00ul),
frame_period_ms_(1000.0 / fps),
@ -677,17 +675,73 @@ uint32_t PeriodicKeyFrameSender::NextPacketSize(uint32_t frame_size,
return std::min(avg_size, remaining_payload);
}
RegularVideoSender::RegularVideoSender(PacketProcessorListener* listener,
uint32_t kbps,
AdaptiveVideoSender* source)
// It is important that the first_frame_offset and the initial time of
// clock_ are both zero, otherwise we can't have absolute time in this
// class.
: PacketSender(listener, source->flow_ids()[0]),
clock_(0),
start_of_run_ms_(0),
bitrate_controller_(BitrateController::CreateBitrateController(&clock_,
false)),
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
source_(source),
modules_() {
const int kMinBitrateBps = 10000;
const int kMaxBitrateBps = 20000000;
bitrate_controller_->SetBitrateObserver(this, 1000 * kbps, kMinBitrateBps,
kMaxBitrateBps);
modules_.push_back(bitrate_controller_.get());
}
RegularVideoSender::~RegularVideoSender() {
}
void RegularVideoSender::GiveFeedback(const Feedback& feedback) {
feedback_observer_->OnReceivedEstimatedBitrate(feedback.estimated_bps);
ReportBlockList report_blocks;
report_blocks.push_back(feedback.report_block);
feedback_observer_->OnReceivedRtcpReceiverReport(report_blocks, 0,
clock_.TimeInMilliseconds());
bitrate_controller_->Process();
}
void RegularVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
start_of_run_ms_ = clock_.TimeInMilliseconds();
source_->RunFor(time_ms, in_out);
clock_.AdvanceTimeMilliseconds(time_ms);
}
void RegularVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost,
int64_t rtt) {
PacketSender::Feedback feedback;
feedback.estimated_bps = target_bitrate_bps;
source_->GiveFeedback(feedback);
std::stringstream ss;
ss << "SendEstimate_" << flow_ids()[0] << "#1";
BWE_TEST_LOGGING_PLOT(ss.str(), clock_.TimeInMilliseconds(),
target_bitrate_bps / 1000);
}
PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
uint32_t kbps,
AdaptiveVideoSender* source)
// It is important that the first_frame_offset and the initial time of
// clock_ are both zero, otherwise we can't have absolute time in this
// class.
: PacketSender(listener, source->flow_ids()),
clock_(0),
start_of_run_ms_(0),
pacer_(&clock_, this, kbps, PacedSender::kDefaultPaceMultiplier* kbps, 0),
source_(source) {
: RegularVideoSender(listener, kbps, source),
pacer_(&clock_,
this,
kbps,
PacedSender::kDefaultPaceMultiplier* kbps,
0) {
modules_.push_back(&pacer_);
}
PacedVideoSender::~PacedVideoSender() {
}
void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
@ -698,18 +752,18 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms;
Packets::iterator it = generated_packets.begin();
while (clock_.TimeInMilliseconds() <= end_time_ms) {
int64_t time_until_process_ms = pacer_.TimeUntilNextProcess();
if (time_until_process_ms < 0)
time_until_process_ms = 0;
int64_t time_until_process_ms = TimeUntilNextProcess(modules_);
int time_until_packet_ms = time_ms;
if (it != generated_packets.end())
time_until_packet_ms =
(it->send_time_us() + 500) / 1000 - clock_.TimeInMilliseconds();
assert(time_until_packet_ms >= 0);
int time_until_next_event_ms = time_until_packet_ms;
if (time_until_process_ms < time_until_packet_ms &&
pacer_.QueueSizePackets() > 0)
if (time_until_process_ms < time_until_packet_ms) {
time_until_next_event_ms = time_until_process_ms;
}
if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) {
clock_.AdvanceTimeMilliseconds(end_time_ms - clock_.TimeInMilliseconds());
@ -718,7 +772,7 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
clock_.AdvanceTimeMilliseconds(time_until_next_event_ms);
if (time_until_process_ms < time_until_packet_ms) {
// Time to process.
pacer_.Process();
CallProcess(modules_);
} else {
// Time to send next packet to pacer.
pacer_.SendPacket(PacedSender::kNormalPriority,
@ -738,6 +792,27 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
QueuePackets(in_out, end_time_ms * 1000);
}
int64_t PacedVideoSender::TimeUntilNextProcess(
const std::list<Module*>& modules) {
int64_t time_until_next_process_ms = 10;
for (auto* 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<Module*>& modules) {
for (auto* module : modules) {
if (module->TimeUntilNextProcess() <= 0) {
module->Process();
}
}
}
void PacedVideoSender::QueuePackets(Packets* batch,
int64_t end_of_batch_time_us) {
queue_.merge(*batch);
@ -755,14 +830,6 @@ void PacedVideoSender::QueuePackets(Packets* batch,
batch->merge(to_transfer);
}
void PacedVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
source_->GiveFeedback(feedback);
pacer_.UpdateBitrate(
feedback.estimated_bps / 1000,
PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000,
0);
}
bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
int64_t capture_time_ms,
@ -786,6 +853,15 @@ bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
size_t PacedVideoSender::TimeToSendPadding(size_t bytes) {
return 0;
}
void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost,
int64_t rtt) {
RegularVideoSender::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

View File

@ -21,13 +21,18 @@
#include <string>
#include <vector>
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/modules/pacing/include/paced_sender.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.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"
namespace webrtc {
class RtcpBandwidthObserver;
namespace testing {
namespace bwe {
@ -365,10 +370,11 @@ class PacketSender : public PacketProcessor {
public:
struct Feedback {
uint32_t estimated_bps;
RTCPReportBlock report_block;
};
explicit PacketSender(PacketProcessorListener* listener);
PacketSender(PacketProcessorListener* listener, const FlowIds& flow_ids);
PacketSender(PacketProcessorListener* listener, int flow_id);
virtual ~PacketSender() {}
virtual uint32_t GetCapacityKbps() const { return 0; }
@ -462,16 +468,45 @@ class PeriodicKeyFrameSender : public AdaptiveVideoSender {
DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSender);
};
class PacedVideoSender : public PacketSender, public PacedSender::Callback {
class RegularVideoSender : public PacketSender, public BitrateObserver {
public:
PacedVideoSender(PacketProcessorListener* listener,
uint32_t kbps, AdaptiveVideoSender* source);
virtual ~PacedVideoSender() {}
RegularVideoSender(PacketProcessorListener* listener,
uint32_t kbps,
AdaptiveVideoSender* source);
virtual ~RegularVideoSender();
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
virtual void GiveFeedback(const Feedback& feedback) OVERRIDE;
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
// Implements BitrateObserver.
virtual void OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost,
int64_t rtt) OVERRIDE;
protected:
static const int64_t kInitialTimeMs = 0;
SimulatedClock clock_;
int64_t start_of_run_ms_;
scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
AdaptiveVideoSender* source_;
std::list<Module*> modules_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(RegularVideoSender);
};
class PacedVideoSender : public RegularVideoSender,
public PacedSender::Callback {
public:
PacedVideoSender(PacketProcessorListener* listener,
uint32_t kbps,
AdaptiveVideoSender* source);
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,
@ -479,6 +514,11 @@ class PacedVideoSender : public PacketSender, public PacedSender::Callback {
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:
@ -496,15 +536,13 @@ class PacedVideoSender : public PacketSender, public PacedSender::Callback {
virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; }
};
int64_t TimeUntilNextProcess(const std::list<Module*>& modules);
void CallProcess(const std::list<Module*>& modules);
void QueuePackets(Packets* batch, int64_t end_of_batch_time_us);
static const int64_t kInitialTimeMs = 0;
SimulatedClock clock_;
int64_t start_of_run_ms_;
ProbingPacedSender pacer_;
Packets pacer_queue_;
Packets queue_;
AdaptiveVideoSender* source_;
Packets pacer_queue_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender);
};