Break out unittest helpers for remote_bitrate_estimator.
BUG= Review URL: https://webrtc-codereview.appspot.com/934012 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3056 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -62,6 +62,8 @@
|
|||||||
'include/mock/mock_remote_bitrate_observer.h',
|
'include/mock/mock_remote_bitrate_observer.h',
|
||||||
'bitrate_estimator_unittest.cc',
|
'bitrate_estimator_unittest.cc',
|
||||||
'remote_bitrate_estimator_unittest.cc',
|
'remote_bitrate_estimator_unittest.cc',
|
||||||
|
'remote_bitrate_estimator_unittest_helper.cc',
|
||||||
|
'remote_bitrate_estimator_unittest_helper.h',
|
||||||
'rtp_to_ntp_unittest.cc',
|
'rtp_to_ntp_unittest.cc',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -16,380 +16,12 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||||
|
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h"
|
||||||
#include "system_wrappers/interface/constructor_magic.h"
|
#include "system_wrappers/interface/constructor_magic.h"
|
||||||
#include "system_wrappers/interface/scoped_ptr.h"
|
#include "system_wrappers/interface/scoped_ptr.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
enum { kMtu = 1200 };
|
|
||||||
|
|
||||||
class TestBitrateObserver : public RemoteBitrateObserver {
|
|
||||||
public:
|
|
||||||
TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
|
|
||||||
|
|
||||||
void OnReceiveBitrateChanged(unsigned int bitrate) {
|
|
||||||
latest_bitrate_ = bitrate;
|
|
||||||
updated_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
updated_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool updated() const {
|
|
||||||
return updated_;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int latest_bitrate() const {
|
|
||||||
return latest_bitrate_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool updated_;
|
|
||||||
unsigned int latest_bitrate_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RtpStream {
|
|
||||||
public:
|
|
||||||
struct RtpPacket {
|
|
||||||
int64_t send_time;
|
|
||||||
int64_t arrival_time;
|
|
||||||
uint32_t rtp_timestamp;
|
|
||||||
unsigned int size;
|
|
||||||
unsigned int ssrc;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RtcpPacket {
|
|
||||||
uint32_t ntp_secs;
|
|
||||||
uint32_t ntp_frac;
|
|
||||||
uint32_t timestamp;
|
|
||||||
unsigned int ssrc;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<RtpPacket*> PacketList;
|
|
||||||
|
|
||||||
enum { kSendSideOffsetMs = 1000 };
|
|
||||||
|
|
||||||
RtpStream(int fps, int bitrate_bps, unsigned int ssrc, unsigned int frequency,
|
|
||||||
uint32_t timestamp_offset, int64_t rtcp_receive_time)
|
|
||||||
: fps_(fps),
|
|
||||||
bitrate_bps_(bitrate_bps),
|
|
||||||
ssrc_(ssrc),
|
|
||||||
frequency_(frequency),
|
|
||||||
next_rtp_time_(0),
|
|
||||||
next_rtcp_time_(rtcp_receive_time),
|
|
||||||
rtp_timestamp_offset_(timestamp_offset),
|
|
||||||
kNtpFracPerMs(4.294967296E6) {
|
|
||||||
assert(fps_ > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_rtp_timestamp_offset(uint32_t offset) {
|
|
||||||
rtp_timestamp_offset_ = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a new frame for this stream. If called too soon after the
|
|
||||||
// previous frame, no frame will be generated. The frame is split into
|
|
||||||
// packets.
|
|
||||||
int64_t GenerateFrame(double time_now, PacketList* packets) {
|
|
||||||
if (time_now < next_rtp_time_) {
|
|
||||||
return next_rtp_time_;
|
|
||||||
}
|
|
||||||
assert(packets != NULL);
|
|
||||||
int bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_;
|
|
||||||
int n_packets = std::max((bits_per_frame + 8 * kMtu) / (8 * kMtu), 1);
|
|
||||||
int packet_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets);
|
|
||||||
assert(n_packets >= 0);
|
|
||||||
for (int i = 0; i < n_packets; ++i) {
|
|
||||||
RtpPacket* packet = new RtpPacket;
|
|
||||||
packet->send_time = time_now + kSendSideOffsetMs + 0.5f;
|
|
||||||
packet->size = packet_size;
|
|
||||||
packet->rtp_timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
|
|
||||||
(frequency_ / 1000.0) * packet->send_time + 0.5);
|
|
||||||
packet->ssrc = ssrc_;
|
|
||||||
packets->push_back(packet);
|
|
||||||
}
|
|
||||||
next_rtp_time_ = time_now + 1000.0 / static_cast<double>(fps_);
|
|
||||||
return next_rtp_time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The send-side time when the next frame can be generated.
|
|
||||||
double next_rtp_time() const {
|
|
||||||
return next_rtp_time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates an RTCP packet.
|
|
||||||
RtcpPacket* Rtcp(double time_now) {
|
|
||||||
if (time_now < next_rtcp_time_) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
RtcpPacket* rtcp = new RtcpPacket;
|
|
||||||
int64_t send_time = RtpStream::kSendSideOffsetMs + time_now + 0.5;
|
|
||||||
rtcp->timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
|
|
||||||
(frequency_ / 1000.0) * send_time + 0.5);
|
|
||||||
rtcp->ntp_secs = send_time / 1000;
|
|
||||||
rtcp->ntp_frac = (send_time % 1000) * kNtpFracPerMs;
|
|
||||||
rtcp->ssrc = ssrc_;
|
|
||||||
next_rtcp_time_ = time_now + kRtcpIntervalMs;
|
|
||||||
return rtcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_bitrate_bps(int bitrate_bps) {
|
|
||||||
ASSERT_GE(bitrate_bps, 0);
|
|
||||||
bitrate_bps_ = bitrate_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bitrate_bps() const {
|
|
||||||
return bitrate_bps_;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ssrc() const {
|
|
||||||
return ssrc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Compare(const std::pair<unsigned int, RtpStream*>& left,
|
|
||||||
const std::pair<unsigned int, RtpStream*>& right) {
|
|
||||||
return left.second->next_rtp_time_ < right.second->next_rtp_time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { kRtcpIntervalMs = 1000 };
|
|
||||||
|
|
||||||
int fps_;
|
|
||||||
int bitrate_bps_;
|
|
||||||
unsigned int ssrc_;
|
|
||||||
unsigned int frequency_;
|
|
||||||
double next_rtp_time_;
|
|
||||||
double next_rtcp_time_;
|
|
||||||
uint32_t rtp_timestamp_offset_;
|
|
||||||
const double kNtpFracPerMs;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RtpStream);
|
|
||||||
};
|
|
||||||
|
|
||||||
class StreamGenerator {
|
|
||||||
public:
|
|
||||||
typedef std::list<RtpStream::RtcpPacket*> RtcpList;
|
|
||||||
|
|
||||||
StreamGenerator(int capacity, double time_now)
|
|
||||||
: capacity_(capacity),
|
|
||||||
prev_arrival_time_(time_now) {}
|
|
||||||
|
|
||||||
~StreamGenerator() {
|
|
||||||
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
|
||||||
++it) {
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
streams_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new stream.
|
|
||||||
void AddStream(RtpStream* stream) {
|
|
||||||
streams_[stream->ssrc()] = stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the link capacity.
|
|
||||||
void set_capacity_bps(int capacity_bps) {
|
|
||||||
ASSERT_GT(capacity_bps, 0);
|
|
||||||
capacity_ = capacity_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
|
|
||||||
// is decided by the initial allocation ratios.
|
|
||||||
void set_bitrate_bps(int bitrate_bps) {
|
|
||||||
ASSERT_GE(streams_.size(), 0u);
|
|
||||||
double total_bitrate_before = 0;
|
|
||||||
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
|
||||||
++it) {
|
|
||||||
total_bitrate_before += it->second->bitrate_bps();
|
|
||||||
}
|
|
||||||
int total_bitrate_after = 0;
|
|
||||||
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
|
||||||
++it) {
|
|
||||||
double ratio = it->second->bitrate_bps() / total_bitrate_before;
|
|
||||||
it->second->set_bitrate_bps(ratio * bitrate_bps + 0.5);
|
|
||||||
total_bitrate_after += it->second->bitrate_bps();
|
|
||||||
}
|
|
||||||
EXPECT_NEAR(total_bitrate_after, bitrate_bps, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the RTP timestamp offset for the stream identified by |ssrc|.
|
|
||||||
void set_rtp_timestamp_offset(unsigned int ssrc, uint32_t offset) {
|
|
||||||
streams_[ssrc]->set_rtp_timestamp_offset(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(holmer): Break out the channel simulation part from this class to make
|
|
||||||
// it possible to simulate different types of channels.
|
|
||||||
double GenerateFrame(RtpStream::PacketList* packets, double time_now) {
|
|
||||||
assert(packets != NULL);
|
|
||||||
assert(packets->empty());
|
|
||||||
assert(capacity_ > 0);
|
|
||||||
StreamMap::iterator it = std::min_element(streams_.begin(), streams_.end(),
|
|
||||||
RtpStream::Compare);
|
|
||||||
(*it).second->GenerateFrame(time_now, packets);
|
|
||||||
for (RtpStream::PacketList::iterator packet_it = packets->begin();
|
|
||||||
packet_it != packets->end(); ++packet_it) {
|
|
||||||
int required_network_time =
|
|
||||||
(8 * 1000 * (*packet_it)->size + capacity_ / 2) / capacity_;
|
|
||||||
prev_arrival_time_ = std::max(time_now + required_network_time,
|
|
||||||
prev_arrival_time_ + required_network_time);
|
|
||||||
(*packet_it)->arrival_time = prev_arrival_time_ + 0.5;
|
|
||||||
}
|
|
||||||
it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
|
|
||||||
return (*it).second->next_rtp_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rtcps(RtcpList* rtcps, double time_now) const {
|
|
||||||
for (StreamMap::const_iterator it = streams_.begin(); it != streams_.end();
|
|
||||||
++it) {
|
|
||||||
RtpStream::RtcpPacket* rtcp = it->second->Rtcp(time_now);
|
|
||||||
if (rtcp) {
|
|
||||||
rtcps->push_front(rtcp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::map<unsigned int, RtpStream*> StreamMap;
|
|
||||||
|
|
||||||
// Capacity of the simulated channel in bits per second.
|
|
||||||
int capacity_;
|
|
||||||
// The time when the last packet arrived.
|
|
||||||
double prev_arrival_time_;
|
|
||||||
// All streams being transmitted on this simulated channel.
|
|
||||||
StreamMap streams_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(StreamGenerator);
|
|
||||||
};
|
|
||||||
|
|
||||||
class RemoteBitrateEstimatorTest : public ::testing::Test {
|
|
||||||
public:
|
|
||||||
RemoteBitrateEstimatorTest()
|
|
||||||
: time_now_(0.0),
|
|
||||||
align_streams_(false) {}
|
|
||||||
explicit RemoteBitrateEstimatorTest(bool align_streams)
|
|
||||||
: time_now_(0.0),
|
|
||||||
align_streams_(align_streams) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
bitrate_observer_.reset(new TestBitrateObserver);
|
|
||||||
bitrate_estimator_.reset(
|
|
||||||
RemoteBitrateEstimator::Create(
|
|
||||||
bitrate_observer_.get(),
|
|
||||||
over_use_detector_options_,
|
|
||||||
RemoteBitrateEstimator::kSingleStreamEstimation));
|
|
||||||
stream_generator_.reset(new StreamGenerator(1e6, // Capacity.
|
|
||||||
time_now_));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddDefaultStream() {
|
|
||||||
stream_generator_->AddStream(new RtpStream(
|
|
||||||
30, // Frames per second.
|
|
||||||
3e5, // Bitrate.
|
|
||||||
1, // SSRC.
|
|
||||||
90000, // RTP frequency.
|
|
||||||
0xFFFFF000, // Timestamp offset.
|
|
||||||
0)); // RTCP receive time.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a frame of packets belonging to a stream at a given bitrate and
|
|
||||||
// with a given ssrc. The stream is pushed through a very simple simulated
|
|
||||||
// network, and is then given to the receive-side bandwidth estimator.
|
|
||||||
// Returns true if an over-use was seen, false otherwise.
|
|
||||||
// The StreamGenerator::updated() should be used to check for any changes in
|
|
||||||
// target bitrate after the call to this function.
|
|
||||||
bool GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps) {
|
|
||||||
stream_generator_->set_bitrate_bps(bitrate_bps);
|
|
||||||
RtpStream::PacketList packets;
|
|
||||||
time_now_ = stream_generator_->GenerateFrame(&packets, time_now_);
|
|
||||||
int64_t last_arrival_time = -1;
|
|
||||||
bool prev_was_decrease = false;
|
|
||||||
bool overuse = false;
|
|
||||||
while (!packets.empty()) {
|
|
||||||
RtpStream::RtpPacket* packet = packets.front();
|
|
||||||
if (align_streams_) {
|
|
||||||
StreamGenerator::RtcpList rtcps;
|
|
||||||
stream_generator_->Rtcps(&rtcps, time_now_);
|
|
||||||
for (StreamGenerator::RtcpList::iterator it = rtcps.begin();
|
|
||||||
it != rtcps.end(); ++it) {
|
|
||||||
bitrate_estimator_->IncomingRtcp((*it)->ssrc,
|
|
||||||
(*it)->ntp_secs,
|
|
||||||
(*it)->ntp_frac,
|
|
||||||
(*it)->timestamp);
|
|
||||||
delete *it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitrate_observer_->Reset();
|
|
||||||
bitrate_estimator_->IncomingPacket(packet->ssrc,
|
|
||||||
packet->size,
|
|
||||||
packet->arrival_time,
|
|
||||||
packet->rtp_timestamp);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
// Verify that new estimates only are triggered by an overuse and a
|
|
||||||
// rate decrease.
|
|
||||||
overuse = true;
|
|
||||||
EXPECT_LE(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
|
||||||
EXPECT_FALSE(prev_was_decrease);
|
|
||||||
prev_was_decrease = true;
|
|
||||||
} else {
|
|
||||||
prev_was_decrease = false;
|
|
||||||
}
|
|
||||||
last_arrival_time = packet->arrival_time;
|
|
||||||
delete packet;
|
|
||||||
packets.pop_front();
|
|
||||||
}
|
|
||||||
EXPECT_GT(last_arrival_time, -1);
|
|
||||||
bitrate_estimator_->UpdateEstimate(ssrc, last_arrival_time);
|
|
||||||
return overuse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the bandwidth estimator with a stream of |number_of_frames| frames.
|
|
||||||
// Can for instance be used to run the estimator for some time to get it
|
|
||||||
// into a steady state.
|
|
||||||
unsigned int SteadyStateRun(unsigned int ssrc,
|
|
||||||
int number_of_frames,
|
|
||||||
unsigned int start_bitrate,
|
|
||||||
unsigned int min_bitrate,
|
|
||||||
unsigned int max_bitrate) {
|
|
||||||
unsigned int bitrate_bps = start_bitrate;
|
|
||||||
bool bitrate_update_seen = false;
|
|
||||||
// Produce |number_of_frames| frames and give them to the estimator.
|
|
||||||
for (int i = 0; i < number_of_frames; ++i) {
|
|
||||||
bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps);
|
|
||||||
if (overuse) {
|
|
||||||
EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate);
|
|
||||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate);
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
bitrate_update_seen = true;
|
|
||||||
} else if (bitrate_observer_->updated()) {
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
bitrate_observer_->Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(bitrate_update_seen);
|
|
||||||
return bitrate_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned int kDefaultSsrc = 1;
|
|
||||||
|
|
||||||
double time_now_; // Current time at the receiver.
|
|
||||||
OverUseDetectorOptions over_use_detector_options_;
|
|
||||||
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
|
||||||
scoped_ptr<TestBitrateObserver> bitrate_observer_;
|
|
||||||
scoped_ptr<StreamGenerator> stream_generator_;
|
|
||||||
const bool align_streams_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTest);
|
|
||||||
};
|
|
||||||
|
|
||||||
class RemoteBitrateEstimatorTestAlign : public RemoteBitrateEstimatorTest {
|
|
||||||
public:
|
|
||||||
RemoteBitrateEstimatorTestAlign() : RemoteBitrateEstimatorTest(true) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTestAlign);
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) {
|
TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) {
|
||||||
unsigned int bitrate_bps = 0;
|
unsigned int bitrate_bps = 0;
|
||||||
int64_t time_now = 0;
|
int64_t time_now = 0;
|
||||||
@ -593,7 +225,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, TwoStreamsCapacityDropWithWrap) {
|
|||||||
const int kMinExpectedBitrate = 800e3;
|
const int kMinExpectedBitrate = 800e3;
|
||||||
const int kMaxExpectedBitrate = 1100e3;
|
const int kMaxExpectedBitrate = 1100e3;
|
||||||
const int kSteadyStateTime = 7; // Seconds.
|
const int kSteadyStateTime = 7; // Seconds.
|
||||||
stream_generator_->AddStream(new RtpStream(
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
30, // Frames per second.
|
30, // Frames per second.
|
||||||
kStartBitrate/2, // Bitrate.
|
kStartBitrate/2, // Bitrate.
|
||||||
1, // SSRC.
|
1, // SSRC.
|
||||||
@ -601,7 +233,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, TwoStreamsCapacityDropWithWrap) {
|
|||||||
0xFFFFF000, // Timestamp offset.
|
0xFFFFF000, // Timestamp offset.
|
||||||
0)); // RTCP receive time.
|
0)); // RTCP receive time.
|
||||||
|
|
||||||
stream_generator_->AddStream(new RtpStream(
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
15, // Frames per second.
|
15, // Frames per second.
|
||||||
kStartBitrate/2, // Bitrate.
|
kStartBitrate/2, // Bitrate.
|
||||||
2, // SSRC.
|
2, // SSRC.
|
||||||
@ -646,7 +278,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
|
|||||||
const int kMinExpectedBitrate = 800e3;
|
const int kMinExpectedBitrate = 800e3;
|
||||||
const int kMaxExpectedBitrate = 1100e3;
|
const int kMaxExpectedBitrate = 1100e3;
|
||||||
const int kSteadyStateTime = 11; // Seconds.
|
const int kSteadyStateTime = 11; // Seconds.
|
||||||
stream_generator_->AddStream(new RtpStream(
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
30, // Frames per second.
|
30, // Frames per second.
|
||||||
kStartBitrate/2, // Bitrate.
|
kStartBitrate/2, // Bitrate.
|
||||||
1, // SSRC.
|
1, // SSRC.
|
||||||
@ -654,7 +286,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
|
|||||||
0xFFFFF000, // Timestamp offset.
|
0xFFFFF000, // Timestamp offset.
|
||||||
0)); // RTCP receive time.
|
0)); // RTCP receive time.
|
||||||
|
|
||||||
stream_generator_->AddStream(new RtpStream(
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
30, // Frames per second.
|
30, // Frames per second.
|
||||||
kStartBitrate/3, // Bitrate.
|
kStartBitrate/3, // Bitrate.
|
||||||
2, // SSRC.
|
2, // SSRC.
|
||||||
@ -662,7 +294,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
|
|||||||
0x00000FFF, // Timestamp offset.
|
0x00000FFF, // Timestamp offset.
|
||||||
0)); // RTCP receive time.
|
0)); // RTCP receive time.
|
||||||
|
|
||||||
stream_generator_->AddStream(new RtpStream(
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
30, // Frames per second.
|
30, // Frames per second.
|
||||||
kStartBitrate/6, // Bitrate.
|
kStartBitrate/6, // Bitrate.
|
||||||
3, // SSRC.
|
3, // SSRC.
|
||||||
|
@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 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/remote_bitrate_estimator_unittest_helper.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
RtpStream::RtpStream(int fps,
|
||||||
|
int bitrate_bps,
|
||||||
|
unsigned int ssrc,
|
||||||
|
unsigned int frequency,
|
||||||
|
uint32_t timestamp_offset,
|
||||||
|
int64_t rtcp_receive_time)
|
||||||
|
: fps_(fps),
|
||||||
|
bitrate_bps_(bitrate_bps),
|
||||||
|
ssrc_(ssrc),
|
||||||
|
frequency_(frequency),
|
||||||
|
next_rtp_time_(0),
|
||||||
|
next_rtcp_time_(rtcp_receive_time),
|
||||||
|
rtp_timestamp_offset_(timestamp_offset),
|
||||||
|
kNtpFracPerMs(4.294967296E6) {
|
||||||
|
assert(fps_ > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpStream::set_rtp_timestamp_offset(uint32_t offset) {
|
||||||
|
rtp_timestamp_offset_ = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a new frame for this stream. If called too soon after the
|
||||||
|
// previous frame, no frame will be generated. The frame is split into
|
||||||
|
// packets.
|
||||||
|
int64_t RtpStream::GenerateFrame(double time_now, PacketList* packets) {
|
||||||
|
if (time_now < next_rtp_time_) {
|
||||||
|
return next_rtp_time_;
|
||||||
|
}
|
||||||
|
assert(packets != NULL);
|
||||||
|
int bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_;
|
||||||
|
int n_packets = std::max((bits_per_frame + 8 * kMtu) / (8 * kMtu), 1);
|
||||||
|
int packet_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets);
|
||||||
|
assert(n_packets >= 0);
|
||||||
|
for (int i = 0; i < n_packets; ++i) {
|
||||||
|
RtpPacket* packet = new RtpPacket;
|
||||||
|
packet->send_time = time_now + kSendSideOffsetMs + 0.5f;
|
||||||
|
packet->size = packet_size;
|
||||||
|
packet->rtp_timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
|
||||||
|
(frequency_ / 1000.0) * packet->send_time + 0.5);
|
||||||
|
packet->ssrc = ssrc_;
|
||||||
|
packets->push_back(packet);
|
||||||
|
}
|
||||||
|
next_rtp_time_ = time_now + 1000.0 / static_cast<double>(fps_);
|
||||||
|
return next_rtp_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The send-side time when the next frame can be generated.
|
||||||
|
double RtpStream::next_rtp_time() const {
|
||||||
|
return next_rtp_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates an RTCP packet.
|
||||||
|
RtpStream::RtcpPacket* RtpStream::Rtcp(double time_now) {
|
||||||
|
if (time_now < next_rtcp_time_) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
RtcpPacket* rtcp = new RtcpPacket;
|
||||||
|
int64_t send_time = RtpStream::kSendSideOffsetMs + time_now + 0.5;
|
||||||
|
rtcp->timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
|
||||||
|
(frequency_ / 1000.0) * send_time + 0.5);
|
||||||
|
rtcp->ntp_secs = send_time / 1000;
|
||||||
|
rtcp->ntp_frac = (send_time % 1000) * kNtpFracPerMs;
|
||||||
|
rtcp->ssrc = ssrc_;
|
||||||
|
next_rtcp_time_ = time_now + kRtcpIntervalMs;
|
||||||
|
return rtcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpStream::set_bitrate_bps(int bitrate_bps) {
|
||||||
|
ASSERT_GE(bitrate_bps, 0);
|
||||||
|
bitrate_bps_ = bitrate_bps;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtpStream::bitrate_bps() const {
|
||||||
|
return bitrate_bps_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int RtpStream::ssrc() const {
|
||||||
|
return ssrc_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtpStream::Compare(const std::pair<unsigned int, RtpStream*>& left,
|
||||||
|
const std::pair<unsigned int, RtpStream*>& right) {
|
||||||
|
return left.second->next_rtp_time_ < right.second->next_rtp_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamGenerator::StreamGenerator(int capacity, double time_now)
|
||||||
|
: capacity_(capacity),
|
||||||
|
prev_arrival_time_(time_now) {}
|
||||||
|
|
||||||
|
StreamGenerator::~StreamGenerator() {
|
||||||
|
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
||||||
|
++it) {
|
||||||
|
delete it->second;
|
||||||
|
}
|
||||||
|
streams_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new stream.
|
||||||
|
void StreamGenerator::AddStream(RtpStream* stream) {
|
||||||
|
streams_[stream->ssrc()] = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the link capacity.
|
||||||
|
void StreamGenerator::set_capacity_bps(int capacity_bps) {
|
||||||
|
ASSERT_GT(capacity_bps, 0);
|
||||||
|
capacity_ = capacity_bps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
|
||||||
|
// is decided by the initial allocation ratios.
|
||||||
|
void StreamGenerator::set_bitrate_bps(int bitrate_bps) {
|
||||||
|
ASSERT_GE(streams_.size(), 0u);
|
||||||
|
double total_bitrate_before = 0;
|
||||||
|
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
||||||
|
++it) {
|
||||||
|
total_bitrate_before += it->second->bitrate_bps();
|
||||||
|
}
|
||||||
|
int total_bitrate_after = 0;
|
||||||
|
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
|
||||||
|
++it) {
|
||||||
|
double ratio = it->second->bitrate_bps() / total_bitrate_before;
|
||||||
|
it->second->set_bitrate_bps(ratio * bitrate_bps + 0.5);
|
||||||
|
total_bitrate_after += it->second->bitrate_bps();
|
||||||
|
}
|
||||||
|
EXPECT_NEAR(total_bitrate_after, bitrate_bps, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the RTP timestamp offset for the stream identified by |ssrc|.
|
||||||
|
void StreamGenerator::set_rtp_timestamp_offset(unsigned int ssrc,
|
||||||
|
uint32_t offset) {
|
||||||
|
streams_[ssrc]->set_rtp_timestamp_offset(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(holmer): Break out the channel simulation part from this class to make
|
||||||
|
// it possible to simulate different types of channels.
|
||||||
|
double StreamGenerator::GenerateFrame(RtpStream::PacketList* packets,
|
||||||
|
double time_now) {
|
||||||
|
assert(packets != NULL);
|
||||||
|
assert(packets->empty());
|
||||||
|
assert(capacity_ > 0);
|
||||||
|
StreamMap::iterator it = std::min_element(streams_.begin(), streams_.end(),
|
||||||
|
RtpStream::Compare);
|
||||||
|
(*it).second->GenerateFrame(time_now, packets);
|
||||||
|
for (RtpStream::PacketList::iterator packet_it = packets->begin();
|
||||||
|
packet_it != packets->end(); ++packet_it) {
|
||||||
|
int required_network_time =
|
||||||
|
(8 * 1000 * (*packet_it)->size + capacity_ / 2) / capacity_;
|
||||||
|
prev_arrival_time_ = std::max(time_now + required_network_time,
|
||||||
|
prev_arrival_time_ + required_network_time);
|
||||||
|
(*packet_it)->arrival_time = prev_arrival_time_ + 0.5;
|
||||||
|
}
|
||||||
|
it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
|
||||||
|
return (*it).second->next_rtp_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamGenerator::Rtcps(RtcpList* rtcps, double time_now) const {
|
||||||
|
for (StreamMap::const_iterator it = streams_.begin(); it != streams_.end();
|
||||||
|
++it) {
|
||||||
|
RtpStream::RtcpPacket* rtcp = it->second->Rtcp(time_now);
|
||||||
|
if (rtcp) {
|
||||||
|
rtcps->push_front(rtcp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest()
|
||||||
|
: time_now_(0.0),
|
||||||
|
align_streams_(false) {}
|
||||||
|
|
||||||
|
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest(bool align_streams)
|
||||||
|
: time_now_(0.0),
|
||||||
|
align_streams_(align_streams) {}
|
||||||
|
|
||||||
|
void RemoteBitrateEstimatorTest::SetUp() {
|
||||||
|
bitrate_observer_.reset(new testing::TestBitrateObserver);
|
||||||
|
bitrate_estimator_.reset(
|
||||||
|
RemoteBitrateEstimator::Create(
|
||||||
|
bitrate_observer_.get(),
|
||||||
|
over_use_detector_options_,
|
||||||
|
RemoteBitrateEstimator::kSingleStreamEstimation));
|
||||||
|
stream_generator_.reset(new testing::StreamGenerator(1e6, // Capacity.
|
||||||
|
time_now_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteBitrateEstimatorTest::AddDefaultStream() {
|
||||||
|
stream_generator_->AddStream(new testing::RtpStream(
|
||||||
|
30, // Frames per second.
|
||||||
|
3e5, // Bitrate.
|
||||||
|
1, // SSRC.
|
||||||
|
90000, // RTP frequency.
|
||||||
|
0xFFFFF000, // Timestamp offset.
|
||||||
|
0)); // RTCP receive time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a frame of packets belonging to a stream at a given bitrate and
|
||||||
|
// with a given ssrc. The stream is pushed through a very simple simulated
|
||||||
|
// network, and is then given to the receive-side bandwidth estimator.
|
||||||
|
// Returns true if an over-use was seen, false otherwise.
|
||||||
|
// The StreamGenerator::updated() should be used to check for any changes in
|
||||||
|
// target bitrate after the call to this function.
|
||||||
|
bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(unsigned int ssrc,
|
||||||
|
unsigned int bitrate_bps) {
|
||||||
|
stream_generator_->set_bitrate_bps(bitrate_bps);
|
||||||
|
testing::RtpStream::PacketList packets;
|
||||||
|
time_now_ = stream_generator_->GenerateFrame(&packets, time_now_);
|
||||||
|
int64_t last_arrival_time = -1;
|
||||||
|
bool prev_was_decrease = false;
|
||||||
|
bool overuse = false;
|
||||||
|
while (!packets.empty()) {
|
||||||
|
testing::RtpStream::RtpPacket* packet = packets.front();
|
||||||
|
if (align_streams_) {
|
||||||
|
testing::StreamGenerator::RtcpList rtcps;
|
||||||
|
stream_generator_->Rtcps(&rtcps, time_now_);
|
||||||
|
for (testing::StreamGenerator::RtcpList::iterator it = rtcps.begin();
|
||||||
|
it != rtcps.end(); ++it) {
|
||||||
|
bitrate_estimator_->IncomingRtcp((*it)->ssrc,
|
||||||
|
(*it)->ntp_secs,
|
||||||
|
(*it)->ntp_frac,
|
||||||
|
(*it)->timestamp);
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitrate_observer_->Reset();
|
||||||
|
bitrate_estimator_->IncomingPacket(packet->ssrc,
|
||||||
|
packet->size,
|
||||||
|
packet->arrival_time,
|
||||||
|
packet->rtp_timestamp);
|
||||||
|
if (bitrate_observer_->updated()) {
|
||||||
|
// Verify that new estimates only are triggered by an overuse and a
|
||||||
|
// rate decrease.
|
||||||
|
overuse = true;
|
||||||
|
EXPECT_LE(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
||||||
|
EXPECT_FALSE(prev_was_decrease);
|
||||||
|
prev_was_decrease = true;
|
||||||
|
} else {
|
||||||
|
prev_was_decrease = false;
|
||||||
|
}
|
||||||
|
last_arrival_time = packet->arrival_time;
|
||||||
|
delete packet;
|
||||||
|
packets.pop_front();
|
||||||
|
}
|
||||||
|
EXPECT_GT(last_arrival_time, -1);
|
||||||
|
bitrate_estimator_->UpdateEstimate(ssrc, last_arrival_time);
|
||||||
|
return overuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the bandwidth estimator with a stream of |number_of_frames| frames.
|
||||||
|
// Can for instance be used to run the estimator for some time to get it
|
||||||
|
// into a steady state.
|
||||||
|
unsigned int RemoteBitrateEstimatorTest::SteadyStateRun(
|
||||||
|
unsigned int ssrc,
|
||||||
|
int number_of_frames,
|
||||||
|
unsigned int start_bitrate,
|
||||||
|
unsigned int min_bitrate,
|
||||||
|
unsigned int max_bitrate) {
|
||||||
|
unsigned int bitrate_bps = start_bitrate;
|
||||||
|
bool bitrate_update_seen = false;
|
||||||
|
// Produce |number_of_frames| frames and give them to the estimator.
|
||||||
|
for (int i = 0; i < number_of_frames; ++i) {
|
||||||
|
bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps);
|
||||||
|
if (overuse) {
|
||||||
|
EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate);
|
||||||
|
EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate);
|
||||||
|
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||||
|
bitrate_update_seen = true;
|
||||||
|
} else if (bitrate_observer_->updated()) {
|
||||||
|
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||||
|
bitrate_observer_->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(bitrate_update_seen);
|
||||||
|
return bitrate_bps;
|
||||||
|
}
|
||||||
|
} // namespace webrtc
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 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_REMOTE_BITRATE_ESTIMATOR_UNITTEST_HELPER_H_
|
||||||
|
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_BITRATE_ESTIMATOR_UNITTEST_HELPER_H_
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||||
|
#include "system_wrappers/interface/constructor_magic.h"
|
||||||
|
#include "system_wrappers/interface/scoped_ptr.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
enum { kMtu = 1200 };
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class TestBitrateObserver : public RemoteBitrateObserver {
|
||||||
|
public:
|
||||||
|
TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
|
||||||
|
|
||||||
|
void OnReceiveBitrateChanged(unsigned int bitrate) {
|
||||||
|
latest_bitrate_ = bitrate;
|
||||||
|
updated_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
updated_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updated() const {
|
||||||
|
return updated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int latest_bitrate() const {
|
||||||
|
return latest_bitrate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool updated_;
|
||||||
|
unsigned int latest_bitrate_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class RtpStream {
|
||||||
|
public:
|
||||||
|
struct RtpPacket {
|
||||||
|
int64_t send_time;
|
||||||
|
int64_t arrival_time;
|
||||||
|
uint32_t rtp_timestamp;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int ssrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RtcpPacket {
|
||||||
|
uint32_t ntp_secs;
|
||||||
|
uint32_t ntp_frac;
|
||||||
|
uint32_t timestamp;
|
||||||
|
unsigned int ssrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<RtpPacket*> PacketList;
|
||||||
|
|
||||||
|
enum { kSendSideOffsetMs = 1000 };
|
||||||
|
|
||||||
|
RtpStream(int fps, int bitrate_bps, unsigned int ssrc, unsigned int frequency,
|
||||||
|
uint32_t timestamp_offset, int64_t rtcp_receive_time);
|
||||||
|
void set_rtp_timestamp_offset(uint32_t offset);
|
||||||
|
|
||||||
|
// Generates a new frame for this stream. If called too soon after the
|
||||||
|
// previous frame, no frame will be generated. The frame is split into
|
||||||
|
// packets.
|
||||||
|
int64_t GenerateFrame(double time_now, PacketList* packets);
|
||||||
|
|
||||||
|
// The send-side time when the next frame can be generated.
|
||||||
|
double next_rtp_time() const;
|
||||||
|
|
||||||
|
// Generates an RTCP packet.
|
||||||
|
RtcpPacket* Rtcp(double time_now);
|
||||||
|
|
||||||
|
void set_bitrate_bps(int bitrate_bps);
|
||||||
|
|
||||||
|
int bitrate_bps() const;
|
||||||
|
|
||||||
|
unsigned int ssrc() const;
|
||||||
|
|
||||||
|
static bool Compare(const std::pair<unsigned int, RtpStream*>& left,
|
||||||
|
const std::pair<unsigned int, RtpStream*>& right);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum { kRtcpIntervalMs = 1000 };
|
||||||
|
|
||||||
|
int fps_;
|
||||||
|
int bitrate_bps_;
|
||||||
|
unsigned int ssrc_;
|
||||||
|
unsigned int frequency_;
|
||||||
|
double next_rtp_time_;
|
||||||
|
double next_rtcp_time_;
|
||||||
|
uint32_t rtp_timestamp_offset_;
|
||||||
|
const double kNtpFracPerMs;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RtpStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StreamGenerator {
|
||||||
|
public:
|
||||||
|
typedef std::list<RtpStream::RtcpPacket*> RtcpList;
|
||||||
|
|
||||||
|
StreamGenerator(int capacity, double time_now);
|
||||||
|
|
||||||
|
~StreamGenerator();
|
||||||
|
|
||||||
|
// Add a new stream.
|
||||||
|
void AddStream(RtpStream* stream);
|
||||||
|
|
||||||
|
// Set the link capacity.
|
||||||
|
void set_capacity_bps(int capacity_bps);
|
||||||
|
|
||||||
|
// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
|
||||||
|
// is decided by the initial allocation ratios.
|
||||||
|
void set_bitrate_bps(int bitrate_bps);
|
||||||
|
|
||||||
|
// Set the RTP timestamp offset for the stream identified by |ssrc|.
|
||||||
|
void set_rtp_timestamp_offset(unsigned int ssrc, uint32_t offset);
|
||||||
|
|
||||||
|
// TODO(holmer): Break out the channel simulation part from this class to make
|
||||||
|
// it possible to simulate different types of channels.
|
||||||
|
double GenerateFrame(RtpStream::PacketList* packets, double time_now);
|
||||||
|
|
||||||
|
void Rtcps(RtcpList* rtcps, double time_now) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<unsigned int, RtpStream*> StreamMap;
|
||||||
|
|
||||||
|
// Capacity of the simulated channel in bits per second.
|
||||||
|
int capacity_;
|
||||||
|
// The time when the last packet arrived.
|
||||||
|
double prev_arrival_time_;
|
||||||
|
// All streams being transmitted on this simulated channel.
|
||||||
|
StreamMap streams_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StreamGenerator);
|
||||||
|
};
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
class RemoteBitrateEstimatorTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
RemoteBitrateEstimatorTest();
|
||||||
|
explicit RemoteBitrateEstimatorTest(bool align_streams);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void SetUp();
|
||||||
|
|
||||||
|
void AddDefaultStream();
|
||||||
|
|
||||||
|
// Generates a frame of packets belonging to a stream at a given bitrate and
|
||||||
|
// with a given ssrc. The stream is pushed through a very simple simulated
|
||||||
|
// network, and is then given to the receive-side bandwidth estimator.
|
||||||
|
// Returns true if an over-use was seen, false otherwise.
|
||||||
|
// The StreamGenerator::updated() should be used to check for any changes in
|
||||||
|
// target bitrate after the call to this function.
|
||||||
|
bool GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps);
|
||||||
|
|
||||||
|
// Run the bandwidth estimator with a stream of |number_of_frames| frames.
|
||||||
|
// Can for instance be used to run the estimator for some time to get it
|
||||||
|
// into a steady state.
|
||||||
|
unsigned int SteadyStateRun(unsigned int ssrc,
|
||||||
|
int number_of_frames,
|
||||||
|
unsigned int start_bitrate,
|
||||||
|
unsigned int min_bitrate,
|
||||||
|
unsigned int max_bitrate);
|
||||||
|
|
||||||
|
static const unsigned int kDefaultSsrc = 1;
|
||||||
|
|
||||||
|
double time_now_; // Current time at the receiver.
|
||||||
|
OverUseDetectorOptions over_use_detector_options_;
|
||||||
|
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
||||||
|
scoped_ptr<testing::TestBitrateObserver> bitrate_observer_;
|
||||||
|
scoped_ptr<testing::StreamGenerator> stream_generator_;
|
||||||
|
const bool align_streams_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTest);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemoteBitrateEstimatorTestAlign : public RemoteBitrateEstimatorTest {
|
||||||
|
public:
|
||||||
|
RemoteBitrateEstimatorTestAlign() : RemoteBitrateEstimatorTest(true) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTestAlign);
|
||||||
|
};
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_BITRATE_ESTIMATOR_UNITTEST_HELPER_H_
|
Reference in New Issue
Block a user