Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix "SimulcastConsumer cannot switch layers if initial tsReferenceSpa… #500

Open
wants to merge 2 commits into
base: v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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