#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
+#include <cstdio>
+#include <sstream>
+
namespace webrtc {
namespace testing {
namespace bwe {
+class RateCounter {
+ public:
+ RateCounter()
+ : kWindowSizeUs(1000000),
+ packets_per_second_(0),
+ bytes_per_second_(0),
+ last_accumulated_us_(0),
+ window_() {}
+
+ void UpdateRates(int64_t send_time_us, uint32_t payload_size) {
+ packets_per_second_++;
+ bytes_per_second_ += payload_size;
+ last_accumulated_us_ = send_time_us;
+ window_.push_back(std::make_pair(send_time_us, payload_size));
+ while (!window_.empty()) {
+ const TimeSizePair& packet = window_.front();
+ if (packet.first > (last_accumulated_us_ - kWindowSizeUs)) {
+ break;
+ }
+ assert(packets_per_second_ >= 1);
+ assert(bytes_per_second_ >= packet.second);
+ packets_per_second_--;
+ bytes_per_second_ -= packet.second;
+ window_.pop_front();
+ }
+ }
+
+ uint32_t bits_per_second() const {
+ return bytes_per_second_ * 8;
+ }
+ uint32_t packets_per_second() const { return packets_per_second_; }
+
+ private:
+ typedef std::pair<int64_t, uint32_t> TimeSizePair;
+
+ const int64_t kWindowSizeUs;
+ uint32_t packets_per_second_;
+ uint32_t bytes_per_second_;
+ int64_t last_accumulated_us_;
+ std::list<TimeSizePair> window_;
+};
+
Random::Random(uint32_t seed)
: a_(0x531FDB97 ^ seed),
b_(0x6420ECA8 + seed) {
}
Packet::Packet()
- : send_time_us_(0),
+ : creation_time_us_(-1),
+ send_time_us_(-1),
payload_size_(0) {
memset(&header_, 0, sizeof(header_));
}
Packet::Packet(int64_t send_time_us, uint32_t payload_size,
- const RTPHeader& header)
- : send_time_us_(send_time_us),
+ const RTPHeader& header)
+ : creation_time_us_(send_time_us),
+ send_time_us_(send_time_us),
payload_size_(payload_size),
header_(header) {
}
Packet::Packet(int64_t send_time_us, uint32_t sequence_number)
- : send_time_us_(send_time_us),
+ : creation_time_us_(send_time_us),
+ send_time_us_(send_time_us),
payload_size_(0) {
memset(&header_, 0, sizeof(header_));
header_.sequenceNumber = sequence_number;
RateCounterFilter::RateCounterFilter(PacketProcessorListener* listener)
: PacketProcessor(listener),
- kWindowSizeUs(1000000),
- packets_per_second_(0),
- bytes_per_second_(0),
- last_accumulated_us_(0),
- window_(),
+ rate_counter_(new RateCounter()),
pps_stats_(),
- kbps_stats_() {
-}
+ kbps_stats_(),
+ name_("") {}
+
+RateCounterFilter::RateCounterFilter(PacketProcessorListener* listener,
+ const std::string& name)
+ : PacketProcessor(listener),
+ rate_counter_(new RateCounter()),
+ pps_stats_(),
+ kbps_stats_(),
+ name_(name) {}
RateCounterFilter::~RateCounterFilter() {
LogStats();
}
+uint32_t RateCounterFilter::packets_per_second() const {
+ return rate_counter_->packets_per_second();
+}
+
+uint32_t RateCounterFilter::bits_per_second() const {
+ return rate_counter_->bits_per_second();
+}
+
void RateCounterFilter::LogStats() {
BWE_TEST_LOGGING_CONTEXT("RateCounterFilter");
pps_stats_.Log("pps");
kbps_stats_.Log("kbps");
}
+void RateCounterFilter::Plot(int64_t timestamp_ms) {
+ BWE_TEST_LOGGING_CONTEXT(name_.c_str());
+ BWE_TEST_LOGGING_PLOT("Throughput_#1", timestamp_ms,
+ rate_counter_->bits_per_second() / 1000.0);
+}
+
void RateCounterFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
assert(in_out);
for (PacketsConstIt it = in_out->begin(); it != in_out->end(); ++it) {
- packets_per_second_++;
- bytes_per_second_ += it->payload_size();
- last_accumulated_us_ = it->send_time_us();
- }
- window_.insert(window_.end(), in_out->begin(), in_out->end());
- while (!window_.empty()) {
- const Packet& packet = window_.front();
- if (packet.send_time_us() > (last_accumulated_us_ - kWindowSizeUs)) {
- break;
- }
- assert(packets_per_second_ >= 1);
- assert(bytes_per_second_ >= packet.payload_size());
- packets_per_second_--;
- bytes_per_second_ -= packet.payload_size();
- window_.pop_front();
+ rate_counter_->UpdateRates(it->send_time_us(), it->payload_size());
}
- pps_stats_.Push(packets_per_second_);
- kbps_stats_.Push((bytes_per_second_ * 8) / 1000.0);
+ pps_stats_.Push(rate_counter_->packets_per_second());
+ kbps_stats_.Push(rate_counter_->bits_per_second() / 1000.0);
}
LossFilter::LossFilter(PacketProcessorListener* listener)
}
}
+TraceBasedDeliveryFilter::TraceBasedDeliveryFilter(
+ PacketProcessorListener* listener)
+ : PacketProcessor(listener),
+ delivery_times_us_(),
+ next_delivery_it_(),
+ local_time_us_(-1),
+ rate_counter_(new RateCounter),
+ name_("") {}
+
+TraceBasedDeliveryFilter::TraceBasedDeliveryFilter(
+ PacketProcessorListener* listener,
+ const std::string& name)
+ : PacketProcessor(listener),
+ delivery_times_us_(),
+ next_delivery_it_(),
+ local_time_us_(-1),
+ rate_counter_(new RateCounter),
+ name_(name) {}
+
+TraceBasedDeliveryFilter::~TraceBasedDeliveryFilter() {
+}
+
+bool TraceBasedDeliveryFilter::Init(const std::string& filename) {
+ FILE* trace_file = fopen(filename.c_str(), "r");
+ if (!trace_file) {
+ return false;
+ }
+ int64_t first_timestamp = -1;
+ while(!feof(trace_file)) {
+ const size_t kMaxLineLength = 100;
+ char line[kMaxLineLength];
+ if (fgets(line, kMaxLineLength, trace_file)) {
+ std::string line_string(line);
+ std::istringstream buffer(line_string);
+ int64_t timestamp;
+ buffer >> timestamp;
+ timestamp /= 1000; // Convert to microseconds.
+ if (first_timestamp == -1)
+ first_timestamp = timestamp;
+ assert(delivery_times_us_.empty() ||
+ timestamp - first_timestamp - delivery_times_us_.back() >= 0);
+ delivery_times_us_.push_back(timestamp - first_timestamp);
+ }
+ }
+ assert(!delivery_times_us_.empty());
+ next_delivery_it_ = delivery_times_us_.begin();
+ fclose(trace_file);
+ return true;
+}
+
+void TraceBasedDeliveryFilter::Plot(int64_t timestamp_ms) {
+ BWE_TEST_LOGGING_CONTEXT(name_.c_str());
+ // This plots the max possible throughput of the trace-based delivery filter,
+ // which will be reached if a packet sent on every packet slot of the trace.
+ BWE_TEST_LOGGING_PLOT("MaxThroughput_#1", timestamp_ms,
+ rate_counter_->bits_per_second() / 1000.0);
+}
+
+void TraceBasedDeliveryFilter::RunFor(int64_t time_ms, Packets* in_out) {
+ assert(in_out);
+ for (PacketsIt it = in_out->begin(); it != in_out->end(); ++it) {
+ do {
+ ProceedToNextSlot();
+ const int kPayloadSize = 1240;
+ rate_counter_->UpdateRates(local_time_us_, kPayloadSize);
+ } while (local_time_us_ < it->send_time_us());
+ it->set_send_time_us(local_time_us_);
+ }
+}
+
+void TraceBasedDeliveryFilter::ProceedToNextSlot() {
+ if (*next_delivery_it_ <= local_time_us_) {
+ ++next_delivery_it_;
+ if (next_delivery_it_ == delivery_times_us_.end()) {
+ // When the trace wraps we allow two packets to be sent back-to-back.
+ for (TimeList::iterator it = delivery_times_us_.begin();
+ it != delivery_times_us_.end(); ++it) {
+ *it += local_time_us_;
+ }
+ next_delivery_it_ = delivery_times_us_.begin();
+ }
+ }
+ local_time_us_ = *next_delivery_it_;
+}
+
PacketSender::PacketSender(PacketProcessorListener* listener)
: PacketProcessor(listener) {
}
kMaxPayloadSizeBytes(1000),
kTimestampBase(0xff80ff00ul),
frame_period_ms_(1000.0 / fps),
- next_frame_ms_(frame_period_ms_ * first_frame_offset),
- now_ms_(0.0),
bytes_per_second_((1000 * kbps) / 8),
frame_size_bytes_(bytes_per_second_ / fps),
+ next_frame_ms_(frame_period_ms_ * first_frame_offset),
+ now_ms_(0.0),
prototype_header_() {
assert(first_frame_offset >= 0.0f);
assert(first_frame_offset < 1.0f);
}
in_out->merge(newPackets);
}
+
+AdaptiveVideoSender::AdaptiveVideoSender(PacketProcessorListener* listener,
+ float fps,
+ uint32_t kbps,
+ uint32_t ssrc,
+ float first_frame_offset)
+ : VideoSender(listener, fps, kbps, ssrc, first_frame_offset) {}
+
+void AdaptiveVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
+ bytes_per_second_ = feedback.estimated_bps / 8;
+ frame_size_bytes_ = (bytes_per_second_ * frame_period_ms_ + 500) / 1000;
+}
} // namespace bwe
} // namespace testing
} // namespace webrtc