Break out RemoteBitrateEstimator from RtpRtcp module and make RemoteBitrateEstimator::Process trigger new REMB messages.

Also make sure RTT is computed independently of whether it's time to send RTCP messages or not.

BUG=1298

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3455 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2013-02-01 14:33:42 +00:00
parent 46d90dcd74
commit b586507986
32 changed files with 523 additions and 393 deletions

View File

@ -320,6 +320,16 @@ struct FecProtectionParams {
FecMaskType fec_mask_type; FecMaskType fec_mask_type;
}; };
// Interface used by the CallStats class to distribute call statistics.
// Callbacks will be triggered as soon as the class has been registered to a
// CallStats object using RegisterStatsObserver.
class StatsObserver {
public:
virtual void OnRttUpdate(uint32_t rtt_ms) = 0;
virtual ~StatsObserver() {}
};
// class describing a complete, or parts of an encoded frame. // class describing a complete, or parts of an encoded frame.
class EncodedVideoData class EncodedVideoData
{ {

View File

@ -19,9 +19,9 @@
namespace webrtc { namespace webrtc {
enum BandwidthUsage enum BandwidthUsage
{ {
kBwNormal, kBwNormal = 0,
kBwOverusing, kBwUnderusing = 1,
kBwUnderusing kBwOverusing = 2,
}; };
enum RateControlState enum RateControlState

View File

@ -16,11 +16,15 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "common_types.h" #include "webrtc/common_types.h"
#include "typedefs.h" #include "webrtc/modules/interface/module.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc { namespace webrtc {
class Clock;
// RemoteBitrateObserver is used to signal changes in bitrate estimates for // RemoteBitrateObserver is used to signal changes in bitrate estimates for
// the incoming streams. // the incoming streams.
class RemoteBitrateObserver { class RemoteBitrateObserver {
@ -33,7 +37,7 @@ class RemoteBitrateObserver {
virtual ~RemoteBitrateObserver() {} virtual ~RemoteBitrateObserver() {}
}; };
class RemoteBitrateEstimator { class RemoteBitrateEstimator : public StatsObserver, public Module {
public: public:
enum EstimationMode { enum EstimationMode {
kMultiStreamEstimation, kMultiStreamEstimation,
@ -42,9 +46,10 @@ class RemoteBitrateEstimator {
virtual ~RemoteBitrateEstimator() {} virtual ~RemoteBitrateEstimator() {}
static RemoteBitrateEstimator* Create(RemoteBitrateObserver* observer, static RemoteBitrateEstimator* Create(const OverUseDetectorOptions& options,
const OverUseDetectorOptions& options, EstimationMode mode,
EstimationMode mode); RemoteBitrateObserver* observer,
Clock* clock);
// Stores an RTCP SR (NTP, RTP timestamp) tuple for a specific SSRC to be used // 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 // in future RTP timestamp to NTP time conversions. As soon as any SSRC has
@ -61,13 +66,6 @@ class RemoteBitrateEstimator {
int64_t arrival_time, int64_t arrival_time,
uint32_t rtp_timestamp) = 0; uint32_t rtp_timestamp) = 0;
// Triggers a new estimate calculation.
virtual void UpdateEstimate(unsigned int ssrc, int64_t time_now) = 0;
// Set the current round-trip time experienced by the streams going into this
// estimator.
virtual void SetRtt(unsigned int rtt) = 0;
// Removes all data for |ssrc|. // Removes all data for |ssrc|.
virtual void RemoveStream(unsigned int ssrc) = 0; virtual void RemoveStream(unsigned int ssrc) = 0;
@ -76,6 +74,10 @@ class RemoteBitrateEstimator {
// currently being received and of which the bitrate estimate is based upon. // currently being received and of which the bitrate estimate is based upon.
virtual bool LatestEstimate(std::vector<unsigned int>* ssrcs, virtual bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const = 0; unsigned int* bitrate_bps) const = 0;
protected:
static const int kProcessIntervalMs = 1000;
static const int kStreamTimeOutMs = 2000;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -43,7 +43,8 @@ OveruseDetector::OveruseDetector(const OverUseDetectorOptions& options)
prev_offset_(0.0), prev_offset_(0.0),
time_over_using_(-1), time_over_using_(-1),
over_use_counter_(0), over_use_counter_(0),
hypothesis_(kBwNormal) hypothesis_(kBwNormal),
time_of_last_received_packet_(-1)
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
, plots_() , plots_()
#endif #endif
@ -80,6 +81,7 @@ void OveruseDetector::Update(uint16_t packet_size,
int64_t timestamp_ms, int64_t timestamp_ms,
uint32_t timestamp, uint32_t timestamp,
const int64_t now_ms) { const int64_t now_ms) {
time_of_last_received_packet_ = now_ms;
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
// Create plots // Create plots
const int64_t startTimeMs = nowMS; const int64_t startTimeMs = nowMS;
@ -166,6 +168,10 @@ void OveruseDetector::SetRateControlRegion(RateControlRegion region) {
} }
} }
int64_t OveruseDetector::time_of_last_received_packet() const {
return time_of_last_received_packet_;
}
void OveruseDetector::SwitchTimeBase() { void OveruseDetector::SwitchTimeBase() {
current_frame_.size = 0; current_frame_.size = 0;
current_frame_.complete_time_ms = -1; current_frame_.complete_time_ms = -1;

View File

@ -23,6 +23,8 @@
namespace webrtc { namespace webrtc {
enum RateControlRegion; enum RateControlRegion;
// This class is assumed to be protected by the owner if used by multiple
// threads.
class OveruseDetector { class OveruseDetector {
public: public:
explicit OveruseDetector(const OverUseDetectorOptions& options); explicit OveruseDetector(const OverUseDetectorOptions& options);
@ -34,6 +36,7 @@ class OveruseDetector {
BandwidthUsage State() const; BandwidthUsage State() const;
double NoiseVar() const; double NoiseVar() const;
void SetRateControlRegion(RateControlRegion region); void SetRateControlRegion(RateControlRegion region);
int64_t time_of_last_received_packet() const;
private: private:
struct FrameSample { struct FrameSample {
@ -100,6 +103,7 @@ class OveruseDetector {
double time_over_using_; double time_over_using_;
uint16_t over_use_counter_; uint16_t over_use_counter_;
BandwidthUsage hypothesis_; BandwidthUsage hypothesis_;
int64_t time_of_last_received_packet_;
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
DebugPlots plots_; DebugPlots plots_;
#endif #endif

View File

@ -8,38 +8,43 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_multi_stream.h" #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_multi_stream.h"
#include "modules/remote_bitrate_estimator/include/rtp_to_ntp.h" #include "webrtc/modules/remote_bitrate_estimator/include/rtp_to_ntp.h"
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h" #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
#include "system_wrappers/interface/tick_util.h" #include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
namespace webrtc { namespace webrtc {
RemoteBitrateEstimator* RemoteBitrateEstimator::Create( RemoteBitrateEstimator* RemoteBitrateEstimator::Create(
RemoteBitrateObserver* observer,
const OverUseDetectorOptions& options, const OverUseDetectorOptions& options,
EstimationMode mode) { EstimationMode mode,
RemoteBitrateObserver* observer,
Clock* clock) {
switch (mode) { switch (mode) {
case kMultiStreamEstimation: case kMultiStreamEstimation:
return new RemoteBitrateEstimatorMultiStream(observer, options); return new RemoteBitrateEstimatorMultiStream(options, observer, clock);
case kSingleStreamEstimation: case kSingleStreamEstimation:
return new RemoteBitrateEstimatorSingleStream(observer, options); return new RemoteBitrateEstimatorSingleStream(options, observer, clock);
} }
return NULL; return NULL;
} }
RemoteBitrateEstimatorMultiStream::RemoteBitrateEstimatorMultiStream( RemoteBitrateEstimatorMultiStream::RemoteBitrateEstimatorMultiStream(
const OverUseDetectorOptions& options,
RemoteBitrateObserver* observer, RemoteBitrateObserver* observer,
const OverUseDetectorOptions& options) Clock* clock)
: remote_rate_(), : clock_(clock),
remote_rate_(),
overuse_detector_(options), overuse_detector_(options),
incoming_bitrate_(), incoming_bitrate_(),
observer_(observer), observer_(observer),
streams_(), streams_(),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
initial_ssrc_(0), initial_ssrc_(0),
multi_stream_(false) { multi_stream_(false),
last_process_time_(-1) {
assert(observer_); assert(observer_);
} }
@ -108,16 +113,45 @@ void RemoteBitrateEstimatorMultiStream::IncomingPacket(unsigned int ssrc,
} }
overuse_detector_.Update(payload_size, timestamp_in_ms, rtp_timestamp, overuse_detector_.Update(payload_size, timestamp_in_ms, rtp_timestamp,
arrival_time); arrival_time);
if (prior_state != kBwOverusing && if (overuse_detector_.State() == kBwOverusing) {
overuse_detector_.State() == kBwOverusing) { unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time);
// The first overuse should immediately trigger a new estimate. if (prior_state != kBwOverusing ||
UpdateEstimate(1, arrival_time); remote_rate_.TimeToReduceFurther(arrival_time, 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);
}
} }
} }
void RemoteBitrateEstimatorMultiStream::UpdateEstimate(unsigned int ssrc, int32_t RemoteBitrateEstimatorMultiStream::Process() {
int64_t time_now) { if (TimeUntilNextProcess() > 0) {
return 0;
}
UpdateEstimate(clock_->TimeInMilliseconds());
last_process_time_ = clock_->TimeInMilliseconds();
return 0;
}
int32_t RemoteBitrateEstimatorMultiStream::TimeUntilNextProcess() {
if (last_process_time_ < 0) {
return 0;
}
return last_process_time_ + kProcessIntervalMs - clock_->TimeInMilliseconds();
}
void RemoteBitrateEstimatorMultiStream::UpdateEstimate(int64_t time_now) {
CriticalSectionScoped cs(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
const int64_t time_of_last_received_packet =
overuse_detector_.time_of_last_received_packet();
if (time_of_last_received_packet >= 0 &&
time_now - time_of_last_received_packet > kStreamTimeOutMs) {
// This over-use detector hasn't received packets for |kStreamTimeOutMs|
// milliseconds and is considered stale.
remote_rate_.Reset();
return;
}
const RateControlInput input(overuse_detector_.State(), const RateControlInput input(overuse_detector_.State(),
incoming_bitrate_.BitRate(time_now), incoming_bitrate_.BitRate(time_now),
overuse_detector_.NoiseVar()); overuse_detector_.NoiseVar());
@ -133,7 +167,7 @@ void RemoteBitrateEstimatorMultiStream::UpdateEstimate(unsigned int ssrc,
overuse_detector_.SetRateControlRegion(region); overuse_detector_.SetRateControlRegion(region);
} }
void RemoteBitrateEstimatorMultiStream::SetRtt(unsigned int rtt) { void RemoteBitrateEstimatorMultiStream::OnRttUpdate(uint32_t rtt) {
CriticalSectionScoped cs(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
remote_rate_.SetRtt(rtt); remote_rate_.SetRtt(rtt);
} }

View File

@ -27,10 +27,13 @@
namespace webrtc { namespace webrtc {
class Clock;
class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator { class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
public: public:
RemoteBitrateEstimatorMultiStream(RemoteBitrateObserver* observer, RemoteBitrateEstimatorMultiStream(const OverUseDetectorOptions& options,
const OverUseDetectorOptions& options); RemoteBitrateObserver* observer,
Clock* clock);
~RemoteBitrateEstimatorMultiStream() {} ~RemoteBitrateEstimatorMultiStream() {}
@ -52,11 +55,12 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
uint32_t rtp_timestamp); uint32_t rtp_timestamp);
// Triggers a new estimate calculation. // Triggers a new estimate calculation.
void UpdateEstimate(unsigned int ssrc, int64_t time_now); // Implements the Module interface.
virtual int32_t Process();
// Set the current round-trip time experienced by the streams going into this virtual int32_t TimeUntilNextProcess();
// estimator. // Set the current round-trip time experienced by the stream.
void SetRtt(unsigned int rtt); // Implements the StatsObserver interface.
virtual void OnRttUpdate(uint32_t rtt);
// Removes all data for |ssrc|. // Removes all data for |ssrc|.
void RemoveStream(unsigned int ssrc); void RemoveStream(unsigned int ssrc);
@ -70,8 +74,12 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
private: private:
typedef std::map<unsigned int, synchronization::RtcpList> StreamMap; typedef std::map<unsigned int, synchronization::RtcpList> StreamMap;
// Triggers a new estimate calculation.
void UpdateEstimate(int64_t time_now);
void GetSsrcs(std::vector<unsigned int>* ssrcs) const; void GetSsrcs(std::vector<unsigned int>* ssrcs) const;
Clock* clock_;
RemoteRateControl remote_rate_; RemoteRateControl remote_rate_;
OveruseDetector overuse_detector_; OveruseDetector overuse_detector_;
BitRateStats incoming_bitrate_; BitRateStats incoming_bitrate_;
@ -80,6 +88,7 @@ class RemoteBitrateEstimatorMultiStream : public RemoteBitrateEstimator {
scoped_ptr<CriticalSectionWrapper> crit_sect_; scoped_ptr<CriticalSectionWrapper> crit_sect_;
unsigned int initial_ssrc_; unsigned int initial_ssrc_;
bool multi_stream_; bool multi_stream_;
int32_t last_process_time_;
DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorMultiStream); DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorMultiStream);
}; };

View File

@ -8,17 +8,21 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h" #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
#include "system_wrappers/interface/tick_util.h" #include "webrtc/system_wrappers/interface/clock.h"
namespace webrtc { namespace webrtc {
RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream( RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream(
RemoteBitrateObserver* observer, const OverUseDetectorOptions& options) const OverUseDetectorOptions& options,
RemoteBitrateObserver* observer,
Clock* clock)
: options_(options), : options_(options),
clock_(clock),
observer_(observer), observer_(observer),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) { crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
last_process_time_(-1) {
assert(observer_); assert(observer_);
} }
@ -45,37 +49,80 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
incoming_bitrate_.Update(payload_size, arrival_time); incoming_bitrate_.Update(payload_size, arrival_time);
const BandwidthUsage prior_state = overuse_detector->State(); 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);
if (prior_state != overuse_detector->State() && if (overuse_detector->State() == kBwOverusing) {
overuse_detector->State() == kBwOverusing) { unsigned int incoming_bitrate = incoming_bitrate_.BitRate(arrival_time);
// The first overuse should immediately trigger a new estimate. if (prior_state != kBwOverusing ||
UpdateEstimate(ssrc, arrival_time); remote_rate_.TimeToReduceFurther(arrival_time, 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);
}
} }
} }
void RemoteBitrateEstimatorSingleStream::UpdateEstimate(unsigned int ssrc, int32_t RemoteBitrateEstimatorSingleStream::Process() {
int64_t time_now) { if (TimeUntilNextProcess() > 0) {
return 0;
}
UpdateEstimate(clock_->TimeInMilliseconds());
last_process_time_ = clock_->TimeInMilliseconds();
return 0;
}
int32_t RemoteBitrateEstimatorSingleStream::TimeUntilNextProcess() {
if (last_process_time_ < 0) {
return 0;
}
return last_process_time_ + kProcessIntervalMs - clock_->TimeInMilliseconds();
}
void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t time_now) {
CriticalSectionScoped cs(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
SsrcOveruseDetectorMap::iterator it = overuse_detectors_.find(ssrc); BandwidthUsage bw_state = kBwNormal;
if (it == overuse_detectors_.end()) { double sum_noise_var = 0.0;
SsrcOveruseDetectorMap::iterator it = overuse_detectors_.begin();
while (it != overuse_detectors_.end()) {
const int64_t time_of_last_received_packet =
it->second.time_of_last_received_packet();
if (time_of_last_received_packet >= 0 &&
time_now - time_of_last_received_packet > kStreamTimeOutMs) {
// This over-use detector hasn't received packets for |kStreamTimeOutMs|
// milliseconds and is considered stale.
overuse_detectors_.erase(it++);
} else {
sum_noise_var += it->second.NoiseVar();
// Make sure that we trigger an over-use if any of the over-use detectors
// is detecting over-use.
if (it->second.State() > bw_state) {
bw_state = it->second.State();
}
++it;
}
}
// We can't update the estimate if we don't have any active streams.
if (overuse_detectors_.empty()) {
remote_rate_.Reset();
return; return;
} }
OveruseDetector* overuse_detector = &it->second; double mean_noise_var = sum_noise_var /
const RateControlInput input(overuse_detector->State(), static_cast<double>(overuse_detectors_.size());
const RateControlInput input(bw_state,
incoming_bitrate_.BitRate(time_now), incoming_bitrate_.BitRate(time_now),
overuse_detector->NoiseVar()); mean_noise_var);
const RateControlRegion region = remote_rate_.Update(&input, time_now); const RateControlRegion region = remote_rate_.Update(&input, time_now);
unsigned int target_bitrate = remote_rate_.UpdateBandwidthEstimate(time_now); unsigned int target_bitrate = remote_rate_.UpdateBandwidthEstimate(time_now);
if (remote_rate_.ValidEstimate()) { if (remote_rate_.ValidEstimate()) {
std::vector<unsigned int> ssrcs; std::vector<unsigned int> ssrcs;
GetSsrcs(&ssrcs); GetSsrcs(&ssrcs);
if (!ssrcs.empty()) { observer_->OnReceiveBitrateChanged(&ssrcs, target_bitrate);
observer_->OnReceiveBitrateChanged(&ssrcs, target_bitrate); }
} for (it = overuse_detectors_.begin(); it != overuse_detectors_.end(); ++it) {
it->second.SetRateControlRegion(region);
} }
overuse_detector->SetRateControlRegion(region);
} }
void RemoteBitrateEstimatorSingleStream::SetRtt(unsigned int rtt) { void RemoteBitrateEstimatorSingleStream::OnRttUpdate(uint32_t rtt) {
CriticalSectionScoped cs(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
remote_rate_.SetRtt(rtt); remote_rate_.SetRtt(rtt);
} }

View File

@ -15,20 +15,25 @@
#include <map> #include <map>
#include "modules/remote_bitrate_estimator/bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/overuse_detector.h" #include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
#include "modules/remote_bitrate_estimator/remote_rate_control.h" #include "webrtc/modules/remote_bitrate_estimator/remote_rate_control.h"
#include "system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "typedefs.h" #include "webrtc/typedefs.h"
namespace webrtc { namespace webrtc {
class Clock;
class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator { class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
public: public:
RemoteBitrateEstimatorSingleStream(RemoteBitrateObserver* observer, RemoteBitrateEstimatorSingleStream(const OverUseDetectorOptions& options,
const OverUseDetectorOptions& options); RemoteBitrateObserver* observer,
Clock* clock);
virtual ~RemoteBitrateEstimatorSingleStream() {}
void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs, uint32_t ntp_frac, void IncomingRtcp(unsigned int ssrc, uint32_t ntp_secs, uint32_t ntp_frac,
uint32_t rtp_timestamp) {} uint32_t rtp_timestamp) {}
@ -43,12 +48,13 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
int64_t arrival_time, int64_t arrival_time,
uint32_t rtp_timestamp); uint32_t rtp_timestamp);
// Triggers a new estimate calculation for the stream identified by |ssrc|. // Triggers a new estimate calculation.
void UpdateEstimate(unsigned int ssrc, int64_t time_now); // Implements the Module interface.
virtual int32_t Process();
// Set the current round-trip time experienced by the stream identified by virtual int32_t TimeUntilNextProcess();
// |ssrc|. // Set the current round-trip time experienced by the stream.
void SetRtt(unsigned int ssrc); // Implements the StatsObserver interface.
virtual void OnRttUpdate(uint32_t rtt);
// Removes all data for |ssrc|. // Removes all data for |ssrc|.
void RemoveStream(unsigned int ssrc); void RemoveStream(unsigned int ssrc);
@ -62,14 +68,19 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
private: private:
typedef std::map<unsigned int, OveruseDetector> SsrcOveruseDetectorMap; typedef std::map<unsigned int, OveruseDetector> SsrcOveruseDetectorMap;
// Triggers a new estimate calculation.
void UpdateEstimate(int64_t time_now);
void GetSsrcs(std::vector<unsigned int>* ssrcs) const; void GetSsrcs(std::vector<unsigned int>* ssrcs) const;
const OverUseDetectorOptions& options_; const OverUseDetectorOptions& options_;
Clock* clock_;
SsrcOveruseDetectorMap overuse_detectors_; SsrcOveruseDetectorMap overuse_detectors_;
BitRateStats incoming_bitrate_; BitRateStats incoming_bitrate_;
RemoteRateControl remote_rate_; RemoteRateControl remote_rate_;
RemoteBitrateObserver* observer_; RemoteBitrateObserver* observer_;
scoped_ptr<CriticalSectionWrapper> crit_sect_; scoped_ptr<CriticalSectionWrapper> crit_sect_;
int64_t last_process_time_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -23,73 +23,84 @@
namespace webrtc { namespace webrtc {
TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) { TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
unsigned int bitrate_bps = 0; unsigned int bitrate_bps = 0;
int64_t time_now = 0;
uint32_t timestamp = 0; uint32_t timestamp = 0;
std::vector<unsigned int> ssrcs; std::vector<unsigned int> ssrcs;
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size()); EXPECT_EQ(0u, ssrcs.size());
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); clock_.AdvanceTimeMilliseconds(1000);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_FALSE(bitrate_observer_->updated()); EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset(); bitrate_observer_->Reset();
clock_.AdvanceTimeMilliseconds(1000);
// Inserting a packet. Still no valid estimate. We need to wait 1 second. // Inserting a packet. Still no valid estimate. We need to wait 1 second.
bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu, time_now, bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
timestamp); clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(0u, ssrcs.size()); EXPECT_EQ(0u, ssrcs.size());
EXPECT_FALSE(bitrate_observer_->updated()); EXPECT_FALSE(bitrate_observer_->updated());
bitrate_observer_->Reset(); bitrate_observer_->Reset();
// Waiting more than one second gives us a valid estimate. // Inserting packets for one second to get a valid estimate.
// We need at least two packets for the incoming bitrate to be > 0 since the for (int i = 0; i < kFramerate; ++i) {
// window is 500 ms. bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
time_now += 499; clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu, time_now, clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
timestamp); timestamp += 90 * kFrameIntervalMs;
time_now += 2; }
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
EXPECT_EQ(1u, ssrcs.size()); ASSERT_EQ(1u, ssrcs.size());
EXPECT_EQ(kDefaultSsrc, ssrcs.front()); EXPECT_EQ(kDefaultSsrc, ssrcs.front());
EXPECT_EQ(20607u, bitrate_bps); EXPECT_EQ(498075u, bitrate_bps);
EXPECT_TRUE(bitrate_observer_->updated()); EXPECT_TRUE(bitrate_observer_->updated());
bitrate_observer_->Reset(); bitrate_observer_->Reset();
EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps); EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
} }
TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseReordering) { TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseReordering) {
int64_t time_now = 0;
uint32_t timestamp = 0; uint32_t timestamp = 0;
const int framerate = 50; // 50 fps to avoid rounding errors. const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int frame_interval_ms = 1000 / framerate; const int kFrameIntervalMs = 1000 / kFramerate;
bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000, time_now, timestamp); bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000,
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->Process();
EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate. EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate.
// Increase time with 1 second to get a valid estimate. // Inserting packets for one second to get a valid estimate.
time_now += 1000; for (int i = 0; i < kFramerate; ++i) {
timestamp += 90 * 1000; bitrate_estimator_->IncomingPacket(kDefaultSsrc, kMtu,
bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000, time_now, timestamp); clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
timestamp += 90 * kFrameIntervalMs;
}
bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated()); EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(17645u, bitrate_observer_->latest_bitrate()); EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
time_now += 2 * frame_interval_ms; clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
timestamp += 2 * 90 * frame_interval_ms; timestamp += 2 * 90 * kFrameIntervalMs;
bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000, time_now, timestamp); bitrate_estimator_->IncomingPacket(kDefaultSsrc, 1000,
clock_.TimeInMilliseconds(), timestamp);
bitrate_estimator_->IncomingPacket(kDefaultSsrc, bitrate_estimator_->IncomingPacket(kDefaultSsrc,
1000, 1000,
time_now - frame_interval_ms, clock_.TimeInMilliseconds() -
timestamp - 90 * frame_interval_ms); kFrameIntervalMs,
timestamp - 90 * kFrameIntervalMs);
} }
bitrate_estimator_->UpdateEstimate(kDefaultSsrc, time_now); bitrate_estimator_->Process();
EXPECT_TRUE(bitrate_observer_->updated()); EXPECT_TRUE(bitrate_observer_->updated());
EXPECT_EQ(18985u, bitrate_observer_->latest_bitrate()); EXPECT_EQ(498136u, bitrate_observer_->latest_bitrate());
} }
// Make sure we initially increase the bitrate as expected. // Make sure we initially increase the bitrate as expected.
TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) { TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) {
const int kExpectedIterations = 276; // 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; unsigned int bitrate_bps = 30000;
int iterations = 0; int iterations = 0;
AddDefaultStream(); AddDefaultStream();
@ -114,32 +125,35 @@ TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) {
// Verify that the time it takes for the estimator to reduce the bitrate when // Verify that the time it takes for the estimator to reduce the bitrate when
// the capacity is tightened stays the same. // the capacity is tightened stays the same.
TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestamps) { TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestamps) {
const int kNumberOfFrames= 300; const int kNumberOfFrames = 300;
const int kStartBitrate = 900e3; const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3; const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3; const int kMaxExpectedBitrate = 1100e3;
AddDefaultStream(); AddDefaultStream();
// Run in steady state to make the estimator converge. // Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(1000e3); stream_generator_->set_capacity_bps(1000e3);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, kNumberOfFrames, unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, kNumberOfFrames,
kStartBitrate, kMinExpectedBitrate, kStartBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate); kMaxExpectedBitrate, capacity_bps);
// Reduce the capacity and verify the decrease time. // Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(500e3); capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1; int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease. // Check for either increase or decrease.
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 && if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= 500e3) { bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = time_now_; bitrate_drop_time = clock_.TimeInMilliseconds();
} }
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
} }
EXPECT_EQ(10333, bitrate_drop_time); EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
} }
// Verify that the time it takes for the estimator to reduce the bitrate when // Verify that the time it takes for the estimator to reduce the bitrate when
@ -156,29 +170,33 @@ TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestampsWrap) {
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc, stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000); std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000);
// Run in steady state to make the estimator converge. // Run in steady state to make the estimator converge.
unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(1000e3); stream_generator_->set_capacity_bps(1000e3);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate, kSteadyStateTime * kFramerate,
kStartBitrate, kStartBitrate,
kMinExpectedBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate); kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset(); bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time. // Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(500e3); capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1; int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease. // Check for either increase or decrease.
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 && if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= 500e3) { bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = time_now_; bitrate_drop_time = clock_.TimeInMilliseconds();
} }
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
} }
EXPECT_EQ(8299, bitrate_drop_time); EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
} }
// Verify that the time it takes for the estimator to reduce the bitrate when // Verify that the time it takes for the estimator to reduce the bitrate when
@ -196,29 +214,33 @@ TEST_F(RemoteBitrateEstimatorTestAlign, TestCapacityDropRtpTimestampsWrap) {
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc, stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000); std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000);
// Run in steady state to make the estimator converge. // Run in steady state to make the estimator converge.
stream_generator_->set_capacity_bps(1000e3); unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate, kSteadyStateTime * kFramerate,
kStartBitrate, kStartBitrate,
kMinExpectedBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate); kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset(); bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time. // Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(500e3); capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1; int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease. // Check for either increase or decrease.
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 && if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= 500e3) { bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = time_now_; bitrate_drop_time = clock_.TimeInMilliseconds();
} }
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
} }
EXPECT_EQ(8299, bitrate_drop_time); EXPECT_EQ(367, bitrate_drop_time - overuse_start_time);
} }
// Verify that the time it takes for the estimator to reduce the bitrate when // Verify that the time it takes for the estimator to reduce the bitrate when
@ -229,7 +251,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, TwoStreamsCapacityDropWithWrap) {
const int kStartBitrate = 900e3; const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3; const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3; const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateTime = 7; // Seconds. const int kSteadyStateFrames = 9 * kFramerate;
stream_generator_->AddStream(new testing::RtpStream( stream_generator_->AddStream(new testing::RtpStream(
30, // Frames per second. 30, // Frames per second.
kStartBitrate/2, // Bitrate. kStartBitrate/2, // Bitrate.
@ -247,31 +269,35 @@ TEST_F(RemoteBitrateEstimatorTestAlign, TwoStreamsCapacityDropWithWrap) {
0)); // RTCP receive time. 0)); // RTCP receive time.
// Trigger wrap right after the steady state run. // Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc, stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000); std::numeric_limits<uint32_t>::max() - kSteadyStateFrames * 90000);
// Run in steady state to make the estimator converge. // Run in steady state to make the estimator converge.
stream_generator_->set_capacity_bps(1000e3); unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate, kSteadyStateFrames,
kStartBitrate, kStartBitrate,
kMinExpectedBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate); kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset(); bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time. // Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(500e3); capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1; int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease. // Check for either increase or decrease.
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 && if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= 500e3) { bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = time_now_; bitrate_drop_time = clock_.TimeInMilliseconds();
} }
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
} }
EXPECT_EQ(4933, bitrate_drop_time); EXPECT_EQ(567, bitrate_drop_time - overuse_start_time);
} }
// Verify that the time it takes for the estimator to reduce the bitrate when // Verify that the time it takes for the estimator to reduce the bitrate when
@ -282,9 +308,9 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
const int kStartBitrate = 900e3; const int kStartBitrate = 900e3;
const int kMinExpectedBitrate = 800e3; const int kMinExpectedBitrate = 800e3;
const int kMaxExpectedBitrate = 1100e3; const int kMaxExpectedBitrate = 1100e3;
const int kSteadyStateTime = 11; // Seconds. const int kSteadyStateFrames = 12 * kFramerate;
stream_generator_->AddStream(new testing::RtpStream( stream_generator_->AddStream(new testing::RtpStream(
30, // Frames per second. kFramerate, // Frames per second.
kStartBitrate/2, // Bitrate. kStartBitrate/2, // Bitrate.
1, // SSRC. 1, // SSRC.
90000, // RTP frequency. 90000, // RTP frequency.
@ -292,7 +318,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
0)); // RTCP receive time. 0)); // RTCP receive time.
stream_generator_->AddStream(new testing::RtpStream( stream_generator_->AddStream(new testing::RtpStream(
30, // Frames per second. kFramerate, // Frames per second.
kStartBitrate/3, // Bitrate. kStartBitrate/3, // Bitrate.
2, // SSRC. 2, // SSRC.
90000, // RTP frequency. 90000, // RTP frequency.
@ -300,7 +326,7 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
0)); // RTCP receive time. 0)); // RTCP receive time.
stream_generator_->AddStream(new testing::RtpStream( stream_generator_->AddStream(new testing::RtpStream(
30, // Frames per second. kFramerate, // Frames per second.
kStartBitrate/6, // Bitrate. kStartBitrate/6, // Bitrate.
3, // SSRC. 3, // SSRC.
90000, // RTP frequency. 90000, // RTP frequency.
@ -308,31 +334,35 @@ TEST_F(RemoteBitrateEstimatorTestAlign, ThreeStreams) {
0)); // RTCP receive time. 0)); // RTCP receive time.
// Trigger wrap right after the steady state run. // Trigger wrap right after the steady state run.
stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc, stream_generator_->set_rtp_timestamp_offset(kDefaultSsrc,
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000); std::numeric_limits<uint32_t>::max() - kSteadyStateFrames * 90000);
// Run in steady state to make the estimator converge. // Run in steady state to make the estimator converge.
stream_generator_->set_capacity_bps(1000e3); unsigned int capacity_bps = 1000e3;
stream_generator_->set_capacity_bps(capacity_bps);
unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc, unsigned int bitrate_bps = SteadyStateRun(kDefaultSsrc,
kSteadyStateTime * kFramerate, kSteadyStateFrames,
kStartBitrate, kStartBitrate,
kMinExpectedBitrate, kMinExpectedBitrate,
kMaxExpectedBitrate); kMaxExpectedBitrate,
capacity_bps);
bitrate_observer_->Reset(); bitrate_observer_->Reset();
// Reduce the capacity and verify the decrease time. // Reduce the capacity and verify the decrease time.
stream_generator_->set_capacity_bps(500e3); capacity_bps = 500e3;
stream_generator_->set_capacity_bps(capacity_bps);
int64_t overuse_start_time = clock_.TimeInMilliseconds();
int64_t bitrate_drop_time = -1; int64_t bitrate_drop_time = -1;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
// Check for either increase or decrease. // Check for either increase or decrease.
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
if (bitrate_drop_time == -1 && if (bitrate_drop_time == -1 &&
bitrate_observer_->latest_bitrate() <= 500e3) { bitrate_observer_->latest_bitrate() <= capacity_bps) {
bitrate_drop_time = time_now_; bitrate_drop_time = clock_.TimeInMilliseconds();
} }
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
} }
EXPECT_EQ(3966, bitrate_drop_time); EXPECT_EQ(433, bitrate_drop_time - overuse_start_time);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -39,25 +39,25 @@ void RtpStream::set_rtp_timestamp_offset(uint32_t offset) {
// Generates a new frame for this stream. If called too soon after the // 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 // previous frame, no frame will be generated. The frame is split into
// packets. // packets.
int64_t RtpStream::GenerateFrame(double time_now, PacketList* packets) { int64_t RtpStream::GenerateFrame(int64_t time_now_us, PacketList* packets) {
if (time_now < next_rtp_time_) { if (time_now_us < next_rtp_time_) {
return next_rtp_time_; return next_rtp_time_;
} }
assert(packets != NULL); assert(packets != NULL);
int bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_; int bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_;
int n_packets = std::max((bits_per_frame + 8 * kMtu) / (8 * kMtu), 1); int n_packets = std::max((bits_per_frame + 4 * kMtu) / (8 * kMtu), 1);
int packet_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets); int packet_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets);
assert(n_packets >= 0); assert(n_packets >= 0);
for (int i = 0; i < n_packets; ++i) { for (int i = 0; i < n_packets; ++i) {
RtpPacket* packet = new RtpPacket; RtpPacket* packet = new RtpPacket;
packet->send_time = time_now + kSendSideOffsetMs + 0.5f; packet->send_time = time_now_us + kSendSideOffsetUs;
packet->size = packet_size; packet->size = packet_size;
packet->rtp_timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>( packet->rtp_timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
(frequency_ / 1000.0) * packet->send_time + 0.5); ((frequency_ / 1000) * packet->send_time + 500) / 1000);
packet->ssrc = ssrc_; packet->ssrc = ssrc_;
packets->push_back(packet); packets->push_back(packet);
} }
next_rtp_time_ = time_now + 1000.0 / static_cast<double>(fps_); next_rtp_time_ = time_now_us + (1000000 + fps_ / 2) / fps_;
return next_rtp_time_; return next_rtp_time_;
} }
@ -67,18 +67,18 @@ double RtpStream::next_rtp_time() const {
} }
// Generates an RTCP packet. // Generates an RTCP packet.
RtpStream::RtcpPacket* RtpStream::Rtcp(double time_now) { RtpStream::RtcpPacket* RtpStream::Rtcp(int64_t time_now_us) {
if (time_now < next_rtcp_time_) { if (time_now_us < next_rtcp_time_) {
return NULL; return NULL;
} }
RtcpPacket* rtcp = new RtcpPacket; RtcpPacket* rtcp = new RtcpPacket;
int64_t send_time = RtpStream::kSendSideOffsetMs + time_now + 0.5; int64_t send_time_us = RtpStream::kSendSideOffsetUs + time_now_us;
rtcp->timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>( rtcp->timestamp = rtp_timestamp_offset_ + static_cast<uint32_t>(
(frequency_ / 1000.0) * send_time + 0.5); ((frequency_ / 1000) * send_time_us + 500) / 1000);
rtcp->ntp_secs = send_time / 1000; rtcp->ntp_secs = send_time_us / 1000000;
rtcp->ntp_frac = (send_time % 1000) * kNtpFracPerMs; rtcp->ntp_frac = (send_time_us % 1000000) * kNtpFracPerMs;
rtcp->ssrc = ssrc_; rtcp->ssrc = ssrc_;
next_rtcp_time_ = time_now + kRtcpIntervalMs; next_rtcp_time_ = time_now_us + kRtcpIntervalUs;
return rtcp; return rtcp;
} }
@ -102,7 +102,7 @@ bool RtpStream::Compare(const std::pair<unsigned int, RtpStream*>& left,
StreamGenerator::StreamGenerator(int capacity, double time_now) StreamGenerator::StreamGenerator(int capacity, double time_now)
: capacity_(capacity), : capacity_(capacity),
prev_arrival_time_(time_now) {} prev_arrival_time_us_(time_now) {}
StreamGenerator::~StreamGenerator() { StreamGenerator::~StreamGenerator() {
for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); for (StreamMap::iterator it = streams_.begin(); it != streams_.end();
@ -150,30 +150,33 @@ void StreamGenerator::set_rtp_timestamp_offset(unsigned int ssrc,
// TODO(holmer): Break out the channel simulation part from this class to make // TODO(holmer): Break out the channel simulation part from this class to make
// it possible to simulate different types of channels. // it possible to simulate different types of channels.
double StreamGenerator::GenerateFrame(RtpStream::PacketList* packets, int64_t StreamGenerator::GenerateFrame(RtpStream::PacketList* packets,
double time_now) { int64_t time_now_us) {
assert(packets != NULL); assert(packets != NULL);
assert(packets->empty()); assert(packets->empty());
assert(capacity_ > 0); assert(capacity_ > 0);
StreamMap::iterator it = std::min_element(streams_.begin(), streams_.end(), StreamMap::iterator it = std::min_element(streams_.begin(), streams_.end(),
RtpStream::Compare); RtpStream::Compare);
(*it).second->GenerateFrame(time_now, packets); (*it).second->GenerateFrame(time_now_us, packets);
int i = 0;
for (RtpStream::PacketList::iterator packet_it = packets->begin(); for (RtpStream::PacketList::iterator packet_it = packets->begin();
packet_it != packets->end(); ++packet_it) { packet_it != packets->end(); ++packet_it) {
int required_network_time = int capacity_bpus = capacity_ / 1000;
(8 * 1000 * (*packet_it)->size + capacity_ / 2) / capacity_; int64_t required_network_time_us =
prev_arrival_time_ = std::max(time_now + required_network_time, (8 * 1000 * (*packet_it)->size + capacity_bpus / 2) / capacity_bpus;
prev_arrival_time_ + required_network_time); prev_arrival_time_us_ = std::max(time_now_us + required_network_time_us,
(*packet_it)->arrival_time = prev_arrival_time_ + 0.5; prev_arrival_time_us_ + required_network_time_us);
(*packet_it)->arrival_time = prev_arrival_time_us_;
++i;
} }
it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
return (*it).second->next_rtp_time(); return (*it).second->next_rtp_time();
} }
void StreamGenerator::Rtcps(RtcpList* rtcps, double time_now) const { void StreamGenerator::Rtcps(RtcpList* rtcps, int64_t time_now_us) const {
for (StreamMap::const_iterator it = streams_.begin(); it != streams_.end(); for (StreamMap::const_iterator it = streams_.begin(); it != streams_.end();
++it) { ++it) {
RtpStream::RtcpPacket* rtcp = it->second->Rtcp(time_now); RtpStream::RtcpPacket* rtcp = it->second->Rtcp(time_now_us);
if (rtcp) { if (rtcp) {
rtcps->push_front(rtcp); rtcps->push_front(rtcp);
} }
@ -182,22 +185,24 @@ void StreamGenerator::Rtcps(RtcpList* rtcps, double time_now) const {
} // namespace testing } // namespace testing
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest() RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest()
: time_now_(0.0), : clock_(0),
align_streams_(false) {} align_streams_(false) {}
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest(bool align_streams) RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest(bool align_streams)
: time_now_(0.0), : clock_(0),
align_streams_(align_streams) {} align_streams_(align_streams) {}
void RemoteBitrateEstimatorTest::SetUp() { void RemoteBitrateEstimatorTest::SetUp() {
bitrate_observer_.reset(new testing::TestBitrateObserver); bitrate_observer_.reset(new testing::TestBitrateObserver);
bitrate_estimator_.reset( bitrate_estimator_.reset(
RemoteBitrateEstimator::Create( RemoteBitrateEstimator::Create(
overuse_detector_options_,
RemoteBitrateEstimator::kSingleStreamEstimation,
bitrate_observer_.get(), bitrate_observer_.get(),
over_use_detector_options_, &clock_));
RemoteBitrateEstimator::kSingleStreamEstimation)); stream_generator_.reset(new testing::StreamGenerator(
stream_generator_.reset(new testing::StreamGenerator(1e6, // Capacity. 1e6, // Capacity.
time_now_)); clock_.TimeInMicroseconds()));
} }
void RemoteBitrateEstimatorTest::AddDefaultStream() { void RemoteBitrateEstimatorTest::AddDefaultStream() {
@ -220,15 +225,14 @@ bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(unsigned int ssrc,
unsigned int bitrate_bps) { unsigned int bitrate_bps) {
stream_generator_->set_bitrate_bps(bitrate_bps); stream_generator_->set_bitrate_bps(bitrate_bps);
testing::RtpStream::PacketList packets; testing::RtpStream::PacketList packets;
time_now_ = stream_generator_->GenerateFrame(&packets, time_now_); int64_t next_time_us = stream_generator_->GenerateFrame(
int64_t last_arrival_time = -1; &packets, clock_.TimeInMicroseconds());
bool prev_was_decrease = false;
bool overuse = false; bool overuse = false;
while (!packets.empty()) { while (!packets.empty()) {
testing::RtpStream::RtpPacket* packet = packets.front(); testing::RtpStream::RtpPacket* packet = packets.front();
if (align_streams_) { if (align_streams_) {
testing::StreamGenerator::RtcpList rtcps; testing::StreamGenerator::RtcpList rtcps;
stream_generator_->Rtcps(&rtcps, time_now_); stream_generator_->Rtcps(&rtcps, clock_.TimeInMicroseconds());
for (testing::StreamGenerator::RtcpList::iterator it = rtcps.begin(); for (testing::StreamGenerator::RtcpList::iterator it = rtcps.begin();
it != rtcps.end(); ++it) { it != rtcps.end(); ++it) {
bitrate_estimator_->IncomingRtcp((*it)->ssrc, bitrate_estimator_->IncomingRtcp((*it)->ssrc,
@ -241,40 +245,39 @@ bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(unsigned int ssrc,
bitrate_observer_->Reset(); bitrate_observer_->Reset();
bitrate_estimator_->IncomingPacket(packet->ssrc, bitrate_estimator_->IncomingPacket(packet->ssrc,
packet->size, packet->size,
packet->arrival_time, (packet->arrival_time + 500) / 1000,
packet->rtp_timestamp); packet->rtp_timestamp);
if (bitrate_observer_->updated()) { if (bitrate_observer_->updated()) {
// Verify that new estimates only are triggered by an overuse and a // Verify that new estimates only are triggered by an overuse and a
// rate decrease. // rate decrease.
overuse = true; overuse = true;
EXPECT_LE(bitrate_observer_->latest_bitrate(), bitrate_bps); 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; clock_.AdvanceTimeMicroseconds(packet->arrival_time -
clock_.TimeInMicroseconds());
delete packet; delete packet;
packets.pop_front(); packets.pop_front();
} }
EXPECT_GT(last_arrival_time, -1); bitrate_estimator_->Process();
bitrate_estimator_->UpdateEstimate(ssrc, last_arrival_time); clock_.AdvanceTimeMicroseconds(next_time_us - clock_.TimeInMicroseconds());
return overuse; return overuse;
} }
// Run the bandwidth estimator with a stream of |number_of_frames| frames. // Run the bandwidth estimator with a stream of |number_of_frames| frames, or
// until it reaches |target_bitrate|.
// Can for instance be used to run the estimator for some time to get it // Can for instance be used to run the estimator for some time to get it
// into a steady state. // into a steady state.
unsigned int RemoteBitrateEstimatorTest::SteadyStateRun( unsigned int RemoteBitrateEstimatorTest::SteadyStateRun(
unsigned int ssrc, unsigned int ssrc,
int number_of_frames, int max_number_of_frames,
unsigned int start_bitrate, unsigned int start_bitrate,
unsigned int min_bitrate, unsigned int min_bitrate,
unsigned int max_bitrate) { unsigned int max_bitrate,
unsigned int target_bitrate) {
unsigned int bitrate_bps = start_bitrate; unsigned int bitrate_bps = start_bitrate;
bool bitrate_update_seen = false; bool bitrate_update_seen = false;
// Produce |number_of_frames| frames and give them to the estimator. // Produce |number_of_frames| frames and give them to the estimator.
for (int i = 0; i < number_of_frames; ++i) { for (int i = 0; i < max_number_of_frames; ++i) {
bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps); bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps);
if (overuse) { if (overuse) {
EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate); EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate);
@ -285,6 +288,9 @@ unsigned int RemoteBitrateEstimatorTest::SteadyStateRun(
bitrate_bps = bitrate_observer_->latest_bitrate(); bitrate_bps = bitrate_observer_->latest_bitrate();
bitrate_observer_->Reset(); bitrate_observer_->Reset();
} }
if (bitrate_update_seen && bitrate_bps > target_bitrate) {
break;
}
} }
EXPECT_TRUE(bitrate_update_seen); EXPECT_TRUE(bitrate_update_seen);
return bitrate_bps; return bitrate_bps;

View File

@ -17,9 +17,10 @@
#include <map> #include <map>
#include <utility> #include <utility>
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "system_wrappers/interface/constructor_magic.h" #include "webrtc/system_wrappers/interface/clock.h"
#include "system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/constructor_magic.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc { namespace webrtc {
@ -74,7 +75,7 @@ class RtpStream {
typedef std::list<RtpPacket*> PacketList; typedef std::list<RtpPacket*> PacketList;
enum { kSendSideOffsetMs = 1000 }; enum { kSendSideOffsetUs = 1000000 };
RtpStream(int fps, int bitrate_bps, unsigned int ssrc, unsigned int frequency, RtpStream(int fps, int bitrate_bps, unsigned int ssrc, unsigned int frequency,
uint32_t timestamp_offset, int64_t rtcp_receive_time); uint32_t timestamp_offset, int64_t rtcp_receive_time);
@ -83,13 +84,13 @@ class RtpStream {
// Generates a new frame for this stream. If called too soon after the // 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 // previous frame, no frame will be generated. The frame is split into
// packets. // packets.
int64_t GenerateFrame(double time_now, PacketList* packets); int64_t GenerateFrame(int64_t time_now_us, PacketList* packets);
// The send-side time when the next frame can be generated. // The send-side time when the next frame can be generated.
double next_rtp_time() const; double next_rtp_time() const;
// Generates an RTCP packet. // Generates an RTCP packet.
RtcpPacket* Rtcp(double time_now); RtcpPacket* Rtcp(int64_t time_now_us);
void set_bitrate_bps(int bitrate_bps); void set_bitrate_bps(int bitrate_bps);
@ -101,14 +102,14 @@ class RtpStream {
const std::pair<unsigned int, RtpStream*>& right); const std::pair<unsigned int, RtpStream*>& right);
private: private:
enum { kRtcpIntervalMs = 1000 }; enum { kRtcpIntervalUs = 1000000 };
int fps_; int fps_;
int bitrate_bps_; int bitrate_bps_;
unsigned int ssrc_; unsigned int ssrc_;
unsigned int frequency_; unsigned int frequency_;
double next_rtp_time_; int64_t next_rtp_time_;
double next_rtcp_time_; int64_t next_rtcp_time_;
uint32_t rtp_timestamp_offset_; uint32_t rtp_timestamp_offset_;
const double kNtpFracPerMs; const double kNtpFracPerMs;
@ -138,9 +139,9 @@ class StreamGenerator {
// TODO(holmer): Break out the channel simulation part from this class to make // TODO(holmer): Break out the channel simulation part from this class to make
// it possible to simulate different types of channels. // it possible to simulate different types of channels.
double GenerateFrame(RtpStream::PacketList* packets, double time_now); int64_t GenerateFrame(RtpStream::PacketList* packets, int64_t time_now_us);
void Rtcps(RtcpList* rtcps, double time_now) const; void Rtcps(RtcpList* rtcps, int64_t time_now_us) const;
private: private:
typedef std::map<unsigned int, RtpStream*> StreamMap; typedef std::map<unsigned int, RtpStream*> StreamMap;
@ -148,7 +149,7 @@ class StreamGenerator {
// Capacity of the simulated channel in bits per second. // Capacity of the simulated channel in bits per second.
int capacity_; int capacity_;
// The time when the last packet arrived. // The time when the last packet arrived.
double prev_arrival_time_; int64_t prev_arrival_time_us_;
// All streams being transmitted on this simulated channel. // All streams being transmitted on this simulated channel.
StreamMap streams_; StreamMap streams_;
@ -174,19 +175,21 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
// target bitrate after the call to this function. // target bitrate after the call to this function.
bool GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps); bool GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps);
// Run the bandwidth estimator with a stream of |number_of_frames| frames. // Run the bandwidth estimator with a stream of |number_of_frames| frames, or
// until it reaches |target_bitrate|.
// Can for instance be used to run the estimator for some time to get it // Can for instance be used to run the estimator for some time to get it
// into a steady state. // into a steady state.
unsigned int SteadyStateRun(unsigned int ssrc, unsigned int SteadyStateRun(unsigned int ssrc,
int number_of_frames, int number_of_frames,
unsigned int start_bitrate, unsigned int start_bitrate,
unsigned int min_bitrate, unsigned int min_bitrate,
unsigned int max_bitrate); unsigned int max_bitrate,
unsigned int target_bitrate);
enum { kDefaultSsrc = 1 }; enum { kDefaultSsrc = 1 };
double time_now_; // Current time at the receiver. SimulatedClock clock_; // Time at the receiver.
OverUseDetectorOptions over_use_detector_options_; OverUseDetectorOptions overuse_detector_options_;
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_; scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
scoped_ptr<testing::TestBitrateObserver> bitrate_observer_; scoped_ptr<testing::TestBitrateObserver> bitrate_observer_;
scoped_ptr<testing::StreamGenerator> stream_generator_; scoped_ptr<testing::StreamGenerator> stream_generator_;

View File

@ -24,6 +24,9 @@ extern MatlabEngine eng; // global variable defined elsewhere
#endif #endif
namespace webrtc { namespace webrtc {
const unsigned int kDefaultRttMs = 200;
RemoteRateControl::RemoteRateControl() RemoteRateControl::RemoteRateControl()
: :
_minConfiguredBitRate(30000), _minConfiguredBitRate(30000),
@ -43,7 +46,7 @@ _initializedBitRate(false),
_avgChangePeriod(1000.0f), _avgChangePeriod(1000.0f),
_lastChangeMs(-1), _lastChangeMs(-1),
_beta(0.9f), _beta(0.9f),
_rtt(0) _rtt(kDefaultRttMs)
#ifdef MATLAB #ifdef MATLAB
,_plot1(NULL), ,_plot1(NULL),
_plot2(NULL) _plot2(NULL)
@ -86,6 +89,20 @@ bool RemoteRateControl::ValidEstimate() const {
return _initializedBitRate; return _initializedBitRate;
} }
bool RemoteRateControl::TimeToReduceFurther(
int64_t time_now, unsigned int incoming_bitrate) const {
const int bitrate_reduction_interval = BWE_MAX(BWE_MIN(_rtt, 200), 10);
if (time_now - _lastBitRateChange >= bitrate_reduction_interval) {
return true;
}
if (ValidEstimate()) {
const int threshold = static_cast<int>(1.05 * incoming_bitrate);
const int bitrate_difference = LatestEstimate() - incoming_bitrate;
return bitrate_difference > threshold;
}
return false;
}
WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates( WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates(
WebRtc_UWord32 minBitRateBps, WebRtc_UWord32 maxBitRateBps) WebRtc_UWord32 minBitRateBps, WebRtc_UWord32 maxBitRateBps)
{ {

View File

@ -36,6 +36,12 @@ public:
// Returns true if there is a valid estimate of the incoming bitrate, false // Returns true if there is a valid estimate of the incoming bitrate, false
// otherwise. // otherwise.
bool ValidEstimate() const; bool ValidEstimate() const;
// Returns true if the bitrate estimate hasn't been changed for more than
// an RTT, or if the incoming_bitrate is more than 5% above the current
// estimate. Should be used to decide if we should reduce the rate further
// when over-using.
bool TimeToReduceFurther(int64_t time_now,
unsigned int incoming_bitrate) const;
private: private:
WebRtc_UWord32 ChangeBitRate(WebRtc_UWord32 currentBitRate, WebRtc_UWord32 ChangeBitRate(WebRtc_UWord32 currentBitRate,

View File

@ -462,12 +462,6 @@ class RtpRtcp : public Module {
WebRtc_UWord32* fecRate, WebRtc_UWord32* fecRate,
WebRtc_UWord32* nackRate) const = 0; WebRtc_UWord32* nackRate) const = 0;
/*
* Get the receive-side estimate of the available bandwidth.
*/
virtual int EstimatedReceiveBandwidth(
WebRtc_UWord32* available_bandwidth) const = 0;
/* /*
* Used by the codec module to deliver a video or audio frame for * Used by the codec module to deliver a video or audio frame for
* packetization. * packetization.

View File

@ -60,11 +60,13 @@ class RtcpFormatRembTest : public ::testing::Test {
protected: protected:
RtcpFormatRembTest() RtcpFormatRembTest()
: over_use_detector_options_(), : over_use_detector_options_(),
system_clock_(Clock::GetRealTimeClock()),
remote_bitrate_observer_(), remote_bitrate_observer_(),
remote_bitrate_estimator_(RemoteBitrateEstimator::Create( remote_bitrate_estimator_(RemoteBitrateEstimator::Create(
&remote_bitrate_observer_,
over_use_detector_options_, over_use_detector_options_,
RemoteBitrateEstimator::kMultiStreamEstimation)) {} RemoteBitrateEstimator::kMultiStreamEstimation,
&remote_bitrate_observer_,
system_clock_)) {}
virtual void SetUp(); virtual void SetUp();
virtual void TearDown(); virtual void TearDown();
@ -79,7 +81,6 @@ class RtcpFormatRembTest : public ::testing::Test {
}; };
void RtcpFormatRembTest::SetUp() { void RtcpFormatRembTest::SetUp() {
system_clock_ = Clock::GetRealTimeClock();
RtpRtcp::Configuration configuration; RtpRtcp::Configuration configuration;
configuration.id = 0; configuration.id = 0;
configuration.audio = false; configuration.audio = false;

View File

@ -113,6 +113,19 @@ RTCPReceiver::LastReceived()
return _lastReceived; return _lastReceived;
} }
WebRtc_Word64
RTCPReceiver::LastReceivedReceiverReport() const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
WebRtc_Word64 last_received_rr = -1;
for (ReceivedInfoMap::const_iterator it = _receivedInfoMap.begin();
it != _receivedInfoMap.end(); ++it) {
if (it->second->lastTimeReceived > last_received_rr) {
last_received_rr = it->second->lastTimeReceived;
}
}
return last_received_rr;
}
WebRtc_Word32 WebRtc_Word32
RTCPReceiver::SetRemoteSSRC( const WebRtc_UWord32 ssrc) RTCPReceiver::SetRemoteSSRC( const WebRtc_UWord32 ssrc)
{ {

View File

@ -37,6 +37,7 @@ public:
WebRtc_Word32 SetRTCPStatus(const RTCPMethod method); WebRtc_Word32 SetRTCPStatus(const RTCPMethod method);
WebRtc_Word64 LastReceived(); WebRtc_Word64 LastReceived();
WebRtc_Word64 LastReceivedReceiverReport() const;
void SetSSRC( const WebRtc_UWord32 ssrc); void SetSSRC( const WebRtc_UWord32 ssrc);
void SetRelaySSRC( const WebRtc_UWord32 ssrc); void SetRelaySSRC( const WebRtc_UWord32 ssrc);
@ -197,6 +198,8 @@ protected:
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation); RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
private: private:
typedef std::map<WebRtc_UWord32, RTCPHelp::RTCPReceiveInformation*>
ReceivedInfoMap;
WebRtc_Word32 _id; WebRtc_Word32 _id;
Clock* _clock; Clock* _clock;
RTCPMethod _method; RTCPMethod _method;
@ -221,8 +224,7 @@ protected:
// Received report blocks. // Received report blocks.
std::map<WebRtc_UWord32, RTCPHelp::RTCPReportBlockInformation*> std::map<WebRtc_UWord32, RTCPHelp::RTCPReportBlockInformation*>
_receivedReportBlockMap; _receivedReportBlockMap;
std::map<WebRtc_UWord32, RTCPHelp::RTCPReceiveInformation*> ReceivedInfoMap _receivedInfoMap;
_receivedInfoMap;
std::map<WebRtc_UWord32, RTCPUtility::RTCPCnameInformation*> std::map<WebRtc_UWord32, RTCPUtility::RTCPCnameInformation*>
_receivedCnameMap; _receivedCnameMap;

View File

@ -172,9 +172,10 @@ class RtcpReceiverTest : public ::testing::Test {
remote_bitrate_observer_(), remote_bitrate_observer_(),
remote_bitrate_estimator_( remote_bitrate_estimator_(
RemoteBitrateEstimator::Create( RemoteBitrateEstimator::Create(
&remote_bitrate_observer_,
over_use_detector_options_, over_use_detector_options_,
RemoteBitrateEstimator::kMultiStreamEstimation)) { RemoteBitrateEstimator::kMultiStreamEstimation,
&remote_bitrate_observer_,
&system_clock_)) {
test_transport_ = new TestTransport(); test_transport_ = new TestTransport();
RtpRtcp::Configuration configuration; RtpRtcp::Configuration configuration;

View File

@ -99,13 +99,14 @@ class RtcpSenderTest : public ::testing::Test {
protected: protected:
RtcpSenderTest() RtcpSenderTest()
: over_use_detector_options_(), : over_use_detector_options_(),
system_clock_(Clock::GetRealTimeClock()),
remote_bitrate_observer_(), remote_bitrate_observer_(),
remote_bitrate_estimator_( remote_bitrate_estimator_(
RemoteBitrateEstimator::Create( RemoteBitrateEstimator::Create(
&remote_bitrate_observer_,
over_use_detector_options_, over_use_detector_options_,
RemoteBitrateEstimator::kMultiStreamEstimation)) { RemoteBitrateEstimator::kMultiStreamEstimation,
system_clock_ = Clock::GetRealTimeClock(); &remote_bitrate_observer_,
system_clock_)) {
test_transport_ = new TestTransport(); test_transport_ = new TestTransport();
RtpRtcp::Configuration configuration; RtpRtcp::Configuration configuration;

View File

@ -15,7 +15,8 @@
namespace webrtc { namespace webrtc {
enum { kRtpRtcpMaxIdleTimeProcess = 5, enum { kRtpRtcpMaxIdleTimeProcess = 5,
kRtpRtcpBitrateProcessTimeMs = 10, kRtpRtcpBitrateProcessTimeMs = 10,
kRtpRtcpPacketTimeoutProcessTimeMs = 100 }; kRtpRtcpPacketTimeoutProcessTimeMs = 100,
kRtpRtcpRttProcessTimeMs = 1000 };
enum { NACK_PACKETS_MAX_SIZE = 256 }; // in packets enum { NACK_PACKETS_MAX_SIZE = 256 }; // in packets
enum { NACK_BYTECOUNT_SIZE = 60}; // size of our NACK history enum { NACK_BYTECOUNT_SIZE = 60}; // size of our NACK history

View File

@ -11,7 +11,6 @@
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h" #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
#include <string.h> #include <string.h>
#include <cassert> #include <cassert>
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
@ -39,8 +38,6 @@ const float kFracMs = 4.294967296E6f;
namespace webrtc { namespace webrtc {
const WebRtc_UWord16 kDefaultRtt = 200;
static RtpData* NullObjectRtpData() { static RtpData* NullObjectRtpData() {
static NullRtpData null_rtp_data; static NullRtpData null_rtp_data;
return &null_rtp_data; return &null_rtp_data;
@ -107,6 +104,7 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
last_bitrate_process_time_(configuration.clock->TimeInMilliseconds()), last_bitrate_process_time_(configuration.clock->TimeInMilliseconds()),
last_packet_timeout_process_time_( last_packet_timeout_process_time_(
configuration.clock->TimeInMilliseconds()), configuration.clock->TimeInMilliseconds()),
last_rtt_process_time_(configuration.clock->TimeInMilliseconds()),
packet_overhead_(28), // IPV4 UDP. packet_overhead_(28), // IPV4 UDP.
critical_section_module_ptrs_( critical_section_module_ptrs_(
CriticalSectionWrapper::CreateCriticalSection()), CriticalSectionWrapper::CreateCriticalSection()),
@ -258,33 +256,30 @@ WebRtc_Word32 ModuleRtpRtcpImpl::Process() {
ProcessDeadOrAliveTimer(); ProcessDeadOrAliveTimer();
const bool default_instance(child_modules_.empty() ? false : true); const bool default_instance(child_modules_.empty() ? false : true);
if (!default_instance && rtcp_sender_.TimeToSendRTCPReport()) { if (!default_instance) {
WebRtc_UWord16 max_rtt = 0;
if (rtcp_sender_.Sending()) { if (rtcp_sender_.Sending()) {
std::vector<RTCPReportBlock> receive_blocks; // Process RTT if we have received a receiver report and we haven't
rtcp_receiver_.StatisticsReceived(&receive_blocks); // processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds.
for (std::vector<RTCPReportBlock>::iterator it = receive_blocks.begin(); if (rtcp_receiver_.LastReceivedReceiverReport() >
it != receive_blocks.end(); ++it) { last_rtt_process_time_ && now >= last_rtt_process_time_ +
WebRtc_UWord16 rtt = 0; kRtpRtcpRttProcessTimeMs) {
rtcp_receiver_.RTT(it->remoteSSRC, &rtt, NULL, NULL, NULL); last_rtt_process_time_ = now;
max_rtt = (rtt > max_rtt) ? rtt : max_rtt; std::vector<RTCPReportBlock> receive_blocks;
rtcp_receiver_.StatisticsReceived(&receive_blocks);
uint16_t max_rtt = 0;
for (std::vector<RTCPReportBlock>::iterator it = receive_blocks.begin();
it != receive_blocks.end(); ++it) {
uint16_t rtt = 0;
rtcp_receiver_.RTT(it->remoteSSRC, &rtt, NULL, NULL, NULL);
max_rtt = (rtt > max_rtt) ? rtt : max_rtt;
}
// Report the rtt.
if (rtt_observer_ && max_rtt != 0)
rtt_observer_->OnRttUpdate(max_rtt);
} }
// Report the rtt.
if (rtt_observer_ && max_rtt != 0)
rtt_observer_->OnRttUpdate(max_rtt);
} else {
// No valid RTT estimate, probably since this is a receive only channel.
// Use an estimate set by a send module.
max_rtt = rtcp_receiver_.RTT();
}
if (max_rtt == 0) {
// No own rtt calculation or set rtt, use default value.
max_rtt = kDefaultRtt;
}
// Verify receiver reports are delivered and the reported sequence number is // Verify receiver reports are delivered and the reported sequence number
// increasing. // is increasing.
if (rtcp_sender_.Sending()) {
int64_t rtcp_interval = RtcpReportInterval(); int64_t rtcp_interval = RtcpReportInterval();
if (rtcp_receiver_.RtcpRrTimeout(rtcp_interval)) { if (rtcp_receiver_.RtcpRrTimeout(rtcp_interval)) {
LOG_F(LS_WARNING) << "Timeout: No RTCP RR received."; LOG_F(LS_WARNING) << "Timeout: No RTCP RR received.";
@ -292,13 +287,8 @@ WebRtc_Word32 ModuleRtpRtcpImpl::Process() {
LOG_F(LS_WARNING) << LOG_F(LS_WARNING) <<
"Timeout: No increase in RTCP RR extended highest sequence number."; "Timeout: No increase in RTCP RR extended highest sequence number.";
} }
}
if (remote_bitrate_) { if (remote_bitrate_ && TMMBR()) {
// TODO(mflodman) Remove this and let this be propagated by CallStats.
remote_bitrate_->SetRtt(max_rtt);
remote_bitrate_->UpdateEstimate(rtp_receiver_->SSRC(), now);
if (TMMBR()) {
unsigned int target_bitrate = 0; unsigned int target_bitrate = 0;
std::vector<unsigned int> ssrcs; std::vector<unsigned int> ssrcs;
if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) { if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) {
@ -309,7 +299,8 @@ WebRtc_Word32 ModuleRtpRtcpImpl::Process() {
} }
} }
} }
rtcp_sender_.SendRTCP(kRtcpReport); if (rtcp_sender_.TimeToSendRTCPReport())
rtcp_sender_.SendRTCP(kRtcpReport);
} }
if (UpdateRTCPReceiveInformationTimers()) { if (UpdateRTCPReceiveInformationTimers()) {
@ -1995,22 +1986,6 @@ void ModuleRtpRtcpImpl::BitrateSent(WebRtc_UWord32* total_rate,
*nack_rate = rtp_sender_.NackOverheadRate(); *nack_rate = rtp_sender_.NackOverheadRate();
} }
int ModuleRtpRtcpImpl::EstimatedReceiveBandwidth(
WebRtc_UWord32* available_bandwidth) const {
if (remote_bitrate_) {
std::vector<unsigned int> ssrcs;
if (!remote_bitrate_->LatestEstimate(&ssrcs, available_bandwidth)) {
return -1;
}
if (!ssrcs.empty()) {
*available_bandwidth /= ssrcs.size();
}
return 0;
}
// No bandwidth receive-side bandwidth estimation is connected to this module.
return -1;
}
// Bad state of RTP receiver request a keyframe. // Bad state of RTP receiver request a keyframe.
void ModuleRtpRtcpImpl::OnRequestIntraFrame() { void ModuleRtpRtcpImpl::OnRequestIntraFrame() {
RequestKeyFrame(); RequestKeyFrame();

View File

@ -427,9 +427,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
WebRtc_UWord32* fec_rate, WebRtc_UWord32* fec_rate,
WebRtc_UWord32* nackRate) const; WebRtc_UWord32* nackRate) const;
virtual int EstimatedReceiveBandwidth(
WebRtc_UWord32* available_bandwidth) const;
virtual void SetRemoteSSRC(const WebRtc_UWord32 ssrc); virtual void SetRemoteSSRC(const WebRtc_UWord32 ssrc);
virtual WebRtc_UWord32 SendTimeOfSendReport(const WebRtc_UWord32 send_report); virtual WebRtc_UWord32 SendTimeOfSendReport(const WebRtc_UWord32 send_report);
@ -493,6 +490,7 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
WebRtc_Word64 last_process_time_; WebRtc_Word64 last_process_time_;
WebRtc_Word64 last_bitrate_process_time_; WebRtc_Word64 last_bitrate_process_time_;
WebRtc_Word64 last_packet_timeout_process_time_; WebRtc_Word64 last_packet_timeout_process_time_;
WebRtc_Word64 last_rtt_process_time_;
WebRtc_UWord16 packet_overhead_; WebRtc_UWord16 packet_overhead_;
scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_; scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_;

View File

@ -271,7 +271,7 @@ TEST_F(RtpRtcpRtcpTest, RTCP) {
std::vector<RTCPReportBlock> report_blocks; std::vector<RTCPReportBlock> report_blocks;
EXPECT_EQ(-1, module1->RemoteRTCPStat(NULL)); EXPECT_EQ(-1, module1->RemoteRTCPStat(NULL));
EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
EXPECT_EQ(1u, report_blocks.size()); ASSERT_EQ(1u, report_blocks.size());
const RTCPReportBlock& reportBlockReceived = report_blocks[0]; const RTCPReportBlock& reportBlockReceived = report_blocks[0];
float secSinceLastReport = float secSinceLastReport =

View File

@ -21,15 +21,7 @@ namespace webrtc {
class CriticalSectionWrapper; class CriticalSectionWrapper;
class RtcpRttObserver; class RtcpRttObserver;
class StatsObserver;
// Interface used to distribute call statistics. Callbacks will be triggered as
// soon as the class has been registered using RegisterStatsObserver.
class StatsObserver {
public:
virtual void OnRttUpdate(uint32_t rtt) = 0;
virtual ~StatsObserver() {}
};
// CallStats keeps track of statistics for a call. // CallStats keeps track of statistics for a call.
class CallStats : public Module { class CallStats : public Module {

View File

@ -1158,7 +1158,9 @@ void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent,
int ViEChannel::GetEstimatedReceiveBandwidth( int ViEChannel::GetEstimatedReceiveBandwidth(
uint32_t* estimated_bandwidth) const { uint32_t* estimated_bandwidth) const {
return rtp_rtcp_->EstimatedReceiveBandwidth(estimated_bandwidth); if (!vie_receiver_.EstimatedReceiveBandwidth(estimated_bandwidth))
return -1;
return 0;
} }
WebRtc_Word32 ViEChannel::StartRTPDump(const char file_nameUTF8[1024], WebRtc_Word32 ViEChannel::StartRTPDump(const char file_nameUTF8[1024],

View File

@ -25,18 +25,22 @@ namespace webrtc {
ChannelGroup::ChannelGroup(ProcessThread* process_thread, ChannelGroup::ChannelGroup(ProcessThread* process_thread,
const OverUseDetectorOptions& options, const OverUseDetectorOptions& options,
RemoteBitrateEstimator::EstimationMode mode) RemoteBitrateEstimator::EstimationMode mode)
: remb_(new VieRemb(process_thread)), : remb_(new VieRemb()),
bitrate_controller_(BitrateController::CreateBitrateController()), bitrate_controller_(BitrateController::CreateBitrateController()),
call_stats_(new CallStats()), call_stats_(new CallStats()),
remote_bitrate_estimator_(RemoteBitrateEstimator::Create(remb_.get(), remote_bitrate_estimator_(RemoteBitrateEstimator::Create(
options, mode)), options, mode, remb_.get(), Clock::GetRealTimeClock())),
encoder_state_feedback_(new EncoderStateFeedback()), encoder_state_feedback_(new EncoderStateFeedback()),
process_thread_(process_thread) { process_thread_(process_thread) {
call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
process_thread->RegisterModule(call_stats_.get()); process_thread->RegisterModule(call_stats_.get());
process_thread->RegisterModule(remote_bitrate_estimator_.get());
} }
ChannelGroup::~ChannelGroup() { ChannelGroup::~ChannelGroup() {
call_stats_->DeregisterStatsObserver(remote_bitrate_estimator_.get());
process_thread_->DeRegisterModule(call_stats_.get()); process_thread_->DeRegisterModule(call_stats_.get());
process_thread_->DeRegisterModule(remote_bitrate_estimator_.get());
assert(channels_.empty()); assert(channels_.empty());
assert(!remb_->InUse()); assert(!remb_->InUse());
} }

View File

@ -284,4 +284,18 @@ int ViEReceiver::StopRTPDump() {
return 0; return 0;
} }
// TODO(holmer): To be moved to ViEChannelGroup.
bool ViEReceiver::EstimatedReceiveBandwidth(
unsigned int* available_bandwidth) const {
std::vector<unsigned int> ssrcs;
if (!remote_bitrate_estimator_->LatestEstimate(&ssrcs,
available_bandwidth)) {
return false;
}
if (!ssrcs.empty()) {
*available_bandwidth /= ssrcs.size();
}
return true;
}
} // namespace webrtc } // namespace webrtc

View File

@ -74,6 +74,8 @@ class ViEReceiver : public UdpTransportData, public RtpData {
uint32_t ntp_frac, uint32_t ntp_frac,
uint32_t timestamp); uint32_t timestamp);
bool EstimatedReceiveBandwidth(unsigned int* available_bandwidth) const;
private: private:
int InsertRTPPacket(const WebRtc_Word8* rtp_packet, int rtp_packet_length); int InsertRTPPacket(const WebRtc_Word8* rtp_packet, int rtp_packet_length);
int InsertRTCPPacket(const WebRtc_Word8* rtcp_packet, int rtcp_packet_length); int InsertRTCPPacket(const WebRtc_Word8* rtcp_packet, int rtcp_packet_length);

View File

@ -28,19 +28,13 @@ const unsigned int kRembMinimumBitrateKbps = 50;
// % threshold for if we should send a new REMB asap. // % threshold for if we should send a new REMB asap.
const unsigned int kSendThresholdPercent = 97; const unsigned int kSendThresholdPercent = 97;
VieRemb::VieRemb(ProcessThread* process_thread) VieRemb::VieRemb()
: process_thread_(process_thread), : list_crit_(CriticalSectionWrapper::CreateCriticalSection()),
list_crit_(CriticalSectionWrapper::CreateCriticalSection()),
last_remb_time_(TickTime::MillisecondTimestamp()), last_remb_time_(TickTime::MillisecondTimestamp()),
last_send_bitrate_(0), last_send_bitrate_(0),
bitrate_(0), bitrate_(0) {}
bitrate_update_time_ms_(-1) {
process_thread->RegisterModule(this);
}
VieRemb::~VieRemb() { VieRemb::~VieRemb() {}
process_thread_->DeRegisterModule(this);
}
void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) { void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp); assert(rtp_rtcp);
@ -115,7 +109,7 @@ void VieRemb::OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
WEBRTC_TRACE(kTraceStream, kTraceVideo, -1, WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
"VieRemb::UpdateBitrateEstimate(bitrate: %u)", bitrate); "VieRemb::UpdateBitrateEstimate(bitrate: %u)", bitrate);
assert(ssrcs); assert(ssrcs);
CriticalSectionScoped cs(list_crit_.get()); list_crit_->Enter();
// If we already have an estimate, check if the new total estimate is below // If we already have an estimate, check if the new total estimate is below
// kSendThresholdPercent of the previous estimate. // kSendThresholdPercent of the previous estimate.
if (last_send_bitrate_ > 0) { if (last_send_bitrate_ > 0) {
@ -128,40 +122,23 @@ void VieRemb::OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
} }
} }
bitrate_ = bitrate; bitrate_ = bitrate;
// TODO(holmer): Remove |ssrcs_| from this class as the REMB is produced
// immediately upon a call to this function.
ssrcs_.resize(ssrcs->size()); ssrcs_.resize(ssrcs->size());
std::copy(ssrcs->begin(), ssrcs->end(), ssrcs_.begin()); std::copy(ssrcs->begin(), ssrcs->end(), ssrcs_.begin());
bitrate_update_time_ms_ = TickTime::MillisecondTimestamp();
}
WebRtc_Word32 VieRemb::ChangeUniqueId(const WebRtc_Word32 id) {
return 0;
}
WebRtc_Word32 VieRemb::TimeUntilNextProcess() {
return kRembSendIntervallMs -
(TickTime::MillisecondTimestamp() - last_remb_time_);
}
WebRtc_Word32 VieRemb::Process() {
int64_t now = TickTime::MillisecondTimestamp();
if (now - last_remb_time_ < kRembSendIntervallMs)
return 0;
last_remb_time_ = now;
// Calculate total receive bitrate estimate. // Calculate total receive bitrate estimate.
list_crit_->Enter(); int64_t now = TickTime::MillisecondTimestamp();
// Reset the estimate if it has timed out. if (now - last_remb_time_ < kRembSendIntervallMs) {
if (TickTime::MillisecondTimestamp() - bitrate_update_time_ms_ >
kRembTimeOutThresholdMs) {
bitrate_ = 0;
bitrate_update_time_ms_ = -1;
}
if (bitrate_update_time_ms_ == -1 || ssrcs_.empty() ||
receive_modules_.empty()) {
list_crit_->Leave(); list_crit_->Leave();
return 0; return;
}
last_remb_time_ = now;
if (ssrcs_.empty() || receive_modules_.empty()) {
list_crit_->Leave();
return;
} }
// Send a REMB packet. // Send a REMB packet.
@ -179,18 +156,17 @@ WebRtc_Word32 VieRemb::Process() {
} }
// Copy SSRCs to avoid race conditions. // Copy SSRCs to avoid race conditions.
int ssrcs_length = ssrcs_.size(); int ssrcs_length = ssrcs_.size();
unsigned int* ssrcs = new unsigned int[ssrcs_length]; unsigned int* ssrcs_copy = new unsigned int[ssrcs_length];
for (int i = 0; i < ssrcs_length; ++i) { for (int i = 0; i < ssrcs_length; ++i) {
ssrcs[i] = ssrcs_[i]; ssrcs_copy[i] = ssrcs_[i];
} }
list_crit_->Leave(); list_crit_->Leave();
if (sender) { if (sender) {
// TODO(holmer): Change RTP module API to take a vector pointer. // TODO(holmer): Change RTP module API to take a vector pointer.
sender->SetREMBData(bitrate_, ssrcs_length, ssrcs); sender->SetREMBData(bitrate_, ssrcs_length, ssrcs_copy);
} }
delete [] ssrcs; delete [] ssrcs_copy;
return 0;
} }
} // namespace webrtc } // namespace webrtc

View File

@ -26,9 +26,9 @@ class CriticalSectionWrapper;
class ProcessThread; class ProcessThread;
class RtpRtcp; class RtpRtcp;
class VieRemb : public RemoteBitrateObserver, public Module { class VieRemb : public RemoteBitrateObserver {
public: public:
explicit VieRemb(ProcessThread* process_thread); VieRemb();
~VieRemb(); ~VieRemb();
// Called to add a receive channel to include in the REMB packet. // Called to add a receive channel to include in the REMB packet.
@ -54,15 +54,9 @@ class VieRemb : public RemoteBitrateObserver, public Module {
virtual void OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs, virtual void OnReceiveBitrateChanged(std::vector<unsigned int>* ssrcs,
unsigned int bitrate); unsigned int bitrate);
// Implements Module.
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual WebRtc_Word32 TimeUntilNextProcess();
virtual WebRtc_Word32 Process();
private: private:
typedef std::list<RtpRtcp*> RtpModules; typedef std::list<RtpRtcp*> RtpModules;
ProcessThread* process_thread_;
scoped_ptr<CriticalSectionWrapper> list_crit_; scoped_ptr<CriticalSectionWrapper> list_crit_;
// The last time a REMB was sent. // The last time a REMB was sent.
@ -78,7 +72,6 @@ class VieRemb : public RemoteBitrateObserver, public Module {
// The last bitrate update. // The last bitrate update.
unsigned int bitrate_; unsigned int bitrate_;
std::vector<unsigned int> ssrcs_; std::vector<unsigned int> ssrcs_;
int64_t bitrate_update_time_ms_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -44,7 +44,7 @@ class ViERembTest : public ::testing::Test {
virtual void SetUp() { virtual void SetUp() {
TickTime::UseFakeClock(12345); TickTime::UseFakeClock(12345);
process_thread_.reset(new TestProcessThread); process_thread_.reset(new TestProcessThread);
vie_remb_.reset(new VieRemb(process_thread_.get())); vie_remb_.reset(new VieRemb());
} }
scoped_ptr<TestProcessThread> process_thread_; scoped_ptr<TestProcessThread> process_thread_;
scoped_ptr<VieRemb> vie_remb_; scoped_ptr<VieRemb> vie_remb_;
@ -64,13 +64,12 @@ TEST_F(ViERembTest, OneModuleTestForSendingRemb) {
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _)) EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Lower bitrate to send another REMB packet. // Lower bitrate to send another REMB packet.
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate - 100);
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _)) EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate - 100);
vie_remb_->RemoveReceiveChannel(&rtp); vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp); vie_remb_->RemoveRembSender(&rtp);
@ -86,11 +85,11 @@ TEST_F(ViERembTest, LowerEstimateToSendRemb) {
std::vector<unsigned int> ssrcs(&ssrc, &ssrc + 1); std::vector<unsigned int> ssrcs(&ssrc, &ssrc + 1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Call process to get a first estimate. // Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _)) EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Lower the estimate with more than 3% to trigger a call to SetREMBData right // Lower the estimate with more than 3% to trigger a call to SetREMBData right
// away. // away.
@ -98,7 +97,6 @@ TEST_F(ViERembTest, LowerEstimateToSendRemb) {
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _)) EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->Process();
} }
TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) { TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
@ -114,11 +112,11 @@ TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[0]); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[0]);
// Call process to get a first estimate. // Call OnReceiveBitrateChanged twice to get a first estimate.
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0], 2, _)) EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0], 2, _))
.Times(1); .Times(1);
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[0]);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1] + 100); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1] + 100);
@ -126,7 +124,6 @@ TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[1], 2, _)) EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[1], 2, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1]); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate[1]);
vie_remb_->Process();
vie_remb_->RemoveReceiveChannel(&rtp_0); vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0); vie_remb_->RemoveRembSender(&rtp_0);
@ -145,24 +142,23 @@ TEST_F(ViERembTest, NoRembForIncreasedBitrate) {
std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0])); std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0]));
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Trigger a first call to have a running state. // Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _)) EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Increased estimate shouldn't trigger a callback right away. // Increased estimate shouldn't trigger a callback right away.
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate + 1);
EXPECT_CALL(rtp_0, SetREMBData(_, _, _)) EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
.Times(0); .Times(0);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate + 1);
// Decreasing the estimate less than 3% shouldn't trigger a new callback. // Decreasing the estimate less than 3% shouldn't trigger a new callback.
int lower_estimate = bitrate_estimate * 98 / 100;
vie_remb_->OnReceiveBitrateChanged(&ssrcs, lower_estimate);
EXPECT_CALL(rtp_0, SetREMBData(_, _, _)) EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
.Times(0); .Times(0);
int lower_estimate = bitrate_estimate * 98 / 100;
vie_remb_->OnReceiveBitrateChanged(&ssrcs, lower_estimate);
vie_remb_->Process();
vie_remb_->RemoveReceiveChannel(&rtp_1); vie_remb_->RemoveReceiveChannel(&rtp_1);
vie_remb_->RemoveReceiveChannel(&rtp_0); vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0); vie_remb_->RemoveRembSender(&rtp_0);
@ -180,18 +176,17 @@ TEST_F(ViERembTest, ChangeSendRtpModule) {
std::vector<unsigned int> ssrcs(ssrc, ssrc + sizeof(ssrc) / sizeof(ssrc[0])); 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 process to get a first estimate. // Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _)) EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Decrease estimate to trigger a REMB. // Decrease estimate to trigger a REMB.
bitrate_estimate = bitrate_estimate - 100; bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _)) EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->Process();
// Remove the sending module, add it again -> should get remb on the second // Remove the sending module, add it again -> should get remb on the second
// module. // module.
@ -203,7 +198,6 @@ TEST_F(ViERembTest, ChangeSendRtpModule) {
EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate, 2, _)) EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate, 2, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->Process();
vie_remb_->RemoveReceiveChannel(&rtp_0); vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveReceiveChannel(&rtp_1); vie_remb_->RemoveReceiveChannel(&rtp_1);
@ -218,39 +212,22 @@ TEST_F(ViERembTest, OnlyOneRembForDoubleProcess) {
vie_remb_->AddReceiveChannel(&rtp); vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddRembSender(&rtp); vie_remb_->AddRembSender(&rtp);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Call process to get a first estimate. // Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(_, _, _)) EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Lower the estimate, should trigger a call to SetREMBData right away. // Lower the estimate, should trigger a call to SetREMBData right away.
bitrate_estimate = bitrate_estimate - 100; bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _)) EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->Process();
// Call Process again, this should not trigger a new callback. // Call OnReceiveBitrateChanged again, this should not trigger a new callback.
EXPECT_CALL(rtp, SetREMBData(_, _, _)) EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(0); .Times(0);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
}
TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall) {
MockRtpRtcp rtp;
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
// TODO(mflodman) Add fake clock.
TickTime::AdvanceFakeClock(1000);
// No bitrate estimate given, no callback expected.
EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(0);
vie_remb_->Process();
vie_remb_->RemoveReceiveChannel(&rtp); vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp); vie_remb_->RemoveRembSender(&rtp);
} }
@ -267,18 +244,17 @@ TEST_F(ViERembTest, NoSendingRtpModule) {
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Call process to get a first estimate. // Call OnReceiveBitrateChanged twice to get a first estimate.
TickTime::AdvanceFakeClock(1000); TickTime::AdvanceFakeClock(1000);
EXPECT_CALL(rtp, SetREMBData(_, _, _)) EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1); .Times(1);
vie_remb_->Process(); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
// Lower the estimate to trigger a new packet REMB packet. // Lower the estimate to trigger a new packet REMB packet.
bitrate_estimate = bitrate_estimate - 100; bitrate_estimate = bitrate_estimate - 100;
EXPECT_CALL(rtp, SetREMBData(_, _, _)) EXPECT_CALL(rtp, SetREMBData(_, _, _))
.Times(1); .Times(1);
vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate); vie_remb_->OnReceiveBitrateChanged(&ssrcs, bitrate_estimate);
vie_remb_->Process();
} }
} // namespace webrtc } // namespace webrtc