- Changed RemoteBitrateEstimator::IncomingPacket() to include a const WebRtcRTPHeader& and remove ssrc, rtp_timestamp.

- Changed RemoteBitrateObserver::OnReceivedBitrateChanged() to use a const & instead of non-const *, to avoid unnecessary copying.
- Refactored RemoteBitrateEstimatorTest so it can be instantiated for both single and multi stream BWE (first using a parameterized test, but then as a standard test fixture and a few helper functions).
- Refactored some tests in RemoteBitrateEstimatorTest into a common function CapacityDropTestHelper().

BUG=
R=andresp@webrtc.org, mflodman@webrtc.org, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4086 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
solenberg@webrtc.org 2013-05-22 19:04:19 +00:00
parent 6ec25073e3
commit 561990fd73
15 changed files with 526 additions and 509 deletions

View File

@ -22,7 +22,7 @@ namespace webrtc {
class MockRemoteBitrateObserver : public RemoteBitrateObserver {
public:
MOCK_METHOD2(OnReceiveBitrateChanged,
void(std::vector<unsigned int>* ssrcs, unsigned int bitrate));
void(const std::vector<unsigned int>& ssrcs, unsigned int bitrate));
};
} // namespace webrtc

View File

@ -31,7 +31,7 @@ class RemoteBitrateObserver {
public:
// Called when a receive channel group has a new bitrate estimate for the
// incoming streams.
virtual void OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) = 0;
virtual ~RemoteBitrateObserver() {}
@ -41,7 +41,6 @@ class RemoteBitrateEstimator : public CallStatsObserver, public Module {
public:
virtual ~RemoteBitrateEstimator() {}
// Stores an RTCP SR (NTP, RTP timestamp) tuple for a specific SSRC to be used
// in future RTP timestamp to NTP time conversions. As soon as any SSRC has
// two tuples the RemoteBitrateEstimator will switch to multi-stream mode.
@ -51,11 +50,12 @@ class RemoteBitrateEstimator : public CallStatsObserver, public Module {
// Called for each incoming packet. Updates the incoming payload bitrate
// estimate and the over-use detector. If an over-use is detected the
// remote bitrate estimate will be updated. Note that |payload_size| is the
// packet size excluding headers.
virtual void IncomingPacket(unsigned int ssrc,
// packet size excluding headers. The estimator can only count on the
// "header" (an RTPHeader) and "extension" (an RTPHeaderExtension) fields of
// the WebRtcRTPHeader to be initialized.
virtual void IncomingPacket(int64_t arrival_time_ms,
int payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp) = 0;
const WebRtcRTPHeader& header) = 0;
// Removes all data for |ssrc|.
virtual void RemoveStream(unsigned int ssrc) = 0;

View File

@ -59,7 +59,8 @@
'sources': [
'include/mock/mock_remote_bitrate_observer.h',
'bitrate_estimator_unittest.cc',
'remote_bitrate_estimator_unittest.cc',
'remote_bitrate_estimator_multi_stream_unittest.cc',
'remote_bitrate_estimator_single_stream_unittest.cc',
'remote_bitrate_estimator_unittest_helper.cc',
'remote_bitrate_estimator_unittest_helper.h',
'rtp_to_ntp_unittest.cc',

View File

@ -28,14 +28,13 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
public:
RemoteBitrateEstimatorMultiStream(RemoteBitrateObserver* observer,
Clock* clock);
~RemoteBitrateEstimatorMultiStream() {}
virtual ~RemoteBitrateEstimatorMultiStream() {}
// Stores an RTCP SR (NTP, RTP timestamp) tuple for a specific SSRC to be used
// in future RTP timestamp to NTP time conversions. As soon as any SSRC has
// two tuples the RemoteBitrateEstimator will switch to multi-stream mode.
void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs, uint32_t ntp_frac,
uint32_t rtp_timestamp);
virtual void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs,
uint32_t ntp_frac, uint32_t rtp_timestamp);
// Called for each incoming packet. The first SSRC will immediately be used
// for over-use detection. Subsequent SSRCs will only be used when at least
@ -43,10 +42,9 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
// incoming payload bitrate estimate and the over-use detector.
// If an over-use is detected the remote bitrate estimate will be updated.
// Note that |payload_size| is the packet size excluding headers.
void IncomingPacket(unsigned int ssrc,
int payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp);
virtual void IncomingPacket(int64_t arrival_time_ms,
int payload_size,
const WebRtcRTPHeader& header);
// Triggers a new estimate calculation.
// Implements the Module interface.
@ -57,13 +55,13 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
virtual void OnRttUpdate(uint32_t rtt);
// Removes all data for |ssrc|.
void RemoveStream(unsigned int ssrc);
virtual void RemoveStream(unsigned int ssrc);
// Returns true if a valid estimate exists and sets |bitrate_bps| to the
// estimated payload bitrate in bits per second. |ssrcs| is the list of ssrcs
// currently being received and of which the bitrate estimate is based upon.
bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const;
virtual bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const;
private:
typedef std::map<unsigned int, synchronization::RtcpList> StreamMap;
@ -138,12 +136,15 @@ void RemoteBitrateEstimatorMultiStream::IncomingRtcp(unsigned int ssrc,
rtcp_list->push_front(measurement);
}
void RemoteBitrateEstimatorMultiStream::IncomingPacket(unsigned int ssrc,
int payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp) {
void RemoteBitrateEstimatorMultiStream::IncomingPacket(
int64_t arrival_time_ms,
int payload_size,
const WebRtcRTPHeader& header) {
uint32_t ssrc = header.header.ssrc;
uint32_t rtp_timestamp = header.header.timestamp +
header.extension.transmissionTimeOffset;
CriticalSectionScoped cs(crit_sect_.get());
incoming_bitrate_.Update(payload_size, arrival_time);
incoming_bitrate_.Update(payload_size, arrival_time_ms);
// Add this stream to the map of streams if it doesn't already exist.
std::pair<StreamMap::iterator, bool> stream_insert_result =
streams_.insert(std::make_pair(ssrc, synchronization::RtcpList()));
@ -167,15 +168,15 @@ void RemoteBitrateEstimatorMultiStream::IncomingPacket(unsigned int ssrc,
synchronization::RtpToNtpMs(rtp_timestamp, *rtcp_list, &timestamp_in_ms);
}
overuse_detector_.Update(payload_size, timestamp_in_ms, rtp_timestamp,
arrival_time);
arrival_time_ms);
if (overuse_detector_.State() == kBwOverusing) {
unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time);
unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time_ms);
if (prior_state != kBwOverusing ||
remote_rate_.TimeToReduceFurther(arrival_time, incoming_bitrate)) {
remote_rate_.TimeToReduceFurther(arrival_time_ms, incoming_bitrate)) {
// The first overuse should immediately trigger a new estimate.
// We also have to update the estimate immediately if we are overusing
// and the target bitrate is too high compared to what we are receiving.
UpdateEstimate(arrival_time);
UpdateEstimate(arrival_time_ms);
}
}
}
@ -216,7 +217,7 @@ void RemoteBitrateEstimatorMultiStream::UpdateEstimate(int64_t time_now) {
std::vector<unsigned int> ssrcs;
GetSsrcs(&ssrcs);
if (!ssrcs.empty()) {
observer_->OnReceiveBitrateChanged(&ssrcs, target_bitrate);
observer_->OnReceiveBitrateChanged(ssrcs, target_bitrate);
}
}
overuse_detector_.SetRateControlRegion(region);

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2013 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 <gtest/gtest.h>
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h"
#include "webrtc/system_wrappers/interface/constructor_magic.h"
namespace webrtc {
class RemoteBitrateEstimatorMultiTest : public RemoteBitrateEstimatorTest {
public:
RemoteBitrateEstimatorMultiTest() {}
virtual void SetUp() {
bitrate_estimator_.reset(MultiStreamRemoteBitrateEstimatorFactory().Create(
bitrate_observer_.get(),
&clock_));
}
protected:
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorMultiTest);
};
TEST_F(RemoteBitrateEstimatorMultiTest, InitialBehavior) {
InitialBehaviorTestHelper(497919);
}
TEST_F(RemoteBitrateEstimatorMultiTest, RateIncreaseReordering) {
RateIncreaseReorderingTestHelper();
}
TEST_F(RemoteBitrateEstimatorMultiTest, RateIncreaseRtpTimestamps) {
RateIncreaseRtpTimestampsTestHelper();
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropOneStream) {
CapacityDropTestHelper(1, false, 956214, 367);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropOneStreamWrap) {
CapacityDropTestHelper(1, true, 956214, 367);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropOneStreamWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(1, true, 838645, 533);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropTwoStreamsWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(2, true, 810646, 433);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropThreeStreamsWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(3, true, 868522, 2067);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropThirteenStreamsWrap) {
CapacityDropTestHelper(13, true, 918810, 433);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropNineteenStreamsWrap) {
CapacityDropTestHelper(19, true, 919119, 433);
}
TEST_F(RemoteBitrateEstimatorMultiTest, CapacityDropThirtyStreamsWrap) {
CapacityDropTestHelper(30, true, 918724, 433);
}
} // namespace webrtc

