mediasoup 3.24.2 → 3.25.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 +12 -0
- package/node/lib/Transport.d.ts.map +1 -1
- package/node/lib/Transport.js +7 -0
- package/node/lib/ortc.d.ts.map +1 -1
- package/node/lib/ortc.js +10 -0
- package/node/lib/test/test-PipeTransport.js +35 -30
- package/package.json +1 -1
- package/worker/include/DepLibUV.hpp +33 -4
- package/worker/include/RTC/Consumer.hpp +4 -1
- package/worker/include/RTC/Producer.hpp +34 -5
- package/worker/include/RTC/RTCP/Packet.hpp +7 -1
- package/worker/include/RTC/RTP/Packet.hpp +18 -0
- package/worker/include/RTC/RTP/RtpStream.hpp +76 -14
- package/worker/include/RTC/RTP/RtpStreamRecv.hpp +191 -7
- package/worker/include/RTC/RTP/RtpStreamSend.hpp +56 -10
- package/worker/include/RTC/RTP/RtxStream.hpp +34 -2
- package/worker/include/RTC/RemoteCaptureTimeEstimator.hpp +92 -0
- package/worker/include/RTC/RemoteClockOffsetEstimator.hpp +87 -0
- package/worker/include/RTC/Router.hpp +2 -5
- package/worker/include/RTC/SimulcastProducerStreamManager.hpp +3 -0
- package/worker/include/RTC/Transport.hpp +15 -7
- package/worker/include/Shared.hpp +5 -0
- package/worker/include/SharedInterface.hpp +6 -0
- package/worker/include/Utils.hpp +44 -3
- package/worker/meson.build +4 -0
- package/worker/mocks/include/MockShared.hpp +7 -0
- package/worker/src/DepLibUV.cpp +17 -0
- package/worker/src/RTC/Consumer.cpp +8 -5
- package/worker/src/RTC/Producer.cpp +85 -16
- package/worker/src/RTC/RTP/Packet.cpp +9 -1
- package/worker/src/RTC/RTP/RtpStream.cpp +14 -10
- package/worker/src/RTC/RTP/RtpStreamRecv.cpp +150 -23
- package/worker/src/RTC/RTP/RtpStreamSend.cpp +34 -19
- package/worker/src/RTC/RTP/RtxStream.cpp +12 -6
- package/worker/src/RTC/RemoteCaptureTimeEstimator.cpp +77 -0
- package/worker/src/RTC/RemoteClockOffsetEstimator.cpp +106 -0
- package/worker/src/RTC/Router.cpp +10 -8
- package/worker/src/RTC/RtpDictionaries/RtcpParameters.cpp +13 -3
- package/worker/src/RTC/SCTP/packet/chunks/SackChunk.cpp +6 -2
- package/worker/src/RTC/SimulcastProducerStreamManager.cpp +82 -40
- package/worker/src/RTC/Transport.cpp +96 -4
- package/worker/test/src/RTC/RTP/TestPacket.cpp +6 -0
- package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +2 -2
- package/worker/test/src/RTC/RTP/TestRtpStreamSend.cpp +119 -0
- package/worker/test/src/RTC/TestConsumer.cpp +4 -3
- package/worker/test/src/RTC/TestPortManager.cpp +1 -1
- package/worker/test/src/RTC/TestRemoteCaptureTimeEstimator.cpp +164 -0
- package/worker/test/src/RTC/TestRemoteClockOffsetEstimator.cpp +241 -0
- package/worker/test/src/RTC/TestSimpleProducerStreamManager.cpp +2 -2
- package/worker/test/src/RTC/TestSimulcastProducerStreamManager.cpp +340 -15
- package/worker/test/src/RTC/TestSvcProducerStreamManager.cpp +2 -2
- package/worker/test/src/RTC/TestTransportTuple.cpp +1 -1
- package/worker/test/src/Utils/TestTime.cpp +49 -0
|
@@ -164,19 +164,32 @@ namespace RTC
|
|
|
164
164
|
{
|
|
165
165
|
MS_TRACE();
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
if (first)
|
|
168
|
+
{
|
|
169
|
+
MS_DEBUG_TAG(simulcast, "first SenderReport [ssrc:%" PRIu32 "]", rtpStream->GetSsrc());
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// If the capture instant of our RTP timestamp reference stream cannot be told
|
|
173
|
+
// yet, do nothing since we know we won't be able to switch.
|
|
174
|
+
auto* producerTsReferenceRtpStream = GetProducerTsReferenceRtpStream();
|
|
175
|
+
|
|
176
|
+
if (!producerTsReferenceRtpStream || !producerTsReferenceRtpStream->GetCaptureMapping().has_value())
|
|
169
177
|
{
|
|
170
178
|
return;
|
|
171
179
|
}
|
|
172
180
|
|
|
173
|
-
|
|
181
|
+
// Other than the first Sender Report of each stream, the only one worth checking
|
|
182
|
+
// layers upon is the one that makes the capture instant of the RTP timestamp
|
|
183
|
+
// reference stream known, since other spatial layers may become switchable then.
|
|
184
|
+
// NOTE: Doing it on every single Sender Report would ask the Transport to
|
|
185
|
+
// redistribute its outgoing bitrate at the pace of the RTCP of the sender and we
|
|
186
|
+
// don't want that.
|
|
187
|
+
const bool tsReferenceCaptureMappingIsNew =
|
|
188
|
+
this->tsReferenceSpatialLayerWithCaptureMapping != this->tsReferenceSpatialLayer;
|
|
174
189
|
|
|
175
|
-
|
|
176
|
-
// since we know we won't be able to switch.
|
|
177
|
-
auto* producerTsReferenceRtpStream = GetProducerTsReferenceRtpStream();
|
|
190
|
+
this->tsReferenceSpatialLayerWithCaptureMapping = this->tsReferenceSpatialLayer;
|
|
178
191
|
|
|
179
|
-
if (!
|
|
192
|
+
if (!first && !tsReferenceCaptureMappingIsNew)
|
|
180
193
|
{
|
|
181
194
|
return;
|
|
182
195
|
}
|
|
@@ -589,43 +602,71 @@ namespace RTC
|
|
|
589
602
|
{
|
|
590
603
|
tsOffset = 0u;
|
|
591
604
|
}
|
|
592
|
-
// If this is not the RTP stream we use as TS reference,
|
|
593
|
-
//
|
|
605
|
+
// If this is not the RTP stream we use as TS reference, synchronize its RTP
|
|
606
|
+
// timestamps based on the capture instant of the media.
|
|
594
607
|
else
|
|
595
608
|
{
|
|
596
|
-
auto* producerTsReferenceRtpStream = GetProducerTsReferenceRtpStream();
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
//
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
auto ntpMs2 = producerTargetRtpStream->GetSenderReportNtpMs();
|
|
611
|
-
auto ts2 = producerTargetRtpStream->GetSenderReportTs();
|
|
612
|
-
int64_t diffMs;
|
|
613
|
-
|
|
614
|
-
if (ntpMs2 >= ntpMs1)
|
|
609
|
+
const auto* producerTsReferenceRtpStream = GetProducerTsReferenceRtpStream();
|
|
610
|
+
// NOTE: The stream of the spatial layer of this packet, which is not always
|
|
611
|
+
// the one of the target spatial layer. A resync may be pending for the
|
|
612
|
+
// current spatial layer while the target one is a different one.
|
|
613
|
+
const auto* producerRtpStream = this->producerRtpStreams.at(spatialLayer);
|
|
614
|
+
|
|
615
|
+
const auto tsReferenceCaptureMapping = producerTsReferenceRtpStream->GetCaptureMapping();
|
|
616
|
+
const auto captureMapping = producerRtpStream->GetCaptureMapping();
|
|
617
|
+
|
|
618
|
+
// Without the capture instant of the TS reference stream there is nothing to
|
|
619
|
+
// align this one to, so take this spatial layer as the new TS reference and
|
|
620
|
+
// let its RTP timestamps go untouched, which is what would have been done had
|
|
621
|
+
// it been chosen as TS reference in the first place.
|
|
622
|
+
if (!tsReferenceCaptureMapping.has_value())
|
|
615
623
|
{
|
|
616
|
-
|
|
624
|
+
MS_DEBUG_TAG(
|
|
625
|
+
simulcast,
|
|
626
|
+
"cannot tell the capture instant of the TS reference stream, using spatial layer "
|
|
627
|
+
"%" PRIi16 " as RTP timestamp reference",
|
|
628
|
+
spatialLayer);
|
|
629
|
+
|
|
630
|
+
this->tsReferenceSpatialLayer = spatialLayer;
|
|
617
631
|
}
|
|
618
|
-
|
|
632
|
+
// The capture instant of this stream cannot be told yet, so there is no way to
|
|
633
|
+
// align it and no reason to give up a TS reference stream that is good. Discard
|
|
634
|
+
// the packet and wait, since the Sender Report that is missing is on its way.
|
|
635
|
+
else if (!captureMapping.has_value())
|
|
619
636
|
{
|
|
620
|
-
|
|
621
|
-
|
|
637
|
+
MS_DEBUG_TAG(
|
|
638
|
+
simulcast,
|
|
639
|
+
"cannot tell yet the capture instant of spatial layer %" PRIi16
|
|
640
|
+
", discarding packet [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
|
|
641
|
+
spatialLayer,
|
|
642
|
+
packet->GetSsrc(),
|
|
643
|
+
packet->GetSequenceNumber());
|
|
644
|
+
|
|
645
|
+
// Ask for another key frame since this one is being discarded.
|
|
646
|
+
if (packet->IsKeyFrame())
|
|
647
|
+
{
|
|
648
|
+
RequestKeyFrame();
|
|
649
|
+
}
|
|
622
650
|
|
|
623
|
-
|
|
624
|
-
const uint32_t newTs2 = ts2 - diffTs;
|
|
651
|
+
result.type = RtpPacketProcessResult::Type::SILENT_DROP;
|
|
625
652
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
653
|
+
return result;
|
|
654
|
+
}
|
|
655
|
+
else
|
|
656
|
+
{
|
|
657
|
+
// Calculate capture instant and TS stuff.
|
|
658
|
+
const auto captureMs1 = tsReferenceCaptureMapping.value().captureMs;
|
|
659
|
+
const auto ts1 = tsReferenceCaptureMapping.value().ts;
|
|
660
|
+
const auto captureMs2 = captureMapping.value().captureMs;
|
|
661
|
+
const auto ts2 = captureMapping.value().ts;
|
|
662
|
+
const int64_t diffMs = static_cast<int64_t>(captureMs2) - static_cast<int64_t>(captureMs1);
|
|
663
|
+
const int64_t diffTs = diffMs * clockRate / 1000;
|
|
664
|
+
const uint32_t newTs2 = ts2 - diffTs;
|
|
665
|
+
|
|
666
|
+
// Apply offset. This is the difference that later must be removed from
|
|
667
|
+
// the sending RTP packet.
|
|
668
|
+
tsOffset = newTs2 - ts1;
|
|
669
|
+
}
|
|
629
670
|
}
|
|
630
671
|
|
|
631
672
|
// When switching to a new stream it may happen that the timestamp of this
|
|
@@ -857,8 +898,9 @@ namespace RTC
|
|
|
857
898
|
|
|
858
899
|
// If we don't have yet a RTP timestamp reference, set it now.
|
|
859
900
|
if (
|
|
860
|
-
newTargetSpatialLayer != -1 &&
|
|
861
|
-
|
|
901
|
+
newTargetSpatialLayer != -1 &&
|
|
902
|
+
(this->tsReferenceSpatialLayer == -1 ||
|
|
903
|
+
!GetProducerTsReferenceRtpStream()->GetCaptureMapping().has_value()))
|
|
862
904
|
{
|
|
863
905
|
MS_DEBUG_TAG(
|
|
864
906
|
simulcast, "using spatial layer %" PRIi16 " as RTP timestamp reference", newTargetSpatialLayer);
|
|
@@ -1050,7 +1092,7 @@ namespace RTC
|
|
|
1050
1092
|
|
|
1051
1093
|
return (
|
|
1052
1094
|
this->tsReferenceSpatialLayer == -1 || spatialLayer == this->tsReferenceSpatialLayer ||
|
|
1053
|
-
this->producerRtpStreams.at(spatialLayer)->
|
|
1095
|
+
this->producerRtpStreams.at(spatialLayer)->GetCaptureMapping().has_value());
|
|
1054
1096
|
}
|
|
1055
1097
|
|
|
1056
1098
|
RTC::RTP::RtpStreamRecv* SimulcastProducerStreamManager::GetProducerTsReferenceRtpStream() const
|
|
@@ -640,6 +640,15 @@ namespace RTC
|
|
|
640
640
|
// Insert into the map.
|
|
641
641
|
this->mapProducers[producerId] = producer;
|
|
642
642
|
|
|
643
|
+
// Take this Producer into account for the capture time estimation of its
|
|
644
|
+
// sender.
|
|
645
|
+
{
|
|
646
|
+
const auto& cname = producer->GetRtpParameters().rtcp.cname;
|
|
647
|
+
|
|
648
|
+
this->mapCnameRemoteCaptureTimeEstimator[cname].UpdateSource(
|
|
649
|
+
producer->GetRtpHeaderExtensionIds().absCaptureTime != 0);
|
|
650
|
+
}
|
|
651
|
+
|
|
643
652
|
MS_DEBUG_DEV("Producer created [producerId:%s]", producerId.c_str());
|
|
644
653
|
|
|
645
654
|
// Take the transport related RTP header extensions of the Producer and
|
|
@@ -680,6 +689,14 @@ namespace RTC
|
|
|
680
689
|
producerRtpHeaderExtensionIds.dependencyDescriptor;
|
|
681
690
|
}
|
|
682
691
|
|
|
692
|
+
// NOTE: Not transport related, but needed here so that received packets carry
|
|
693
|
+
// its id and `RtpStreamRecv` can read the extension off them.
|
|
694
|
+
if (producerRtpHeaderExtensionIds.absCaptureTime != 0)
|
|
695
|
+
{
|
|
696
|
+
this->recvRtpHeaderExtensionIds.absCaptureTime =
|
|
697
|
+
producerRtpHeaderExtensionIds.absCaptureTime;
|
|
698
|
+
}
|
|
699
|
+
|
|
683
700
|
// Create status response.
|
|
684
701
|
auto responseOffset = FBS::Transport::CreateProduceResponse(
|
|
685
702
|
request->GetBufferBuilder(), FBS::RtpParameters::Type(producer->GetType()));
|
|
@@ -1245,6 +1262,26 @@ namespace RTC
|
|
|
1245
1262
|
// Remove it from the map.
|
|
1246
1263
|
this->mapProducers.erase(producer->id);
|
|
1247
1264
|
|
|
1265
|
+
// Remove the capture time estimator of its sender once its last Producer
|
|
1266
|
+
// is gone.
|
|
1267
|
+
{
|
|
1268
|
+
const auto& cname = producer->GetRtpParameters().rtcp.cname;
|
|
1269
|
+
|
|
1270
|
+
const bool cnameStillInUse = std::ranges::any_of(
|
|
1271
|
+
this->mapProducers,
|
|
1272
|
+
[&cname](const auto& kv)
|
|
1273
|
+
{
|
|
1274
|
+
const auto* otherProducer = kv.second;
|
|
1275
|
+
|
|
1276
|
+
return otherProducer->GetRtpParameters().rtcp.cname == cname;
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
if (!cnameStillInUse)
|
|
1280
|
+
{
|
|
1281
|
+
this->mapCnameRemoteCaptureTimeEstimator.erase(cname);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1248
1285
|
// Tell the child class to clear associated SSRCs.
|
|
1249
1286
|
for (const auto& kv : producer->GetRtpStreams())
|
|
1250
1287
|
{
|
|
@@ -2538,6 +2575,17 @@ namespace RTC
|
|
|
2538
2575
|
{
|
|
2539
2576
|
MS_TRACE();
|
|
2540
2577
|
|
|
2578
|
+
// Feed the capture time estimator of the sender of this Producer.
|
|
2579
|
+
const auto it =
|
|
2580
|
+
this->mapCnameRemoteCaptureTimeEstimator.find(producer->GetRtpParameters().rtcp.cname);
|
|
2581
|
+
|
|
2582
|
+
if (it != this->mapCnameRemoteCaptureTimeEstimator.end())
|
|
2583
|
+
{
|
|
2584
|
+
auto& remoteCaptureTimeEstimator = it->second;
|
|
2585
|
+
|
|
2586
|
+
remoteCaptureTimeEstimator.SenderReportReceived(rtpStream);
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2541
2589
|
this->listener->OnTransportProducerRtcpSenderReport(this, producer, rtpStream, first);
|
|
2542
2590
|
}
|
|
2543
2591
|
|
|
@@ -2555,13 +2603,57 @@ namespace RTC
|
|
|
2555
2603
|
SendRtcpPacket(packet);
|
|
2556
2604
|
}
|
|
2557
2605
|
|
|
2558
|
-
|
|
2559
|
-
|
|
2606
|
+
uint8_t Transport::OnProducerNeedWorstRemoteFractionLost(RTC::Producer* producer, uint32_t mappedSsrc)
|
|
2607
|
+
{
|
|
2608
|
+
MS_TRACE();
|
|
2609
|
+
|
|
2610
|
+
return this->listener->OnTransportNeedWorstRemoteFractionLost(this, producer, mappedSsrc);
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
std::optional<uint64_t> Transport::OnProducerNeedLocalCaptureMs(
|
|
2614
|
+
RTC::Producer* producer, const RTC::RTP::RtpStreamRecv* rtpStream, uint32_t ts)
|
|
2615
|
+
{
|
|
2616
|
+
MS_TRACE();
|
|
2617
|
+
|
|
2618
|
+
const auto it =
|
|
2619
|
+
this->mapCnameRemoteCaptureTimeEstimator.find(producer->GetRtpParameters().rtcp.cname);
|
|
2620
|
+
|
|
2621
|
+
if (it == this->mapCnameRemoteCaptureTimeEstimator.end())
|
|
2622
|
+
{
|
|
2623
|
+
return std::nullopt;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
const auto& remoteCaptureTimeEstimator = it->second;
|
|
2627
|
+
|
|
2628
|
+
return remoteCaptureTimeEstimator.GetLocalCaptureMs(rtpStream, ts);
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
std::optional<int64_t> Transport::OnProducerNeedRemoteClockOffsetMs(const RTC::Producer* producer)
|
|
2560
2632
|
{
|
|
2561
2633
|
MS_TRACE();
|
|
2562
2634
|
|
|
2563
|
-
|
|
2564
|
-
this
|
|
2635
|
+
const auto it =
|
|
2636
|
+
this->mapCnameRemoteCaptureTimeEstimator.find(producer->GetRtpParameters().rtcp.cname);
|
|
2637
|
+
|
|
2638
|
+
if (it == this->mapCnameRemoteCaptureTimeEstimator.end())
|
|
2639
|
+
{
|
|
2640
|
+
return std::nullopt;
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
const auto& remoteCaptureTimeEstimator = it->second;
|
|
2644
|
+
const auto clockOffsetMs = remoteCaptureTimeEstimator.GetClockOffsetMs();
|
|
2645
|
+
|
|
2646
|
+
if (!clockOffsetMs.has_value())
|
|
2647
|
+
{
|
|
2648
|
+
return std::nullopt;
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// NOTE: The estimator gives the offset against our own monotonic clock, while what
|
|
2652
|
+
// a receiver reconstructs out of the Sender Reports we send is the clock we
|
|
2653
|
+
// announce, so the distance to the NTP epoch has to be taken into account. Both
|
|
2654
|
+
// terms are huge and their sum is small, so they are added as milliseconds before
|
|
2655
|
+
// anything scales them up.
|
|
2656
|
+
return clockOffsetMs.value() + static_cast<int64_t>(this->shared->GetNtpOffsetMs());
|
|
2565
2657
|
}
|
|
2566
2658
|
|
|
2567
2659
|
void Transport::OnConsumerSendRtpPacket(RTC::Consumer* consumer, RTC::RTP::Packet* packet)
|
|
@@ -1059,12 +1059,16 @@ SCENARIO("RTP Packet", "[serializable][rtp][packet]")
|
|
|
1059
1059
|
/*paddingLength*/ 0);
|
|
1060
1060
|
|
|
1061
1061
|
REQUIRE(packet->IsPaddedTo4Bytes() == true);
|
|
1062
|
+
REQUIRE(packet->GetCaptureMs() == std::nullopt);
|
|
1062
1063
|
|
|
1063
1064
|
packet->SetPayloadType(100);
|
|
1064
1065
|
packet->SetMarker(true);
|
|
1065
1066
|
packet->SetSequenceNumber(12345);
|
|
1066
1067
|
packet->SetTimestamp(987654321);
|
|
1067
1068
|
packet->SetSsrc(1234567890);
|
|
1069
|
+
packet->SetCaptureMs(99998888);
|
|
1070
|
+
|
|
1071
|
+
REQUIRE(packet->GetCaptureMs() == 99998888);
|
|
1068
1072
|
|
|
1069
1073
|
std::vector<RTC::RTP::Packet::Extension> extensions;
|
|
1070
1074
|
|
|
@@ -1204,6 +1208,7 @@ SCENARIO("RTP Packet", "[serializable][rtp][packet]")
|
|
|
1204
1208
|
REQUIRE(extensionLen == 3);
|
|
1205
1209
|
|
|
1206
1210
|
REQUIRE(packet->IsPaddedTo4Bytes() == true);
|
|
1211
|
+
REQUIRE(packet->GetCaptureMs() == 99998888);
|
|
1207
1212
|
|
|
1208
1213
|
/* Clone it. */
|
|
1209
1214
|
|
|
@@ -1252,6 +1257,7 @@ SCENARIO("RTP Packet", "[serializable][rtp][packet]")
|
|
|
1252
1257
|
REQUIRE(extensionLen == 3);
|
|
1253
1258
|
|
|
1254
1259
|
REQUIRE(packet->IsPaddedTo4Bytes() == true);
|
|
1260
|
+
REQUIRE(packet->GetCaptureMs() == 99998888);
|
|
1255
1261
|
|
|
1256
1262
|
/* Set payload. */
|
|
1257
1263
|
|
|
@@ -106,9 +106,9 @@ SCENARIO("RtpStreamRecv", "[rtp][rtpstream][rtpstreamrecv]")
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
RTC::RTP::RtpStreamRecv* /*rtpStream*/, uint8_t& /*worstRemoteFractionLost*/) override
|
|
109
|
+
uint8_t OnRtpStreamNeedWorstRemoteFractionLost(RTC::RTP::RtpStreamRecv* /*rtpStream*/) override
|
|
111
110
|
{
|
|
111
|
+
return 0;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
public:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "common.hpp"
|
|
2
2
|
#include "RTC/RTCP/FeedbackRtpNack.hpp"
|
|
3
|
+
#include "RTC/RTCP/SenderReport.hpp"
|
|
3
4
|
#include "RTC/RTP/Codecs/AV1.hpp"
|
|
4
5
|
#include "RTC/RTP/Codecs/PayloadDescriptorHandler.hpp"
|
|
5
6
|
#include "RTC/RTP/Codecs/VP8.hpp"
|
|
@@ -1125,6 +1126,124 @@ SCENARIO("RtpStreamSend", "[rtp][rtcp][nack][rtpstream][rtpstreamsend]")
|
|
|
1125
1126
|
REQUIRE(result == RTC::RTP::RtpStreamSend::ReceivePacketResult::DISCARDED);
|
|
1126
1127
|
}
|
|
1127
1128
|
|
|
1129
|
+
SECTION("Sender Report RTP timestamp is based on the capture instant when known")
|
|
1130
|
+
{
|
|
1131
|
+
// Instant reported by the mocked clock, and hence the one at which packets are seen.
|
|
1132
|
+
constexpr uint64_t PacketMs{ 1000 };
|
|
1133
|
+
constexpr uint32_t PacketTs{ 1533790901 };
|
|
1134
|
+
|
|
1135
|
+
TestRtpStreamListener testRtpStreamListener;
|
|
1136
|
+
|
|
1137
|
+
RTC::RTP::RtpStream::Params params;
|
|
1138
|
+
|
|
1139
|
+
params.ssrc = 1111;
|
|
1140
|
+
params.clockRate = 90000;
|
|
1141
|
+
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
|
|
1142
|
+
|
|
1143
|
+
std::string mid;
|
|
1144
|
+
|
|
1145
|
+
// Without capture instant, the instant at which the packet was seen is used.
|
|
1146
|
+
{
|
|
1147
|
+
RTC::RTP::RtpStreamSend stream(
|
|
1148
|
+
std::addressof(testRtpStreamListener), std::addressof(shared), params, mid);
|
|
1149
|
+
auto packet(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, PacketTs));
|
|
1150
|
+
|
|
1151
|
+
sendRtpPacket(
|
|
1152
|
+
{
|
|
1153
|
+
{ std::addressof(stream), params.ssrc }
|
|
1154
|
+
},
|
|
1155
|
+
packet.get());
|
|
1156
|
+
|
|
1157
|
+
const std::unique_ptr<RTC::RTCP::SenderReport> report(
|
|
1158
|
+
stream.GetRtcpSenderReport(PacketMs + 1000));
|
|
1159
|
+
|
|
1160
|
+
REQUIRE(report);
|
|
1161
|
+
REQUIRE(report->GetRtpTs() == PacketTs + params.clockRate);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// With capture instant, the extra half second since it is accounted for.
|
|
1165
|
+
{
|
|
1166
|
+
RTC::RTP::RtpStreamSend stream(
|
|
1167
|
+
std::addressof(testRtpStreamListener), std::addressof(shared), params, mid);
|
|
1168
|
+
auto packet(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, PacketTs));
|
|
1169
|
+
|
|
1170
|
+
packet->SetCaptureMs(PacketMs - 500);
|
|
1171
|
+
|
|
1172
|
+
sendRtpPacket(
|
|
1173
|
+
{
|
|
1174
|
+
{ std::addressof(stream), params.ssrc }
|
|
1175
|
+
},
|
|
1176
|
+
packet.get());
|
|
1177
|
+
|
|
1178
|
+
const std::unique_ptr<RTC::RTCP::SenderReport> report(
|
|
1179
|
+
stream.GetRtcpSenderReport(PacketMs + 1000));
|
|
1180
|
+
|
|
1181
|
+
REQUIRE(report);
|
|
1182
|
+
REQUIRE(report->GetRtpTs() == PacketTs + ((1500 * params.clockRate) / 1000));
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// A capture instant ahead of now, which the estimation may yield, does not make the
|
|
1186
|
+
// difference wrap around.
|
|
1187
|
+
{
|
|
1188
|
+
RTC::RTP::RtpStreamSend stream(
|
|
1189
|
+
std::addressof(testRtpStreamListener), std::addressof(shared), params, mid);
|
|
1190
|
+
auto packet(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, PacketTs));
|
|
1191
|
+
|
|
1192
|
+
packet->SetCaptureMs(PacketMs + 3000);
|
|
1193
|
+
|
|
1194
|
+
sendRtpPacket(
|
|
1195
|
+
{
|
|
1196
|
+
{ std::addressof(stream), params.ssrc }
|
|
1197
|
+
},
|
|
1198
|
+
packet.get());
|
|
1199
|
+
|
|
1200
|
+
const std::unique_ptr<RTC::RTCP::SenderReport> report(
|
|
1201
|
+
stream.GetRtcpSenderReport(PacketMs + 1000));
|
|
1202
|
+
|
|
1203
|
+
REQUIRE(report);
|
|
1204
|
+
REQUIRE(report->GetRtpTs() == PacketTs);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
SECTION("no Sender Report is generated once the stream has stopped sending")
|
|
1209
|
+
{
|
|
1210
|
+
// Instant reported by the mocked clock, and hence the one at which packets are seen.
|
|
1211
|
+
constexpr uint64_t PacketMs{ 1000 };
|
|
1212
|
+
constexpr uint32_t PacketTs{ 1533790901 };
|
|
1213
|
+
|
|
1214
|
+
TestRtpStreamListener testRtpStreamListener;
|
|
1215
|
+
|
|
1216
|
+
RTC::RTP::RtpStream::Params params;
|
|
1217
|
+
|
|
1218
|
+
params.ssrc = 1111;
|
|
1219
|
+
params.clockRate = 90000;
|
|
1220
|
+
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
|
|
1221
|
+
|
|
1222
|
+
std::string mid;
|
|
1223
|
+
|
|
1224
|
+
RTC::RTP::RtpStreamSend stream(
|
|
1225
|
+
std::addressof(testRtpStreamListener), std::addressof(shared), params, mid);
|
|
1226
|
+
auto packet(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, PacketTs));
|
|
1227
|
+
|
|
1228
|
+
sendRtpPacket(
|
|
1229
|
+
{
|
|
1230
|
+
{ std::addressof(stream), params.ssrc }
|
|
1231
|
+
},
|
|
1232
|
+
packet.get());
|
|
1233
|
+
|
|
1234
|
+
// Right at the limit the Sender Report is still generated.
|
|
1235
|
+
const std::unique_ptr<RTC::RTCP::SenderReport> report(
|
|
1236
|
+
stream.GetRtcpSenderReport(PacketMs + RTC::RTP::RtpStreamSend::MaxSenderReportReferenceAgeMs));
|
|
1237
|
+
|
|
1238
|
+
REQUIRE(report);
|
|
1239
|
+
|
|
1240
|
+
// Past the limit it is not.
|
|
1241
|
+
const std::unique_ptr<RTC::RTCP::SenderReport> staleReport(stream.GetRtcpSenderReport(
|
|
1242
|
+
PacketMs + RTC::RTP::RtpStreamSend::MaxSenderReportReferenceAgeMs + 1));
|
|
1243
|
+
|
|
1244
|
+
REQUIRE_FALSE(staleReport);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1128
1247
|
#ifdef PERFORMANCE_TEST
|
|
1129
1248
|
SECTION("Performance")
|
|
1130
1249
|
{
|
|
@@ -33,9 +33,9 @@ namespace
|
|
|
33
33
|
{
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
RTC::RTP::RtpStreamRecv* /*rtpStream*/, uint8_t& /*worstRemoteFractionLost*/) override
|
|
36
|
+
uint8_t OnRtpStreamNeedWorstRemoteFractionLost(RTC::RTP::RtpStreamRecv* /*rtpStream*/) override
|
|
38
37
|
{
|
|
38
|
+
return 0;
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -104,7 +104,8 @@ namespace
|
|
|
104
104
|
|
|
105
105
|
encoding.ssrc = 1234567890;
|
|
106
106
|
|
|
107
|
-
rtpParameters.mid
|
|
107
|
+
rtpParameters.mid = "mid";
|
|
108
|
+
rtpParameters.rtcp.cname = "cname";
|
|
108
109
|
rtpParameters.codecs.emplace_back(codec);
|
|
109
110
|
rtpParameters.encodings.emplace_back(encoding);
|
|
110
111
|
rtpParameters.headerExtensions = std::vector<RTC::RtpHeaderExtensionParameters>();
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// merged unrelated bindings. This scenario locks down the post-fix
|
|
11
11
|
// behavior: distinct tuples produce distinct keys, equal tuples produce equal
|
|
12
12
|
// keys.
|
|
13
|
-
SCENARIO("PortManager", "[
|
|
13
|
+
SCENARIO("PortManager", "[portmanager]")
|
|
14
14
|
{
|
|
15
15
|
// Helper: build an IPv4 `sockaddr_storage` from a dotted-quad string + port=0.
|
|
16
16
|
auto makeV4 = [](const char* dottedQuad)
|
|
@@ -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
|
+
}
|