| Index: webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
|
| diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc b/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ff271d58b62315decac9b538eb1fc2e9112daab4
|
| --- /dev/null
|
| +++ b/webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
|
| @@ -0,0 +1,179 @@
|
| +/*
|
| + * 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 <iterator>
|
| +#include <utility>
|
| +
|
| +#include "webrtc/base/checks.h"
|
| +#include "webrtc/base/logging.h"
|
| +
|
| +namespace webrtc {
|
| +
|
| +FrameLengthController::Config::Config(
|
| + const std::vector<int>& encoder_frame_lengths_ms,
|
| + int initial_frame_length_ms,
|
| + float fl_increasing_packet_loss_fraction,
|
| + float fl_decreasing_packet_loss_fraction,
|
| + int fl_20ms_to_60ms_bandwidth_bps,
|
| + int fl_60ms_to_20ms_bandwidth_bps)
|
| + : encoder_frame_lengths_ms(encoder_frame_lengths_ms),
|
| + initial_frame_length_ms(initial_frame_length_ms),
|
| + fl_increasing_packet_loss_fraction(fl_increasing_packet_loss_fraction),
|
| + fl_decreasing_packet_loss_fraction(fl_decreasing_packet_loss_fraction),
|
| + fl_20ms_to_60ms_bandwidth_bps(fl_20ms_to_60ms_bandwidth_bps),
|
| + fl_60ms_to_20ms_bandwidth_bps(fl_60ms_to_20ms_bandwidth_bps) {}
|
| +
|
| +FrameLengthController::Config::Config(const Config& other) = default;
|
| +
|
| +FrameLengthController::Config::~Config() = default;
|
| +
|
| +FrameLengthController::FrameLengthController(const Config& config)
|
| + : config_(config) {
|
| + // |encoder_frame_lengths_ms| must contain |initial_frame_length_ms|.
|
| + RTC_DCHECK(config_.encoder_frame_lengths_ms.end() !=
|
| + std::find(config_.encoder_frame_lengths_ms.begin(),
|
| + config_.encoder_frame_lengths_ms.end(),
|
| + config_.initial_frame_length_ms));
|
| +
|
| + // We start with assuming that the receiver only accepts
|
| + // |config_.initial_frame_length_ms|.
|
| + run_time_frame_lengths_ms_.push_back(config_.initial_frame_length_ms);
|
| + frame_length_ms_ = run_time_frame_lengths_ms_.begin();
|
| +
|
| + frame_length_change_criteria_.insert(std::make_pair(
|
| + FrameLengthChange(20, 60), config_.fl_20ms_to_60ms_bandwidth_bps));
|
| + frame_length_change_criteria_.insert(std::make_pair(
|
| + FrameLengthChange(60, 20), config_.fl_60ms_to_20ms_bandwidth_bps));
|
| +}
|
| +
|
| +FrameLengthController::~FrameLengthController() = default;
|
| +
|
| +void FrameLengthController::MakeDecision(
|
| + const NetworkMetrics& metrics,
|
| + AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
|
| + // Decision on |frame_length_ms| should not have been made.
|
| + RTC_DCHECK(!config->frame_length_ms);
|
| +
|
| + if (FrameLengthIncreasingDecision(metrics, *config)) {
|
| + ++frame_length_ms_;
|
| + } else if (FrameLengthDecreasingDecision(metrics, *config)) {
|
| + --frame_length_ms_;
|
| + }
|
| + config->frame_length_ms = rtc::Optional<int>(*frame_length_ms_);
|
| +}
|
| +
|
| +void FrameLengthController::SetConstraints(const Constraints& constraints) {
|
| + if (constraints.receiver_frame_length_range) {
|
| + SetReceiverFrameLengthRange(
|
| + constraints.receiver_frame_length_range->min_frame_length_ms,
|
| + constraints.receiver_frame_length_range->max_frame_length_ms);
|
| + }
|
| +}
|
| +
|
| +FrameLengthController::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) {}
|
| +
|
| +FrameLengthController::FrameLengthChange::~FrameLengthChange() = default;
|
| +
|
| +bool FrameLengthController::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);
|
| +}
|
| +
|
| +void FrameLengthController::SetReceiverFrameLengthRange(
|
| + int min_frame_length_ms,
|
| + int max_frame_length_ms) {
|
| + int frame_length_ms = *frame_length_ms_;
|
| + // Reset |run_time_frame_lengths_ms_| by filtering |config_.frame_lengths_ms|
|
| + // with the receiver frame length range.
|
| + run_time_frame_lengths_ms_.clear();
|
| + std::copy_if(config_.encoder_frame_lengths_ms.begin(),
|
| + config_.encoder_frame_lengths_ms.end(),
|
| + std::back_inserter(run_time_frame_lengths_ms_),
|
| + [&](int frame_length_ms) {
|
| + return frame_length_ms >= min_frame_length_ms &&
|
| + frame_length_ms <= max_frame_length_ms;
|
| + });
|
| + RTC_DCHECK(std::is_sorted(run_time_frame_lengths_ms_.begin(),
|
| + run_time_frame_lengths_ms_.end()));
|
| +
|
| + // Keep the current frame length. If it has gone out of the new range, use
|
| + // the smallest available frame length.
|
| + frame_length_ms_ =
|
| + std::find(run_time_frame_lengths_ms_.begin(),
|
| + run_time_frame_lengths_ms_.end(), frame_length_ms);
|
| + if (frame_length_ms_ == run_time_frame_lengths_ms_.end()) {
|
| + LOG(LS_WARNING)
|
| + << "Actual frame length not in frame length range of the receiver";
|
| + frame_length_ms_ = run_time_frame_lengths_ms_.begin();
|
| + }
|
| +}
|
| +
|
| +bool FrameLengthController::FrameLengthIncreasingDecision(
|
| + const NetworkMetrics& metrics,
|
| + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) const {
|
| + // Increase frame length if
|
| + // 1. longer frame length is available AND
|
| + // 2. |uplink_bandwidth_bps| is known to be smaller than a threshold AND
|
| + // 3. |uplink_packet_loss_fraction| is known to be smaller than a threshold
|
| + // AND
|
| + // 4. FEC is not decided or is OFF.
|
| + auto longer_frame_length_ms = std::next(frame_length_ms_);
|
| + if (longer_frame_length_ms == run_time_frame_lengths_ms_.end())
|
| + return false;
|
| +
|
| + auto increase_threshold = frame_length_change_criteria_.find(
|
| + FrameLengthChange(*frame_length_ms_, *longer_frame_length_ms));
|
| +
|
| + if (increase_threshold == frame_length_change_criteria_.end())
|
| + return false;
|
| +
|
| + return (metrics.uplink_bandwidth_bps &&
|
| + *metrics.uplink_bandwidth_bps <= increase_threshold->second) &&
|
| + (metrics.uplink_packet_loss_fraction &&
|
| + *metrics.uplink_packet_loss_fraction <=
|
| + config_.fl_increasing_packet_loss_fraction) &&
|
| + !config.enable_fec.value_or(false);
|
| +}
|
| +
|
| +bool FrameLengthController::FrameLengthDecreasingDecision(
|
| + const NetworkMetrics& metrics,
|
| + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) const {
|
| + // Decrease frame length if
|
| + // 1. shorter frame length is available AND one or more of the followings:
|
| + // 2. |uplink_bandwidth_bps| is known to be larger than a threshold,
|
| + // 3. |uplink_packet_loss_fraction| is known to be larger than a threshold,
|
| + // 4. FEC is decided ON.
|
| + if (frame_length_ms_ == run_time_frame_lengths_ms_.begin())
|
| + return false;
|
| +
|
| + auto shorter_frame_length_ms = std::prev(frame_length_ms_);
|
| + auto decrease_threshold = frame_length_change_criteria_.find(
|
| + FrameLengthChange(*frame_length_ms_, *shorter_frame_length_ms));
|
| +
|
| + if (decrease_threshold == frame_length_change_criteria_.end())
|
| + return false;
|
| +
|
| + return (metrics.uplink_bandwidth_bps &&
|
| + *metrics.uplink_bandwidth_bps >= decrease_threshold->second) ||
|
| + (metrics.uplink_packet_loss_fraction &&
|
| + *metrics.uplink_packet_loss_fraction >=
|
| + config_.fl_decreasing_packet_loss_fraction) ||
|
| + config.enable_fec.value_or(false);
|
| +}
|
| +
|
| +} // namespace webrtc
|
|
|