mediasoup 3.28.0 → 3.29.0

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.
Files changed (155) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/node/lib/PipeTransportTypes.d.ts +6 -1
  3. package/node/lib/PipeTransportTypes.d.ts.map +1 -1
  4. package/node/lib/PlainTransportTypes.d.ts +6 -1
  5. package/node/lib/PlainTransportTypes.d.ts.map +1 -1
  6. package/node/lib/Router.d.ts +4 -4
  7. package/node/lib/Router.d.ts.map +1 -1
  8. package/node/lib/Router.js +10 -7
  9. package/node/lib/RouterTypes.d.ts +7 -1
  10. package/node/lib/RouterTypes.d.ts.map +1 -1
  11. package/node/lib/Transport.d.ts +2 -1
  12. package/node/lib/Transport.d.ts.map +1 -1
  13. package/node/lib/Transport.js +17 -6
  14. package/node/lib/TransportTypes.d.ts +12 -2
  15. package/node/lib/TransportTypes.d.ts.map +1 -1
  16. package/node/lib/WebRtcTransportTypes.d.ts +6 -1
  17. package/node/lib/WebRtcTransportTypes.d.ts.map +1 -1
  18. package/node/lib/fbs/transport/options.d.ts +6 -2
  19. package/node/lib/fbs/transport/options.d.ts.map +1 -1
  20. package/node/lib/fbs/transport/options.js +19 -7
  21. package/node/lib/fbs/transport/sctp-zero-checksum.d.ts +6 -0
  22. package/node/lib/fbs/transport/sctp-zero-checksum.d.ts.map +1 -0
  23. package/node/lib/fbs/transport/sctp-zero-checksum.js +11 -0
  24. package/node/lib/fbs/transport/stats.d.ts +2 -8
  25. package/node/lib/fbs/transport/stats.d.ts.map +1 -1
  26. package/node/lib/fbs/transport/stats.js +5 -29
  27. package/node/lib/fbs/transport.d.ts +1 -0
  28. package/node/lib/fbs/transport.d.ts.map +1 -1
  29. package/node/lib/fbs/transport.js +4 -2
  30. package/npm-scripts.mjs +35 -44
  31. package/package.json +10 -6
  32. package/worker/fbs/transport.fbs +9 -2
  33. package/worker/fuzzer/src/RTC/RTP/FuzzerRetransmissionBuffer.cpp +14 -1
  34. package/worker/fuzzer/src/RTC/RTP/FuzzerRtpStreamSend.cpp +17 -4
  35. package/worker/include/RTC/BWE/AimdRateControl.hpp +9 -9
  36. package/worker/include/RTC/BWE/BweTypes.hpp +54 -17
  37. package/worker/include/RTC/BWE/DelayBasedBwe.hpp +3 -3
  38. package/worker/include/RTC/BWE/FeedbackAdapter.hpp +2 -2
  39. package/worker/include/RTC/BWE/LossBasedController.hpp +4 -4
  40. package/worker/include/RTC/BWE/OveruseDetector.hpp +5 -4
  41. package/worker/include/RTC/BWE/ProbeBitrateEstimator.hpp +1 -1
  42. package/worker/include/RTC/BWE/ProbeController.hpp +6 -6
  43. package/worker/include/RTC/BWE/ProbePacketGenerator.hpp +2 -6
  44. package/worker/include/RTC/BWE/ProbingScheduler.hpp +3 -7
  45. package/worker/include/RTC/BWE/ReceiverTransportCongestionController.hpp +148 -0
  46. package/worker/include/RTC/BWE/RembGenerator.hpp +4 -3
  47. package/worker/include/RTC/BWE/RemoteBitrateEstimatorAbsSendTime.hpp +1 -1
  48. package/worker/include/RTC/BWE/SenderTransportCongestionController.hpp +343 -0
  49. package/worker/include/RTC/BWE/TargetRateController.hpp +4 -1
  50. package/worker/include/RTC/BWE/TransportWideCcFeedbackGenerator.hpp +5 -4
  51. package/worker/include/RTC/BWE/TrendlineEstimator.hpp +3 -3
  52. package/worker/include/RTC/Consumer.hpp +8 -1
  53. package/worker/include/RTC/RTP/RetransmissionBuffer.hpp +36 -10
  54. package/worker/include/RTC/RTP/RtpStream.hpp +21 -0
  55. package/worker/include/RTC/RTP/RtpStreamRecv.hpp +1 -0
  56. package/worker/include/RTC/RTP/RtpStreamSend.hpp +122 -9
  57. package/worker/include/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp +12 -3
  58. package/worker/include/RTC/TransportCongestionControlClient.hpp +0 -5
  59. package/worker/include/RTC/TransportCongestionControlServer.hpp +0 -5
  60. package/worker/include/Utils.hpp +9 -2
  61. package/worker/meson.build +4 -0
  62. package/worker/src/RTC/BWE/AimdRateControl.cpp +22 -22
  63. package/worker/src/RTC/BWE/DelayBasedBwe.cpp +16 -20
  64. package/worker/src/RTC/BWE/FeedbackAdapter.cpp +1 -1
  65. package/worker/src/RTC/BWE/OveruseDetector.cpp +8 -8
  66. package/worker/src/RTC/BWE/ProbeBitrateEstimator.cpp +2 -2
  67. package/worker/src/RTC/BWE/ProbeController.cpp +1 -1
  68. package/worker/src/RTC/BWE/ProbePacketGenerator.cpp +1 -6
  69. package/worker/src/RTC/BWE/ProbingScheduler.cpp +2 -7
  70. package/worker/src/RTC/BWE/ReceiverTransportCongestionController.cpp +207 -0
  71. package/worker/src/RTC/BWE/RembGenerator.cpp +1 -1
  72. package/worker/src/RTC/BWE/RemoteBitrateEstimatorAbsSendTime.cpp +1 -1
  73. package/worker/src/RTC/BWE/SenderTransportCongestionController.cpp +599 -0
  74. package/worker/src/RTC/BWE/TransportWideCcFeedbackGenerator.cpp +2 -3
  75. package/worker/src/RTC/BWE/TrendlineEstimator.cpp +5 -5
  76. package/worker/src/RTC/Consumer.cpp +3 -2
  77. package/worker/src/RTC/DataConsumer.cpp +2 -2
  78. package/worker/src/RTC/RTP/RetransmissionBuffer.cpp +21 -8
  79. package/worker/src/RTC/RTP/RtpStream.cpp +0 -3
  80. package/worker/src/RTC/RTP/RtpStreamRecv.cpp +57 -71
  81. package/worker/src/RTC/RTP/RtpStreamSend.cpp +428 -244
  82. package/worker/src/RTC/RTP/RtxStream.cpp +14 -19
  83. package/worker/src/RTC/SCTP/association/Association.cpp +3 -2
  84. package/worker/src/RTC/SCTP/association/StateCookie.cpp +26 -6
  85. package/worker/src/RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.cpp +4 -3
  86. package/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp +2 -1
  87. package/worker/src/RTC/SCTP/tx/RetransmissionQueue.cpp +4 -2
  88. package/worker/src/RTC/Transport.cpp +49 -20
  89. package/worker/src/RTC/TransportCongestionControlClient.cpp +0 -66
  90. package/worker/src/RTC/TransportCongestionControlServer.cpp +0 -55
  91. package/worker/src/Utils/Crypto.cpp +114 -98
  92. package/worker/subprojects/catch2.wrap +6 -6
  93. package/worker/subprojects/openssl.wrap +11 -12
  94. package/worker/subprojects/packagefiles/ankerl-unordered-dense/meson.build +1 -1
  95. package/worker/subprojects/unordered-dense.wrap +4 -4
  96. package/worker/test/src/RTC/BWE/TestDelayBasedBwe.cpp +5 -5
  97. package/worker/test/src/RTC/BWE/TestFeedbackAdapter.cpp +26 -23
  98. package/worker/test/src/RTC/BWE/TestInterArrivalDelta.cpp +8 -8
  99. package/worker/test/src/RTC/BWE/TestOveruseDetector.cpp +4 -4
  100. package/worker/test/src/RTC/BWE/TestProbeController.cpp +35 -32
  101. package/worker/test/src/RTC/BWE/TestProbePacketGenerator.cpp +2 -17
  102. package/worker/test/src/RTC/BWE/TestProbingScheduler.cpp +1 -25
  103. package/worker/test/src/RTC/BWE/TestReceiverTransportCongestionController.cpp +346 -0
  104. package/worker/test/src/RTC/BWE/TestRembGenerator.cpp +1 -1
  105. package/worker/test/src/RTC/BWE/TestRemoteBitrateEstimatorAbsSendTime.cpp +9 -9
  106. package/worker/test/src/RTC/BWE/TestSenderTransportCongestionController.cpp +510 -0
  107. package/worker/test/src/RTC/BWE/TestTransportWideCcFeedbackGenerator.cpp +16 -14
  108. package/worker/test/src/RTC/BWE/TestTrendlineEstimator.cpp +6 -6
  109. package/worker/test/src/RTC/BWE/helpers/RemoteBitrateEstimatorAbsSendTimeTestHelper.cpp +1 -2
  110. package/worker/test/src/RTC/RTCP/TestBye.cpp +1 -1
  111. package/worker/test/src/RTC/RTCP/TestFeedbackPsAfb.cpp +1 -1
  112. package/worker/test/src/RTC/RTCP/TestFeedbackPsFir.cpp +1 -1
  113. package/worker/test/src/RTC/RTCP/TestFeedbackPsLei.cpp +1 -1
  114. package/worker/test/src/RTC/RTCP/TestFeedbackPsPli.cpp +1 -1
  115. package/worker/test/src/RTC/RTCP/TestFeedbackPsRemb.cpp +1 -1
  116. package/worker/test/src/RTC/RTCP/TestFeedbackPsRpsi.cpp +1 -1
  117. package/worker/test/src/RTC/RTCP/TestFeedbackPsSli.cpp +1 -1
  118. package/worker/test/src/RTC/RTCP/TestFeedbackPsTst.cpp +1 -1
  119. package/worker/test/src/RTC/RTCP/TestFeedbackPsVbcm.cpp +1 -1
  120. package/worker/test/src/RTC/RTCP/TestFeedbackRtpEcn.cpp +1 -1
  121. package/worker/test/src/RTC/RTCP/TestFeedbackRtpNack.cpp +1 -1
  122. package/worker/test/src/RTC/RTCP/TestFeedbackRtpSrReq.cpp +1 -1
  123. package/worker/test/src/RTC/RTCP/TestFeedbackRtpTllei.cpp +1 -1
  124. package/worker/test/src/RTC/RTCP/TestFeedbackRtpTmmb.cpp +1 -1
  125. package/worker/test/src/RTC/RTCP/TestFeedbackRtpTransport.cpp +1 -1
  126. package/worker/test/src/RTC/RTCP/TestReceiverReport.cpp +1 -1
  127. package/worker/test/src/RTC/RTCP/TestSenderReport.cpp +1 -1
  128. package/worker/test/src/RTC/RTP/TestRetransmissionBuffer.cpp +60 -28
  129. package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +1 -1
  130. package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +746 -24
  131. package/worker/test/src/RTC/RTP/TestSharedPacket.cpp +1 -1
  132. package/worker/test/src/RTC/SCTP/association/TestAssociation.cpp +42 -0
  133. package/worker/test/src/RTC/SCTP/association/TestNegotiatedCapabilities.cpp +54 -5
  134. package/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +80 -15
  135. package/worker/test/src/RTC/SCTP/association/TestStreamResetHandler.cpp +410 -3
  136. package/worker/test/src/RTC/SCTP/association/TestTransmissionControlBlock.cpp +1 -1
  137. package/worker/test/src/RTC/SCTP/packet/parameters/TestZeroChecksumAcceptableParameter.cpp +37 -5
  138. package/worker/test/src/RTC/SCTP/rx/TestDataTracker.cpp +5 -4
  139. package/worker/test/src/RTC/SCTP/rx/TestInterleavedReassemblyStreams.cpp +1 -1
  140. package/worker/test/src/RTC/SCTP/rx/TestReassemblyQueue.cpp +1 -1
  141. package/worker/test/src/RTC/SCTP/rx/TestTraditionalReassemblyStreams.cpp +1 -1
  142. package/worker/test/src/RTC/SCTP/tx/TestOutstandingData.cpp +1 -1
  143. package/worker/test/src/RTC/SCTP/tx/TestRetransmissionQueue.cpp +11 -10
  144. package/worker/test/src/RTC/SCTP/tx/TestRetransmissionTimeout.cpp +1 -1
  145. package/worker/test/src/RTC/TestNackGenerator.cpp +1 -1
  146. package/worker/test/src/RTC/TestPortManager.cpp +2 -2
  147. package/worker/test/src/RTC/TestRateCalculator.cpp +1 -1
  148. package/worker/test/src/RTC/TestRemoteCaptureTimeEstimator.cpp +21 -15
  149. package/worker/test/src/RTC/TestRemoteClockOffsetEstimator.cpp +13 -13
  150. package/worker/test/src/RTC/TestRtpEncodingParameters.cpp +1 -1
  151. package/worker/test/src/RTC/TestSubchannelsCodec.cpp +2 -2
  152. package/worker/test/src/RTC/TestTransportCongestionControlServer.cpp +1 -1
  153. package/worker/test/src/RTC/TestTransportTuple.cpp +3 -2
  154. package/worker/test/src/Utils/TestCrypto.cpp +71 -2
  155. package/worker/test/src/Utils/TestTime.cpp +2 -2
