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

transport-cc parsing to be compliant with libwebrtc, make transport-cc reference time to be unsigned, therefore fix 357. #899

Merged
merged 14 commits into from
Sep 19, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* New C++ `ChannelMessageHandlers` class (PR #894).
* Fix Rust support after recent changes (PR #898).
* Update NPM deps.
* Modify `FeedbackRtpTransport` and tests to be compliant with latest libwebrtc code, make reference time to be unsigned (PR #899 by @penguinol and @sarumjanuch).


### 3.10.5
Expand Down
2 changes: 1 addition & 1 deletion worker/deps/libwebrtc/libwebrtc/mediasoup_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace mediasoup_helpers
int64_t GetBaseDeltaUs(
const RTC::RTCP::FeedbackRtpTransportPacket* packet, int64_t prev_timestamp_us)
{
return GetBaseTimeUs(packet) - prev_timestamp_us;
return packet->GetBaseDelta(prev_timestamp_us / 1000) * 1000;
}
} // namespace FeedbackRtpTransport
} // namespace mediasoup_helpers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp,
current_timestamp_group_.timestamp = timestamp;
current_timestamp_group_.first_timestamp = timestamp;
current_timestamp_group_.first_arrival_ms = arrival_time_ms;
} else if (!PacketInOrder(timestamp, arrival_time_ms)) {
} else if (!PacketInOrder(timestamp)) {
return false;
} else if (NewTimestampGroup(arrival_time_ms, timestamp)) {
// First packet of a later frame, the previous frame sample is ready.
Expand Down Expand Up @@ -115,17 +115,9 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp,
return calculated_deltas;
}

bool InterArrival::PacketInOrder(uint32_t timestamp, int64_t arrival_time_ms) {
bool InterArrival::PacketInOrder(uint32_t timestamp) {
if (current_timestamp_group_.IsFirstPacket()) {
return true;
} else if (arrival_time_ms < 0) {
// NOTE: Change related to https://github.com/versatica/mediasoup/issues/357
//
// Sometimes we do get negative arrival time, which causes BelongsToBurst()
// to fail, which may cause anything that uses InterArrival to crash.
//
// Credits to @sspanak and @Ivaka.
return false;
} else {
// Assume that a diff which is bigger than half the timestamp interval
// (32 bits) must be due to reordering. This code is almost identical to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ class InterArrival {
};

// Returns true if the packet with timestamp |timestamp| arrived in order.
//
// NOTE: Change related to https://github.com/versatica/mediasoup/issues/357
//
// bool PacketInOrder(uint32_t timestamp);
bool PacketInOrder(uint32_t timestamp, int64_t arrival_time_ms);
bool PacketInOrder(uint32_t timestamp);

// Returns true if the last packet was the end of the current batch and the
// packet with |timestamp| is the first of a new batch.
Expand Down
28 changes: 26 additions & 2 deletions worker/include/RTC/RTCP/FeedbackRtpTransport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ namespace RTC
{
class FeedbackRtpTransportPacket : public FeedbackRtpPacket
{
public:
static constexpr int64_t BaseTimeTick = 64;
static constexpr int64_t TimeWrapPeriod = BaseTimeTick * (1ll << 24);

public:
struct PacketResult
{
Expand Down Expand Up @@ -237,9 +241,29 @@ namespace RTC
{
return this->referenceTime;
}
void SetReferenceTime(uint64_t referenceTime) // We only use this for testing purpose.
{
this->referenceTime = (referenceTime % TimeWrapPeriod) / BaseTimeTick;
}
int64_t GetReferenceTimestamp() const // Reference time in ms.
{
return static_cast<int64_t>(this->referenceTime) * 64;
return TimeWrapPeriod + static_cast<int64_t>(this->referenceTime) * BaseTimeTick;
}
int64_t GetBaseDelta(const int64_t previousTimestampMs) const
{
int64_t delta = GetReferenceTimestamp() - previousTimestampMs;

// Compensate for wrap around.
ibc marked this conversation as resolved.
Show resolved Hide resolved
if (std::abs(delta - TimeWrapPeriod) < std::abs(delta))
{
delta -= TimeWrapPeriod;
}
else if (std::abs(delta + TimeWrapPeriod) < std::abs(delta))
{
delta += TimeWrapPeriod;
}

return delta;
}
uint8_t GetFeedbackPacketCount() const
{
Expand Down Expand Up @@ -290,7 +314,7 @@ namespace RTC

private:
uint16_t baseSequenceNumber{ 0u };
int32_t referenceTime{ 0 };
uint32_t referenceTime{ 0 };
ibc marked this conversation as resolved.
Show resolved Hide resolved
uint16_t latestSequenceNumber{ 0u }; // Just for locally generated packets.
uint64_t latestTimestamp{ 0u }; // Just for locally generated packets.
uint16_t packetStatusCount{ 0u };
Expand Down
42 changes: 1 addition & 41 deletions worker/src/RTC/RTCP/FeedbackRtpTransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,6 @@
#include <limits> // std::numeric_limits()
#include <sstream>

// Code taken and adapted from libwebrtc (byte_io.h).
inline static int32_t parseReferenceTime(uint8_t* buffer)
{
int32_t referenceTime;
uint32_t unsignedVal = Utils::Byte::Get3Bytes(buffer, 0);

const auto msb = static_cast<uint8_t>(unsignedVal >> ((3 - 1) * 8));

if ((msb & 0x80) != 0)
{
// Create a mask where all bits used by the 3 bytes are set to one, for
// instance 0x00FFFFFF. Bit-wise inverts that mask to 0xFF000000 and adds
// it to the input value.
static uint32_t usedBitMask = (1 << ((3 % sizeof(int32_t)) * 8)) - 1;

unsignedVal = ~usedBitMask | unsignedVal;
}

// An unsigned value with only the highest order bit set (ex 0x80).
static uint32_t unsignedHighestBitMask = static_cast<uint32_t>(1) << ((sizeof(uint32_t) * 8) - 1);

// A signed value with only the highest bit set. Since this is two's
// complement form, we can use the min value from std::numeric_limits.
static int32_t signedHighestBitMask = std::numeric_limits<int32_t>::min();

if ((unsignedVal & unsignedHighestBitMask) != 0)
{
// Casting is only safe when unsigned value can be represented in the
// signed target type, so mask out highest bit and mask it back manually.
referenceTime = static_cast<int32_t>(unsignedVal & ~unsignedHighestBitMask);
referenceTime |= signedHighestBitMask;
}
else
{
referenceTime = static_cast<int32_t>(unsignedVal);
}

return referenceTime;
}

namespace RTC
{
namespace RTCP
Expand Down Expand Up @@ -117,7 +77,7 @@ namespace RTC

this->baseSequenceNumber = Utils::Byte::Get2Bytes(data, 0);
this->packetStatusCount = Utils::Byte::Get2Bytes(data, 2);
this->referenceTime = parseReferenceTime(data + 4);
this->referenceTime = Utils::Byte::Get3Bytes(data, 4);
this->feedbackPacketCount = Utils::Byte::Get1Byte(data, 7);
this->size = len;

Expand Down
Loading