Break out code from bloated files in the BWE simulator.
No changes to functionality. BUG=4173 R=pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/34209004 Cr-Commit-Position: refs/heads/master@{#8374} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8374 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
0f7f161ed6
commit
14b0279416
@ -211,6 +211,8 @@
|
||||
'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc',
|
||||
'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h',
|
||||
'remote_bitrate_estimator/remote_bitrate_estimators_test.cc',
|
||||
'remote_bitrate_estimator/test/bwe.cc',
|
||||
'remote_bitrate_estimator/test/bwe.h',
|
||||
'remote_bitrate_estimator/test/bwe_test.cc',
|
||||
'remote_bitrate_estimator/test/bwe_test.h',
|
||||
'remote_bitrate_estimator/test/bwe_test_baselinefile.cc',
|
||||
@ -222,6 +224,11 @@
|
||||
'remote_bitrate_estimator/test/bwe_test_framework_unittest.cc',
|
||||
'remote_bitrate_estimator/test/bwe_test_logging.cc',
|
||||
'remote_bitrate_estimator/test/bwe_test_logging.h',
|
||||
'remote_bitrate_estimator/test/packet_receiver.cc',
|
||||
'remote_bitrate_estimator/test/packet_receiver.h',
|
||||
'remote_bitrate_estimator/test/packet_sender.cc',
|
||||
'remote_bitrate_estimator/test/packet_sender.h',
|
||||
'remote_bitrate_estimator/test/packets.h',
|
||||
'rtp_rtcp/source/mock/mock_rtp_payload_strategy.h',
|
||||
'rtp_rtcp/source/byte_io_unittest.cc',
|
||||
'rtp_rtcp/source/fec_receiver_unittest.cc',
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
using std::string;
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/test/testsupport/perf_test.h"
|
||||
|
||||
|
354
webrtc/modules/remote_bitrate_estimator/test/bwe.cc
Normal file
354
webrtc/modules/remote_bitrate_estimator/test/bwe.cc
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/common.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
const int kMinBitrateKbps = 30;
|
||||
const int kMaxBitrateKbps = 20000;
|
||||
|
||||
class NullSendSideBwe : public SendSideBwe {
|
||||
public:
|
||||
NullSendSideBwe() {}
|
||||
virtual ~NullSendSideBwe() {}
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 1000; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE {}
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
virtual int Process() OVERRIDE { return 0; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NullSendSideBwe);
|
||||
};
|
||||
|
||||
class RembSendSideBwe : public SendSideBwe {
|
||||
public:
|
||||
RembSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock);
|
||||
virtual ~RembSendSideBwe();
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE;
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
||||
virtual int Process() OVERRIDE;
|
||||
|
||||
protected:
|
||||
scoped_ptr<BitrateController> bitrate_controller_;
|
||||
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
|
||||
|
||||
private:
|
||||
Clock* clock_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(RembSendSideBwe);
|
||||
};
|
||||
|
||||
class FullSendSideBwe : public SendSideBwe, public RemoteBitrateObserver {
|
||||
public:
|
||||
FullSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock);
|
||||
virtual ~FullSendSideBwe();
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE;
|
||||
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) OVERRIDE;
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
||||
virtual int Process() OVERRIDE;
|
||||
|
||||
protected:
|
||||
scoped_ptr<BitrateController> bitrate_controller_;
|
||||
scoped_ptr<RemoteBitrateEstimator> rbe_;
|
||||
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
|
||||
|
||||
private:
|
||||
Clock* const clock_;
|
||||
RTCPReportBlock report_block_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FullSendSideBwe);
|
||||
};
|
||||
|
||||
RembSendSideBwe::RembSendSideBwe(int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock)
|
||||
: bitrate_controller_(
|
||||
BitrateController::CreateBitrateController(clock, false)),
|
||||
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
|
||||
clock_(clock) {
|
||||
assert(kbps >= kMinBitrateKbps);
|
||||
assert(kbps <= kMaxBitrateKbps);
|
||||
bitrate_controller_->SetBitrateObserver(
|
||||
observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps);
|
||||
}
|
||||
|
||||
RembSendSideBwe::~RembSendSideBwe() {
|
||||
}
|
||||
|
||||
void RembSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) {
|
||||
const RembFeedback& remb_feedback =
|
||||
static_cast<const RembFeedback&>(feedback);
|
||||
feedback_observer_->OnReceivedEstimatedBitrate(remb_feedback.estimated_bps());
|
||||
ReportBlockList report_blocks;
|
||||
report_blocks.push_back(remb_feedback.report_block());
|
||||
feedback_observer_->OnReceivedRtcpReceiverReport(
|
||||
report_blocks, 0, clock_->TimeInMilliseconds());
|
||||
bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
int64_t RembSendSideBwe::TimeUntilNextProcess() {
|
||||
return bitrate_controller_->TimeUntilNextProcess();
|
||||
}
|
||||
|
||||
int RembSendSideBwe::Process() {
|
||||
return bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
FullSendSideBwe::FullSendSideBwe(int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock)
|
||||
: bitrate_controller_(
|
||||
BitrateController::CreateBitrateController(clock, false)),
|
||||
rbe_(AbsoluteSendTimeRemoteBitrateEstimatorFactory()
|
||||
.Create(this, clock, kAimdControl, 1000 * kMinBitrateKbps)),
|
||||
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
|
||||
clock_(clock) {
|
||||
assert(kbps >= kMinBitrateKbps);
|
||||
assert(kbps <= kMaxBitrateKbps);
|
||||
bitrate_controller_->SetBitrateObserver(
|
||||
observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps);
|
||||
}
|
||||
|
||||
FullSendSideBwe::~FullSendSideBwe() {
|
||||
}
|
||||
|
||||
void FullSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) {
|
||||
const SendSideBweFeedback& fb =
|
||||
static_cast<const SendSideBweFeedback&>(feedback);
|
||||
if (fb.packet_feedback_vector().empty())
|
||||
return;
|
||||
rbe_->IncomingPacketFeedbackVector(fb.packet_feedback_vector());
|
||||
// TODO(holmer): Handle losses in between feedback packets.
|
||||
int expected_packets = fb.packet_feedback_vector().back().sequence_number -
|
||||
fb.packet_feedback_vector().front().sequence_number +
|
||||
1;
|
||||
// Assuming no reordering for now.
|
||||
if (expected_packets <= 0)
|
||||
return;
|
||||
int lost_packets = expected_packets - fb.packet_feedback_vector().size();
|
||||
report_block_.fractionLost = (lost_packets << 8) / expected_packets;
|
||||
report_block_.cumulativeLost += lost_packets;
|
||||
ReportBlockList report_blocks;
|
||||
report_blocks.push_back(report_block_);
|
||||
feedback_observer_->OnReceivedRtcpReceiverReport(
|
||||
report_blocks, 0, clock_->TimeInMilliseconds());
|
||||
bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
void FullSendSideBwe::OnReceiveBitrateChanged(
|
||||
const std::vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) {
|
||||
feedback_observer_->OnReceivedEstimatedBitrate(bitrate);
|
||||
}
|
||||
|
||||
int64_t FullSendSideBwe::TimeUntilNextProcess() {
|
||||
return bitrate_controller_->TimeUntilNextProcess();
|
||||
}
|
||||
|
||||
int FullSendSideBwe::Process() {
|
||||
rbe_->Process();
|
||||
return bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) {
|
||||
const int kInterArrivalShift = 26;
|
||||
const int kAbsSendTimeInterArrivalUpshift = 8;
|
||||
const double kTimestampToMs =
|
||||
1000.0 / static_cast<double>(1 << kInterArrivalShift);
|
||||
uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift;
|
||||
return static_cast<int64_t>(timestamp) * kTimestampToMs;
|
||||
}
|
||||
|
||||
class SendSideBweReceiver : public BweReceiver {
|
||||
public:
|
||||
explicit SendSideBweReceiver(int flow_id)
|
||||
: BweReceiver(flow_id), last_feedback_ms_(0) {}
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) OVERRIDE {
|
||||
packet_feedback_vector_.push_back(PacketInfo(
|
||||
arrival_time_ms, GetAbsSendTimeInMs(header.extension.absoluteSendTime),
|
||||
header.sequenceNumber, payload_size));
|
||||
}
|
||||
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE {
|
||||
if (now_ms - last_feedback_ms_ < 100)
|
||||
return NULL;
|
||||
last_feedback_ms_ = now_ms;
|
||||
FeedbackPacket* fb = new SendSideBweFeedback(flow_id_, now_ms * 1000,
|
||||
packet_feedback_vector_);
|
||||
packet_feedback_vector_.clear();
|
||||
return fb;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t last_feedback_ms_;
|
||||
std::vector<PacketInfo> packet_feedback_vector_;
|
||||
};
|
||||
|
||||
class RembReceiver : public BweReceiver, public RemoteBitrateObserver {
|
||||
public:
|
||||
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
|
||||
|
||||
RembReceiver(int flow_id, bool plot)
|
||||
: BweReceiver(flow_id),
|
||||
estimate_log_prefix_(),
|
||||
plot_estimate_(plot),
|
||||
clock_(0),
|
||||
recv_stats_(ReceiveStatistics::Create(&clock_)),
|
||||
latest_estimate_bps_(-1),
|
||||
estimator_(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create(
|
||||
this,
|
||||
&clock_,
|
||||
kAimdControl,
|
||||
kRemoteBitrateEstimatorMinBitrateBps)) {
|
||||
std::stringstream ss;
|
||||
ss << "Estimate_" << flow_id_ << "#1";
|
||||
estimate_log_prefix_ = ss.str();
|
||||
// Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
|
||||
estimator_->OnRttUpdate(50);
|
||||
}
|
||||
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) {
|
||||
recv_stats_->IncomingPacket(header, payload_size, false);
|
||||
|
||||
latest_estimate_bps_ = -1;
|
||||
|
||||
int64_t step_ms = std::max<int64_t>(estimator_->TimeUntilNextProcess(), 0);
|
||||
while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) {
|
||||
clock_.AdvanceTimeMilliseconds(step_ms);
|
||||
estimator_->Process();
|
||||
step_ms = std::max<int64_t>(estimator_->TimeUntilNextProcess(), 0);
|
||||
}
|
||||
estimator_->IncomingPacket(arrival_time_ms, payload_size, header);
|
||||
clock_.AdvanceTimeMilliseconds(arrival_time_ms -
|
||||
clock_.TimeInMilliseconds());
|
||||
ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds());
|
||||
}
|
||||
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE {
|
||||
BWE_TEST_LOGGING_CONTEXT("Remb");
|
||||
uint32_t estimated_bps = 0;
|
||||
RembFeedback* feedback = NULL;
|
||||
if (LatestEstimate(&estimated_bps)) {
|
||||
StatisticianMap statisticians = recv_stats_->GetActiveStatisticians();
|
||||
RTCPReportBlock report_block;
|
||||
if (!statisticians.empty()) {
|
||||
report_block = BuildReportBlock(statisticians.begin()->second);
|
||||
}
|
||||
feedback = new RembFeedback(flow_id_, now_ms * 1000, estimated_bps,
|
||||
report_block);
|
||||
|
||||
double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
|
||||
RTC_UNUSED(estimated_kbps);
|
||||
if (plot_estimate_) {
|
||||
BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(),
|
||||
estimated_kbps);
|
||||
}
|
||||
}
|
||||
return feedback;
|
||||
}
|
||||
|
||||
// Implements RemoteBitrateObserver.
|
||||
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) OVERRIDE {}
|
||||
|
||||
private:
|
||||
static RTCPReportBlock BuildReportBlock(StreamStatistician* statistician) {
|
||||
RTCPReportBlock report_block;
|
||||
RtcpStatistics stats;
|
||||
if (!statistician->GetStatistics(&stats, true))
|
||||
return report_block;
|
||||
report_block.fractionLost = stats.fraction_lost;
|
||||
report_block.cumulativeLost = stats.cumulative_lost;
|
||||
report_block.extendedHighSeqNum = stats.extended_max_sequence_number;
|
||||
report_block.jitter = stats.jitter;
|
||||
return report_block;
|
||||
}
|
||||
|
||||
bool LatestEstimate(uint32_t* estimate_bps) {
|
||||
if (latest_estimate_bps_ < 0) {
|
||||
std::vector<unsigned int> ssrcs;
|
||||
unsigned int bps = 0;
|
||||
if (!estimator_->LatestEstimate(&ssrcs, &bps)) {
|
||||
return false;
|
||||
}
|
||||
latest_estimate_bps_ = bps;
|
||||
}
|
||||
*estimate_bps = latest_estimate_bps_;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string estimate_log_prefix_;
|
||||
bool plot_estimate_;
|
||||
SimulatedClock clock_;
|
||||
scoped_ptr<ReceiveStatistics> recv_stats_;
|
||||
int64_t latest_estimate_bps_;
|
||||
scoped_ptr<RemoteBitrateEstimator> estimator_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(RembReceiver);
|
||||
};
|
||||
|
||||
SendSideBwe* CreateBweSender(BandwidthEstimatorType estimator,
|
||||
int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock) {
|
||||
switch (estimator) {
|
||||
case kRembEstimator:
|
||||
return new RembSendSideBwe(kbps, observer, clock);
|
||||
case kFullSendSideEstimator:
|
||||
return new FullSendSideBwe(kbps, observer, clock);
|
||||
case kNullEstimator:
|
||||
return new NullSendSideBwe();
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
|
||||
int flow_id,
|
||||
bool plot) {
|
||||
switch (type) {
|
||||
case kRembEstimator:
|
||||
return new RembReceiver(flow_id, plot);
|
||||
case kFullSendSideEstimator:
|
||||
return new SendSideBweReceiver(flow_id);
|
||||
case kNullEstimator:
|
||||
return new BweReceiver(flow_id);
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
66
webrtc/modules/remote_bitrate_estimator/test/bwe.h
Normal file
66
webrtc/modules/remote_bitrate_estimator/test/bwe.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_
|
||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet.h"
|
||||
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
class SendSideBwe : public Module {
|
||||
public:
|
||||
SendSideBwe() {}
|
||||
virtual ~SendSideBwe() {}
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const = 0;
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) = 0;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SendSideBwe);
|
||||
};
|
||||
|
||||
class BweReceiver {
|
||||
public:
|
||||
explicit BweReceiver(int flow_id) : flow_id_(flow_id) {}
|
||||
virtual ~BweReceiver() {}
|
||||
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) {}
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; }
|
||||
|
||||
protected:
|
||||
int flow_id_;
|
||||
};
|
||||
|
||||
enum BandwidthEstimatorType {
|
||||
kNullEstimator,
|
||||
kRembEstimator,
|
||||
kFullSendSideEstimator
|
||||
};
|
||||
|
||||
SendSideBwe* CreateBweSender(BandwidthEstimatorType estimator,
|
||||
int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock);
|
||||
|
||||
BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
|
||||
int flow_id,
|
||||
bool plot);
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_H_
|
@ -12,10 +12,9 @@
|
||||
|
||||
#include "webrtc/base/common.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_baselinefile.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
@ -25,304 +24,70 @@ using std::vector;
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
class BweReceiver {
|
||||
public:
|
||||
explicit BweReceiver(int flow_id) : flow_id_(flow_id) {}
|
||||
virtual ~BweReceiver() {}
|
||||
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) {}
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; }
|
||||
|
||||
protected:
|
||||
int flow_id_;
|
||||
};
|
||||
|
||||
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) {
|
||||
const int kInterArrivalShift = 26;
|
||||
const int kAbsSendTimeInterArrivalUpshift = 8;
|
||||
const double kTimestampToMs =
|
||||
1000.0 / static_cast<double>(1 << kInterArrivalShift);
|
||||
uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift;
|
||||
return static_cast<int64_t>(timestamp) * kTimestampToMs;
|
||||
PacketProcessorRunner::PacketProcessorRunner(PacketProcessor* processor)
|
||||
: processor_(processor) {
|
||||
}
|
||||
|
||||
class SendSideBweReceiver : public BweReceiver {
|
||||
public:
|
||||
explicit SendSideBweReceiver(int flow_id)
|
||||
: BweReceiver(flow_id), last_feedback_ms_(0) {}
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) OVERRIDE {
|
||||
packet_feedback_vector_.push_back(PacketInfo(
|
||||
arrival_time_ms, GetAbsSendTimeInMs(header.extension.absoluteSendTime),
|
||||
header.sequenceNumber, payload_size));
|
||||
}
|
||||
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE {
|
||||
if (now_ms - last_feedback_ms_ < 100)
|
||||
return NULL;
|
||||
last_feedback_ms_ = now_ms;
|
||||
FeedbackPacket* fb = new SendSideBweFeedback(flow_id_, now_ms * 1000,
|
||||
packet_feedback_vector_);
|
||||
packet_feedback_vector_.clear();
|
||||
return fb;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t last_feedback_ms_;
|
||||
std::vector<PacketInfo> packet_feedback_vector_;
|
||||
};
|
||||
|
||||
class RembReceiver : public BweReceiver, public RemoteBitrateObserver {
|
||||
public:
|
||||
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
|
||||
|
||||
RembReceiver(int flow_id, bool plot)
|
||||
: BweReceiver(flow_id),
|
||||
estimate_log_prefix_(),
|
||||
plot_estimate_(plot),
|
||||
clock_(0),
|
||||
recv_stats_(ReceiveStatistics::Create(&clock_)),
|
||||
latest_estimate_bps_(-1),
|
||||
estimator_(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create(
|
||||
this,
|
||||
&clock_,
|
||||
kAimdControl,
|
||||
kRemoteBitrateEstimatorMinBitrateBps)) {
|
||||
std::stringstream ss;
|
||||
ss << "Estimate_" << flow_id_ << "#1";
|
||||
estimate_log_prefix_ = ss.str();
|
||||
// Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
|
||||
estimator_->OnRttUpdate(50);
|
||||
}
|
||||
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) {
|
||||
recv_stats_->IncomingPacket(header, payload_size, false);
|
||||
|
||||
latest_estimate_bps_ = -1;
|
||||
|
||||
int64_t step_ms = std::max<int64_t>(estimator_->TimeUntilNextProcess(), 0);
|
||||
while ((clock_.TimeInMilliseconds() + step_ms) < arrival_time_ms) {
|
||||
clock_.AdvanceTimeMilliseconds(step_ms);
|
||||
estimator_->Process();
|
||||
step_ms = std::max<int64_t>(estimator_->TimeUntilNextProcess(), 0);
|
||||
}
|
||||
estimator_->IncomingPacket(arrival_time_ms, payload_size, header);
|
||||
clock_.AdvanceTimeMilliseconds(arrival_time_ms -
|
||||
clock_.TimeInMilliseconds());
|
||||
ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds());
|
||||
}
|
||||
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) OVERRIDE {
|
||||
BWE_TEST_LOGGING_CONTEXT("Remb");
|
||||
uint32_t estimated_bps = 0;
|
||||
RembFeedback* feedback = NULL;
|
||||
if (LatestEstimate(&estimated_bps)) {
|
||||
StatisticianMap statisticians = recv_stats_->GetActiveStatisticians();
|
||||
RTCPReportBlock report_block;
|
||||
if (!statisticians.empty()) {
|
||||
report_block = BuildReportBlock(statisticians.begin()->second);
|
||||
}
|
||||
feedback = new RembFeedback(flow_id_, now_ms * 1000, estimated_bps,
|
||||
report_block);
|
||||
|
||||
double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
|
||||
RTC_UNUSED(estimated_kbps);
|
||||
if (plot_estimate_) {
|
||||
BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(),
|
||||
estimated_kbps);
|
||||
}
|
||||
}
|
||||
return feedback;
|
||||
}
|
||||
|
||||
// Implements RemoteBitrateObserver.
|
||||
virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) OVERRIDE {}
|
||||
|
||||
private:
|
||||
static RTCPReportBlock BuildReportBlock(StreamStatistician* statistician) {
|
||||
RTCPReportBlock report_block;
|
||||
RtcpStatistics stats;
|
||||
if (!statistician->GetStatistics(&stats, true))
|
||||
return report_block;
|
||||
report_block.fractionLost = stats.fraction_lost;
|
||||
report_block.cumulativeLost = stats.cumulative_lost;
|
||||
report_block.extendedHighSeqNum = stats.extended_max_sequence_number;
|
||||
report_block.jitter = stats.jitter;
|
||||
return report_block;
|
||||
}
|
||||
|
||||
bool LatestEstimate(uint32_t* estimate_bps) {
|
||||
if (latest_estimate_bps_ < 0) {
|
||||
vector<unsigned int> ssrcs;
|
||||
unsigned int bps = 0;
|
||||
if (!estimator_->LatestEstimate(&ssrcs, &bps)) {
|
||||
return false;
|
||||
}
|
||||
latest_estimate_bps_ = bps;
|
||||
}
|
||||
*estimate_bps = latest_estimate_bps_;
|
||||
return true;
|
||||
}
|
||||
|
||||
string estimate_log_prefix_;
|
||||
bool plot_estimate_;
|
||||
SimulatedClock clock_;
|
||||
scoped_ptr<ReceiveStatistics> recv_stats_;
|
||||
int64_t latest_estimate_bps_;
|
||||
scoped_ptr<RemoteBitrateEstimator> estimator_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(RembReceiver);
|
||||
};
|
||||
|
||||
BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
|
||||
int flow_id,
|
||||
bool plot) {
|
||||
switch (type) {
|
||||
case kRembEstimator:
|
||||
return new RembReceiver(flow_id, plot);
|
||||
case kFullSendSideEstimator:
|
||||
return new SendSideBweReceiver(flow_id);
|
||||
case kNullEstimator:
|
||||
return new BweReceiver(flow_id);
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
PacketProcessorRunner::~PacketProcessorRunner() {
|
||||
for (Packet* packet : queue_)
|
||||
delete packet;
|
||||
}
|
||||
|
||||
PacketReceiver::PacketReceiver(PacketProcessorListener* listener,
|
||||
int flow_id,
|
||||
BandwidthEstimatorType bwe_type,
|
||||
bool plot_delay,
|
||||
bool plot_bwe)
|
||||
: PacketProcessor(listener, flow_id, kReceiver),
|
||||
delay_log_prefix_(),
|
||||
last_delay_plot_ms_(0),
|
||||
plot_delay_(plot_delay),
|
||||
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) {
|
||||
// Setup the prefix strings used when logging.
|
||||
std::stringstream ss;
|
||||
ss << "Delay_" << flow_id << "#2";
|
||||
delay_log_prefix_ = ss.str();
|
||||
bool PacketProcessorRunner::RunsProcessor(
|
||||
const PacketProcessor* processor) const {
|
||||
return processor == processor_;
|
||||
}
|
||||
|
||||
PacketReceiver::~PacketReceiver() {
|
||||
void PacketProcessorRunner::RunFor(int64_t time_ms,
|
||||
int64_t time_now_ms,
|
||||
Packets* in_out) {
|
||||
Packets to_process;
|
||||
FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process);
|
||||
processor_->RunFor(time_ms, &to_process);
|
||||
QueuePackets(&to_process, time_now_ms * 1000);
|
||||
if (!to_process.empty()) {
|
||||
processor_->Plot((to_process.back()->send_time_us() + 500) / 1000);
|
||||
}
|
||||
in_out->merge(to_process, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
Packets feedback;
|
||||
for (auto it = in_out->begin(); it != in_out->end();) {
|
||||
// PacketReceivers are only associated with a single stream, and therefore
|
||||
// should only process a single flow id.
|
||||
// TODO(holmer): Break this out into a Demuxer which implements both
|
||||
// PacketProcessorListener and PacketProcessor.
|
||||
if ((*it)->GetPacketType() == Packet::kMedia &&
|
||||
(*it)->flow_id() == *flow_ids().begin()) {
|
||||
BWE_TEST_LOGGING_CONTEXT("Receiver");
|
||||
const MediaPacket* media_packet = static_cast<const MediaPacket*>(*it);
|
||||
// We're treating the send time (from previous filter) as the arrival
|
||||
// time once packet reaches the estimator.
|
||||
int64_t arrival_time_ms = (media_packet->send_time_us() + 500) / 1000;
|
||||
BWE_TEST_LOGGING_TIME(arrival_time_ms);
|
||||
PlotDelay(arrival_time_ms,
|
||||
(media_packet->creation_time_us() + 500) / 1000);
|
||||
|
||||
bwe_receiver_->ReceivePacket(arrival_time_ms,
|
||||
media_packet->payload_size(),
|
||||
media_packet->header());
|
||||
FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms);
|
||||
if (fb)
|
||||
feedback.push_back(fb);
|
||||
delete media_packet;
|
||||
it = in_out->erase(it);
|
||||
void PacketProcessorRunner::FindPacketsToProcess(const FlowIds& flow_ids,
|
||||
Packets* in,
|
||||
Packets* out) {
|
||||
assert(out->empty());
|
||||
for (Packets::iterator it = in->begin(); it != in->end();) {
|
||||
// TODO(holmer): Further optimize this by looking for consecutive flow ids
|
||||
// in the packet list and only doing the binary search + splice once for a
|
||||
// sequence.
|
||||
if (flow_ids.find((*it)->flow_id()) != flow_ids.end()) {
|
||||
Packets::iterator next = it;
|
||||
++next;
|
||||
out->splice(out->end(), *in, it);
|
||||
it = next;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Insert feedback packets to be sent back to the sender.
|
||||
in_out->merge(feedback, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) {
|
||||
static const int kDelayPlotIntervalMs = 100;
|
||||
if (!plot_delay_)
|
||||
void PacketProcessorRunner::QueuePackets(Packets* batch,
|
||||
int64_t end_of_batch_time_us) {
|
||||
queue_.merge(*batch, DereferencingComparator<Packet>);
|
||||
if (queue_.empty()) {
|
||||
return;
|
||||
if (arrival_time_ms - last_delay_plot_ms_ > kDelayPlotIntervalMs) {
|
||||
BWE_TEST_LOGGING_PLOT(delay_log_prefix_, arrival_time_ms,
|
||||
arrival_time_ms - send_time_ms);
|
||||
last_delay_plot_ms_ = arrival_time_ms;
|
||||
}
|
||||
Packets::iterator it = queue_.begin();
|
||||
for (; it != queue_.end(); ++it) {
|
||||
if ((*it)->send_time_us() > end_of_batch_time_us) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Packets to_transfer;
|
||||
to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
|
||||
batch->merge(to_transfer, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
class PacketProcessorRunner {
|
||||
public:
|
||||
explicit PacketProcessorRunner(PacketProcessor* processor)
|
||||
: processor_(processor) {}
|
||||
|
||||
~PacketProcessorRunner() {
|
||||
for (Packet* packet : queue_)
|
||||
delete packet;
|
||||
}
|
||||
|
||||
bool RunsProcessor(const PacketProcessor* processor) const {
|
||||
return processor == processor_;
|
||||
}
|
||||
|
||||
void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out) {
|
||||
Packets to_process;
|
||||
FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process);
|
||||
processor_->RunFor(time_ms, &to_process);
|
||||
QueuePackets(&to_process, time_now_ms * 1000);
|
||||
if (!to_process.empty()) {
|
||||
processor_->Plot((to_process.back()->send_time_us() + 500) / 1000);
|
||||
}
|
||||
in_out->merge(to_process, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
private:
|
||||
void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in,
|
||||
Packets* out) {
|
||||
assert(out->empty());
|
||||
for (Packets::iterator it = in->begin(); it != in->end();) {
|
||||
// TODO(holmer): Further optimize this by looking for consecutive flow ids
|
||||
// in the packet list and only doing the binary search + splice once for a
|
||||
// sequence.
|
||||
if (flow_ids.find((*it)->flow_id()) != flow_ids.end()) {
|
||||
Packets::iterator next = it;
|
||||
++next;
|
||||
out->splice(out->end(), *in, it);
|
||||
it = next;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueuePackets(Packets* batch, int64_t end_of_batch_time_us) {
|
||||
queue_.merge(*batch, DereferencingComparator<Packet>);
|
||||
if (queue_.empty()) {
|
||||
return;
|
||||
}
|
||||
Packets::iterator it = queue_.begin();
|
||||
for (; it != queue_.end(); ++it) {
|
||||
if ((*it)->send_time_us() > end_of_batch_time_us) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Packets to_transfer;
|
||||
to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
|
||||
batch->merge(to_transfer, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
PacketProcessor* processor_;
|
||||
Packets queue_;
|
||||
};
|
||||
|
||||
BweTest::BweTest()
|
||||
: run_time_ms_(0), time_now_ms_(-1), simulation_interval_ms_(-1) {
|
||||
links_.push_back(&uplink_);
|
||||
|
@ -8,6 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_
|
||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -22,37 +25,29 @@ namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
class BweReceiver;
|
||||
class PacketProcessorRunner;
|
||||
class PacketReceiver;
|
||||
class PacketSender;
|
||||
|
||||
class PacketReceiver : public PacketProcessor {
|
||||
class PacketProcessorRunner {
|
||||
public:
|
||||
PacketReceiver(PacketProcessorListener* listener,
|
||||
int flow_id,
|
||||
BandwidthEstimatorType bwe_type,
|
||||
bool plot_delay,
|
||||
bool plot_bwe);
|
||||
~PacketReceiver();
|
||||
explicit PacketProcessorRunner(PacketProcessor* processor);
|
||||
~PacketProcessorRunner();
|
||||
|
||||
// Implements PacketProcessor.
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
void LogStats();
|
||||
|
||||
protected:
|
||||
void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms);
|
||||
|
||||
int64_t now_ms_;
|
||||
std::string delay_log_prefix_;
|
||||
int64_t last_delay_plot_ms_;
|
||||
bool plot_delay_;
|
||||
scoped_ptr<BweReceiver> bwe_receiver_;
|
||||
bool RunsProcessor(const PacketProcessor* processor) const;
|
||||
void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
|
||||
void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in, Packets* out);
|
||||
void QueuePackets(Packets* batch, int64_t end_of_batch_time_us);
|
||||
|
||||
PacketProcessor* processor_;
|
||||
Packets queue_;
|
||||
};
|
||||
|
||||
class Link : public PacketProcessorListener {
|
||||
public:
|
||||
virtual ~Link() {}
|
||||
|
||||
virtual void AddPacketProcessor(PacketProcessor* processor,
|
||||
ProcessorType type);
|
||||
virtual void RemovePacketProcessor(PacketProcessor* processor);
|
||||
@ -99,3 +94,5 @@ class BweTest {
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_H_
|
||||
|
@ -18,9 +18,6 @@ namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
const int kMinBitrateKbps = 10;
|
||||
const int kMaxBitrateKbps = 20000;
|
||||
|
||||
class DelayCapHelper {
|
||||
public:
|
||||
DelayCapHelper() : max_delay_us_(0), delay_stats_() {}
|
||||
@ -730,353 +727,6 @@ uint32_t PeriodicKeyFrameSource::NextPacketSize(uint32_t frame_size,
|
||||
uint32_t avg_size = (frame_size + fragments - 1) / fragments;
|
||||
return std::min(avg_size, remaining_payload);
|
||||
}
|
||||
|
||||
RembSendSideBwe::RembSendSideBwe(int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock)
|
||||
: bitrate_controller_(
|
||||
BitrateController::CreateBitrateController(clock, false)),
|
||||
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
|
||||
clock_(clock) {
|
||||
assert(kbps >= kMinBitrateKbps);
|
||||
assert(kbps <= kMaxBitrateKbps);
|
||||
bitrate_controller_->SetBitrateObserver(
|
||||
observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps);
|
||||
}
|
||||
|
||||
RembSendSideBwe::~RembSendSideBwe() {
|
||||
}
|
||||
|
||||
void RembSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) {
|
||||
const RembFeedback& remb_feedback =
|
||||
static_cast<const RembFeedback&>(feedback);
|
||||
feedback_observer_->OnReceivedEstimatedBitrate(remb_feedback.estimated_bps());
|
||||
ReportBlockList report_blocks;
|
||||
report_blocks.push_back(remb_feedback.report_block());
|
||||
feedback_observer_->OnReceivedRtcpReceiverReport(
|
||||
report_blocks, 0, clock_->TimeInMilliseconds());
|
||||
bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
int64_t RembSendSideBwe::TimeUntilNextProcess() {
|
||||
return bitrate_controller_->TimeUntilNextProcess();
|
||||
}
|
||||
|
||||
int RembSendSideBwe::Process() {
|
||||
return bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
FullSendSideBwe::FullSendSideBwe(int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock)
|
||||
: bitrate_controller_(
|
||||
BitrateController::CreateBitrateController(clock, false)),
|
||||
rbe_(AbsoluteSendTimeRemoteBitrateEstimatorFactory()
|
||||
.Create(this, clock, kAimdControl, 1000 * kMinBitrateKbps)),
|
||||
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
|
||||
clock_(clock) {
|
||||
assert(kbps >= kMinBitrateKbps);
|
||||
assert(kbps <= kMaxBitrateKbps);
|
||||
bitrate_controller_->SetBitrateObserver(
|
||||
observer, 1000 * kbps, 1000 * kMinBitrateKbps, 1000 * kMaxBitrateKbps);
|
||||
}
|
||||
|
||||
FullSendSideBwe::~FullSendSideBwe() {
|
||||
}
|
||||
|
||||
void FullSendSideBwe::GiveFeedback(const FeedbackPacket& feedback) {
|
||||
const SendSideBweFeedback& fb =
|
||||
static_cast<const SendSideBweFeedback&>(feedback);
|
||||
if (fb.packet_feedback_vector().empty())
|
||||
return;
|
||||
rbe_->IncomingPacketFeedbackVector(fb.packet_feedback_vector());
|
||||
// TODO(holmer): Handle losses in between feedback packets.
|
||||
int expected_packets = fb.packet_feedback_vector().back().sequence_number -
|
||||
fb.packet_feedback_vector().front().sequence_number +
|
||||
1;
|
||||
// Assuming no reordering for now.
|
||||
if (expected_packets <= 0)
|
||||
return;
|
||||
int lost_packets = expected_packets - fb.packet_feedback_vector().size();
|
||||
report_block_.fractionLost = (lost_packets << 8) / expected_packets;
|
||||
report_block_.cumulativeLost += lost_packets;
|
||||
ReportBlockList report_blocks;
|
||||
report_blocks.push_back(report_block_);
|
||||
feedback_observer_->OnReceivedRtcpReceiverReport(
|
||||
report_blocks, 0, clock_->TimeInMilliseconds());
|
||||
bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
void FullSendSideBwe::OnReceiveBitrateChanged(
|
||||
const std::vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) {
|
||||
feedback_observer_->OnReceivedEstimatedBitrate(bitrate);
|
||||
}
|
||||
|
||||
int64_t FullSendSideBwe::TimeUntilNextProcess() {
|
||||
return bitrate_controller_->TimeUntilNextProcess();
|
||||
}
|
||||
|
||||
int FullSendSideBwe::Process() {
|
||||
rbe_->Process();
|
||||
return bitrate_controller_->Process();
|
||||
}
|
||||
|
||||
SendSideBwe* CreateEstimator(BandwidthEstimatorType estimator,
|
||||
int kbps,
|
||||
BitrateObserver* observer,
|
||||
Clock* clock) {
|
||||
switch (estimator) {
|
||||
case kRembEstimator:
|
||||
return new RembSendSideBwe(kbps, observer, clock);
|
||||
case kFullSendSideEstimator:
|
||||
return new FullSendSideBwe(kbps, observer, clock);
|
||||
case kNullEstimator:
|
||||
return new NullSendSideBwe();
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PacketSender::PacketSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator)
|
||||
: PacketProcessor(listener, source->flow_id(), kSender),
|
||||
// For Packet::send_time_us() to be comparable with timestamps from
|
||||
// clock_, the clock of the PacketSender and the Source must be aligned.
|
||||
// We assume that both start at time 0.
|
||||
clock_(0),
|
||||
source_(source),
|
||||
bwe_(CreateEstimator(estimator,
|
||||
source_->bits_per_second() / 1000,
|
||||
this,
|
||||
&clock_)) {
|
||||
modules_.push_back(bwe_.get());
|
||||
}
|
||||
|
||||
PacketSender::~PacketSender() {
|
||||
}
|
||||
|
||||
void PacketSender::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
std::list<FeedbackPacket*> feedbacks =
|
||||
GetFeedbackPackets(in_out, now_ms + time_ms);
|
||||
ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out);
|
||||
}
|
||||
|
||||
void PacketSender::ProcessFeedbackAndGeneratePackets(
|
||||
int64_t time_ms,
|
||||
std::list<FeedbackPacket*>* feedbacks,
|
||||
Packets* generated) {
|
||||
do {
|
||||
// Make sure to at least run Process() below every 100 ms.
|
||||
int64_t time_to_run_ms = std::min<int64_t>(time_ms, 100);
|
||||
if (!feedbacks->empty()) {
|
||||
int64_t time_until_feedback_ms =
|
||||
feedbacks->front()->send_time_us() / 1000 -
|
||||
clock_.TimeInMilliseconds();
|
||||
time_to_run_ms =
|
||||
std::max<int64_t>(std::min(time_ms, time_until_feedback_ms), 0);
|
||||
}
|
||||
source_->RunFor(time_to_run_ms, generated);
|
||||
clock_.AdvanceTimeMilliseconds(time_to_run_ms);
|
||||
if (!feedbacks->empty()) {
|
||||
bwe_->GiveFeedback(*feedbacks->front());
|
||||
delete feedbacks->front();
|
||||
feedbacks->pop_front();
|
||||
}
|
||||
bwe_->Process();
|
||||
time_ms -= time_to_run_ms;
|
||||
} while (time_ms > 0);
|
||||
assert(feedbacks->empty());
|
||||
}
|
||||
|
||||
int PacketSender::GetFeedbackIntervalMs() const {
|
||||
return bwe_->GetFeedbackIntervalMs();
|
||||
}
|
||||
|
||||
std::list<FeedbackPacket*> PacketSender::GetFeedbackPackets(
|
||||
Packets* in_out,
|
||||
int64_t end_time_ms) {
|
||||
std::list<FeedbackPacket*> fb_packets;
|
||||
for (auto it = in_out->begin(); it != in_out->end();) {
|
||||
if ((*it)->send_time_us() > 1000 * end_time_ms)
|
||||
break;
|
||||
if ((*it)->GetPacketType() == Packet::kFeedback &&
|
||||
source()->flow_id() == (*it)->flow_id()) {
|
||||
fb_packets.push_back(static_cast<FeedbackPacket*>(*it));
|
||||
it = in_out->erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return fb_packets;
|
||||
}
|
||||
|
||||
void PacketSender::OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) {
|
||||
source_->SetBitrateBps(target_bitrate_bps);
|
||||
std::stringstream ss;
|
||||
ss << "SendEstimate_" << source_->flow_id() << "#1";
|
||||
BWE_TEST_LOGGING_PLOT(ss.str(), clock_.TimeInMilliseconds(),
|
||||
target_bitrate_bps / 1000);
|
||||
}
|
||||
|
||||
PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator)
|
||||
: PacketSender(listener, source, estimator),
|
||||
pacer_(&clock_,
|
||||
this,
|
||||
source->bits_per_second() / 1000,
|
||||
PacedSender::kDefaultPaceMultiplier * source->bits_per_second() /
|
||||
1000,
|
||||
0) {
|
||||
modules_.push_back(&pacer_);
|
||||
}
|
||||
|
||||
PacedVideoSender::~PacedVideoSender() {
|
||||
for (Packet* packet : pacer_queue_)
|
||||
delete packet;
|
||||
for (Packet* packet : queue_)
|
||||
delete packet;
|
||||
}
|
||||
|
||||
void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms;
|
||||
// Run process periodically to allow the packets to be paced out.
|
||||
std::list<FeedbackPacket*> feedbacks =
|
||||
GetFeedbackPackets(in_out, end_time_ms);
|
||||
int64_t last_run_time_ms = -1;
|
||||
do {
|
||||
int64_t time_until_process_ms = TimeUntilNextProcess(modules_);
|
||||
int64_t time_until_feedback_ms = time_ms;
|
||||
if (!feedbacks.empty())
|
||||
time_until_feedback_ms = feedbacks.front()->send_time_us() / 1000 -
|
||||
clock_.TimeInMilliseconds();
|
||||
|
||||
int64_t time_until_next_event_ms =
|
||||
std::min(time_until_feedback_ms, time_until_process_ms);
|
||||
|
||||
time_until_next_event_ms =
|
||||
std::min(source_->GetTimeUntilNextFrameMs(), time_until_next_event_ms);
|
||||
|
||||
// Never run for longer than we have been asked for.
|
||||
if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms)
|
||||
time_until_next_event_ms = end_time_ms - clock_.TimeInMilliseconds();
|
||||
|
||||
// Make sure we don't get stuck if an event doesn't trigger. This typically
|
||||
// happens if the prober wants to probe, but there's no packet to send.
|
||||
if (time_until_next_event_ms == 0 && last_run_time_ms == 0)
|
||||
time_until_next_event_ms = 1;
|
||||
last_run_time_ms = time_until_next_event_ms;
|
||||
|
||||
Packets generated_packets;
|
||||
source_->RunFor(time_until_next_event_ms, &generated_packets);
|
||||
if (!generated_packets.empty()) {
|
||||
for (Packet* packet : generated_packets) {
|
||||
MediaPacket* media_packet = static_cast<MediaPacket*>(packet);
|
||||
pacer_.SendPacket(PacedSender::kNormalPriority,
|
||||
media_packet->header().ssrc,
|
||||
media_packet->header().sequenceNumber,
|
||||
(media_packet->send_time_us() + 500) / 1000,
|
||||
media_packet->payload_size(), false);
|
||||
pacer_queue_.push_back(packet);
|
||||
assert(pacer_queue_.size() < 10000);
|
||||
}
|
||||
}
|
||||
|
||||
clock_.AdvanceTimeMilliseconds(time_until_next_event_ms);
|
||||
|
||||
if (time_until_next_event_ms == time_until_feedback_ms) {
|
||||
if (!feedbacks.empty()) {
|
||||
bwe_->GiveFeedback(*feedbacks.front());
|
||||
delete feedbacks.front();
|
||||
feedbacks.pop_front();
|
||||
}
|
||||
bwe_->Process();
|
||||
}
|
||||
|
||||
if (time_until_next_event_ms == time_until_process_ms) {
|
||||
CallProcess(modules_);
|
||||
}
|
||||
} while (clock_.TimeInMilliseconds() < end_time_ms);
|
||||
QueuePackets(in_out, end_time_ms * 1000);
|
||||
}
|
||||
|
||||
int64_t PacedVideoSender::TimeUntilNextProcess(
|
||||
const std::list<Module*>& modules) {
|
||||
int64_t time_until_next_process_ms = 10;
|
||||
for (Module* module : modules) {
|
||||
int64_t next_process_ms = module->TimeUntilNextProcess();
|
||||
if (next_process_ms < time_until_next_process_ms)
|
||||
time_until_next_process_ms = next_process_ms;
|
||||
}
|
||||
if (time_until_next_process_ms < 0)
|
||||
time_until_next_process_ms = 0;
|
||||
return time_until_next_process_ms;
|
||||
}
|
||||
|
||||
void PacedVideoSender::CallProcess(const std::list<Module*>& modules) {
|
||||
for (Module* module : modules) {
|
||||
if (module->TimeUntilNextProcess() <= 0) {
|
||||
module->Process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PacedVideoSender::QueuePackets(Packets* batch,
|
||||
int64_t end_of_batch_time_us) {
|
||||
queue_.merge(*batch, DereferencingComparator<Packet>);
|
||||
if (queue_.empty()) {
|
||||
return;
|
||||
}
|
||||
Packets::iterator it = queue_.begin();
|
||||
for (; it != queue_.end(); ++it) {
|
||||
if ((*it)->send_time_us() > end_of_batch_time_us) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Packets to_transfer;
|
||||
to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
|
||||
batch->merge(to_transfer, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
|
||||
uint16_t sequence_number,
|
||||
int64_t capture_time_ms,
|
||||
bool retransmission) {
|
||||
for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end();
|
||||
++it) {
|
||||
MediaPacket* media_packet = static_cast<MediaPacket*>(*it);
|
||||
if (media_packet->header().sequenceNumber == sequence_number) {
|
||||
int64_t pace_out_time_ms = clock_.TimeInMilliseconds();
|
||||
// Make sure a packet is never paced out earlier than when it was put into
|
||||
// the pacer.
|
||||
assert(pace_out_time_ms >= (media_packet->send_time_us() + 500) / 1000);
|
||||
media_packet->SetAbsSendTimeMs(pace_out_time_ms);
|
||||
media_packet->set_send_time_us(1000 * pace_out_time_ms);
|
||||
queue_.push_back(media_packet);
|
||||
pacer_queue_.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t PacedVideoSender::TimeToSendPadding(size_t bytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) {
|
||||
PacketSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
|
||||
pacer_.UpdateBitrate(
|
||||
target_bitrate_bps / 1000,
|
||||
PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, 0);
|
||||
}
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
@ -27,6 +26,7 @@
|
||||
#include "webrtc/modules/pacing/include/paced_sender.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
@ -162,94 +162,6 @@ class Random {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Random);
|
||||
};
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
enum Type { kMedia, kFeedback };
|
||||
|
||||
Packet();
|
||||
Packet(int flow_id, int64_t send_time_us, size_t payload_size);
|
||||
virtual ~Packet();
|
||||
|
||||
virtual bool operator<(const Packet& rhs) const;
|
||||
|
||||
virtual int flow_id() const { return flow_id_; }
|
||||
virtual int64_t creation_time_us() const { return creation_time_us_; }
|
||||
virtual void set_send_time_us(int64_t send_time_us);
|
||||
virtual int64_t send_time_us() const { return send_time_us_; }
|
||||
virtual size_t payload_size() const { return payload_size_; }
|
||||
virtual Packet::Type GetPacketType() const = 0;
|
||||
|
||||
private:
|
||||
int flow_id_;
|
||||
int64_t creation_time_us_; // Time when the packet was created.
|
||||
int64_t send_time_us_; // Time the packet left last processor touching it.
|
||||
size_t payload_size_; // Size of the (non-existent, simulated) payload.
|
||||
};
|
||||
|
||||
class MediaPacket : public Packet {
|
||||
public:
|
||||
MediaPacket();
|
||||
MediaPacket(int flow_id,
|
||||
int64_t send_time_us,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header);
|
||||
MediaPacket(int64_t send_time_us, uint32_t sequence_number);
|
||||
virtual ~MediaPacket() {}
|
||||
|
||||
int64_t GetAbsSendTimeInMs() const;
|
||||
void SetAbsSendTimeMs(int64_t abs_send_time_ms);
|
||||
const RTPHeader& header() const { return header_; }
|
||||
virtual Packet::Type GetPacketType() const { return kMedia; }
|
||||
|
||||
private:
|
||||
RTPHeader header_;
|
||||
};
|
||||
|
||||
class FeedbackPacket : public Packet {
|
||||
public:
|
||||
FeedbackPacket(int flow_id, int64_t send_time_us)
|
||||
: Packet(flow_id, send_time_us, 0) {}
|
||||
virtual ~FeedbackPacket() {}
|
||||
|
||||
virtual Packet::Type GetPacketType() const { return kFeedback; }
|
||||
};
|
||||
|
||||
class RembFeedback : public FeedbackPacket {
|
||||
public:
|
||||
RembFeedback(int flow_id,
|
||||
int64_t send_time_us,
|
||||
uint32_t estimated_bps,
|
||||
RTCPReportBlock report_block);
|
||||
virtual ~RembFeedback() {}
|
||||
|
||||
uint32_t estimated_bps() const { return estimated_bps_; }
|
||||
RTCPReportBlock report_block() const { return report_block_; }
|
||||
|
||||
private:
|
||||
const uint32_t estimated_bps_;
|
||||
const RTCPReportBlock report_block_;
|
||||
};
|
||||
|
||||
class SendSideBweFeedback : public FeedbackPacket {
|
||||
public:
|
||||
typedef std::map<uint16_t, int64_t> ArrivalTimesMap;
|
||||
SendSideBweFeedback(int flow_id,
|
||||
int64_t send_time_us,
|
||||
const std::vector<PacketInfo>& packet_feedback_vector);
|
||||
virtual ~SendSideBweFeedback() {}
|
||||
|
||||
const std::vector<PacketInfo>& packet_feedback_vector() const {
|
||||
return packet_feedback_vector_;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<PacketInfo> packet_feedback_vector_;
|
||||
};
|
||||
|
||||
typedef std::list<Packet*> Packets;
|
||||
typedef std::list<Packet*>::iterator PacketsIt;
|
||||
typedef std::list<Packet*>::const_iterator PacketsConstIt;
|
||||
|
||||
bool IsTimeSorted(const Packets& packets);
|
||||
|
||||
class PacketProcessor;
|
||||
@ -519,172 +431,6 @@ class PeriodicKeyFrameSource : public AdaptiveVideoSource {
|
||||
int compensation_per_frame_;
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSource);
|
||||
};
|
||||
|
||||
class SendSideBwe : public Module {
|
||||
public:
|
||||
SendSideBwe() {}
|
||||
virtual ~SendSideBwe() {}
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const = 0;
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) = 0;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SendSideBwe);
|
||||
};
|
||||
|
||||
class NullSendSideBwe : public SendSideBwe {
|
||||
public:
|
||||
NullSendSideBwe() {}
|
||||
virtual ~NullSendSideBwe() {}
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 1000; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE {}
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
virtual int Process() OVERRIDE { return 0; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NullSendSideBwe);
|
||||
};
|
||||
|
||||
class RembSendSideBwe : public SendSideBwe {
|
||||
public:
|
||||
RembSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock);
|
||||
virtual ~RembSendSideBwe();
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE;
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
||||
virtual int Process() OVERRIDE;
|
||||
|
||||
protected:
|
||||
scoped_ptr<BitrateController> bitrate_controller_;
|
||||
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
|
||||
|
||||
private:
|
||||
Clock* clock_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(RembSendSideBwe);
|
||||
};
|
||||
|
||||
class FullSendSideBwe : public SendSideBwe, public RemoteBitrateObserver {
|
||||
public:
|
||||
FullSendSideBwe(int kbps, BitrateObserver* observer, Clock* clock);
|
||||
virtual ~FullSendSideBwe();
|
||||
|
||||
virtual int GetFeedbackIntervalMs() const OVERRIDE { return 100; }
|
||||
virtual void GiveFeedback(const FeedbackPacket& feedback) OVERRIDE;
|
||||
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) OVERRIDE;
|
||||
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
||||
virtual int Process() OVERRIDE;
|
||||
|
||||
protected:
|
||||
scoped_ptr<BitrateController> bitrate_controller_;
|
||||
scoped_ptr<RemoteBitrateEstimator> rbe_;
|
||||
scoped_ptr<RtcpBandwidthObserver> feedback_observer_;
|
||||
|
||||
private:
|
||||
Clock* const clock_;
|
||||
RTCPReportBlock report_block_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FullSendSideBwe);
|
||||
};
|
||||
|
||||
enum BandwidthEstimatorType {
|
||||
kNullEstimator,
|
||||
kRembEstimator,
|
||||
kFullSendSideEstimator
|
||||
};
|
||||
|
||||
class PacketSender : public PacketProcessor, public BitrateObserver {
|
||||
public:
|
||||
PacketSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator);
|
||||
virtual ~PacketSender();
|
||||
|
||||
// Call GiveFeedback() with the returned interval in milliseconds, provided
|
||||
// there is a new estimate available.
|
||||
// Note that changing the feedback interval affects the timing of when the
|
||||
// output of the estimators is sampled and therefore the baseline files may
|
||||
// have to be regenerated.
|
||||
virtual int GetFeedbackIntervalMs() const;
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
virtual VideoSource* source() const { return source_; }
|
||||
|
||||
// Implements BitrateObserver.
|
||||
virtual void OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) OVERRIDE;
|
||||
|
||||
protected:
|
||||
void ProcessFeedbackAndGeneratePackets(int64_t time_ms,
|
||||
std::list<FeedbackPacket*>* feedbacks,
|
||||
Packets* generated);
|
||||
std::list<FeedbackPacket*> GetFeedbackPackets(Packets* in_out,
|
||||
int64_t end_time_ms);
|
||||
|
||||
SimulatedClock clock_;
|
||||
VideoSource* source_;
|
||||
scoped_ptr<SendSideBwe> bwe_;
|
||||
int64_t start_of_run_ms_;
|
||||
std::list<Module*> modules_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(PacketSender);
|
||||
};
|
||||
|
||||
class PacedVideoSender : public PacketSender, public PacedSender::Callback {
|
||||
public:
|
||||
PacedVideoSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator);
|
||||
virtual ~PacedVideoSender();
|
||||
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
// Implements PacedSender::Callback.
|
||||
virtual bool TimeToSendPacket(uint32_t ssrc,
|
||||
uint16_t sequence_number,
|
||||
int64_t capture_time_ms,
|
||||
bool retransmission) OVERRIDE;
|
||||
virtual size_t TimeToSendPadding(size_t bytes) OVERRIDE;
|
||||
|
||||
// Implements BitrateObserver.
|
||||
virtual void OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) OVERRIDE;
|
||||
|
||||
private:
|
||||
class ProbingPacedSender : public PacedSender {
|
||||
public:
|
||||
ProbingPacedSender(Clock* clock,
|
||||
Callback* callback,
|
||||
int bitrate_kbps,
|
||||
int max_bitrate_kbps,
|
||||
int min_bitrate_kbps)
|
||||
: PacedSender(clock,
|
||||
callback,
|
||||
bitrate_kbps,
|
||||
max_bitrate_kbps,
|
||||
min_bitrate_kbps) {}
|
||||
|
||||
virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; }
|
||||
};
|
||||
|
||||
int64_t TimeUntilNextProcess(const std::list<Module*>& modules);
|
||||
void CallProcess(const std::list<Module*>& modules);
|
||||
void QueuePackets(Packets* batch, int64_t end_of_batch_time_us);
|
||||
|
||||
ProbingPacedSender pacer_;
|
||||
Packets queue_;
|
||||
Packets pacer_queue_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender);
|
||||
};
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
using std::vector;
|
||||
|
116
webrtc/modules/remote_bitrate_estimator/test/packet.h
Normal file
116
webrtc/modules/remote_bitrate_estimator/test/packet.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_
|
||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
enum Type { kMedia, kFeedback };
|
||||
|
||||
Packet();
|
||||
Packet(int flow_id, int64_t send_time_us, size_t payload_size);
|
||||
virtual ~Packet();
|
||||
|
||||
virtual bool operator<(const Packet& rhs) const;
|
||||
|
||||
virtual int flow_id() const { return flow_id_; }
|
||||
virtual int64_t creation_time_us() const { return creation_time_us_; }
|
||||
virtual void set_send_time_us(int64_t send_time_us);
|
||||
virtual int64_t send_time_us() const { return send_time_us_; }
|
||||
virtual size_t payload_size() const { return payload_size_; }
|
||||
virtual Packet::Type GetPacketType() const = 0;
|
||||
|
||||
private:
|
||||
int flow_id_;
|
||||
int64_t creation_time_us_; // Time when the packet was created.
|
||||
int64_t send_time_us_; // Time the packet left last processor touching it.
|
||||
size_t payload_size_; // Size of the (non-existent, simulated) payload.
|
||||
};
|
||||
|
||||
class MediaPacket : public Packet {
|
||||
public:
|
||||
MediaPacket();
|
||||
MediaPacket(int flow_id,
|
||||
int64_t send_time_us,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header);
|
||||
MediaPacket(int64_t send_time_us, uint32_t sequence_number);
|
||||
virtual ~MediaPacket() {}
|
||||
|
||||
int64_t GetAbsSendTimeInMs() const;
|
||||
void SetAbsSendTimeMs(int64_t abs_send_time_ms);
|
||||
const RTPHeader& header() const { return header_; }
|
||||
virtual Packet::Type GetPacketType() const { return kMedia; }
|
||||
|
||||
private:
|
||||
RTPHeader header_;
|
||||
};
|
||||
|
||||
class FeedbackPacket : public Packet {
|
||||
public:
|
||||
FeedbackPacket(int flow_id, int64_t send_time_us)
|
||||
: Packet(flow_id, send_time_us, 0) {}
|
||||
virtual ~FeedbackPacket() {}
|
||||
|
||||
virtual Packet::Type GetPacketType() const { return kFeedback; }
|
||||
};
|
||||
|
||||
class RembFeedback : public FeedbackPacket {
|
||||
public:
|
||||
RembFeedback(int flow_id,
|
||||
int64_t send_time_us,
|
||||
uint32_t estimated_bps,
|
||||
RTCPReportBlock report_block);
|
||||
virtual ~RembFeedback() {}
|
||||
|
||||
uint32_t estimated_bps() const { return estimated_bps_; }
|
||||
RTCPReportBlock report_block() const { return report_block_; }
|
||||
|
||||
private:
|
||||
const uint32_t estimated_bps_;
|
||||
const RTCPReportBlock report_block_;
|
||||
};
|
||||
|
||||
class SendSideBweFeedback : public FeedbackPacket {
|
||||
public:
|
||||
typedef std::map<uint16_t, int64_t> ArrivalTimesMap;
|
||||
SendSideBweFeedback(int flow_id,
|
||||
int64_t send_time_us,
|
||||
const std::vector<PacketInfo>& packet_feedback_vector);
|
||||
virtual ~SendSideBweFeedback() {}
|
||||
|
||||
const std::vector<PacketInfo>& packet_feedback_vector() const {
|
||||
return packet_feedback_vector_;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<PacketInfo> packet_feedback_vector_;
|
||||
};
|
||||
|
||||
typedef std::list<Packet*> Packets;
|
||||
typedef std::list<Packet*>::iterator PacketsIt;
|
||||
typedef std::list<Packet*>::const_iterator PacketsConstIt;
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_H_
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/common.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
PacketReceiver::PacketReceiver(PacketProcessorListener* listener,
|
||||
int flow_id,
|
||||
BandwidthEstimatorType bwe_type,
|
||||
bool plot_delay,
|
||||
bool plot_bwe)
|
||||
: PacketProcessor(listener, flow_id, kReceiver),
|
||||
delay_log_prefix_(),
|
||||
last_delay_plot_ms_(0),
|
||||
plot_delay_(plot_delay),
|
||||
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) {
|
||||
// Setup the prefix ststd::rings used when logging.
|
||||
std::stringstream ss;
|
||||
ss << "Delay_" << flow_id << "#2";
|
||||
delay_log_prefix_ = ss.str();
|
||||
}
|
||||
|
||||
PacketReceiver::~PacketReceiver() {
|
||||
}
|
||||
|
||||
void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
Packets feedback;
|
||||
for (auto it = in_out->begin(); it != in_out->end();) {
|
||||
// PacketReceivers are only associated with a single stream, and therefore
|
||||
// should only process a single flow id.
|
||||
// TODO(holmer): Break this out into a Demuxer which implements both
|
||||
// PacketProcessorListener and PacketProcessor.
|
||||
if ((*it)->GetPacketType() == Packet::kMedia &&
|
||||
(*it)->flow_id() == *flow_ids().begin()) {
|
||||
BWE_TEST_LOGGING_CONTEXT("Receiver");
|
||||
const MediaPacket* media_packet = static_cast<const MediaPacket*>(*it);
|
||||
// We're treating the send time (from previous filter) as the arrival
|
||||
// time once packet reaches the estimator.
|
||||
int64_t arrival_time_ms = (media_packet->send_time_us() + 500) / 1000;
|
||||
BWE_TEST_LOGGING_TIME(arrival_time_ms);
|
||||
PlotDelay(arrival_time_ms,
|
||||
(media_packet->creation_time_us() + 500) / 1000);
|
||||
|
||||
bwe_receiver_->ReceivePacket(arrival_time_ms,
|
||||
media_packet->payload_size(),
|
||||
media_packet->header());
|
||||
FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms);
|
||||
if (fb)
|
||||
feedback.push_back(fb);
|
||||
delete media_packet;
|
||||
it = in_out->erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Insert feedback packets to be sent back to the sender.
|
||||
in_out->merge(feedback, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) {
|
||||
static const int kDelayPlotIntervalMs = 100;
|
||||
if (!plot_delay_)
|
||||
return;
|
||||
if (arrival_time_ms - last_delay_plot_ms_ > kDelayPlotIntervalMs) {
|
||||
BWE_TEST_LOGGING_PLOT(delay_log_prefix_, arrival_time_ms,
|
||||
arrival_time_ms - send_time_ms);
|
||||
last_delay_plot_ms_ = arrival_time_ms;
|
||||
}
|
||||
}
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_
|
||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
class PacketReceiver : public PacketProcessor {
|
||||
public:
|
||||
PacketReceiver(PacketProcessorListener* listener,
|
||||
int flow_id,
|
||||
BandwidthEstimatorType bwe_type,
|
||||
bool plot_delay,
|
||||
bool plot_bwe);
|
||||
~PacketReceiver();
|
||||
|
||||
// Implements PacketProcessor.
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
void LogStats();
|
||||
|
||||
protected:
|
||||
void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms);
|
||||
|
||||
int64_t now_ms_;
|
||||
std::string delay_log_prefix_;
|
||||
int64_t last_delay_plot_ms_;
|
||||
bool plot_delay_;
|
||||
scoped_ptr<BweReceiver> bwe_receiver_;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
|
||||
};
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_RECEIVER_H_
|
264
webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc
Normal file
264
webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_sender.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
PacketSender::PacketSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator)
|
||||
: PacketProcessor(listener, source->flow_id(), kSender),
|
||||
// For Packet::send_time_us() to be comparable with timestamps from
|
||||
// clock_, the clock of the PacketSender and the Source must be aligned.
|
||||
// We assume that both start at time 0.
|
||||
clock_(0),
|
||||
source_(source),
|
||||
bwe_(CreateBweSender(estimator,
|
||||
source_->bits_per_second() / 1000,
|
||||
this,
|
||||
&clock_)) {
|
||||
modules_.push_back(bwe_.get());
|
||||
}
|
||||
|
||||
PacketSender::~PacketSender() {
|
||||
}
|
||||
|
||||
void PacketSender::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
std::list<FeedbackPacket*> feedbacks =
|
||||
GetFeedbackPackets(in_out, now_ms + time_ms);
|
||||
ProcessFeedbackAndGeneratePackets(time_ms, &feedbacks, in_out);
|
||||
}
|
||||
|
||||
void PacketSender::ProcessFeedbackAndGeneratePackets(
|
||||
int64_t time_ms,
|
||||
std::list<FeedbackPacket*>* feedbacks,
|
||||
Packets* generated) {
|
||||
do {
|
||||
// Make sure to at least run Process() below every 100 ms.
|
||||
int64_t time_to_run_ms = std::min<int64_t>(time_ms, 100);
|
||||
if (!feedbacks->empty()) {
|
||||
int64_t time_until_feedback_ms =
|
||||
feedbacks->front()->send_time_us() / 1000 -
|
||||
clock_.TimeInMilliseconds();
|
||||
time_to_run_ms =
|
||||
std::max<int64_t>(std::min(time_ms, time_until_feedback_ms), 0);
|
||||
}
|
||||
source_->RunFor(time_to_run_ms, generated);
|
||||
clock_.AdvanceTimeMilliseconds(time_to_run_ms);
|
||||
if (!feedbacks->empty()) {
|
||||
bwe_->GiveFeedback(*feedbacks->front());
|
||||
delete feedbacks->front();
|
||||
feedbacks->pop_front();
|
||||
}
|
||||
bwe_->Process();
|
||||
time_ms -= time_to_run_ms;
|
||||
} while (time_ms > 0);
|
||||
assert(feedbacks->empty());
|
||||
}
|
||||
|
||||
int PacketSender::GetFeedbackIntervalMs() const {
|
||||
return bwe_->GetFeedbackIntervalMs();
|
||||
}
|
||||
|
||||
std::list<FeedbackPacket*> PacketSender::GetFeedbackPackets(
|
||||
Packets* in_out,
|
||||
int64_t end_time_ms) {
|
||||
std::list<FeedbackPacket*> fb_packets;
|
||||
for (auto it = in_out->begin(); it != in_out->end();) {
|
||||
if ((*it)->send_time_us() > 1000 * end_time_ms)
|
||||
break;
|
||||
if ((*it)->GetPacketType() == Packet::kFeedback &&
|
||||
source()->flow_id() == (*it)->flow_id()) {
|
||||
fb_packets.push_back(static_cast<FeedbackPacket*>(*it));
|
||||
it = in_out->erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return fb_packets;
|
||||
}
|
||||
|
||||
void PacketSender::OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) {
|
||||
source_->SetBitrateBps(target_bitrate_bps);
|
||||
std::stringstream ss;
|
||||
ss << "SendEstimate_" << source_->flow_id() << "#1";
|
||||
BWE_TEST_LOGGING_PLOT(ss.str(), clock_.TimeInMilliseconds(),
|
||||
target_bitrate_bps / 1000);
|
||||
}
|
||||
|
||||
PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator)
|
||||
: PacketSender(listener, source, estimator),
|
||||
pacer_(&clock_,
|
||||
this,
|
||||
source->bits_per_second() / 1000,
|
||||
PacedSender::kDefaultPaceMultiplier * source->bits_per_second() /
|
||||
1000,
|
||||
0) {
|
||||
modules_.push_back(&pacer_);
|
||||
}
|
||||
|
||||
PacedVideoSender::~PacedVideoSender() {
|
||||
for (Packet* packet : pacer_queue_)
|
||||
delete packet;
|
||||
for (Packet* packet : queue_)
|
||||
delete packet;
|
||||
}
|
||||
|
||||
void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms;
|
||||
// Run process periodically to allow the packets to be paced out.
|
||||
std::list<FeedbackPacket*> feedbacks =
|
||||
GetFeedbackPackets(in_out, end_time_ms);
|
||||
int64_t last_run_time_ms = -1;
|
||||
do {
|
||||
int64_t time_until_process_ms = TimeUntilNextProcess(modules_);
|
||||
int64_t time_until_feedback_ms = time_ms;
|
||||
if (!feedbacks.empty())
|
||||
time_until_feedback_ms = feedbacks.front()->send_time_us() / 1000 -
|
||||
clock_.TimeInMilliseconds();
|
||||
|
||||
int64_t time_until_next_event_ms =
|
||||
std::min(time_until_feedback_ms, time_until_process_ms);
|
||||
|
||||
time_until_next_event_ms =
|
||||
std::min(source_->GetTimeUntilNextFrameMs(), time_until_next_event_ms);
|
||||
|
||||
// Never run for longer than we have been asked for.
|
||||
if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms)
|
||||
time_until_next_event_ms = end_time_ms - clock_.TimeInMilliseconds();
|
||||
|
||||
// Make sure we don't get stuck if an event doesn't trigger. This typically
|
||||
// happens if the prober wants to probe, but there's no packet to send.
|
||||
if (time_until_next_event_ms == 0 && last_run_time_ms == 0)
|
||||
time_until_next_event_ms = 1;
|
||||
last_run_time_ms = time_until_next_event_ms;
|
||||
|
||||
Packets generated_packets;
|
||||
source_->RunFor(time_until_next_event_ms, &generated_packets);
|
||||
if (!generated_packets.empty()) {
|
||||
for (Packet* packet : generated_packets) {
|
||||
MediaPacket* media_packet = static_cast<MediaPacket*>(packet);
|
||||
pacer_.SendPacket(PacedSender::kNormalPriority,
|
||||
media_packet->header().ssrc,
|
||||
media_packet->header().sequenceNumber,
|
||||
(media_packet->send_time_us() + 500) / 1000,
|
||||
media_packet->payload_size(), false);
|
||||
pacer_queue_.push_back(packet);
|
||||
assert(pacer_queue_.size() < 10000);
|
||||
}
|
||||
}
|
||||
|
||||
clock_.AdvanceTimeMilliseconds(time_until_next_event_ms);
|
||||
|
||||
if (time_until_next_event_ms == time_until_feedback_ms) {
|
||||
if (!feedbacks.empty()) {
|
||||
bwe_->GiveFeedback(*feedbacks.front());
|
||||
delete feedbacks.front();
|
||||
feedbacks.pop_front();
|
||||
}
|
||||
bwe_->Process();
|
||||
}
|
||||
|
||||
if (time_until_next_event_ms == time_until_process_ms) {
|
||||
CallProcess(modules_);
|
||||
}
|
||||
} while (clock_.TimeInMilliseconds() < end_time_ms);
|
||||
QueuePackets(in_out, end_time_ms * 1000);
|
||||
}
|
||||
|
||||
int64_t PacedVideoSender::TimeUntilNextProcess(
|
||||
const std::list<Module*>& modules) {
|
||||
int64_t time_until_next_process_ms = 10;
|
||||
for (Module* module : modules) {
|
||||
int64_t next_process_ms = module->TimeUntilNextProcess();
|
||||
if (next_process_ms < time_until_next_process_ms)
|
||||
time_until_next_process_ms = next_process_ms;
|
||||
}
|
||||
if (time_until_next_process_ms < 0)
|
||||
time_until_next_process_ms = 0;
|
||||
return time_until_next_process_ms;
|
||||
}
|
||||
|
||||
void PacedVideoSender::CallProcess(const std::list<Module*>& modules) {
|
||||
for (Module* module : modules) {
|
||||
if (module->TimeUntilNextProcess() <= 0) {
|
||||
module->Process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PacedVideoSender::QueuePackets(Packets* batch,
|
||||
int64_t end_of_batch_time_us) {
|
||||
queue_.merge(*batch, DereferencingComparator<Packet>);
|
||||
if (queue_.empty()) {
|
||||
return;
|
||||
}
|
||||
Packets::iterator it = queue_.begin();
|
||||
for (; it != queue_.end(); ++it) {
|
||||
if ((*it)->send_time_us() > end_of_batch_time_us) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Packets to_transfer;
|
||||
to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
|
||||
batch->merge(to_transfer, DereferencingComparator<Packet>);
|
||||
}
|
||||
|
||||
bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
|
||||
uint16_t sequence_number,
|
||||
int64_t capture_time_ms,
|
||||
bool retransmission) {
|
||||
for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end();
|
||||
++it) {
|
||||
MediaPacket* media_packet = static_cast<MediaPacket*>(*it);
|
||||
if (media_packet->header().sequenceNumber == sequence_number) {
|
||||
int64_t pace_out_time_ms = clock_.TimeInMilliseconds();
|
||||
// Make sure a packet is never paced out earlier than when it was put into
|
||||
// the pacer.
|
||||
assert(pace_out_time_ms >= (media_packet->send_time_us() + 500) / 1000);
|
||||
media_packet->SetAbsSendTimeMs(pace_out_time_ms);
|
||||
media_packet->set_send_time_us(1000 * pace_out_time_ms);
|
||||
queue_.push_back(media_packet);
|
||||
pacer_queue_.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t PacedVideoSender::TimeToSendPadding(size_t bytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) {
|
||||
PacketSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
|
||||
pacer_.UpdateBitrate(
|
||||
target_bitrate_bps / 1000,
|
||||
PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, 0);
|
||||
}
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
117
webrtc/modules/remote_bitrate_estimator/test/packet_sender.h
Normal file
117
webrtc/modules/remote_bitrate_estimator/test/packet_sender.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_
|
||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/interface/module.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
class PacketSender : public PacketProcessor, public BitrateObserver {
|
||||
public:
|
||||
PacketSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator);
|
||||
virtual ~PacketSender();
|
||||
|
||||
// Call GiveFeedback() with the returned interval in milliseconds, provided
|
||||
// there is a new estimate available.
|
||||
// Note that changing the feedback interval affects the timing of when the
|
||||
// output of the estimators is sampled and therefore the baseline files may
|
||||
// have to be regenerated.
|
||||
virtual int GetFeedbackIntervalMs() const;
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
virtual VideoSource* source() const { return source_; }
|
||||
|
||||
// Implements BitrateObserver.
|
||||
virtual void OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) OVERRIDE;
|
||||
|
||||
protected:
|
||||
void ProcessFeedbackAndGeneratePackets(int64_t time_ms,
|
||||
std::list<FeedbackPacket*>* feedbacks,
|
||||
Packets* generated);
|
||||
std::list<FeedbackPacket*> GetFeedbackPackets(Packets* in_out,
|
||||
int64_t end_time_ms);
|
||||
|
||||
SimulatedClock clock_;
|
||||
VideoSource* source_;
|
||||
scoped_ptr<SendSideBwe> bwe_;
|
||||
int64_t start_of_run_ms_;
|
||||
std::list<Module*> modules_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(PacketSender);
|
||||
};
|
||||
|
||||
class PacedVideoSender : public PacketSender, public PacedSender::Callback {
|
||||
public:
|
||||
PacedVideoSender(PacketProcessorListener* listener,
|
||||
VideoSource* source,
|
||||
BandwidthEstimatorType estimator);
|
||||
virtual ~PacedVideoSender();
|
||||
|
||||
virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE;
|
||||
|
||||
// Implements PacedSender::Callback.
|
||||
virtual bool TimeToSendPacket(uint32_t ssrc,
|
||||
uint16_t sequence_number,
|
||||
int64_t capture_time_ms,
|
||||
bool retransmission) OVERRIDE;
|
||||
virtual size_t TimeToSendPadding(size_t bytes) OVERRIDE;
|
||||
|
||||
// Implements BitrateObserver.
|
||||
virtual void OnNetworkChanged(uint32_t target_bitrate_bps,
|
||||
uint8_t fraction_lost,
|
||||
int64_t rtt) OVERRIDE;
|
||||
|
||||
private:
|
||||
class ProbingPacedSender : public PacedSender {
|
||||
public:
|
||||
ProbingPacedSender(Clock* clock,
|
||||
Callback* callback,
|
||||
int bitrate_kbps,
|
||||
int max_bitrate_kbps,
|
||||
int min_bitrate_kbps)
|
||||
: PacedSender(clock,
|
||||
callback,
|
||||
bitrate_kbps,
|
||||
max_bitrate_kbps,
|
||||
min_bitrate_kbps) {}
|
||||
|
||||
virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; }
|
||||
};
|
||||
|
||||
int64_t TimeUntilNextProcess(const std::list<Module*>& modules);
|
||||
void CallProcess(const std::list<Module*>& modules);
|
||||
void QueuePackets(Packets* batch, int64_t end_of_batch_time_us);
|
||||
|
||||
ProbingPacedSender pacer_;
|
||||
Packets queue_;
|
||||
Packets pacer_queue_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PacedVideoSender);
|
||||
};
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_
|
Loading…
x
Reference in New Issue
Block a user