@@ -0,0 +1,599 @@
1
+ #define MS_CLASS "RTC::BWE::SenderTransportCongestionController"
2
+ // #define MS_LOG_DEV_LEVEL 3
3
+
4
+ #include "RTC/BWE/SenderTransportCongestionController.hpp"
5
+ #include "Logger.hpp"
6
+ #include "RTC/BWE/BitrateUtils.hpp"
7
+
8
+ namespace RTC
9
+ {
10
+ namespace BWE
11
+ {
12
+ /* Static. */
13
+
14
+ // How often everything that depends on time rather than on an arrival is run.
15
+ // The shortest deadline it has to meet is the interval the loss based
16
+ // controller waits before lowering the target again, so it is a good deal
17
+ // finer than that.
18
+ static constexpr int64_t ProcessIntervalMs{ 100 };
19
+ // How far below the throughput a probe result may drag the estimate. A probe
20
+ // far below what is already acknowledged is unlikely to be measuring the
21
+ // link, but dropping to slightly below the throughput is what drains the
22
+ // queues when there really is an overuse.
23
+ static constexpr double ProbeDropThroughputFraction{ 0.85 };
24
+
25
+ /* Static methods. */
26
+
27
+ /**
28
+ * What is holding the target back, which is what tells the probe controller
29
+ * whether a probe would make any sense right now.
30
+ */
31
+ static ProbeController::BandwidthLimitedCause getBandwidthLimitedCause(
32
+ LossBasedController::State lossBasedState,
33
+ bool isRttAboveLimit,
34
+ Types::BandwidthUsage bandwidthUsage)
35
+ {
36
+ if (bandwidthUsage == Types::BandwidthUsage::OVERUSING || bandwidthUsage == Types::BandwidthUsage::UNDERUSING)
37
+ {
38
+ return ProbeController::BandwidthLimitedCause::DELAY_BASED_LIMITED_DELAY_INCREASED;
39
+ }
40
+
41
+ if (isRttAboveLimit)
42
+ {
43
+ return ProbeController::BandwidthLimitedCause::RTT_BASED_BACK_OFF_HIGH_RTT;
44
+ }
45
+
46
+ switch (lossBasedState)
47
+ {
48
+ case LossBasedController::State::DECREASING:
49
+ {
50
+ // No probe is sent in this state.
51
+ return ProbeController::BandwidthLimitedCause::LOSS_LIMITED_BWE;
52
+ }
53
+
54
+ case LossBasedController::State::INCREASING:
55
+ {
56
+ // Probes may be sent in this state.
57
+ return ProbeController::BandwidthLimitedCause::LOSS_LIMITED_BWE_INCREASING;
58
+ }
59
+
60
+ case LossBasedController::State::DELAY_BASED_ESTIMATE:
61
+ {
62
+ return ProbeController::BandwidthLimitedCause::DELAY_BASED_LIMITED;
63
+ }
64
+
65
+ NO_DEFAULT();
66
+ }
67
+ }
68
+
69
+ /* Instance methods. */
70
+
71
+ SenderTransportCongestionController::SenderTransportCongestionController(
72
+ Listener* listener, SharedInterface* shared, SenderTransportCongestionControllerOptions options)
73
+ : listener(listener),
74
+ shared(shared),
75
+ processTimer(shared->CreateTimer(this, "sender-transport-congestion-controller-process")),
76
+ feedbackAdapter(std::addressof(this->sendPacketHistory)),
77
+ alrDetector(shared),
78
+ // An SFU forwards what others produce and cannot make more of it, so it
79
+ // spends most of its time not filling the link. Without probing there, the
80
+ // target would only grow when the traffic being forwarded happens to fill
81
+ // it, and after a quiet spell the first stream admitted would be measured
82
+ // against a figure from long ago.
83
+ probeController({ .enablePeriodicAlrProbing = true }),
84
+ probingScheduler(this, shared),
85
+ startBitrate(options.startBitrate)
86
+ {
87
+ MS_TRACE();
88
+
89
+ this->minBitrate = options.minBitrate;
90
+ this->maxBitrate = options.maxBitrate;
91
+
92
+ ResetConstraints(this->shared->GetTimeUs(), /*applyStartBitrate*/ true);
93
+
94
+ // NOTE: Safe to apply from a constructor, where the listener must not be
95
+ // called: the only thing that can be pending at this point is a burst,
96
+ // which goes to a member of this class, since `MayNotifyTargetBitrate()`
97
+ // is not called from here and so there is no target to announce.
98
+ ApplyPendingUpdate();
99
+
100
+ this->processTimer->Start(ProcessIntervalMs, ProcessIntervalMs);
101
+ }
102
+
103
+ void SenderTransportCongestionController::SetNetworkAvailable(bool networkAvailable)
104
+ {
105
+ MS_TRACE();
106
+
107
+ const int64_t nowUs = this->shared->GetTimeUs();
108
+
109
+ AddProbeClusters(this->probeController.OnNetworkAvailability(networkAvailable, nowUs));
110
+
111
+ ApplyPendingUpdate();
112
+ }
113
+
114
+ std::optional<int64_t> SenderTransportCongestionController::OnRtpPacketToBeSent(
115
+ RTC::RTP::Packet* packet, const RtpPacketToBeSentOptions& options)
116
+ {
117
+ MS_TRACE();
118
+
119
+ return AddRtpPacket(packet, options, /*probeCluster*/ std::nullopt);
120
+ }
121
+
122
+ void SenderTransportCongestionController::OnRtpPacketSent(
123
+ std::optional<int64_t> sequenceNumber, size_t size, int64_t sentAtUs)
124
+ {
125
+ MS_TRACE();
126
+
127
+ // A packet that was never taken note of still took room in the link, so its
128
+ // bytes are attributed to the next one that does carry a sequence number.
129
+ if (!sequenceNumber.has_value())
130
+ {
131
+ this->sendPacketHistory.ProcessSentUntrackedPacket(size + this->packetOverhead, sentAtUs);
132
+
133
+ return;
134
+ }
135
+
136
+ const auto sentPacket =
137
+ this->sendPacketHistory.ProcessSentPacket(sequenceNumber.value(), sentAtUs);
138
+
139
+ // Nothing is known about a packet the history does not hold, so there is
140
+ // nothing to tell anybody about it either.
141
+ if (!sentPacket.has_value())
142
+ {
143
+ return;
144
+ }
145
+
146
+ const auto& sentPacketValue = sentPacket.value();
147
+
148
+ this->alrDetector.OnBytesSent(static_cast<int64_t>(sentPacketValue.size), sentAtUs);
149
+ this->acknowledgedBitrateEstimator.SetAlr(this->alrDetector.GetAlrStartTimeUs().has_value());
150
+
151
+ if (!this->firstPacketSent)
152
+ {
153
+ this->firstPacketSent = true;
154
+
155
+ // Until a feedback arrives there is no round trip to measure, so the
156
+ // instant the first packet left is taken as the start of one. Without
157
+ // this the backoff by round trip time would have nothing to work with
158
+ // during the first seconds.
159
+ this->targetRateController.UpdatePropagationRtt(0, sentAtUs);
160
+ }
161
+
162
+ this->targetRateController.OnPacketSent(sentAtUs);
163
+ }
164
+
165
+ void SenderTransportCongestionController::ReceiveTransportWideCcFeedback(
166
+ const RTC::RTCP::FeedbackRtpTransportPacket* feedback, int64_t receivedAtUs)
167
+ {
168
+ MS_TRACE();
169
+
170
+ const auto processedFeedback =
171
+ this->feedbackAdapter.ProcessTransportWideCcFeedback(feedback, receivedAtUs);
172
+
173
+ if (!processedFeedback.has_value())
174
+ {
175
+ return;
176
+ }
177
+
178
+ const auto& transportPacketsFeedback = processedFeedback.value();
179
+
180
+ if (transportPacketsFeedback.packetFeedbacks.empty())
181
+ {
182
+ return;
183
+ }
184
+
185
+ // Something reports back, so the estimation is ours to do and not the
186
+ // remote endpoint's.
187
+ this->firstTransportFeedbackReceived = true;
188
+
189
+ const int64_t feedbackTimeUs = transportPacketsFeedback.feedbackTimeUs;
190
+ const auto receivedWithSendInfo = transportPacketsFeedback.ReceivedWithSendInfo();
191
+
192
+ // The round trip of the whole feedback is the time since the oldest packet
193
+ // it reports on left, minus how long the rest of them waited at the remote
194
+ // endpoint before it decided to report. Taking the smallest of those is
195
+ // what leaves the propagation alone, without the wait.
196
+ //
197
+ // NOTE: Every packet below has an arrival time, since only the ones that
198
+ // were received are in `ReceivedWithSendInfo()`.
199
+ int64_t minPropagationRttUs{ Types::TimeUsInfinite };
200
+ int64_t maxReceiveTimeUs{ 0 };
201
+
202
+ for (const auto& packetResult : receivedWithSendInfo)
203
+ {
204
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
205
+ maxReceiveTimeUs = std::max(maxReceiveTimeUs, packetResult.receiveTimeUs.value());
206
+ }
207
+
208
+ for (const auto& packetResult : receivedWithSendInfo)
209
+ {
210
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
211
+ const int64_t receiveTimeUs = packetResult.receiveTimeUs.value();
212
+ const int64_t feedbackRttUs = feedbackTimeUs - packetResult.sentPacket.sendTimeUs;
213
+ const int64_t minPendingTimeUs = maxReceiveTimeUs - receiveTimeUs;
214
+ const int64_t propagationRttUs = feedbackRttUs - minPendingTimeUs;
215
+
216
+ minPropagationRttUs = std::min(minPropagationRttUs, propagationRttUs);
217
+ }
218
+
219
+ if (!receivedWithSendInfo.empty())
220
+ {
221
+ this->targetRateController.UpdatePropagationRtt(minPropagationRttUs, feedbackTimeUs);
222
+ }
223
+
224
+ const auto alrStartTimeUs = this->alrDetector.GetAlrStartTimeUs();
225
+
226
+ // Leaving the state has to be told to both of them, since each one holds
227
+ // its own idea of when it ended.
228
+ if (this->previouslyInAlr && !alrStartTimeUs.has_value())
229
+ {
230
+ this->acknowledgedBitrateEstimator.SetAlrEndedTimeUs(feedbackTimeUs);
231
+ this->probeController.SetAlrEndedTimeUs(feedbackTimeUs);
232
+ }
233
+
234
+ this->previouslyInAlr = alrStartTimeUs.has_value();
235
+
236
+ this->acknowledgedBitrateEstimator.IncomingPacketFeedbackVector(
237
+ transportPacketsFeedback.SortedByReceiveTime());
238
+
239
+ const auto acknowledgedBitrate = this->acknowledgedBitrateEstimator.GetBitrate();
240
+
241
+ this->targetRateController.SetAcknowledgedBitrate(
242
+ acknowledgedBitrate.value_or(Types::BitrateInfinite));
243
+
244
+ for (const auto& packetResult : transportPacketsFeedback.SortedByReceiveTime())
245
+ {
246
+ if (packetResult.sentPacket.probeCluster.has_value())
247
+ {
248
+ this->probeBitrateEstimator.HandleProbeAndEstimateBitrate(packetResult);
249
+ }
250
+ }
251
+
252
+ auto probeBitrate = this->probeBitrateEstimator.FetchAndResetLastEstimatedBitrate();
253
+
254
+ // A probe that measured far below what is already acknowledged is not
255
+ // measuring the link, so the drop it would cause is bounded.
256
+ if (probeBitrate.has_value() && acknowledgedBitrate.has_value())
257
+ {
258
+ const int64_t limit = std::min(
259
+ this->delayBasedBwe.GetLastEstimate(),
260
+ BitrateUtils::ApplyBitrateFactor(acknowledgedBitrate.value(), ProbeDropThroughputFraction));
261
+
262
+ probeBitrate = std::max(probeBitrate.value(), limit);
263
+ }
264
+
265
+ const auto result = this->delayBasedBwe.IncomingPacketFeedbackVector(
266
+ transportPacketsFeedback,
267
+ acknowledgedBitrate,
268
+ probeBitrate,
269
+ /*networkEstimate*/ std::nullopt,
270
+ alrStartTimeUs.has_value());
271
+
272
+ if (result.updated)
273
+ {
274
+ // A probe result replaces the estimate instead of nudging it, and that
275
+ // has to happen before the delay based estimate is handed over, since
276
+ // setting it clears what the delay based path had.
277
+ if (result.probe)
278
+ {
279
+ this->targetRateController.SetSendBitrate(result.targetBitrate);
280
+ }
281
+
282
+ this->targetRateController.SetDelayBasedEstimate(result.targetBitrate);
283
+ }
284
+
285
+ this->targetRateController.UpdateLossBasedController(
286
+ transportPacketsFeedback.packetFeedbacks, alrStartTimeUs.has_value(), feedbackTimeUs);
287
+
288
+ if (result.updated)
289
+ {
290
+ MayNotifyTargetBitrate(feedbackTimeUs);
291
+ }
292
+
293
+ // Coming out of an overuse is the one moment where a probe is worth it
294
+ // without waiting for anything else.
295
+ if (result.recoveredFromOveruse)
296
+ {
297
+ this->probeController.SetAlrStartTimeUs(alrStartTimeUs);
298
+
299
+ AddProbeClusters(this->probeController.RequestProbe(feedbackTimeUs));
300
+ }
301
+
302
+ ApplyPendingUpdate();
303
+ }
304
+
305
+ void SenderTransportCongestionController::ReceiveRtcpReceiverReport(
306
+ int64_t lostPackets, int64_t expectedPackets)
307
+ {
308
+ MS_TRACE();
309
+
310
+ // Nothing moved since the previous report, so there is no stretch of the
311
+ // stream to work a loss ratio out of.
312
+ if (expectedPackets < 1)
313
+ {
314
+ return;
315
+ }
316
+
317
+ // Not a single packet got through. That is not a loss ratio of one but a
318
+ // stretch the remote endpoint could not report on, so it is left out rather
319
+ // than fed as the worst possible measurement.
320
+ if (expectedPackets - lostPackets < 1)
321
+ {
322
+ return;
323
+ }
324
+
325
+ this->targetRateController.UpdatePacketsLost(
326
+ lostPackets, expectedPackets, this->shared->GetTimeUs());
327
+ }
328
+
329
+ void SenderTransportCongestionController::ReceiveEstimatedBitrate(int64_t bitrate)
330
+ {
331
+ MS_TRACE();
332
+
333
+ this->targetRateController.SetReceiverEstimate(bitrate);
334
+ }
335
+
336
+ void SenderTransportCongestionController::OnRttUpdate(int64_t rttUs)
337
+ {
338
+ MS_TRACE();
339
+
340
+ // NOTE: The round trip is taken in whole milliseconds, which is the
341
+ // resolution the thresholds it is compared against are expressed in.
342
+ const int64_t roundedRttUs = Utils::Time::TimeUsToMs(rttUs) * 1000;
343
+
344
+ if (roundedRttUs == 0)
345
+ {
346
+ return;
347
+ }
348
+
349
+ this->delayBasedBwe.OnRttUpdate(roundedRttUs);
350
+ this->targetRateController.UpdateRtt(roundedRttUs);
351
+ }
352
+
353
+ void SenderTransportCongestionController::SetBitrateLimits(int64_t minBitrate, int64_t maxBitrate)
354
+ {
355
+ MS_TRACE();
356
+
357
+ const int64_t nowUs = this->shared->GetTimeUs();
358
+
359
+ this->minBitrate = minBitrate;
360
+ this->maxBitrate = maxBitrate;
361
+
362
+ ResetConstraints(nowUs, /*applyStartBitrate*/ false);
363
+
364
+ MayNotifyTargetBitrate(nowUs);
365
+
366
+ ApplyPendingUpdate();
367
+ }
368
+
369
+ void SenderTransportCongestionController::SetDesiredBitrate(int64_t desiredBitrate)
370
+ {
371
+ MS_TRACE();
372
+
373
+ const int64_t nowUs = this->shared->GetTimeUs();
374
+
375
+ AddProbeClusters(this->probeController.OnMaxTotalAllocatedBitrate(desiredBitrate, nowUs));
376
+
377
+ ApplyPendingUpdate();
378
+ }
379
+
380
+ void SenderTransportCongestionController::SetPacketOverhead(size_t packetOverhead)
381
+ {
382
+ MS_TRACE();
383
+
384
+ this->packetOverhead = packetOverhead;
385
+
386
+ this->probingScheduler.SetPacketOverhead(packetOverhead);
387
+ }
388
+
389
+ int64_t SenderTransportCongestionController::GetAvailableBitrate() const
390
+ {
391
+ MS_TRACE();
392
+
393
+ return this->targetRateController.GetTargetBitrate();
394
+ }
395
+
396
+ void SenderTransportCongestionController::OnProbingSchedulerSendRtpPacket(
397
+ ProbingScheduler* /*probingScheduler*/,
398
+ RTC::RTP::Packet* packet,
399
+ const Types::ProbeCluster& probeCluster)
400
+ {
401
+ MS_TRACE();
402
+
403
+ // The generator leaves room for both extensions but writes neither, and
404
+ // since it reuses a single packet what is left unwritten is whatever the
405
+ // previous one carried.
406
+ const auto sequenceNumber = AddRtpPacket(packet, RtpPacketToBeSentOptions{}, probeCluster);
407
+
408
+ // The generator builds every packet with room for both extensions, so
409
+ // there is always a sequence number to hand over.
410
+ MS_ASSERT(sequenceNumber.has_value(), "probe packet has no transport wide sequence number");
411
+
412
+ this->listener->OnSenderTransportCongestionControllerSendRtpProbePacket(
413
+ this, packet, sequenceNumber.value());
414
+ }
415
+
416
+ void SenderTransportCongestionController::OnTimer(TimerHandleInterface* timer)
417
+ {
418
+ MS_TRACE();
419
+
420
+ if (timer == this->processTimer.get())
421
+ {
422
+ Process();
423
+ }
424
+ }
425
+
426
+ std::optional<int64_t> SenderTransportCongestionController::AddRtpPacket(
427
+ RTC::RTP::Packet* packet,
428
+ const RtpPacketToBeSentOptions& options,
429
+ std::optional<Types::ProbeCluster> probeCluster)
430
+ {
431
+ MS_TRACE();
432
+
433
+ // Whatever the packet carries there now, which is only read to find out
434
+ // whether it has room for the sequence number at all. Without it the
435
+ // remote endpoint cannot report on this packet, so taking note of it
436
+ // would only fill the history with entries no feedback can ever name.
437
+ uint16_t previousWideSeqNumber{ 0 };
438
+
439
+ if (!packet->ReadTransportWideCc01(previousWideSeqNumber))
440
+ {
441
+ return std::nullopt;
442
+ }
443
+
444
+ const int64_t nowUs = this->shared->GetTimeUs();
445
+
446
+ const int64_t sequenceNumber = this->sendPacketHistory.AddPacket(
447
+ SendPacketHistory::AddPacketOptions{
448
+ .ssrc = packet->GetSsrc(),
449
+ .seq = packet->GetSequenceNumber(),
450
+ // What the link carries is the packet plus everything below RTP, so
451
+ // that is what the rate control has to reason about.
452
+ .size = packet->GetLength() + this->packetOverhead,
453
+ .isAudio = options.isAudio,
454
+ .isRetransmission = options.isRetransmission,
455
+ .originalSsrc = options.originalSsrc,
456
+ .probeCluster = probeCluster,
457
+ .createdAtUs = nowUs });
458
+
459
+ packet->UpdateTransportWideCc01(static_cast<uint16_t>(sequenceNumber));
460
+ packet->UpdateAbsSendTime(Utils::Time::TimeUsToAbsSendTime(nowUs));
461
+
462
+ return sequenceNumber;
463
+ }
464
+
465
+ void SenderTransportCongestionController::Process()
466
+ {
467
+ MS_TRACE();
468
+
469
+ const int64_t nowUs = this->shared->GetTimeUs();
470
+
471
+ this->targetRateController.Update(nowUs);
472
+
473
+ // Probing while the remote endpoint is the one estimating would be probing
474
+ // something nobody is measuring, so it waits for the first feedback.
475
+ this->probeController.SetAlrStartTimeUs(
476
+ this->firstTransportFeedbackReceived ? this->alrDetector.GetAlrStartTimeUs() : std::nullopt);
477
+
478
+ AddProbeClusters(this->probeController.Process(nowUs));
479
+
480
+ MayNotifyTargetBitrate(nowUs);
481
+
482
+ ApplyPendingUpdate();
483
+ }
484
+
485
+ void SenderTransportCongestionController::AddProbeClusters(
486
+ const std::vector<Types::ProbeClusterConfig>& clusterConfigs)
487
+ {
488
+ MS_TRACE();
489
+
490
+ this->pendingUpdate.probeClusterConfigs.insert(
491
+ this->pendingUpdate.probeClusterConfigs.end(), clusterConfigs.begin(), clusterConfigs.end());
492
+ }
493
+
494
+ void SenderTransportCongestionController::ApplyPendingUpdate()
495
+ {
496
+ MS_TRACE();
497
+
498
+ // Taken out before anything leaves this class, so that a listener calling
499
+ // back in starts a cycle of its own instead of finding this one half
500
+ // applied.
501
+ const auto probeClusterConfigs = std::move(this->pendingUpdate.probeClusterConfigs);
502
+ const auto targetBitrateToNotify = this->pendingUpdate.targetBitrateToNotify;
503
+
504
+ this->pendingUpdate = {};
505
+
506
+ if (!probeClusterConfigs.empty())
507
+ {
508
+ this->probingScheduler.CreateProbeClusters(probeClusterConfigs);
509
+ }
510
+
511
+ if (targetBitrateToNotify.has_value())
512
+ {
513
+ this->listener->OnSenderTransportCongestionControllerTargetBitrate(
514
+ this, targetBitrateToNotify.value());
515
+ }
516
+ }
517
+
518
+ void SenderTransportCongestionController::MayNotifyTargetBitrate(int64_t nowUs)
519
+ {
520
+ MS_TRACE();
521
+
522
+ const int64_t targetBitrate = this->targetRateController.GetTargetBitrate();
523
+ const uint8_t fractionLost = this->targetRateController.GetFractionLost();
524
+ const int64_t rttUs = this->targetRateController.GetRttUs();
525
+ const LossBasedController::State lossBasedState =
526
+ this->targetRateController.GetLossBasedState();
527
+ // Not filling the link is not the same as not being able to fill it, and
528
+ // what is announced is whether the link is what holds the sender back.
529
+ const bool isBandwidthLimited = !this->alrDetector.GetAlrStartTimeUs().has_value();
530
+
531
+ // Everything the listener reasons about is compared, since a reallocation
532
+ // is far more expensive than this comparison.
533
+ if (
534
+ this->lastTargetBitrate.has_value() && targetBitrate == this->lastTargetBitrate.value() &&
535
+ fractionLost == this->lastFractionLost && rttUs == this->lastRttUs &&
536
+ lossBasedState == this->lastLossBasedState &&
537
+ isBandwidthLimited == this->lastIsBandwidthLimited)
538
+ {
539
+ return;
540
+ }
541
+
542
+ this->lastTargetBitrate = targetBitrate;
543
+ this->lastFractionLost = fractionLost;
544
+ this->lastRttUs = rttUs;
545
+ this->lastLossBasedState = lossBasedState;
546
+ this->lastIsBandwidthLimited = isBandwidthLimited;
547
+
548
+ this->alrDetector.SetEstimatedBitrate(targetBitrate);
549
+
550
+ AddProbeClusters(this->probeController.SetEstimatedBitrate(
551
+ targetBitrate,
552
+ getBandwidthLimitedCause(
553
+ lossBasedState,
554
+ this->targetRateController.IsRttAboveLimit(),
555
+ this->delayBasedBwe.GetLastState()),
556
+ nowUs));
557
+
558
+ this->pendingUpdate.targetBitrateToNotify = targetBitrate;
559
+ }
560
+
561
+ void SenderTransportCongestionController::ResetConstraints(int64_t nowUs, bool applyStartBitrate)
562
+ {
563
+ MS_TRACE();
564
+
565
+ // Nothing below may be driven to a bitrate it treats as none at all, since
566
+ // with nothing going out there would be nothing left to measure.
567
+ this->minBitrate = std::max(this->minBitrate, RTC::Consts::BweMinBitrate);
568
+
569
+ if (this->maxBitrate < this->minBitrate)
570
+ {
571
+ MS_WARN_TAG(
572
+ bwe,
573
+ "max bitrate is lower than min bitrate [maxBitrate:%" PRIi64 ", minBitrate:%" PRIi64 "]",
574
+ this->maxBitrate,
575
+ this->minBitrate);
576
+
577
+ this->maxBitrate = this->minBitrate;
578
+ }
579
+
580
+ // NOTE: Raised here and not where it is kept, so that the member stays
581
+ // what was configured.
582
+ const int64_t startBitrate =
583
+ applyStartBitrate ? std::max(this->startBitrate, this->minBitrate) : 0;
584
+
585
+ this->targetRateController.SetBitrateLimits(this->minBitrate, this->maxBitrate);
586
+
587
+ this->delayBasedBwe.SetMinBitrate(this->minBitrate);
588
+
589
+ if (applyStartBitrate)
590
+ {
591
+ this->targetRateController.SetSendBitrate(startBitrate);
592
+ this->delayBasedBwe.SetStartBitrate(startBitrate);
593
+ }
594
+
595
+ AddProbeClusters(
596
+ this->probeController.SetBitrates(this->minBitrate, startBitrate, this->maxBitrate, nowUs));
597
+ }
598
+ } // namespace BWE
599
+ } // namespace RTC
@@ -45,7 +45,7 @@ namespace RTC
45
45
  this->sendPeriodicTimer->Start(this->sendIntervalMs, this->sendIntervalMs);
