mediasoup 3.27.0 → 3.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/worker/fbs/FBS/meson.build +25 -0
- package/worker/fbs/meson.build +15 -18
- package/worker/include/RTC/BWE/BweTypes.hpp +1 -1
- package/worker/include/RTC/BWE/LossBasedController.hpp +520 -0
- package/worker/include/RTC/BWE/TargetRateController.hpp +306 -0
- package/worker/include/RTC/BWE/TrendlineEstimator.hpp +58 -16
- package/worker/include/RTC/BWE/Utils.hpp +39 -0
- package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +36 -0
- package/worker/include/RTC/SCTP/public/SctpTypes.hpp +5 -5
- package/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp +10 -0
- package/worker/meson.build +6 -0
- package/worker/src/RTC/BWE/LossBasedController.cpp +1046 -0
- package/worker/src/RTC/BWE/TargetRateController.cpp +435 -0
- package/worker/src/RTC/BWE/TrendlineEstimator.cpp +83 -5
- package/worker/src/RTC/BWE/Utils.cpp +54 -0
- package/worker/src/RTC/SCTP/association/Association.cpp +15 -1
- package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +106 -1
- package/worker/src/RTC/SCTP/public/AssociationMetrics.cpp +1 -1
- package/worker/src/RTC/Transport.cpp +37 -18
- package/worker/tasks.py +43 -18
- package/worker/test/src/RTC/BWE/TestLossBasedController.cpp +1199 -0
- package/worker/test/src/RTC/BWE/TestTargetRateController.cpp +337 -0
- package/worker/test/src/RTC/BWE/TestTrendlineEstimator.cpp +45 -0
- package/worker/test/src/RTC/BWE/TestUtils.cpp +61 -0
- package/worker/test/src/RTC/SCTP/association/TestStreamResetHandler.cpp +111 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
### NEXT
|
|
4
4
|
|
|
5
|
+
### 3.27.1
|
|
6
|
+
|
|
7
|
+
- Worker: Fix endless regeneration of FlatBuffers generated headers ([PR #1926](https://github.com/versatica/mediasoup/pull/1926)).
|
|
8
|
+
- SCTP: Fix unbounded SCTP reassembly queue growth during deferred reset processing ([PR #1927](https://github.com/versatica/mediasoup/pull/1927)).
|
|
9
|
+
|
|
5
10
|
### 3.27.0
|
|
6
11
|
|
|
7
12
|
- Worker: New `RateCalculator` ([PR #1899](https://github.com/versatica/mediasoup/pull/1899)).
|
package/package.json
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# The generator writes a single header per schema, with the same base name and
|
|
2
|
+
# a .h extension since the empty --filename-suffix removes the default one.
|
|
3
|
+
flatbuffers_headers = []
|
|
4
|
+
|
|
5
|
+
foreach schema : flatbuffers_schemas
|
|
6
|
+
flatbuffers_headers += schema.replace('.fbs', '.h')
|
|
7
|
+
endforeach
|
|
8
|
+
|
|
9
|
+
flatc = find_program('flatc')
|
|
10
|
+
|
|
11
|
+
flatbuffers_generator = custom_target('flatbuffers-generator',
|
|
12
|
+
output: flatbuffers_headers,
|
|
13
|
+
input: flatbuffers_schema_files,
|
|
14
|
+
command : [
|
|
15
|
+
flatc,
|
|
16
|
+
'--cpp',
|
|
17
|
+
'--cpp-field-case-style', 'lower',
|
|
18
|
+
'--reflect-names',
|
|
19
|
+
'--scoped-enums',
|
|
20
|
+
'--filename-suffix', '',
|
|
21
|
+
'-o', '@OUTDIR@',
|
|
22
|
+
'@INPUT@'
|
|
23
|
+
],
|
|
24
|
+
build_by_default: true,
|
|
25
|
+
)
|
package/worker/fbs/meson.build
CHANGED
|
@@ -29,26 +29,23 @@ flatbuffers_schemas = [
|
|
|
29
29
|
'worker.fbs',
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
-
#
|
|
33
|
-
|
|
32
|
+
# The schemas are turned into file objects here because the target that
|
|
33
|
+
# consumes them is declared in the FBS subdirectory, where plain relative names
|
|
34
|
+
# would no longer resolve.
|
|
35
|
+
flatbuffers_schema_files = files(flatbuffers_schemas)
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'--filename-suffix', '',
|
|
46
|
-
'-o', '@OUTPUT@',
|
|
47
|
-
'@INPUT@'
|
|
48
|
-
],
|
|
49
|
-
build_by_default: true,
|
|
50
|
-
)
|
|
37
|
+
# FBS is the directory from which worker code includes the generated header
|
|
38
|
+
# files. The generator target is declared from within that very subdirectory
|
|
39
|
+
# because Meson does not allow path segments in the outputs of a custom target,
|
|
40
|
+
# and the outputs must be the individual headers rather than the directory that
|
|
41
|
+
# holds them. Declaring the directory as the output makes the target dirty
|
|
42
|
+
# forever: running the generator rewrites the headers in place, which never
|
|
43
|
+
# updates the modification time of the directory containing them, so the target
|
|
44
|
+
# never becomes up to date and every build regenerates the headers and
|
|
45
|
+
# recompiles every source file that includes them.
|
|
46
|
+
subdir('FBS')
|
|
51
47
|
|
|
52
48
|
flatbuffers_generator_dep = declare_dependency(
|
|
53
49
|
include_directories: '.',
|
|
50
|
+
sources: flatbuffers_generator,
|
|
54
51
|
)
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
#ifndef MS_RTC_BWE_LOSS_BASED_CONTROLLER_HPP
|
|
2
|
+
#define MS_RTC_BWE_LOSS_BASED_CONTROLLER_HPP
|
|
3
|
+
|
|
4
|
+
#include "common.hpp"
|
|
5
|
+
#include "RTC/BWE/BweTypes.hpp"
|
|
6
|
+
#include <ankerl/unordered_dense.h>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
namespace RTC
|
|
10
|
+
{
|
|
11
|
+
namespace BWE
|
|
12
|
+
{
|
|
13
|
+
/**
|
|
14
|
+
* Tells the loss caused by congestion from the loss a link has by itself.
|
|
15
|
+
*
|
|
16
|
+
* A link can lose packets without being congested at all, which is the normal
|
|
17
|
+
* state of Wi-Fi and mobile links, and reacting to that loss by sending less
|
|
18
|
+
* doesn't reduce it: it just gives away capacity that was there. Telling both
|
|
19
|
+
* apart cannot be done by looking at a loss figure, because the very same
|
|
20
|
+
* figure means different things at different sending rates.
|
|
21
|
+
*
|
|
22
|
+
* So instead of a rule on the reported loss, this is an estimator of two
|
|
23
|
+
* values that together describe the link: how much it loses when it is not
|
|
24
|
+
* congested, and how much it can carry. With those two, the loss to expect
|
|
25
|
+
* from an observation is known: the inherent one while sending below the
|
|
26
|
+
* capacity, plus the share of the excess while sending above it. The pair of
|
|
27
|
+
* values that makes the losses actually observed most likely is the estimate,
|
|
28
|
+
* and the bitrate of that pair is the answer.
|
|
29
|
+
*
|
|
30
|
+
* Candidates slightly above, at and below the current estimate are tried on
|
|
31
|
+
* every update, each refined by a step of Newton's method on the inherent
|
|
32
|
+
* loss, and the most likely one wins. A bias towards higher bitrates keeps
|
|
33
|
+
* the estimate from settling low when the observations cannot tell them
|
|
34
|
+
* apart, and fades away as the observed loss grows.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* - This class is a port of the LossBasedBweV2 class in libwebrtc (renamed to
|
|
38
|
+
* a better name).
|
|
39
|
+
*/
|
|
40
|
+
class LossBasedController
|
|
41
|
+
{
|
|
42
|
+
public:
|
|
43
|
+
struct LossBasedControllerOptions
|
|
44
|
+
{
|
|
45
|
+
/**
|
|
46
|
+
* Factors applied to the current estimate to build the candidates that
|
|
47
|
+
* are tried on every update.
|
|
48
|
+
*/
|
|
49
|
+
std::vector<double> candidateFactors{ 1.02, 1.0, 0.95 };
|
|
50
|
+
/**
|
|
51
|
+
* How much the estimate may grow over the acknowledged bitrate while
|
|
52
|
+
* the link is loss limited.
|
|
53
|
+
*/
|
|
54
|
+
double bitrateRampupUpperBoundFactor{ 1.5 };
|
|
55
|
+
/**
|
|
56
|
+
* The same while the estimate is being held, which is more conservative
|
|
57
|
+
* because holding means that a higher bitrate already caused loss.
|
|
58
|
+
*/
|
|
59
|
+
double bitrateRampupUpperBoundFactorInHold{ 1.2 };
|
|
60
|
+
/**
|
|
61
|
+
* How far below the held bitrate the acknowledged one has to be for the
|
|
62
|
+
* factor above to be the one applied.
|
|
63
|
+
*/
|
|
64
|
+
double bitrateRampupHoldThreshold{ 1.3 };
|
|
65
|
+
/**
|
|
66
|
+
* How much of the acknowledged bitrate the estimate may grow by on top
|
|
67
|
+
* of its usual bound, the longer the more time has passed since it was
|
|
68
|
+
* last reduced. Zero disables that acceleration.
|
|
69
|
+
*/
|
|
70
|
+
double rampupAccelerationMaxFactor{ 0.0 };
|
|
71
|
+
/**
|
|
72
|
+
* Time since the last reduction at which that acceleration is at its
|
|
73
|
+
* fullest.
|
|
74
|
+
*/
|
|
75
|
+
int64_t rampupAccelerationMaxoutTimeUs{ 60 * 1000 * 1000 };
|
|
76
|
+
/**
|
|
77
|
+
* Weight given to a higher bitrate when choosing among candidates, so
|
|
78
|
+
* that observations which cannot tell them apart don't settle low.
|
|
79
|
+
*/
|
|
80
|
+
double higherBitrateBiasFactor{ 0.0002 };
|
|
81
|
+
/**
|
|
82
|
+
* The same, applied to the logarithm of the bitrate, so that the bias
|
|
83
|
+
* doesn't grow without bound.
|
|
84
|
+
*/
|
|
85
|
+
double higherLogBitrateBiasFactor{ 0.02 };
|
|
86
|
+
/**
|
|
87
|
+
* Observed loss at which the bias above is gone, since at that much loss
|
|
88
|
+
* preferring a higher bitrate is not defensible anymore.
|
|
89
|
+
*/
|
|
90
|
+
double lossThresholdOfHighBitratePreference{ 0.2 };
|
|
91
|
+
/**
|
|
92
|
+
* How abruptly that bias fades as the observed loss approaches the
|
|
93
|
+
* threshold above.
|
|
94
|
+
*/
|
|
95
|
+
double bitratePreferenceSmoothingFactor{ 0.002 };
|
|
96
|
+
/**
|
|
97
|
+
* Lowest inherent loss that may be estimated for a link.
|
|
98
|
+
*/
|
|
99
|
+
double inherentLossLowerBound{ 1.0e-3 };
|
|
100
|
+
/**
|
|
101
|
+
* Inherent loss that may be estimated at an unbounded bitrate, which
|
|
102
|
+
* grows as the bitrate gets lower by the balance below.
|
|
103
|
+
*/
|
|
104
|
+
double inherentLossUpperBoundOffset{ 0.05 };
|
|
105
|
+
/**
|
|
106
|
+
* Bitrate at which the inherent loss upper bound grows by one, so that a
|
|
107
|
+
* low bitrate is allowed to be explained by a lossy link.
|
|
108
|
+
*/
|
|
109
|
+
int64_t inherentLossUpperBoundBitrateBalance{ 100000 };
|
|
110
|
+
/**
|
|
111
|
+
* Inherent loss assumed before anything has been observed.
|
|
112
|
+
*/
|
|
113
|
+
double initialInherentLossEstimate{ 0.01 };
|
|
114
|
+
/**
|
|
115
|
+
* Steps of Newton's method applied to each candidate.
|
|
116
|
+
*/
|
|
117
|
+
int64_t newtonIterations{ 1 };
|
|
118
|
+
/**
|
|
119
|
+
* Fraction of the step that each of those iterations takes.
|
|
120
|
+
*/
|
|
121
|
+
double newtonStepSize{ 0.75 };
|
|
122
|
+
/**
|
|
123
|
+
* Whether the acknowledged bitrate is tried as a candidate of its own.
|
|
124
|
+
*/
|
|
125
|
+
bool appendAcknowledgedRateCandidate{ true };
|
|
126
|
+
/**
|
|
127
|
+
* Whether the delay based estimate is tried as a candidate of its own
|
|
128
|
+
* while it's above the current one.
|
|
129
|
+
*/
|
|
130
|
+
bool appendDelayBasedEstimateCandidate{ true };
|
|
131
|
+
/**
|
|
132
|
+
* Whether the bound that the observed loss puts on the estimate is tried
|
|
133
|
+
* as a candidate while not filling the link, which lets the estimate
|
|
134
|
+
* come down to it in one step instead of gradually.
|
|
135
|
+
*/
|
|
136
|
+
bool appendUpperBoundCandidateInAlr{ false };
|
|
137
|
+
/**
|
|
138
|
+
* Shortest span of send times that an observation may cover.
|
|
139
|
+
*/
|
|
140
|
+
int64_t observationDurationLowerBoundUs{ 250 * 1000 };
|
|
141
|
+
/**
|
|
142
|
+
* Observations kept, which is how far back the estimate looks.
|
|
143
|
+
*/
|
|
144
|
+
int64_t observationWindowSize{ 15 };
|
|
145
|
+
/**
|
|
146
|
+
* Observations needed before this controller may be used at all.
|
|
147
|
+
*/
|
|
148
|
+
int64_t minNumObservations{ 3 };
|
|
149
|
+
/**
|
|
150
|
+
* How much the sending rate of an observation is smoothed with the one
|
|
151
|
+
* of the previous observation.
|
|
152
|
+
*
|
|
153
|
+
* @remarks
|
|
154
|
+
* - Zero means no smoothing at all, which is what libwebrtc does. A
|
|
155
|
+
* sender of a couple of streams has a sending rate that only changes
|
|
156
|
+
* when it decides so, while ours is the sum of many streams whose
|
|
157
|
+
* makeup changes on its own, and those changes are not the network.
|
|
158
|
+
*/
|
|
159
|
+
double sendingRateSmoothingFactor{ 0.0 };
|
|
160
|
+
/**
|
|
161
|
+
* How much weight each observation loses per observation of age when
|
|
162
|
+
* looking for the most likely pair of values.
|
|
163
|
+
*/
|
|
164
|
+
double temporalWeightFactor{ 0.9 };
|
|
165
|
+
/**
|
|
166
|
+
* The same, for the average observed loss that bounds the estimate right
|
|
167
|
+
* away.
|
|
168
|
+
*/
|
|
169
|
+
double immediateUpperBoundTemporalWeightFactor{ 0.9 };
|
|
170
|
+
/**
|
|
171
|
+
* Observed loss under which no immediate upper bound is applied.
|
|
172
|
+
*/
|
|
173
|
+
double immediateUpperBoundLossOffset{ 0.05 };
|
|
174
|
+
/**
|
|
175
|
+
* Bitrate the immediate upper bound allows per unit of observed loss
|
|
176
|
+
* over the offset above.
|
|
177
|
+
*/
|
|
178
|
+
int64_t immediateUpperBoundBitrateBalance{ 100000 };
|
|
179
|
+
/**
|
|
180
|
+
* How much of the acknowledged bitrate the estimate may never go below.
|
|
181
|
+
*/
|
|
182
|
+
double lowerBoundByAckedRateFactor{ 1.0 };
|
|
183
|
+
/**
|
|
184
|
+
* Fraction of the acknowledged bitrate taken as a candidate when backing
|
|
185
|
+
* off.
|
|
186
|
+
*/
|
|
187
|
+
double bitrateBackoffLowerBoundFactor{ 1.0 };
|
|
188
|
+
/**
|
|
189
|
+
* How much the estimate may grow within the window that follows a
|
|
190
|
+
* decrease.
|
|
191
|
+
*/
|
|
192
|
+
double maxIncreaseFactor{ 1.3 };
|
|
193
|
+
/**
|
|
194
|
+
* How long that window lasts.
|
|
195
|
+
*/
|
|
196
|
+
int64_t delayedIncreaseWindowUs{ 300 * 1000 };
|
|
197
|
+
/**
|
|
198
|
+
* Whether the estimate is held back while the loss observed is worse
|
|
199
|
+
* than the one the chosen candidate says the link has by itself, since
|
|
200
|
+
* then the excess is ours to fix.
|
|
201
|
+
*/
|
|
202
|
+
bool notIncreaseIfInherentLossLessThanAverageLoss{ true };
|
|
203
|
+
/**
|
|
204
|
+
* Whether the acknowledged bitrate stops being a candidate while not
|
|
205
|
+
* filling the link, since then what it delivers says nothing about what
|
|
206
|
+
* it could deliver.
|
|
207
|
+
*/
|
|
208
|
+
bool notUseAckedRateInAlr{ true };
|
|
209
|
+
/**
|
|
210
|
+
* Whether this controller may take the estimate over while the target is
|
|
211
|
+
* still in its start phase.
|
|
212
|
+
*/
|
|
213
|
+
bool useInStartPhase{ true };
|
|
214
|
+
/**
|
|
215
|
+
* How much each hold lasts compared to the previous one, which makes
|
|
216
|
+
* repeated failures to increase back off for longer.
|
|
217
|
+
*/
|
|
218
|
+
double holdDurationFactor{ 2.0 };
|
|
219
|
+
/**
|
|
220
|
+
* Whether loss is measured in bytes rather than in packets, which tells
|
|
221
|
+
* a lost packet of a full frame apart from a lost one carrying almost
|
|
222
|
+
* nothing.
|
|
223
|
+
*/
|
|
224
|
+
bool useByteLossRate{ true };
|
|
225
|
+
/**
|
|
226
|
+
* Whether an estimate that had to be brought down to its bounds stops
|
|
227
|
+
* being kept as a description of the link.
|
|
228
|
+
*/
|
|
229
|
+
bool boundBestCandidate{ true };
|
|
230
|
+
/**
|
|
231
|
+
* How much the sending rate of an observation has to exceed the median
|
|
232
|
+
* of the window for its loss to be taken at face value instead of as a
|
|
233
|
+
* spike.
|
|
234
|
+
*/
|
|
235
|
+
double medianSendingRateFactor{ 2.0 };
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* What this controller is doing with the estimate, which the orchestrator
|
|
240
|
+
* needs in order to decide whether to probe.
|
|
241
|
+
*/
|
|
242
|
+
enum class State : uint8_t
|
|
243
|
+
{
|
|
244
|
+
/**
|
|
245
|
+
* The link is loss limited and the estimate is growing back.
|
|
246
|
+
*/
|
|
247
|
+
INCREASING,
|
|
248
|
+
/**
|
|
249
|
+
* The link is loss limited and the estimate is being reduced.
|
|
250
|
+
*/
|
|
251
|
+
DECREASING,
|
|
252
|
+
/**
|
|
253
|
+
* The link is not loss limited, so the delay based estimate rules.
|
|
254
|
+
*/
|
|
255
|
+
DELAY_BASED_ESTIMATE
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
struct Result
|
|
259
|
+
{
|
|
260
|
+
int64_t bitrate{ 0 };
|
|
261
|
+
State state{ State::DELAY_BASED_ESTIMATE };
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
private:
|
|
265
|
+
/**
|
|
266
|
+
* The pair of values that describe a link.
|
|
267
|
+
*/
|
|
268
|
+
struct ChannelParameters
|
|
269
|
+
{
|
|
270
|
+
/**
|
|
271
|
+
* Loss the link has while not congested at all.
|
|
272
|
+
*/
|
|
273
|
+
double inherentLoss{ 0.0 };
|
|
274
|
+
/**
|
|
275
|
+
* Bitrate the link can carry, or zero while it's not known yet.
|
|
276
|
+
*/
|
|
277
|
+
int64_t lossLimitedBitrate{ 0 };
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* First and second derivatives of the likelihood with respect to the
|
|
282
|
+
* inherent loss, which is what Newton's method needs.
|
|
283
|
+
*/
|
|
284
|
+
struct Derivatives
|
|
285
|
+
{
|
|
286
|
+
double first{ 0.0 };
|
|
287
|
+
double second{ 0.0 };
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* What was sent and lost over a span of send times, which is the unit this
|
|
292
|
+
* controller reasons about.
|
|
293
|
+
*/
|
|
294
|
+
struct Observation
|
|
295
|
+
{
|
|
296
|
+
bool IsInitialized() const
|
|
297
|
+
{
|
|
298
|
+
return this->id != -1;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
int64_t numPackets{ 0 };
|
|
302
|
+
int64_t numLostPackets{ 0 };
|
|
303
|
+
int64_t numReceivedPackets{ 0 };
|
|
304
|
+
int64_t sendingRate{ 0 };
|
|
305
|
+
int64_t sizeBytes{ 0 };
|
|
306
|
+
int64_t lostSizeBytes{ 0 };
|
|
307
|
+
int64_t id{ -1 };
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Feedback accumulated so far, which becomes an observation once it covers
|
|
312
|
+
* a long enough span of send times.
|
|
313
|
+
*/
|
|
314
|
+
struct PartialObservation
|
|
315
|
+
{
|
|
316
|
+
/**
|
|
317
|
+
* Size of the packets reported as lost, by sequence number, so that a
|
|
318
|
+
* packet reported lost and received later stops counting.
|
|
319
|
+
*/
|
|
320
|
+
ankerl::unordered_dense::map<int64_t, int64_t> lostPackets;
|
|
321
|
+
int64_t numPackets{ 0 };
|
|
322
|
+
int64_t sizeBytes{ 0 };
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* The bitrate the estimate is not allowed to grow above while holding, and
|
|
327
|
+
* for how long.
|
|
328
|
+
*/
|
|
329
|
+
struct HoldInfo
|
|
330
|
+
{
|
|
331
|
+
int64_t atUs{ 0 };
|
|
332
|
+
int64_t durationUs{ 0 };
|
|
333
|
+
int64_t bitrate{ Types::BitrateInfinite };
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
public:
|
|
337
|
+
LossBasedController();
|
|
338
|
+
|
|
339
|
+
explicit LossBasedController(LossBasedControllerOptions options);
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Whether enough has been observed for this controller to say anything.
|
|
343
|
+
*/
|
|
344
|
+
bool IsReady() const;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Whether this controller may take the estimate over while the target is
|
|
348
|
+
* still in its start phase.
|
|
349
|
+
*/
|
|
350
|
+
bool IsReadyToUseInStartPhase() const;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Whether this controller is allowed to be used during the start phase at
|
|
354
|
+
* all, regardless of whether it has observed enough to say anything.
|
|
355
|
+
*/
|
|
356
|
+
bool IsUsedInStartPhase() const
|
|
357
|
+
{
|
|
358
|
+
return this->options.useInStartPhase;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Forget everything observed so far, which is what a link that is not the
|
|
363
|
+
* same one anymore calls for.
|
|
364
|
+
*/
|
|
365
|
+
void Reset();
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Latest estimate, or the delay based one while this controller cannot say
|
|
369
|
+
* anything yet.
|
|
370
|
+
*/
|
|
371
|
+
Result GetResult() const;
|
|
372
|
+
|
|
373
|
+
void SetAcknowledgedBitrate(int64_t acknowledgedBitrate);
|
|
374
|
+
|
|
375
|
+
void SetBitrateLimits(int64_t minBitrate, int64_t maxBitrate);
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Place the estimate at the given bitrate.
|
|
379
|
+
*/
|
|
380
|
+
void SetBitrateEstimate(int64_t bitrate);
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Feed the results of a feedback message.
|
|
384
|
+
*
|
|
385
|
+
* @param delayBasedEstimate - Estimate of the delay based path, which
|
|
386
|
+
* bounds this one, or `Types::BitrateInfinite` if there is none.
|
|
387
|
+
* @param inAlr - Whether the sender is not sending enough to fill the link,
|
|
388
|
+
* in which case the acknowledged bitrate says nothing about its capacity.
|
|
389
|
+
*/
|
|
390
|
+
void UpdateBitrateEstimate(
|
|
391
|
+
const std::vector<Types::PacketResult>& packetResults, int64_t delayBasedEstimate, bool inAlr);
|
|
392
|
+
|
|
393
|
+
private:
|
|
394
|
+
/**
|
|
395
|
+
* Add the given results to the observation being accumulated, and close it
|
|
396
|
+
* if it already covers a long enough span of send times.
|
|
397
|
+
*
|
|
398
|
+
* @returns Whether an observation was closed, which is when the estimate
|
|
399
|
+
* can be recalculated.
|
|
400
|
+
*/
|
|
401
|
+
bool PushBackObservation(const std::vector<Types::PacketResult>& packetResults);
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Candidates to try on this update, each already within bounds.
|
|
405
|
+
*/
|
|
406
|
+
std::vector<ChannelParameters> GetCandidates(bool inAlr) const;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Highest bitrate a candidate may have.
|
|
410
|
+
*/
|
|
411
|
+
int64_t GetCandidateBitrateUpperBound() const;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* How likely the losses observed are if the link were as the given pair of
|
|
415
|
+
* values says, plus the bias towards higher bitrates.
|
|
416
|
+
*/
|
|
417
|
+
double GetObjective(const ChannelParameters& channelParameters) const;
|
|
418
|
+
|
|
419
|
+
Derivatives GetDerivatives(const ChannelParameters& channelParameters) const;
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Refine the inherent loss of the given candidate.
|
|
423
|
+
*/
|
|
424
|
+
void ApplyNewtonsMethod(ChannelParameters& channelParameters) const;
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Bring the inherent loss of the given candidate within what a link at its
|
|
428
|
+
* bitrate could plausibly have.
|
|
429
|
+
*/
|
|
430
|
+
double GetFeasibleInherentLoss(const ChannelParameters& channelParameters) const;
|
|
431
|
+
|
|
432
|
+
double GetInherentLossUpperBound(int64_t bitrate) const;
|
|
433
|
+
|
|
434
|
+
double AdjustBiasFactor(double lossRate, double biasFactor) const;
|
|
435
|
+
|
|
436
|
+
double GetHighBitrateBias(int64_t bitrate) const;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Sending rate an observation is taken to have, which is its own smoothed
|
|
440
|
+
* with the one of the previous observation.
|
|
441
|
+
*/
|
|
442
|
+
int64_t GetSendingRate(int64_t instantSendingRate) const;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Average loss observed over the window, leaving out the highest and the
|
|
446
|
+
* lowest so that a single spike doesn't drag it.
|
|
447
|
+
*/
|
|
448
|
+
void UpdateAverageReportedLossRatio();
|
|
449
|
+
|
|
450
|
+
double CalculateAverageReportedPacketLossRatio() const;
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* The same by bytes, which tells a lost packet carrying a full frame apart
|
|
454
|
+
* from one carrying almost nothing.
|
|
455
|
+
*/
|
|
456
|
+
double CalculateAverageReportedByteLossRatio() const;
|
|
457
|
+
|
|
458
|
+
int64_t GetMedianSendingRate() const;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Bound that the observed loss puts on the estimate right away, without
|
|
462
|
+
* waiting for it to converge.
|
|
463
|
+
*/
|
|
464
|
+
int64_t GetImmediateUpperBoundBitrate() const;
|
|
465
|
+
|
|
466
|
+
void CalculateImmediateUpperBoundBitrate();
|
|
467
|
+
|
|
468
|
+
int64_t GetImmediateLowerBoundBitrate() const;
|
|
469
|
+
|
|
470
|
+
void CalculateImmediateLowerBoundBitrate();
|
|
471
|
+
|
|
472
|
+
void CalculateTemporalWeights();
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Whether the link is loss limited at all, which is what tells this
|
|
476
|
+
* controller's estimate apart from just following the delay based one.
|
|
477
|
+
*/
|
|
478
|
+
bool IsInLossLimitedState() const;
|
|
479
|
+
|
|
480
|
+
bool IsEstimateIncreasingWhenLossLimited(int64_t oldEstimate, int64_t newEstimate) const;
|
|
481
|
+
|
|
482
|
+
private:
|
|
483
|
+
// Passed by argument.
|
|
484
|
+
const LossBasedControllerOptions options;
|
|
485
|
+
// Others.
|
|
486
|
+
// Observations of the window, indexed by their id modulo its size.
|
|
487
|
+
std::vector<Observation> observations;
|
|
488
|
+
// Weight of an observation per observation of age.
|
|
489
|
+
std::vector<double> temporalWeights;
|
|
490
|
+
// The same, for the average observed loss.
|
|
491
|
+
std::vector<double> immediateUpperBoundTemporalWeights;
|
|
492
|
+
struct PartialObservation partialObservation;
|
|
493
|
+
struct ChannelParameters currentBestEstimate;
|
|
494
|
+
struct HoldInfo lastHoldInfo;
|
|
495
|
+
struct Result result;
|
|
496
|
+
// Observations closed so far, which never decreases and hence also gives
|
|
497
|
+
// the id of the next one.
|
|
498
|
+
int64_t numObservations{ 0 };
|
|
499
|
+
// Highest send time of the latest observation, which is the clock this
|
|
500
|
+
// controller runs on. Feedback is the only thing that moves it.
|
|
501
|
+
std::optional<int64_t> lastSendTimeOfLatestObservationUs;
|
|
502
|
+
double averageReportedLossRatio{ 0.0 };
|
|
503
|
+
int64_t acknowledgedBitrate{ Types::BitrateInfinite };
|
|
504
|
+
int64_t delayBasedEstimate{ Types::BitrateInfinite };
|
|
505
|
+
int64_t minBitrate{ 0 };
|
|
506
|
+
int64_t maxBitrate{ Types::BitrateInfinite };
|
|
507
|
+
std::optional<int64_t> immediateUpperBoundBitrate;
|
|
508
|
+
std::optional<int64_t> immediateLowerBoundBitrate;
|
|
509
|
+
// Bitrate the estimate may not grow above until the window that follows a
|
|
510
|
+
// decrease is over.
|
|
511
|
+
int64_t bitrateLimitInCurrentWindow{ Types::BitrateInfinite };
|
|
512
|
+
std::optional<int64_t> recoveringAfterLossAtUs;
|
|
513
|
+
// Instant at which the estimate was last brought down, which is what the
|
|
514
|
+
// rampup acceleration grows from.
|
|
515
|
+
std::optional<int64_t> lastBitrateReducedAtUs;
|
|
516
|
+
};
|
|
517
|
+
} // namespace BWE
|
|
518
|
+
} // namespace RTC
|
|
519
|
+
|
|
520
|
+
#endif
|