View File

@ -25,19 +25,19 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
public:
RemoteBitrateEstimatorSingleStream(RemoteBitrateObserver* observer,
Clock* clock);
virtual ~RemoteBitrateEstimatorSingleStream() {}
void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs, uint32_t ntp_frac,
uint32_t rtp_timestamp) {}
virtual void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs,
uint32_t ntp_frac, uint32_t rtp_timestamp) {}
// Called for each incoming packet. If this is a new SSRC, a new
// BitrateControl will be created. Updates the incoming payload bitrate
// estimate and the over-use detector. If an over-use is detected the
// remote bitrate estimate will be updated. Note that |payload_size| is the
// packet size excluding headers.
void IncomingPacket(unsigned int ssrc,
int payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp);
virtual void IncomingPacket(int64_t arrival_time_ms,
int payload_size,
const WebRtcRTPHeader& header);
// Triggers a new estimate calculation.
// Implements the Module interface.
@ -48,13 +48,13 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
virtual void OnRttUpdate(uint32_t rtt);
// Removes all data for |ssrc|.
void RemoveStream(unsigned int ssrc);
virtual void RemoveStream(unsigned int ssrc);
// Returns true if a valid estimate exists and sets |bitrate_bps| to the
// estimated payload bitrate in bits per second. |ssrcs| is the list of ssrcs
// currently being received and of which the bitrate estimate is based upon.
bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const;
virtual bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const;
private:
typedef std::map<unsigned int, OveruseDetector> SsrcOveruseDetectorMap;
@ -84,10 +84,12 @@ RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream(
}
void RemoteBitrateEstimatorSingleStream::IncomingPacket(
unsigned int ssrc,
int64_t arrival_time_ms,
int payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp) {
const WebRtcRTPHeader& header) {
uint32_t ssrc = header.header.ssrc;
uint32_t rtp_timestamp = header.header.timestamp +
header.extension.transmissionTimeOffset;
CriticalSectionScoped cs(crit_sect_.get());
SsrcOveruseDetectorMap::iterator it = overuse_detectors_.find(ssrc);
if (it == overuse_detectors_.end()) {
@ -103,17 +105,17 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
it = insert_result.first;
}
OveruseDetector* overuse_detector = &it->second;
incoming_bitrate_.Update(payload_size, arrival_time);
incoming_bitrate_.Update(payload_size, arrival_time_ms);
const BandwidthUsage prior_state = overuse_detector->State();
overuse_detector->Update(payload_size, -1, rtp_timestamp, arrival_time);
overuse_detector->Update(payload_size, -1, rtp_timestamp, arrival_time_ms);
if (overuse_detector->State() == kBwOverusing) {
unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time);
unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time_ms);
if (prior_state != kBwOverusing ||
remote_rate_.TimeToReduceFurther(arrival_time, incoming_bitrate)) {
remote_rate_.TimeToReduceFurther(arrival_time_ms, incoming_bitrate)) {
// The first overuse should immediately trigger a new estimate.
// We also have to update the estimate immediately if we are overusing
// and the target bitrate is too high compared to what we are receiving.
UpdateEstimate(arrival_time);
UpdateEstimate(arrival_time_ms);
}
}
}
@ -172,7 +174,7 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t time_now) {
if (remote_rate_.ValidEstimate()) {
std::vector<unsigned int> ssrcs;
GetSsrcs(&ssrcs);
observer_->OnReceiveBitrateChanged(&ssrcs, target_bitrate);
observer_->OnReceiveBitrateChanged(ssrcs, target_bitrate);
}
for (it = overuse_detectors_.begin(); it != overuse_detectors_.end(); ++it) {
it->second.SetRateControlRegion(region);

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2013 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 <gtest/gtest.h>
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h"
#include "webrtc/system_wrappers/interface/constructor_magic.h"
namespace webrtc {
class RemoteBitrateEstimatorSingleTest : public RemoteBitrateEstimatorTest {
public:
RemoteBitrateEstimatorSingleTest() {}
virtual void SetUp() {
bitrate_estimator_.reset(RemoteBitrateEstimatorFactory().Create(
bitrate_observer_.get(),
&clock_));
}
protected:
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorSingleTest);
};
TEST_F(RemoteBitrateEstimatorSingleTest, InitialBehavior) {
InitialBehaviorTestHelper(498075);
}
TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseReordering) {
RateIncreaseReorderingTestHelper();
}
TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseRtpTimestamps) {
RateIncreaseRtpTimestampsTestHelper();
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same.
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) {
CapacityDropTestHelper(1, false, 956214, 367);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario.
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) {
CapacityDropTestHelper(1, true, 956214, 367);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario.
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(1, true, 956214, 367);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario. This is a multi-stream test.
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(2, true, 927088, 267);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario. This is a multi-stream test.
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrapAlign) {
align_streams_ = true;
CapacityDropTestHelper(3, true, 920944, 333);
}
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
CapacityDropTestHelper(13, true, 938944, 300);
}
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {
CapacityDropTestHelper(19, true, 926718, 300);
}
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) {
CapacityDropTestHelper(30, true, 927016, 300);
}
} // namespace webrtc

