1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_coding/audio_network_adaptor/frame_length_controller.h"
12
13 #include <algorithm>
14 #include <iterator>
15 #include <utility>
16
17 #include "rtc_base/checks.h"
18
19 namespace webrtc {
20
21 namespace {
22 constexpr int kPreventOveruseMarginBps = 5000;
23
OverheadRateBps(size_t overhead_bytes_per_packet,int frame_length_ms)24 int OverheadRateBps(size_t overhead_bytes_per_packet, int frame_length_ms) {
25 return static_cast<int>(overhead_bytes_per_packet * 8 * 1000 /
26 frame_length_ms);
27 }
28 } // namespace
29
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)30 FrameLengthController::Config::Config(
31 const std::set<int>& encoder_frame_lengths_ms,
32 int initial_frame_length_ms,
33 int min_encoder_bitrate_bps,
34 float fl_increasing_packet_loss_fraction,
35 float fl_decreasing_packet_loss_fraction,
36 int fl_increase_overhead_offset,
37 int fl_decrease_overhead_offset,
38 std::map<FrameLengthChange, int> fl_changing_bandwidths_bps)
39 : encoder_frame_lengths_ms(encoder_frame_lengths_ms),
40 initial_frame_length_ms(initial_frame_length_ms),
41 min_encoder_bitrate_bps(min_encoder_bitrate_bps),
42 fl_increasing_packet_loss_fraction(fl_increasing_packet_loss_fraction),
43 fl_decreasing_packet_loss_fraction(fl_decreasing_packet_loss_fraction),
44 fl_increase_overhead_offset(fl_increase_overhead_offset),
45 fl_decrease_overhead_offset(fl_decrease_overhead_offset),
46 fl_changing_bandwidths_bps(std::move(fl_changing_bandwidths_bps)) {}
47
48 FrameLengthController::Config::Config(const Config& other) = default;
49
50 FrameLengthController::Config::~Config() = default;
51
FrameLengthController(const Config & config)52 FrameLengthController::FrameLengthController(const Config& config)
53 : config_(config) {
54 frame_length_ms_ = std::find(config_.encoder_frame_lengths_ms.begin(),
55 config_.encoder_frame_lengths_ms.end(),
56 config_.initial_frame_length_ms);
57 // |encoder_frame_lengths_ms| must contain |initial_frame_length_ms|.
58 RTC_DCHECK(frame_length_ms_ != config_.encoder_frame_lengths_ms.end());
59 }
60
61 FrameLengthController::~FrameLengthController() = default;
62
UpdateNetworkMetrics(const NetworkMetrics & network_metrics)63 void FrameLengthController::UpdateNetworkMetrics(
64 const NetworkMetrics& network_metrics) {
65 if (network_metrics.uplink_bandwidth_bps)
66 uplink_bandwidth_bps_ = network_metrics.uplink_bandwidth_bps;
67 if (network_metrics.uplink_packet_loss_fraction)
68 uplink_packet_loss_fraction_ = network_metrics.uplink_packet_loss_fraction;
69 if (network_metrics.overhead_bytes_per_packet)
70 overhead_bytes_per_packet_ = network_metrics.overhead_bytes_per_packet;
71 }
72
MakeDecision(AudioEncoderRuntimeConfig * config)73 void FrameLengthController::MakeDecision(AudioEncoderRuntimeConfig* config) {
74 // Decision on |frame_length_ms| should not have been made.
75 RTC_DCHECK(!config->frame_length_ms);
76
77 if (FrameLengthIncreasingDecision(*config)) {
78 prev_decision_increase_ = true;
79 } else if (FrameLengthDecreasingDecision(*config)) {
80 prev_decision_increase_ = false;
81 }
82 config->last_fl_change_increase = prev_decision_increase_;
83 config->frame_length_ms = *frame_length_ms_;
84 }
85
FrameLengthChange(int from_frame_length_ms,int to_frame_length_ms)86 FrameLengthController::Config::FrameLengthChange::FrameLengthChange(
87 int from_frame_length_ms,
88 int to_frame_length_ms)
89 : from_frame_length_ms(from_frame_length_ms),
90 to_frame_length_ms(to_frame_length_ms) {}
91
operator <(const FrameLengthChange & rhs) const92 bool FrameLengthController::Config::FrameLengthChange::operator<(
93 const FrameLengthChange& rhs) const {
94 return from_frame_length_ms < rhs.from_frame_length_ms ||
95 (from_frame_length_ms == rhs.from_frame_length_ms &&
96 to_frame_length_ms < rhs.to_frame_length_ms);
97 }
98
FrameLengthIncreasingDecision(const AudioEncoderRuntimeConfig & config)99 bool FrameLengthController::FrameLengthIncreasingDecision(
100 const AudioEncoderRuntimeConfig& config) {
101 // Increase frame length if
102 // 1. |uplink_bandwidth_bps| is known to be smaller or equal than
103 // |min_encoder_bitrate_bps| plus |prevent_overuse_margin_bps| plus the
104 // current overhead rate OR all the following:
105 // 2. longer frame length is available AND
106 // 3. |uplink_bandwidth_bps| is known to be smaller than a threshold AND
107 // 4. |uplink_packet_loss_fraction| is known to be smaller than a threshold.
108
109 // Find next frame length to which a criterion is defined to shift from
110 // current frame length.
111 auto longer_frame_length_ms = std::next(frame_length_ms_);
112 auto increase_threshold = config_.fl_changing_bandwidths_bps.end();
113 while (longer_frame_length_ms != config_.encoder_frame_lengths_ms.end()) {
114 increase_threshold = config_.fl_changing_bandwidths_bps.find(
115 Config::FrameLengthChange(*frame_length_ms_, *longer_frame_length_ms));
116 if (increase_threshold != config_.fl_changing_bandwidths_bps.end())
117 break;
118 longer_frame_length_ms = std::next(longer_frame_length_ms);
119 }
120
121 if (increase_threshold == config_.fl_changing_bandwidths_bps.end())
122 return false;
123
124 // Check that
125 // -(*overhead_bytes_per_packet_) <= offset <= (*overhead_bytes_per_packet_)
126 RTC_DCHECK(
127 !overhead_bytes_per_packet_ ||
128 (overhead_bytes_per_packet_ &&
129 static_cast<size_t>(std::max(0, -config_.fl_increase_overhead_offset)) <=
130 *overhead_bytes_per_packet_ &&
131 static_cast<size_t>(std::max(0, config_.fl_increase_overhead_offset)) <=
132 *overhead_bytes_per_packet_));
133
134 if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
135 *uplink_bandwidth_bps_ <=
136 config_.min_encoder_bitrate_bps + kPreventOveruseMarginBps +
137 OverheadRateBps(*overhead_bytes_per_packet_ +
138 config_.fl_increase_overhead_offset,
139 *frame_length_ms_)) {
140 frame_length_ms_ = longer_frame_length_ms;
141 return true;
142 }
143
144 if ((uplink_bandwidth_bps_ &&
145 *uplink_bandwidth_bps_ <= increase_threshold->second) &&
146 (uplink_packet_loss_fraction_ &&
147 *uplink_packet_loss_fraction_ <=
148 config_.fl_increasing_packet_loss_fraction)) {
149 frame_length_ms_ = longer_frame_length_ms;
150 return true;
151 }
152 return false;
153 }
154
FrameLengthDecreasingDecision(const AudioEncoderRuntimeConfig & config)155 bool FrameLengthController::FrameLengthDecreasingDecision(
156 const AudioEncoderRuntimeConfig& config) {
157 // Decrease frame length if
158 // 1. shorter frame length is available AND
159 // 2. |uplink_bandwidth_bps| is known to be bigger than
160 // |min_encoder_bitrate_bps| plus |prevent_overuse_margin_bps| plus the
161 // overhead which would be produced with the shorter frame length AND
162 // one or more of the followings:
163 // 3. |uplink_bandwidth_bps| is known to be larger than a threshold,
164 // 4. |uplink_packet_loss_fraction| is known to be larger than a threshold,
165
166 // Find next frame length to which a criterion is defined to shift from
167 // current frame length.
168 auto shorter_frame_length_ms = frame_length_ms_;
169 auto decrease_threshold = config_.fl_changing_bandwidths_bps.end();
170 while (shorter_frame_length_ms != config_.encoder_frame_lengths_ms.begin()) {
171 shorter_frame_length_ms = std::prev(shorter_frame_length_ms);
172 decrease_threshold = config_.fl_changing_bandwidths_bps.find(
173 Config::FrameLengthChange(*frame_length_ms_, *shorter_frame_length_ms));
174 if (decrease_threshold != config_.fl_changing_bandwidths_bps.end())
175 break;
176 }
177
178 if (decrease_threshold == config_.fl_changing_bandwidths_bps.end())
179 return false;
180
181 if (uplink_bandwidth_bps_ && overhead_bytes_per_packet_ &&
182 *uplink_bandwidth_bps_ <=
183 config_.min_encoder_bitrate_bps + kPreventOveruseMarginBps +
184 OverheadRateBps(*overhead_bytes_per_packet_ +
185 config_.fl_decrease_overhead_offset,
186 *shorter_frame_length_ms)) {
187 return false;
188 }
189
190 if ((uplink_bandwidth_bps_ &&
191 *uplink_bandwidth_bps_ >= decrease_threshold->second) ||
192 (uplink_packet_loss_fraction_ &&
193 *uplink_packet_loss_fraction_ >=
194 config_.fl_decreasing_packet_loss_fraction)) {
195 frame_length_ms_ = shorter_frame_length_ms;
196 return true;
197 }
198 return false;
199 }
200
201 } // namespace webrtc
202