mediasoup 3.24.2 → 3.26.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 (55) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/node/lib/Consumer.js +1 -1
  3. package/node/lib/Transport.d.ts.map +1 -1
  4. package/node/lib/Transport.js +7 -0
  5. package/node/lib/ortc.d.ts.map +1 -1
  6. package/node/lib/ortc.js +10 -0
  7. package/node/lib/test/test-PipeTransport.js +35 -30
  8. package/package.json +6 -6
  9. package/worker/include/DepLibUV.hpp +33 -4
  10. package/worker/include/RTC/Consumer.hpp +4 -1
  11. package/worker/include/RTC/Producer.hpp +34 -5
  12. package/worker/include/RTC/RTCP/Packet.hpp +7 -1
  13. package/worker/include/RTC/RTP/Packet.hpp +18 -0
  14. package/worker/include/RTC/RTP/RtpStream.hpp +76 -14
  15. package/worker/include/RTC/RTP/RtpStreamRecv.hpp +191 -7
  16. package/worker/include/RTC/RTP/RtpStreamSend.hpp +56 -10
  17. package/worker/include/RTC/RTP/RtxStream.hpp +34 -2
  18. package/worker/include/RTC/RemoteCaptureTimeEstimator.hpp +92 -0
  19. package/worker/include/RTC/RemoteClockOffsetEstimator.hpp +87 -0
  20. package/worker/include/RTC/Router.hpp +2 -5
  21. package/worker/include/RTC/SimulcastProducerStreamManager.hpp +3 -0
  22. package/worker/include/RTC/Transport.hpp +15 -7
  23. package/worker/include/Shared.hpp +5 -0
  24. package/worker/include/SharedInterface.hpp +6 -0
  25. package/worker/include/Utils.hpp +44 -3
  26. package/worker/meson.build +4 -0
  27. package/worker/mocks/include/MockShared.hpp +7 -0
  28. package/worker/src/DepLibUV.cpp +17 -0
  29. package/worker/src/RTC/Consumer.cpp +8 -5
  30. package/worker/src/RTC/Producer.cpp +85 -16
  31. package/worker/src/RTC/RTP/Packet.cpp +9 -1
  32. package/worker/src/RTC/RTP/RtpStream.cpp +14 -10
  33. package/worker/src/RTC/RTP/RtpStreamRecv.cpp +150 -23
  34. package/worker/src/RTC/RTP/RtpStreamSend.cpp +34 -19
  35. package/worker/src/RTC/RTP/RtxStream.cpp +12 -6
  36. package/worker/src/RTC/RemoteCaptureTimeEstimator.cpp +77 -0
  37. package/worker/src/RTC/RemoteClockOffsetEstimator.cpp +106 -0
  38. package/worker/src/RTC/Router.cpp +10 -8
  39. package/worker/src/RTC/RtpDictionaries/RtcpParameters.cpp +13 -3
  40. package/worker/src/RTC/SCTP/packet/chunks/SackChunk.cpp +6 -2
  41. package/worker/src/RTC/SimulcastProducerStreamManager.cpp +115 -56
  42. package/worker/src/RTC/SvcProducerStreamManager.cpp +22 -17
  43. package/worker/src/RTC/Transport.cpp +96 -4
  44. package/worker/test/src/RTC/RTP/TestPacket.cpp +6 -0
  45. package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +2 -2
  46. package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +119 -0
  47. package/worker/test/src/RTC/TestConsumer.cpp +4 -3
  48. package/worker/test/src/RTC/TestPortManager.cpp +1 -1
  49. package/worker/test/src/RTC/TestRemoteCaptureTimeEstimator.cpp +164 -0
  50. package/worker/test/src/RTC/TestRemoteClockOffsetEstimator.cpp +241 -0
  51. package/worker/test/src/RTC/TestSimpleProducerStreamManager.cpp +2 -2
  52. package/worker/test/src/RTC/TestSimulcastProducerStreamManager.cpp +340 -15
  53. package/worker/test/src/RTC/TestSvcProducerStreamManager.cpp +2 -2
  54. package/worker/test/src/RTC/TestTransportTuple.cpp +1 -1
  55. package/worker/test/src/Utils/TestTime.cpp +49 -0
