| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| * |
| */ |
| |
| #include "webrtc/modules/bitrate_controller/bitrate_controller_impl.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" |
| |
| namespace webrtc { |
| |
| class BitrateControllerImpl::RtcpBandwidthObserverImpl |
| : public RtcpBandwidthObserver { |
| public: |
| explicit RtcpBandwidthObserverImpl(BitrateControllerImpl* owner) |
| : owner_(owner) { |
| } |
| virtual ~RtcpBandwidthObserverImpl() { |
| } |
| // Received RTCP REMB or TMMBR. |
| virtual void OnReceivedEstimatedBitrate(uint32_t bitrate) OVERRIDE { |
| owner_->OnReceivedEstimatedBitrate(bitrate); |
| } |
| // Received RTCP receiver block. |
| virtual void OnReceivedRtcpReceiverReport( |
| const ReportBlockList& report_blocks, |
| int64_t rtt, |
| int64_t now_ms) OVERRIDE { |
| if (report_blocks.empty()) |
| return; |
| |
| int fraction_lost_aggregate = 0; |
| int total_number_of_packets = 0; |
| |
| // Compute the a weighted average of the fraction loss from all report |
| // blocks. |
| for (ReportBlockList::const_iterator it = report_blocks.begin(); |
| it != report_blocks.end(); ++it) { |
| std::map<uint32_t, uint32_t>::iterator seq_num_it = |
| ssrc_to_last_received_extended_high_seq_num_.find(it->sourceSSRC); |
| |
| int number_of_packets = 0; |
| if (seq_num_it != ssrc_to_last_received_extended_high_seq_num_.end()) |
| number_of_packets = it->extendedHighSeqNum - |
| seq_num_it->second; |
| |
| fraction_lost_aggregate += number_of_packets * it->fractionLost; |
| total_number_of_packets += number_of_packets; |
| |
| // Update last received for this SSRC. |
| ssrc_to_last_received_extended_high_seq_num_[it->sourceSSRC] = |
| it->extendedHighSeqNum; |
| } |
| if (total_number_of_packets == 0) |
| fraction_lost_aggregate = 0; |
| else |
| fraction_lost_aggregate = (fraction_lost_aggregate + |
| total_number_of_packets / 2) / total_number_of_packets; |
| if (fraction_lost_aggregate > 255) |
| return; |
| |
| owner_->OnReceivedRtcpReceiverReport(fraction_lost_aggregate, rtt, |
| total_number_of_packets, now_ms); |
| } |
| |
| private: |
| std::map<uint32_t, uint32_t> ssrc_to_last_received_extended_high_seq_num_; |
| BitrateControllerImpl* owner_; |
| }; |
| |
| BitrateController* BitrateController::CreateBitrateController( |
| Clock* clock, |
| bool enforce_min_bitrate) { |
| return new BitrateControllerImpl(clock, enforce_min_bitrate); |
| } |
| |
| BitrateControllerImpl::BitrateControllerImpl(Clock* clock, |
| bool enforce_min_bitrate) |
| : clock_(clock), |
| last_bitrate_update_ms_(clock_->TimeInMilliseconds()), |
| critsect_(CriticalSectionWrapper::CreateCriticalSection()), |
| bandwidth_estimation_(), |
| bitrate_observers_(), |
| enforce_min_bitrate_(enforce_min_bitrate), |
| reserved_bitrate_bps_(0), |
| last_bitrate_bps_(0), |
| last_fraction_loss_(0), |
| last_rtt_ms_(0), |
| last_enforce_min_bitrate_(!enforce_min_bitrate_), |
| bitrate_observers_modified_(false), |
| last_reserved_bitrate_bps_(0), |
| remb_suppressor_(new RembSuppressor(clock)) { |
| } |
| |
| BitrateControllerImpl::~BitrateControllerImpl() { |
| BitrateObserverConfList::iterator it = bitrate_observers_.begin(); |
| while (it != bitrate_observers_.end()) { |
| delete it->second; |
| bitrate_observers_.erase(it); |
| it = bitrate_observers_.begin(); |
| } |
| delete critsect_; |
| } |
| |
| RtcpBandwidthObserver* BitrateControllerImpl::CreateRtcpBandwidthObserver() { |
| return new RtcpBandwidthObserverImpl(this); |
| } |
| |
| BitrateControllerImpl::BitrateObserverConfList::iterator |
| BitrateControllerImpl::FindObserverConfigurationPair(const BitrateObserver* |
| observer) { |
| BitrateObserverConfList::iterator it = bitrate_observers_.begin(); |
| for (; it != bitrate_observers_.end(); ++it) { |
| if (it->first == observer) { |
| return it; |
| } |
| } |
| return bitrate_observers_.end(); |
| } |
| |
| void BitrateControllerImpl::SetBitrateObserver( |
| BitrateObserver* observer, |
| uint32_t start_bitrate, |
| uint32_t min_bitrate, |
| uint32_t max_bitrate) { |
| CriticalSectionScoped cs(critsect_); |
| |
| BitrateObserverConfList::iterator it = FindObserverConfigurationPair( |
| observer); |
| |
| if (it != bitrate_observers_.end()) { |
| // Update current configuration. |
| it->second->start_bitrate_ = start_bitrate; |
| it->second->min_bitrate_ = min_bitrate; |
| it->second->max_bitrate_ = max_bitrate; |
| // Set the send-side bandwidth to the max of the sum of start bitrates and |
| // the current estimate, so that if the user wants to immediately use more |
| // bandwidth, that can be enforced. |
| uint32_t sum_start_bitrate = 0; |
| BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); |
| ++it) { |
| sum_start_bitrate += it->second->start_bitrate_; |
| } |
| uint32_t current_estimate; |
| uint8_t loss; |
| int64_t rtt; |
| bandwidth_estimation_.CurrentEstimate(¤t_estimate, &loss, &rtt); |
| bandwidth_estimation_.SetSendBitrate(std::max(sum_start_bitrate, |
| current_estimate)); |
| } else { |
| // Add new settings. |
| bitrate_observers_.push_back(BitrateObserverConfiguration(observer, |
| new BitrateConfiguration(start_bitrate, min_bitrate, max_bitrate))); |
| bitrate_observers_modified_ = true; |
| |
| // TODO(andresp): This is a ugly way to set start bitrate. |
| // |
| // Only change start bitrate if we have exactly one observer. By definition |
| // you can only have one start bitrate, once we have our first estimate we |
| // will adapt from there. |
| if (bitrate_observers_.size() == 1) { |
| bandwidth_estimation_.SetSendBitrate(start_bitrate); |
| } |
| } |
| |
| UpdateMinMaxBitrate(); |
| } |
| |
| void BitrateControllerImpl::UpdateMinMaxBitrate() { |
| uint32_t sum_min_bitrate = 0; |
| uint32_t sum_max_bitrate = 0; |
| BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) { |
| sum_min_bitrate += it->second->min_bitrate_; |
| sum_max_bitrate += it->second->max_bitrate_; |
| } |
| if (sum_max_bitrate == 0) { |
| // No max configured use 1Gbit/s. |
| sum_max_bitrate = 1000000000; |
| } |
| if (enforce_min_bitrate_ == false) { |
| // If not enforcing min bitrate, allow the bandwidth estimation to |
| // go as low as 10 kbps. |
| sum_min_bitrate = std::min(sum_min_bitrate, 10000u); |
| } |
| bandwidth_estimation_.SetMinMaxBitrate(sum_min_bitrate, |
| sum_max_bitrate); |
| } |
| |
| void BitrateControllerImpl::RemoveBitrateObserver(BitrateObserver* observer) { |
| CriticalSectionScoped cs(critsect_); |
| BitrateObserverConfList::iterator it = FindObserverConfigurationPair( |
| observer); |
| if (it != bitrate_observers_.end()) { |
| delete it->second; |
| bitrate_observers_.erase(it); |
| bitrate_observers_modified_ = true; |
| } |
| } |
| |
| void BitrateControllerImpl::EnforceMinBitrate(bool enforce_min_bitrate) { |
| CriticalSectionScoped cs(critsect_); |
| enforce_min_bitrate_ = enforce_min_bitrate; |
| UpdateMinMaxBitrate(); |
| } |
| |
| void BitrateControllerImpl::SetReservedBitrate(uint32_t reserved_bitrate_bps) { |
| CriticalSectionScoped cs(critsect_); |
| reserved_bitrate_bps_ = reserved_bitrate_bps; |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::OnReceivedEstimatedBitrate(uint32_t bitrate) { |
| CriticalSectionScoped cs(critsect_); |
| if (remb_suppressor_->SuppresNewRemb(bitrate)) { |
| return; |
| } |
| bandwidth_estimation_.UpdateReceiverEstimate(bitrate); |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| int64_t BitrateControllerImpl::TimeUntilNextProcess() { |
| const int64_t kBitrateControllerUpdateIntervalMs = 25; |
| CriticalSectionScoped cs(critsect_); |
| int64_t time_since_update_ms = |
| clock_->TimeInMilliseconds() - last_bitrate_update_ms_; |
| return std::max<int64_t>( |
| kBitrateControllerUpdateIntervalMs - time_since_update_ms, 0); |
| } |
| |
| int32_t BitrateControllerImpl::Process() { |
| if (TimeUntilNextProcess() > 0) |
| return 0; |
| { |
| CriticalSectionScoped cs(critsect_); |
| bandwidth_estimation_.UpdateEstimate(clock_->TimeInMilliseconds()); |
| MaybeTriggerOnNetworkChanged(); |
| } |
| last_bitrate_update_ms_ = clock_->TimeInMilliseconds(); |
| return 0; |
| } |
| |
| void BitrateControllerImpl::OnReceivedRtcpReceiverReport( |
| uint8_t fraction_loss, |
| int64_t rtt, |
| int number_of_packets, |
| int64_t now_ms) { |
| CriticalSectionScoped cs(critsect_); |
| bandwidth_estimation_.UpdateReceiverBlock( |
| fraction_loss, rtt, number_of_packets, now_ms); |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::MaybeTriggerOnNetworkChanged() { |
| uint32_t bitrate; |
| uint8_t fraction_loss; |
| int64_t rtt; |
| bandwidth_estimation_.CurrentEstimate(&bitrate, &fraction_loss, &rtt); |
| bitrate -= std::min(bitrate, reserved_bitrate_bps_); |
| |
| if (bitrate_observers_modified_ || |
| bitrate != last_bitrate_bps_ || |
| fraction_loss != last_fraction_loss_ || |
| rtt != last_rtt_ms_ || |
| last_enforce_min_bitrate_ != enforce_min_bitrate_ || |
| last_reserved_bitrate_bps_ != reserved_bitrate_bps_) { |
| last_bitrate_bps_ = bitrate; |
| last_fraction_loss_ = fraction_loss; |
| last_rtt_ms_ = rtt; |
| last_enforce_min_bitrate_ = enforce_min_bitrate_; |
| last_reserved_bitrate_bps_ = reserved_bitrate_bps_; |
| bitrate_observers_modified_ = false; |
| OnNetworkChanged(bitrate, fraction_loss, rtt); |
| } |
| } |
| |
| void BitrateControllerImpl::OnNetworkChanged(uint32_t bitrate, |
| uint8_t fraction_loss, |
| int64_t rtt) { |
| // Sanity check. |
| if (bitrate_observers_.empty()) |
| return; |
| |
| uint32_t sum_min_bitrates = 0; |
| BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) { |
| sum_min_bitrates += it->second->min_bitrate_; |
| } |
| if (bitrate <= sum_min_bitrates) |
| return LowRateAllocation(bitrate, fraction_loss, rtt, sum_min_bitrates); |
| else |
| return NormalRateAllocation(bitrate, fraction_loss, rtt, sum_min_bitrates); |
| } |
| |
| void BitrateControllerImpl::NormalRateAllocation(uint32_t bitrate, |
| uint8_t fraction_loss, |
| int64_t rtt, |
| uint32_t sum_min_bitrates) { |
| uint32_t number_of_observers = bitrate_observers_.size(); |
| uint32_t bitrate_per_observer = (bitrate - sum_min_bitrates) / |
| number_of_observers; |
| // Use map to sort list based on max bitrate. |
| ObserverSortingMap list_max_bitrates; |
| BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) { |
| list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration*>( |
| it->second->max_bitrate_, |
| new ObserverConfiguration(it->first, it->second->min_bitrate_))); |
| } |
| ObserverSortingMap::iterator max_it = list_max_bitrates.begin(); |
| while (max_it != list_max_bitrates.end()) { |
| number_of_observers--; |
| uint32_t observer_allowance = max_it->second->min_bitrate_ + |
| bitrate_per_observer; |
| if (max_it->first < observer_allowance) { |
| // We have more than enough for this observer. |
| // Carry the remainder forward. |
| uint32_t remainder = observer_allowance - max_it->first; |
| if (number_of_observers != 0) { |
| bitrate_per_observer += remainder / number_of_observers; |
| } |
| max_it->second->observer_->OnNetworkChanged(max_it->first, fraction_loss, |
| rtt); |
| } else { |
| max_it->second->observer_->OnNetworkChanged(observer_allowance, |
| fraction_loss, rtt); |
| } |
| delete max_it->second; |
| list_max_bitrates.erase(max_it); |
| // Prepare next iteration. |
| max_it = list_max_bitrates.begin(); |
| } |
| } |
| |
| void BitrateControllerImpl::LowRateAllocation(uint32_t bitrate, |
| uint8_t fraction_loss, |
| int64_t rtt, |
| uint32_t sum_min_bitrates) { |
| if (enforce_min_bitrate_) { |
| // Min bitrate to all observers. |
| BitrateControllerImpl::BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); |
| ++it) { |
| it->first->OnNetworkChanged(it->second->min_bitrate_, fraction_loss, rtt); |
| } |
| // Set sum of min to current send bitrate. |
| bandwidth_estimation_.SetSendBitrate(sum_min_bitrates); |
| } else { |
| // Allocate up to |min_bitrate_| to one observer at a time, until |
| // |bitrate| is depleted. |
| uint32_t remainder = bitrate; |
| BitrateControllerImpl::BitrateObserverConfList::iterator it; |
| for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); |
| ++it) { |
| uint32_t allocation = std::min(remainder, it->second->min_bitrate_); |
| it->first->OnNetworkChanged(allocation, fraction_loss, rtt); |
| remainder -= allocation; |
| } |
| // Set |bitrate| to current send bitrate. |
| bandwidth_estimation_.SetSendBitrate(bitrate); |
| } |
| } |
| |
| bool BitrateControllerImpl::AvailableBandwidth(uint32_t* bandwidth) const { |
| CriticalSectionScoped cs(critsect_); |
| uint32_t bitrate; |
| uint8_t fraction_loss; |
| int64_t rtt; |
| bandwidth_estimation_.CurrentEstimate(&bitrate, &fraction_loss, &rtt); |
| if (bitrate) { |
| *bandwidth = bitrate - std::min(bitrate, reserved_bitrate_bps_); |
| return true; |
| } |
| return false; |
| } |
| |
| void BitrateControllerImpl::SetBitrateSent(uint32_t bitrate_sent_bps) { |
| CriticalSectionScoped cs(critsect_); |
| remb_suppressor_->SetBitrateSent(bitrate_sent_bps); |
| } |
| |
| void BitrateControllerImpl::SetCodecMode(webrtc::VideoCodecMode mode) { |
| CriticalSectionScoped cs(critsect_); |
| remb_suppressor_->SetEnabled(mode == kScreensharing); |
| } |
| |
| } // namespace webrtc |