View File

@ -1,367 +0,0 @@
/*
* 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.
*/
// This file includes unit tests for RemoteBitrateEstimator.
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
#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/scoped_ptr.h"
namespace webrtc {
TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
unsigned int bitrate_bps = 0;
uint32_t timestamp = 0;
std::vector<unsigned int> ssrcs;
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size());
clock_.AdvanceTimeMilliseconds(1000);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset();
clock_.AdvanceTimeMilliseconds(1000);
// Inserting a packet. Still no valid estimate. We need to wait 1 second.
bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size());
EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset();
// Inserting packets for one second to get a valid estimate.
for (int i = 0; i < kFramerate; ++i) {
bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
clock_.TimeInMilliseconds(), timestamp);
clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
timestamp += 90 * kFrameIntervalMs;
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
ASSERT_EQ(1u, ssrcs.size());
EXPECT_EQ(kDefaultSsrc, ssrcs.front());
EXPECT_EQ(498075u, bitrate_bps);
EXPECT_TRUE(bitrate_observer_->updated());
bitrate_observer_->Reset();
EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
}
TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseReordering) {
uint32_t timestamp = 0;
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000,
clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate.
// Inserting packets for one second to get a valid estimate.
for (int i = 0; i < kFramerate; ++i) {
bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
clock_.TimeInMilliseconds(), timestamp);
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
timestamp += 90 * kFrameIntervalMs;
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
for (int i = 0; i < 10; ++i) {
clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
timestamp += 2 * 90 * kFrameIntervalMs;
bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000,
clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->IncomingPacket(kDefaultSsrc,
1000,
clock_.TimeInMilliseconds(),
timestamp - 90 * kFrameIntervalMs);
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
}
// Make sure we initially increase the bitrate as expected.
TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) {
// This threshold corresponds approximately to increasing linearly with
// bitrate(i) = 1.04 * bitrate(i-1) + 1000
// until bitrate(i) > 500000, with bitrate(1) ~= 30000.
const int kExpectedIterations = 1621;
unsigned int bitrate_bps = 30000;
int iterations = 0;
AddDefaultStream();
// Feed the estimator with a stream of packets and verify that it reaches
// 500 kbps at the expected time.
while (bitrate_bps < 5e5) {
bool overuse = GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
if (overuse) {
EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps);
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
} else if (bitrate_observer_->updated()) {
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
++iterations;
ASSERT_LE(iterations, kExpectedIterations);
}
ASSERT_EQ(kExpectedIterations, iterations);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same.
TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestamps) {
const int kNumberOfFrames = 300;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
AddDefaultStream();
// Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(1000e3);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, kNumberOfFrames,
kStartBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate, capacity_bps);
// Reduce the capacity and verify the decrease time.
capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario.
TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestampsWrap) {
const int kFramerate= 30;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateTime = 8; // Seconds.
AddDefaultStream();
// Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000);
// Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(1000e3);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate,
kStartBitrate,
kMinExpectedBitrate,
kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time.
capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario. This test also converts the timestamps
// to NTP time.
TEST_F(RemoteBitrateEstimatorTestAlign, TestCapacityDropRtpTimestampsWrap) {
const int kFramerate= 30;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateTime = 8; // Seconds.
AddDefaultStream();
// Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000);
// Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate,
kStartBitrate,
kMinExpectedBitrate,
kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time.
capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario. This is a multi-stream test.
TEST_F(RemoteBitrateEstimatorTestAlign, TwoStreamsCapacityDropWithWrap) {
const int kFramerate= 30;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateFrames = 9 * kFramerate;
stream_generator_->AddStream(new testing::RtpStream(
30, // Frames per second.
kStartBitrate/2, // Bitrate.
1, // SSRC.
90000, // RTP frequency.
0xFFFFF000, // Timestamp offset.
0)); // RTCP receive time.
stream_generator_->AddStream(new testing::RtpStream(
15, // Frames per second.
kStartBitrate/2, // Bitrate.
2, // SSRC.
90000, // RTP frequency.
0x00000FFF, // Timestamp offset.
0)); // RTCP receive time.
// Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateFrames * 90000);
// Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateFrames,
kStartBitrate,
kMinExpectedBitrate,
kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time.
capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(567, bitrate_drop_time - overuse_start_time);
}
// Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. This test also verifies that we
// handle wrap-arounds in this scenario. This is a multi-stream test.
TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
const int kFramerate= 30;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateFrames = 12 * kFramerate;
stream_generator_->AddStream(new testing::RtpStream(
kFramerate, // Frames per second.
kStartBitrate/2, // Bitrate.
1, // SSRC.
90000, // RTP frequency.
0xFFFFF000, // Timestamp offset.
0)); // RTCP receive time.
stream_generator_->AddStream(new testing::RtpStream(
kFramerate, // Frames per second.
kStartBitrate/3, // Bitrate.
2, // SSRC.
90000, // RTP frequency.
0x00000FFF, // Timestamp offset.
0)); // RTCP receive time.
stream_generator_->AddStream(new testing::RtpStream(
kFramerate, // Frames per second.
kStartBitrate/6, // Bitrate.
3, // SSRC.
90000, // RTP frequency.
0x00000FFF, // Timestamp offset.
0)); // RTCP receive time.
// Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateFrames * 90000);
// Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateFrames,
kStartBitrate,
kMinExpectedBitrate,
kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time.
capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(433, bitrate_drop_time - overuse_start_time);
}
} // namespace webrtc

