blob: fcf19590f6bc53b03e69c328efbdb964d4b8318e [file] [log] [blame]
/*
* Copyright (c) 2016 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/audio_coding/audio_network_adaptor/fec_controller.h"
#include <limits>
#include <utility>
#include "webrtc/base/checks.h"
namespace webrtc {
FecController::Config::Threshold::Threshold(int low_bandwidth_bps,
float low_bandwidth_packet_loss,
int high_bandwidth_bps,
float high_bandwidth_packet_loss)
: low_bandwidth_bps(low_bandwidth_bps),
low_bandwidth_packet_loss(low_bandwidth_packet_loss),
high_bandwidth_bps(high_bandwidth_bps),
high_bandwidth_packet_loss(high_bandwidth_packet_loss) {}
FecController::Config::Config(bool initial_fec_enabled,
const Threshold& fec_enabling_threshold,
const Threshold& fec_disabling_threshold,
int time_constant_ms,
Clock* clock)
: initial_fec_enabled(initial_fec_enabled),
fec_enabling_threshold(fec_enabling_threshold),
fec_disabling_threshold(fec_disabling_threshold),
time_constant_ms(time_constant_ms),
clock(clock) {}
FecController::FecController(const Config& config)
: config_(config),
fec_enabled_(config.initial_fec_enabled),
packet_loss_smoothed_(
new SmoothingFilterImpl(config_.time_constant_ms, config_.clock)),
fec_enabling_threshold_info_(config_.fec_enabling_threshold),
fec_disabling_threshold_info_(config_.fec_disabling_threshold) {
RTC_DCHECK_LE(fec_enabling_threshold_info_.slope, 0);
RTC_DCHECK_LE(fec_enabling_threshold_info_.slope, 0);
RTC_DCHECK_LE(
GetPacketLossThreshold(config_.fec_enabling_threshold.low_bandwidth_bps,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_),
config_.fec_enabling_threshold.low_bandwidth_packet_loss);
RTC_DCHECK_LE(
GetPacketLossThreshold(config_.fec_enabling_threshold.high_bandwidth_bps,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_),
config_.fec_enabling_threshold.high_bandwidth_packet_loss);
}
FecController::FecController(const Config& config,
std::unique_ptr<SmoothingFilter> smoothing_filter)
: FecController(config) {
packet_loss_smoothed_ = std::move(smoothing_filter);
}
FecController::~FecController() = default;
void FecController::MakeDecision(
const NetworkMetrics& metrics,
AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
RTC_DCHECK(!config->enable_fec);
RTC_DCHECK(!config->uplink_packet_loss_fraction);
if (metrics.uplink_packet_loss_fraction)
packet_loss_smoothed_->AddSample(*metrics.uplink_packet_loss_fraction);
fec_enabled_ = fec_enabled_ ? !FecDisablingDecision(metrics)
: FecEnablingDecision(metrics);
config->enable_fec = rtc::Optional<bool>(fec_enabled_);
auto packet_loss_fraction = packet_loss_smoothed_->GetAverage();
config->uplink_packet_loss_fraction = rtc::Optional<float>(
packet_loss_fraction ? *packet_loss_fraction : 0.0);
}
FecController::ThresholdInfo::ThresholdInfo(
const Config::Threshold& threshold) {
int bandwidth_diff_bps =
threshold.high_bandwidth_bps - threshold.low_bandwidth_bps;
float packet_loss_diff = threshold.high_bandwidth_packet_loss -
threshold.low_bandwidth_packet_loss;
slope = bandwidth_diff_bps == 0 ? 0.0 : packet_loss_diff / bandwidth_diff_bps;
offset =
threshold.low_bandwidth_packet_loss - slope * threshold.low_bandwidth_bps;
}
float FecController::GetPacketLossThreshold(
int bandwidth_bps,
const Config::Threshold& threshold,
const ThresholdInfo& threshold_info) const {
if (bandwidth_bps < threshold.low_bandwidth_bps)
return std::numeric_limits<float>::max();
if (bandwidth_bps >= threshold.high_bandwidth_bps)
return threshold.high_bandwidth_packet_loss;
return threshold_info.offset + threshold_info.slope * bandwidth_bps;
}
bool FecController::FecEnablingDecision(const NetworkMetrics& metrics) const {
if (!metrics.uplink_bandwidth_bps)
return false;
auto packet_loss = packet_loss_smoothed_->GetAverage();
if (!packet_loss)
return false;
return *packet_loss >= GetPacketLossThreshold(*metrics.uplink_bandwidth_bps,
config_.fec_enabling_threshold,
fec_enabling_threshold_info_);
}
bool FecController::FecDisablingDecision(const NetworkMetrics& metrics) const {
if (!metrics.uplink_bandwidth_bps)
return false;
auto packet_loss = packet_loss_smoothed_->GetAverage();
if (!packet_loss)
return false;
return *packet_loss <= GetPacketLossThreshold(*metrics.uplink_bandwidth_bps,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_);
}
} // namespace webrtc