blob: 4dd60888295316fa1eba57128695dbd4ba6fbeff [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/frame_length_controller.h"
#include <utility>
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/logging.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);
}
}
FrameLengthController::Config::Config(
const std::vector<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,
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_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)) {
++frame_length_ms_;
} else if (FrameLengthDecreasingDecision(*config)) {
--frame_length_ms_;
}
config->frame_length_ms = rtc::Optional<int>(*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) const {
// 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.
auto longer_frame_length_ms = std::next(frame_length_ms_);
if (longer_frame_length_ms == config_.encoder_frame_lengths_ms.end())
return false;
auto 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())
return false;
if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
*uplink_bandwidth_bps_ <=
config_.min_encoder_bitrate_bps + kPreventOveruseMarginBps +
OverheadRateBps(*overhead_bytes_per_packet_, *frame_length_ms_)) {
return true;
}
return (uplink_bandwidth_bps_ &&
*uplink_bandwidth_bps_ <= increase_threshold->second) &&
(uplink_packet_loss_fraction_ &&
*uplink_packet_loss_fraction_ <=
config_.fl_increasing_packet_loss_fraction);
}
bool FrameLengthController::FrameLengthDecreasingDecision(
const AudioEncoderRuntimeConfig& config) const {
// 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,
if (frame_length_ms_ == config_.encoder_frame_lengths_ms.begin())
return false;
auto shorter_frame_length_ms = std::prev(frame_length_ms_);
auto 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())
return false;
if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
*uplink_bandwidth_bps_ <= config_.min_encoder_bitrate_bps +
kPreventOveruseMarginBps +
OverheadRateBps(*overhead_bytes_per_packet_,
*shorter_frame_length_ms)) {
return false;
}
return (uplink_bandwidth_bps_ &&
*uplink_bandwidth_bps_ >= decrease_threshold->second) ||
(uplink_packet_loss_fraction_ &&
*uplink_packet_loss_fraction_ >=
config_.fl_decreasing_packet_loss_fraction);
}
} // namespace webrtc