| /* |
| * 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/bitrate_controller/bitrate_controller_impl.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" |
| #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/logging.h" |
| |
| namespace webrtc { |
| namespace { |
| absl::optional<DataRate> ToOptionalDataRate(int send_bitrate_bps) { |
| if (send_bitrate_bps > 0) |
| return DataRate::bps(send_bitrate_bps); |
| return absl::nullopt; |
| } |
| DataRate MaxRate(int max_bitrate_bps) { |
| if (max_bitrate_bps == -1) |
| return DataRate::Infinity(); |
| return DataRate::bps(max_bitrate_bps); |
| } |
| } // namespace |
| class BitrateControllerImpl::RtcpBandwidthObserverImpl |
| : public RtcpBandwidthObserver { |
| public: |
| explicit RtcpBandwidthObserverImpl(BitrateControllerImpl* owner) |
| : owner_(owner) {} |
| ~RtcpBandwidthObserverImpl() override = default; |
| // Received RTCP REMB or TMMBR. |
| void OnReceivedEstimatedBitrate(uint32_t bitrate) override { |
| owner_->OnReceivedEstimatedBitrate(bitrate); |
| } |
| // Received RTCP receiver block. |
| void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks, |
| int64_t rtt, |
| int64_t now_ms) override { |
| owner_->OnReceivedRtcpReceiverReport(report_blocks, rtt, now_ms); |
| } |
| |
| private: |
| BitrateControllerImpl* const owner_; |
| }; |
| |
| BitrateController* BitrateController::CreateBitrateController( |
| const Clock* clock, |
| BitrateObserver* observer, |
| RtcEventLog* event_log) { |
| return new BitrateControllerImpl(clock, observer, event_log); |
| } |
| |
| BitrateController* BitrateController::CreateBitrateController( |
| const Clock* clock, |
| RtcEventLog* event_log) { |
| return CreateBitrateController(clock, nullptr, event_log); |
| } |
| |
| BitrateControllerImpl::BitrateControllerImpl(const Clock* clock, |
| BitrateObserver* observer, |
| RtcEventLog* event_log) |
| : clock_(clock), |
| observer_(observer), |
| last_bitrate_update_ms_(clock_->TimeInMilliseconds()), |
| event_log_(event_log), |
| bandwidth_estimation_(event_log), |
| last_bitrate_bps_(0), |
| last_fraction_loss_(0), |
| last_rtt_ms_(0) { |
| // This calls the observer_ if set, which means that the observer provided by |
| // the user must be ready to accept a bitrate update when it constructs the |
| // controller. We do this to avoid having to keep synchronized initial values |
| // in both the controller and the allocator. |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| RtcpBandwidthObserver* BitrateControllerImpl::CreateRtcpBandwidthObserver() { |
| return new RtcpBandwidthObserverImpl(this); |
| } |
| |
| void BitrateControllerImpl::SetStartBitrate(int start_bitrate_bps) { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_.SetSendBitrate( |
| DataRate::bps(start_bitrate_bps), |
| Timestamp::ms(clock_->TimeInMilliseconds())); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::SetMinMaxBitrate(int min_bitrate_bps, |
| int max_bitrate_bps) { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_.SetMinMaxBitrate(DataRate::bps(min_bitrate_bps), |
| DataRate::bps(max_bitrate_bps)); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::SetBitrates(int start_bitrate_bps, |
| int min_bitrate_bps, |
| int max_bitrate_bps) { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_.SetBitrates( |
| ToOptionalDataRate(start_bitrate_bps), DataRate::bps(min_bitrate_bps), |
| MaxRate(max_bitrate_bps), Timestamp::ms(clock_->TimeInMilliseconds())); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::ResetBitrates(int bitrate_bps, |
| int min_bitrate_bps, |
| int max_bitrate_bps) { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_ = SendSideBandwidthEstimation(event_log_); |
| bandwidth_estimation_.SetBitrates( |
| ToOptionalDataRate(bitrate_bps), DataRate::bps(min_bitrate_bps), |
| MaxRate(max_bitrate_bps), Timestamp::ms(clock_->TimeInMilliseconds())); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| // This is called upon reception of REMB or TMMBR. |
| void BitrateControllerImpl::OnReceivedEstimatedBitrate(uint32_t bitrate) { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_.UpdateReceiverEstimate( |
| Timestamp::ms(clock_->TimeInMilliseconds()), DataRate::bps(bitrate)); |
| BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", clock_->TimeInMilliseconds(), |
| bitrate / 1000); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::OnDelayBasedBweResult( |
| const DelayBasedBwe::Result& result) { |
| if (!result.updated) |
| return; |
| { |
| rtc::CritScope cs(&critsect_); |
| if (result.probe) { |
| bandwidth_estimation_.SetSendBitrate( |
| DataRate::bps(result.target_bitrate_bps), |
| Timestamp::ms(clock_->TimeInMilliseconds())); |
| } |
| // Since SetSendBitrate now resets the delay-based estimate, we have to call |
| // UpdateDelayBasedEstimate after SetSendBitrate. |
| bandwidth_estimation_.UpdateDelayBasedEstimate( |
| Timestamp::ms(clock_->TimeInMilliseconds()), |
| DataRate::bps(result.target_bitrate_bps)); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| int64_t BitrateControllerImpl::TimeUntilNextProcess() { |
| const int64_t kBitrateControllerUpdateIntervalMs = 25; |
| rtc::CritScope 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); |
| } |
| |
| void BitrateControllerImpl::Process() { |
| { |
| rtc::CritScope cs(&critsect_); |
| bandwidth_estimation_.UpdateEstimate( |
| Timestamp::ms(clock_->TimeInMilliseconds())); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| last_bitrate_update_ms_ = clock_->TimeInMilliseconds(); |
| } |
| |
| void BitrateControllerImpl::OnReceivedRtcpReceiverReport( |
| const ReportBlockList& report_blocks, |
| int64_t rtt, |
| int64_t now_ms) { |
| if (report_blocks.empty()) |
| return; |
| |
| { |
| rtc::CritScope cs(&critsect_); |
| 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 (const RTCPReportBlock& report_block : report_blocks) { |
| std::map<uint32_t, uint32_t>::iterator seq_num_it = |
| ssrc_to_last_received_extended_high_seq_num_.find( |
| report_block.source_ssrc); |
| |
| int number_of_packets = 0; |
| if (seq_num_it != ssrc_to_last_received_extended_high_seq_num_.end()) { |
| number_of_packets = |
| report_block.extended_highest_sequence_number - seq_num_it->second; |
| } |
| |
| fraction_lost_aggregate += number_of_packets * report_block.fraction_lost; |
| total_number_of_packets += number_of_packets; |
| |
| // Update last received for this SSRC. |
| ssrc_to_last_received_extended_high_seq_num_[report_block.source_ssrc] = |
| report_block.extended_highest_sequence_number; |
| } |
| if (total_number_of_packets < 0) { |
| RTC_LOG(LS_WARNING) |
| << "Received report block where extended high sequence " |
| "number goes backwards, ignoring."; |
| return; |
| } |
| 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; |
| |
| RTC_DCHECK_GE(total_number_of_packets, 0); |
| |
| bandwidth_estimation_.UpdateReceiverBlock( |
| fraction_lost_aggregate, TimeDelta::ms(rtt), total_number_of_packets, |
| Timestamp::ms(now_ms)); |
| } |
| MaybeTriggerOnNetworkChanged(); |
| } |
| |
| void BitrateControllerImpl::MaybeTriggerOnNetworkChanged() { |
| if (!observer_) |
| return; |
| |
| uint32_t bitrate_bps; |
| uint8_t fraction_loss; |
| int64_t rtt; |
| |
| if (GetNetworkParameters(&bitrate_bps, &fraction_loss, &rtt)) |
| observer_->OnNetworkChanged(bitrate_bps, fraction_loss, rtt); |
| } |
| |
| bool BitrateControllerImpl::GetNetworkParameters(uint32_t* bitrate, |
| uint8_t* fraction_loss, |
| int64_t* rtt) { |
| rtc::CritScope cs(&critsect_); |
| int current_bitrate; |
| bandwidth_estimation_.CurrentEstimate(¤t_bitrate, fraction_loss, rtt); |
| *bitrate = current_bitrate; |
| *bitrate = |
| std::max<uint32_t>(*bitrate, bandwidth_estimation_.GetMinBitrate()); |
| |
| bool new_bitrate = false; |
| if (*bitrate != last_bitrate_bps_ || *fraction_loss != last_fraction_loss_ || |
| *rtt != last_rtt_ms_) { |
| last_bitrate_bps_ = *bitrate; |
| last_fraction_loss_ = *fraction_loss; |
| last_rtt_ms_ = *rtt; |
| new_bitrate = true; |
| } |
| |
| BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", clock_->TimeInMilliseconds(), |
| (last_fraction_loss_ * 100) / 256); |
| BWE_TEST_LOGGING_PLOT(1, "rtt_ms", clock_->TimeInMilliseconds(), |
| last_rtt_ms_); |
| BWE_TEST_LOGGING_PLOT(1, "Target_bitrate_kbps", clock_->TimeInMilliseconds(), |
| last_bitrate_bps_ / 1000); |
| |
| return new_bitrate; |
| } |
| |
| bool BitrateControllerImpl::AvailableBandwidth(uint32_t* bandwidth) const { |
| rtc::CritScope cs(&critsect_); |
| int bitrate; |
| uint8_t fraction_loss; |
| int64_t rtt; |
| bandwidth_estimation_.CurrentEstimate(&bitrate, &fraction_loss, &rtt); |
| if (bitrate > 0) { |
| bitrate = std::max(bitrate, bandwidth_estimation_.GetMinBitrate()); |
| *bandwidth = bitrate; |
| return true; |
| } |
| return false; |
| } |
| } // namespace webrtc |