View File

@ -13,6 +13,9 @@
#include <utility>
namespace webrtc {
enum { kMtu = 1200 };
namespace testing {
RtpStream::RtpStream(int fps,
@ -124,22 +127,24 @@ void StreamGenerator::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 StreamGenerator::set_bitrate_bps(int bitrate_bps) {
// is decided by the current allocation ratios.
void StreamGenerator::SetBitrateBps(int bitrate_bps) {
ASSERT_GE(streams_.size(), 0u);
double total_bitrate_before = 0;
for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
++it) {
int total_bitrate_before = 0;
for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); ++it) {
total_bitrate_before += it->second->bitrate_bps();
}
int64_t bitrate_before = 0;
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);
for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); ++it) {
bitrate_before += it->second->bitrate_bps();
int64_t bitrate_after = (bitrate_before * bitrate_bps +
total_bitrate_before / 2) / total_bitrate_before;
it->second->set_bitrate_bps(bitrate_after - total_bitrate_after);
total_bitrate_after += it->second->bitrate_bps();
}
EXPECT_NEAR(total_bitrate_after, bitrate_bps, 1);
ASSERT_EQ(bitrate_before, total_bitrate_before);
EXPECT_EQ(total_bitrate_after, bitrate_bps);
}
// Set the RTP timestamp offset for the stream identified by |ssrc|.
@ -186,22 +191,11 @@ void StreamGenerator::Rtcps(RtcpList* rtcps, int64_t time_now_us) const {
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest()
: clock_(0),
align_streams_(false) {}
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest(bool align_streams)
: clock_(0),
align_streams_(align_streams) {}
void RemoteBitrateEstimatorTest::SetUp() {
bitrate_observer_.reset(new testing::TestBitrateObserver);
bitrate_estimator_.reset(
RemoteBitrateEstimatorFactory().Create(
bitrate_observer_.get(),
&clock_));
stream_generator_.reset(new testing::StreamGenerator(
1e6, // Capacity.
clock_.TimeInMicroseconds()));
}
align_streams_(false),
bitrate_observer_(new testing::TestBitrateObserver),
stream_generator_(new testing::StreamGenerator(
1e6, // Capacity.
clock_.TimeInMicroseconds())) {}
void RemoteBitrateEstimatorTest::AddDefaultStream() {
stream_generator_->AddStream(new testing::RtpStream(
@ -213,8 +207,29 @@ void RemoteBitrateEstimatorTest::AddDefaultStream() {
0)); // RTCP receive time.
}
uint32_t RemoteBitrateEstimatorTest::AbsSendTime(int64_t t, int64_t denom) {
return (((t << 18) + (denom >> 1)) / denom) & 0x00fffffful;
}
uint32_t RemoteBitrateEstimatorTest::AddAbsSendTime(uint32_t t1, uint32_t t2) {
return (t1 + t2) & 0x00fffffful;
}
const unsigned int RemoteBitrateEstimatorTest::kDefaultSsrc = 1;
void RemoteBitrateEstimatorTest::IncomingPacket(uint32_t ssrc,
uint32_t payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp,
uint32_t absolute_send_time) {
WebRtcRTPHeader header;
memset(&header, 0, sizeof(header));
header.header.ssrc = ssrc;
header.header.timestamp = rtp_timestamp;
header.extension.absoluteSendTime = absolute_send_time;
bitrate_estimator_->IncomingPacket(arrival_time, payload_size, header);
}
// 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.
@ -223,7 +238,7 @@ const unsigned int RemoteBitrateEstimatorTest::kDefaultSsrc = 1;
// 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);
stream_generator_->SetBitrateBps(bitrate_bps);
testing::RtpStream::PacketList packets;
int64_t next_time_us = stream_generator_->GenerateFrame(
&packets, clock_.TimeInMicroseconds());
@ -243,10 +258,11 @@ bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(unsigned int ssrc,
}
}
bitrate_observer_->Reset();
bitrate_estimator_->IncomingPacket(packet->ssrc,
packet->size,
(packet->arrival_time + 500) / 1000,
packet->rtp_timestamp);
IncomingPacket(packet->ssrc,
packet->size,
(packet->arrival_time + 500) / 1000,
packet->rtp_timestamp,
AbsSendTime(packet->send_time, 1000000));
if (bitrate_observer_->updated()) {
// Verify that new estimates only are triggered by an overuse and a
// rate decrease.
@ -295,4 +311,193 @@ unsigned int RemoteBitrateEstimatorTest::SteadyStateRun(
EXPECT_TRUE(bitrate_update_seen);
return bitrate_bps;
}
void RemoteBitrateEstimatorTest::InitialBehaviorTestHelper(
unsigned int expected_converge_bitrate) {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
const uint32_t kFrameIntervalAbsSendTime = AbsSendTime(1, kFramerate);
unsigned int bitrate_bps = 0;
uint32_t timestamp = 0;
uint32_t absolute_send_time = 0;
std::vector<unsigned int> ssrcs;
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size());
clock_.AdvanceTimeMilliseconds(1000);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset();
clock_.AdvanceTimeMilliseconds(1000);
// Inserting a packet. Still no valid estimate. We need to wait 1 second.
IncomingPacket(kDefaultSsrc, kMtu, clock_.TimeInMilliseconds(), timestamp,
absolute_send_time);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size());
EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset();
// Inserting packets for one second to get a valid estimate.
for (int i = 0; i < kFramerate; ++i) {
IncomingPacket(kDefaultSsrc, kMtu, clock_.TimeInMilliseconds(), timestamp,
absolute_send_time);
clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
timestamp += 90 * kFrameIntervalMs;
absolute_send_time = AddAbsSendTime(absolute_send_time,
kFrameIntervalAbsSendTime);
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
ASSERT_EQ(1u, ssrcs.size());
EXPECT_EQ(kDefaultSsrc, ssrcs.front());
EXPECT_EQ(expected_converge_bitrate, bitrate_bps);
EXPECT_TRUE(bitrate_observer_->updated());
bitrate_observer_->Reset();
EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
}
void RemoteBitrateEstimatorTest::RateIncreaseReorderingTestHelper() {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
const uint32_t kFrameIntervalAbsSendTime = AbsSendTime(1, kFramerate);
uint32_t timestamp = 0;
uint32_t absolute_send_time = 0;
IncomingPacket(kDefaultSsrc, 1000, clock_.TimeInMilliseconds(), timestamp,
absolute_send_time);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate.
// Inserting packets for one second to get a valid estimate.
for (int i = 0; i < kFramerate; ++i) {
IncomingPacket(kDefaultSsrc, kMtu, clock_.TimeInMilliseconds(), timestamp,
absolute_send_time);
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
timestamp += 90 * kFrameIntervalMs;
absolute_send_time = AddAbsSendTime(absolute_send_time,
kFrameIntervalAbsSendTime);
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
for (int i = 0; i < 10; ++i) {
clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
timestamp += 2 * 90 * kFrameIntervalMs;
absolute_send_time = AddAbsSendTime(absolute_send_time,
2 * kFrameIntervalAbsSendTime);
IncomingPacket(kDefaultSsrc, 1000, clock_.TimeInMilliseconds(), timestamp,
absolute_send_time);
IncomingPacket(kDefaultSsrc, 1000, clock_.TimeInMilliseconds(),
timestamp - 90 * kFrameIntervalMs,
AddAbsSendTime(absolute_send_time,
-int(kFrameIntervalAbsSendTime)));
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
}
// Make sure we initially increase the bitrate as expected.
void RemoteBitrateEstimatorTest::RateIncreaseRtpTimestampsTestHelper() {
// This threshold corresponds approximately to increasing linearly with
// bitrate(i) = 1.04 * bitrate(i-1) + 1000
// until bitrate(i) > 500000, with bitrate(1) ~= 30000.
const int kExpectedIterations = 1621;
unsigned int bitrate_bps = 30000;
int iterations = 0;
AddDefaultStream();
// Feed the estimator with a stream of packets and verify that it reaches
// 500 kbps at the expected time.
while (bitrate_bps < 5e5) {
bool overuse = GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
if (overuse) {
EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps);
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
} else if (bitrate_observer_->updated()) {
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
++iterations;
ASSERT_LE(iterations, kExpectedIterations);
}
ASSERT_EQ(kExpectedIterations, iterations);
}
void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
int number_of_streams,
bool wrap_time_stamp,
unsigned int expected_converge_bitrate,
unsigned int expected_bitrate_drop_delta) {
const int kFramerate = 30;
const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3;
const unsigned int kInitialCapacityBps = 1000e3;
const unsigned int kReducedCapacityBps = 500e3;
int steady_state_time = 0;
int expected_overuse_start_time = 0;
if (number_of_streams <= 1) {
steady_state_time = 10;
expected_overuse_start_time = 10000;
AddDefaultStream();
} else {
steady_state_time = 8 * number_of_streams;
expected_overuse_start_time = 8000;
int bitrate_sum = 0;
int kBitrateDenom = number_of_streams * (number_of_streams - 1);
for (int i = 0; i < number_of_streams; i++) {
// First stream gets half available bitrate, while the rest share the
// remaining half i.e.: 1/2 = Sum[n/(N*(N-1))] for n=1..N-1 (rounded up)
int bitrate = kStartBitrate / 2;
if (i > 0) {
bitrate = (kStartBitrate * i + kBitrateDenom / 2) / kBitrateDenom;
}
stream_generator_->AddStream(new testing::RtpStream(
kFramerate, // Frames per second.
bitrate, // Bitrate.
kDefaultSsrc + i, // SSRC.
90000, // RTP frequency.
0xFFFFF000 ^ (~0 << (32 - i)), // Timestamp offset.
0)); // RTCP receive time.
bitrate_sum += bitrate;
}
ASSERT_EQ(bitrate_sum, kStartBitrate);
}
if (wrap_time_stamp) {
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - steady_state_time * 90000);
}
// Run in steady state to make the estimator converge.
stream_generator_->set_capacity_bps(kInitialCapacityBps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
steady_state_time * kFramerate,
kStartBitrate,
kMinExpectedBitrate,
kMaxExpectedBitrate,
kInitialCapacityBps);
EXPECT_EQ(expected_converge_bitrate, bitrate_bps);
bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(kReducedCapacityBps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
EXPECT_EQ(expected_overuse_start_time, overuse_start_time);
int64_t bitrate_drop_time = -1;
for (int i = 0; i < 100 * number_of_streams; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease.
if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= kReducedCapacityBps) {
bitrate_drop_time = clock_.TimeInMilliseconds();
}
bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset();
}
}
EXPECT_EQ(expected_bitrate_drop_delta,
bitrate_drop_time - overuse_start_time);
}
} // namespace webrtc

