Add utility class for unwrapping 16 bit sequence numbers
Unwrap uint16_t to int64_t, based on delta and last sequence number. This can make application logic, putting packets in maps etc, much simpler. BUG= Review URL: https://codereview.webrtc.org/1209623002 Cr-Commit-Position: refs/heads/master@{#9887}
This commit is contained in:
@ -765,6 +765,46 @@ inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
|
|||||||
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility class to unwrap a sequence number to a larger type, for easier
|
||||||
|
// handling large ranges. Note that sequence numbers will never be unwrapped
|
||||||
|
// to a negative value.
|
||||||
|
class SequenceNumberUnwrapper {
|
||||||
|
public:
|
||||||
|
SequenceNumberUnwrapper() : last_seq_(-1) {}
|
||||||
|
|
||||||
|
// Get the unwrapped sequence, but don't update the internal state.
|
||||||
|
int64_t UnwrapWithoutUpdate(uint16_t sequence_number) {
|
||||||
|
if (last_seq_ == -1)
|
||||||
|
return sequence_number;
|
||||||
|
|
||||||
|
uint16_t cropped_last = static_cast<uint16_t>(last_seq_);
|
||||||
|
int64_t delta = sequence_number - cropped_last;
|
||||||
|
if (IsNewerSequenceNumber(sequence_number, cropped_last)) {
|
||||||
|
if (delta < 0)
|
||||||
|
delta += (1 << 16); // Wrap forwards.
|
||||||
|
} else if (delta > 0 && (last_seq_ + delta - (1 << 16)) >= 0) {
|
||||||
|
// If sequence_number is older but delta is positive, this is a backwards
|
||||||
|
// wrap-around. However, don't wrap backwards past 0 (unwrapped).
|
||||||
|
delta -= (1 << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return last_seq_ + delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update the internal state to the specified last (unwrapped) sequence.
|
||||||
|
void UpdateLast(int64_t last_sequence) { last_seq_ = last_sequence; }
|
||||||
|
|
||||||
|
// Unwrap the sequence number and update the internal state.
|
||||||
|
int64_t Unwrap(uint16_t sequence_number) {
|
||||||
|
int64_t unwrapped = UnwrapWithoutUpdate(sequence_number);
|
||||||
|
UpdateLast(unwrapped);
|
||||||
|
return unwrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int64_t last_seq_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // MODULE_COMMON_TYPES_H
|
#endif // MODULE_COMMON_TYPES_H
|
||||||
|
@ -122,4 +122,63 @@ TEST(ClampToInt16, TestCases) {
|
|||||||
EXPECT_EQ(-0x8000, ClampToInt16(-0x7FFFFFFF));
|
EXPECT_EQ(-0x8000, ClampToInt16(-0x7FFFFFFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SequenceNumberUnwrapper, Limits) {
|
||||||
|
SequenceNumberUnwrapper unwrapper;
|
||||||
|
|
||||||
|
EXPECT_EQ(0, unwrapper.Unwrap(0));
|
||||||
|
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||||
|
// Delta is exactly 0x8000 but current is lower than input, wrap backwards.
|
||||||
|
EXPECT_EQ(0x0, unwrapper.Unwrap(0x0000));
|
||||||
|
|
||||||
|
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||||
|
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||||
|
EXPECT_EQ(0x10000, unwrapper.Unwrap(0x0000));
|
||||||
|
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||||
|
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||||
|
EXPECT_EQ(0, unwrapper.Unwrap(0));
|
||||||
|
|
||||||
|
// Don't allow negative values.
|
||||||
|
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SequenceNumberUnwrapper, ForwardWraps) {
|
||||||
|
int64_t seq = 0;
|
||||||
|
SequenceNumberUnwrapper unwrapper;
|
||||||
|
|
||||||
|
const int kMaxIncrease = 0x8000 - 1;
|
||||||
|
const int kNumWraps = 4;
|
||||||
|
for (int i = 0; i < kNumWraps * 2; ++i) {
|
||||||
|
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||||
|
EXPECT_EQ(seq, unwrapped);
|
||||||
|
seq += kMaxIncrease;
|
||||||
|
}
|
||||||
|
|
||||||
|
unwrapper.UpdateLast(0);
|
||||||
|
for (int seq = 0; seq < kNumWraps * 0xFFFF; ++seq) {
|
||||||
|
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||||
|
EXPECT_EQ(seq, unwrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SequenceNumberUnwrapper, BackwardWraps) {
|
||||||
|
SequenceNumberUnwrapper unwrapper;
|
||||||
|
|
||||||
|
const int kMaxDecrease = 0x8000 - 1;
|
||||||
|
const int kNumWraps = 4;
|
||||||
|
int64_t seq = kNumWraps * 2 * kMaxDecrease;
|
||||||
|
unwrapper.UpdateLast(seq);
|
||||||
|
for (int i = kNumWraps * 2; i >= 0; --i) {
|
||||||
|
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||||
|
EXPECT_EQ(seq, unwrapped);
|
||||||
|
seq -= kMaxDecrease;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq = kNumWraps * 0xFFFF;
|
||||||
|
unwrapper.UpdateLast(seq);
|
||||||
|
for (; seq >= 0; --seq) {
|
||||||
|
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||||
|
EXPECT_EQ(seq, unwrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
Reference in New Issue
Block a user