blob: 60981976aef4365e4f64eabdf3312e1605e6ea22 [file] [log] [blame]
/*
* Copyright (c) 2013 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_TEST_FRAMEWORK_H_
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_FRAMEWORK_H_
#include <assert.h>
#include <math.h>
#include <algorithm>
#include <list>
#include <numeric>
#include <sstream>
#include <string>
#include <vector>
#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/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
namespace testing {
namespace bwe {
class DelayCapHelper;
class RateCounter;
typedef std::vector<int> FlowIds;
const FlowIds CreateFlowIds(const int *flow_ids_array, size_t num_flow_ids);
template<typename T> class Stats {
public:
Stats()
: data_(),
last_mean_count_(0),
last_variance_count_(0),
last_minmax_count_(0),
mean_(0),
variance_(0),
min_(0),
max_(0) {
}
void Push(T data_point) {
data_.push_back(data_point);
}
T GetMean() {
if (last_mean_count_ != data_.size()) {
last_mean_count_ = data_.size();
mean_ = std::accumulate(data_.begin(), data_.end(), static_cast<T>(0));
assert(last_mean_count_ != 0);
mean_ /= static_cast<T>(last_mean_count_);
}
return mean_;
}
T GetVariance() {
if (last_variance_count_ != data_.size()) {
last_variance_count_ = data_.size();
T mean = GetMean();
variance_ = 0;
for (typename std::vector<T>::const_iterator it = data_.begin();
it != data_.end(); ++it) {
T diff = (*it - mean);
variance_ += diff * diff;
}
assert(last_variance_count_ != 0);
variance_ /= static_cast<T>(last_variance_count_);
}
return variance_;
}
T GetStdDev() {
return sqrt(static_cast<double>(GetVariance()));
}
T GetMin() {
RefreshMinMax();
return min_;
}
T GetMax() {
RefreshMinMax();
return max_;
}
std::string AsString() {
std::stringstream ss;
ss << (GetMean() >= 0 ? GetMean() : -1) << ", " <<
(GetStdDev() >= 0 ? GetStdDev() : -1);
return ss.str();
}
void Log(const std::string& units) {
BWE_TEST_LOGGING_LOG5("", "%f %s\t+/-%f\t[%f,%f]",
GetMean(), units.c_str(), GetStdDev(), GetMin(), GetMax());
}
private:
void RefreshMinMax() {
if (last_minmax_count_ != data_.size()) {
last_minmax_count_ = data_.size();
min_ = max_ = 0;
if (data_.empty()) {
return;
}
typename std::vector<T>::const_iterator it = data_.begin();
min_ = max_ = *it;
while (++it != data_.end()) {
min_ = std::min(min_, *it);
max_ = std::max(max_, *it);
}
}
}
std::vector<T> data_;
typename std::vector<T>::size_type last_mean_count_;
typename std::vector<T>::size_type last_variance_count_;
typename std::vector<T>::size_type last_minmax_count_;
T mean_;
T variance_;
T min_;
T max_;
};
class Random {
public:
explicit Random(uint32_t seed);
// Return pseudo random number in the interval [0.0, 1.0].
float Rand();
// Normal Distribution.
int Gaussian(int mean, int standard_deviation);
// TODO(solenberg): Random from histogram.
// template<typename T> int Distribution(const std::vector<T> histogram) {
private:
uint32_t a_;
uint32_t b_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Random);
};
class Packet {
public:
Packet();
Packet(int flow_id, int64_t send_time_us, uint32_t payload_size,
const RTPHeader& header);
Packet(int64_t send_time_us, uint32_t sequence_number);
bool operator<(const Packet& rhs) const;
int flow_id() const { return flow_id_; }
int64_t creation_time_us() const { return creation_time_us_; }
void set_send_time_us(int64_t send_time_us);
int64_t send_time_us() const { return send_time_us_; }
void SetAbsSendTimeMs(int64_t abs_send_time_ms);
uint32_t payload_size() const { return payload_size_; }
const RTPHeader& header() const { return header_; }
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.
uint32_t payload_size_; // Size of the (non-existent, simulated) payload.
RTPHeader header_; // Actual contents.
};
typedef std::list<Packet> Packets;
typedef std::list<Packet>::iterator PacketsIt;
typedef std::list<Packet>::const_iterator PacketsConstIt;
bool IsTimeSorted(const Packets& packets);
class PacketProcessor;
class PacketProcessorListener {
public:
virtual ~PacketProcessorListener() {}
virtual void AddPacketProcessor(PacketProcessor* processor,
bool is_sender) = 0;
virtual void RemovePacketProcessor(PacketProcessor* processor) = 0;
};
class PacketProcessor {
public:
PacketProcessor(PacketProcessorListener* listener, bool is_sender);
PacketProcessor(PacketProcessorListener* listener, const FlowIds& flow_ids,
bool is_sender);
virtual ~PacketProcessor();
// Called after each simulation batch to allow the processor to plot any
// internal data.
virtual void Plot(int64_t timestamp_ms) {}
// Run simulation for |time_ms| micro seconds, consuming packets from, and
// producing packets into in_out. The outgoing packet list must be sorted on
// |send_time_us_|. The simulation time |time_ms| is optional to use.
virtual void RunFor(int64_t time_ms, Packets* in_out) = 0;
const FlowIds& flow_ids() const { return flow_ids_; }
private:
PacketProcessorListener* listener_;
FlowIds flow_ids_;
DISALLOW_COPY_AND_ASSIGN(PacketProcessor);
};
class RateCounterFilter : public PacketProcessor {
public:
explicit RateCounterFilter(PacketProcessorListener* listener);
RateCounterFilter(PacketProcessorListener* listener,
const std::string& name);
RateCounterFilter(PacketProcessorListener* listener,
const FlowIds& flow_ids,
const std::string& name);
virtual ~RateCounterFilter();
uint32_t packets_per_second() const;
uint32_t bits_per_second() const;
void LogStats();
Stats<double> GetBitrateStats() const;
virtual void Plot(int64_t timestamp_ms);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
scoped_ptr<RateCounter> rate_counter_;
Stats<double> packets_per_second_stats_;
Stats<double> kbps_stats_;
std::string name_;
DISALLOW_IMPLICIT_CONSTRUCTORS(RateCounterFilter);
};
class LossFilter : public PacketProcessor {
public:
explicit LossFilter(PacketProcessorListener* listener);
virtual ~LossFilter() {}
void SetLoss(float loss_percent);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
Random random_;
float loss_fraction_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LossFilter);
};
class DelayFilter : public PacketProcessor {
public:
explicit DelayFilter(PacketProcessorListener* listener);
virtual ~DelayFilter() {}
void SetDelay(int64_t delay_ms);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
int64_t delay_us_;
int64_t last_send_time_us_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DelayFilter);
};
class JitterFilter : public PacketProcessor {
public:
explicit JitterFilter(PacketProcessorListener* listener);
virtual ~JitterFilter() {}
void SetJitter(int64_t stddev_jitter_ms);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
Random random_;
int64_t stddev_jitter_us_;
int64_t last_send_time_us_;
DISALLOW_IMPLICIT_CONSTRUCTORS(JitterFilter);
};
class ReorderFilter : public PacketProcessor {
public:
explicit ReorderFilter(PacketProcessorListener* listener);
virtual ~ReorderFilter() {}
void SetReorder(float reorder_percent);
virtual void RunFor(int64_t time_ms, Packets* in_out);
private:
Random random_;
float reorder_fraction_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ReorderFilter);
};
// Apply a bitrate choke with an infinite queue on the packet stream.
class ChokeFilter : public PacketProcessor {
public:
explicit ChokeFilter(PacketProcessorListener* listener);
ChokeFilter(PacketProcessorListener* listener, const FlowIds& flow_ids);
virtual ~ChokeFilter();
void SetCapacity(uint32_t kbps);
void SetMaxDelay(int max_delay_ms);
virtual void RunFor(int64_t time_ms, Packets* in_out);
Stats<double> GetDelayStats() const;
private:
uint32_t kbps_;
int64_t last_send_time_us_;
scoped_ptr<DelayCapHelper> delay_cap_helper_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ChokeFilter);
};
class TraceBasedDeliveryFilter : public PacketProcessor {
public:
explicit TraceBasedDeliveryFilter(PacketProcessorListener* listener);
TraceBasedDeliveryFilter(PacketProcessorListener* listener,
const std::string& name);
virtual ~TraceBasedDeliveryFilter();
// The file should contain nanosecond timestamps corresponding to the time
// when the network can accept another packet. The timestamps should be
// separated by new lines, e.g., "100000000\n125000000\n321000000\n..."
bool Init(const std::string& filename);
virtual void Plot(int64_t timestamp_ms);
virtual void RunFor(int64_t time_ms, Packets* in_out);
void SetMaxDelay(int max_delay_ms);
Stats<double> GetDelayStats() const;
Stats<double> GetBitrateStats() const;
private:
void ProceedToNextSlot();
typedef std::vector<int64_t> TimeList;
int64_t current_offset_us_;
TimeList delivery_times_us_;
TimeList::const_iterator next_delivery_it_;
int64_t local_time_us_;
scoped_ptr<RateCounter> rate_counter_;
std::string name_;
scoped_ptr<DelayCapHelper> delay_cap_helper_;
Stats<double> packets_per_second_stats_;
Stats<double> kbps_stats_;
DISALLOW_COPY_AND_ASSIGN(TraceBasedDeliveryFilter);
};
class PacketSender : public PacketProcessor {
public:
struct Feedback {
uint32_t estimated_bps;
};
explicit PacketSender(PacketProcessorListener* listener);
PacketSender(PacketProcessorListener* listener, const FlowIds& flow_ids);
virtual ~PacketSender() {}
virtual uint32_t GetCapacityKbps() const { return 0; }
// 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 { return 1000; }
virtual void GiveFeedback(const Feedback& feedback) {}
private:
DISALLOW_COPY_AND_ASSIGN(PacketSender);
};
class VideoSender : public PacketSender {
public:
VideoSender(int flow_id,
PacketProcessorListener* listener,
float fps,
uint32_t kbps,
uint32_t ssrc,
float first_frame_offset);
virtual ~VideoSender() {}
uint32_t max_payload_size_bytes() const { return kMaxPayloadSizeBytes; }
uint32_t bytes_per_second() const { return bytes_per_second_; }
virtual uint32_t GetCapacityKbps() const OVERRIDE;
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
protected:
virtual uint32_t NextFrameSize();
virtual uint32_t NextPacketSize(uint32_t frame_size,
uint32_t remaining_payload);
const uint32_t kMaxPayloadSizeBytes;
const uint32_t kTimestampBase;
const double frame_period_ms_;
uint32_t bytes_per_second_;
uint32_t frame_size_bytes_;
private:
double next_frame_ms_;
double now_ms_;
RTPHeader prototype_header_;
DISALLOW_IMPLICIT_CONSTRUCTORS(VideoSender);
};
class AdaptiveVideoSender : public VideoSender {
public:
AdaptiveVideoSender(int flow_id, PacketProcessorListener* listener,
float fps, uint32_t kbps, uint32_t ssrc,
float first_frame_offset);
virtual ~AdaptiveVideoSender() {}
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
virtual void GiveFeedback(const Feedback& feedback) OVERRIDE;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AdaptiveVideoSender);
};
class PeriodicKeyFrameSender : public AdaptiveVideoSender {
public:
PeriodicKeyFrameSender(int flow_id,
PacketProcessorListener* listener,
float fps,
uint32_t kbps,
uint32_t ssrc,
float first_frame_offset,
int key_frame_interval);
virtual ~PeriodicKeyFrameSender() {}
protected:
virtual uint32_t NextFrameSize() OVERRIDE;
virtual uint32_t NextPacketSize(uint32_t frame_size,
uint32_t remaining_payload) OVERRIDE;
private:
int key_frame_interval_;
uint32_t frame_counter_;
int compensation_bytes_;
int compensation_per_frame_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSender);
};
class PacedVideoSender : public PacketSender, public PacedSender::Callback {
public:
PacedVideoSender(PacketProcessorListener* listener,
uint32_t kbps, AdaptiveVideoSender* source);
virtual ~PacedVideoSender() {}
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 PacedSender::Callback.
virtual bool TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
int64_t capture_time_ms,
bool retransmission) OVERRIDE;
virtual int TimeToSendPadding(int bytes) 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; }
};
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_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender);
};
} // namespace bwe
} // namespace testing
} // namespace webrtc
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_FRAMEWORK_H_