Wire up new feedback format by introducing a FeedbackPacket type.

The new format instantiates the RemoteBitrateEstimator at the send-side and feeds back all packet arrival timestamps and sequence numbers to the sender, where inter-arrival deltas are calculated.

Next step will be to make feedback packets part of regular packets and send them over the network. This also requires bi-directional simulations.

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

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

Cr-Commit-Position: refs/heads/master@{#8264}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8264 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2015-02-06 12:20:33 +00:00
parent 353c8b8c08
commit fb609a1f57
9 changed files with 699 additions and 323 deletions

View File

@ -25,7 +25,8 @@ BweTestConfig::EstimatorConfig CreateEstimatorConfig(
AbsoluteSendTimeRemoteBitrateEstimatorFactory();
return BweTestConfig::EstimatorConfig("AST", flow_id, &factory, kAimdControl,
plot_delay, plot_estimate);
kRembEstimator, plot_delay,
plot_estimate);
}
BweTestConfig MakeAdaptiveBweTestConfig() {
@ -65,7 +66,7 @@ INSTANTIATE_TEST_CASE_P(VideoSendersTest, BweSimulation,
TEST_P(BweSimulation, SprintUplinkTest) {
VerboseLogging(true);
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
RateCounterFilter counter2(this, "receiver_input");
@ -76,7 +77,7 @@ TEST_P(BweSimulation, SprintUplinkTest) {
TEST_P(BweSimulation, Verizon4gDownlinkTest) {
VerboseLogging(true);
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
RateCounterFilter counter2(this, "receiver_input");
@ -87,7 +88,7 @@ TEST_P(BweSimulation, Verizon4gDownlinkTest) {
TEST_P(BweSimulation, Choke1000kbps500kbps1000kbps) {
VerboseLogging(true);
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
filter.SetCapacity(1000);
@ -102,7 +103,7 @@ TEST_P(BweSimulation, Choke1000kbps500kbps1000kbps) {
TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) {
VerboseLogging(true);
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
PacedVideoSender sender(this, &source, 300);
PacedVideoSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
filter.SetCapacity(1000);
@ -117,7 +118,7 @@ TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) {
TEST_P(BweSimulation, PacerChoke10000kbps) {
VerboseLogging(true);
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
PacedVideoSender sender(this, &source, 300);
PacedVideoSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
filter.SetCapacity(10000);
@ -128,7 +129,7 @@ TEST_P(BweSimulation, PacerChoke10000kbps) {
TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) {
VerboseLogging(true);
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
PacedVideoSender sender(this, &source, 300);
PacedVideoSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
filter.SetCapacity(200);
@ -143,7 +144,7 @@ TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) {
TEST_P(BweSimulation, Choke200kbps30kbps200kbps) {
VerboseLogging(true);
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
filter.SetCapacity(200);
@ -158,7 +159,7 @@ TEST_P(BweSimulation, Choke200kbps30kbps200kbps) {
TEST_P(BweSimulation, GoogleWifiTrace3Mbps) {
VerboseLogging(true);
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
filter.SetMaxDelay(500);
@ -170,7 +171,7 @@ TEST_P(BweSimulation, GoogleWifiTrace3Mbps) {
TEST_P(BweSimulation, PacerGoogleWifiTrace3Mbps) {
VerboseLogging(true);
PeriodicKeyFrameSource source(0, 30, 300, 0, 0, 1000);
PacedVideoSender sender(this, &source, 300);
PacedVideoSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
filter.SetMaxDelay(500);
@ -196,13 +197,13 @@ TEST_P(MultiFlowBweSimulation, SelfFairnessTest) {
const int kAllFlowIds[] = {0, 1, 2};
const size_t kNumFlows = sizeof(kAllFlowIds) / sizeof(kAllFlowIds[0]);
scoped_ptr<AdaptiveVideoSource> sources[kNumFlows];
scoped_ptr<RegularVideoSender> senders[kNumFlows];
scoped_ptr<PacketSender> senders[kNumFlows];
for (size_t i = 0; i < kNumFlows; ++i) {
// Streams started 20 seconds apart to give them different advantage when
// competing for the bandwidth.
sources[i].reset(
new AdaptiveVideoSource(kAllFlowIds[i], 30, 300, 0, i * 20000));
senders[i].reset(new RegularVideoSender(this, sources[i].get(), 300));
senders[i].reset(new PacketSender(this, sources[i].get(), kRembEstimator));
}
ChokeFilter choke(this, CreateFlowIds(kAllFlowIds, kNumFlows));
@ -232,7 +233,8 @@ TEST_P(MultiFlowBweSimulation, PacedSelfFairnessTest) {
// competing for the bandwidth.
sources[i].reset(new PeriodicKeyFrameSource(kAllFlowIds[i], 30, 300, 0,
i * 20000, 1000));
senders[i].reset(new PacedVideoSender(this, sources[i].get(), 300));
senders[i].reset(
new PacedVideoSender(this, sources[i].get(), kRembEstimator));
}
ChokeFilter choke(this, CreateFlowIds(kAllFlowIds, kNumFlows));

View File

@ -63,10 +63,37 @@ struct ReceiveBandwidthEstimatorStats {
std::vector<int64_t> recent_arrival_time_ms;
};
struct PacketInfo {
PacketInfo(int64_t arrival_time_ms,
int64_t send_time_ms,
uint16_t sequence_number,
size_t payload_size)
: arrival_time_ms(arrival_time_ms),
send_time_ms(send_time_ms),
sequence_number(sequence_number),
payload_size(payload_size) {}
// Time corresponding to when the packet was received. Timestamped with the
// receiver's clock.
int64_t arrival_time_ms;
// Time corresponding to when the packet was sent, timestamped with the
// sender's clock.
int64_t send_time_ms;
// Packet identifier, incremented with 1 for every packet generated by the
// sender.
uint16_t sequence_number;
// Size of the packet excluding RTP headers.
size_t payload_size;
};
class RemoteBitrateEstimator : public CallStatsObserver, public Module {
public:
virtual ~RemoteBitrateEstimator() {}
virtual void IncomingPacketFeedbackVector(
const std::vector<PacketInfo>& packet_feedback_vector) {
assert(false);
}
// Called for each incoming packet. Updates the incoming payload bitrate
// estimate and the over-use detector. If an over-use is detected the
// remote bitrate estimate will be updated. Note that |payload_size| is the

View File

@ -111,6 +111,9 @@ class RemoteBitrateEstimatorAbsSendTimeImpl : public RemoteBitrateEstimator {
uint32_t min_bitrate_bps);
virtual ~RemoteBitrateEstimatorAbsSendTimeImpl() {}
virtual void IncomingPacketFeedbackVector(
const std::vector<PacketInfo>& packet_feedback_vector) OVERRIDE;
virtual void IncomingPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header) OVERRIDE;
@ -129,7 +132,6 @@ class RemoteBitrateEstimatorAbsSendTimeImpl : public RemoteBitrateEstimator {
private:
typedef std::map<unsigned int, int64_t> Ssrcs;
static bool IsWithinClusterBounds(int send_delta_ms,
const Cluster& cluster_aggregate) {
if (cluster_aggregate.count == 0)
@ -150,6 +152,11 @@ class RemoteBitrateEstimatorAbsSendTimeImpl : public RemoteBitrateEstimator {
return static_cast<int>(reinterpret_cast<uint64_t>(this));
}
void IncomingPacketInfo(int64_t arrival_time_ms,
uint32_t send_time_24bits,
size_t payload_size,
uint32_t ssrc);
bool IsProbe(int64_t send_time_ms, int payload_size) const
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get());
@ -322,6 +329,19 @@ bool RemoteBitrateEstimatorAbsSendTimeImpl::IsBitrateImproving(
return initial_probe || bitrate_above_estimate;
}
void RemoteBitrateEstimatorAbsSendTimeImpl::IncomingPacketFeedbackVector(
const std::vector<PacketInfo>& packet_feedback_vector) {
for (const auto& packet_info : packet_feedback_vector) {
// TODO(holmer): We should get rid of this conversion if possible as we may
// lose precision.
uint32_t send_time_32bits = (packet_info.send_time_ms) / kTimestampToMs;
uint32_t send_time_24bits =
send_time_32bits >> kAbsSendTimeInterArrivalUpshift;
IncomingPacketInfo(packet_info.arrival_time_ms, send_time_24bits,
packet_info.payload_size, 0);
}
}
void RemoteBitrateEstimatorAbsSendTimeImpl::IncomingPacket(
int64_t arrival_time_ms,
size_t payload_size,
@ -330,27 +350,38 @@ void RemoteBitrateEstimatorAbsSendTimeImpl::IncomingPacket(
LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTimeImpl: Incoming packet "
"is missing absolute send time extension!";
}
uint32_t absolute_send_time = header.extension.absoluteSendTime;
assert(absolute_send_time < (1ul << 24));
int64_t now_ms = clock_->TimeInMilliseconds();
IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime,
payload_size, header.ssrc);
}
void RemoteBitrateEstimatorAbsSendTimeImpl::IncomingPacketInfo(
int64_t arrival_time_ms,
uint32_t send_time_24bits,
size_t payload_size,
uint32_t ssrc) {
assert(send_time_24bits < (1ul << 24));
// Shift up send time to use the full 32 bits that inter_arrival works with,
// so wrapping works properly.
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
int64_t send_time_ms = static_cast<int64_t>(timestamp) * kTimestampToMs;
CriticalSectionScoped cs(crit_sect_.get());
ssrcs_[header.ssrc] = now_ms;
int64_t now_ms = clock_->TimeInMilliseconds();
// TODO(holmer): SSRCs are only needed for REMB, should be broken out from
// here.
ssrcs_[ssrc] = now_ms;
incoming_bitrate_.Update(payload_size, now_ms);
const BandwidthUsage prior_state = detector_.State();
if (first_packet_time_ms_ == -1)
first_packet_time_ms_ = clock_->TimeInMilliseconds();
// Shift up send time to use the full 32 bits that inter_arrival works with,
// so wrapping works properly.
uint32_t timestamp = absolute_send_time << kAbsSendTimeInterArrivalUpshift;
uint32_t ts_delta = 0;
int64_t t_delta = 0;
int size_delta = 0;
// For now only try to detect probes while we don't have a valid estimate.
if (!remote_rate_->ValidEstimate() ||
now_ms - first_packet_time_ms_ < kInitialProbingIntervalMs) {
int64_t send_time_ms = static_cast<int64_t>(timestamp) * kTimestampToMs;
// TODO(holmer): Use a map instead to get correct order?
if (total_probes_received_ < kMaxProbePackets) {
int send_delta_ms = -1;
@ -370,15 +401,11 @@ void RemoteBitrateEstimatorAbsSendTimeImpl::IncomingPacket(
}
if (!inter_arrival_.get()) {
inter_arrival_.reset(new InterArrival(
(kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
kTimestampToMs, remote_rate_->GetControlType() == kAimdControl));
(kTimestampGroupLengthMs << kInterArrivalShift) / 1000, kTimestampToMs,
remote_rate_->GetControlType() == kAimdControl));
}
if (inter_arrival_->ComputeDeltas(timestamp,
arrival_time_ms,
payload_size,
&ts_delta,
&t_delta,
&size_delta)) {
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size,
&ts_delta, &t_delta, &size_delta)) {
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
estimator_.Update(t_delta, ts_delta_ms, size_delta, detector_.State());
detector_.Detect(estimator_.offset(), ts_delta_ms,

View File

@ -31,10 +31,12 @@ BweTestConfig::EstimatorConfig EstimatorConfigs(Estimator estimator,
switch (estimator) {
case kTransmissionOffset:
return BweTestConfig::EstimatorConfig("TOF", flow_id, &factories[0],
kMimdControl, false, false);
kAimdControl, kRembEstimator, false,
false);
case kAbsSendTime:
return BweTestConfig::EstimatorConfig("AST", flow_id, &factories[1],
kMimdControl, false, false);
kAimdControl, kRembEstimator, false,
false);
}
assert(false);
return BweTestConfig::EstimatorConfig();
@ -64,7 +66,8 @@ class DefaultBweTest : public BweTest,
SetupTestFromConfig(config.bwe_test_config);
for (size_t i = 0; i < config.number_of_senders; ++i) {
sources_.push_back(new VideoSource(0, 30, 300, 0, 0));
packet_senders_.push_back(new PacketSender(this, sources_.back()));
packet_senders_.push_back(
new PacketSender(this, sources_.back(), kNullEstimator));
}
}
@ -283,7 +286,7 @@ class BweFeedbackTest : public BweTest,
TEST_F(BweFeedbackTest, Choke1000kbps500kbps1000kbps) {
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
const int kHighCapacityKbps = 1000;
@ -301,7 +304,7 @@ TEST_F(BweFeedbackTest, Choke1000kbps500kbps1000kbps) {
TEST_F(BweFeedbackTest, Choke200kbps30kbps200kbps) {
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
ChokeFilter filter(this);
RateCounterFilter counter(this, "receiver_input");
const int kHighCapacityKbps = 200;
@ -320,7 +323,7 @@ TEST_F(BweFeedbackTest, Choke200kbps30kbps200kbps) {
TEST_F(BweFeedbackTest, Verizon4gDownlinkTest) {
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
RateCounterFilter counter2(this, "receiver_input");
@ -333,7 +336,7 @@ TEST_F(BweFeedbackTest, Verizon4gDownlinkTest) {
// webrtc:3277
TEST_F(BweFeedbackTest, DISABLED_GoogleWifiTrace3Mbps) {
AdaptiveVideoSource source(0, 30, 300, 0, 0);
RegularVideoSender sender(this, &source, 300);
PacketSender sender(this, &source, kRembEstimator);
RateCounterFilter counter1(this, "sender_output");
TraceBasedDeliveryFilter filter(this, "link_capacity");
filter.SetMaxDelay(500);

View File

@ -26,36 +26,110 @@ namespace webrtc {
namespace testing {
namespace bwe {
class PacketReceiver : public RemoteBitrateObserver {
class PacketReceiver {
public:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
static const int kDelayPlotIntervalMs = 100;
PacketReceiver(const string& test_name,
const BweTestConfig::EstimatorConfig& config)
: debug_name_(config.debug_name),
: flow_id_(config.flow_id),
debug_name_(config.debug_name),
delay_log_prefix_(),
estimate_log_prefix_(),
last_delay_plot_ms_(0),
plot_delay_(config.plot_delay),
baseline_(BaseLineFileInterface::Create(test_name + "_" + debug_name_,
config.update_baseline)) {
// Setup the prefix strings used when logging.
std::stringstream ss;
ss << "Delay_" << config.flow_id << "#2";
delay_log_prefix_ = ss.str();
}
virtual ~PacketReceiver() {}
virtual void ReceivePacket(const Packet& packet) {}
virtual FeedbackPacket* GetFeedback() { return NULL; }
void LogStats() {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
BWE_TEST_LOGGING_CONTEXT("Mean");
stats_.Log("kbps");
}
void VerifyOrWriteBaseline() { EXPECT_TRUE(baseline_->VerifyOrWrite()); }
protected:
static const int kDelayPlotIntervalMs = 100;
void LogDelay(int64_t arrival_time_ms, int64_t send_time_ms) {
if (plot_delay_) {
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;
}
}
}
const int flow_id_;
const string debug_name_;
string delay_log_prefix_;
int64_t last_delay_plot_ms_;
bool plot_delay_;
scoped_ptr<BaseLineFileInterface> baseline_;
Stats<double> stats_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
};
class SendSideBweReceiver : public PacketReceiver {
public:
SendSideBweReceiver(const string& test_name,
const BweTestConfig::EstimatorConfig& config)
: PacketReceiver(test_name, config) {}
virtual void EatPacket(const Packet& packet) {
const MediaPacket& media_packet = static_cast<const MediaPacket&>(packet);
// 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);
LogDelay(arrival_time_ms, (media_packet.creation_time_us() + 500) / 1000);
packet_feedback_vector_.push_back(PacketInfo(
arrival_time_ms, media_packet.GetAbsSendTimeInMs(),
media_packet.header().sequenceNumber, media_packet.payload_size()));
}
virtual FeedbackPacket* GetFeedback() {
FeedbackPacket* fb =
new SendSideBweFeedback(flow_id_, 0, packet_feedback_vector_);
packet_feedback_vector_.clear();
return fb;
}
private:
std::vector<PacketInfo> packet_feedback_vector_;
};
class RembReceiver : public PacketReceiver, public RemoteBitrateObserver {
public:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
RembReceiver(const string& test_name,
const BweTestConfig::EstimatorConfig& config)
: PacketReceiver(test_name, config),
estimate_log_prefix_(),
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,
kRemoteBitrateEstimatorMinBitrateBps)),
baseline_(BaseLineFileInterface::Create(test_name + "_" + debug_name_,
config.update_baseline)) {
kRemoteBitrateEstimatorMinBitrateBps)) {
assert(estimator_.get());
assert(baseline_.get());
// Setup the prefix strings used when logging.
std::stringstream ss;
ss << "Delay_" << config.flow_id << "#2";
delay_log_prefix_ = ss.str();
ss.str("");
ss << "Estimate_" << config.flow_id << "#1";
estimate_log_prefix_ = ss.str();
@ -63,53 +137,45 @@ class PacketReceiver : public RemoteBitrateObserver {
estimator_->OnRttUpdate(50);
}
void EatPacket(const Packet& packet) {
virtual void ReceivePacket(const Packet& packet) {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
recv_stats_->IncomingPacket(packet.header(), packet.payload_size(), false);
assert(packet.GetPacketType() == Packet::kMediaPacket);
const MediaPacket& media_packet = static_cast<const MediaPacket&>(packet);
// 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);
LogDelay(arrival_time_ms, (media_packet.creation_time_us() + 500) / 1000);
recv_stats_->IncomingPacket(media_packet.header(),
media_packet.payload_size(), false);
latest_estimate_bps_ = -1;
// We're treating the send time (from previous filter) as the arrival
// time once packet reaches the estimator.
int64_t packet_time_ms = (packet.send_time_us() + 500) / 1000;
BWE_TEST_LOGGING_TIME(packet_time_ms);
if (plot_delay_) {
if (clock_.TimeInMilliseconds() - last_delay_plot_ms_ >
kDelayPlotIntervalMs) {
BWE_TEST_LOGGING_PLOT(delay_log_prefix_, clock_.TimeInMilliseconds(),
packet_time_ms -
(packet.creation_time_us() + 500) / 1000);
last_delay_plot_ms_ = clock_.TimeInMilliseconds();
}
}
int64_t step_ms = std::max<int64_t>(estimator_->TimeUntilNextProcess(), 0);
while ((clock_.TimeInMilliseconds() + step_ms) < packet_time_ms) {
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(packet_time_ms, packet.payload_size(),
packet.header());
clock_.AdvanceTimeMilliseconds(packet_time_ms -
estimator_->IncomingPacket(arrival_time_ms, media_packet.payload_size(),
media_packet.header());
clock_.AdvanceTimeMilliseconds(arrival_time_ms -
clock_.TimeInMilliseconds());
ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds());
ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds());
}
bool GetFeedback(PacketSender::Feedback* feedback) {
assert(feedback);
virtual FeedbackPacket* GetFeedback() {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
uint32_t estimated_bps = 0;
RembFeedback* feedback = NULL;
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);
RTCPReportBlock report_block;
if (!statisticians.empty()) {
report_block = BuildReportBlock(statisticians.begin()->second);
}
feedback = new RembFeedback(flow_id_, clock_.TimeInMilliseconds(),
estimated_bps, report_block);
baseline_->Estimate(clock_.TimeInMilliseconds(), estimated_bps);
double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
@ -118,19 +184,8 @@ class PacketReceiver : public RemoteBitrateObserver {
BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(),
estimated_kbps);
}
return true;
}
return false;
}
void LogStats() {
BWE_TEST_LOGGING_CONTEXT(debug_name_);
BWE_TEST_LOGGING_CONTEXT("Mean");
stats_.Log("kbps");
}
void VerifyOrWriteBaseline() {
EXPECT_TRUE(baseline_->VerifyOrWrite());
return feedback;
}
virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs,
@ -163,29 +218,39 @@ class PacketReceiver : public RemoteBitrateObserver {
return true;
}
string debug_name_;
string delay_log_prefix_;
string estimate_log_prefix_;
int64_t last_delay_plot_ms_;
bool plot_delay_;
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(PacketReceiver);
DISALLOW_IMPLICIT_CONSTRUCTORS(RembReceiver);
};
PacketReceiver* CreatePacketReceiver(
BandwidthEstimatorType type,
const string& test_name,
const BweTestConfig::EstimatorConfig& config) {
switch (type) {
case kRembEstimator:
return new RembReceiver(test_name, config);
case kFullSendSideEstimator:
return new SendSideBweReceiver(test_name, config);
case kNullEstimator:
return new PacketReceiver(test_name, config);
}
assert(false);
return NULL;
}
class PacketProcessorRunner {
public:
explicit PacketProcessorRunner(PacketProcessor* processor)
: processor_(processor) {}
~PacketProcessorRunner() {
for (auto* packet : queue_)
for (Packet* packet : queue_)
delete packet;
}
@ -253,16 +318,14 @@ BweTest::BweTest()
BweTest::~BweTest() {
BWE_TEST_LOGGING_GLOBAL_ENABLE(true);
for (EstimatorMap::iterator it = estimators_.begin(); it != estimators_.end();
++it) {
it->second->VerifyOrWriteBaseline();
it->second->LogStats();
for (const auto& estimator : estimators_) {
estimator.second->VerifyOrWriteBaseline();
estimator.second->LogStats();
}
BWE_TEST_LOGGING_GLOBAL_CONTEXT("");
for (EstimatorMap::iterator it = estimators_.begin();
it != estimators_.end(); ++it) {
delete it->second;
for (const auto& estimator : estimators_) {
delete estimator.second;
}
}
@ -272,11 +335,11 @@ void BweTest::SetupTestFromConfig(const BweTestConfig& config) {
string test_name =
string(test_info->test_case_name()) + "_" + string(test_info->name());
BWE_TEST_LOGGING_GLOBAL_CONTEXT(test_name);
for (vector<BweTestConfig::EstimatorConfig>::const_iterator it =
config.estimator_configs.begin(); it != config.estimator_configs.end();
++it) {
for (const auto& estimator_config : config.estimator_configs) {
estimators_.insert(
std::make_pair(it->flow_id, new PacketReceiver(test_name, *it)));
std::make_pair(estimator_config.flow_id,
CreatePacketReceiver(estimator_config.bwe_type,
test_name, estimator_config)));
}
BWE_TEST_LOGGING_GLOBAL_ENABLE(false);
}
@ -287,7 +350,7 @@ void BweTest::AddPacketProcessor(PacketProcessor* processor, bool is_sender) {
senders_.push_back(static_cast<PacketSender*>(processor));
}
processors_.push_back(PacketProcessorRunner(processor));
for (const auto& flow_id : processor->flow_ids()) {
for (const int& flow_id : processor->flow_ids()) {
RTC_UNUSED(flow_id);
assert(estimators_.count(flow_id) == 1);
}
@ -308,22 +371,18 @@ void BweTest::VerboseLogging(bool enable) {
BWE_TEST_LOGGING_GLOBAL_ENABLE(enable);
}
void BweTest::GiveFeedbackToAffectedSenders(int flow_id,
PacketReceiver* estimator) {
std::list<PacketSender*> affected_senders;
for (auto* sender : senders_) {
if (sender->flow_ids().find(flow_id) != sender->flow_ids().end()) {
affected_senders.push_back(sender);
}
}
PacketSender::Feedback feedback = {0};
if (estimator->GetFeedback(&feedback) && !affected_senders.empty()) {
// Allocate the bitrate evenly between the senders.
feedback.estimated_bps /= affected_senders.size();
for (auto* sender : affected_senders) {
sender->GiveFeedback(feedback);
void BweTest::GiveFeedbackToAffectedSenders(PacketReceiver* estimator) {
FeedbackPacket* feedback = estimator->GetFeedback();
if (feedback) {
for (PacketSender* sender : senders_) {
if (sender->flow_ids().find(feedback->flow_id()) !=
sender->flow_ids().end()) {
sender->GiveFeedback(*feedback);
break;
}
}
}
delete feedback;
}
void BweTest::RunFor(int64_t time_ms) {
@ -340,7 +399,7 @@ void BweTest::RunFor(int64_t time_ms) {
time_now_ms_ <= run_time_ms_ - simulation_interval_ms_;
time_now_ms_ += simulation_interval_ms_) {
Packets packets;
for (auto& processor : processors_) {
for (PacketProcessorRunner& processor : processors_) {
processor.RunFor(simulation_interval_ms_, time_now_ms_, &packets);
}
@ -359,15 +418,15 @@ void BweTest::RunFor(int64_t time_ms) {
ASSERT_TRUE(IsTimeSorted(packets));
}
for (const auto* packet : packets) {
for (const Packet* packet : packets) {
EstimatorMap::iterator est_it = estimators_.find(packet->flow_id());
ASSERT_TRUE(est_it != estimators_.end());
est_it->second->EatPacket(*packet);
est_it->second->ReceivePacket(*packet);
delete packet;
}
for (const auto& estimator : estimators_) {
GiveFeedbackToAffectedSenders(estimator.first, estimator.second);
GiveFeedbackToAffectedSenders(estimator.second);
}
}
}

View File

@ -29,55 +29,59 @@ struct BweTestConfig {
: debug_name(),
flow_id(0),
estimator_factory(NULL),
control_type(kMimdControl),
control_type(kAimdControl),
bwe_type(kRembEstimator),
update_baseline(false),
plot_delay(true),
plot_estimate(true) {
}
plot_estimate(true) {}
EstimatorConfig(std::string debug_name,
int flow_id,
const RemoteBitrateEstimatorFactory* estimator_factory,
BandwidthEstimatorType estimator_type,
bool plot_delay,
bool plot_estimate)
: debug_name(debug_name),
flow_id(flow_id),
estimator_factory(estimator_factory),
control_type(kMimdControl),
control_type(kAimdControl),
bwe_type(kRembEstimator),
update_baseline(false),
plot_delay(plot_delay),
plot_estimate(plot_estimate) {
}
plot_estimate(plot_estimate) {}
EstimatorConfig(std::string debug_name,
int flow_id,
const RemoteBitrateEstimatorFactory* estimator_factory,
RateControlType control_type,
BandwidthEstimatorType estimator_type,
bool plot_delay,
bool plot_estimate)
: debug_name(debug_name),
flow_id(flow_id),
estimator_factory(estimator_factory),
control_type(control_type),
bwe_type(estimator_type),
update_baseline(false),
plot_delay(plot_delay),
plot_estimate(plot_estimate) {
}
plot_estimate(plot_estimate) {}
EstimatorConfig(std::string debug_name,
int flow_id,
const RemoteBitrateEstimatorFactory* estimator_factory,
RateControlType control_type,
BandwidthEstimatorType estimator_type,
bool update_baseline)
: debug_name(debug_name),
flow_id(flow_id),
estimator_factory(estimator_factory),
control_type(control_type),
bwe_type(kRembEstimator),
update_baseline(update_baseline),
plot_delay(false),
plot_estimate(false) {
}
plot_estimate(false) {}
std::string debug_name;
int flow_id;
const RemoteBitrateEstimatorFactory* estimator_factory;
RateControlType control_type;
BandwidthEstimatorType bwe_type;
bool update_baseline;
bool plot_delay;
bool plot_estimate;
@ -108,7 +112,7 @@ class BweTest : public PacketProcessorListener {
void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in,
Packets* out);
void GiveFeedbackToAffectedSenders(int flow_id, PacketReceiver* estimator);
void GiveFeedbackToAffectedSenders(PacketReceiver* estimator);
int64_t run_time_ms_;
int64_t time_now_ms_;

View File

@ -17,6 +17,10 @@
namespace webrtc {
namespace testing {
namespace bwe {
const int kMinBitrateKbps = 10;
const int kMaxBitrateKbps = 20000;
class DelayCapHelper {
public:
DelayCapHelper() : max_delay_us_(0), delay_stats_() {}
@ -120,29 +124,14 @@ int Random::Gaussian(int mean, int standard_deviation) {
}
Packet::Packet()
: flow_id_(0),
creation_time_us_(-1),
send_time_us_(-1),
payload_size_(0) {
memset(&header_, 0, sizeof(header_));
: flow_id_(0), creation_time_us_(-1), send_time_us_(-1), payload_size_(0) {
}
Packet::Packet(int flow_id, int64_t send_time_us, size_t payload_size,
const RTPHeader& header)
Packet::Packet(int flow_id, int64_t send_time_us, size_t payload_size)
: flow_id_(flow_id),
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)
: flow_id_(0),
creation_time_us_(send_time_us),
send_time_us_(send_time_us),
payload_size_(0) {
memset(&header_, 0, sizeof(header_));
header_.sequenceNumber = sequence_number;
payload_size_(payload_size) {
}
Packet::~Packet() {
@ -157,12 +146,56 @@ void Packet::set_send_time_us(int64_t send_time_us) {
send_time_us_ = send_time_us;
}
void Packet::SetAbsSendTimeMs(int64_t abs_send_time_ms) {
MediaPacket::MediaPacket() {
memset(&header_, 0, sizeof(header_));
}
MediaPacket::MediaPacket(int flow_id,
int64_t send_time_us,
size_t payload_size,
const RTPHeader& header)
: Packet(flow_id, send_time_us, payload_size), header_(header) {
}
MediaPacket::MediaPacket(int64_t send_time_us, uint32_t sequence_number)
: Packet(0, send_time_us, 0) {
memset(&header_, 0, sizeof(header_));
header_.sequenceNumber = sequence_number;
}
int64_t MediaPacket::GetAbsSendTimeInMs() const {
const int kInterArrivalShift = 26;
const int kAbsSendTimeInterArrivalUpshift = 8;
const double kTimestampToMs =
1000.0 / static_cast<double>(1 << kInterArrivalShift);
uint32_t timestamp = header_.extension.absoluteSendTime
<< kAbsSendTimeInterArrivalUpshift;
return static_cast<int64_t>(timestamp) * kTimestampToMs;
}
void MediaPacket::SetAbsSendTimeMs(int64_t abs_send_time_ms) {
header_.extension.hasAbsoluteSendTime = true;
header_.extension.absoluteSendTime = ((static_cast<int64_t>(abs_send_time_ms *
(1 << 18)) + 500) / 1000) & 0x00fffffful;
}
RembFeedback::RembFeedback(int flow_id,
int64_t send_time_us,
uint32_t estimated_bps,
RTCPReportBlock report_block)
: FeedbackPacket(flow_id, send_time_us),
estimated_bps_(estimated_bps),
report_block_(report_block) {
}
SendSideBweFeedback::SendSideBweFeedback(
int flow_id,
int64_t send_time_us,
const std::vector<PacketInfo>& packet_feedback_vector)
: FeedbackPacket(flow_id, send_time_us),
packet_feedback_vector_(packet_feedback_vector) {
}
bool IsTimeSorted(const Packets& packets) {
PacketsConstIt last_it = packets.begin();
for (PacketsConstIt it = last_it; it != packets.end(); ++it) {
@ -233,7 +266,7 @@ RateCounterFilter::RateCounterFilter(PacketProcessorListener* listener,
name_(name) {
std::stringstream ss;
ss << name_ << "_";
for (auto flow_id : flow_ids) {
for (int flow_id : flow_ids) {
ss << flow_id << ",";
}
name_ = ss.str();
@ -269,7 +302,7 @@ void RateCounterFilter::Plot(int64_t timestamp_ms) {
void RateCounterFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
assert(in_out);
for (const auto* packet : *in_out) {
for (const Packet* packet : *in_out) {
rate_counter_->UpdateRates(packet->send_time_us(), packet->payload_size());
}
packets_per_second_stats_.Push(rate_counter_->packets_per_second());
@ -317,7 +350,7 @@ void DelayFilter::SetDelay(int64_t delay_ms) {
void DelayFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
assert(in_out);
for (auto* packet : *in_out) {
for (Packet* packet : *in_out) {
int64_t new_send_time_us = packet->send_time_us() + delay_us_;
last_send_time_us_ = std::max(last_send_time_us_, new_send_time_us);
packet->set_send_time_us(last_send_time_us_);
@ -341,7 +374,7 @@ void JitterFilter::SetJitter(int64_t stddev_jitter_ms) {
void JitterFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
assert(in_out);
for (auto* packet : *in_out) {
for (Packet* packet : *in_out) {
int64_t new_send_time_us = packet->send_time_us();
new_send_time_us += random_.Gaussian(0, stddev_jitter_us_);
last_send_time_us_ = std::max(last_send_time_us_, new_send_time_us);
@ -372,7 +405,7 @@ void ReorderFilter::RunFor(int64_t /*time_ms*/, Packets* in_out) {
if (random_.Rand() < reorder_fraction_) {
int64_t t1 = (*last_it)->send_time_us();
int64_t t2 = (*it)->send_time_us();
std::swap(**last_it, **it);
std::swap(*last_it, *it);
(*last_it)->set_send_time_us(t1);
(*it)->set_send_time_us(t2);
}
@ -540,7 +573,7 @@ void TraceBasedDeliveryFilter::ProceedToNextSlot() {
++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 (auto& delivery_time_us : delivery_times_us_) {
for (int64_t& delivery_time_us : delivery_times_us_) {
delivery_time_us += local_time_us_ - current_offset_us_;
}
current_offset_us_ += local_time_us_ - current_offset_us_;
@ -600,9 +633,10 @@ void VideoSource::RunFor(int64_t time_ms, Packets* in_out) {
while (payload_size > 0) {
++prototype_header_.sequenceNumber;
uint32_t size = NextPacketSize(frame_size, payload_size);
new_packets.push_back(
new Packet(flow_id_, send_time_us, size, prototype_header_));
new_packets.back()->SetAbsSendTimeMs(next_frame_ms_);
MediaPacket* new_packet =
new MediaPacket(flow_id_, send_time_us, size, prototype_header_);
new_packets.push_back(new_packet);
new_packet->SetAbsSendTimeMs(next_frame_ms_);
payload_size -= size;
}
@ -672,60 +706,155 @@ uint32_t PeriodicKeyFrameSource::NextPacketSize(uint32_t frame_size,
return std::min(avg_size, remaining_payload);
}
PacketSender::PacketSender(PacketProcessorListener* listener,
VideoSource* source)
: PacketProcessor(listener, source->flow_id(), true), source_(source) {
}
void PacketSender::RunFor(int64_t time_ms, Packets* in_out) {
source_->RunFor(time_ms, in_out);
}
RegularVideoSender::RegularVideoSender(PacketProcessorListener* listener,
VideoSource* source,
uint32_t kbps)
// 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),
clock_(kInitialTimeMs),
bitrate_controller_(BitrateController::CreateBitrateController(&clock_,
false)),
RembSendSideBwe::RembSendSideBwe(int kbps,
BitrateObserver* observer,
Clock* clock)
: bitrate_controller_(
BitrateController::CreateBitrateController(clock, false)),
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
modules_() {
const int kMinBitrateBps = 10000;
const int kMaxBitrateBps = 20000000;
bitrate_controller_->SetBitrateObserver(this, 1000 * kbps, kMinBitrateBps,
kMaxBitrateBps);
modules_.push_back(bitrate_controller_.get());
clock_(clock) {
assert(kbps >= kMinBitrateKbps);
assert(kbps <= kMaxBitrateKbps);
bitrate_controller_->SetBitrateObserver(
observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps);
}
RegularVideoSender::~RegularVideoSender() {
RembSendSideBwe::~RembSendSideBwe() {
}
void RegularVideoSender::GiveFeedback(const Feedback& feedback) {
feedback_observer_->OnReceivedEstimatedBitrate(feedback.estimated_bps);
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(feedback.report_block);
feedback_observer_->OnReceivedRtcpReceiverReport(report_blocks, 0,
clock_.TimeInMilliseconds());
report_blocks.push_back(remb_feedback.report_block());
feedback_observer_->OnReceivedRtcpReceiverReport(
report_blocks, 0, clock_->TimeInMilliseconds());
bitrate_controller_->Process();
}
void RegularVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
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());
if (rbe_->TimeUntilNextProcess() <= 0)
rbe_->Process();
// 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;
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: {
static NullSendSideBwe null_bwe;
return &null_bwe;
}
}
assert(false);
return NULL;
}
PacketSender::PacketSender(PacketProcessorListener* listener,
VideoSource* source,
BandwidthEstimatorType estimator)
: PacketProcessor(listener, source->flow_id(), true),
// 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,
8 * source_->bytes_per_second() / 1000,
this,
&clock_)) {
modules_.push_back(bwe_.get());
}
PacketSender::~PacketSender() {
}
void PacketSender::RunFor(int64_t time_ms, Packets* in_out) {
start_of_run_ms_ = clock_.TimeInMilliseconds();
while (time_ms > 0) {
int64_t time_to_run_ms = std::min(time_ms, static_cast<int64_t>(100));
PacketSender::RunFor(time_to_run_ms, in_out);
source_->RunFor(time_to_run_ms, in_out);
clock_.AdvanceTimeMilliseconds(time_to_run_ms);
bitrate_controller_->Process();
bwe_->Process();
time_ms -= time_to_run_ms;
}
}
void RegularVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost,
int64_t rtt) {
int PacketSender::GetFeedbackIntervalMs() const {
return bwe_->GetFeedbackIntervalMs();
}
void PacketSender::GiveFeedback(const FeedbackPacket& feedback) {
bwe_->GiveFeedback(feedback);
}
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";
@ -735,23 +864,22 @@ void RegularVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
VideoSource* source,
uint32_t kbps)
// 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.
: RegularVideoSender(listener, source, kbps),
BandwidthEstimatorType estimator)
: PacketSender(listener, source, estimator),
pacer_(&clock_,
this,
kbps,
PacedSender::kDefaultPaceMultiplier* kbps,
8 * source->bytes_per_second() / 1000,
PacedSender::kDefaultPaceMultiplier * 8 *
source->bytes_per_second() /
1000,
0) {
modules_.push_back(&pacer_);
}
PacedVideoSender::~PacedVideoSender() {
for (auto* packet : pacer_queue_)
for (Packet* packet : pacer_queue_)
delete packet;
for (auto* packet : queue_)
for (Packet* packet : queue_)
delete packet;
}
@ -786,11 +914,13 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
CallProcess(modules_);
} else {
// Time to send next packet to pacer.
pacer_.SendPacket(PacedSender::kNormalPriority, (*it)->header().ssrc,
(*it)->header().sequenceNumber,
((*it)->send_time_us() + 500) / 1000,
(*it)->payload_size(), false);
pacer_queue_.push_back(*it);
MediaPacket* media_packet = static_cast<MediaPacket*>(*it);
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(media_packet);
assert(pacer_queue_.size() < 10000);
++it;
}
@ -801,7 +931,7 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
int64_t PacedVideoSender::TimeUntilNextProcess(
const std::list<Module*>& modules) {
int64_t time_until_next_process_ms = 10;
for (auto* module : modules) {
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;
@ -812,7 +942,7 @@ int64_t PacedVideoSender::TimeUntilNextProcess(
}
void PacedVideoSender::CallProcess(const std::list<Module*>& modules) {
for (auto* module : modules) {
for (Module* module : modules) {
if (module->TimeUntilNextProcess() <= 0) {
module->Process();
}
@ -842,14 +972,15 @@ bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
bool retransmission) {
for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end();
++it) {
if ((*it)->header().sequenceNumber == sequence_number) {
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 >= ((*it)->send_time_us() + 500) / 1000);
(*it)->SetAbsSendTimeMs(pace_out_time_ms);
(*it)->set_send_time_us(1000 * pace_out_time_ms);
queue_.push_back(*it);
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;
}
@ -864,7 +995,7 @@ size_t PacedVideoSender::TimeToSendPadding(size_t bytes) {
void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost,
int64_t rtt) {
RegularVideoSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
PacketSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
pacer_.UpdateBitrate(
target_bitrate_bps / 1000,
PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, 0);

View File

@ -15,6 +15,7 @@
#include <math.h>
#include <algorithm>
#include <limits>
#include <list>
#include <numeric>
#include <sstream>
@ -24,6 +25,7 @@
#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/include/remote_bitrate_estimator.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"
@ -160,29 +162,86 @@ class Random {
class Packet {
public:
Packet();
Packet(int flow_id, int64_t send_time_us, size_t payload_size,
const RTPHeader& header);
Packet(int64_t send_time_us, uint32_t sequence_number);
enum Type { kMediaPacket, kFeedbackPacket };
Packet();
Packet(int flow_id, int64_t send_time_us, size_t payload_size);
virtual ~Packet();
bool operator<(const Packet& rhs) const;
virtual 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);
size_t payload_size() const { return payload_size_; }
const RTPHeader& header() const { return header_; }
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.
RTPHeader header_; // Actual contents.
};
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 kMediaPacket; }
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 kFeedbackPacket; }
};
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;
@ -303,6 +362,7 @@ class JitterFilter : public PacketProcessor {
DISALLOW_IMPLICIT_CONSTRUCTORS(JitterFilter);
};
// Reorders two consecutive packets with a probability of reorder_percent.
class ReorderFilter : public PacketProcessor {
public:
explicit ReorderFilter(PacketProcessorListener* listener);
@ -448,70 +508,123 @@ class PeriodicKeyFrameSource : public AdaptiveVideoSource {
DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSource);
};
class PacketSender : public PacketProcessor {
class SendSideBwe : public Module {
public:
struct Feedback {
uint32_t estimated_bps;
RTCPReportBlock report_block;
};
SendSideBwe() {}
virtual ~SendSideBwe() {}
PacketSender(PacketProcessorListener* listener, VideoSource* source);
virtual ~PacketSender() {}
virtual int GetFeedbackIntervalMs() const = 0;
virtual void GiveFeedback(const FeedbackPacket& feedback) = 0;
virtual uint32_t GetCapacityKbps() const { return 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 { return 1000; }
virtual void GiveFeedback(const Feedback& feedback) {}
virtual int GetFeedbackIntervalMs() const;
virtual void GiveFeedback(const FeedbackPacket& feedback);
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
virtual VideoSource* source() const { return source_; }
protected:
VideoSource* source_;
private:
DISALLOW_COPY_AND_ASSIGN(PacketSender);
};
class RegularVideoSender : public PacketSender, public BitrateObserver {
public:
RegularVideoSender(PacketProcessorListener* listener,
VideoSource* source,
uint32_t kbps);
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_;
VideoSource* source_;
scoped_ptr<SendSideBwe> bwe_;
int64_t start_of_run_ms_;
scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
std::list<Module*> modules_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(RegularVideoSender);
DISALLOW_COPY_AND_ASSIGN(PacketSender);
};
class PacedVideoSender : public RegularVideoSender,
public PacedSender::Callback {
class PacedVideoSender : public PacketSender, public PacedSender::Callback {
public:
PacedVideoSender(PacketProcessorListener* listener,
VideoSource* source,
uint32_t kbps);
BandwidthEstimatorType estimator);
virtual ~PacedVideoSender();
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;

View File

@ -58,8 +58,10 @@ TEST(BweTestFramework_RandomTest, Gaussian) {
static bool IsSequenceNumberSorted(const Packets& packets) {
PacketsConstIt last_it = packets.begin();
for (PacketsConstIt it = last_it; it != packets.end(); ++it) {
if (IsNewerSequenceNumber((*last_it)->header().sequenceNumber,
(*it)->header().sequenceNumber)) {
const MediaPacket* packet = static_cast<const MediaPacket*>(*it);
const MediaPacket* last_packet = static_cast<const MediaPacket*>(*last_it);
if (IsNewerSequenceNumber(last_packet->header().sequenceNumber,
packet->header().sequenceNumber)) {
return false;
}
last_it = it;
@ -72,20 +74,20 @@ TEST(BweTestFramework_PacketTest, IsTimeSorted) {
// Insert some packets in order...
EXPECT_TRUE(IsTimeSorted(packets));
packets.push_back(new Packet(100, 0));
packets.push_back(new MediaPacket(100, 0));
EXPECT_TRUE(IsTimeSorted(packets));
packets.push_back(new Packet(110, 0));
packets.push_back(new MediaPacket(110, 0));
EXPECT_TRUE(IsTimeSorted(packets));
// ...and one out-of-order...
packets.push_back(new Packet(100, 0));
packets.push_back(new MediaPacket(100, 0));
EXPECT_FALSE(IsTimeSorted(packets));
// ...remove the out-of-order packet, insert another in-order packet.
delete packets.back();
packets.pop_back();
packets.push_back(new Packet(120, 0));
packets.push_back(new MediaPacket(120, 0));
EXPECT_TRUE(IsTimeSorted(packets));
for (auto* packet : packets)
@ -97,20 +99,20 @@ TEST(BweTestFramework_PacketTest, IsSequenceNumberSorted) {
// Insert some packets in order...
EXPECT_TRUE(IsSequenceNumberSorted(packets));
packets.push_back(new Packet(0, 100));
packets.push_back(new MediaPacket(0, 100));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
packets.push_back(new Packet(0, 110));
packets.push_back(new MediaPacket(0, 110));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
// ...and one out-of-order...
packets.push_back(new Packet(0, 100));
packets.push_back(new MediaPacket(0, 100));
EXPECT_FALSE(IsSequenceNumberSorted(packets));
// ...remove the out-of-order packet, insert another in-order packet.
delete packets.back();
packets.pop_back();
packets.push_back(new Packet(0, 120));
packets.push_back(new MediaPacket(0, 120));
EXPECT_TRUE(IsSequenceNumberSorted(packets));
for (auto* packet : packets)
@ -193,7 +195,7 @@ class BweTestFramework_RateCounterFilterTest : public ::testing::Test {
// "Send" a packet every 10 ms.
for (int64_t i = 0; i < run_for_ms; i += 10, now_ms_ += 10) {
packets.push_back(
new Packet(0, now_ms_ * 1000, payload_bits / 8, header));
new MediaPacket(0, now_ms_ * 1000, payload_bits / 8, header));
}
filter_.RunFor(run_for_ms, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
@ -265,7 +267,7 @@ static void TestLossFilter(float loss_percent, bool zero_tolerance) {
for (int i = 0; i < 2225; ++i) {
Packets packets;
for (int j = 0; j < i % 10; ++j)
packets.push_back(new Packet(i, i));
packets.push_back(new MediaPacket(i, i));
sent_packets += packets.size();
filter.RunFor(0, &packets);
ASSERT_TRUE(IsTimeSorted(packets));
@ -320,8 +322,8 @@ class BweTestFramework_DelayFilterTest : public ::testing::Test {
uint32_t out_packets) {
Packets packets;
for (uint32_t i = 0; i < in_packets; ++i) {
packets.push_back(new Packet(now_ms_ * 1000 + (sequence_number_ >> 4),
sequence_number_));
packets.push_back(new MediaPacket(
now_ms_ * 1000 + (sequence_number_ >> 4), sequence_number_));
sequence_number_++;
}
filter_.RunFor(run_for_ms, &packets);
@ -421,7 +423,7 @@ TEST_F(BweTestFramework_DelayFilterTest, JumpToZeroDelay) {
// Delay a bunch of packets, accumulate them to the 'acc' list.
delay.SetDelay(100.0f);
for (uint32_t i = 0; i < 10; ++i) {
packets.push_back(new Packet(i * 100, i));
packets.push_back(new MediaPacket(i * 100, i));
}
delay.RunFor(1000, &packets);
acc.splice(acc.end(), packets);
@ -432,7 +434,7 @@ TEST_F(BweTestFramework_DelayFilterTest, JumpToZeroDelay) {
// to the 'acc' list and verify that it is all sorted.
delay.SetDelay(0.0f);
for (uint32_t i = 10; i < 50; ++i) {
packets.push_back(new Packet(i * 100, i));
packets.push_back(new MediaPacket(i * 100, i));
}
delay.RunFor(1000, &packets);
acc.splice(acc.end(), packets);
@ -474,8 +476,8 @@ static void TestJitterFilter(int64_t stddev_jitter_ms) {
for (uint32_t i = 0; i < 1000; ++i) {
Packets packets;
for (uint32_t j = 0; j < i % 100; ++j) {
packets.push_back(new Packet(now_ms * 1000, sequence_number));
original.push_back(new Packet(now_ms * 1000, sequence_number));
packets.push_back(new MediaPacket(now_ms * 1000, sequence_number));
original.push_back(new MediaPacket(now_ms * 1000, sequence_number));
++sequence_number;
now_ms += 5 * stddev_jitter_ms;
}
@ -496,8 +498,11 @@ static void TestJitterFilter(int64_t stddev_jitter_ms) {
Stats<double> jitter_us;
for (PacketsIt it1 = original.begin(), it2 = jittered.begin();
it1 != original.end() && it2 != jittered.end(); ++it1, ++it2) {
EXPECT_EQ((*it1)->header().sequenceNumber, (*it2)->header().sequenceNumber);
jitter_us.Push((*it2)->send_time_us() - (*it1)->send_time_us());
const MediaPacket* packet1 = static_cast<const MediaPacket*>(*it1);
const MediaPacket* packet2 = static_cast<const MediaPacket*>(*it2);
EXPECT_EQ(packet1->header().sequenceNumber,
packet2->header().sequenceNumber);
jitter_us.Push(packet1->send_time_us() - packet2->send_time_us());
}
EXPECT_NEAR(0.0, jitter_us.GetMean(), stddev_jitter_ms * 1000.0 * 0.008);
EXPECT_NEAR(stddev_jitter_ms * 1000.0, jitter_us.GetStdDev(),
@ -536,7 +541,7 @@ static void TestReorderFilter(uint32_t reorder_percent, uint32_t near_value) {
int64_t now_ms = 0;
uint32_t sequence_number = 1;
for (uint32_t i = 0; i < kPacketCount; ++i, now_ms += 10) {
packets.push_back(new Packet(now_ms * 1000, sequence_number++));
packets.push_back(new MediaPacket(now_ms * 1000, sequence_number++));
}
ASSERT_TRUE(IsTimeSorted(packets));
ASSERT_TRUE(IsSequenceNumberSorted(packets));
@ -552,7 +557,8 @@ static void TestReorderFilter(uint32_t reorder_percent, uint32_t near_value) {
uint32_t distance = 0;
uint32_t last_sequence_number = 0;
for (auto* packet : packets) {
uint32_t sequence_number = packet->header().sequenceNumber;
const MediaPacket* media_packet = static_cast<const MediaPacket*>(packet);
uint32_t sequence_number = media_packet->header().sequenceNumber;
if (sequence_number < last_sequence_number) {
distance += last_sequence_number - sequence_number;
}
@ -622,7 +628,7 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
int64_t send_time_ms = now_ms_ + (i * run_for_ms) / packets_to_generate;
header.sequenceNumber = sequence_number_++;
// Payload is 1000 bits.
packets.push_back(new Packet(0, send_time_ms * 1000, 125, header));
packets.push_back(new MediaPacket(0, send_time_ms * 1000, 125, header));
send_times_us_.push_back(send_time_ms * 1000);
}
ASSERT_TRUE(IsTimeSorted(packets));
@ -648,8 +654,9 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
void CheckMaxDelay(int64_t max_delay_ms) {
for (const auto* packet : output_packets_) {
int64_t delay_us = packet->send_time_us() -
send_times_us_[packet->header().sequenceNumber];
const MediaPacket* media_packet = static_cast<const MediaPacket*>(packet);
int64_t delay_us = media_packet->send_time_us() -
send_times_us_[media_packet->header().sequenceNumber];
EXPECT_GE(max_delay_ms * 1000, delay_us);
}
}
@ -781,20 +788,23 @@ void TestVideoSender(PacketSender* sender,
uint32_t rtp_timestamp = 0;
uint32_t rtp_timestamp_wraps = 0;
for (const auto* packet : packets) {
EXPECT_LE(send_time_us, packet->send_time_us());
send_time_us = packet->send_time_us();
if (sender->source()->max_payload_size_bytes() != packet->payload_size()) {
EXPECT_EQ(expected_payload_size, packet->payload_size());
const MediaPacket* media_packet = static_cast<const MediaPacket*>(packet);
EXPECT_LE(send_time_us, media_packet->send_time_us());
send_time_us = media_packet->send_time_us();
if (sender->source()->max_payload_size_bytes() !=
media_packet->payload_size()) {
EXPECT_EQ(expected_payload_size, media_packet->payload_size());
}
total_payload_size += packet->payload_size();
if (absolute_send_time > packet->header().extension.absoluteSendTime) {
total_payload_size += media_packet->payload_size();
if (absolute_send_time >
media_packet->header().extension.absoluteSendTime) {
absolute_send_time_wraps++;
}
absolute_send_time = packet->header().extension.absoluteSendTime;
if (rtp_timestamp > packet->header().timestamp) {
absolute_send_time = media_packet->header().extension.absoluteSendTime;
if (rtp_timestamp > media_packet->header().timestamp) {
rtp_timestamp_wraps++;
}
rtp_timestamp = packet->header().timestamp;
rtp_timestamp = media_packet->header().timestamp;
}
EXPECT_EQ(expected_total_payload_size, total_payload_size);
EXPECT_GE(1u, absolute_send_time_wraps);
@ -807,7 +817,7 @@ void TestVideoSender(PacketSender* sender,
TEST(BweTestFramework_VideoSenderTest, Fps1Kbps80_1s) {
// 1 fps, 80 kbps
VideoSource source(0, 1.0f, 80, 0x1234, 0);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(10000u, source.bytes_per_second());
// We're at 1 fps, so all packets should be generated on first call, giving 10
// packets of each 1000 bytes, total 10000 bytes.
@ -825,7 +835,7 @@ TEST(BweTestFramework_VideoSenderTest, Fps1Kbps80_1s) {
TEST(BweTestFramework_VideoSenderTest, Fps1Kbps80_1s_Offset) {
// 1 fps, 80 kbps, offset 0.5 of a frame period, ==0.5s in this case.
VideoSource source(0, 1.0f, 80, 0x1234, 500);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(10000u, source.bytes_per_second());
// 499ms, no output.
TestVideoSender(&sender, 499, 0, 0, 0);
@ -846,7 +856,7 @@ TEST(BweTestFramework_VideoSenderTest, Fps1Kbps80_1s_Offset) {
TEST(BweTestFramework_VideoSenderTest, Fps50Kpbs80_11s) {
// 50 fps, 80 kbps.
VideoSource source(0, 50.0f, 80, 0x1234, 0);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(10000u, source.bytes_per_second());
// 9998ms, should see 500 frames, 200 byte payloads, total 100000 bytes.
TestVideoSender(&sender, 9998, 500, 200, 100000);
@ -863,7 +873,7 @@ TEST(BweTestFramework_VideoSenderTest, Fps50Kpbs80_11s) {
TEST(BweTestFramework_VideoSenderTest, Fps10Kpbs120_1s) {
// 20 fps, 120 kbps.
VideoSource source(0, 20.0f, 120, 0x1234, 0);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(15000u, source.bytes_per_second());
// 498ms, 10 frames with 750 byte payloads, total 7500 bytes.
TestVideoSender(&sender, 498, 10, 750, 7500);
@ -880,7 +890,7 @@ TEST(BweTestFramework_VideoSenderTest, Fps10Kpbs120_1s) {
TEST(BweTestFramework_VideoSenderTest, Fps30Kbps800_20s) {
// 20 fps, 820 kbps.
VideoSource source(0, 25.0f, 820, 0x1234, 0);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(102500u, source.bytes_per_second());
// 9998ms, 250 frames. 820 kbps = 102500 bytes/s, so total should be 1025000.
// Each frame is 102500/25=4100 bytes, or 5 packets (4 @1000 bytes, 1 @100),
@ -902,7 +912,7 @@ TEST(BweTestFramework_VideoSenderTest, Fps30Kbps800_20s) {
TEST(BweTestFramework_VideoSenderTest, TestAppendInOrder) {
// 1 fps, 80 kbps, 250ms offset.
VideoSource source1(0, 1.0f, 80, 0x1234, 250);
PacketSender sender1(NULL, &source1);
PacketSender sender1(NULL, &source1, kNullEstimator);
EXPECT_EQ(10000u, source1.bytes_per_second());
Packets packets;
// Generate some packets, verify they are sorted.
@ -918,7 +928,7 @@ TEST(BweTestFramework_VideoSenderTest, TestAppendInOrder) {
// Another sender, 2 fps, 160 kbps, 150ms offset
VideoSource source2(0, 2.0f, 160, 0x2234, 150);
PacketSender sender2(NULL, &source2);
PacketSender sender2(NULL, &source2, kNullEstimator);
EXPECT_EQ(20000u, source2.bytes_per_second());
// Generate some packets, verify that they are merged with the packets already
// on the list.
@ -936,13 +946,13 @@ TEST(BweTestFramework_VideoSenderTest, TestAppendInOrder) {
TEST(BweTestFramework_VideoSenderTest, FeedbackIneffective) {
VideoSource source(0, 25.0f, 820, 0x1234, 0);
PacketSender sender(NULL, &source);
PacketSender sender(NULL, &source, kNullEstimator);
EXPECT_EQ(102500u, source.bytes_per_second());
TestVideoSender(&sender, 9998, 1000, 500, 1025000);
// Make sure feedback has no effect on a regular video sender.
PacketSender::Feedback feedback = { 512000 };
RembFeedback feedback(0, 0, 512000, RTCPReportBlock());
sender.GiveFeedback(feedback);
EXPECT_EQ(102500u, source.bytes_per_second());
TestVideoSender(&sender, 9998, 1000, 500, 1025000);
@ -950,20 +960,20 @@ TEST(BweTestFramework_VideoSenderTest, FeedbackIneffective) {
TEST(BweTestFramework_AdaptiveVideoSenderTest, FeedbackChangesBitrate) {
AdaptiveVideoSource source(0, 25.0f, 820, 0x1234, 0);
RegularVideoSender sender(NULL, &source, 820);
PacketSender sender(NULL, &source, kRembEstimator);
EXPECT_EQ(102500u, source.bytes_per_second());
TestVideoSender(&sender, 9998, 1000, 500, 1025000);
// Make sure we can reduce the bitrate.
PacketSender::Feedback feedback = { 512000 };
RembFeedback feedback(0, 0, 512000, RTCPReportBlock());
sender.GiveFeedback(feedback);
EXPECT_EQ(64000u, source.bytes_per_second());
TestVideoSender(&sender, 9998, 750, 160, 640000);
// Increase the bitrate to the initial bitrate and verify that the output is
// the same.
feedback.estimated_bps = 820000;
sender.GiveFeedback(feedback);
RembFeedback feedback2(0, 0, 820000, RTCPReportBlock());
sender.GiveFeedback(feedback2);
Packets packets;
sender.RunFor(10000, &packets);
EXPECT_EQ(102500u, source.bytes_per_second());