Skip to content

Commit

Permalink
Fix "SimulcastConsumer cannot switch layers if initial
Browse files Browse the repository at this point in the history
 tsReferenceSpatialLayer disappears" (versatica#492) * Set tsReferenceSpatialLayer
 later, only after receiving an RTCP Sender Report. * Track and carry forward
 offset from tsReferenceSpatialLayer.
  • Loading branch information
LewisWolfgang authored and Eugene Voityuk committed Apr 12, 2021
1 parent 75a0d63 commit 4b5ef63
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 23 deletions.
3 changes: 2 additions & 1 deletion worker/include/RTC/SimulcastConsumer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ namespace RTC
int16_t currentSpatialLayer{ -1 };
int16_t tsReferenceSpatialLayer{ -1 }; // Used for RTP TS sync.
std::unique_ptr<RTC::Codecs::EncodingContext> encodingContext;
uint32_t tsOffset{ 0u }; // RTP Timestamp offset.
uint32_t tsOffset{ 0u }; // RTP Timestamp offset.
uint32_t tsReferenceOffset{ 0u }; // RTP Timestamp offset from the tsReferenceSpatialLayer.
bool keyFrameForTsOffsetRequested{ false };
uint64_t lastBweDowngradeAtMs{ 0u }; // Last time we moved to lower spatial layer due to BWE.
};
Expand Down
65 changes: 43 additions & 22 deletions worker/src/RTC/SimulcastConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,9 +700,27 @@ namespace RTC
uint32_t tsOffset{ 0u };

// Sync our RTP stream's RTP timestamp.
if (spatialLayer == this->tsReferenceSpatialLayer)
if (-1 == this->tsReferenceSpatialLayer)
{
if (shouldSwitchCurrentSpatialLayer)
{
// If we're actually switching streams, push the RTP timestamp up (we don't have a way to
// offset based on abs time yet) otherwise, if it's the first packet, we can just keep the
// timestamps
if (this->rtpStream->GetMaxPacketTs())
tsOffset = packet->GetTimestamp() - this->rtpStream->GetMaxPacketTs() -
33 * this->rtpStream->GetClockRate() / 1000;
else
tsOffset = 0u;
}
else
{
tsOffset = this->tsOffset; // status quo
}
}
else if (spatialLayer == this->tsReferenceSpatialLayer)
{
tsOffset = 0u;
tsOffset = this->tsReferenceOffset;
}
// If this is not the RTP stream we use as TS reference, do NTP based RTP TS synchronization.
else
Expand All @@ -719,23 +737,18 @@ namespace RTC
producerTargetRtpStream->GetSenderReportNtpMs(), "no Sender Report for current RTP stream");

// Calculate NTP and TS stuff.
auto ntpMs1 = producerTsReferenceRtpStream->GetSenderReportNtpMs();
auto ts1 = producerTsReferenceRtpStream->GetSenderReportTs();
auto ntpMs2 = producerTargetRtpStream->GetSenderReportNtpMs();
auto ts2 = producerTargetRtpStream->GetSenderReportTs();
int64_t diffMs;

if (ntpMs2 >= ntpMs1)
diffMs = ntpMs2 - ntpMs1;
else
diffMs = -1 * (ntpMs1 - ntpMs2);
auto ntpMs1 = producerTsReferenceRtpStream->GetSenderReportNtpMs();
auto ts1 = producerTsReferenceRtpStream->GetSenderReportTs();
auto ntpMs2 = producerTargetRtpStream->GetSenderReportNtpMs();
auto ts2 = producerTargetRtpStream->GetSenderReportTs();
int64_t diffMs = ntpMs2 - ntpMs1;

int64_t diffTs = diffMs * this->rtpStream->GetClockRate() / 1000;
uint32_t newTs2 = ts2 - diffTs;

// Apply offset. This is the difference that later must be removed from the
// sending RTP packet.
tsOffset = newTs2 - ts1;
tsOffset = this->tsReferenceOffset + newTs2 - ts1;
}

// When switching to a new stream it may happen that the timestamp of this
Expand Down Expand Up @@ -812,6 +825,10 @@ namespace RTC

this->tsOffset = tsOffset;

// We need this update here and below, it picks up and carries forward any adjustments we made above
if (spatialLayer == this->tsReferenceSpatialLayer)
this->tsReferenceOffset = this->tsOffset;

// Sync our RTP stream's sequence number.
this->rtpSeqManager.Sync(packet->GetSequenceNumber() - 1);

Expand All @@ -826,6 +843,9 @@ namespace RTC
// Update current spatial layer.
this->currentSpatialLayer = this->targetSpatialLayer;

if (this->currentSpatialLayer == this->tsReferenceSpatialLayer)
this->tsReferenceOffset = this->tsOffset;

// Update target and current temporal layer.
this->encodingContext->SetTargetTemporalLayer(this->targetTemporalLayer);
this->encodingContext->SetCurrentTemporalLayer(packet->GetTemporalLayer());
Expand Down Expand Up @@ -858,6 +878,16 @@ namespace RTC
EmitLayersChange();
}

if (-1 == this->tsReferenceSpatialLayer && this->currentSpatialLayer == this->targetSpatialLayer)
{
auto* producerCurrentRtpStream = GetProducerCurrentRtpStream();
if (producerCurrentRtpStream && producerCurrentRtpStream->GetSenderReportNtpMs())
{
this->tsReferenceSpatialLayer = this->currentSpatialLayer;
this->tsReferenceOffset = this->tsOffset;
}
}

// Update RTP seq number and timestamp based on NTP offset.
uint16_t seq;
uint32_t timestamp = packet->GetTimestamp() - this->tsOffset;
Expand Down Expand Up @@ -1328,15 +1358,6 @@ namespace RTC
{
MS_TRACE();

// If we don't have yet a RTP timestamp reference, set it now.
if (newTargetSpatialLayer != -1 && this->tsReferenceSpatialLayer == -1)
{
MS_DEBUG_TAG(
simulcast, "using spatial layer %" PRIi16 " as RTP timestamp reference", newTargetSpatialLayer);

this->tsReferenceSpatialLayer = newTargetSpatialLayer;
}

if (newTargetSpatialLayer == -1)
{
// Unset current and target layers.
Expand Down

0 comments on commit 4b5ef63

Please sign in to comment.