View File

@ -23,17 +23,15 @@
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
enum { kMtu = 1200 };
namespace testing {
class TestBitrateObserver : public RemoteBitrateObserver {
public:
TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
virtual ~TestBitrateObserver() {}
void OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
unsigned int bitrate) {
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) {
latest_bitrate_ = bitrate;
updated_ = true;
}
@ -55,7 +53,6 @@ class TestBitrateObserver : public RemoteBitrateObserver {
unsigned int latest_bitrate_;
};
class RtpStream {
public:
struct RtpPacket {
@ -132,7 +129,7 @@ class StreamGenerator {
// 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);
void SetBitrateBps(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);
@ -160,13 +157,30 @@ class StreamGenerator {
class RemoteBitrateEstimatorTest : public ::testing::Test {
public:
RemoteBitrateEstimatorTest();
explicit RemoteBitrateEstimatorTest(bool align_streams);
protected:
virtual void SetUp();
virtual void SetUp() = 0;
void AddDefaultStream();
// Helper to convert some time format to resolution used in absolute send time
// header extension, rounded upwards. |t| is the time to convert, in some
// resolution. |denom| is the value to divide |t| by to get whole seconds,
// e.g. |denom| = 1000 if |t| is in milliseconds.
static uint32_t AbsSendTime(int64_t t, int64_t denom);
// Helper to add two absolute send time values and keep it less than 1<<24.
static uint32_t AddAbsSendTime(uint32_t t1, uint32_t t2);
// Helper to create a WebRtcRTPHeader containing the relevant data for the
// estimator (all other fields are cleared) and call IncomingPacket on the
// estimator.
void IncomingPacket(uint32_t ssrc,
uint32_t payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp,
uint32_t absolute_send_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.
@ -186,25 +200,24 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
unsigned int max_bitrate,
unsigned int target_bitrate);
void InitialBehaviorTestHelper(unsigned int expected_converge_bitrate);
void RateIncreaseReorderingTestHelper();
void RateIncreaseRtpTimestampsTestHelper();
void CapacityDropTestHelper(int number_of_streams,
bool wrap_time_stamp,
unsigned int expected_converge_bitrate,
unsigned int expected_bitrate_drop_delta);
static const unsigned int kDefaultSsrc;
SimulatedClock clock_; // Time at the receiver.
OverUseDetectorOptions overuse_detector_options_;
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
bool align_streams_;
scoped_ptr<testing::TestBitrateObserver> bitrate_observer_;
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
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
} // namespace webrtc
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_BITRATE_ESTIMATOR_UNITTEST_HELPER_H_

View File

@ -268,12 +268,12 @@ double RemoteRateControl::RateIncreaseFactor(int64_t now_ms,
}
void RemoteRateControl::UpdateChangePeriod(int64_t now_ms) {
int64_t changePeriod = 0;
int64_t change_period = 0;
if (last_change_ms_ > -1) {
changePeriod = now_ms - last_change_ms_;
change_period = now_ms - last_change_ms_;
}
last_change_ms_ = now_ms;
avg_change_period_ = 0.9f * avg_change_period_ + 0.1f * changePeriod;
avg_change_period_ = 0.9f * avg_change_period_ + 0.1f * change_period;
}
void RemoteRateControl::UpdateMaxBitRateEstimate(float incoming_bit_rate_kbps) {
@ -288,8 +288,8 @@ void RemoteRateControl::UpdateMaxBitRateEstimate(float incoming_bit_rate_kbps) {
// with the average max bit rate.
const float norm = std::max(avg_max_bit_rate_, 1.0f);
var_max_bit_rate_ = (1 - alpha) * var_max_bit_rate_ +
alpha * (avg_max_bit_rate_ - incoming_bit_rate_kbps) *
(avg_max_bit_rate_ - incoming_bit_rate_kbps) / norm;
alpha * (avg_max_bit_rate_ - incoming_bit_rate_kbps) *
(avg_max_bit_rate_ - incoming_bit_rate_kbps) / norm;
// 0.4 ~= 14 kbit/s at 500 kbit/s
if (var_max_bit_rate_ < 0.4f) {
var_max_bit_rate_ = 0.4f;
@ -347,7 +347,7 @@ void RemoteRateControl::ChangeState(RateControlState new_state) {
StateStr(rate_control_state_, state2);
StateStr(current_input_._bwState, state3);
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"\t%s => %s due to %s\n", state1, state2, state3);
"\t%s => %s due to %s\n", state1, state2, state3);
}
void RemoteRateControl::StateStr(RateControlState state, char* str) {

View File

@ -115,11 +115,8 @@ int32_t ViEReceiver::OnReceivedPayloadData(
// TODO(holmer): Make sure packets reconstructed using FEC are not passed to
// the bandwidth estimator.
const int packet_size = payload_size + rtp_header->header.paddingLength;
uint32_t compensated_timestamp = rtp_header->header.timestamp +
rtp_header->extension.transmissionTimeOffset;
remote_bitrate_estimator_->IncomingPacket(
rtp_header->header.ssrc, packet_size,
TickTime::MillisecondTimestamp(), compensated_timestamp);
remote_bitrate_estimator_->IncomingPacket(TickTime::MillisecondTimestamp(),
packet_size, *rtp_header);
if (vcm_->IncomingPacket(payload_data, payload_size, *rtp_header) != 0) {
// Check this...
return -1;

View File

@ -104,11 +104,10 @@ bool VieRemb::InUse() const {
return true;
}
void VieRemb::OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
void VieRemb::OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) {
WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
"VieRemb::UpdateBitrateEstimate(bitrate: %u)", bitrate);
assert(ssrcs);
list_crit_->Enter();
// If we already have an estimate, check if the new total estimate is below
// kSendThresholdPercent of the previous estimate.
@ -132,7 +131,7 @@ void VieRemb::OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
}
last_remb_time_ = now;
if (ssrcs->empty() || receive_modules_.empty()) {
if (ssrcs.empty() || receive_modules_.empty()) {
list_crit_->Leave();
return;
}
@ -154,8 +153,8 @@ void VieRemb::OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
list_crit_->Leave();
if (sender) {
// TODO(holmer): Change RTP module API to take a vector pointer.
sender->SetREMBData(bitrate_, ssrcs->size(), &(*ssrcs)[0]);
// TODO(holmer): Change RTP module API to take a const vector reference.
sender->SetREMBData(bitrate_, ssrcs.size(), &ssrcs[0]);
}
}

View File

@ -51,7 +51,7 @@ class VieRemb : public RemoteBitrateObserver {
// estimate has decreased or if no RTCP REMB packet has been sent for
// a certain time interval.
// Implements RtpReceiveBitrateUpdate.
virtual void OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate);
private:

View File

@ -59,17 +59,17 @@ TEST_F(ViERembTest, OneModuleTestForSendingRemb) {
unsigned int ssrc = 1234;
std::vector<unsigned int> ssrcs(&ssrc, &ssrc + 1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Lower bitrate to send another REMB packet.
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate - 100);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate - 100);
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
@ -84,19 +84,19 @@ TEST_F(ViERembTest, LowerEstimateToSendRemb) {
unsigned int ssrc = 1234;
std::vector<unsigned int> ssrcs(&ssrc, &ssrc + 1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Lower the estimate with more than 3% to trigger a call to SetREMBData right
// away.
bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
}
TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
@ -110,20 +110,20 @@ TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
unsigned int ssrc[] = { 1234, 5678 };
std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0]));
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[0]);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate[0]);
// Call OnReceiveBitrateChanged twice to get a first estimate.
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0], 2, _))
.Times(1);
TickTime::AdvanceFakeClock(1000);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[0]);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate[0]);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1] + 100);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate[1] + 100);
// Lower the estimate to trigger a callback.
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[1], 2, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1]);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate[1]);
vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0);
@ -141,23 +141,23 @@ TEST_F(ViERembTest, NoRembForIncreasedBitrate) {
unsigned int ssrc[] = { 1234, 5678 };
std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0]));
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Increased estimate shouldn't trigger a callback right away.
EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
.Times(0);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate + 1);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate + 1);
// Decreasing the estimate less than 3% shouldn't trigger a new callback.
EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
.Times(0);
int lower_estimate = bitrate_estimate * 98 / 100;
vie_remb_->OnReceiveBitrateChanged(&ssrcs, lower_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, lower_estimate);
vie_remb_->RemoveReceiveChannel(&rtp_1);
vie_remb_->RemoveReceiveChannel(&rtp_0);
@ -175,29 +175,29 @@ TEST_F(ViERembTest, ChangeSendRtpModule) {
unsigned int ssrc[] = { 1234, 5678 };
std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0]));
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Decrease estimate to trigger a REMB.
bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Remove the sending module, add it again -> should get remb on the second
// module.
vie_remb_->RemoveRembSender(&rtp_0);
vie_remb_->AddRembSender(&rtp_1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate, 2, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveReceiveChannel(&rtp_1);
@ -211,23 +211,23 @@ TEST_F(ViERembTest, OnlyOneRembForDoubleProcess) {
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Lower the estimate, should trigger a call to SetREMBData right away.
bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged again, this should not trigger a new callback.
EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(0);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
}
@ -242,19 +242,19 @@ TEST_F(ViERembTest, NoSendingRtpModule) {
unsigned int ssrc = 1234;
std::vector<unsigned int> ssrcs(&ssrc, &ssrc + 1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
// Lower the estimate to trigger a new packet REMB packet.
bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->OnReceiveBitrateChanged(ssrcs, bitrate_estimate);
}
} // namespace webrtc