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
This commit is contained in:
stefan@webrtc.org 2015-02-16 12:02:20 +00:00
parent 0f7f161ed6
commit 14b0279416
15 changed files with 1142 additions and 909 deletions

View File

@ -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',

View File

@ -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;

View File

@ -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"

View File

@ -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 <algorithm>
#include <limits>
#include <string>
#include <vector>
#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<int64_t>::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<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> 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<unsigned int>& ssrcs,
unsigned int bitrate) OVERRIDE;
virtual int64_t TimeUntilNextProcess() OVERRIDE;
virtual int Process() OVERRIDE;
protected:
scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RemoteBitrateEstimator> rbe_;
scoped_ptr<RtcpBandwidthObserver> 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<const RembFeedback&>(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<const SendSideBweFeedback&>(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<unsigned int>& 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<double>(1 << kInterArrivalShift);
uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift;
return static_cast<int64_t>(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<PacketInfo> 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<int64_t>(estimator_->TimeUntilNextProcess(), 0);
while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) {
clock_.AdvanceTimeMilliseconds(step_ms);
estimator_->Process();
step_ms = std::max<int64_t>(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<double>(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<unsigned int>& 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<unsigned int> 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<ReceiveStatistics> recv_stats_;
int64_t latest_estimate_bps_;
scoped_ptr<RemoteBitrateEstimator> 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

View File

@ -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 <sstream>
#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_

View File

@ -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<double>(1 << kInterArrivalShift);
uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift;
return static_cast<int64_t>(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<PacketInfo> 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<int64_t>(estimator_->TimeUntilNextProcess(), 0);
while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) {
clock_.AdvanceTimeMilliseconds(step_ms);
estimator_->Process();
step_ms = std::max<int64_t>(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<double>(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<unsigned int>& 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<unsigned int> 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<ReceiveStatistics> recv_stats_;
int64_t latest_estimate_bps_;
scoped_ptr<RemoteBitrateEstimator> 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<Packet>);
}
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<const MediaPacket*>(*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<Packet>);
}
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<Packet>);
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<Packet>);
}
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<Packet>);
}
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<Packet>);
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<Packet>);
}
PacketProcessor* processor_;
Packets queue_;
};
BweTest::BweTest()
: run_time_ms_(0), time_now_ms_(-1), simulation_interval_ms_(-1) {
links_.push_back(&uplink_);

View File

@ -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 <map>
#include <string>
#include <vector>
@ -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<BweReceiver> 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_

View File

@ -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<const RembFeedback&>(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<const SendSideBweFeedback&>(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<unsigned int>& 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<FeedbackPacket*> feedbacks =
GetFeedbackPackets(in_out, now_ms + time_ms);
ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out);
}
void PacketSender::ProcessFeedbackAndGeneratePackets(
int64_t time_ms,
std::list<FeedbackPacket*>* feedbacks,
Packets* generated) {
do {
// Make sure to at least run Process() below every 100 ms.
int64_t time_to_run_ms = std::min<int64_t>(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<int64_t>(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<FeedbackPacket*> PacketSender::GetFeedbackPackets(
Packets* in_out,
int64_t end_time_ms) {
std::list<FeedbackPacket*> 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<FeedbackPacket*>(*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<FeedbackPacket*> 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<MediaPacket*>(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<Module*>& 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<Module*>& 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<Packet>);
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<Packet>);
}
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<MediaPacket*>(*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

View File

@ -15,7 +15,6 @@
#include <math.h>
#include <algorithm>
#include <limits>
#include <list>
#include <numeric>
#include <sstream>
@ -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<uint16_t, int64_t> ArrivalTimesMap;
SendSideBweFeedback(int flow_id,
int64_t send_time_us,
const std::vector<PacketInfo>& packet_feedback_vector);
virtual ~SendSideBweFeedback() {}
const std::vector<PacketInfo>& packet_feedback_vector() const {
return packet_feedback_vector_;
}
private:
const std::vector<PacketInfo> packet_feedback_vector_;
};
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;
@ -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<int64_t>::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<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> 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<unsigned int>& ssrcs,
unsigned int bitrate) OVERRIDE;
virtual int64_t TimeUntilNextProcess() OVERRIDE;
virtual int Process() OVERRIDE;
protected:
scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RemoteBitrateEstimator> rbe_;
scoped_ptr<RtcpBandwidthObserver> 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<FeedbackPacket*>* feedbacks,
Packets* generated);
std::list<FeedbackPacket*> GetFeedbackPackets(Packets* in_out,
int64_t end_time_ms);
SimulatedClock clock_;
VideoSource* source_;
scoped_ptr<SendSideBwe> bwe_;
int64_t start_of_run_ms_;
std::list<Module*> 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<Module*>& modules);
void CallProcess(const std::list<Module*>& 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

View File

@ -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;

View File

@ -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 <list>
#include <map>
#include <vector>
#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<uint16_t, int64_t> ArrivalTimesMap;
SendSideBweFeedback(int flow_id,
int64_t send_time_us,
const std::vector<PacketInfo>& packet_feedback_vector);
virtual ~SendSideBweFeedback() {}
const std::vector<PacketInfo>& packet_feedback_vector() const {
return packet_feedback_vector_;
}
private:
const std::vector<PacketInfo> packet_feedback_vector_;
};
typedef std::list<Packet*> Packets;
typedef std::list<Packet*>::iterator PacketsIt;
typedef std::list<Packet*>::const_iterator PacketsConstIt;
} // namespace bwe
} // namespace testing
} // namespace webrtc
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_

View File

@ -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 <vector>
#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<const MediaPacket*>(*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<Packet>);
}
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

View File

@ -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 <string>
#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<BweReceiver> bwe_receiver_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
};
} // namespace bwe
} // namespace testing
} // namespace webrtc
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_

View File

@ -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 <algorithm>
#include <list>
#include <sstream>
#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<FeedbackPacket*> feedbacks =
GetFeedbackPackets(in_out, now_ms + time_ms);
ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out);
}
void PacketSender::ProcessFeedbackAndGeneratePackets(
int64_t time_ms,
std::list<FeedbackPacket*>* feedbacks,
Packets* generated) {
do {
// Make sure to at least run Process() below every 100 ms.
int64_t time_to_run_ms = std::min<int64_t>(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<int64_t>(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<FeedbackPacket*> PacketSender::GetFeedbackPackets(
Packets* in_out,
int64_t end_time_ms) {
std::list<FeedbackPacket*> 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<FeedbackPacket*>(*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<FeedbackPacket*> 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<MediaPacket*>(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<Module*>& 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<Module*>& 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<Packet>);
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<Packet>);
}
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<MediaPacket*>(*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

View File

@ -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 <list>
#include <string>
#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<FeedbackPacket*>* feedbacks,
Packets* generated);
std::list<FeedbackPacket*> GetFeedbackPackets(Packets* in_out,
int64_t end_time_ms);
SimulatedClock clock_;
VideoSource* source_;
scoped_ptr<SendSideBwe> bwe_;
int64_t start_of_run_ms_;
std::list<Module*> 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<Module*>& modules);
void CallProcess(const std::list<Module*>& 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_