diff --git a/src/modules/modules.gyp b/src/modules/modules.gyp index 5e64715098..d62bee4b12 100644 --- a/src/modules/modules.gyp +++ b/src/modules/modules.gyp @@ -28,6 +28,7 @@ 'audio_processing/utility/util.gypi', 'bitrate_controller/bitrate_controller.gypi', 'media_file/source/media_file.gypi', + 'remote_bitrate_estimator/remote_bitrate_estimator.gypi', 'udp_transport/source/udp_transport.gypi', 'utility/source/utility.gypi', 'video_coding/codecs/i420/main/source/i420.gypi', @@ -47,7 +48,6 @@ 'audio_coding/codecs/iSAC/isacfix_test.gypi', 'audio_processing/apm_tests.gypi', 'rtp_rtcp/source/rtp_rtcp_tests.gypi', - 'rtp_rtcp/test/test_bwe/test_bwe.gypi', 'rtp_rtcp/test/testFec/test_fec.gypi', 'rtp_rtcp/test/testAPI/test_api.gypi', 'video_coding/main/source/video_coding_test.gypi', diff --git a/src/modules/remote_bitrate_estimator/OWNERS b/src/modules/remote_bitrate_estimator/OWNERS new file mode 100644 index 0000000000..b705ede2a0 --- /dev/null +++ b/src/modules/remote_bitrate_estimator/OWNERS @@ -0,0 +1,5 @@ +pwestin@webrtc.org +stefan@webrtc.org +henrik.lundin@webrtc.org +mflodman@webrtc.org +asapersson@webrtc.org \ No newline at end of file diff --git a/src/modules/remote_bitrate_estimator/bitrate_estimator.cc b/src/modules/remote_bitrate_estimator/bitrate_estimator.cc new file mode 100644 index 0000000000..84c287cf7b --- /dev/null +++ b/src/modules/remote_bitrate_estimator/bitrate_estimator.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "bitrate_estimator.h" + +namespace webrtc { + +enum { kBitrateAverageWindow = 2000 }; + +BitRateStats::BitRateStats() + :_dataSamples(), _accumulatedBytes(0) +{ +} + +BitRateStats::~BitRateStats() +{ + while (_dataSamples.size() > 0) + { + delete _dataSamples.front(); + _dataSamples.pop_front(); + } +} + +void BitRateStats::Init() +{ + _accumulatedBytes = 0; + while (_dataSamples.size() > 0) + { + delete _dataSamples.front(); + _dataSamples.pop_front(); + } +} + +void BitRateStats::Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs) +{ + // Find an empty slot for storing the new sample and at the same time + // accumulate the history. + _dataSamples.push_back(new DataTimeSizeTuple(packetSizeBytes, nowMs)); + _accumulatedBytes += packetSizeBytes; + EraseOld(nowMs); +} + +void BitRateStats::EraseOld(WebRtc_Word64 nowMs) +{ + while (_dataSamples.size() > 0) + { + if (nowMs - _dataSamples.front()->_timeCompleteMs > + kBitrateAverageWindow) + { + // Delete old sample + _accumulatedBytes -= _dataSamples.front()->_sizeBytes; + delete _dataSamples.front(); + _dataSamples.pop_front(); + } + else + { + break; + } + } +} + +WebRtc_UWord32 BitRateStats::BitRate(WebRtc_Word64 nowMs) +{ + // Calculate the average bit rate the past BITRATE_AVERAGE_WINDOW ms. + // Removes any old samples from the list. + EraseOld(nowMs); + WebRtc_Word64 timeOldest = nowMs; + if (_dataSamples.size() > 0) + { + timeOldest = _dataSamples.front()->_timeCompleteMs; + } + // Update average bit rate + float denom = static_cast(nowMs - timeOldest); + if (nowMs == timeOldest) + { + // Calculate with a one second window when we haven't + // received more than one packet. + denom = 1000.0; + } + return static_cast(_accumulatedBytes * 8.0f * 1000.0f / + denom + 0.5f); +} + +} // namespace webrtc diff --git a/src/modules/remote_bitrate_estimator/bitrate_estimator.h b/src/modules/remote_bitrate_estimator/bitrate_estimator.h new file mode 100644 index 0000000000..a3622a75c2 --- /dev/null +++ b/src/modules/remote_bitrate_estimator/bitrate_estimator.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_ + +#include + +#include "typedefs.h" + +namespace webrtc { + +class BitRateStats +{ +public: + BitRateStats(); + ~BitRateStats(); + + void Init(); + void Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs); + WebRtc_UWord32 BitRate(WebRtc_Word64 nowMs); + +private: + struct DataTimeSizeTuple + { + DataTimeSizeTuple(uint32_t sizeBytes, int64_t timeCompleteMs) + : + _sizeBytes(sizeBytes), + _timeCompleteMs(timeCompleteMs) {} + + WebRtc_UWord32 _sizeBytes; + WebRtc_Word64 _timeCompleteMs; + }; + + void EraseOld(WebRtc_Word64 nowMs); + + std::list _dataSamples; + WebRtc_UWord32 _accumulatedBytes; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_ diff --git a/src/modules/rtp_rtcp/test/test_bwe/unit_test.cc b/src/modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc similarity index 88% rename from src/modules/rtp_rtcp/test/test_bwe/unit_test.cc rename to src/modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc index 3adb099777..b42798a090 100644 --- a/src/modules/rtp_rtcp/test/test_bwe/unit_test.cc +++ b/src/modules/remote_bitrate_estimator/bitrate_estimator_unittest.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -8,15 +8,14 @@ * be found in the AUTHORS file in the root of the source tree. */ - /* - * This file includes unit tests for the bandwidth estimation and management + * This file includes unit tests for the bitrate estimator. */ #include #include "typedefs.h" -#include "Bitrate.h" +#include "bitrate_estimator.h" namespace { @@ -26,7 +25,7 @@ class BitRateStatsTest : public ::testing::Test { protected: BitRateStatsTest() {}; - BitRateStats bitRate; + BitRateStats bitRate; }; TEST_F(BitRateStatsTest, TestStrictMode) diff --git a/src/modules/rtp_rtcp/source/bwe_defines.h b/src/modules/remote_bitrate_estimator/include/bwe_defines.h similarity index 84% rename from src/modules/rtp_rtcp/source/bwe_defines.h rename to src/modules/remote_bitrate_estimator/include/bwe_defines.h index 8fdc985c8f..173a284329 100644 --- a/src/modules/rtp_rtcp/source/bwe_defines.h +++ b/src/modules/remote_bitrate_estimator/include/bwe_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -43,9 +43,10 @@ class RateControlInput public: RateControlInput(BandwidthUsage bwState, WebRtc_UWord32 incomingBitRate, - double noiseVar) : - _bwState(bwState), _incomingBitRate(incomingBitRate), _noiseVar(noiseVar) - {}; + double noiseVar) + : _bwState(bwState), + _incomingBitRate(incomingBitRate), + _noiseVar(noiseVar) {} BandwidthUsage _bwState; WebRtc_UWord32 _incomingBitRate; diff --git a/src/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h b/src/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h new file mode 100644 index 0000000000..76a958354b --- /dev/null +++ b/src/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_ + +#include + +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" + +namespace webrtc { + +class MockRemoteBitrateObserver : public RemoteBitrateObserver { + public: + MOCK_METHOD2(OnReceiveBitrateChanged, + void(unsigned int ssrc, unsigned int bitrate)); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_ diff --git a/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h b/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h new file mode 100644 index 0000000000..990b383b3a --- /dev/null +++ b/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// RemoteBitrateEstimator +// This class estimates the incoming bitrate capacity. + +#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_ +#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_ + +#include + +#include "modules/remote_bitrate_estimator/bitrate_estimator.h" +#include "modules/remote_bitrate_estimator/overuse_detector.h" +#include "modules/remote_bitrate_estimator/remote_rate_control.h" +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/scoped_ptr.h" +#include "typedefs.h" + +namespace webrtc { + +// RemoteBitrateObserver is used to signal changes in bitrate estimates for +// the incoming stream. +class RemoteBitrateObserver { + public: + // Called when a receive channel has a new bitrate estimate for the incoming + // stream. + virtual void OnReceiveBitrateChanged(unsigned int ssrc, + unsigned int bitrate) = 0; + + virtual ~RemoteBitrateObserver() {} +}; + +class RemoteBitrateEstimator { + public: + explicit RemoteBitrateEstimator(RemoteBitrateObserver* observer); + + // Called for each incoming packet. If this is a new SSRC, a new + // BitrateControl will be created. + void IncomingPacket(unsigned int ssrc, + int packet_size, + int64_t arrival_time, + uint32_t rtp_timestamp, + int64_t packet_send_time); + + // Triggers a new estimate calculation for the stream identified by |ssrc|. + void UpdateEstimate(unsigned int ssrc, int64_t time_now); + + // Set the current round-trip time experienced by the stream identified by + // |ssrc|. + void SetRtt(unsigned int ssrc); + + // Removes all data for |ssrc|. + void RemoveStream(unsigned int ssrc); + + // Returns true if a valid estimate exists for a stream identified by |ssrc| + // and sets |bitrate_bps| to the estimated bitrate in bits per second. + bool LatestEstimate(unsigned int ssrc, unsigned int* bitrate_bps) const; + + private: + struct BitrateControls { + RemoteRateControl remote_rate; + OverUseDetector overuse_detector; + BitRateStats incoming_bitrate; + }; + + typedef std::map SsrcBitrateControlsMap; + + SsrcBitrateControlsMap bitrate_controls_; + RemoteBitrateObserver* observer_; + scoped_ptr crit_sect_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_ diff --git a/src/modules/rtp_rtcp/source/overuse_detector.cc b/src/modules/remote_bitrate_estimator/overuse_detector.cc similarity index 92% rename from src/modules/rtp_rtcp/source/overuse_detector.cc rename to src/modules/remote_bitrate_estimator/overuse_detector.cc index be609eeca4..8947839c75 100644 --- a/src/modules/rtp_rtcp/source/overuse_detector.cc +++ b/src/modules/remote_bitrate_estimator/overuse_detector.cc @@ -14,8 +14,8 @@ #include #endif -#include "modules/rtp_rtcp/source/overuse_detector.h" -#include "modules/rtp_rtcp/source/remote_rate_control.h" +#include "modules/remote_bitrate_estimator/overuse_detector.h" +#include "modules/remote_bitrate_estimator/remote_rate_control.h" #include "modules/rtp_rtcp/source/rtp_utility.h" #include "system_wrappers/interface/trace.h" @@ -109,8 +109,8 @@ void OverUseDetector::Reset() { tsDeltaHist_.clear(); } -bool OverUseDetector::Update(const WebRtcRTPHeader& rtpHeader, - const WebRtc_UWord16 packetSize, +void OverUseDetector::Update(WebRtc_UWord16 packetSize, + WebRtc_UWord32 timestamp, const WebRtc_Word64 nowMS) { #ifdef WEBRTC_BWE_MATLAB // Create plots @@ -145,14 +145,14 @@ bool OverUseDetector::Update(const WebRtcRTPHeader& rtpHeader, bool wrapped = false; bool completeFrame = false; if (currentFrame_.timestamp_ == -1) { - currentFrame_.timestamp_ = rtpHeader.header.timestamp; - } else if (ModuleRTPUtility::OldTimestamp( - rtpHeader.header.timestamp, + currentFrame_.timestamp_ = timestamp; + } else if (OldTimestamp( + timestamp, static_cast(currentFrame_.timestamp_), &wrapped)) { // Don't update with old data - return completeFrame; - } else if (rtpHeader.header.timestamp != currentFrame_.timestamp_) { + return; + } else if (timestamp != currentFrame_.timestamp_) { // First packet of a later frame, the previous frame sample is ready WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "Frame complete at %I64i", currentFrame_.completeTimeMs_); @@ -160,7 +160,7 @@ bool OverUseDetector::Update(const WebRtcRTPHeader& rtpHeader, WebRtc_Word64 tDelta = 0; double tsDelta = 0; // Check for wrap - ModuleRTPUtility::OldTimestamp( + OldTimestamp( static_cast(prevFrame_.timestamp_), static_cast(currentFrame_.timestamp_), &wrapped); @@ -172,7 +172,7 @@ bool OverUseDetector::Update(const WebRtcRTPHeader& rtpHeader, // The new timestamp is now the current frame, // and the old timestamp becomes the previous frame. prevFrame_ = currentFrame_; - currentFrame_.timestamp_ = rtpHeader.header.timestamp; + currentFrame_.timestamp_ = timestamp; currentFrame_.size_ = 0; currentFrame_.completeTimeMs_ = -1; completeFrame = true; @@ -180,7 +180,6 @@ bool OverUseDetector::Update(const WebRtcRTPHeader& rtpHeader, // Accumulate the frame size currentFrame_.size_ += packetSize; currentFrame_.completeTimeMs_ = nowMS; - return completeFrame; } BandwidthUsage OverUseDetector::State() const { @@ -420,4 +419,22 @@ BandwidthUsage OverUseDetector::Detect(double tsDelta) { return hypothesis_; } +bool OverUseDetector::OldTimestamp(uint32_t newTimestamp, + uint32_t existingTimestamp, + bool* wrapped) { + bool tmpWrapped = + (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) || + (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff); + *wrapped = tmpWrapped; + if (existingTimestamp > newTimestamp && !tmpWrapped) { + return true; + } else if (existingTimestamp <= newTimestamp && !tmpWrapped) { + return false; + } else if (existingTimestamp < newTimestamp && tmpWrapped) { + return true; + } else { + return false; + } +} + } // namespace webrtc diff --git a/src/modules/rtp_rtcp/source/overuse_detector.h b/src/modules/remote_bitrate_estimator/overuse_detector.h similarity index 88% rename from src/modules/rtp_rtcp/source/overuse_detector.h rename to src/modules/remote_bitrate_estimator/overuse_detector.h index 3b432fb0fb..e4b4c68eb5 100644 --- a/src/modules/rtp_rtcp/source/overuse_detector.h +++ b/src/modules/remote_bitrate_estimator/overuse_detector.h @@ -13,7 +13,7 @@ #include #include "modules/interface/module_common_types.h" -#include "modules/rtp_rtcp/source/bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "typedefs.h" // NOLINT(build/include) #ifdef WEBRTC_BWE_MATLAB @@ -27,8 +27,8 @@ class OverUseDetector { public: OverUseDetector(); ~OverUseDetector(); - bool Update(const WebRtcRTPHeader& rtpHeader, - const WebRtc_UWord16 packetSize, + void Update(const WebRtc_UWord16 packetSize, + const WebRtc_UWord32 timestamp, const WebRtc_Word64 nowMS); BandwidthUsage State() const; void Reset(); @@ -44,6 +44,10 @@ class OverUseDetector { WebRtc_Word64 timestamp_; }; + static bool OldTimestamp(uint32_t newTimestamp, + uint32_t existingTimestamp, + bool* wrapped); + void CompensatedTimeDelta(const FrameSample& currentFrame, const FrameSample& prevFrame, WebRtc_Word64& tDelta, diff --git a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc new file mode 100644 index 0000000000..a0239f8d25 --- /dev/null +++ b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" + +#include "system_wrappers/interface/tick_util.h" + +namespace webrtc { + +RemoteBitrateEstimator::RemoteBitrateEstimator( + RemoteBitrateObserver* observer) + : observer_(observer), + crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) { + assert(observer_); +} + +void RemoteBitrateEstimator::IncomingPacket(unsigned int ssrc, + int packet_size, + int64_t arrival_time, + uint32_t rtp_timestamp, + int64_t packet_send_time) { + CriticalSectionScoped cs(crit_sect_.get()); + SsrcBitrateControlsMap::iterator it = bitrate_controls_.find(ssrc); + if (it == bitrate_controls_.end()) { + // This is a new SSRC. Adding to map. + // TODO(holmer): If the channel changes SSRC the old SSRC will still be + // around in this map until the channel is deleted. This is OK since the + // callback will no longer be called for the old SSRC. This will be + // automatically cleaned up when we have one RemoteBitrateEstimator per REMB + // group. + bitrate_controls_[ssrc] = BitrateControls(); + it = bitrate_controls_.find(ssrc); + } + OverUseDetector* overuse_detector = + &bitrate_controls_[ssrc].overuse_detector; + bitrate_controls_[ssrc].incoming_bitrate.Update(packet_size, arrival_time); + const BandwidthUsage prior_state = overuse_detector->State(); + overuse_detector->Update(packet_size, rtp_timestamp, arrival_time); + if (prior_state != overuse_detector->State() && + overuse_detector->State() == kBwOverusing) { + // The first overuse should immediately trigger a new estimate. + UpdateEstimate(ssrc, arrival_time); + } +} + +void RemoteBitrateEstimator::UpdateEstimate(unsigned int ssrc, + int64_t time_now) { + CriticalSectionScoped cs(crit_sect_.get()); + SsrcBitrateControlsMap::iterator it = bitrate_controls_.find(ssrc); + if (it == bitrate_controls_.end()) { + return; + } + OverUseDetector* overuse_detector = &it->second.overuse_detector; + RemoteRateControl* remote_rate = &it->second.remote_rate; + const RateControlInput input(overuse_detector->State(), + it->second.incoming_bitrate.BitRate(time_now), + overuse_detector->NoiseVar()); + const RateControlRegion region = remote_rate->Update(&input, time_now); + unsigned int target_bitrate = remote_rate->UpdateBandwidthEstimate(time_now); + if (remote_rate->ValidEstimate()) { + observer_->OnReceiveBitrateChanged(ssrc, target_bitrate); + } + overuse_detector->SetRateControlRegion(region); +} + +void RemoteBitrateEstimator::SetRtt(unsigned int rtt) { + CriticalSectionScoped cs(crit_sect_.get()); + for (SsrcBitrateControlsMap::iterator it = bitrate_controls_.begin(); + it != bitrate_controls_.end(); ++it) { + it->second.remote_rate.SetRtt(rtt); + } +} + +void RemoteBitrateEstimator::RemoveStream(unsigned int ssrc) { + CriticalSectionScoped cs(crit_sect_.get()); + // Ignoring the return value which is the number of elements erased. + bitrate_controls_.erase(ssrc); +} + +bool RemoteBitrateEstimator::LatestEstimate(unsigned int ssrc, + unsigned int* bitrate_bps) const { + CriticalSectionScoped cs(crit_sect_.get()); + assert(bitrate_bps != NULL); + SsrcBitrateControlsMap::const_iterator it = bitrate_controls_.find(ssrc); + if (it == bitrate_controls_.end()) { + return false; + } + if (!it->second.remote_rate.ValidEstimate()) { + return false; + } + *bitrate_bps = it->second.remote_rate.LatestEstimate(); + return true; +} + +} // namespace webrtc diff --git a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi new file mode 100644 index 0000000000..7b652a4ade --- /dev/null +++ b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi @@ -0,0 +1,71 @@ +# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +{ + 'targets': [ + { + 'target_name': 'remote_bitrate_estimator', + 'type': '<(library)', + 'dependencies': [ + # system_wrappers + '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', + ], + 'include_dirs': [ + 'include', + '../rtp_rtcp/interface', + '../interface', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'include', + ], + }, + 'sources': [ + # interface + 'include/bwe_defines.h', + 'include/remote_bitrate_estimator.h', + + # source + 'bitrate_estimator.cc', + 'bitrate_estimator.h', + 'overuse_detector.cc', + 'overuse_detector.h', + 'remote_bitrate_estimator.cc', + 'remote_rate_control.cc', + 'remote_rate_control.h', + ], # source + }, + ], # targets + 'conditions': [ + ['include_tests==1', { + 'targets': [ + { + 'target_name': 'remote_bitrate_estimator_unittests', + 'type': 'executable', + 'dependencies': [ + 'remote_bitrate_estimator', + '<(webrtc_root)/../testing/gmock.gyp:gmock', + '<(webrtc_root)/../testing/gtest.gyp:gtest', + '<(webrtc_root)/../test/test.gyp:test_support_main', + ], + 'sources': [ + 'include/mock/mock_remote_bitrate_estimator.h', + 'bitrate_estimator_unittest.cc', + 'remote_bitrate_estimator_unittest.cc', + ], + }, + ], # targets + }], # build_with_chromium + ], # conditions +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc new file mode 100644 index 0000000000..b2a424fea9 --- /dev/null +++ b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +// This file includes unit tests for RemoteBitrateEstimator. + +#include +#include + +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +enum { kMtu = 1200 }; + +class TestBitrateObserver : public RemoteBitrateObserver { + public: + TestBitrateObserver() : updated_(false), latest_bitrate_(0) {} + + void OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) { + latest_bitrate_ = bitrate; + updated_ = true; + } + + bool updated() { + bool updated = updated_; + updated_ = false; + return updated; + } + + unsigned int latest_bitrate() const { + return latest_bitrate_; + } + + private: + bool updated_; + unsigned int latest_bitrate_; +}; + +class StreamGenerator { + public: + struct Packet { + int64_t send_time; + int64_t arrival_time; + uint32_t rtp_timestamp; + unsigned int size; + }; + + typedef std::list PacketList; + + StreamGenerator(int fps, int bitrate_bps, int capacity, int64_t time_now) + : fps_(fps), + bitrate_bps_(bitrate_bps), + capacity_(capacity), + time_now_(time_now), + prev_arrival_time_(time_now), + rtp_timestamp_offset_(0xFFFFF000) {} + + void SetCapacity(int capacity_bps) { + ASSERT_GT(capacity_bps, 0); + capacity_ = capacity_bps; + } + + void SetBitrate(int bitrate_bps) { + ASSERT_GE(bitrate_bps, 0); + bitrate_bps_ = bitrate_bps; + } + + void SetRtpTimestampOffset(uint32_t offset) { + rtp_timestamp_offset_ = offset; + } + + void GenerateFrame(PacketList* packets) { + ASSERT_FALSE(packets == NULL); + ASSERT_TRUE(packets->empty()); + ASSERT_GT(fps_, 0); + int bits_per_frame = bitrate_bps_ / fps_; + int n_packets = std::max(bits_per_frame / (8 * kMtu), 1); + int packet_size = bits_per_frame / (8 * n_packets); + ASSERT_GE(n_packets, 0); + for (int i = 0; i < n_packets; ++i) { + Packet* packet = new Packet; + packet->send_time = time_now_ + kSendSideOffsetMs; + ASSERT_GT(capacity_, 0); + packet->arrival_time = std::max( + prev_arrival_time_ + 8 * 1000 * packet_size / capacity_, + time_now_); + packet->size = packet_size; + packet->rtp_timestamp = rtp_timestamp_offset_ + 90 * packet->send_time; + prev_arrival_time_ = packet->arrival_time; + packets->push_back(packet); + } + time_now_ = time_now_ + 1000 / fps_; + } + + int64_t TimeNow() const { + return time_now_; + } + + private: + enum { kSendSideOffsetMs = 1000 }; + + int fps_; + int bitrate_bps_; + int capacity_; + int64_t time_now_; + int64_t prev_arrival_time_; + uint32_t rtp_timestamp_offset_; +}; + +class RemoteBitrateEstimatorTest : public ::testing::Test { + protected: + virtual void SetUp() { + bitrate_observer_.reset(new TestBitrateObserver); + bitrate_estimator_.reset(new RemoteBitrateEstimator( + bitrate_observer_.get())); + // Framerate: 30 fps; Start bitrate: 300 kbps; Link capacity: 1000 kbps, + // Start time: 0. + stream_generator_.reset(new StreamGenerator(30, 3e5, 1e6, 0)); + } + + // Generates a frame of packets belonging to a stream at a given bitrate and + // with a given ssrc. The stream is pushed through a very simple simulated + // network, and is then given to the receive-side bandwidth estimator. + void GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps) { + stream_generator_->SetBitrate(bitrate_bps); + StreamGenerator::PacketList packets; + stream_generator_->GenerateFrame(&packets); + int64_t last_arrival_time = -1; + bool prev_was_decrease = false; + while (!packets.empty()) { + StreamGenerator::Packet* packet = packets.front(); + bitrate_estimator_->IncomingPacket(ssrc, + packet->size, + packet->arrival_time, + packet->rtp_timestamp, + -1); + if (bitrate_observer_->updated()) { + // Verify that new estimates only are triggered by an overuse and a + // rate decrease. + EXPECT_LE(bitrate_observer_->latest_bitrate(), bitrate_bps); + EXPECT_FALSE(prev_was_decrease); + prev_was_decrease = true; + } else { + prev_was_decrease = false; + } + last_arrival_time = packet->arrival_time; + delete packet; + packets.pop_front(); + } + EXPECT_GT(last_arrival_time, -1); + bitrate_estimator_->UpdateEstimate(ssrc, last_arrival_time); + } + + // Run the bandwidth estimator with a stream of |number_of_frames| frames. + // Can for instance be used to run the estimator for some time to get it + // into a steady state. + unsigned int SteadyStateRun(unsigned int ssrc, + int number_of_frames, + unsigned int start_bitrate, + unsigned int min_bitrate, + unsigned int max_bitrate) { + unsigned int bitrate_bps = start_bitrate; + bool bitrate_update_seen = false; + // Produce |number_of_frames| frames and give them to the estimator. + for (int i = 0; i < number_of_frames; ++i) { + GenerateAndProcessFrame(ssrc, bitrate_bps); + if (bitrate_observer_->updated()) { + EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate); + EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate); + bitrate_bps = bitrate_observer_->latest_bitrate(); + bitrate_update_seen = true; + } + } + EXPECT_TRUE(bitrate_update_seen); + return bitrate_bps; + } + + scoped_ptr bitrate_estimator_; + scoped_ptr bitrate_observer_; + scoped_ptr stream_generator_; +}; + +TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) { + unsigned int bitrate_bps = 0; + unsigned int ssrc = 0; + int64_t time_now = 0; + uint32_t timestamp = 0; + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps)); + bitrate_estimator_->UpdateEstimate(ssrc, time_now); + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps)); + EXPECT_FALSE(bitrate_observer_->updated()); + // Inserting a packet. Still no valid estimate. We need to wait 1 second. + bitrate_estimator_->IncomingPacket(ssrc, kMtu, time_now, + timestamp, -1); + bitrate_estimator_->UpdateEstimate(ssrc, time_now); + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps)); + EXPECT_FALSE(bitrate_observer_->updated()); + // Waiting more than one second gives us a valid estimate. + time_now += 1001; + bitrate_estimator_->UpdateEstimate(ssrc, time_now); + EXPECT_TRUE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps)); + EXPECT_EQ(bitrate_bps, 10734u); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps); +} + +// Make sure we initially increase the bitrate as expected. +TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) { + const int kExpectedIterations = 323; + unsigned int bitrate_bps = 30000; + unsigned int ssrc = 0; + int iterations = 0; + // Feed the estimator with a stream of packets and verify that it reaches + // 500 kbps at the expected time. + while (bitrate_bps < 5e5) { + GenerateAndProcessFrame(ssrc, bitrate_bps); + if (bitrate_observer_->updated()) { + EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps); + bitrate_bps = bitrate_observer_->latest_bitrate(); + } + ++iterations; + ASSERT_LE(iterations, kExpectedIterations); + } + ASSERT_EQ(iterations, kExpectedIterations); +} + +// Verify that the time it takes for the estimator to reduce the bitrate when +// the capacity is tightened stays the same. +TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestamps) { + const unsigned int kSsrc = 0; + const int kNumberOfFrames= 1000; + const int kStartBitrate = 900e3; + const int kMinExpectedBitrate = 800e3; + const int kMaxExpectedBitrate = 1500e3; + // Run in steady state to make the estimator converge. + unsigned int bitrate_bps = SteadyStateRun(kSsrc, kNumberOfFrames, + kStartBitrate, kMinExpectedBitrate, + kMaxExpectedBitrate); + // Reduce the capacity and verify the decrease time. + stream_generator_->SetCapacity(500e3); + int64_t bitrate_drop_time = 0; + for (int i = 0; i < 1000; ++i) { + GenerateAndProcessFrame(kSsrc, bitrate_bps); + if (bitrate_observer_->updated()) { + if (bitrate_observer_->latest_bitrate() <= 500e3) { + bitrate_drop_time = stream_generator_->TimeNow(); + } + bitrate_bps = bitrate_observer_->latest_bitrate(); + } + } + EXPECT_EQ(66000, bitrate_drop_time); +} + +// Verify that the time it takes for the estimator to reduce the bitrate when +// the capacity is tightened stays the same. This test also verifies that we +// handle wrap-arounds in this scenario. +TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestampsWrap) { + const unsigned int kSsrc = 0; + const int kFramerate= 30; + const int kStartBitrate = 900e3; + const int kMinExpectedBitrate = 800e3; + const int kMaxExpectedBitrate = 1500e3; + const int kSteadyStateTime = 5; // Seconds. + // Trigger wrap right after the steady state run. + stream_generator_->SetRtpTimestampOffset( + std::numeric_limits::max() - kSteadyStateTime * 90000); + // Run in steady state to make the estimator converge. + unsigned int bitrate_bps = SteadyStateRun(kSsrc, + kSteadyStateTime * kFramerate, + kStartBitrate, + kMinExpectedBitrate, + kMaxExpectedBitrate); + // Reduce the capacity and verify the decrease time. + stream_generator_->SetCapacity(500e3); + int64_t bitrate_drop_time = 0; + for (int i = 0; i < 1000; ++i) { + GenerateAndProcessFrame(kSsrc, bitrate_bps); + if (bitrate_observer_->updated()) { + if (bitrate_observer_->latest_bitrate() <= 500e3) { + bitrate_drop_time = stream_generator_->TimeNow(); + } + bitrate_bps = bitrate_observer_->latest_bitrate(); + } + } + EXPECT_EQ(37356, bitrate_drop_time); +} + +} // namespace webrtc diff --git a/src/modules/rtp_rtcp/source/remote_rate_control.cc b/src/modules/remote_bitrate_estimator/remote_rate_control.cc similarity index 92% rename from src/modules/rtp_rtcp/source/remote_rate_control.cc rename to src/modules/remote_bitrate_estimator/remote_rate_control.cc index fe8477c6b3..cb542a47b2 100644 --- a/src/modules/rtp_rtcp/source/remote_rate_control.cc +++ b/src/modules/remote_bitrate_estimator/remote_rate_control.cc @@ -8,14 +8,16 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "modules/remote_bitrate_estimator/remote_rate_control.h" + +#include +#include +#include #if _WIN32 #include #endif -#include "remote_rate_control.h" -#include "trace.h" -#include -#include +#include "system_wrappers/interface/trace.h" #ifdef MATLAB extern MatlabEngine eng; // global variable defined elsewhere @@ -40,7 +42,8 @@ _timeFirstIncomingEstimate(-1), _initializedBitRate(false), _avgChangePeriod(1000.0f), _lastChangeMs(-1), -_beta(0.9f) +_beta(0.9f), +_rtt(0) #ifdef MATLAB ,_plot1(NULL), _plot2(NULL) @@ -83,7 +86,8 @@ bool RemoteRateControl::ValidEstimate() const { return _initializedBitRate; } -WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates(WebRtc_UWord32 minBitRateBps, WebRtc_UWord32 maxBitRateBps) +WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates( + WebRtc_UWord32 minBitRateBps, WebRtc_UWord32 maxBitRateBps) { if (minBitRateBps > maxBitRateBps) { @@ -91,7 +95,8 @@ WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates(WebRtc_UWord32 minBitRate } _minConfiguredBitRate = minBitRateBps; _maxConfiguredBitRate = maxBitRateBps; - _currentBitRate = BWE_MIN(BWE_MAX(minBitRateBps, _currentBitRate), maxBitRateBps); + _currentBitRate = BWE_MIN(BWE_MAX(minBitRateBps, _currentBitRate), + maxBitRateBps); return 0; } @@ -99,18 +104,23 @@ WebRtc_UWord32 RemoteRateControl::LatestEstimate() const { return _currentBitRate; } -WebRtc_UWord32 RemoteRateControl::UpdateBandwidthEstimate(WebRtc_UWord32 RTT, - WebRtc_Word64 nowMS) +WebRtc_UWord32 RemoteRateControl::UpdateBandwidthEstimate(WebRtc_Word64 nowMS) { - _currentBitRate = ChangeBitRate(_currentBitRate, _currentInput._incomingBitRate, - _currentInput._noiseVar, RTT, nowMS); + _currentBitRate = ChangeBitRate(_currentBitRate, + _currentInput._incomingBitRate, + _currentInput._noiseVar, + nowMS); return _currentBitRate; } -RateControlRegion RemoteRateControl::Update(const RateControlInput& input, - bool& firstOverUse, +void RemoteRateControl::SetRtt(unsigned int rtt) { + _rtt = rtt; +} + +RateControlRegion RemoteRateControl::Update(const RateControlInput* input, WebRtc_Word64 nowMS) { + assert(input); #ifdef MATLAB // Create plots if (_plot1 == NULL) @@ -133,23 +143,20 @@ RateControlRegion RemoteRateControl::Update(const RateControlInput& input, } #endif - firstOverUse = (_currentInput._bwState != kBwOverusing && - input._bwState == kBwOverusing); - // Set the initial bit rate value to what we're receiving the first second if (!_initializedBitRate) { if (_timeFirstIncomingEstimate < 0) { - if (input._incomingBitRate > 0) + if (input->_incomingBitRate > 0) { _timeFirstIncomingEstimate = nowMS; } } else if (nowMS - _timeFirstIncomingEstimate > 1000 && - input._incomingBitRate > 0) + input->_incomingBitRate > 0) { - _currentBitRate = input._incomingBitRate; + _currentBitRate = input->_incomingBitRate; _initializedBitRate = true; } } @@ -157,20 +164,19 @@ RateControlRegion RemoteRateControl::Update(const RateControlInput& input, if (_updated && _currentInput._bwState == kBwOverusing) { // Only update delay factor and incoming bit rate. We always want to react on an over-use. - _currentInput._noiseVar = input._noiseVar; - _currentInput._incomingBitRate = input._incomingBitRate; + _currentInput._noiseVar = input->_noiseVar; + _currentInput._incomingBitRate = input->_incomingBitRate; return _rcRegion; } _updated = true; - _currentInput = input; - WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: Incoming rate = %u kbps", input._incomingBitRate/1000); + _currentInput = *input; + WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: Incoming rate = %u kbps", input->_incomingBitRate/1000); return _rcRegion; } WebRtc_UWord32 RemoteRateControl::ChangeBitRate(WebRtc_UWord32 currentBitRate, WebRtc_UWord32 incomingBitRate, double noiseVar, - WebRtc_UWord32 RTT, WebRtc_Word64 nowMS) { if (!_updated) @@ -209,13 +215,13 @@ WebRtc_UWord32 RemoteRateControl::ChangeBitRate(WebRtc_UWord32 currentBitRate, } WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: Response time: %f + %i + 10*33\n", - _avgChangePeriod, RTT); - const WebRtc_UWord32 responseTime = static_cast(_avgChangePeriod + 0.5f) + RTT + 300; + _avgChangePeriod, _rtt); + const WebRtc_UWord32 responseTime = static_cast(_avgChangePeriod + 0.5f) + _rtt + 300; double alpha = RateIncreaseFactor(nowMS, _lastBitRateChange, responseTime, noiseVar); WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, - "BWE: _avgChangePeriod = %f ms; RTT = %u ms", _avgChangePeriod, RTT); + "BWE: _avgChangePeriod = %f ms; RTT = %u ms", _avgChangePeriod, _rtt); currentBitRate = static_cast(currentBitRate * alpha) + 1000; if (_maxHoldRate > 0 && _beta * _maxHoldRate > currentBitRate) diff --git a/src/modules/rtp_rtcp/source/remote_rate_control.h b/src/modules/remote_bitrate_estimator/remote_rate_control.h similarity index 90% rename from src/modules/rtp_rtcp/source/remote_rate_control.h rename to src/modules/remote_bitrate_estimator/remote_rate_control.h index 197bf223c8..6c9d116589 100644 --- a/src/modules/rtp_rtcp/source/remote_rate_control.h +++ b/src/modules/remote_bitrate_estimator/remote_rate_control.h @@ -11,7 +11,7 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_REMOTE_RATE_CONTROL_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_REMOTE_RATE_CONTROL_H_ -#include "bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "typedefs.h" #ifdef MATLAB @@ -27,9 +27,9 @@ public: WebRtc_Word32 SetConfiguredBitRates(WebRtc_UWord32 minBitRate, WebRtc_UWord32 maxBitRate); WebRtc_UWord32 LatestEstimate() const; - WebRtc_UWord32 UpdateBandwidthEstimate(WebRtc_UWord32 RTT, - WebRtc_Word64 nowMS); - RateControlRegion Update(const RateControlInput& input, bool& firstOverUse, + WebRtc_UWord32 UpdateBandwidthEstimate(WebRtc_Word64 nowMS); + void SetRtt(unsigned int rtt); + RateControlRegion Update(const RateControlInput* input, WebRtc_Word64 nowMS); void Reset(); @@ -40,7 +40,7 @@ public: private: WebRtc_UWord32 ChangeBitRate(WebRtc_UWord32 currentBitRate, WebRtc_UWord32 incomingBitRate, - double delayFactor, WebRtc_UWord32 RTT, + double delayFactor, WebRtc_Word64 nowMS); double RateIncreaseFactor(WebRtc_Word64 nowMs, WebRtc_Word64 lastMs, @@ -72,6 +72,7 @@ private: float _avgChangePeriod; WebRtc_Word64 _lastChangeMs; float _beta; + unsigned int _rtt; #ifdef MATLAB MatlabPlot *_plot1; MatlabPlot *_plot2; diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h index c1f9a4a2a6..7db981088a 100644 --- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -18,6 +18,8 @@ namespace webrtc { // forward declaration +class RemoteBitrateEstimator; +class RemoteBitrateObserver; class Transport; class RtpRtcp : public Module { @@ -35,7 +37,7 @@ class RtpRtcp : public Module { intra_frame_callback(NULL), bandwidth_callback(NULL), audio_messages(NULL), - bitrate_observer(NULL) { + remote_bitrate_estimator(NULL) { } /* id - Unique identifier of this RTP/RTCP module object * audio - True for a audio version of the RTP/RTCP module @@ -54,8 +56,8 @@ class RtpRtcp : public Module { * bandwidth_callback - Called when we receive a changed estimate from * the receiver of out stream. * audio_messages - Telehone events. - * bitrate_observer - Called when the estimate of the incoming RTP - * stream changes. + * remote_bitrate_estimator - Estimates the bandwidth available for a set of + * streams from the same client. */ int32_t id; bool audio; @@ -68,7 +70,7 @@ class RtpRtcp : public Module { RtcpIntraFrameObserver* intra_frame_callback; RtcpBandwidthObserver* bandwidth_callback; RtpAudioFeedback* audio_messages; - RtpRemoteBitrateObserver* bitrate_observer; + RemoteBitrateEstimator* remote_bitrate_estimator; }; /* * Create a RTP/RTCP module object using the system clock. diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index 110b08c2b1..6bc787ee73 100644 --- a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -251,16 +251,5 @@ class RtpRtcpClock { virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) = 0; }; -// RtpReceiveBitrateUpdate is used to signal changes in bitrate estimates for -// the incoming stream. -class RtpRemoteBitrateObserver { - public: - // Called when a receive channel has a new bitrate estimate for the incoming - // stream. - virtual void OnReceiveBitrateChanged(uint32_t ssrc, - uint32_t bitrate) = 0; - - virtual ~RtpRemoteBitrateObserver() {} -}; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_ diff --git a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 1b5e407d02..2ac912590f 100644 --- a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -8,7 +8,10 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "../testing/gmock/include/gmock/gmock.h" +#ifndef WEBRTC_MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ +#define WEBRTC_MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ + +#include #include "modules/interface/module.h" #include "modules/rtp_rtcp/interface/rtp_rtcp.h" @@ -211,7 +214,7 @@ class MockRtpRtcp : public RtpRtcp { MOCK_METHOD3(SetREMBData, WebRtc_Word32(const WebRtc_UWord32 bitrate, const WebRtc_UWord8 numberOfSSRC, const WebRtc_UWord32* SSRC)); MOCK_METHOD1(SetRemoteBitrateObserver, - bool(RtpRemoteBitrateObserver*)); + bool(RemoteBitrateObserver*)); MOCK_CONST_METHOD0(IJ, bool()); MOCK_METHOD1(SetIJStatus, @@ -285,3 +288,5 @@ class MockRtpRtcp : public RtpRtcp { }; } // namespace webrtc + +#endif // WEBRTC_MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ diff --git a/src/modules/rtp_rtcp/source/Bitrate.h b/src/modules/rtp_rtcp/source/Bitrate.h index 3859aaa3a8..074476bdac 100644 --- a/src/modules/rtp_rtcp/source/Bitrate.h +++ b/src/modules/rtp_rtcp/source/Bitrate.h @@ -55,32 +55,6 @@ private: WebRtc_UWord32 _packetCount; }; -struct DataTimeSizeTuple -{ - DataTimeSizeTuple(WebRtc_UWord32 sizeBytes, WebRtc_Word64 timeCompleteMs) : - _sizeBytes(sizeBytes), - _timeCompleteMs(timeCompleteMs) {} - - WebRtc_UWord32 _sizeBytes; - WebRtc_Word64 _timeCompleteMs; -}; - -class BitRateStats -{ -public: - BitRateStats(); - ~BitRateStats(); - - void Init(); - void Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs); - WebRtc_UWord32 BitRate(WebRtc_Word64 nowMs); - -private: - void EraseOld(WebRtc_Word64 nowMs); - - std::list _dataSamples; - WebRtc_UWord32 _accumulatedBytes; -}; -} // namespace webrtc +} // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BITRATE_H_ diff --git a/src/modules/rtp_rtcp/source/bitrate.cc b/src/modules/rtp_rtcp/source/bitrate.cc index 0fbb7ad3b0..8f09034003 100644 --- a/src/modules/rtp_rtcp/source/bitrate.cc +++ b/src/modules/rtp_rtcp/source/bitrate.cc @@ -11,8 +11,6 @@ #include "Bitrate.h" #include "rtp_utility.h" -#define BITRATE_AVERAGE_WINDOW 2000 - namespace webrtc { Bitrate::Bitrate(RtpRtcpClock* clock) : _clock(*clock), @@ -112,77 +110,4 @@ Bitrate::Process() } } -BitRateStats::BitRateStats() - :_dataSamples(), _accumulatedBytes(0) -{ -} - -BitRateStats::~BitRateStats() -{ - while (_dataSamples.size() > 0) - { - delete _dataSamples.front(); - _dataSamples.pop_front(); - } -} - -void BitRateStats::Init() -{ - _accumulatedBytes = 0; - while (_dataSamples.size() > 0) - { - delete _dataSamples.front(); - _dataSamples.pop_front(); - } -} - -void BitRateStats::Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs) -{ - // Find an empty slot for storing the new sample and at the same time - // accumulate the history. - _dataSamples.push_back(new DataTimeSizeTuple(packetSizeBytes, nowMs)); - _accumulatedBytes += packetSizeBytes; - EraseOld(nowMs); -} - -void BitRateStats::EraseOld(WebRtc_Word64 nowMs) -{ - while (_dataSamples.size() > 0) - { - if (nowMs - _dataSamples.front()->_timeCompleteMs > - BITRATE_AVERAGE_WINDOW) - { - // Delete old sample - _accumulatedBytes -= _dataSamples.front()->_sizeBytes; - delete _dataSamples.front(); - _dataSamples.pop_front(); - } - else - { - break; - } - } -} - -WebRtc_UWord32 BitRateStats::BitRate(WebRtc_Word64 nowMs) -{ - // Calculate the average bit rate the past BITRATE_AVERAGE_WINDOW ms. - // Removes any old samples from the list. - EraseOld(nowMs); - WebRtc_Word64 timeOldest = nowMs; - if (_dataSamples.size() > 0) - { - timeOldest = _dataSamples.front()->_timeCompleteMs; - } - // Update average bit rate - float denom = static_cast(nowMs - timeOldest); - if (nowMs == timeOldest) - { - // Calculate with a one second window when we haven't - // received more than one packet. - denom = 1000.0; - } - return static_cast(_accumulatedBytes * 8.0f * 1000.0f / - denom + 0.5f); -} } // namespace webrtc diff --git a/src/modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h b/src/modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h index cb7ebbae52..9498b74be3 100644 --- a/src/modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h +++ b/src/modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h @@ -8,12 +8,16 @@ * be found in the AUTHORS file in the root of the source tree. */ +#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_MOCK_MOCK_RTP_RECEIVER_VIDEO_H_ +#define WEBRTC_MODULES_RTP_RTCP_SOURCE_MOCK_MOCK_RTP_RECEIVER_VIDEO_H_ + #include "modules/rtp_rtcp/source/rtp_receiver_video.h" namespace webrtc { class MockRTPReceiverVideo : public RTPReceiverVideo { public: + MockRTPReceiverVideo() : RTPReceiverVideo(0, NULL, NULL) {} MOCK_METHOD1(ChangeUniqueId, void(const WebRtc_Word32 id)); MOCK_METHOD3(ReceiveRecoveredPacketCallback, @@ -39,3 +43,5 @@ class MockRTPReceiverVideo : public RTPReceiverVideo { }; } // namespace webrtc + +#endif //WEBRTC_MODULES_RTP_RTCP_SOURCE_MOCK_MOCK_RTP_RECEIVER_VIDEO_H_ diff --git a/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc index d937f3510b..96d1d2f2ed 100644 --- a/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc @@ -16,7 +16,8 @@ #include "rtcp_sender.h" #include "rtcp_receiver.h" #include "rtp_rtcp_impl.h" -#include "bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h" namespace { @@ -57,7 +58,9 @@ class TestTransport : public Transport { class RtcpFormatRembTest : public ::testing::Test { protected: - RtcpFormatRembTest() {}; + RtcpFormatRembTest() + : remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_) {} virtual void SetUp(); virtual void TearDown(); @@ -66,6 +69,8 @@ class RtcpFormatRembTest : public ::testing::Test { RTCPSender* rtcp_sender_; RTCPReceiver* rtcp_receiver_; TestTransport* test_transport_; + MockRemoteBitrateObserver remote_bitrate_observer_; + RemoteBitrateEstimator remote_bitrate_estimator_; }; void RtcpFormatRembTest::SetUp() { @@ -74,6 +79,7 @@ void RtcpFormatRembTest::SetUp() { configuration.id = 0; configuration.audio = false; configuration.clock = system_clock_; + configuration.remote_bitrate_estimator = &remote_bitrate_estimator_; dummy_rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtcp_sender_ = new RTCPSender(0, false, system_clock_, dummy_rtp_rtcp_impl_); rtcp_receiver_ = new RTCPReceiver(0, system_clock_, dummy_rtp_rtcp_impl_); diff --git a/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 9598a43318..b511c4e9c5 100644 --- a/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -12,10 +12,13 @@ /* * This file includes unit tests for the RTCPReceiver. */ +#include #include // Note: This file has no directory. Lint warning must be ignored. #include "common_types.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h" #include "modules/rtp_rtcp/source/rtp_utility.h" #include "modules/rtp_rtcp/source/rtcp_sender.h" #include "modules/rtp_rtcp/source/rtcp_receiver.h" @@ -179,15 +182,19 @@ class TestTransport : public Transport, class RtcpReceiverTest : public ::testing::Test { protected: - RtcpReceiverTest() { + RtcpReceiverTest() + : remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_) { // system_clock_ = ModuleRTPUtility::GetSystemClock(); system_clock_ = new FakeSystemClock(); test_transport_ = new TestTransport(); + RtpRtcp::Configuration configuration; configuration.id = 0; configuration.audio = false; configuration.clock = system_clock_; configuration.outgoing_transport = test_transport_; + configuration.remote_bitrate_estimator = &remote_bitrate_estimator_; rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtcp_receiver_ = new RTCPReceiver(0, system_clock_, rtp_rtcp_impl_); test_transport_->SetRTCPReceiver(rtcp_receiver_); @@ -219,6 +226,8 @@ class RtcpReceiverTest : public ::testing::Test { RTCPReceiver* rtcp_receiver_; TestTransport* test_transport_; RTCPHelp::RTCPPacketInformation rtcp_packet_info_; + MockRemoteBitrateObserver remote_bitrate_observer_; + RemoteBitrateEstimator remote_bitrate_estimator_; }; diff --git a/src/modules/rtp_rtcp/source/rtcp_sender.cc b/src/modules/rtp_rtcp/source/rtcp_sender.cc index 6383f8f369..eb3a905d99 100644 --- a/src/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/src/modules/rtp_rtcp/source/rtcp_sender.cc @@ -10,15 +10,15 @@ #include "rtcp_sender.h" -#include // memcpy -#include // assert -#include // rand +#include // assert +#include // rand +#include // memcpy -#include "trace.h" #include "common_types.h" -#include "critical_section_wrapper.h" - -#include "rtp_rtcp_impl.h" +#include "modules/remote_bitrate_estimator/remote_rate_control.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/trace.h" namespace webrtc { @@ -66,12 +66,10 @@ RTCPSender::RTCPSender(const WebRtc_Word32 id, _sizeRembSSRC(0), _rembSSRC(NULL), _rembBitrate(0), - _bitrate_observer(NULL), _tmmbrHelp(), _tmmbr_Send(0), _packetOH_Send(0), - _remoteRateControl(), _appSend(false), _appSubType(0), @@ -130,7 +128,7 @@ RTCPSender::Init() _sequenceNumberFIR = 0; _tmmbr_Send = 0; _packetOH_Send = 0; - _remoteRateControl.Reset(); + //_remoteRateControl.Reset(); _nextTimeToSendRTCP = 0; _CSRCs = 0; _appSend = false; @@ -261,22 +259,6 @@ RTCPSender::SetREMBData(const WebRtc_UWord32 bitrate, return 0; } -bool RTCPSender::SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer) { - CriticalSectionScoped lock(_criticalSectionRTCPSender); - if (observer && _bitrate_observer) { - return false; - } - _bitrate_observer = observer; - return true; -} - -void RTCPSender::UpdateRemoteBitrateEstimate(unsigned int target_bitrate) { - CriticalSectionScoped lock(_criticalSectionRTCPSender); - if (_bitrate_observer) { - _bitrate_observer->OnReceiveBitrateChanged(_remoteSSRC, target_bitrate); - } -} - bool RTCPSender::TMMBR() const { @@ -327,7 +309,7 @@ RTCPSender::SetRemoteSSRC( const WebRtc_UWord32 ssrc) { CriticalSectionScoped lock(_criticalSectionRTCPSender); _remoteSSRC = ssrc; - _remoteRateControl.Reset(); + //_remoteRateControl.Reset(); return 0; } @@ -1104,25 +1086,11 @@ RTCPSender::BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos) return 0; } -WebRtc_UWord32 -RTCPSender::CalculateNewTargetBitrate(WebRtc_UWord32 RTT) +void +RTCPSender::SetTargetBitrate(unsigned int target_bitrate) { CriticalSectionScoped lock(_criticalSectionRTCPSender); - WebRtc_UWord32 target_bitrate = - _remoteRateControl.UpdateBandwidthEstimate(RTT, _clock.GetTimeInMS()); _tmmbr_Send = target_bitrate / 1000; - return target_bitrate; -} - -WebRtc_UWord32 RTCPSender::LatestBandwidthEstimate() const { - CriticalSectionScoped lock(_criticalSectionRTCPSender); - return _remoteRateControl.LatestEstimate(); -} - -bool -RTCPSender::ValidBitrateEstimate() const { - CriticalSectionScoped lock(_criticalSectionRTCPSender); - return _remoteRateControl.ValidEstimate(); } WebRtc_Word32 @@ -2163,12 +2131,4 @@ RTCPSender::SetTMMBN(const TMMBRSet* boundingSet, } return -1; } - -RateControlRegion -RTCPSender::UpdateOverUseState(const RateControlInput& rateControlInput, bool& firstOverUse) -{ - CriticalSectionScoped lock(_criticalSectionRTCPSender); - return _remoteRateControl.Update(rateControlInput, firstOverUse, - _clock.GetTimeInMS()); -} } // namespace webrtc diff --git a/src/modules/rtp_rtcp/source/rtcp_sender.h b/src/modules/rtp_rtcp/source/rtcp_sender.h index e3441da34c..e31ca0715e 100644 --- a/src/modules/rtp_rtcp/source/rtcp_sender.h +++ b/src/modules/rtp_rtcp/source/rtcp_sender.h @@ -17,8 +17,10 @@ #include "rtcp_utility.h" #include "rtp_utility.h" #include "rtp_rtcp_defines.h" -#include "remote_rate_control.h" +#include "scoped_ptr.h" #include "tmmbr_help.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" namespace webrtc { @@ -87,10 +89,6 @@ public: const WebRtc_UWord8 numberOfSSRC, const WebRtc_UWord32* SSRC); - bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer); - - void UpdateRemoteBitrateEstimate(unsigned int target_bitrate); - /* * TMMBR */ @@ -124,19 +122,7 @@ public: WebRtc_Word32 SetCSRCStatus(const bool include); - /* - * New bandwidth estimation - */ - - RateControlRegion UpdateOverUseState(const RateControlInput& rateControlInput, bool& firstOverUse); - - WebRtc_UWord32 CalculateNewTargetBitrate(WebRtc_UWord32 RTT); - - WebRtc_UWord32 LatestBandwidthEstimate() const; - - // Returns true if there is a valid estimate of the incoming bitrate, false - // otherwise. - bool ValidBitrateEstimate() const; + void SetTargetBitrate(unsigned int target_bitrate); private: WebRtc_Word32 SendToNetwork(const WebRtc_UWord8* dataBuffer, @@ -240,12 +226,10 @@ private: WebRtc_UWord8 _sizeRembSSRC; WebRtc_UWord32* _rembSSRC; WebRtc_UWord32 _rembBitrate; - RtpRemoteBitrateObserver* _bitrate_observer; TMMBRHelp _tmmbrHelp; WebRtc_UWord32 _tmmbr_Send; WebRtc_UWord32 _packetOH_Send; - RemoteRateControl _remoteRateControl; // APP bool _appSend; diff --git a/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 17fbafc72c..0b14547b7d 100644 --- a/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -13,13 +13,16 @@ * This file includes unit tests for the RTCPSender. */ +#include #include #include "common_types.h" -#include "rtp_utility.h" -#include "rtcp_sender.h" -#include "rtcp_receiver.h" -#include "rtp_rtcp_impl.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h" +#include "modules/rtp_rtcp/source/rtcp_receiver.h" +#include "modules/rtp_rtcp/source/rtcp_sender.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" namespace webrtc { @@ -94,7 +97,9 @@ class TestTransport : public Transport, class RtcpSenderTest : public ::testing::Test { protected: - RtcpSenderTest() { + RtcpSenderTest() + : remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_) { system_clock_ = ModuleRTPUtility::GetSystemClock(); test_transport_ = new TestTransport(); @@ -104,6 +109,7 @@ class RtcpSenderTest : public ::testing::Test { configuration.clock = system_clock_; configuration.incoming_data = test_transport_; configuration.outgoing_transport = test_transport_; + configuration.remote_bitrate_estimator = &remote_bitrate_estimator_; rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtcp_sender_ = new RTCPSender(0, false, system_clock_, rtp_rtcp_impl_); @@ -132,6 +138,8 @@ class RtcpSenderTest : public ::testing::Test { RTCPSender* rtcp_sender_; RTCPReceiver* rtcp_receiver_; TestTransport* test_transport_; + MockRemoteBitrateObserver remote_bitrate_observer_; + RemoteBitrateEstimator remote_bitrate_estimator_; enum {kMaxPacketLength = 1500}; uint8_t packet_[kMaxPacketLength]; diff --git a/src/modules/rtp_rtcp/source/rtp_receiver.cc b/src/modules/rtp_rtcp/source/rtp_receiver.cc index 7c5439eeac..6d927a55d8 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver.cc +++ b/src/modules/rtp_rtcp/source/rtp_receiver.cc @@ -32,9 +32,10 @@ using ModuleRTPUtility::VideoPayload; RTPReceiver::RTPReceiver(const WebRtc_Word32 id, const bool audio, RtpRtcpClock* clock, + RemoteBitrateEstimator* remote_bitrate, ModuleRtpRtcpImpl* owner) : RTPReceiverAudio(id), - RTPReceiverVideo(id, owner), + RTPReceiverVideo(id, remote_bitrate, owner), Bitrate(clock), _id(id), _audio(audio), @@ -1083,7 +1084,6 @@ void RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader) { // reset last report ResetStatistics(); - RTPReceiverVideo::ResetOverUseDetector(); _lastReceivedTimestamp = 0; _lastReceivedSequenceNumber = 0; diff --git a/src/modules/rtp_rtcp/source/rtp_receiver.h b/src/modules/rtp_rtcp/source/rtp_receiver.h index d6ecfaaafa..e8bd7f364b 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver.h +++ b/src/modules/rtp_rtcp/source/rtp_receiver.h @@ -35,6 +35,7 @@ public: RTPReceiver(const WebRtc_Word32 id, const bool audio, RtpRtcpClock* clock, + RemoteBitrateEstimator* remote_bitrate, ModuleRtpRtcpImpl* owner); virtual ~RTPReceiver(); diff --git a/src/modules/rtp_rtcp/source/rtp_receiver_video.cc b/src/modules/rtp_rtcp/source/rtp_receiver_video.cc index 94d49e0588..807a52cfcf 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver_video.cc +++ b/src/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -26,20 +26,8 @@ WebRtc_UWord32 BitRateBPS(WebRtc_UWord16 x ) return (x & 0x3fff) * WebRtc_UWord32(pow(10.0f,(2 + (x >> 14)))); } -RTPReceiverVideo::RTPReceiverVideo() - : _id(0), - _rtpRtcp(NULL), - _criticalSectionReceiverVideo( - CriticalSectionWrapper::CreateCriticalSection()), - _currentFecFrameDecoded(false), - _receiveFEC(NULL), - _overUseDetector(), - _videoBitRate(), - _lastBitRateChange(0), - _packetOverHead(28) { -} - RTPReceiverVideo::RTPReceiverVideo(const WebRtc_Word32 id, + RemoteBitrateEstimator* remote_bitrate, ModuleRtpRtcpImpl* owner) : _id(id), _rtpRtcp(owner), @@ -47,9 +35,7 @@ RTPReceiverVideo::RTPReceiverVideo(const WebRtc_Word32 id, CriticalSectionWrapper::CreateCriticalSection()), _currentFecFrameDecoded(false), _receiveFEC(NULL), - _overUseDetector(), - _videoBitRate(), - _lastBitRateChange(0), + remote_bitrate_(remote_bitrate), _packetOverHead(28) { } @@ -87,12 +73,6 @@ ModuleRTPUtility::Payload* RTPReceiverVideo::RegisterReceiveVideoPayload( return payload; } -void RTPReceiverVideo::ResetOverUseDetector() { - _overUseDetector.Reset(); - _videoBitRate.Init(); - _lastBitRateChange = 0; -} - // we have no critext when calling this // we are not allowed to have any critsects when calling // CallbackOfReceivedPayloadData @@ -109,14 +89,15 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecific( _criticalSectionReceiverVideo->Enter(); - _videoBitRate.Update(payloadDataLength + rtpHeader->header.paddingLength, - nowMS); - // Add headers, ideally we would like to include for instance // Ethernet header here as well. const WebRtc_UWord16 packetSize = payloadDataLength + _packetOverHead + rtpHeader->header.headerLength + rtpHeader->header.paddingLength; - _overUseDetector.Update(*rtpHeader, packetSize, nowMS); + remote_bitrate_->IncomingPacket(rtpHeader->header.ssrc, + packetSize, + nowMS, + rtpHeader->header.timestamp, + -1); if (isRED) { if(_receiveFEC == NULL) { @@ -154,24 +135,6 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecific( payloadDataLength, videoType); } - - // Update the remote rate control object and update the overuse - // detector with the current rate control region. - _criticalSectionReceiverVideo->Enter(); - const RateControlInput input(_overUseDetector.State(), - _videoBitRate.BitRate(nowMS), - _overUseDetector.NoiseVar()); - _criticalSectionReceiverVideo->Leave(); - - // Call the callback outside critical section - if (_rtpRtcp) { - const RateControlRegion region = _rtpRtcp->OnOverUseStateUpdate(input); - - _criticalSectionReceiverVideo->Enter(); - _overUseDetector.SetRateControlRegion(region); - _criticalSectionReceiverVideo->Leave(); - } - return retVal; } diff --git a/src/modules/rtp_rtcp/source/rtp_receiver_video.h b/src/modules/rtp_rtcp/source/rtp_receiver_video.h index ce3229374e..1405630740 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver_video.h +++ b/src/modules/rtp_rtcp/source/rtp_receiver_video.h @@ -16,9 +16,11 @@ #include "typedefs.h" -#include "overuse_detector.h" -#include "remote_rate_control.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/remote_bitrate_estimator/overuse_detector.h" +#include "modules/remote_bitrate_estimator/remote_rate_control.h" #include "Bitrate.h" +#include "scoped_ptr.h" namespace webrtc { class ReceiverFEC; @@ -27,8 +29,9 @@ class CriticalSectionWrapper; class RTPReceiverVideo { public: - RTPReceiverVideo(); - RTPReceiverVideo(const WebRtc_Word32 id, ModuleRtpRtcpImpl* owner); + RTPReceiverVideo(const WebRtc_Word32 id, + RemoteBitrateEstimator* remote_bitrate, + ModuleRtpRtcpImpl* owner); virtual ~RTPReceiverVideo(); @@ -55,8 +58,6 @@ class RTPReceiverVideo { void SetPacketOverHead(WebRtc_UWord16 packetOverHead); protected: - void ResetOverUseDetector(); - virtual WebRtc_Word32 CallbackOfReceivedPayloadData( const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, @@ -106,9 +107,7 @@ class RTPReceiverVideo { ReceiverFEC* _receiveFEC; // BWE - OverUseDetector _overUseDetector; - BitRateStats _videoBitRate; - WebRtc_Word64 _lastBitRateChange; + RemoteBitrateEstimator* remote_bitrate_; WebRtc_UWord16 _packetOverHead; }; } // namespace webrtc diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi index 2017dff9c8..5c47bd39a8 100644 --- a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi +++ b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi @@ -13,6 +13,7 @@ 'type': '<(library)', 'dependencies': [ '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', + '<(webrtc_root)/modules/modules.gyp:remote_bitrate_estimator', ], 'include_dirs': [ '../interface', @@ -67,12 +68,8 @@ 'forward_error_correction.h', 'forward_error_correction_internal.cc', 'forward_error_correction_internal.h', - 'overuse_detector.cc', - 'overuse_detector.h', 'producer_fec.cc', 'producer_fec.h', - 'remote_rate_control.cc', - 'remote_rate_control.h', 'rtp_packet_history.cc', 'rtp_packet_history.h', 'rtp_receiver_video.cc', diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 4a2a21742c..d86ccee439 100644 --- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -54,7 +54,7 @@ RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) { ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) : _rtpSender(configuration.id, configuration.audio, configuration.clock), _rtpReceiver(configuration.id, configuration.audio, configuration.clock, - this), + configuration.remote_bitrate_estimator, this), _rtcpSender(configuration.id, configuration.audio, configuration.clock, this), _rtcpReceiver(configuration.id, configuration.clock, this), @@ -80,7 +80,8 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) _nackLastTimeSent(0), _nackLastSeqNumberSent(0), _simulcast(false), - _keyFrameReqMethod(kKeyFrameReqFirRtp) + _keyFrameReqMethod(kKeyFrameReqFirRtp), + remote_bitrate_(configuration.remote_bitrate_estimator) #ifdef MATLAB , _plot1(NULL) #endif @@ -102,8 +103,6 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) _rtpSender.RegisterSendTransport(configuration.outgoing_transport); _rtcpSender.RegisterSendTransport(configuration.outgoing_transport); - _rtcpSender.SetRemoteBitrateObserver(configuration.bitrate_observer); - // make sure that RTCP objects are aware of our SSRC WebRtc_UWord32 SSRC = _rtpSender.SSRC(); _rtcpSender.SetSSRC(SSRC); @@ -224,15 +223,16 @@ WebRtc_Word32 ModuleRtpRtcpImpl::Process() { // default module or no RTCP received yet. max_rtt = kDefaultRtt; } - if (_rtcpSender.ValidBitrateEstimate()) { - if (REMB()) { - uint32_t target_bitrate = - _rtcpSender.CalculateNewTargetBitrate(max_rtt); - _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate); - } else if (TMMBR()) { - _rtcpSender.CalculateNewTargetBitrate(max_rtt); + remote_bitrate_->SetRtt(max_rtt); + remote_bitrate_->UpdateEstimate(_rtpReceiver.SSRC(), now); + if (TMMBR()) { + unsigned int target_bitrate = 0; + if (remote_bitrate_->LatestEstimate(_rtpReceiver.SSRC(), + &target_bitrate)) { + _rtcpSender.SetTargetBitrate(target_bitrate); } } + _rtcpSender.SendRTCP(kRtcpReport); } @@ -1882,35 +1882,12 @@ void ModuleRtpRtcpImpl::BitrateSent(WebRtc_UWord32* totalRate, int ModuleRtpRtcpImpl::EstimatedReceiveBandwidth( WebRtc_UWord32* available_bandwidth) const { - if (!_rtcpSender.ValidBitrateEstimate()) + if (!remote_bitrate_->LatestEstimate(_rtpReceiver.SSRC(), + available_bandwidth)) return -1; - *available_bandwidth = _rtcpSender.LatestBandwidthEstimate(); return 0; } -RateControlRegion ModuleRtpRtcpImpl::OnOverUseStateUpdate( - const RateControlInput& rateControlInput) { - - bool firstOverUse = false; - RateControlRegion region = _rtcpSender.UpdateOverUseState(rateControlInput, - firstOverUse); - if (firstOverUse) { - // Send TMMBR or REMB immediately. - WebRtc_UWord16 RTT = 0; - _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL); - // About to send TMMBR, first run remote rate control - // to get a target bit rate. - unsigned int target_bitrate = - _rtcpSender.CalculateNewTargetBitrate(RTT); - if (REMB()) { - _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate); - } else if (TMMBR()) { - _rtcpSender.SendRTCP(kRtcpTmmbr); - } - } - return region; -} - // bad state of RTP receiver request a keyframe void ModuleRtpRtcpImpl::OnRequestIntraFrame() { RequestKeyFrame(); diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 8724d78b3f..fbabb1b98e 100644 --- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -428,8 +428,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp { virtual WebRtc_UWord32 SendTimeOfSendReport(const WebRtc_UWord32 sendReport); - virtual RateControlRegion OnOverUseStateUpdate(const RateControlInput& rateControlInput); - // good state of RTP receiver inform sender virtual WebRtc_Word32 SendRTCPReferencePictureSelection(const WebRtc_UWord64 pictureID); @@ -506,6 +504,8 @@ private: VideoCodec _sendVideoCodec; KeyFrameRequestMethod _keyFrameReqMethod; + RemoteBitrateEstimator* remote_bitrate_; + #ifdef MATLAB MatlabPlot* _plot1; #endif diff --git a/src/modules/rtp_rtcp/test/test_bwe/test_bwe.gypi b/src/modules/rtp_rtcp/test/test_bwe/test_bwe.gypi deleted file mode 100644 index d165e7d501..0000000000 --- a/src/modules/rtp_rtcp/test/test_bwe/test_bwe.gypi +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -{ - 'targets': [ - { - 'target_name': 'test_bwe', - 'type': 'executable', - 'dependencies': [ - 'rtp_rtcp', - '<(webrtc_root)/../test/test.gyp:test_support_main', - '<(webrtc_root)/../testing/gtest.gyp:gtest', - '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', - ], - 'include_dirs': [ - '../../source', - ], - 'sources': [ - 'unit_test.cc', - '../../source/bitrate.cc', - ], - }, - ], -} - -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/src/video_engine/vie_channel.cc b/src/video_engine/vie_channel.cc index 0e0f690346..3bd3b273a2 100644 --- a/src/video_engine/vie_channel.cc +++ b/src/video_engine/vie_channel.cc @@ -38,7 +38,7 @@ ViEChannel::ViEChannel(WebRtc_Word32 channel_id, ProcessThread& module_process_thread, RtcpIntraFrameObserver* intra_frame_observer, RtcpBandwidthObserver* bandwidth_observer, - RtpRemoteBitrateObserver* bitrate_observer, + RemoteBitrateEstimator* remote_bitrate_estimator, RtpRtcp* default_rtp_rtcp) : ViEFrameProviderBase(channel_id, engine_id), channel_id_(channel_id), @@ -91,7 +91,7 @@ ViEChannel::ViEChannel(WebRtc_Word32 channel_id, configuration.rtcp_feedback = this; configuration.intra_frame_callback = intra_frame_observer; configuration.bandwidth_callback = bandwidth_observer; - configuration.bitrate_observer = bitrate_observer; + configuration.remote_bitrate_estimator = remote_bitrate_estimator; rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration)); vie_receiver_.SetRtpRtcpModule(rtp_rtcp_.get()); diff --git a/src/video_engine/vie_channel.h b/src/video_engine/vie_channel.h index b450d244c3..92bf0be719 100644 --- a/src/video_engine/vie_channel.h +++ b/src/video_engine/vie_channel.h @@ -15,6 +15,7 @@ #include +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "modules/udp_transport/interface/udp_transport.h" #include "modules/video_coding/main/interface/video_coding_defines.h" @@ -63,7 +64,7 @@ class ViEChannel ProcessThread& module_process_thread, RtcpIntraFrameObserver* intra_frame_observer, RtcpBandwidthObserver* bandwidth_observer, - RtpRemoteBitrateObserver* bitrate_observer, + RemoteBitrateEstimator* remote_bitrate_estimator, RtpRtcp* default_rtp_rtcp); ~ViEChannel(); diff --git a/src/video_engine/vie_channel_group.cc b/src/video_engine/vie_channel_group.cc index 2555286b8c..e26e19c1c7 100644 --- a/src/video_engine/vie_channel_group.cc +++ b/src/video_engine/vie_channel_group.cc @@ -11,6 +11,7 @@ #include "video_engine/vie_channel_group.h" #include "modules/bitrate_controller/include/bitrate_controller.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "modules/rtp_rtcp/interface/rtp_rtcp.h" #include "video_engine/vie_channel.h" #include "video_engine/vie_encoder.h" @@ -20,7 +21,8 @@ namespace webrtc { ChannelGroup::ChannelGroup(ProcessThread* process_thread) : remb_(new VieRemb(process_thread)), - bitrate_controller_(BitrateController::CreateBitrateController()) { + bitrate_controller_(BitrateController::CreateBitrateController()), + remote_bitrate_estimator_(new RemoteBitrateEstimator(remb_.get())) { } ChannelGroup::~ChannelGroup() { @@ -31,8 +33,9 @@ void ChannelGroup::AddChannel(int channel_id) { channels_.insert(channel_id); } -void ChannelGroup::RemoveChannel(int channel_id) { +void ChannelGroup::RemoveChannel(int channel_id, unsigned int ssrc) { channels_.erase(channel_id); + remote_bitrate_estimator_->RemoveStream(ssrc); } bool ChannelGroup::HasChannel(int channel_id) { @@ -43,14 +46,14 @@ bool ChannelGroup::Empty() { return channels_.empty(); } -RtpRemoteBitrateObserver* ChannelGroup::GetRtpRemoteBitrateObserver() { - return remb_.get(); -} - BitrateController* ChannelGroup::GetBitrateController() { return bitrate_controller_.get(); } +RemoteBitrateEstimator* ChannelGroup::GetRemoteBitrateEstimator() { + return remote_bitrate_estimator_.get(); +} + bool ChannelGroup::SetChannelRembStatus(int channel_id, bool sender, bool receiver, @@ -64,7 +67,7 @@ bool ChannelGroup::SetChannelRembStatus(int channel_id, } else if (channel) { channel->EnableRemb(false); } - // Update the remb instance with necesary RTp modules. + // Update the REMB instance with necessary RTP modules. RtpRtcp* rtp_module = channel->rtp_rtcp(); if (sender) { remb_->AddRembSender(rtp_module); diff --git a/src/video_engine/vie_channel_group.h b/src/video_engine/vie_channel_group.h index 279a5560ee..0fb777cd2d 100644 --- a/src/video_engine/vie_channel_group.h +++ b/src/video_engine/vie_channel_group.h @@ -19,7 +19,8 @@ namespace webrtc { class BitrateController; class ProcessThread; -class RtpRemoteBitrateObserver; +class RemoteBitrateEstimator; +class RemoteBitrateObserver; class ViEChannel; class ViEEncoder; class VieRemb; @@ -32,7 +33,7 @@ class ChannelGroup { ~ChannelGroup(); void AddChannel(int channel_id); - void RemoveChannel(int channel_id); + void RemoveChannel(int channel_id, unsigned int ssrc); bool HasChannel(int channel_id); bool Empty(); @@ -43,14 +44,14 @@ class ChannelGroup { ViEEncoder* encoder); BitrateController* GetBitrateController(); - - RtpRemoteBitrateObserver* GetRtpRemoteBitrateObserver(); + RemoteBitrateEstimator* GetRemoteBitrateEstimator(); private: typedef std::set ChannelSet; scoped_ptr remb_; scoped_ptr bitrate_controller_; + scoped_ptr remote_bitrate_estimator_; ChannelSet channels_; }; diff --git a/src/video_engine/vie_channel_manager.cc b/src/video_engine/vie_channel_manager.cc index 777bcccc29..c51f527df6 100644 --- a/src/video_engine/vie_channel_manager.cc +++ b/src/video_engine/vie_channel_manager.cc @@ -97,13 +97,12 @@ int ViEChannelManager::CreateChannel(int& channel_id) { RtcpBandwidthObserver* bandwidth_observer = bitrate_controller->CreateRtcpBandwidthObserver(); - - RtpRemoteBitrateObserver* bitrate_observer = - group->GetRtpRemoteBitrateObserver(); + RemoteBitrateEstimator* remote_bitrate_estimator = + group->GetRemoteBitrateEstimator(); if (!(vie_encoder->Init() && CreateChannelObject(new_channel_id, vie_encoder, bandwidth_observer, - bitrate_observer))) { + remote_bitrate_estimator))) { delete vie_encoder; vie_encoder = NULL; ReturnChannelId(new_channel_id); @@ -136,9 +135,8 @@ int ViEChannelManager::CreateChannel(int& channel_id, RtcpBandwidthObserver* bandwidth_observer = bitrate_controller->CreateRtcpBandwidthObserver(); - - RtpRemoteBitrateObserver* bitrate_observer = - channel_group->GetRtpRemoteBitrateObserver(); + RemoteBitrateEstimator* remote_bitrate_estimator = + channel_group->GetRemoteBitrateEstimator(); ViEEncoder* vie_encoder = NULL; if (sender) { @@ -148,7 +146,8 @@ int ViEChannelManager::CreateChannel(int& channel_id, bitrate_controller); if (!(vie_encoder->Init() && CreateChannelObject(new_channel_id, vie_encoder, - bandwidth_observer, bitrate_observer))) { + bandwidth_observer, + remote_bitrate_estimator))) { delete vie_encoder; vie_encoder = NULL; } @@ -156,7 +155,7 @@ int ViEChannelManager::CreateChannel(int& channel_id, vie_encoder = ViEEncoderPtr(original_channel); assert(vie_encoder); if (!CreateChannelObject(new_channel_id, vie_encoder, bandwidth_observer, - bitrate_observer)) { + remote_bitrate_estimator)) { vie_encoder = NULL; } } @@ -202,7 +201,9 @@ int ViEChannelManager::DeleteChannel(int channel_id) { group = FindGroup(channel_id); group->SetChannelRembStatus(channel_id, false, false, vie_channel, vie_encoder); - group->RemoveChannel(channel_id); + unsigned int ssrc = 0; + vie_channel->GetRemoteSSRC(ssrc); + group->RemoveChannel(channel_id, ssrc); // Check if other channels are using the same encoder. if (ChannelUsingViEEncoder(channel_id)) { @@ -326,7 +327,7 @@ bool ViEChannelManager::CreateChannelObject( int channel_id, ViEEncoder* vie_encoder, RtcpBandwidthObserver* bandwidth_observer, - RtpRemoteBitrateObserver* bitrate_observer) { + RemoteBitrateEstimator* remote_bitrate_estimator) { // Register the channel at the encoder. RtpRtcp* send_rtp_rtcp_module = vie_encoder->SendRtpRtcpModule(); @@ -335,7 +336,7 @@ bool ViEChannelManager::CreateChannelObject( *module_process_thread_, vie_encoder, bandwidth_observer, - bitrate_observer, + remote_bitrate_estimator, send_rtp_rtcp_module); if (vie_channel->Init() != 0) { WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_), diff --git a/src/video_engine/vie_channel_manager.h b/src/video_engine/vie_channel_manager.h index a0c9382a59..e61e741317 100644 --- a/src/video_engine/vie_channel_manager.h +++ b/src/video_engine/vie_channel_manager.h @@ -78,7 +78,7 @@ class ViEChannelManager: private ViEManagerBase { // protected. bool CreateChannelObject(int channel_id, ViEEncoder* vie_encoder, RtcpBandwidthObserver* bandwidth_observer, - RtpRemoteBitrateObserver* bitrate_observer); + RemoteBitrateEstimator* remote_bitrate_estimator); // Used by ViEChannelScoped, forcing a manager user to use scoped. // Returns a pointer to the channel with id 'channelId'. diff --git a/src/video_engine/vie_remb.h b/src/video_engine/vie_remb.h index dfcdf2df1e..45921065ad 100644 --- a/src/video_engine/vie_remb.h +++ b/src/video_engine/vie_remb.h @@ -22,6 +22,7 @@ #include #include "modules/interface/module.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "system_wrappers/interface/scoped_ptr.h" @@ -31,7 +32,7 @@ class CriticalSectionWrapper; class ProcessThread; class RtpRtcp; -class VieRemb : public RtpRemoteBitrateObserver, public Module { +class VieRemb : public RemoteBitrateObserver, public Module { public: VieRemb(ProcessThread* process_thread); ~VieRemb();