46
46
  }
47
47
 
48
- void TransportWideCcFeedbackGenerator::IncomingPacket(
48
+ void TransportWideCcFeedbackGenerator::ReceiveRtpPacket(
49
49
  int64_t arrivalTimeUs, const RTC::RTP::Packet* packet)
50
50
  {
51
51
  MS_TRACE();
@@ -247,8 +247,7 @@ namespace RTC
247
247
 
248
248
  const auto latestWideSeqNumber = this->feedbackPacket->GetLatestSequenceNumber();
249
249
 
250
- this->listener->OnTransportWideCcFeedbackGeneratorSendRtcpPacket(
251
- this, this->feedbackPacket.get());
250
+ this->listener->OnTransportWideCcFeedbackGeneratorSendPacket(this, this->feedbackPacket.get());
252
251
 
253
252
  this->feedbackWideSeqNumStart = latestWideSeqNumber + 1;
254
253
 
@@ -297,16 +297,16 @@ namespace RTC
297
297
  {
298
298
  MS_TRACE();
299
299
 
300
- if (!this->lastThresholdUpdateAtUs.has_value())
300
+ if (!this->lastSampleArrivalTimeUs.has_value())
301
301
  {
302
- this->lastThresholdUpdateAtUs = arrivalTimeUs;
302
+ this->lastSampleArrivalTimeUs = arrivalTimeUs;
303
303
  }
304
304
 
305
305
  // Avoid adapting the threshold to big latency spikes, caused for instance
306
306
  // by a sudden capacity drop.
307
307
  if (std::fabs(modifiedTrend) > this->threshold + MaxAdaptOffset)
308
308
  {
309
- this->lastThresholdUpdateAtUs = arrivalTimeUs;
309
+ this->lastSampleArrivalTimeUs = arrivalTimeUs;
310
310
 
311
311
  return;
312
312
  }
@@ -318,13 +318,13 @@ namespace RTC
318
318
  // NOTE: The coefficients above are rates per millisecond, so the step is
319
319
  // expressed in those units no matter that the instants are microseconds.
320
320
  const double elapsedMs = std::min(
321
- static_cast<double>(arrivalTimeUs - this->lastThresholdUpdateAtUs.value()) / 1000.0,
321
+ static_cast<double>(arrivalTimeUs - this->lastSampleArrivalTimeUs.value()) / 1000.0,
322
322
  static_cast<double>(MaxThresholdUpdateDeltaMs));
323
323
 
324
324
  this->threshold += coef * (std::fabs(modifiedTrend) - this->threshold) * elapsedMs;
325
325
  this->threshold = std::clamp(this->threshold, ThresholdMin, ThresholdMax);
326
326
 
327
- this->lastThresholdUpdateAtUs = arrivalTimeUs;
327
+ this->lastSampleArrivalTimeUs = arrivalTimeUs;
328
328
  }
329
329
  } // namespace BWE
330
330
  } // namespace RTC
