mediasoup 3.27.0 → 3.28.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.
- package/CHANGELOG.md +19 -0
- package/node/lib/Consumer.d.ts.map +1 -1
- package/node/lib/Consumer.js +4 -51
- package/node/lib/Producer.d.ts.map +1 -1
- package/node/lib/Producer.js +4 -8
- package/node/lib/ProducerTypes.d.ts +4 -2
- package/node/lib/ProducerTypes.d.ts.map +1 -1
- package/node/lib/Router.d.ts.map +1 -1
- package/node/lib/Router.js +4 -0
- package/node/lib/Transport.d.ts.map +1 -1
- package/node/lib/Transport.js +7 -10
- package/node/lib/fbs/rtp-parameters/rtp-header-extension-uri.d.ts +3 -4
- package/node/lib/fbs/rtp-parameters/rtp-header-extension-uri.d.ts.map +1 -1
- package/node/lib/fbs/rtp-parameters/rtp-header-extension-uri.js +3 -4
- package/node/lib/ortc.d.ts +0 -2
- package/node/lib/ortc.d.ts.map +1 -1
- package/node/lib/ortc.js +11 -21
- package/node/lib/rtpMappingFbsUtils.d.ts +6 -0
- package/node/lib/rtpMappingFbsUtils.d.ts.map +1 -0
- package/node/lib/rtpMappingFbsUtils.js +65 -0
- package/node/lib/rtpParametersFbsUtils.d.ts.map +1 -1
- package/node/lib/rtpParametersFbsUtils.js +0 -6
- package/node/lib/rtpParametersTypes.d.ts +1 -1
- package/node/lib/rtpParametersTypes.d.ts.map +1 -1
- package/node/lib/rtpStreamFbsUtils.d.ts +4 -0
- package/node/lib/rtpStreamFbsUtils.d.ts.map +1 -0
- package/node/lib/rtpStreamFbsUtils.js +51 -0
- package/node/lib/supportedRtpCapabilities.d.ts.map +1 -1
- package/node/lib/supportedRtpCapabilities.js +6 -13
- package/node/lib/test/test-Consumer.js +1 -13
- package/node/lib/test/test-DataConsumer.js +9 -0
- package/node/lib/test/test-DataProducer.js +38 -0
- package/node/lib/test/test-PipeTransport.js +27 -29
- package/node/lib/test/test-Producer.js +97 -0
- package/node/lib/test/test-ortc.js +34 -14
- package/package.json +10 -10
- package/worker/fbs/FBS/meson.build +25 -0
- package/worker/fbs/meson.build +15 -18
- package/worker/fbs/rtpParameters.fbs +0 -1
- package/worker/fuzzer/src/FuzzerUtils.cpp +5 -3
- package/worker/fuzzer/src/RTC/RTP/FuzzerPacket.cpp +16 -2
- package/worker/include/DepLibUV.hpp +13 -0
- package/worker/include/RTC/BWE/AlrDetector.hpp +97 -0
- package/worker/include/RTC/BWE/BitrateProber.hpp +217 -0
- package/worker/include/RTC/BWE/BitrateUtils.hpp +39 -0
- package/worker/include/RTC/BWE/BweTypes.hpp +171 -3
- package/worker/include/RTC/BWE/FeedbackAdapter.hpp +0 -14
- package/worker/include/RTC/BWE/InterArrival.hpp +117 -0
- package/worker/include/RTC/BWE/IntervalBudget.hpp +81 -0
- package/worker/include/RTC/BWE/LossBasedController.hpp +625 -0
- package/worker/include/RTC/BWE/OveruseDetector.hpp +71 -0
- package/worker/include/RTC/BWE/OveruseEstimator.hpp +115 -0
- package/worker/include/RTC/BWE/ProbeBitrateEstimator.hpp +84 -0
- package/worker/include/RTC/BWE/ProbeController.hpp +379 -0
- package/worker/include/RTC/BWE/ProbePacketGenerator.hpp +130 -0
- package/worker/include/RTC/BWE/ProbingScheduler.hpp +187 -0
- package/worker/include/RTC/BWE/RembGenerator.hpp +96 -0
- package/worker/include/RTC/BWE/RemoteBitrateEstimatorAbsSendTime.hpp +237 -0
- package/worker/include/RTC/BWE/RobustThroughputEstimator.hpp +26 -0
- package/worker/include/RTC/BWE/SendPacketHistory.hpp +161 -25
- package/worker/include/RTC/BWE/TargetRateController.hpp +306 -0
- package/worker/include/RTC/BWE/TransportWideCcFeedbackGenerator.hpp +146 -0
- package/worker/include/RTC/BWE/TrendlineEstimator.hpp +73 -16
- package/worker/include/RTC/Consts.hpp +70 -0
- package/worker/include/RTC/DataConsumer.hpp +3 -5
- package/worker/include/RTC/DirectTransport.hpp +4 -5
- package/worker/include/RTC/PipeTransport.hpp +4 -5
- package/worker/include/RTC/PlainTransport.hpp +4 -5
- package/worker/include/RTC/RTCP/FeedbackPsRemb.hpp +6 -7
- package/worker/include/RTC/RTCP/FeedbackRtpTransport.hpp +3 -1
- package/worker/include/RTC/RTP/Codecs/Tools.hpp +1 -1
- package/worker/include/RTC/RTP/HeaderExtensionIds.hpp +0 -1
- package/worker/include/RTC/RTP/Packet.hpp +16 -4
- package/worker/include/RTC/RTP/ProbationGenerator.hpp +0 -8
- package/worker/include/RTC/RTP/RtpStream.hpp +12 -9
- package/worker/include/RTC/RTP/RtpStreamRecv.hpp +22 -4
- package/worker/include/RTC/RTP/RtpStreamSend.hpp +4 -2
- package/worker/include/RTC/RTP/RtxStream.hpp +10 -4
- package/worker/include/RTC/RateCalculator.hpp +103 -24
- package/worker/include/RTC/RemoteCaptureTimeEstimator.hpp +33 -3
- package/worker/include/RTC/{RtcLogger.hpp → RtcLogger/RtpPacket.hpp} +5 -3
- package/worker/include/RTC/RtcLogger/SendBurst.hpp +88 -0
- package/worker/include/RTC/RtpDictionaries.hpp +3 -4
- package/worker/include/RTC/SCTP/association/Association.hpp +1 -1
- package/worker/include/RTC/SCTP/association/StreamResetHandler.hpp +36 -0
- package/worker/include/RTC/SCTP/public/AssociationMetrics.hpp +0 -1
- package/worker/include/RTC/SCTP/public/SctpTypes.hpp +9 -9
- package/worker/include/RTC/SCTP/rx/DataTracker.hpp +1 -1
- package/worker/include/RTC/SCTP/rx/ReassemblyQueue.hpp +11 -1
- package/worker/include/RTC/SctpDictionaries.hpp +2 -2
- package/worker/include/RTC/TcpConnection.hpp +2 -1
- package/worker/include/RTC/Transport.hpp +23 -8
- package/worker/include/RTC/TransportTuple.hpp +61 -6
- package/worker/include/RTC/WebRtcTransport.hpp +4 -5
- package/worker/include/Shared.hpp +5 -0
- package/worker/include/SharedInterface.hpp +10 -0
- package/worker/include/Utils.hpp +72 -3
- package/worker/include/common.hpp +12 -4
- package/worker/include/handles/SendCallbacks.hpp +34 -0
- package/worker/include/handles/TcpConnectionHandle.hpp +4 -12
- package/worker/include/handles/UdpSocketHandle.hpp +4 -8
- package/worker/meson.build +45 -1
- package/worker/meson_options.txt +1 -0
- package/worker/mocks/include/MockShared.hpp +16 -2
- package/worker/mocks/include/handles/MockBackoffTimerHandle.hpp +1 -1
- package/worker/scripts/package-lock.json +6 -6
- package/worker/src/RTC/BWE/AimdRateControl.cpp +4 -5
- package/worker/src/RTC/BWE/AlrDetector.cpp +80 -0
- package/worker/src/RTC/BWE/BitrateProber.cpp +256 -0
- package/worker/src/RTC/BWE/BitrateUtils.cpp +54 -0
- package/worker/src/RTC/BWE/DelayBasedBwe.cpp +2 -2
- package/worker/src/RTC/BWE/FeedbackAdapter.cpp +20 -37
- package/worker/src/RTC/BWE/InterArrival.cpp +216 -0
- package/worker/src/RTC/BWE/IntervalBudget.cpp +93 -0
- package/worker/src/RTC/BWE/LossBasedController.cpp +1194 -0
- package/worker/src/RTC/BWE/OveruseDetector.cpp +128 -0
- package/worker/src/RTC/BWE/OveruseEstimator.cpp +166 -0
- package/worker/src/RTC/BWE/ProbeBitrateEstimator.cpp +222 -0
- package/worker/src/RTC/BWE/ProbeController.cpp +645 -0
- package/worker/src/RTC/BWE/ProbePacketGenerator.cpp +140 -0
- package/worker/src/RTC/BWE/ProbingScheduler.cpp +196 -0
- package/worker/src/RTC/BWE/RembGenerator.cpp +169 -0
- package/worker/src/RTC/BWE/RemoteBitrateEstimatorAbsSendTime.cpp +497 -0
- package/worker/src/RTC/BWE/RobustThroughputEstimator.cpp +47 -0
- package/worker/src/RTC/BWE/SendPacketHistory.cpp +173 -50
- package/worker/src/RTC/BWE/TargetRateController.cpp +433 -0
- package/worker/src/RTC/BWE/TransportWideCcFeedbackGenerator.cpp +377 -0
- package/worker/src/RTC/BWE/TrendlineEstimator.cpp +102 -5
- package/worker/src/RTC/Consumer.cpp +7 -5
- package/worker/src/RTC/DataConsumer.cpp +8 -10
- package/worker/src/RTC/DirectTransport.cpp +14 -8
- package/worker/src/RTC/DtlsTransport.cpp +8 -8
- package/worker/src/RTC/ICE/IceCandidate.cpp +4 -4
- package/worker/src/RTC/ICE/IceServer.cpp +1 -1
- package/worker/src/RTC/PipeTransport.cpp +13 -8
- package/worker/src/RTC/PlainTransport.cpp +13 -8
- package/worker/src/RTC/Producer.cpp +14 -31
- package/worker/src/RTC/RTCP/Bye.cpp +1 -1
- package/worker/src/RTC/RTCP/FeedbackPsRemb.cpp +18 -0
- package/worker/src/RTC/RTCP/FeedbackPsRpsi.cpp +2 -2
- package/worker/src/RTC/RTCP/FeedbackPsVbcm.cpp +2 -1
- package/worker/src/RTC/RTCP/FeedbackRtpTransport.cpp +2 -2
- package/worker/src/RTC/RTCP/Sdes.cpp +1 -1
- package/worker/src/RTC/RTP/Codecs/DependencyDescriptor.cpp +2 -1
- package/worker/src/RTC/RTP/Packet.cpp +26 -11
- package/worker/src/RTC/RTP/ProbationGenerator.cpp +5 -6
- package/worker/src/RTC/RTP/RtpStream.cpp +1 -1
- package/worker/src/RTC/RTP/RtpStreamRecv.cpp +69 -48
- package/worker/src/RTC/RTP/RtpStreamSend.cpp +31 -31
- package/worker/src/RTC/RTP/RtxStream.cpp +22 -7
- package/worker/src/RTC/RateCalculator.cpp +133 -28
- package/worker/src/RTC/RemoteCaptureTimeEstimator.cpp +56 -1
- package/worker/src/RTC/{RtcLogger.cpp → RtcLogger/RtpPacket.cpp} +2 -2
- package/worker/src/RTC/RtcLogger/SendBurst.cpp +124 -0
- package/worker/src/RTC/RtpDictionaries/RtpHeaderExtensionUri.cpp +2 -12
- package/worker/src/RTC/RtpDictionaries/RtpParameters.cpp +1 -1
- package/worker/src/RTC/SCTP/association/Association.cpp +16 -2
- package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +106 -1
- package/worker/src/RTC/SCTP/public/AssociationMetrics.cpp +1 -1
- package/worker/src/RTC/SCTP/rx/InterleavedReassemblyStreams.cpp +3 -3
- package/worker/src/RTC/SCTP/rx/ReassemblyQueue.cpp +2 -1
- package/worker/src/RTC/SCTP/rx/TraditionalReassemblyStreams.cpp +4 -4
- package/worker/src/RTC/SCTP/tx/RetransmissionTimeout.cpp +4 -4
- package/worker/src/RTC/SctpDictionaries/SctpStreamParameters.cpp +6 -10
- package/worker/src/RTC/SimulcastProducerStreamManager.cpp +2 -2
- package/worker/src/RTC/SrtpSession.cpp +2 -2
- package/worker/src/RTC/SvcProducerStreamManager.cpp +2 -2
- package/worker/src/RTC/TcpConnection.cpp +2 -2
- package/worker/src/RTC/Transport.cpp +112 -75
- package/worker/src/RTC/TransportTuple.cpp +4 -4
- package/worker/src/RTC/WebRtcServer.cpp +4 -3
- package/worker/src/RTC/WebRtcTransport.cpp +20 -13
- package/worker/src/Utils/BitStream.cpp +24 -0
- package/worker/src/handles/BackoffTimerHandle.cpp +1 -1
- package/worker/src/handles/TcpConnectionHandle.cpp +13 -23
- package/worker/src/handles/UdpSocketHandle.cpp +14 -21
- package/worker/tasks.py +43 -18
- package/worker/test/include/RTC/BWE/helpers/LinkSimulator.hpp +68 -14
- package/worker/test/include/RTC/BWE/helpers/RemoteBitrateEstimatorAbsSendTimeTestHelper.hpp +125 -0
- package/worker/test/src/RTC/BWE/TestAlrDetector.cpp +110 -0
- package/worker/test/src/RTC/BWE/TestBitrateProber.cpp +418 -0
- package/worker/test/src/RTC/BWE/TestBitrateUtils.cpp +61 -0
- package/worker/test/src/RTC/BWE/TestDelayBasedBwe.cpp +4 -4
- package/worker/test/src/RTC/BWE/TestFeedbackAdapter.cpp +53 -37
- package/worker/test/src/RTC/BWE/TestInterArrival.cpp +643 -0
- package/worker/test/src/RTC/BWE/TestIntervalBudget.cpp +130 -0
- package/worker/test/src/RTC/BWE/TestLossBasedController.cpp +1199 -0
- package/worker/test/src/RTC/BWE/TestOveruseDetector.cpp +519 -0
- package/worker/test/src/RTC/BWE/TestProbeBitrateEstimator.cpp +266 -0
- package/worker/test/src/RTC/BWE/TestProbeController.cpp +1682 -0
- package/worker/test/src/RTC/BWE/TestProbePacketGenerator.cpp +265 -0
- package/worker/test/src/RTC/BWE/TestProbingScheduler.cpp +260 -0
- package/worker/test/src/RTC/BWE/TestRembGenerator.cpp +285 -0
- package/worker/test/src/RTC/BWE/TestRemoteBitrateEstimatorAbsSendTime.cpp +414 -0
- package/worker/test/src/RTC/BWE/TestSendPacketHistory.cpp +296 -77
- package/worker/test/src/RTC/BWE/TestTargetRateController.cpp +337 -0
- package/worker/test/src/RTC/BWE/TestTransportWideCcFeedbackGenerator.cpp +578 -0
- package/worker/test/src/RTC/BWE/TestTrendlineEstimator.cpp +45 -0
- package/worker/test/src/RTC/BWE/helpers/LinkSimulator.cpp +133 -29
- package/worker/test/src/RTC/BWE/helpers/RemoteBitrateEstimatorAbsSendTimeTestHelper.cpp +625 -0
- package/worker/test/src/RTC/RTCP/TestFeedbackPsRemb.cpp +19 -0
- package/worker/test/src/RTC/RTP/TestPacket.cpp +58 -4
- package/worker/test/src/RTC/RTP/TestProbationGenerator.cpp +3 -2
- package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +50 -0
- package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +59 -0
- package/worker/test/src/RTC/SCTP/association/TestStreamResetHandler.cpp +111 -0
- package/worker/test/src/RTC/TestRateCalculator.cpp +322 -60
- package/worker/test/src/RTC/TestRemoteCaptureTimeEstimator.cpp +95 -7
- package/worker/test/src/RTC/TestSimpleProducerStreamManager.cpp +34 -16
- package/worker/test/src/RTC/TestSimulcastProducerStreamManager.cpp +31 -13
- package/worker/test/src/RTC/TestSvcProducerStreamManager.cpp +37 -19
- package/worker/test/src/RTC/TestTransportCongestionControlServer.cpp +10 -10
- package/worker/test/src/Utils/TestTime.cpp +120 -21
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
#define MS_CLASS "RTC::BWE::RemoteBitrateEstimatorAbsSendTime"
|
|
2
|
+
// #define MS_LOG_DEV_LEVEL 3
|
|
3
|
+
|
|
4
|
+
#include "RTC/BWE/RemoteBitrateEstimatorAbsSendTime.hpp"
|
|
5
|
+
#include "Logger.hpp"
|
|
6
|
+
#include "Utils.hpp"
|
|
7
|
+
#include <cstdlib> // std::abs()
|
|
8
|
+
|
|
9
|
+
namespace RTC
|
|
10
|
+
{
|
|
11
|
+
namespace BWE
|
|
12
|
+
{
|
|
13
|
+
/* Static. */
|
|
14
|
+
|
|
15
|
+
// Shortest gap between two probes for it to be taken as measurable rather
|
|
16
|
+
// than as two packets that left together.
|
|
17
|
+
static constexpr int64_t MinClusterDeltaUs{ 1000 };
|
|
18
|
+
// How long after the first packet bursts are still looked for even though
|
|
19
|
+
// there already is an estimation.
|
|
20
|
+
static constexpr int64_t InitialProbingIntervalUs{ 2 * 1000 * 1000 };
|
|
21
|
+
// Every packet whose send timestamp is within this many milliseconds of the
|
|
22
|
+
// first one of a group belongs to that group.
|
|
23
|
+
static constexpr int64_t TimestampGroupLengthMs{ 5 };
|
|
24
|
+
// The 'abs-send-time' extension carries 24 bits with 18 of fraction, and it
|
|
25
|
+
// is shifted up so that it fills the 32 bits the inter arrival works with and
|
|
26
|
+
// wraps the way they do.
|
|
27
|
+
static constexpr uint32_t AbsSendTimeFraction{ 18 };
|
|
28
|
+
static constexpr uint32_t AbsSendTimeInterArrivalUpshift{ 8 };
|
|
29
|
+
static constexpr uint32_t InterArrivalShift{ AbsSendTimeFraction +
|
|
30
|
+
AbsSendTimeInterArrivalUpshift };
|
|
31
|
+
// Microseconds a single tick of those shifted timestamps is worth.
|
|
32
|
+
static constexpr double TimestampToUs{ 1000000.0 / static_cast<double>(1 << InterArrivalShift) };
|
|
33
|
+
// Fewest probes a run must hold to be taken as a burst.
|
|
34
|
+
static constexpr int MinClusterSize{ 4 };
|
|
35
|
+
// Most probes kept while looking for a burst.
|
|
36
|
+
static constexpr size_t MaxProbePackets{ 15 };
|
|
37
|
+
// How many runs are enough to give up on the probes seen so far.
|
|
38
|
+
static constexpr size_t ExpectedNumberOfProbes{ 3 };
|
|
39
|
+
// Smallest packet taken as paced by the sender, since anything smaller is
|
|
40
|
+
// likely audio, which is not.
|
|
41
|
+
static constexpr size_t MinProbePacketSize{ 200 };
|
|
42
|
+
// How long a stream may be silent before it stops counting.
|
|
43
|
+
static constexpr int64_t StreamTimeOutUs{ 2 * 1000 * 1000 };
|
|
44
|
+
// Window of the meter of incoming data.
|
|
45
|
+
static constexpr int64_t IncomingBitrateWindowMs{ 1000 };
|
|
46
|
+
// Number of items that meter splits its window into, one per millisecond of
|
|
47
|
+
// it. The rate it reports is what the estimation drops to on an overuse, so
|
|
48
|
+
// a coarser item makes the edge of the window take in or let go of a whole
|
|
49
|
+
// frame of the measured stream several milliseconds off, which moves the
|
|
50
|
+
// estimation by as much as that frame is worth.
|
|
51
|
+
static constexpr uint16_t IncomingBitrateWindowItems{ 1000 };
|
|
52
|
+
// Widest gap between a send delta and the mean of the run it is compared
|
|
53
|
+
// against for both to be taken as the same burst.
|
|
54
|
+
static constexpr int64_t MaxClusterDeviationUs{ 2500 };
|
|
55
|
+
// How much longer the arrival deltas of a burst may be than its send deltas,
|
|
56
|
+
// and how much shorter, for the burst to say anything about the link.
|
|
57
|
+
static constexpr int64_t MaxReceiveDeltaExcessUs{ 2000 };
|
|
58
|
+
static constexpr int64_t MaxSendDeltaExcessUs{ 5000 };
|
|
59
|
+
|
|
60
|
+
static_assert(
|
|
61
|
+
IncomingBitrateWindowItems == IncomingBitrateWindowMs,
|
|
62
|
+
"the meter of incoming data needs one item per millisecond of its window");
|
|
63
|
+
|
|
64
|
+
/* Instance methods. */
|
|
65
|
+
|
|
66
|
+
RemoteBitrateEstimatorAbsSendTime::RemoteBitrateEstimatorAbsSendTime(Listener* listener)
|
|
67
|
+
: listener(listener),
|
|
68
|
+
incomingRateCalculator(
|
|
69
|
+
IncomingBitrateWindowMs, RTC::RateCalculator::DefaultBpsScale, IncomingBitrateWindowItems)
|
|
70
|
+
{
|
|
71
|
+
MS_TRACE();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
void RemoteBitrateEstimatorAbsSendTime::IncomingPacket(
|
|
75
|
+
const RTC::RTP::Packet* packet, int64_t arrivalTimeUs, int64_t nowUs)
|
|
76
|
+
{
|
|
77
|
+
MS_TRACE();
|
|
78
|
+
|
|
79
|
+
uint32_t sendTime24bits{ 0 };
|
|
80
|
+
|
|
81
|
+
if (!packet->ReadAbsSendTime(sendTime24bits))
|
|
82
|
+
{
|
|
83
|
+
MS_WARN_DEV("packet is missing the abs-send-time extension, ignoring it");
|
|
84
|
+
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const size_t payloadSize = packet->GetPayloadLength() + packet->GetPaddingLength();
|
|
89
|
+
|
|
90
|
+
// Shift up the send time to use the full 32 bits the inter arrival works
|
|
91
|
+
// with, so that wrapping works properly.
|
|
92
|
+
const uint32_t timestamp = sendTime24bits << AbsSendTimeInterArrivalUpshift;
|
|
93
|
+
|
|
94
|
+
// NOTE: Truncated rather than rounded, which is not a slip. A tick of this
|
|
95
|
+
// field is 3.8 us, so a burst whose packets left exactly a millisecond
|
|
96
|
+
// apart gives deltas that land a hair under or over it. Truncating leaves
|
|
97
|
+
// enough of them at or above the millisecond for the burst to be taken as
|
|
98
|
+
// one, and rounding does not.
|
|
99
|
+
const auto sendTimeUs = static_cast<int64_t>(static_cast<double>(timestamp) * TimestampToUs);
|
|
100
|
+
|
|
101
|
+
// Tell whether the meter of incoming data still has something to say, and
|
|
102
|
+
// start it over when it doesn't.
|
|
103
|
+
const auto incomingBitrateValue = this->incomingRateCalculator.GetRate(arrivalTimeUs / 1000);
|
|
104
|
+
|
|
105
|
+
if (incomingBitrateValue.has_value())
|
|
106
|
+
{
|
|
107
|
+
this->incomingBitrateInitialized = true;
|
|
108
|
+
}
|
|
109
|
+
else if (this->incomingBitrateInitialized)
|
|
110
|
+
{
|
|
111
|
+
// It had a valid value before, but there are no longer enough samples
|
|
112
|
+
// within its window. Start it over so that the window only holds new
|
|
113
|
+
// data.
|
|
114
|
+
this->incomingRateCalculator.Reset();
|
|
115
|
+
|
|
116
|
+
this->incomingBitrateInitialized = false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this->incomingRateCalculator.Update(payloadSize, arrivalTimeUs / 1000);
|
|
120
|
+
|
|
121
|
+
if (!this->firstPacketTimeUs.has_value())
|
|
122
|
+
{
|
|
123
|
+
this->firstPacketTimeUs = nowUs;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
bool updateEstimate{ false };
|
|
127
|
+
int64_t targetBitrate{ 0 };
|
|
128
|
+
|
|
129
|
+
TimeoutStreams(nowUs);
|
|
130
|
+
|
|
131
|
+
// NOTE: Guaranteed by the call right above, which creates both whenever no
|
|
132
|
+
// stream is left. The very first call always finds none, since the only
|
|
133
|
+
// place a stream is put into the map is below this point, and no path ever
|
|
134
|
+
// gives either of them up afterwards.
|
|
135
|
+
MS_ASSERT(this->interArrival, "no inter arrival");
|
|
136
|
+
MS_ASSERT(this->overuseEstimator, "no overuse estimator");
|
|
137
|
+
|
|
138
|
+
this->ssrcs.insert_or_assign(packet->GetSsrc(), nowUs);
|
|
139
|
+
|
|
140
|
+
// For now only try to detect bursts while there is no valid estimation. It
|
|
141
|
+
// is assumed that only packets larger than 200 bytes are paced by the
|
|
142
|
+
// sender.
|
|
143
|
+
if (
|
|
144
|
+
payloadSize > MinProbePacketSize &&
|
|
145
|
+
(!this->remoteRateControl.IsValidEstimate() ||
|
|
146
|
+
// NOTE: It was given a value right above if it had none, which the
|
|
147
|
+
// checker cannot tell.
|
|
148
|
+
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
|
149
|
+
nowUs - this->firstPacketTimeUs.value() < InitialProbingIntervalUs))
|
|
150
|
+
{
|
|
151
|
+
this->probes.push_back(
|
|
152
|
+
Probe{
|
|
153
|
+
.sendTimeUs = sendTimeUs, .receiveTimeUs = arrivalTimeUs, .payloadSize = payloadSize });
|
|
154
|
+
|
|
155
|
+
// Make sure that a burst which updated the estimation right away has an
|
|
156
|
+
// effect, by telling the listener about it.
|
|
157
|
+
if (ProcessClusters(nowUs) == ProbeResult::BITRATE_UPDATED)
|
|
158
|
+
{
|
|
159
|
+
updateEstimate = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const auto deltas =
|
|
164
|
+
this->interArrival->ComputeDeltas(timestamp, arrivalTimeUs, nowUs, payloadSize);
|
|
165
|
+
|
|
166
|
+
if (deltas.has_value())
|
|
167
|
+
{
|
|
168
|
+
const auto sendDeltaMs = (1000.0 * static_cast<double>(deltas.value().timestampDelta)) /
|
|
169
|
+
static_cast<double>(1 << InterArrivalShift);
|
|
170
|
+
const auto arrivalDeltaMs = static_cast<double>(deltas.value().arrivalDeltaUs) / 1000.0;
|
|
171
|
+
|
|
172
|
+
this->overuseEstimator->Update(
|
|
173
|
+
arrivalDeltaMs, sendDeltaMs, deltas.value().sizeDelta, this->overuseDetector.GetState());
|
|
174
|
+
|
|
175
|
+
this->overuseDetector.Detect(
|
|
176
|
+
this->overuseEstimator->GetOffsetMs(),
|
|
177
|
+
sendDeltaMs,
|
|
178
|
+
this->overuseEstimator->GetNumOfDeltas(),
|
|
179
|
+
arrivalTimeUs);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!updateEstimate)
|
|
183
|
+
{
|
|
184
|
+
// Tell whether it's time for a periodic update, or whether there is an
|
|
185
|
+
// overuse to react to right away.
|
|
186
|
+
//
|
|
187
|
+
// NOTE: The wait is measured in whole milliseconds, which is the
|
|
188
|
+
// resolution the interval is expressed in. Microseconds would not be
|
|
189
|
+
// more precise here but a different rule: this is a threshold being
|
|
190
|
+
// crossed, and packets do not arrive on whole milliseconds, so moving
|
|
191
|
+
// the boundary within a millisecond changes which packet crosses it.
|
|
192
|
+
if (
|
|
193
|
+
!this->lastUpdateUs.has_value() ||
|
|
194
|
+
Utils::Time::TimeUsToMs(nowUs) - Utils::Time::TimeUsToMs(this->lastUpdateUs.value()) >
|
|
195
|
+
Utils::Time::TimeUsToMs(this->remoteRateControl.GetFeedbackIntervalUs()))
|
|
196
|
+
{
|
|
197
|
+
updateEstimate = true;
|
|
198
|
+
}
|
|
199
|
+
else if (this->overuseDetector.GetState() == Types::BandwidthUsage::OVERUSING)
|
|
200
|
+
{
|
|
201
|
+
const auto incomingRate = this->incomingRateCalculator.GetRate(arrivalTimeUs / 1000);
|
|
202
|
+
|
|
203
|
+
if (
|
|
204
|
+
incomingRate.has_value() &&
|
|
205
|
+
this->remoteRateControl.IsTimeToReduceFurther(nowUs, incomingRate.value()))
|
|
206
|
+
{
|
|
207
|
+
updateEstimate = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (updateEstimate)
|
|
213
|
+
{
|
|
214
|
+
// The first overuse triggers a new estimation right away, and so does
|
|
215
|
+
// being in overuse with an estimation far above what is coming in.
|
|
216
|
+
const Types::RateControlInput input{
|
|
217
|
+
.bandwidthUsage = this->overuseDetector.GetState(),
|
|
218
|
+
.estimatedThroughput = this->incomingRateCalculator.GetRate(arrivalTimeUs / 1000)
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
targetBitrate = this->remoteRateControl.Update(input, nowUs);
|
|
222
|
+
updateEstimate = this->remoteRateControl.IsValidEstimate();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (updateEstimate)
|
|
226
|
+
{
|
|
227
|
+
this->lastUpdateUs = nowUs;
|
|
228
|
+
|
|
229
|
+
std::vector<uint32_t> ssrcs;
|
|
230
|
+
|
|
231
|
+
ssrcs.reserve(this->ssrcs.size());
|
|
232
|
+
|
|
233
|
+
for (const auto& kv : this->ssrcs)
|
|
234
|
+
{
|
|
235
|
+
const uint32_t ssrc = kv.first;
|
|
236
|
+
|
|
237
|
+
ssrcs.push_back(ssrc);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this->listener->OnRemoteBitrateEstimatorAbsSendTimeBitrateChanged(this, ssrcs, targetBitrate);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t avgRttUs)
|
|
245
|
+
{
|
|
246
|
+
MS_TRACE();
|
|
247
|
+
|
|
248
|
+
this->remoteRateControl.SetRttUs(avgRttUs);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
void RemoteBitrateEstimatorAbsSendTime::RemoveStream(uint32_t ssrc)
|
|
252
|
+
{
|
|
253
|
+
MS_TRACE();
|
|
254
|
+
|
|
255
|
+
this->ssrcs.erase(ssrc);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
int64_t RemoteBitrateEstimatorAbsSendTime::GetLatestEstimate() const
|
|
259
|
+
{
|
|
260
|
+
MS_TRACE();
|
|
261
|
+
|
|
262
|
+
if (!this->remoteRateControl.IsValidEstimate() || this->ssrcs.empty())
|
|
263
|
+
{
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return this->remoteRateControl.GetLatestEstimate();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
bool RemoteBitrateEstimatorAbsSendTime::IsWithinClusterBounds(
|
|
271
|
+
int64_t sendDeltaUs, const Cluster& clusterAggregate)
|
|
272
|
+
{
|
|
273
|
+
MS_TRACE();
|
|
274
|
+
|
|
275
|
+
if (clusterAggregate.count == 0)
|
|
276
|
+
{
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const int64_t clusterMeanUs = clusterAggregate.sendMeanUs / clusterAggregate.count;
|
|
281
|
+
|
|
282
|
+
return std::abs(sendDeltaUs - clusterMeanUs) < MaxClusterDeviationUs;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
void RemoteBitrateEstimatorAbsSendTime::MaybeAddCluster(
|
|
286
|
+
const Cluster& clusterAggregate, std::list<Cluster>& clusters)
|
|
287
|
+
{
|
|
288
|
+
MS_TRACE();
|
|
289
|
+
|
|
290
|
+
if (
|
|
291
|
+
clusterAggregate.count < MinClusterSize || clusterAggregate.sendMeanUs <= 0 ||
|
|
292
|
+
clusterAggregate.receiveMeanUs <= 0)
|
|
293
|
+
{
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
clusters.push_back(
|
|
298
|
+
Cluster{ .sendMeanUs = clusterAggregate.sendMeanUs / clusterAggregate.count,
|
|
299
|
+
.receiveMeanUs = clusterAggregate.receiveMeanUs / clusterAggregate.count,
|
|
300
|
+
.meanSize = clusterAggregate.meanSize / clusterAggregate.count,
|
|
301
|
+
.count = clusterAggregate.count,
|
|
302
|
+
.numAboveMinDelta = clusterAggregate.numAboveMinDelta });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
std::list<RemoteBitrateEstimatorAbsSendTime::Cluster> RemoteBitrateEstimatorAbsSendTime::ComputeClusters() const
|
|
306
|
+
{
|
|
307
|
+
MS_TRACE();
|
|
308
|
+
|
|
309
|
+
std::list<Cluster> clusters;
|
|
310
|
+
Cluster clusterAggregate;
|
|
311
|
+
// NOTE: The two instants a delta is taken against always come from the
|
|
312
|
+
// very same probe, so they are held as one rather than as two values that
|
|
313
|
+
// could tell a different story from each other.
|
|
314
|
+
const Probe* prevProbe{ nullptr };
|
|
315
|
+
|
|
316
|
+
for (const auto& probe : this->probes)
|
|
317
|
+
{
|
|
318
|
+
if (prevProbe)
|
|
319
|
+
{
|
|
320
|
+
const int64_t sendDeltaUs = probe.sendTimeUs - prevProbe->sendTimeUs;
|
|
321
|
+
const int64_t receiveDeltaUs = probe.receiveTimeUs - prevProbe->receiveTimeUs;
|
|
322
|
+
|
|
323
|
+
if (sendDeltaUs >= MinClusterDeltaUs && receiveDeltaUs >= MinClusterDeltaUs)
|
|
324
|
+
{
|
|
325
|
+
clusterAggregate.numAboveMinDelta++;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (!IsWithinClusterBounds(sendDeltaUs, clusterAggregate))
|
|
329
|
+
{
|
|
330
|
+
MaybeAddCluster(clusterAggregate, clusters);
|
|
331
|
+
|
|
332
|
+
clusterAggregate = Cluster();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
clusterAggregate.sendMeanUs += sendDeltaUs;
|
|
336
|
+
clusterAggregate.receiveMeanUs += receiveDeltaUs;
|
|
337
|
+
clusterAggregate.meanSize += probe.payloadSize;
|
|
338
|
+
clusterAggregate.count++;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
prevProbe = std::addressof(probe);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
MaybeAddCluster(clusterAggregate, clusters);
|
|
345
|
+
|
|
346
|
+
return clusters;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const RemoteBitrateEstimatorAbsSendTime::Cluster* RemoteBitrateEstimatorAbsSendTime::FindBestProbe(
|
|
350
|
+
const std::list<Cluster>& clusters) const
|
|
351
|
+
{
|
|
352
|
+
MS_TRACE();
|
|
353
|
+
|
|
354
|
+
int64_t highestProbeBitrate{ 0 };
|
|
355
|
+
const Cluster* best{ nullptr };
|
|
356
|
+
|
|
357
|
+
for (const auto& cluster : clusters)
|
|
358
|
+
{
|
|
359
|
+
// NOTE: This is not redundant with the check MaybeAddCluster() does.
|
|
360
|
+
// That one requires the sums to be positive, but what is stored is
|
|
361
|
+
// their integer division by the number of probes, and a small enough
|
|
362
|
+
// sum over four probes or more gives a mean of zero. This is what keeps
|
|
363
|
+
// the rates below from dividing by it.
|
|
364
|
+
if (cluster.sendMeanUs == 0 || cluster.receiveMeanUs == 0)
|
|
365
|
+
{
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (
|
|
370
|
+
cluster.numAboveMinDelta > cluster.count / 2 &&
|
|
371
|
+
(cluster.receiveMeanUs - cluster.sendMeanUs <= MaxReceiveDeltaExcessUs &&
|
|
372
|
+
cluster.sendMeanUs - cluster.receiveMeanUs <= MaxSendDeltaExcessUs))
|
|
373
|
+
{
|
|
374
|
+
const int64_t probeBitrate =
|
|
375
|
+
std::min(cluster.GetSendBitrate(), cluster.GetReceiveBitrate());
|
|
376
|
+
|
|
377
|
+
if (probeBitrate > highestProbeBitrate)
|
|
378
|
+
{
|
|
379
|
+
highestProbeBitrate = probeBitrate;
|
|
380
|
+
best = std::addressof(cluster);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else
|
|
384
|
+
{
|
|
385
|
+
MS_DEBUG_DEV(
|
|
386
|
+
"burst failed [sendBitrate:%" PRIi64 " bps, receiveBitrate:%" PRIi64
|
|
387
|
+
" bps, sendMean:%" PRIi64 " us, receiveMean:%" PRIi64 " us, numProbes:%d]",
|
|
388
|
+
cluster.GetSendBitrate(),
|
|
389
|
+
cluster.GetReceiveBitrate(),
|
|
390
|
+
cluster.sendMeanUs,
|
|
391
|
+
cluster.receiveMeanUs,
|
|
392
|
+
cluster.count);
|
|
393
|
+
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return best;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
RemoteBitrateEstimatorAbsSendTime::ProbeResult RemoteBitrateEstimatorAbsSendTime::ProcessClusters(
|
|
402
|
+
int64_t nowUs)
|
|
403
|
+
{
|
|
404
|
+
MS_TRACE();
|
|
405
|
+
|
|
406
|
+
const std::list<Cluster> clusters = ComputeClusters();
|
|
407
|
+
|
|
408
|
+
if (clusters.empty())
|
|
409
|
+
{
|
|
410
|
+
// The most probes that are kept have been reached and still no run came
|
|
411
|
+
// out of them, so the oldest one is dropped.
|
|
412
|
+
if (this->probes.size() >= MaxProbePackets)
|
|
413
|
+
{
|
|
414
|
+
this->probes.pop_front();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return ProbeResult::NO_UPDATE;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const auto* best = FindBestProbe(clusters);
|
|
421
|
+
|
|
422
|
+
if (best)
|
|
423
|
+
{
|
|
424
|
+
const int64_t probeBitrate = std::min(best->GetSendBitrate(), best->GetReceiveBitrate());
|
|
425
|
+
|
|
426
|
+
// Make sure that a burst sent at a lower rate than the estimation cannot
|
|
427
|
+
// bring it down.
|
|
428
|
+
if (IsBitrateImproving(probeBitrate))
|
|
429
|
+
{
|
|
430
|
+
MS_DEBUG_DEV(
|
|
431
|
+
"burst successful [sendBitrate:%" PRIi64 " bps, receiveBitrate:%" PRIi64
|
|
432
|
+
" bps, sendMean:%" PRIi64 " us, receiveMean:%" PRIi64 " us, numProbes:%d]",
|
|
433
|
+
best->GetSendBitrate(),
|
|
434
|
+
best->GetReceiveBitrate(),
|
|
435
|
+
best->sendMeanUs,
|
|
436
|
+
best->receiveMeanUs,
|
|
437
|
+
best->count);
|
|
438
|
+
|
|
439
|
+
this->remoteRateControl.SetEstimate(probeBitrate, nowUs);
|
|
440
|
+
|
|
441
|
+
return ProbeResult::BITRATE_UPDATED;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Either not bursting and a regular packet came in, or done with the
|
|
446
|
+
// current set of probes.
|
|
447
|
+
if (clusters.size() >= ExpectedNumberOfProbes)
|
|
448
|
+
{
|
|
449
|
+
this->probes.clear();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return ProbeResult::NO_UPDATE;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
bool RemoteBitrateEstimatorAbsSendTime::IsBitrateImproving(int64_t probeBitrate) const
|
|
456
|
+
{
|
|
457
|
+
MS_TRACE();
|
|
458
|
+
|
|
459
|
+
const bool initialProbe = !this->remoteRateControl.IsValidEstimate() && probeBitrate > 0;
|
|
460
|
+
const bool bitrateAboveEstimate = this->remoteRateControl.IsValidEstimate() &&
|
|
461
|
+
probeBitrate > this->remoteRateControl.GetLatestEstimate();
|
|
462
|
+
|
|
463
|
+
return initialProbe || bitrateAboveEstimate;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
void RemoteBitrateEstimatorAbsSendTime::TimeoutStreams(int64_t nowUs)
|
|
467
|
+
{
|
|
468
|
+
MS_TRACE();
|
|
469
|
+
|
|
470
|
+
for (auto it = this->ssrcs.begin(); it != this->ssrcs.end();)
|
|
471
|
+
{
|
|
472
|
+
const int64_t lastSeenUs = it->second;
|
|
473
|
+
|
|
474
|
+
if (nowUs - lastSeenUs > StreamTimeOutUs)
|
|
475
|
+
{
|
|
476
|
+
it = this->ssrcs.erase(it);
|
|
477
|
+
}
|
|
478
|
+
else
|
|
479
|
+
{
|
|
480
|
+
++it;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (this->ssrcs.empty())
|
|
485
|
+
{
|
|
486
|
+
// The estimation cannot be updated without an active stream, so the
|
|
487
|
+
// delay based detection starts over.
|
|
488
|
+
//
|
|
489
|
+
// NOTE: The instant of the first packet is deliberately not reset, since
|
|
490
|
+
// bursts are only looked for at the beginning of a call.
|
|
491
|
+
this->interArrival = std::make_unique<InterArrival>(
|
|
492
|
+
static_cast<uint32_t>((TimestampGroupLengthMs << InterArrivalShift) / 1000), TimestampToUs);
|
|
493
|
+
this->overuseEstimator = std::make_unique<OveruseEstimator>();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
} // namespace BWE
|
|
497
|
+
} // namespace RTC
|
|
@@ -30,6 +30,53 @@ namespace RTC
|
|
|
30
30
|
: options(options)
|
|
31
31
|
{
|
|
32
32
|
MS_TRACE();
|
|
33
|
+
|
|
34
|
+
// NOTE: Every option below is set from C++ alone, never from the network
|
|
35
|
+
// nor from the API, so a value out of range can only be a programming
|
|
36
|
+
// error. Without them a window that requires no packets would reach the
|
|
37
|
+
// send rate with no send time to compute it from.
|
|
38
|
+
MS_ASSERT(
|
|
39
|
+
this->options.windowPackets >= 10 && this->options.windowPackets <= 1000,
|
|
40
|
+
"window size must be between 10 and 1000 packets [value:%zu]",
|
|
41
|
+
this->options.windowPackets);
|
|
42
|
+
MS_ASSERT(
|
|
43
|
+
this->options.maxWindowPackets >= 10 && this->options.maxWindowPackets <= 1000,
|
|
44
|
+
"max window size must be between 10 and 1000 packets [value:%zu]",
|
|
45
|
+
this->options.maxWindowPackets);
|
|
46
|
+
MS_ASSERT(
|
|
47
|
+
this->options.maxWindowPackets >= this->options.windowPackets,
|
|
48
|
+
"max window size is below the window size [maxWindowPackets:%zu, windowPackets:%zu]",
|
|
49
|
+
this->options.maxWindowPackets,
|
|
50
|
+
this->options.windowPackets);
|
|
51
|
+
MS_ASSERT(
|
|
52
|
+
this->options.requiredPackets >= 10 && this->options.requiredPackets <= 1000,
|
|
53
|
+
"required number of packets must be between 10 and 1000 [value:%zu]",
|
|
54
|
+
this->options.requiredPackets);
|
|
55
|
+
MS_ASSERT(
|
|
56
|
+
this->options.requiredPackets <= this->options.windowPackets,
|
|
57
|
+
"more packets are required than the window holds [requiredPackets:%zu, windowPackets:%zu]",
|
|
58
|
+
this->options.requiredPackets,
|
|
59
|
+
this->options.windowPackets);
|
|
60
|
+
MS_ASSERT(
|
|
61
|
+
this->options.minWindowDurationUs >= 100 * 1000 &&
|
|
62
|
+
this->options.minWindowDurationUs <= 3000 * 1000,
|
|
63
|
+
"window duration must be between 100 and 3000 ms [value:%" PRIi64 "]",
|
|
64
|
+
this->options.minWindowDurationUs);
|
|
65
|
+
MS_ASSERT(
|
|
66
|
+
this->options.maxWindowDurationUs >= 1000 * 1000 &&
|
|
67
|
+
this->options.maxWindowDurationUs <= 15 * 1000 * 1000,
|
|
68
|
+
"max window duration must be between 1 and 15 s [value:%" PRIi64 "]",
|
|
69
|
+
this->options.maxWindowDurationUs);
|
|
70
|
+
MS_ASSERT(
|
|
71
|
+
this->options.maxWindowDurationUs >= this->options.minWindowDurationUs,
|
|
72
|
+
"max window duration is below the window duration [maxWindowDurationUs:%" PRIi64
|
|
73
|
+
", minWindowDurationUs:%" PRIi64 "]",
|
|
74
|
+
this->options.maxWindowDurationUs,
|
|
75
|
+
this->options.minWindowDurationUs);
|
|
76
|
+
MS_ASSERT(
|
|
77
|
+
this->options.unackedWeight >= 0.0 && this->options.unackedWeight <= 1.0,
|
|
78
|
+
"weight for the prior unacked size must be in [0, 1] [value:%f]",
|
|
79
|
+
this->options.unackedWeight);
|
|
33
80
|
}
|
|
34
81
|
|
|
35
82
|
void RobustThroughputEstimator::IncomingPacketFeedbackVector(
|