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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#include "common.hpp"
|
|
2
2
|
#include "RTC/RateCalculator.hpp"
|
|
3
3
|
#include <catch2/catch_test_macros.hpp>
|
|
4
|
-
#include <
|
|
4
|
+
#include <cstdlib> // std::abs()
|
|
5
|
+
#include <limits> // std::numeric_limits
|
|
5
6
|
#include <vector>
|
|
6
7
|
|
|
7
8
|
SCENARIO("RateCalculator", "[rate-calculator]")
|
|
@@ -10,7 +11,7 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
10
11
|
{
|
|
11
12
|
int64_t offset;
|
|
12
13
|
uint32_t size;
|
|
13
|
-
|
|
14
|
+
std::optional<int64_t> rate;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
auto validate =
|
|
@@ -23,23 +24,249 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
23
24
|
REQUIRE(rate.GetRate(timeBaseMs + item.offset) == item.rate);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
// Repeat asking for the rate at a time older than the whole window
|
|
27
|
-
//
|
|
27
|
+
// Repeat asking for the rate at a time older than the whole window. There is
|
|
28
|
+
// no period between the samples and a time that precedes all of them, so
|
|
29
|
+
// there is nothing to measure.
|
|
28
30
|
rate.Reset();
|
|
29
31
|
|
|
30
32
|
for (const auto& item : input)
|
|
31
33
|
{
|
|
32
34
|
rate.Update(item.size, timeBaseMs + item.offset);
|
|
33
35
|
|
|
34
|
-
REQUIRE(rate.GetRate(item.offset) ==
|
|
36
|
+
REQUIRE(rate.GetRate(item.offset) == std::nullopt);
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
// The reads above left the data untouched, so the rate at the time of the
|
|
40
|
+
// latest sample is still the one that was reported for it.
|
|
41
|
+
REQUIRE(rate.GetRate(timeBaseMs + input.back().offset) == input.back().rate);
|
|
42
|
+
|
|
37
43
|
// Asking for the rate far in the future expires every item.
|
|
38
|
-
REQUIRE(rate.GetRate(std::numeric_limits<int64_t>::max()) ==
|
|
44
|
+
REQUIRE(rate.GetRate(std::numeric_limits<int64_t>::max()) == std::nullopt);
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
const int64_t nowMs = 12345678;
|
|
42
48
|
|
|
49
|
+
// NOTE: This pins the three states in which there is nothing to measure, and
|
|
50
|
+
// that a lone sample does become a measurement once the window has filled
|
|
51
|
+
// around it.
|
|
52
|
+
SECTION("no rate until there is something to measure")
|
|
53
|
+
{
|
|
54
|
+
RTC::RateCalculator rate(1000, 8000, 100);
|
|
55
|
+
|
|
56
|
+
// Not a single sample.
|
|
57
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
58
|
+
|
|
59
|
+
rate.Update(5, nowMs);
|
|
60
|
+
|
|
61
|
+
// A single sample taken at an instant says how much data there was, not how
|
|
62
|
+
// fast it is flowing.
|
|
63
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
64
|
+
REQUIRE(rate.GetRate(nowMs + 500) == std::nullopt);
|
|
65
|
+
|
|
66
|
+
// Once the window has filled, that lone sample is all the data there was
|
|
67
|
+
// during a whole window, which is a rate.
|
|
68
|
+
REQUIRE(rate.GetRate(nowMs + 999) == 40);
|
|
69
|
+
|
|
70
|
+
// And one more item later it has expired, leaving nothing again.
|
|
71
|
+
REQUIRE(rate.GetRate(nowMs + 1000) == std::nullopt);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// NOTE: This pins the headline of the whole thing: the divisor is the period
|
|
75
|
+
// the samples span, not the window they sit in. Dividing by the window here
|
|
76
|
+
// would report 32 bps for a link carrying 16 kbps.
|
|
77
|
+
SECTION("rate is measured over the period the samples span")
|
|
78
|
+
{
|
|
79
|
+
RTC::RateCalculator rate(1000, 8000, 100);
|
|
80
|
+
|
|
81
|
+
rate.Update(1000, nowMs);
|
|
82
|
+
rate.Update(1000, nowMs + 999);
|
|
83
|
+
|
|
84
|
+
// The period is the whole window, so both samples count: 2000 * 8000 / 1000.
|
|
85
|
+
REQUIRE(rate.GetRate(nowMs + 999) == 16000);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// NOTE: The five sections below use a window of 500 ms split into items of a
|
|
89
|
+
// single millisecond, so that expiration happens sample by sample and every
|
|
90
|
+
// expected value can be worked out by hand.
|
|
91
|
+
|
|
92
|
+
SECTION("a lone sample is measured once the window has filled around it")
|
|
93
|
+
{
|
|
94
|
+
// window: 500ms, items: 500 (granularity: 1ms)
|
|
95
|
+
RTC::RateCalculator rate(500, 8000, 500);
|
|
96
|
+
|
|
97
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
98
|
+
|
|
99
|
+
// One byte per millisecond, given as a single sample.
|
|
100
|
+
rate.Update(500, nowMs);
|
|
101
|
+
|
|
102
|
+
// Only one sample, and the window has not filled.
|
|
103
|
+
REQUIRE(rate.GetRate(nowMs + 498) == std::nullopt);
|
|
104
|
+
|
|
105
|
+
// Now it has, so the single sample is all the data of a whole window.
|
|
106
|
+
REQUIRE(rate.GetRate(nowMs + 499) == 1000 * 8);
|
|
107
|
+
|
|
108
|
+
// Another one on top doubles it.
|
|
109
|
+
rate.Update(500, nowMs + 499);
|
|
110
|
+
|
|
111
|
+
REQUIRE(rate.GetRate(nowMs + 499) == 2 * 1000 * 8);
|
|
112
|
+
|
|
113
|
+
// And now the first one drops out.
|
|
114
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 1000 * 8);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
SECTION("samples of size zero are measured as no data rather than no rate")
|
|
118
|
+
{
|
|
119
|
+
// window: 500ms, items: 500 (granularity: 1ms)
|
|
120
|
+
RTC::RateCalculator rate(500, 8000, 500);
|
|
121
|
+
|
|
122
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
123
|
+
|
|
124
|
+
rate.Update(500, nowMs);
|
|
125
|
+
rate.Update(0, nowMs + 499);
|
|
126
|
+
|
|
127
|
+
REQUIRE(rate.GetRate(nowMs + 499) == 1000 * 8);
|
|
128
|
+
|
|
129
|
+
// The first sample drops out, leaving the empty one, which is a rate of
|
|
130
|
+
// zero rather than no rate at all.
|
|
131
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 0);
|
|
132
|
+
|
|
133
|
+
// And now the empty one drops out too.
|
|
134
|
+
REQUIRE(rate.GetRate(nowMs + 1000) == std::nullopt);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
SECTION("a quiet period is measured as no data until it empties the window")
|
|
138
|
+
{
|
|
139
|
+
// window: 500ms, items: 500 (granularity: 1ms)
|
|
140
|
+
RTC::RateCalculator rate(500, 8000, 500);
|
|
141
|
+
|
|
142
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
143
|
+
|
|
144
|
+
rate.Update(0, nowMs);
|
|
145
|
+
|
|
146
|
+
REQUIRE(rate.GetRate(nowMs + 499) == 0);
|
|
147
|
+
|
|
148
|
+
// Move the window along so that the sample falls out.
|
|
149
|
+
REQUIRE(rate.GetRate(nowMs + 500) == std::nullopt);
|
|
150
|
+
|
|
151
|
+
// Move it a long way out, which makes the next sample start a new period.
|
|
152
|
+
rate.Update(0, nowMs + 1500);
|
|
153
|
+
|
|
154
|
+
REQUIRE(rate.GetRate(nowMs + 1500) == std::nullopt);
|
|
155
|
+
|
|
156
|
+
// The second one gives a period to measure over.
|
|
157
|
+
rate.Update(0, nowMs + 1501);
|
|
158
|
+
|
|
159
|
+
REQUIRE(rate.GetRate(nowMs + 1501) == 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
SECTION("silence longer than the window starts a new period")
|
|
163
|
+
{
|
|
164
|
+
// window: 500ms, items: 500 (granularity: 1ms)
|
|
165
|
+
RTC::RateCalculator rate(500, 8000, 500);
|
|
166
|
+
|
|
167
|
+
// 1000 bytes per millisecond until the window has filled, which must not make
|
|
168
|
+
// the estimation error grow as the measured period is extended.
|
|
169
|
+
int64_t prevError{ 8000000 };
|
|
170
|
+
std::optional<int64_t> bitrate;
|
|
171
|
+
|
|
172
|
+
for (int64_t i{ 1 }; i < 10000; ++i)
|
|
173
|
+
{
|
|
174
|
+
rate.Update(1000, nowMs + i);
|
|
175
|
+
|
|
176
|
+
bitrate = rate.GetRate(nowMs + i);
|
|
177
|
+
|
|
178
|
+
if (bitrate.has_value())
|
|
179
|
+
{
|
|
180
|
+
const int64_t error = std::abs(8000000 - bitrate.value());
|
|
181
|
+
|
|
182
|
+
REQUIRE(error <= prevError + 1);
|
|
183
|
+
|
|
184
|
+
prevError = error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
REQUIRE(bitrate == 8000000);
|
|
189
|
+
|
|
190
|
+
// Silence over the window size, read during the silence.
|
|
191
|
+
REQUIRE(rate.GetRate(nowMs + 10500) == std::nullopt);
|
|
192
|
+
|
|
193
|
+
// So the samples that come next are measured over their own period, which is
|
|
194
|
+
// the 2ms they span, leaving out the one that starts it: 1000 * 8000 / 2.
|
|
195
|
+
rate.Update(1000, nowMs + 10500);
|
|
196
|
+
rate.Update(1000, nowMs + 10501);
|
|
197
|
+
|
|
198
|
+
REQUIRE(rate.GetRate(nowMs + 10501) == 4000000);
|
|
199
|
+
|
|
200
|
+
// A manual reset does the same.
|
|
201
|
+
rate.Reset();
|
|
202
|
+
|
|
203
|
+
REQUIRE(rate.GetRate(nowMs + 10501) == std::nullopt);
|
|
204
|
+
|
|
205
|
+
rate.Update(1000, nowMs + 10501);
|
|
206
|
+
rate.Update(1000, nowMs + 10502);
|
|
207
|
+
|
|
208
|
+
REQUIRE(rate.GetRate(nowMs + 10502) == 4000000);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// NOTE: This pins that data given with an instant that precedes the whole
|
|
212
|
+
// window is not lost. It is taken as if it had been given at the instant the
|
|
213
|
+
// newest item starts at, so it counts towards both the rate and the total.
|
|
214
|
+
SECTION("a sample older than the whole window still counts")
|
|
215
|
+
{
|
|
216
|
+
// window: 1000ms, items: 1000 (granularity: 1ms)
|
|
217
|
+
RTC::RateCalculator rate(1000, 8000, 1000);
|
|
218
|
+
|
|
219
|
+
rate.Update(1000, nowMs);
|
|
220
|
+
rate.Update(1000, nowMs + 500);
|
|
221
|
+
|
|
222
|
+
// 1000 * 8000 / 501, without the sample that starts the period.
|
|
223
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 15968);
|
|
224
|
+
REQUIRE(rate.GetBytes() == 2000);
|
|
225
|
+
|
|
226
|
+
// Five seconds before the window, which spans one.
|
|
227
|
+
rate.Update(1000, nowMs - 5000);
|
|
228
|
+
|
|
229
|
+
REQUIRE(rate.GetBytes() == 3000);
|
|
230
|
+
// 2000 * 8000 / 501.
|
|
231
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 31936);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// NOTE: This is what the margin exists for: the samples come a whole window
|
|
235
|
+
// apart, so without it each of them would find the window empty, restart the
|
|
236
|
+
// measured period and never be measured at all.
|
|
237
|
+
SECTION("a stream sending as often as the window is still measured")
|
|
238
|
+
{
|
|
239
|
+
// window: 1000ms, items: 1000 (granularity: 1ms), counting frames
|
|
240
|
+
RTC::RateCalculator rate(1000, 1000, 1000);
|
|
241
|
+
|
|
242
|
+
REQUIRE(rate.GetRate(nowMs) == std::nullopt);
|
|
243
|
+
|
|
244
|
+
// One frame per second for ten seconds.
|
|
245
|
+
for (int64_t i{ 0 }; i < 10000; i += 1000)
|
|
246
|
+
{
|
|
247
|
+
rate.Update(1, nowMs + i);
|
|
248
|
+
|
|
249
|
+
if (i > 0)
|
|
250
|
+
{
|
|
251
|
+
REQUIRE(rate.GetRate(nowMs + i) == 1);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// NOTE: The overflow is provoked through the scale rather than through the size
|
|
257
|
+
// of the samples, since Update() takes a size_t and on a 32 bit build no amount
|
|
258
|
+
// of samples of that size makes the result overflow.
|
|
259
|
+
SECTION("a rate that does not fit is no rate at all")
|
|
260
|
+
{
|
|
261
|
+
// window: 1000ms, items: 1000 (granularity: 1ms)
|
|
262
|
+
RTC::RateCalculator rate(1000, 1e30F, 1000);
|
|
263
|
+
|
|
264
|
+
rate.Update(1000, nowMs);
|
|
265
|
+
rate.Update(1000, nowMs + 1);
|
|
266
|
+
|
|
267
|
+
REQUIRE(rate.GetRate(nowMs + 1) == std::nullopt);
|
|
268
|
+
}
|
|
269
|
+
|
|
43
270
|
SECTION("receive single item per 1000 ms")
|
|
44
271
|
{
|
|
45
272
|
RTC::RateCalculator rate;
|
|
@@ -47,7 +274,7 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
47
274
|
// clang-format off
|
|
48
275
|
const std::vector<TestRateCalculatorData> input =
|
|
49
276
|
{
|
|
50
|
-
{ .offset=0, .size=5, .rate=
|
|
277
|
+
{ .offset=0, .size=5, .rate=std::nullopt }
|
|
51
278
|
};
|
|
52
279
|
// clang-format on
|
|
53
280
|
|
|
@@ -61,10 +288,15 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
61
288
|
// clang-format off
|
|
62
289
|
const std::vector<TestRateCalculatorData> input =
|
|
63
290
|
{
|
|
64
|
-
|
|
65
|
-
{ .offset=
|
|
66
|
-
|
|
67
|
-
{ .offset=
|
|
291
|
+
// A lone sample with the window unfilled.
|
|
292
|
+
{ .offset=0, .size=5, .rate=std::nullopt },
|
|
293
|
+
// 2 * 8000 / 101, the first sample being the one that starts the period.
|
|
294
|
+
{ .offset=100, .size=2, .rate=158 },
|
|
295
|
+
// (2 + 2) * 8000 / 301.
|
|
296
|
+
{ .offset=300, .size=2, .rate=106 },
|
|
297
|
+
// The period is the whole window now, so every sample counts:
|
|
298
|
+
// (5 + 2 + 2 + 4) * 8000 / 1000.
|
|
299
|
+
{ .offset=999, .size=4, .rate=104 }
|
|
68
300
|
};
|
|
69
301
|
// clang-format on
|
|
70
302
|
|
|
@@ -75,12 +307,15 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
75
307
|
{
|
|
76
308
|
RTC::RateCalculator rate(1000, 8000, 100);
|
|
77
309
|
|
|
310
|
+
// Each sample expires the previous one, but they come close enough together
|
|
311
|
+
// for the measured period to be kept, so each of them is measured over the
|
|
312
|
+
// window instead of over the instant it was taken in.
|
|
78
313
|
// clang-format off
|
|
79
314
|
const std::vector<TestRateCalculatorData> input =
|
|
80
315
|
{
|
|
81
|
-
{ .offset=0, .size=5, .rate=
|
|
82
|
-
{ .offset=1000, .size=5, .rate=40
|
|
83
|
-
{ .offset=2000, .size=5, .rate=40
|
|
316
|
+
{ .offset=0, .size=5, .rate=std::nullopt },
|
|
317
|
+
{ .offset=1000, .size=5, .rate=40 },
|
|
318
|
+
{ .offset=2000, .size=5, .rate=40 }
|
|
84
319
|
};
|
|
85
320
|
// clang-format on
|
|
86
321
|
|
|
@@ -91,20 +326,22 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
91
326
|
{
|
|
92
327
|
RTC::RateCalculator rate(1000, 8000, 1000);
|
|
93
328
|
|
|
329
|
+
// From the second sample on the period is already the whole window, so every
|
|
330
|
+
// rate below is the bytes left within it times 8.
|
|
94
331
|
// clang-format off
|
|
95
332
|
const std::vector<TestRateCalculatorData> input =
|
|
96
333
|
{
|
|
97
|
-
{ .offset=0, .size=5, .rate=
|
|
98
|
-
{ .offset=999, .size=2, .rate=56
|
|
99
|
-
{ .offset=1001, .size=1, .rate=24
|
|
100
|
-
{ .offset=1001, .size=1, .rate=32
|
|
101
|
-
{ .offset=2000, .size=1, .rate=24
|
|
334
|
+
{ .offset=0, .size=5, .rate=std::nullopt },
|
|
335
|
+
{ .offset=999, .size=2, .rate=56 },
|
|
336
|
+
{ .offset=1001, .size=1, .rate=24 },
|
|
337
|
+
{ .offset=1001, .size=1, .rate=32 },
|
|
338
|
+
{ .offset=2000, .size=1, .rate=24 }
|
|
102
339
|
};
|
|
103
340
|
// clang-format on
|
|
104
341
|
|
|
105
342
|
validate(rate, nowMs, input);
|
|
106
343
|
|
|
107
|
-
REQUIRE(rate.GetRate(nowMs + 3001) ==
|
|
344
|
+
REQUIRE(rate.GetRate(nowMs + 3001) == std::nullopt);
|
|
108
345
|
}
|
|
109
346
|
|
|
110
347
|
SECTION("slide with 100 items")
|
|
@@ -114,19 +351,21 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
114
351
|
// clang-format off
|
|
115
352
|
const std::vector<TestRateCalculatorData> input =
|
|
116
353
|
{
|
|
117
|
-
{ .offset=0, .size=5, .rate=
|
|
118
|
-
{ .offset=999, .size=2, .rate=56
|
|
119
|
-
{ .offset=1001, .size=1, .rate=24
|
|
120
|
-
{ .offset=1001, .size=1, .rate=32
|
|
121
|
-
{ .offset=2000, .size=1, .rate=8
|
|
122
|
-
// timestamp=999, removing also the next two samples.
|
|
123
|
-
//
|
|
354
|
+
{ .offset=0, .size=5, .rate=std::nullopt },
|
|
355
|
+
{ .offset=999, .size=2, .rate=56 },
|
|
356
|
+
{ .offset=1001, .size=1, .rate=24 }, // merged inside 999
|
|
357
|
+
{ .offset=1001, .size=1, .rate=32 }, // merged inside 999
|
|
358
|
+
{ .offset=2000, .size=1, .rate=8 } // it will erase the item
|
|
359
|
+
// with timestamp=999, removing also the next two samples.
|
|
360
|
+
// Only the last sample is left, and it comes close enough
|
|
361
|
+
// to the previous one to keep being measured over the
|
|
362
|
+
// window.
|
|
124
363
|
};
|
|
125
364
|
// clang-format on
|
|
126
365
|
|
|
127
366
|
validate(rate, nowMs, input);
|
|
128
367
|
|
|
129
|
-
REQUIRE(rate.GetRate(nowMs + 3001) ==
|
|
368
|
+
REQUIRE(rate.GetRate(nowMs + 3001) == std::nullopt);
|
|
130
369
|
}
|
|
131
370
|
|
|
132
371
|
SECTION("wrap")
|
|
@@ -134,19 +373,22 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
134
373
|
// window: 1000ms, items: 5 (granularity: 200ms)
|
|
135
374
|
RTC::RateCalculator rate(1000, 8000, 5);
|
|
136
375
|
|
|
376
|
+
// A byte every 200ms is 40 bps, and that is what comes out from the second
|
|
377
|
+
// sample on: leaving out the one that starts the period is what makes the
|
|
378
|
+
// samples and the gaps between them match while the window fills.
|
|
137
379
|
// clang-format off
|
|
138
380
|
const std::vector<TestRateCalculatorData> input =
|
|
139
381
|
{
|
|
140
|
-
{ .offset=1000, .size=1, .rate=
|
|
141
|
-
{ .offset=1200, .size=1, .rate=
|
|
142
|
-
{ .offset=1400, .size=1, .rate=
|
|
143
|
-
{ .offset=1600, .size=1, .rate=
|
|
144
|
-
{ .offset=1800, .size=1, .rate=
|
|
145
|
-
{ .offset=2000, .size=1, .rate=(1*8) + ((5-1)*8)
|
|
146
|
-
{ .offset=2200, .size=1, .rate=(1*8) + ((6-2)*8)
|
|
147
|
-
{ .offset=2400, .size=1, .rate=(1*8) + ((7-3)*8)
|
|
148
|
-
{ .offset=2600, .size=1, .rate=(1*8) + ((8-4)*8)
|
|
149
|
-
{ .offset=2800, .size=1, .rate=(1*8) + ((9-5)*8)
|
|
382
|
+
{ .offset=1000, .size=1, .rate=std::nullopt },
|
|
383
|
+
{ .offset=1200, .size=1, .rate=40 },
|
|
384
|
+
{ .offset=1400, .size=1, .rate=40 },
|
|
385
|
+
{ .offset=1600, .size=1, .rate=40 },
|
|
386
|
+
{ .offset=1800, .size=1, .rate=40 },
|
|
387
|
+
{ .offset=2000, .size=1, .rate=(1*8) + ((5-1)*8) }, // starts wrap here
|
|
388
|
+
{ .offset=2200, .size=1, .rate=(1*8) + ((6-2)*8) },
|
|
389
|
+
{ .offset=2400, .size=1, .rate=(1*8) + ((7-3)*8) },
|
|
390
|
+
{ .offset=2600, .size=1, .rate=(1*8) + ((8-4)*8) },
|
|
391
|
+
{ .offset=2800, .size=1, .rate=(1*8) + ((9-5)*8) },
|
|
150
392
|
};
|
|
151
393
|
// clang-format on
|
|
152
394
|
|
|
@@ -163,10 +405,13 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
163
405
|
// clang-format off
|
|
164
406
|
const std::vector<TestRateCalculatorData> input =
|
|
165
407
|
{
|
|
166
|
-
{ .offset=0, .size=1, .rate=
|
|
167
|
-
|
|
168
|
-
{ .offset=
|
|
169
|
-
|
|
408
|
+
{ .offset=0, .size=1, .rate=std::nullopt },
|
|
409
|
+
// 1 * 8000 / 334, without the sample that starts the period.
|
|
410
|
+
{ .offset=333, .size=1, .rate=24 },
|
|
411
|
+
// 2 * 8000 / 667.
|
|
412
|
+
{ .offset=666, .size=1, .rate=24 },
|
|
413
|
+
// The period is the whole window now: 4 * 8000 / 1000.
|
|
414
|
+
{ .offset=999, .size=1, .rate=32 },
|
|
170
415
|
};
|
|
171
416
|
// clang-format on
|
|
172
417
|
|
|
@@ -194,27 +439,33 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
194
439
|
REQUIRE(rate.GetRate(nowMs + 1100) == 91 * 8);
|
|
195
440
|
}
|
|
196
441
|
|
|
197
|
-
// NOTE: This pins the GetRate() memoization key, which is
|
|
198
|
-
//
|
|
442
|
+
// NOTE: This pins the GetRate() memoization key, which is the time plus both
|
|
443
|
+
// totals. Keying it on the time alone would return a stale rate.
|
|
199
444
|
SECTION("rate is recalculated after Update() with the same now")
|
|
200
445
|
{
|
|
201
446
|
RTC::RateCalculator rate(1000, 8000, 100);
|
|
202
447
|
|
|
448
|
+
// Two samples apart in time, so that there is a period to measure over and
|
|
449
|
+
// the reads below are not rejected for lack of one.
|
|
203
450
|
rate.Update(5, nowMs);
|
|
451
|
+
rate.Update(5, nowMs + 500);
|
|
204
452
|
|
|
205
|
-
|
|
453
|
+
// 5 * 8000 / 501, without the sample that starts the period.
|
|
454
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 80);
|
|
206
455
|
|
|
207
|
-
rate.Update(5, nowMs);
|
|
456
|
+
rate.Update(5, nowMs + 500);
|
|
208
457
|
|
|
209
|
-
|
|
458
|
+
// 10 * 8000 / 501.
|
|
459
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 160);
|
|
210
460
|
|
|
211
|
-
rate.Update(5, nowMs);
|
|
461
|
+
rate.Update(5, nowMs + 500);
|
|
212
462
|
|
|
213
|
-
|
|
463
|
+
// 15 * 8000 / 501.
|
|
464
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 240);
|
|
214
465
|
|
|
215
466
|
// Repeated reads with no Update() in between must be stable.
|
|
216
|
-
REQUIRE(rate.GetRate(nowMs) ==
|
|
217
|
-
REQUIRE(rate.GetRate(nowMs) ==
|
|
467
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 240);
|
|
468
|
+
REQUIRE(rate.GetRate(nowMs + 500) == 240);
|
|
218
469
|
}
|
|
219
470
|
|
|
220
471
|
// NOTE: This pins the item size rounding for a window size which is not a
|
|
@@ -237,24 +488,28 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
237
488
|
|
|
238
489
|
// NOTE: This pins that the GetRate() memoization needs no "not calculated yet"
|
|
239
490
|
// mark. Its zeroed initial state is a valid entry, so a read at time 0 must be
|
|
240
|
-
// neither a stale hit nor a miss returning something else than
|
|
491
|
+
// neither a stale hit nor a miss returning something else than no rate at all.
|
|
241
492
|
SECTION("rate at time 0 on a fresh and on a reset calculator")
|
|
242
493
|
{
|
|
243
494
|
RTC::RateCalculator rate(1000, 8000, 100);
|
|
244
495
|
|
|
245
|
-
REQUIRE(rate.GetRate(0) ==
|
|
496
|
+
REQUIRE(rate.GetRate(0) == std::nullopt);
|
|
246
497
|
|
|
247
498
|
rate.Update(5, 0);
|
|
499
|
+
rate.Update(5, 500);
|
|
248
500
|
|
|
249
|
-
|
|
501
|
+
// 5 * 8000 / 501, without the sample that starts the period.
|
|
502
|
+
REQUIRE(rate.GetRate(500) == 80);
|
|
250
503
|
|
|
251
504
|
rate.Reset();
|
|
252
505
|
|
|
253
|
-
REQUIRE(rate.GetRate(0) ==
|
|
506
|
+
REQUIRE(rate.GetRate(0) == std::nullopt);
|
|
254
507
|
|
|
255
508
|
rate.Update(5, 0);
|
|
509
|
+
rate.Update(5, 500);
|
|
256
510
|
|
|
257
|
-
|
|
511
|
+
// The same as before the reset.
|
|
512
|
+
REQUIRE(rate.GetRate(500) == 80);
|
|
258
513
|
}
|
|
259
514
|
|
|
260
515
|
// NOTE: This pins the constructor clamping. A zero number of items used to
|
|
@@ -269,9 +524,16 @@ SCENARIO("RateCalculator", "[rate-calculator]")
|
|
|
269
524
|
oneItem.Update(5, nowMs);
|
|
270
525
|
noWindow.Update(5, nowMs);
|
|
271
526
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
527
|
+
noItems.Update(5, nowMs + 500);
|
|
528
|
+
oneItem.Update(5, nowMs + 500);
|
|
529
|
+
noWindow.Update(5, nowMs + 500);
|
|
530
|
+
|
|
531
|
+
// Two samples 500ms apart, of which the one that starts the period is left
|
|
532
|
+
// out: 5 * 8000 / 501.
|
|
533
|
+
REQUIRE(noItems.GetRate(nowMs + 500) == 80);
|
|
534
|
+
REQUIRE(oneItem.GetRate(nowMs + 500) == 80);
|
|
535
|
+
// The window size is clamped to 1ms, which leaves every sample alone in a
|
|
536
|
+
// period of a single millisecond, so such a window can never measure a rate.
|
|
537
|
+
REQUIRE(noWindow.GetRate(nowMs + 500) == std::nullopt);
|
|
276
538
|
}
|
|
277
539
|
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
#include "RTC/RTCP/SenderReport.hpp"
|
|
3
3
|
#include "RTC/RTP/RtpStreamRecv.hpp"
|
|
4
4
|
#include "RTC/RemoteCaptureTimeEstimator.hpp"
|
|
5
|
+
#include "RTC/RtpDictionaries.hpp"
|
|
6
|
+
#include "Utils.hpp"
|
|
7
|
+
#include "test/include/RTC/RTP/rtpCommon.hpp"
|
|
5
8
|
#include "mocks/include/MockShared.hpp"
|
|
6
9
|
#include <catch2/catch_test_macros.hpp>
|
|
7
10
|
|
|
@@ -81,10 +84,49 @@ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]"
|
|
|
81
84
|
estimator.SenderReportReceived(std::addressof(rtpStream));
|
|
82
85
|
};
|
|
83
86
|
|
|
87
|
+
// Makes a packet carrying the 'abs-capture-time' extension reach the stream, which
|
|
88
|
+
// is what tells a sender that does send it from one that only announced it.
|
|
89
|
+
auto receiveAbsCaptureTimePacket = [&nowUs, &rtpStream]() -> void
|
|
90
|
+
{
|
|
91
|
+
// Id the extension is given, which only has to match between what is written
|
|
92
|
+
// and what is read back.
|
|
93
|
+
constexpr uint8_t AbsCaptureTimeId{ 1 };
|
|
94
|
+
|
|
95
|
+
std::unique_ptr<RTC::RTP::Packet> packet(
|
|
96
|
+
RTC::RTP::Packet::Factory(rtpCommon::FactoryBuffer, sizeof(rtpCommon::FactoryBuffer)));
|
|
97
|
+
|
|
98
|
+
REQUIRE(packet);
|
|
99
|
+
|
|
100
|
+
packet->SetSsrc(Ssrc);
|
|
101
|
+
packet->SetTimestamp(RemoteBaseTs);
|
|
102
|
+
|
|
103
|
+
const std::vector<RTC::RTP::Packet::Extension> extensions{
|
|
104
|
+
{ RTC::RtpHeaderExtensionUri::Type::ABS_CAPTURE_TIME,
|
|
105
|
+
AbsCaptureTimeId, /*len*/ 8,
|
|
106
|
+
rtpCommon::DataBuffer }
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
packet->SetExtensions(RTC::RTP::Packet::ExtensionsType::OneByte, extensions);
|
|
110
|
+
|
|
111
|
+
RTC::RTP::HeaderExtensionIds headerExtensionIds;
|
|
112
|
+
|
|
113
|
+
headerExtensionIds.absCaptureTime = AbsCaptureTimeId;
|
|
114
|
+
|
|
115
|
+
packet->AssignExtensionIds(headerExtensionIds);
|
|
116
|
+
|
|
117
|
+
const auto ntp = Utils::Time::TimeUsToNtp(static_cast<int64_t>(RemoteBaseNtpSec) * 1000000);
|
|
118
|
+
|
|
119
|
+
REQUIRE(packet->UpdateAbsCaptureTime(
|
|
120
|
+
(static_cast<uint64_t>(ntp.seconds) << 32) | static_cast<uint64_t>(ntp.fractions)));
|
|
121
|
+
|
|
122
|
+
rtpStream.ReceivePacket(packet.get(), nowUs);
|
|
123
|
+
};
|
|
124
|
+
|
|
84
125
|
SECTION("no source until the first Producer has been taken into account")
|
|
85
126
|
{
|
|
86
127
|
REQUIRE_FALSE(estimator.GetSource().has_value());
|
|
87
|
-
REQUIRE_FALSE(
|
|
128
|
+
REQUIRE_FALSE(
|
|
129
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
88
130
|
}
|
|
89
131
|
|
|
90
132
|
SECTION("the first Producer chooses abs-capture-time when it negotiated it")
|
|
@@ -118,6 +160,50 @@ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]"
|
|
|
118
160
|
REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::SENDER_REPORT);
|
|
119
161
|
}
|
|
120
162
|
|
|
163
|
+
SECTION("abs-capture-time negotiated but never received moves the source to Sender Report")
|
|
164
|
+
{
|
|
165
|
+
estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
|
|
166
|
+
|
|
167
|
+
// The first packet is what the wait is measured against, so nothing happens on
|
|
168
|
+
// it however long this sender has been around.
|
|
169
|
+
nowUs += 60 * 1000000;
|
|
170
|
+
|
|
171
|
+
REQUIRE_FALSE(
|
|
172
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
173
|
+
REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::ABS_CAPTURE_TIME);
|
|
174
|
+
|
|
175
|
+
// Still within the wait, since the extension travels on some packets rather
|
|
176
|
+
// than on every one and may simply not have arrived yet.
|
|
177
|
+
nowUs += 4 * 1000000;
|
|
178
|
+
|
|
179
|
+
REQUIRE_FALSE(
|
|
180
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
181
|
+
REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::ABS_CAPTURE_TIME);
|
|
182
|
+
|
|
183
|
+
// Long enough without a single packet carrying it.
|
|
184
|
+
nowUs += 1 * 1000000;
|
|
185
|
+
|
|
186
|
+
REQUIRE_FALSE(
|
|
187
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
188
|
+
REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::SENDER_REPORT);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
SECTION("abs-capture-time received keeps the source whatever the sender does later")
|
|
192
|
+
{
|
|
193
|
+
estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
|
|
194
|
+
|
|
195
|
+
receiveAbsCaptureTimePacket();
|
|
196
|
+
|
|
197
|
+
REQUIRE(rtpStream.HasAbsCaptureTime());
|
|
198
|
+
|
|
199
|
+
// Way past the wait, which is not armed at all once the extension has been seen.
|
|
200
|
+
nowUs += 60 * 1000000;
|
|
201
|
+
|
|
202
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs);
|
|
203
|
+
|
|
204
|
+
REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::ABS_CAPTURE_TIME);
|
|
205
|
+
}
|
|
206
|
+
|
|
121
207
|
SECTION("the capture instant is translated into our clock")
|
|
122
208
|
{
|
|
123
209
|
estimator.UpdateSource(/*absCaptureTimeNegotiated*/ false);
|
|
@@ -125,7 +211,8 @@ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]"
|
|
|
125
211
|
// A single Sender Report is not enough for the clock offset to be estimated.
|
|
126
212
|
receiveSenderReport(0);
|
|
127
213
|
|
|
128
|
-
REQUIRE_FALSE(
|
|
214
|
+
REQUIRE_FALSE(
|
|
215
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
129
216
|
|
|
130
217
|
for (uint32_t idx{ 1 }; idx < RTC::RemoteClockOffsetEstimator::MinSampleCount; ++idx)
|
|
131
218
|
{
|
|
@@ -137,19 +224,19 @@ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]"
|
|
|
137
224
|
const auto lastIdx = RTC::RemoteClockOffsetEstimator::MinSampleCount - 1;
|
|
138
225
|
const auto lastTs = static_cast<uint32_t>(RemoteBaseTs + (lastIdx * ClockRate));
|
|
139
226
|
|
|
140
|
-
REQUIRE(estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), lastTs).has_value());
|
|
227
|
+
REQUIRE(estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), lastTs, nowUs).has_value());
|
|
141
228
|
REQUIRE(
|
|
142
229
|
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
|
143
|
-
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), lastTs).value() ==
|
|
230
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), lastTs, nowUs).value() ==
|
|
144
231
|
LocalBaseUs + (lastIdx * 1000000));
|
|
145
232
|
|
|
146
233
|
// One second of media later maps one second later in our clock too.
|
|
147
234
|
const auto nextTs = static_cast<uint32_t>(RemoteBaseTs + ((lastIdx + 1) * ClockRate));
|
|
148
235
|
|
|
149
|
-
REQUIRE(estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), nextTs).has_value());
|
|
236
|
+
REQUIRE(estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), nextTs, nowUs).has_value());
|
|
150
237
|
REQUIRE(
|
|
151
238
|
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
|
152
|
-
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), nextTs).value() ==
|
|
239
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), nextTs, nowUs).value() ==
|
|
153
240
|
LocalBaseUs + ((lastIdx + 1) * 1000000));
|
|
154
241
|
}
|
|
155
242
|
|
|
@@ -164,6 +251,7 @@ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]"
|
|
|
164
251
|
|
|
165
252
|
// Sender Reports have been received, but the source in use is not allowed to
|
|
166
253
|
// fall back to them.
|
|
167
|
-
REQUIRE_FALSE(
|
|
254
|
+
REQUIRE_FALSE(
|
|
255
|
+
estimator.GetLocalCaptureAtUs(std::addressof(rtpStream), RemoteBaseTs, nowUs).has_value());
|
|
168
256
|
}
|
|
169
257
|
}
|