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.
- package/CHANGELOG.md +16 -0
- package/node/lib/Consumer.js +1 -1
- 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 +6 -6
- 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 +115 -56
- package/worker/src/RTC/SvcProducerStreamManager.cpp +22 -17
- 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
|
@@ -80,6 +80,9 @@ namespace RTC
|
|
|
80
80
|
int16_t spatialLayerToSync{ -1 };
|
|
81
81
|
// Timestamp synchronization.
|
|
82
82
|
int16_t tsReferenceSpatialLayer{ -1 };
|
|
83
|
+
// Spatial layer that was the RTP timestamp reference the last time its capture
|
|
84
|
+
// instant was known upon a received Sender Report.
|
|
85
|
+
int16_t tsReferenceSpatialLayerWithCaptureMapping{ -1 };
|
|
83
86
|
uint32_t tsOffset{ 0u };
|
|
84
87
|
bool keyFrameForTsOffsetRequested{ false };
|
|
85
88
|
// Old-packet filtering after spatial switch.
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
#include "RTC/RTP/HeaderExtensionIds.hpp"
|
|
18
18
|
#include "RTC/RTP/Packet.hpp"
|
|
19
19
|
#include "RTC/RateCalculator.hpp"
|
|
20
|
+
#include "RTC/RemoteCaptureTimeEstimator.hpp"
|
|
20
21
|
#include "RTC/RtpListener.hpp"
|
|
21
22
|
#include "RTC/SCTP/public/AssociationInterface.hpp"
|
|
22
23
|
#include "RTC/SCTP/public/AssociationListenerInterface.hpp"
|
|
@@ -83,11 +84,12 @@ namespace RTC
|
|
|
83
84
|
bool first) = 0;
|
|
84
85
|
virtual void OnTransportProducerRtpPacketReceived(
|
|
85
86
|
RTC::Transport* transport, RTC::Producer* producer, RTC::RTP::Packet* packet) = 0;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Obtains the worst remote fraction lost of all the Consumers consuming the
|
|
89
|
+
* given mapped SSRC of the given Producer.
|
|
90
|
+
*/
|
|
91
|
+
virtual uint8_t OnTransportNeedWorstRemoteFractionLost(
|
|
92
|
+
RTC::Transport* transport, RTC::Producer* producer, uint32_t mappedSsrc) = 0;
|
|
91
93
|
virtual void OnTransportNewConsumer(
|
|
92
94
|
RTC::Transport* transport, RTC::Consumer* consumer, const std::string& producerId) = 0;
|
|
93
95
|
virtual void OnTransportConsumerClosed(RTC::Transport* transport, RTC::Consumer* consumer) = 0;
|
|
@@ -264,8 +266,10 @@ namespace RTC
|
|
|
264
266
|
RTC::Producer* producer, RTC::RTP::RtpStreamRecv* rtpStream, bool first) override;
|
|
265
267
|
void OnProducerRtpPacketReceived(RTC::Producer* producer, RTC::RTP::Packet* packet) override;
|
|
266
268
|
void OnProducerSendRtcpPacket(RTC::Producer* producer, RTC::RTCP::Packet* packet) override;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
+
uint8_t OnProducerNeedWorstRemoteFractionLost(RTC::Producer* producer, uint32_t mappedSsrc) override;
|
|
270
|
+
std::optional<uint64_t> OnProducerNeedLocalCaptureMs(
|
|
271
|
+
RTC::Producer* producer, const RTC::RTP::RtpStreamRecv* rtpStream, uint32_t ts) override;
|
|
272
|
+
std::optional<int64_t> OnProducerNeedRemoteClockOffsetMs(const RTC::Producer* producer) override;
|
|
269
273
|
|
|
270
274
|
/* Pure virtual methods inherited from RTC::Consumer::Listener. */
|
|
271
275
|
public:
|
|
@@ -367,6 +371,10 @@ namespace RTC
|
|
|
367
371
|
ankerl::unordered_dense::map<uint16_t, RTC::DataConsumer*> mapSctpStreamIdDataConsumers;
|
|
368
372
|
ankerl::unordered_dense::map<uint32_t, RTC::Consumer*> mapSsrcConsumer;
|
|
369
373
|
ankerl::unordered_dense::map<uint32_t, RTC::Consumer*> mapRtxSsrcConsumer;
|
|
374
|
+
// Capture time estimator of each sender publishing to this Transport, keyed by
|
|
375
|
+
// its CNAME.
|
|
376
|
+
ankerl::unordered_dense::map<std::string, RTC::RemoteCaptureTimeEstimator>
|
|
377
|
+
mapCnameRemoteCaptureTimeEstimator;
|
|
370
378
|
TimerHandleInterface* rtcpTimer{ nullptr };
|
|
371
379
|
// Allocated by this.
|
|
372
380
|
std::unique_ptr<RTC::SCTP::AssociationInterface> sctpAssociation{ nullptr };
|
|
@@ -56,6 +56,11 @@ public:
|
|
|
56
56
|
return DepLibUV::GetTimeUsInt64();
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
uint64_t GetNtpOffsetMs() override
|
|
60
|
+
{
|
|
61
|
+
return DepLibUV::GetNtpOffsetMs();
|
|
62
|
+
}
|
|
63
|
+
|
|
59
64
|
private:
|
|
60
65
|
std::unique_ptr<Channel::ChannelMessageRegistrator> channelMessageRegistrator;
|
|
61
66
|
std::unique_ptr<Channel::ChannelNotifier> channelNotifier;
|
|
@@ -72,6 +72,12 @@ public:
|
|
|
72
72
|
* @todo Remove once not needed.
|
|
73
73
|
*/
|
|
74
74
|
virtual int64_t GetTimeUsInt64() = 0;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Distance from the clock above to the NTP epoch (ms), which is what has to be added
|
|
78
|
+
* to it to obtain the NTP timestamps of the RTCP we generate.
|
|
79
|
+
*/
|
|
80
|
+
virtual uint64_t GetNtpOffsetMs() = 0;
|
|
75
81
|
};
|
|
76
82
|
|
|
77
83
|
#endif
|
package/worker/include/Utils.hpp
CHANGED
|
@@ -500,9 +500,11 @@ namespace Utils
|
|
|
500
500
|
|
|
501
501
|
class Time
|
|
502
502
|
{
|
|
503
|
-
|
|
503
|
+
public:
|
|
504
504
|
// Seconds from Jan 1, 1900 to Jan 1, 1970.
|
|
505
|
-
static constexpr uint32_t
|
|
505
|
+
static constexpr uint32_t UnixNtpOffsetSec{ 0x83AA7E80 };
|
|
506
|
+
|
|
507
|
+
private:
|
|
506
508
|
// NTP fractional unit.
|
|
507
509
|
static constexpr uint64_t NtpFractionalUnit{ 1LL << 32 };
|
|
508
510
|
|
|
@@ -517,7 +519,11 @@ namespace Utils
|
|
|
517
519
|
{
|
|
518
520
|
Time::Ntp ntp{}; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
|
519
521
|
|
|
520
|
-
|
|
522
|
+
// NOTE: The truncation is intended. Seconds are 32 bits wide in NTP, so they wrap
|
|
523
|
+
// every 2^32 seconds since Jan 1, 1900, being Feb 7, 2036 the next time it
|
|
524
|
+
// happens. That is the NTP era and receivers deal with it by doing modular
|
|
525
|
+
// arithmetic, so there is nothing to protect against here.
|
|
526
|
+
ntp.seconds = static_cast<uint32_t>(ms / 1000);
|
|
521
527
|
ntp.fractions =
|
|
522
528
|
static_cast<uint32_t>((static_cast<double>(ms % 1000) / 1000) * NtpFractionalUnit);
|
|
523
529
|
|
|
@@ -536,6 +542,41 @@ namespace Utils
|
|
|
536
542
|
{
|
|
537
543
|
return static_cast<uint32_t>(((ms << 18) + 500) / 1000) & 0x00FFFFFF;
|
|
538
544
|
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Convert milliseconds into signed Q32.32 fixed point seconds, which is how the
|
|
548
|
+
* `abs-capture-time` RTP header extension encodes its clock offset, being the
|
|
549
|
+
* capture timestamp itself unsigned instead (UQ32.32).
|
|
550
|
+
*
|
|
551
|
+
* @returns No value if the given instant does not fit in the format, whose seconds
|
|
552
|
+
* are 32 bits wide.
|
|
553
|
+
*
|
|
554
|
+
* @see https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-abs-capture-time-00
|
|
555
|
+
*/
|
|
556
|
+
static std::optional<int64_t> TimeMs2Q32x32(int64_t ms)
|
|
557
|
+
{
|
|
558
|
+
// The seconds of the format are 32 bits wide, so from here on it does not fit.
|
|
559
|
+
static constexpr int64_t OutOfRangeMs{ (1LL << 31) * 1000 };
|
|
560
|
+
|
|
561
|
+
if (ms >= OutOfRangeMs || ms <= -OutOfRangeMs)
|
|
562
|
+
{
|
|
563
|
+
return std::nullopt;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return static_cast<int64_t>(
|
|
567
|
+
std::round(static_cast<double>(ms) * (static_cast<double>(NtpFractionalUnit) / 1000)));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Convert signed Q32.32 fixed point seconds into milliseconds.
|
|
572
|
+
*
|
|
573
|
+
* @see https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-abs-capture-time-00
|
|
574
|
+
*/
|
|
575
|
+
static int64_t Q32x32ToTimeMs(int64_t q32x32)
|
|
576
|
+
{
|
|
577
|
+
return static_cast<int64_t>(
|
|
578
|
+
std::round(static_cast<double>(q32x32) * (1000 / static_cast<double>(NtpFractionalUnit))));
|
|
579
|
+
}
|
|
539
580
|
};
|
|
540
581
|
|
|
541
582
|
class BitStream
|
package/worker/meson.build
CHANGED
|
@@ -124,6 +124,8 @@ common_sources = [
|
|
|
124
124
|
'src/RTC/PortManager.cpp',
|
|
125
125
|
'src/RTC/Producer.cpp',
|
|
126
126
|
'src/RTC/RateCalculator.cpp',
|
|
127
|
+
'src/RTC/RemoteCaptureTimeEstimator.cpp',
|
|
128
|
+
'src/RTC/RemoteClockOffsetEstimator.cpp',
|
|
127
129
|
'src/RTC/Router.cpp',
|
|
128
130
|
'src/RTC/RtcLogger.cpp',
|
|
129
131
|
'src/RTC/RtpListener.cpp',
|
|
@@ -429,6 +431,8 @@ test_sources = [
|
|
|
429
431
|
'test/src/RTC/TestNackGenerator.cpp',
|
|
430
432
|
'test/src/RTC/TestPortManager.cpp',
|
|
431
433
|
'test/src/RTC/TestRateCalculator.cpp',
|
|
434
|
+
'test/src/RTC/TestRemoteCaptureTimeEstimator.cpp',
|
|
435
|
+
'test/src/RTC/TestRemoteClockOffsetEstimator.cpp',
|
|
432
436
|
'test/src/RTC/TestRtpEncodingParameters.cpp',
|
|
433
437
|
'test/src/RTC/TestSeqManager.cpp',
|
|
434
438
|
'test/src/RTC/TestSubchannelsCodec.cpp',
|
|
@@ -60,6 +60,13 @@ namespace mocks
|
|
|
60
60
|
return static_cast<int64_t>(GetTimeUs());
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// NOTE: The NTP epoch is made to be the very clock given by argument, so that tests
|
|
64
|
+
// can reason about a single set of values.
|
|
65
|
+
uint64_t GetNtpOffsetMs() override
|
|
66
|
+
{
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
// Methods for testing.
|
|
64
71
|
public:
|
|
65
72
|
MockBackoffTimerHandle* GetBackoffTimer(const std::string_view label) const
|
package/worker/src/DepLibUV.cpp
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
#include "DepLibUV.hpp"
|
|
5
5
|
#include "Logger.hpp"
|
|
6
|
+
#include "Utils.hpp"
|
|
6
7
|
|
|
7
8
|
/* Class variables. */
|
|
8
9
|
|
|
9
10
|
thread_local uv_loop_t* DepLibUV::loop{ nullptr };
|
|
11
|
+
thread_local uint64_t DepLibUV::ntpOffsetMs{ 0 };
|
|
10
12
|
|
|
11
13
|
/* Static methods for UV callbacks. */
|
|
12
14
|
|
|
@@ -48,6 +50,21 @@ void DepLibUV::ClassInit()
|
|
|
48
50
|
{
|
|
49
51
|
MS_ABORT("libuv loop initialization failed");
|
|
50
52
|
}
|
|
53
|
+
|
|
54
|
+
// Take the distance from our own monotonic clock to the NTP epoch just once, so that
|
|
55
|
+
// the NTP timestamps we generate never step when the system clock is adjusted.
|
|
56
|
+
uv_timeval64_t timeval{}; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
|
57
|
+
|
|
58
|
+
if (uv_gettimeofday(std::addressof(timeval)) != 0)
|
|
59
|
+
{
|
|
60
|
+
MS_ABORT("uv_gettimeofday() failed");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const auto unixSec = static_cast<uint64_t>(timeval.tv_sec);
|
|
64
|
+
const auto unixMs = (unixSec * 1000) + (static_cast<uint64_t>(timeval.tv_usec) / 1000);
|
|
65
|
+
const auto ntpMs = unixMs + (static_cast<uint64_t>(Utils::Time::UnixNtpOffsetSec) * 1000);
|
|
66
|
+
|
|
67
|
+
DepLibUV::ntpOffsetMs = ntpMs - DepLibUV::GetTimeMs();
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
void DepLibUV::ClassDestroy()
|
|
@@ -1414,22 +1414,25 @@ namespace RTC
|
|
|
1414
1414
|
return true;
|
|
1415
1415
|
}
|
|
1416
1416
|
|
|
1417
|
-
|
|
1417
|
+
uint8_t Consumer::GetWorstRemoteFractionLost(uint32_t /*mappedSsrc*/) const
|
|
1418
1418
|
{
|
|
1419
1419
|
MS_TRACE();
|
|
1420
1420
|
|
|
1421
1421
|
if (!IsActive())
|
|
1422
1422
|
{
|
|
1423
|
-
return;
|
|
1423
|
+
return 0;
|
|
1424
1424
|
}
|
|
1425
1425
|
|
|
1426
|
-
|
|
1426
|
+
uint8_t worstRemoteFractionLost{ 0 };
|
|
1427
|
+
|
|
1428
|
+
for (const auto* rtpStream : this->rtpStreams)
|
|
1427
1429
|
{
|
|
1428
|
-
auto fractionLost = rtpStream->GetFractionLost();
|
|
1430
|
+
const auto fractionLost = rtpStream->GetFractionLost();
|
|
1429
1431
|
|
|
1430
|
-
// If our fraction lost is worse than the given one, update it.
|
|
1431
1432
|
worstRemoteFractionLost = std::max(fractionLost, worstRemoteFractionLost);
|
|
1432
1433
|
}
|
|
1434
|
+
|
|
1435
|
+
return worstRemoteFractionLost;
|
|
1433
1436
|
}
|
|
1434
1437
|
|
|
1435
1438
|
void Consumer::ReceiveNack(RTC::RTCP::FeedbackRtpNackPacket* nackPacket)
|
|
@@ -580,6 +580,9 @@ namespace RTC
|
|
|
580
580
|
|
|
581
581
|
ReceiveRtpPacketResult result;
|
|
582
582
|
bool isRtx{ false };
|
|
583
|
+
// Highest RTP timestamp of the stream before this packet is processed, so that it
|
|
584
|
+
// can be told afterwards whether this packet made it change.
|
|
585
|
+
const auto previousMaxPacketTs = rtpStream->GetMaxPacketTs();
|
|
583
586
|
|
|
584
587
|
// Media packet.
|
|
585
588
|
if (packet->GetSsrc() == rtpStream->GetSsrc())
|
|
@@ -675,7 +678,10 @@ namespace RTC
|
|
|
675
678
|
}
|
|
676
679
|
|
|
677
680
|
// Post-process the packet.
|
|
678
|
-
PostProcessRtpPacket(
|
|
681
|
+
PostProcessRtpPacket(
|
|
682
|
+
packet,
|
|
683
|
+
rtpStream,
|
|
684
|
+
/*maxPacketTsChanged*/ rtpStream->GetMaxPacketTs() != previousMaxPacketTs);
|
|
679
685
|
|
|
680
686
|
this->listener->OnProducerRtpPacketReceived(this, packet);
|
|
681
687
|
|
|
@@ -691,7 +697,7 @@ namespace RTC
|
|
|
691
697
|
if (it != this->mapSsrcRtpStream.end())
|
|
692
698
|
{
|
|
693
699
|
auto* rtpStream = it->second;
|
|
694
|
-
const bool first = rtpStream->
|
|
700
|
+
const bool first = !rtpStream->GetSenderReportMapping().has_value();
|
|
695
701
|
|
|
696
702
|
rtpStream->ReceiveRtcpSenderReport(report);
|
|
697
703
|
|
|
@@ -765,7 +771,8 @@ namespace RTC
|
|
|
765
771
|
// Add a receiver reference time report if no present in the packet.
|
|
766
772
|
if (!packet->HasReceiverReferenceTime())
|
|
767
773
|
{
|
|
768
|
-
auto ntp
|
|
774
|
+
auto ntp = Utils::Time::TimeMs2Ntp(nowMs + this->shared->GetNtpOffsetMs());
|
|
775
|
+
|
|
769
776
|
receiverReferenceTimeReport = new RTC::RTCP::ReceiverReferenceTime();
|
|
770
777
|
|
|
771
778
|
receiverReferenceTimeReport->SetNtpSec(ntp.seconds);
|
|
@@ -1223,19 +1230,64 @@ namespace RTC
|
|
|
1223
1230
|
}
|
|
1224
1231
|
|
|
1225
1232
|
// Proxy http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time.
|
|
1233
|
+
//
|
|
1234
|
+
// The capture timestamp is left untouched since it belongs to the clock of the
|
|
1235
|
+
// capture system, but the capture clock offset has to be rewritten. It tells the
|
|
1236
|
+
// offset between the clock of the capture system and the clock of whoever sends
|
|
1237
|
+
// the stream, and by forwarding the stream we become that sender:
|
|
1238
|
+
//
|
|
1239
|
+
// capture NTP clock = sender NTP clock + capture clock offset
|
|
1240
|
+
//
|
|
1241
|
+
// @see https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-abs-capture-time-00
|
|
1226
1242
|
extenValue = packet->GetExtensionValue(this->rtpHeaderExtensionIds.absCaptureTime, extenLen);
|
|
1227
1243
|
|
|
1228
|
-
|
|
1244
|
+
// NOTE: The extension value is 8 or 16 bytes long depending on whether it holds
|
|
1245
|
+
// the capture clock offset or not.
|
|
1246
|
+
if (extenValue && (extenLen == 8u || extenLen == 16u))
|
|
1229
1247
|
{
|
|
1230
|
-
|
|
1248
|
+
// Offset between our own clock and the clock of the sender of this stream, in
|
|
1249
|
+
// the format the extension uses.
|
|
1250
|
+
//
|
|
1251
|
+
// NOTE: While it cannot be told yet, and it never can if the sender sends no
|
|
1252
|
+
// RTCP at all, both clocks are taken to be the same. Our own clock is real NTP
|
|
1253
|
+
// and so is the one of any sender that fills this extension, so no offset is
|
|
1254
|
+
// the most likely case rather than a wild guess.
|
|
1255
|
+
const auto remoteClockOffsetMs = this->listener->OnProducerNeedRemoteClockOffsetMs(this);
|
|
1256
|
+
const auto remoteClockOffsetQ32x32 =
|
|
1257
|
+
Utils::Time::TimeMs2Q32x32(remoteClockOffsetMs.value_or(0));
|
|
1258
|
+
|
|
1259
|
+
// NOTE: An offset that does not fit in the extension means a sender whose clock
|
|
1260
|
+
// is decades away from ours, and there is no value to write that would not be a
|
|
1261
|
+
// lie, so the extension is not forwarded.
|
|
1262
|
+
if (remoteClockOffsetQ32x32.has_value())
|
|
1263
|
+
{
|
|
1264
|
+
const auto absCaptureTimestamp = Utils::Byte::Get8Bytes(extenValue, 0);
|
|
1265
|
+
// Offset between the clock of the capture system and the clock of the sender
|
|
1266
|
+
// of this stream, as told by that sender. There is none when the extension
|
|
1267
|
+
// comes in its shortened form, which is what a sender that captures its own
|
|
1268
|
+
// media sends.
|
|
1269
|
+
const int64_t incomingCaptureClockOffset =
|
|
1270
|
+
extenLen == 16u ? static_cast<int64_t>(Utils::Byte::Get8Bytes(extenValue, 8)) : 0;
|
|
1271
|
+
// NOTE: The estimator gives our own clock minus the one of the sender, so
|
|
1272
|
+
// subtracting it adds the offset of the sender against ours.
|
|
1273
|
+
const int64_t captureClockOffset =
|
|
1274
|
+
incomingCaptureClockOffset - remoteClockOffsetQ32x32.value();
|
|
1275
|
+
|
|
1276
|
+
// The extension is always forwarded in its extended form, since the capture
|
|
1277
|
+
// clock offset is always written.
|
|
1278
|
+
extenLen = 16u;
|
|
1279
|
+
|
|
1280
|
+
Utils::Byte::Set8Bytes(bufferPtr, 0, absCaptureTimestamp);
|
|
1281
|
+
Utils::Byte::Set8Bytes(bufferPtr, 8, static_cast<uint64_t>(captureClockOffset));
|
|
1231
1282
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1283
|
+
extensions.emplace_back(
|
|
1284
|
+
/*type*/ RTC::RtpHeaderExtensionUri::Type::ABS_CAPTURE_TIME,
|
|
1285
|
+
/*id*/ static_cast<uint8_t>(RTC::RtpHeaderExtensionUri::Type::ABS_CAPTURE_TIME),
|
|
1286
|
+
/*len*/ extenLen,
|
|
1287
|
+
/*value*/ bufferPtr);
|
|
1237
1288
|
|
|
1238
|
-
|
|
1289
|
+
bufferPtr += extenLen;
|
|
1290
|
+
}
|
|
1239
1291
|
}
|
|
1240
1292
|
|
|
1241
1293
|
// Proxy http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
|
|
@@ -1409,10 +1461,28 @@ namespace RTC
|
|
|
1409
1461
|
return true;
|
|
1410
1462
|
}
|
|
1411
1463
|
|
|
1412
|
-
inline void Producer::PostProcessRtpPacket(
|
|
1464
|
+
inline void Producer::PostProcessRtpPacket(
|
|
1465
|
+
RTC::RTP::Packet* packet, RTC::RTP::RtpStreamRecv* rtpStream, bool maxPacketTsChanged)
|
|
1413
1466
|
{
|
|
1414
1467
|
MS_TRACE();
|
|
1415
1468
|
|
|
1469
|
+
// Store the capture instant of the packet holding the highest RTP timestamp of its
|
|
1470
|
+
// stream, which is the one the Sender Reports we send are built upon.
|
|
1471
|
+
if (maxPacketTsChanged)
|
|
1472
|
+
{
|
|
1473
|
+
const auto captureMs =
|
|
1474
|
+
this->listener->OnProducerNeedLocalCaptureMs(this, rtpStream, packet->GetTimestamp());
|
|
1475
|
+
|
|
1476
|
+
if (captureMs.has_value())
|
|
1477
|
+
{
|
|
1478
|
+
packet->SetCaptureMs(captureMs.value());
|
|
1479
|
+
|
|
1480
|
+
// Also let the stream remember it, since this is the only place where the
|
|
1481
|
+
// capture instant of a received packet can be told.
|
|
1482
|
+
rtpStream->SetCaptureMapping(captureMs.value(), packet->GetTimestamp());
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1416
1486
|
if (this->kind == RTC::Media::Kind::VIDEO)
|
|
1417
1487
|
{
|
|
1418
1488
|
bool camera{ false };
|
|
@@ -1697,15 +1767,14 @@ namespace RTC
|
|
|
1697
1767
|
this->listener->OnProducerSendRtcpPacket(this, packet);
|
|
1698
1768
|
}
|
|
1699
1769
|
|
|
1700
|
-
inline
|
|
1701
|
-
RTC::RTP::RtpStreamRecv* rtpStream, uint8_t& worstRemoteFractionLost)
|
|
1770
|
+
inline uint8_t Producer::OnRtpStreamNeedWorstRemoteFractionLost(RTC::RTP::RtpStreamRecv* rtpStream)
|
|
1702
1771
|
{
|
|
1703
1772
|
MS_TRACE();
|
|
1704
1773
|
|
|
1705
|
-
auto mappedSsrc = this->mapRtpStreamMappedSsrc.at(rtpStream);
|
|
1774
|
+
const auto mappedSsrc = this->mapRtpStreamMappedSsrc.at(rtpStream);
|
|
1706
1775
|
|
|
1707
1776
|
// Notify the listener.
|
|
1708
|
-
this->listener->OnProducerNeedWorstRemoteFractionLost(this, mappedSsrc
|
|
1777
|
+
return this->listener->OnProducerNeedWorstRemoteFractionLost(this, mappedSsrc);
|
|
1709
1778
|
}
|
|
1710
1779
|
|
|
1711
1780
|
inline void Producer::OnKeyFrameNeeded(
|
|
@@ -391,6 +391,11 @@ namespace RTC
|
|
|
391
391
|
MS_DUMP_CLEAN(indentation, " padding length: %" PRIu8, GetPaddingLength());
|
|
392
392
|
MS_DUMP_CLEAN(indentation, " padded to 4 bytes: %s", IsPaddedTo4Bytes() ? "yes" : "no");
|
|
393
393
|
|
|
394
|
+
if (GetCaptureMs())
|
|
395
|
+
{
|
|
396
|
+
MS_DUMP_CLEAN(indentation, " capture time (ms):%" PRIu64, GetCaptureMs().value());
|
|
397
|
+
}
|
|
398
|
+
|
|
394
399
|
if (this->payloadDescriptorHandler)
|
|
395
400
|
{
|
|
396
401
|
MS_DUMP_CLEAN(indentation + 1, "<PayloadDescriptorHandler>");
|
|
@@ -422,6 +427,9 @@ namespace RTC
|
|
|
422
427
|
// Clone extension ids.
|
|
423
428
|
clonedPacket->headerExtensionIds = this->headerExtensionIds;
|
|
424
429
|
|
|
430
|
+
// Clone capture time.
|
|
431
|
+
clonedPacket->captureMs = this->captureMs;
|
|
432
|
+
|
|
425
433
|
// Assign the payload descriptor handler.
|
|
426
434
|
clonedPacket->payloadDescriptorHandler = this->payloadDescriptorHandler;
|
|
427
435
|
|
|
@@ -1174,7 +1182,7 @@ namespace RTC
|
|
|
1174
1182
|
// Extension value can be 8 or 16 bytes depending on whether it contains
|
|
1175
1183
|
// estimated capture clock offset or not.
|
|
1176
1184
|
//
|
|
1177
|
-
// https://
|
|
1185
|
+
// @see https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-abs-capture-time-00
|
|
1178
1186
|
if (!extenValue || (extenLen != 8u && extenLen != 16u))
|
|
1179
1187
|
{
|
|
1180
1188
|
return false;
|
|
@@ -137,10 +137,11 @@ namespace RTC
|
|
|
137
137
|
{
|
|
138
138
|
InitSeq(seq);
|
|
139
139
|
|
|
140
|
-
this->started
|
|
141
|
-
this->maxSeq
|
|
142
|
-
this->maxPacketTs
|
|
143
|
-
this->maxPacketMs
|
|
140
|
+
this->started = true;
|
|
141
|
+
this->maxSeq = seq - 1;
|
|
142
|
+
this->maxPacketTs = packet->GetTimestamp();
|
|
143
|
+
this->maxPacketMs = this->shared->GetTimeMs();
|
|
144
|
+
this->maxPacketCaptureMs = packet->GetCaptureMs();
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
// If not a valid packet ignore it.
|
|
@@ -158,8 +159,9 @@ namespace RTC
|
|
|
158
159
|
// Update highest seen RTP timestamp.
|
|
159
160
|
if (Utils::Number::IsHigherThan<uint32_t>(packet->GetTimestamp(), this->maxPacketTs))
|
|
160
161
|
{
|
|
161
|
-
this->maxPacketTs
|
|
162
|
-
this->maxPacketMs
|
|
162
|
+
this->maxPacketTs = packet->GetTimestamp();
|
|
163
|
+
this->maxPacketMs = this->shared->GetTimeMs();
|
|
164
|
+
this->maxPacketCaptureMs = packet->GetCaptureMs();
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
return true;
|
|
@@ -226,8 +228,9 @@ namespace RTC
|
|
|
226
228
|
this->maxPacketTs,
|
|
227
229
|
packet->GetTimestamp());
|
|
228
230
|
|
|
229
|
-
this->maxPacketTs
|
|
230
|
-
this->maxPacketMs
|
|
231
|
+
this->maxPacketTs = packet->GetTimestamp();
|
|
232
|
+
this->maxPacketMs = this->shared->GetTimeMs();
|
|
233
|
+
this->maxPacketCaptureMs = packet->GetCaptureMs();
|
|
231
234
|
}
|
|
232
235
|
}
|
|
233
236
|
// Too old packet received (older than the allowed misorder).
|
|
@@ -248,8 +251,9 @@ namespace RTC
|
|
|
248
251
|
|
|
249
252
|
InitSeq(seq);
|
|
250
253
|
|
|
251
|
-
this->maxPacketTs
|
|
252
|
-
this->maxPacketMs
|
|
254
|
+
this->maxPacketTs = packet->GetTimestamp();
|
|
255
|
+
this->maxPacketMs = this->shared->GetTimeMs();
|
|
256
|
+
this->maxPacketCaptureMs = packet->GetCaptureMs();
|
|
253
257
|
|
|
254
258
|
// Notify the subclass about it.
|
|
255
259
|
UserOnSequenceNumberReset();
|