blob: 23123934dc378152a2489cf743b8e7b45e056ea7 [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 <memory>
#include <utility>
#include "test/gtest.h"
namespace webrtc {
namespace {
constexpr float kFlIncreasingPacketLossFraction = 0.04f;
constexpr float kFlDecreasingPacketLossFraction = 0.05f;
constexpr int kFlIncreaseOverheadOffset = 0;
constexpr int kFlDecreaseOverheadOffset = 0;
constexpr int kMinEncoderBitrateBps = 6000;
constexpr int kPreventOveruseMarginBps = 5000;
constexpr size_t kOverheadBytesPerPacket = 20;
constexpr int kFl20msTo60msBandwidthBps = 40000;
constexpr int kFl60msTo20msBandwidthBps = 50000;
constexpr int kFl60msTo120msBandwidthBps = 30000;
constexpr int kFl120msTo60msBandwidthBps = 40000;
constexpr int kFl20msTo40msBandwidthBps = 45000;
constexpr int kFl40msTo20msBandwidthBps = 50000;
constexpr int kFl40msTo60msBandwidthBps = 40000;
constexpr int kFl60msTo40msBandwidthBps = 45000;
constexpr int kMediumBandwidthBps =
(kFl40msTo20msBandwidthBps + kFl20msTo40msBandwidthBps) / 2;
constexpr float kMediumPacketLossFraction =
(kFlDecreasingPacketLossFraction + kFlIncreasingPacketLossFraction) / 2;
const std::set<int> kDefaultEncoderFrameLengthsMs = {20, 40, 60, 120};
int VeryLowBitrate(int frame_length_ms) {
return kMinEncoderBitrateBps + kPreventOveruseMarginBps +
(kOverheadBytesPerPacket * 8 * 1000 / frame_length_ms);
}
std::unique_ptr<FrameLengthController> CreateController(
const std::map<FrameLengthController::Config::FrameLengthChange, int>&
frame_length_change_criteria,
const std::set<int>& encoder_frame_lengths_ms,
int initial_frame_length_ms) {
std::unique_ptr<FrameLengthController> controller(
new FrameLengthController(FrameLengthController::Config(
encoder_frame_lengths_ms, initial_frame_length_ms,
kMinEncoderBitrateBps, kFlIncreasingPacketLossFraction,
kFlDecreasingPacketLossFraction, kFlIncreaseOverheadOffset,
kFlDecreaseOverheadOffset, frame_length_change_criteria)));
return controller;
}
std::map<FrameLengthController::Config::FrameLengthChange, int>
CreateChangeCriteriaFor20msAnd60ms() {
return std::map<FrameLengthController::Config::FrameLengthChange, int>{
{FrameLengthController::Config::FrameLengthChange(20, 60),
kFl20msTo60msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 20),
kFl60msTo20msBandwidthBps}};
}
std::map<FrameLengthController::Config::FrameLengthChange, int>
CreateChangeCriteriaFor20msAnd40ms() {
return std::map<FrameLengthController::Config::FrameLengthChange, int>{
{FrameLengthController::Config::FrameLengthChange(20, 40),
kFl20msTo40msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(40, 20),
kFl40msTo20msBandwidthBps}};
}
std::map<FrameLengthController::Config::FrameLengthChange, int>
CreateChangeCriteriaFor20ms60msAnd120ms() {
return std::map<FrameLengthController::Config::FrameLengthChange, int>{
{FrameLengthController::Config::FrameLengthChange(20, 60),
kFl20msTo60msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 20),
kFl60msTo20msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 120),
kFl60msTo120msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(120, 60),
kFl120msTo60msBandwidthBps}};
}
std::map<FrameLengthController::Config::FrameLengthChange, int>
CreateChangeCriteriaFor20ms40ms60msAnd120ms() {
return std::map<FrameLengthController::Config::FrameLengthChange, int>{
{FrameLengthController::Config::FrameLengthChange(20, 60),
kFl20msTo60msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 20),
kFl60msTo20msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(20, 40),
kFl20msTo40msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(40, 20),
kFl40msTo20msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(40, 60),
kFl40msTo60msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 40),
kFl60msTo40msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 120),
kFl60msTo120msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(120, 60),
kFl120msTo60msBandwidthBps}};
}
std::map<FrameLengthController::Config::FrameLengthChange, int>
CreateChangeCriteriaFor40msAnd60ms() {
return std::map<FrameLengthController::Config::FrameLengthChange, int>{
{FrameLengthController::Config::FrameLengthChange(40, 60),
kFl40msTo60msBandwidthBps},
{FrameLengthController::Config::FrameLengthChange(60, 40),
kFl60msTo40msBandwidthBps}};
}
void UpdateNetworkMetrics(
FrameLengthController* controller,
const absl::optional<int>& uplink_bandwidth_bps,
const absl::optional<float>& uplink_packet_loss_fraction,
const absl::optional<size_t>& overhead_bytes_per_packet) {
// UpdateNetworkMetrics can accept multiple network metric updates at once.
// However, currently, the most used case is to update one metric at a time.
// To reflect this fact, we separate the calls.
if (uplink_bandwidth_bps) {
Controller::NetworkMetrics network_metrics;
network_metrics.uplink_bandwidth_bps = uplink_bandwidth_bps;
controller->UpdateNetworkMetrics(network_metrics);
}
if (uplink_packet_loss_fraction) {
Controller::NetworkMetrics network_metrics;
network_metrics.uplink_packet_loss_fraction = uplink_packet_loss_fraction;
controller->UpdateNetworkMetrics(network_metrics);
}
if (overhead_bytes_per_packet) {
Controller::NetworkMetrics network_metrics;
network_metrics.overhead_bytes_per_packet = overhead_bytes_per_packet;
controller->UpdateNetworkMetrics(network_metrics);
}
}
void CheckDecision(FrameLengthController* controller,
int expected_frame_length_ms) {
AudioEncoderRuntimeConfig config;
controller->MakeDecision(&config);
EXPECT_EQ(expected_frame_length_ms, config.frame_length_ms);
}
} // namespace
TEST(FrameLengthControllerTest, DecreaseTo20MsOnHighUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
absl::nullopt, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, DecreaseTo20MsOnHighUplinkPacketLossFraction) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 60);
UpdateNetworkMetrics(controller.get(), absl::nullopt,
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest,
Maintain60MsIf20MsNotInReceiverFrameLengthRange) {
auto controller =
CreateController(CreateChangeCriteriaFor20msAnd60ms(), {60}, 60);
// Set FEC on that would cause frame length to decrease if receiver frame
// length range included 20ms.
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, IncreaseTo40MsOnMultipleConditions) {
// Increase to 40ms frame length if
// 1. `uplink_bandwidth_bps` is known to be smaller than a threshold AND
// 2. `uplink_packet_loss_fraction` is known to be smaller than a threshold
// AND
// 3. FEC is not decided or OFF.
auto controller = CreateController(CreateChangeCriteriaFor20msAnd40ms(),
kDefaultEncoderFrameLengthsMs, 20);
UpdateNetworkMetrics(controller.get(), kFl20msTo40msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 40);
}
TEST(FrameLengthControllerTest, DecreaseTo40MsOnHighUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor40msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 40);
UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
absl::nullopt, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 40);
}
TEST(FrameLengthControllerTest, Maintain60MsOnMultipleConditions) {
// Maintain 60ms frame length if
// 1. `uplink_bandwidth_bps` is at medium level,
// 2. `uplink_packet_loss_fraction` is at medium,
// 3. FEC is not decided ON.
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 60);
UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
kMediumPacketLossFraction, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, IncreaseTo60MsOnMultipleConditions) {
// Increase to 60ms frame length if
// 1. `uplink_bandwidth_bps` is known to be smaller than a threshold AND
// 2. `uplink_packet_loss_fraction` is known to be smaller than a threshold
// AND
// 3. FEC is not decided or OFF.
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 20);
UpdateNetworkMetrics(controller.get(), kFl20msTo60msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, IncreaseTo60MsOnVeryLowUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 20);
// We set packet loss fraction to kFlDecreasingPacketLossFraction, which
// should have prevented frame length to increase, if the uplink bandwidth
// was not this low.
UpdateNetworkMetrics(controller.get(), VeryLowBitrate(20),
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, Maintain60MsOnVeryLowUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 60);
// We set packet loss fraction to FlDecreasingPacketLossFraction, which should
// have caused the frame length to decrease, if the uplink bandwidth was not
// this low.
UpdateNetworkMetrics(controller.get(), VeryLowBitrate(20),
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, UpdateMultipleNetworkMetricsAtOnce) {
// This test is similar to IncreaseTo60MsOnMultipleConditions. But instead of
// using ::UpdateNetworkMetrics(...), which calls
// FrameLengthController::UpdateNetworkMetrics(...) multiple times, we
// we call it only once. This is to verify that
// FrameLengthController::UpdateNetworkMetrics(...) can handle multiple
// network updates at once. This is, however, not a common use case in current
// audio_network_adaptor_impl.cc.
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 20);
Controller::NetworkMetrics network_metrics;
network_metrics.uplink_bandwidth_bps = kFl20msTo60msBandwidthBps;
network_metrics.uplink_packet_loss_fraction = kFlIncreasingPacketLossFraction;
controller->UpdateNetworkMetrics(network_metrics);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest,
Maintain20MsIf60MsNotInReceiverFrameLengthRange) {
auto controller =
CreateController(CreateChangeCriteriaFor20msAnd60ms(), {20}, 20);
// Use a low uplink bandwidth and a low uplink packet loss fraction that would
// cause frame length to increase if receiver frame length included 60ms.
UpdateNetworkMetrics(controller.get(), kFl20msTo60msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, Maintain20MsOnMediumUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 20);
UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, Maintain20MsOnMediumUplinkPacketLossFraction) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 20);
// Use a low uplink bandwidth that would cause frame length to increase if
// uplink packet loss fraction was low.
UpdateNetworkMetrics(controller.get(), kFl20msTo60msBandwidthBps,
kMediumPacketLossFraction, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, Maintain60MsWhenNo120msCriteriaIsSet) {
auto controller = CreateController(CreateChangeCriteriaFor20msAnd60ms(),
kDefaultEncoderFrameLengthsMs, 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, From120MsTo20MsOnHighUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 120);
// It takes two steps for frame length to go from 120ms to 20ms.
UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
absl::nullopt, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
absl::nullopt, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, From120MsTo20MsOnHighUplinkPacketLossFraction) {
auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 120);
// It takes two steps for frame length to go from 120ms to 20ms.
UpdateNetworkMetrics(controller.get(), absl::nullopt,
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), absl::nullopt,
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
TEST(FrameLengthControllerTest, Maintain120MsOnVeryLowUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 120);
// We set packet loss fraction to FlDecreasingPacketLossFraction, which should
// have caused the frame length to decrease, if the uplink bandwidth was not
// this low.
UpdateNetworkMetrics(controller.get(), VeryLowBitrate(60),
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 120);
}
TEST(FrameLengthControllerTest, From60MsTo120MsOnVeryLowUplinkBandwidth) {
auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 60);
// We set packet loss fraction to FlDecreasingPacketLossFraction, which should
// have prevented frame length to increase, if the uplink bandwidth was not
// this low.
UpdateNetworkMetrics(controller.get(), VeryLowBitrate(60),
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 120);
}
TEST(FrameLengthControllerTest, From20MsTo120MsOnMultipleConditions) {
// Increase to 120ms frame length if
// 1. `uplink_bandwidth_bps` is known to be smaller than a threshold AND
// 2. `uplink_packet_loss_fraction` is known to be smaller than a threshold.
auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 20);
// It takes two steps for frame length to go from 20ms to 120ms.
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 120);
}
TEST(FrameLengthControllerTest, Stall60MsIf120MsNotInReceiverFrameLengthRange) {
auto controller =
CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(), {20, 60}, 20);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
}
TEST(FrameLengthControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
auto controller =
CreateController(CreateChangeCriteriaFor20ms40ms60msAnd120ms(),
kDefaultEncoderFrameLengthsMs, 20);
UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
UpdateNetworkMetrics(controller.get(), kFl20msTo40msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 40);
UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
kMediumPacketLossFraction, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 40);
UpdateNetworkMetrics(controller.get(), kFl20msTo60msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kMediumPacketLossFraction, kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo120msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 120);
UpdateNetworkMetrics(controller.get(), kFl120msTo60msBandwidthBps,
kFlIncreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 60);
UpdateNetworkMetrics(controller.get(), kFl60msTo40msBandwidthBps,
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 40);
UpdateNetworkMetrics(controller.get(), kMediumBandwidthBps,
kFlDecreasingPacketLossFraction,
kOverheadBytesPerPacket);
CheckDecision(controller.get(), 20);
}
} // namespace webrtc