blob: c47434f9aa85046e79fda3b4f67064615280c3d9 [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 "modules/audio_coding/audio_network_adaptor/frame_length_controller.h"
#include <algorithm>
#include <iterator>
#include <utility>
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
constexpr int kPreventOveruseMarginBps = 5000;
int OverheadRateBps(size_t overhead_bytes_per_packet, int frame_length_ms) {
return static_cast<int>(overhead_bytes_per_packet * 8 * 1000 /
frame_length_ms);
}
} // namespace
FrameLengthController::Config::Config(
const std::set<int>& encoder_frame_lengths_ms,
int initial_frame_length_ms,
int min_encoder_bitrate_bps,
float fl_increasing_packet_loss_fraction,
float fl_decreasing_packet_loss_fraction,
int fl_increase_overhead_offset,
int fl_decrease_overhead_offset,
std::map<FrameLengthChange, int> fl_changing_bandwidths_bps)
: encoder_frame_lengths_ms(encoder_frame_lengths_ms),
initial_frame_length_ms(initial_frame_length_ms),
min_encoder_bitrate_bps(min_encoder_bitrate_bps),
fl_increasing_packet_loss_fraction(fl_increasing_packet_loss_fraction),
fl_decreasing_packet_loss_fraction(fl_decreasing_packet_loss_fraction),
fl_increase_overhead_offset(fl_increase_overhead_offset),
fl_decrease_overhead_offset(fl_decrease_overhead_offset),
fl_changing_bandwidths_bps(std::move(fl_changing_bandwidths_bps)) {}
FrameLengthController::Config::Config(const Config& other) = default;
FrameLengthController::Config::~Config() = default;
FrameLengthController::FrameLengthController(const Config& config)
: config_(config) {
frame_length_ms_ = std::find(config_.encoder_frame_lengths_ms.begin(),
config_.encoder_frame_lengths_ms.end(),
config_.initial_frame_length_ms);
// `encoder_frame_lengths_ms` must contain `initial_frame_length_ms`.
RTC_DCHECK(frame_length_ms_ != config_.encoder_frame_lengths_ms.end());
}
FrameLengthController::~FrameLengthController() = default;
void FrameLengthController::UpdateNetworkMetrics(
const NetworkMetrics& network_metrics) {
if (network_metrics.uplink_bandwidth_bps)
uplink_bandwidth_bps_ = network_metrics.uplink_bandwidth_bps;
if (network_metrics.uplink_packet_loss_fraction)
uplink_packet_loss_fraction_ = network_metrics.uplink_packet_loss_fraction;
if (network_metrics.overhead_bytes_per_packet)
overhead_bytes_per_packet_ = network_metrics.overhead_bytes_per_packet;
}
void FrameLengthController::MakeDecision(AudioEncoderRuntimeConfig* config) {
// Decision on `frame_length_ms` should not have been made.
RTC_DCHECK(!config->frame_length_ms);
if (FrameLengthIncreasingDecision(*config)) {
prev_decision_increase_ = true;
} else if (FrameLengthDecreasingDecision(*config)) {
prev_decision_increase_ = false;
}
config->last_fl_change_increase = prev_decision_increase_;
config->frame_length_ms = *frame_length_ms_;
}
FrameLengthController::Config::FrameLengthChange::FrameLengthChange(
int from_frame_length_ms,
int to_frame_length_ms)
: from_frame_length_ms(from_frame_length_ms),
to_frame_length_ms(to_frame_length_ms) {}
bool FrameLengthController::Config::FrameLengthChange::operator<(
const FrameLengthChange& rhs) const {
return from_frame_length_ms < rhs.from_frame_length_ms ||
(from_frame_length_ms == rhs.from_frame_length_ms &&
to_frame_length_ms < rhs.to_frame_length_ms);
}
bool FrameLengthController::FrameLengthIncreasingDecision(
const AudioEncoderRuntimeConfig& config) {
// Increase frame length if
// 1. `uplink_bandwidth_bps` is known to be smaller or equal than
// `min_encoder_bitrate_bps` plus `prevent_overuse_margin_bps` plus the
// current overhead rate OR all the following:
// 2. longer frame length is available AND
// 3. `uplink_bandwidth_bps` is known to be smaller than a threshold AND
// 4. `uplink_packet_loss_fraction` is known to be smaller than a threshold.
// Find next frame length to which a criterion is defined to shift from
// current frame length.
auto longer_frame_length_ms = std::next(frame_length_ms_);
auto increase_threshold = config_.fl_changing_bandwidths_bps.end();
while (longer_frame_length_ms != config_.encoder_frame_lengths_ms.end()) {
increase_threshold = config_.fl_changing_bandwidths_bps.find(
Config::FrameLengthChange(*frame_length_ms_, *longer_frame_length_ms));
if (increase_threshold != config_.fl_changing_bandwidths_bps.end())
break;
longer_frame_length_ms = std::next(longer_frame_length_ms);
}
if (increase_threshold == config_.fl_changing_bandwidths_bps.end())
return false;
// Check that
// -(*overhead_bytes_per_packet_) <= offset <= (*overhead_bytes_per_packet_)
RTC_DCHECK(
!overhead_bytes_per_packet_ ||
(overhead_bytes_per_packet_ &&
static_cast<size_t>(std::max(0, -config_.fl_increase_overhead_offset)) <=
*overhead_bytes_per_packet_ &&
static_cast<size_t>(std::max(0, config_.fl_increase_overhead_offset)) <=
*overhead_bytes_per_packet_));
if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
*uplink_bandwidth_bps_ <=
config_.min_encoder_bitrate_bps + kPreventOveruseMarginBps +
OverheadRateBps(*overhead_bytes_per_packet_ +
config_.fl_increase_overhead_offset,
*frame_length_ms_)) {
frame_length_ms_ = longer_frame_length_ms;
return true;
}
if ((uplink_bandwidth_bps_ &&
*uplink_bandwidth_bps_ <= increase_threshold->second) &&
(uplink_packet_loss_fraction_ &&
*uplink_packet_loss_fraction_ <=
config_.fl_increasing_packet_loss_fraction)) {
frame_length_ms_ = longer_frame_length_ms;
return true;
}
return false;
}
bool FrameLengthController::FrameLengthDecreasingDecision(
const AudioEncoderRuntimeConfig& config) {
// Decrease frame length if
// 1. shorter frame length is available AND
// 2. `uplink_bandwidth_bps` is known to be bigger than
// `min_encoder_bitrate_bps` plus `prevent_overuse_margin_bps` plus the
// overhead which would be produced with the shorter frame length AND
// one or more of the followings:
// 3. `uplink_bandwidth_bps` is known to be larger than a threshold,
// 4. `uplink_packet_loss_fraction` is known to be larger than a threshold,
// Find next frame length to which a criterion is defined to shift from
// current frame length.
auto shorter_frame_length_ms = frame_length_ms_;
auto decrease_threshold = config_.fl_changing_bandwidths_bps.end();
while (shorter_frame_length_ms != config_.encoder_frame_lengths_ms.begin()) {
shorter_frame_length_ms = std::prev(shorter_frame_length_ms);
decrease_threshold = config_.fl_changing_bandwidths_bps.find(
Config::FrameLengthChange(*frame_length_ms_, *shorter_frame_length_ms));
if (decrease_threshold != config_.fl_changing_bandwidths_bps.end())
break;
}
if (decrease_threshold == config_.fl_changing_bandwidths_bps.end())
return false;
if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
*uplink_bandwidth_bps_ <=
config_.min_encoder_bitrate_bps + kPreventOveruseMarginBps +
OverheadRateBps(*overhead_bytes_per_packet_ +
config_.fl_decrease_overhead_offset,
*shorter_frame_length_ms)) {
return false;
}
if ((uplink_bandwidth_bps_ &&
*uplink_bandwidth_bps_ >= decrease_threshold->second) ||
(uplink_packet_loss_fraction_ &&
*uplink_packet_loss_fraction_ >=
config_.fl_decreasing_packet_loss_fraction)) {
frame_length_ms_ = shorter_frame_length_ms;
return true;
}
return false;
}
} // namespace webrtc