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:
parent
353c8b8c08
commit
fb609a1f57
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user