@@ -0,0 +1,164 @@
1
+ #include "common.hpp"
2
+ #include "RTC/RTCP/SenderReport.hpp"
3
+ #include "RTC/RTP/RtpStreamRecv.hpp"
4
+ #include "RTC/RemoteCaptureTimeEstimator.hpp"
5
+ #include "mocks/include/MockShared.hpp"
6
+ #include <catch2/catch_test_macros.hpp>
7
+
8
+ SCENARIO("RemoteCaptureTimeEstimator", "[rtp][rtcp][remotecapturetimeestimator]")
9
+ {
10
+ // Wall clock of the remote sender when it generates its first Sender Report
11
+ // (seconds since 1900).
12
+ constexpr uint32_t RemoteBaseNtpSec{ 3976000000 };
13
+ // RTP timestamp that first Sender Report reports about.
14
+ constexpr uint32_t RemoteBaseTs{ 1000000 };
15
+ // Our own monotonic clock when that first Sender Report arrives.
16
+ constexpr uint64_t LocalBaseMs{ 1000000 };
17
+ constexpr uint32_t ClockRate{ 90000 };
18
+ constexpr uint32_t Ssrc{ 1111 };
19
+
20
+ class RtpStreamRecvListener : public RTC::RTP::RtpStreamRecv::Listener
21
+ {
22
+ public:
23
+ void OnRtpStreamScore(
24
+ RTC::RTP::RtpStream* /*rtpStream*/, uint8_t /*score*/, uint8_t /*previousScore*/) override
25
+ {
26
+ }
27
+
28
+ void OnRtpStreamSendRtcpPacket(
29
+ RTC::RTP::RtpStreamRecv* /*rtpStream*/, RTC::RTCP::Packet* /*packet*/) override
30
+ {
31
+ }
32
+
33
+ uint8_t OnRtpStreamNeedWorstRemoteFractionLost(RTC::RTP::RtpStreamRecv* /*rtpStream*/) override
34
+ {
35
+ return 0;
36
+ }
37
+ };
38
+
39
+ uint64_t nowMs{ LocalBaseMs };
40
+
41
+ mocks::MockShared shared(/*getTimeMs*/
42
+ [&nowMs]() -> uint64_t
43
+ {
44
+ return nowMs;
45
+ });
46
+
47
+ RTC::RTP::RtpStream::Params params;
48
+
49
+ params.ssrc = Ssrc;
50
+ params.clockRate = ClockRate;
51
+
52
+ RtpStreamRecvListener listener;
53
+ RTC::RTP::RtpStreamRecv rtpStream(
54
+ std::addressof(listener),
55
+ std::addressof(shared),
56
+ params,
57
+ /*sendNackDelayMs*/ 0,
58
+ /*useRtpInactivityCheck*/ false);
59
+
60
+ RTC::RemoteCaptureTimeEstimator estimator;
61
+
62
+ // Makes the Sender Report about `RemoteBaseTs` plus `idx` seconds of media reach
63
+ // us with no delay at all, and feeds it to the estimator.
64
+ auto receiveSenderReport = [&nowMs, &rtpStream, &estimator](uint32_t idx) -> void
65
+ {
66
+ nowMs = LocalBaseMs + (idx * 1000);
67
+
68
+ RTC::RTCP::SenderReport report;
69
+
70
+ report.SetSsrc(Ssrc);
71
+ report.SetNtpSec(RemoteBaseNtpSec + idx);
72
+ report.SetNtpFrac(0);
73
+ report.SetRtpTs(RemoteBaseTs + (idx * ClockRate));
74
+
75
+ rtpStream.ReceiveRtcpSenderReport(std::addressof(report));
76
+ estimator.SenderReportReceived(std::addressof(rtpStream));
77
+ };
78
+
79
+ SECTION("no source until the first Producer has been taken into account")
80
+ {
81
+ REQUIRE_FALSE(estimator.GetSource().has_value());
82
+ REQUIRE_FALSE(estimator.GetLocalCaptureMs(std::addressof(rtpStream), RemoteBaseTs).has_value());
83
+ }
84
+
85
+ SECTION("the first Producer chooses abs-capture-time when it negotiated it")
86
+ {
87
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
88
+
89
+ REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::ABS_CAPTURE_TIME);
90
+ }
91
+
92
+ SECTION("the first Producer chooses Sender Report when it did not negotiate abs-capture-time")
93
+ {
94
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ false);
95
+
96
+ REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::SENDER_REPORT);
97
+ }
98
+
99
+ SECTION("a Producer without abs-capture-time moves the source to Sender Report")
100
+ {
101
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
102
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ false);
103
+
104
+ REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::SENDER_REPORT);
105
+ }
106
+
107
+ SECTION("the source never moves back to abs-capture-time")
108
+ {
109
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ false);
110
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
111
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
112
+
113
+ REQUIRE(estimator.GetSource() == RTC::RemoteCaptureTimeEstimator::Source::SENDER_REPORT);
114
+ }
115
+
116
+ SECTION("the capture instant is translated into our clock")
117
+ {
118
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ false);
119
+
120
+ // A single Sender Report is not enough for the clock offset to be estimated.
121
+ receiveSenderReport(0);
122
+
123
+ REQUIRE_FALSE(estimator.GetLocalCaptureMs(std::addressof(rtpStream), RemoteBaseTs).has_value());
124
+
125
+ for (uint32_t idx{ 1 }; idx < RTC::RemoteClockOffsetEstimator::MinSampleCount; ++idx)
126
+ {
127
+ receiveSenderReport(idx);
128
+ }
129
+
130
+ // The Sender Reports reached us with no delay, so the capture instant of the
131
+ // RTP timestamp of the last one is the very instant at which it arrived.
132
+ const auto lastIdx = RTC::RemoteClockOffsetEstimator::MinSampleCount - 1;
133
+ const auto lastTs = static_cast<uint32_t>(RemoteBaseTs + (lastIdx * ClockRate));
134
+
135
+ REQUIRE(estimator.GetLocalCaptureMs(std::addressof(rtpStream), lastTs).has_value());
136
+ REQUIRE(
137
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
138
+ estimator.GetLocalCaptureMs(std::addressof(rtpStream), lastTs).value() ==
139
+ LocalBaseMs + (lastIdx * 1000));
140
+
141
+ // One second of media later maps one second later in our clock too.
142
+ const auto nextTs = static_cast<uint32_t>(RemoteBaseTs + ((lastIdx + 1) * ClockRate));
143
+
144
+ REQUIRE(estimator.GetLocalCaptureMs(std::addressof(rtpStream), nextTs).has_value());
145
+ REQUIRE(
146
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
147
+ estimator.GetLocalCaptureMs(std::addressof(rtpStream), nextTs).value() ==
148
+ LocalBaseMs + ((lastIdx + 1) * 1000));
149
+ }
150
+
151
+ SECTION("no capture instant while the abs-capture-time source has nothing to offer")
152
+ {
153
+ estimator.UpdateSource(/*absCaptureTimeNegotiated*/ true);
154
+
155
+ for (uint32_t idx{ 0 }; idx < RTC::RemoteClockOffsetEstimator::MinSampleCount; ++idx)
156
+ {
157
+ receiveSenderReport(idx);
158
+ }
159
+
160
+ // Sender Reports have been received, but the source in use is not allowed to
161
+ // fall back to them.
162
+ REQUIRE_FALSE(estimator.GetLocalCaptureMs(std::addressof(rtpStream), RemoteBaseTs).has_value());
163
+ }
164
+ }
@@ -0,0 +1,241 @@
1
+ #include "common.hpp"
2
+ #include "RTC/RemoteClockOffsetEstimator.hpp"
3
+ #include <catch2/catch_test_macros.hpp>
4
+
5
+ SCENARIO("RemoteClockOffsetEstimator", "[rtp][rtcp][remoteclockoffsetestimator]")
6
+ {
7
+ // Remote sender wall clock, as reported in the NTP field of its Sender Reports
8
+ // (milliseconds since 1900).
9
+ constexpr uint64_t RemoteBaseMs{ 3976000000000 };
10
+ // Our own monotonic clock.
11
+ constexpr uint64_t LocalBaseMs{ 1000000 };
12
+ // Offset expected when Sender Reports reach us with no delay at all.
13
+ constexpr int64_t BaseOffsetMs{ static_cast<int64_t>(LocalBaseMs) -
14
+ static_cast<int64_t>(RemoteBaseMs) };
15
+
16
+ const auto minSampleCount = RTC::RemoteClockOffsetEstimator::MinSampleCount;
17
+ const auto windowSize = RTC::RemoteClockOffsetEstimator::WindowSize;
18
+
19
+ // Feeds `count` Sender Reports one second apart, each one reaching us `owdMs`
20
+ // after having been generated by the sender.
21
+ auto feed = [](
22
+ RTC::RemoteClockOffsetEstimator& estimator,
23
+ uint64_t remoteNtpMs,
24
+ uint64_t localArrivalMs,
25
+ size_t count,
26
+ uint64_t owdMs,
27
+ uint32_t rttMs) -> void
28
+ {
29
+ for (size_t idx{ 0 }; idx < count; ++idx)
30
+ {
31
+ const uint64_t elapsedMs = static_cast<uint64_t>(idx) * 1000;
32
+
33
+ estimator.AddSenderReport(remoteNtpMs + elapsedMs, localArrivalMs + elapsedMs + owdMs, rttMs);
34
+ }
35
+ };
36
+
37
+ RTC::RemoteClockOffsetEstimator estimator;
38
+
39
+ SECTION("no offset until MinSampleCount Sender Reports have been received")
40
+ {
41
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount - 1, 0, 0);
42
+
43
+ REQUIRE_FALSE(estimator.GetOffsetMs().has_value());
44
+
45
+ // One more Sender Report reaches the minimum.
46
+ const uint64_t elapsedMs = static_cast<uint64_t>(minSampleCount - 1) * 1000;
47
+
48
+ feed(estimator, RemoteBaseMs + elapsedMs, LocalBaseMs + elapsedMs, 1, 0, 0);
49
+
50
+ REQUIRE(estimator.GetOffsetMs().has_value());
51
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
52
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
53
+ }
54
+
55
+ SECTION("the offset carries the Sender Report one way delay when the RTT is unknown")
56
+ {
57
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount, 40, 0);
58
+
59
+ REQUIRE(estimator.GetOffsetMs().has_value());
60
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
61
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + 40);
62
+ }
63
+
64
+ SECTION("half of the RTT is removed from the offset")
65
+ {
66
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount, 40, 80);
67
+
68
+ REQUIRE(estimator.GetOffsetMs().has_value());
69
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
70
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
71
+ }
72
+
73
+ SECTION("a single delayed Sender Report does not move the offset")
74
+ {
75
+ feed(estimator, RemoteBaseMs, LocalBaseMs, windowSize, 20, 0);
76
+
77
+ REQUIRE(estimator.GetOffsetMs().has_value());
78
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
79
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + 20);
80
+
81
+ // A Sender Report that took much longer to reach us must be rejected by the
82
+ // median.
83
+ const uint64_t elapsedMs = static_cast<uint64_t>(windowSize) * 1000;
84
+
85
+ feed(estimator, RemoteBaseMs + elapsedMs, LocalBaseMs + elapsedMs, 1, 500, 0);
86
+
87
+ REQUIRE(estimator.GetOffsetMs().has_value());
88
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
89
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + 20);
90
+ }
91
+
92
+ SECTION("the offset follows a sustained change in delay")
93
+ {
94
+ feed(estimator, RemoteBaseMs, LocalBaseMs, windowSize, 0, 0);
95
+
96
+ REQUIRE(estimator.GetOffsetMs().has_value());
97
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
98
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
99
+
100
+ // Once the whole window has been replaced the new delay is fully reflected.
101
+ const uint64_t elapsedMs = static_cast<uint64_t>(windowSize) * 1000;
102
+
103
+ feed(estimator, RemoteBaseMs + elapsedMs, LocalBaseMs + elapsedMs, windowSize, 100, 0);
104
+
105
+ REQUIRE(estimator.GetOffsetMs().has_value());
106
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
107
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + 100);
108
+ }
109
+
110
+ SECTION("delayed Sender Reports move the offset once they are the majority")
111
+ {
112
+ feed(estimator, RemoteBaseMs, LocalBaseMs, windowSize, 0, 0);
113
+
114
+ REQUIRE(estimator.GetOffsetMs().has_value());
115
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
116
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
117
+
118
+ // Less than half of the window delayed, so the median still falls on a
119
+ // Sender Report that reached us with no delay.
120
+ uint64_t elapsedMs = static_cast<uint64_t>(windowSize) * 1000;
121
+
122
+ feed(estimator, RemoteBaseMs + elapsedMs, LocalBaseMs + elapsedMs, windowSize / 2, 300, 0);
123
+
124
+ REQUIRE(estimator.GetOffsetMs().has_value());
125
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
126
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
127
+
128
+ // One more delayed Sender Report makes them the majority.
129
+ elapsedMs += static_cast<uint64_t>(windowSize / 2) * 1000;
130
+
131
+ feed(estimator, RemoteBaseMs + elapsedMs, LocalBaseMs + elapsedMs, 1, 300, 0);
132
+
133
+ REQUIRE(estimator.GetOffsetMs().has_value());
134
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
135
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + 300);
136
+ }
137
+
138
+ SECTION("the offset tracks a drifting remote clock")
139
+ {
140
+ // The remote wall clock runs one millisecond per second slower than ours, so
141
+ // each Sender Report yields an offset one millisecond higher than the
142
+ // previous one.
143
+ for (size_t idx{ 0 }; idx < windowSize; ++idx)
144
+ {
145
+ estimator.AddSenderReport(
146
+ RemoteBaseMs + (static_cast<uint64_t>(idx) * 1000),
147
+ LocalBaseMs + (static_cast<uint64_t>(idx) * 1001),
148
+ 0);
149
+ }
150
+
151
+ REQUIRE(estimator.GetOffsetMs().has_value());
152
+ // The samples in the window grow by one millisecond each, so the median is
153
+ // the middle of that ramp.
154
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
155
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs + static_cast<int64_t>(windowSize / 2));
156
+
157
+ // The drift keeps going, so the offset keeps up with it rather than sticking
158
+ // to the value it already had.
159
+ for (size_t idx{ windowSize }; idx < windowSize * 2; ++idx)
160
+ {
161
+ estimator.AddSenderReport(
162
+ RemoteBaseMs + (static_cast<uint64_t>(idx) * 1000),
163
+ LocalBaseMs + (static_cast<uint64_t>(idx) * 1001),
164
+ 0);
165
+ }
166
+
167
+ REQUIRE(estimator.GetOffsetMs().has_value());
168
+ REQUIRE(
169
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
170
+ estimator.GetOffsetMs().value() ==
171
+ BaseOffsetMs + static_cast<int64_t>(windowSize + (windowSize / 2)));
172
+ }
173
+
174
+ SECTION("all the Sender Reports of a compound packet produce a single sample")
175
+ {
176
+ // Three Sender Reports of a same compound packet, hence a single arrival
177
+ // time.
178
+ estimator.AddSenderReport(RemoteBaseMs, LocalBaseMs, 0);
179
+ estimator.AddSenderReport(RemoteBaseMs + 1, LocalBaseMs, 0);
180
+ estimator.AddSenderReport(RemoteBaseMs + 2, LocalBaseMs, 0);
181
+
182
+ REQUIRE_FALSE(estimator.GetOffsetMs().has_value());
183
+
184
+ // Two more compound packets reach the minimum.
185
+ estimator.AddSenderReport(RemoteBaseMs + 1000, LocalBaseMs + 1000, 0);
186
+ estimator.AddSenderReport(RemoteBaseMs + 1001, LocalBaseMs + 1000, 0);
187
+ estimator.AddSenderReport(RemoteBaseMs + 2000, LocalBaseMs + 2000, 0);
188
+
189
+ REQUIRE(estimator.GetOffsetMs().has_value());
190
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
191
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
192
+ }
193
+
194
+ SECTION("Sender Reports with no NTP timestamp are ignored")
195
+ {
196
+ // NOTE: Not using feed() here since it would advance the NTP timestamp.
197
+ estimator.AddSenderReport(0, LocalBaseMs, 0);
198
+ estimator.AddSenderReport(0, LocalBaseMs + 1000, 0);
199
+ estimator.AddSenderReport(0, LocalBaseMs + 2000, 0);
200
+
201
+ REQUIRE_FALSE(estimator.GetOffsetMs().has_value());
202
+ }
203
+
204
+ SECTION("remote times are translated into our clock")
205
+ {
206
+ const RTC::RemoteClockOffsetEstimator untrainedEstimator;
207
+
208
+ REQUIRE_FALSE(untrainedEstimator.RemoteMsToLocalMs(RemoteBaseMs).has_value());
209
+
210
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount, 0, 0);
211
+
212
+ REQUIRE(estimator.RemoteMsToLocalMs(RemoteBaseMs).has_value());
213
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
214
+ REQUIRE(estimator.RemoteMsToLocalMs(RemoteBaseMs).value() == LocalBaseMs);
215
+ REQUIRE(estimator.RemoteMsToLocalMs(RemoteBaseMs + 500).has_value());
216
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
217
+ REQUIRE(estimator.RemoteMsToLocalMs(RemoteBaseMs + 500).value() == LocalBaseMs + 500);
218
+
219
+ // A remote time older than the origin of our clock cannot be translated.
220
+ REQUIRE_FALSE(estimator.RemoteMsToLocalMs(0).has_value());
221
+ }
222
+
223
+ SECTION("Reset() clears the estimation")
224
+ {
225
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount, 0, 0);
226
+
227
+ REQUIRE(estimator.GetOffsetMs().has_value());
228
+
229
+ estimator.Reset();
230
+
231
+ REQUIRE_FALSE(estimator.GetOffsetMs().has_value());
232
+
233
+ // The last arrival time is forgotten as well, so Sender Reports arriving at
234
+ // the very same times as before the reset are not taken as duplicates.
235
+ feed(estimator, RemoteBaseMs, LocalBaseMs, minSampleCount, 0, 0);
236
+
237
+ REQUIRE(estimator.GetOffsetMs().has_value());
238
+ // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
239
+ REQUIRE(estimator.GetOffsetMs().value() == BaseOffsetMs);
240
+ }
241
+ }
@@ -61,9 +61,9 @@ namespace
61
61
  {
62
62
  }
63
63
 
64
- void OnRtpStreamNeedWorstRemoteFractionLost(
65
- RTC::RTP::RtpStreamRecv* /*rtpStream*/, uint8_t& /*worstRemoteFractionLost*/) override
64
+ uint8_t OnRtpStreamNeedWorstRemoteFractionLost(RTC::RTP::RtpStreamRecv* /*rtpStream*/) override
66
65
  {
66
+ return 0;
67
67
  }
68
68
  };
69
69