@@ -1526,13 +1526,14 @@ namespace RTC
1526
1526
  }
1527
1527
  }
1528
1528
 
1529
- void Consumer::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report, int64_t receivedAtUs)
1529
+ std::optional<RTC::RTP::RtpStreamSend::Loss> Consumer::ReceiveRtcpReceiverReport(
1530
+ RTC::RTCP::ReceiverReport* report, int64_t receivedAtUs)
1530
1531
  {
1531
1532
  MS_TRACE();
1532
1533
 
1533
1534
  auto* rtpStream = this->mapSsrcRtpStream.at(report->GetSsrc());
1534
1535
 
1535
- rtpStream->ReceiveRtcpReceiverReport(report, receivedAtUs);
1536
+ return rtpStream->ReceiveRtcpReceiverReport(report, receivedAtUs);
1536
1537
  }
1537
1538
 
1538
1539
  void Consumer::ReceiveRtcpXrReceiverReferenceTime(
@@ -598,8 +598,8 @@ namespace RTC
598
598
  MS_WARN_TAG(
599
599
  message,
600
600
  "message exceeds maxMessageSize value [maxMessageSize:%zu, len:%zu]",
601
- messageLen,
602
- this->maxMessageSize);
601
+ this->maxMessageSize,
602
+ messageLen);
603
603
 
604
604
  if (cb)
605
605
  {