mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

Passing an empty arg is working at the moment but it is not guaranteed to continue to work in the future. This CL has been generated with: git grep -l "INSTANTIATE_TEST_SUITE_P(," | xargs sed -i \ "s/INSTANTIATE_TEST_SUITE_P(,/INSTANTIATE_TEST_SUITE_P(All,/g" Bug: None Change-Id: Icd2fb9d9d29aed5d692a234124bd990d0f097db4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/153890 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29282}
502 lines
19 KiB
C++
502 lines
19 KiB
C++
/*
|
|
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/rtp_rtcp/source/rtp_sequence_number_map.h"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
#include "absl/memory/memory.h"
|
|
#include "absl/types/optional.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/numerics/sequence_number_util.h"
|
|
#include "rtc_base/random.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
using Info = RtpSequenceNumberMap::Info;
|
|
|
|
constexpr uint16_t kUint16Max = std::numeric_limits<uint16_t>::max();
|
|
constexpr size_t kMaxPossibleMaxEntries = 1 << 15;
|
|
|
|
// Just a named pair.
|
|
struct Association final {
|
|
Association(uint16_t sequence_number, Info info)
|
|
: sequence_number(sequence_number), info(info) {}
|
|
|
|
uint16_t sequence_number;
|
|
Info info;
|
|
};
|
|
|
|
class RtpSequenceNumberMapTest : public ::testing::Test {
|
|
protected:
|
|
RtpSequenceNumberMapTest() : random_(1983) {}
|
|
~RtpSequenceNumberMapTest() override = default;
|
|
|
|
Association CreateAssociation(uint16_t sequence_number, uint32_t timestamp) {
|
|
return Association(sequence_number,
|
|
{timestamp, random_.Rand<bool>(), random_.Rand<bool>()});
|
|
}
|
|
|
|
void VerifyAssociations(const RtpSequenceNumberMap& uut,
|
|
const std::vector<Association>& associations) {
|
|
return VerifyAssociations(uut, associations.begin(), associations.end());
|
|
}
|
|
|
|
void VerifyAssociations(
|
|
const RtpSequenceNumberMap& uut,
|
|
std::vector<Association>::const_iterator associations_begin,
|
|
std::vector<Association>::const_iterator associations_end) {
|
|
RTC_DCHECK(associations_begin < associations_end);
|
|
ASSERT_EQ(static_cast<size_t>(associations_end - associations_begin),
|
|
uut.AssociationCountForTesting());
|
|
for (auto association = associations_begin; association != associations_end;
|
|
++association) {
|
|
EXPECT_EQ(uut.Get(association->sequence_number), association->info);
|
|
}
|
|
}
|
|
|
|
// Allows several variations of the same test; definition next to the tests.
|
|
void GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
bool with_wrap_around,
|
|
bool last_element_kept);
|
|
|
|
// Allows several variations of the same test; definition next to the tests.
|
|
void RepeatedSequenceNumberInvalidatesAll(size_t index_of_repeated);
|
|
|
|
// Allows several variations of the same test; definition next to the tests.
|
|
void MaxEntriesReachedAtSameTimeAsObsoletionOfItem(size_t max_entries,
|
|
size_t obsoleted_count);
|
|
|
|
Random random_;
|
|
};
|
|
|
|
class RtpSequenceNumberMapTestWithParams
|
|
: public RtpSequenceNumberMapTest,
|
|
public ::testing::WithParamInterface<std::tuple<size_t, uint16_t>> {
|
|
protected:
|
|
RtpSequenceNumberMapTestWithParams() = default;
|
|
~RtpSequenceNumberMapTestWithParams() override = default;
|
|
|
|
std::vector<Association> ProduceRandomAssociationSequence(
|
|
size_t association_count,
|
|
uint16_t first_sequence_number,
|
|
bool allow_obsoletion) {
|
|
std::vector<Association> associations;
|
|
associations.reserve(association_count);
|
|
|
|
if (association_count == 0) {
|
|
return associations;
|
|
}
|
|
|
|
associations.emplace_back(
|
|
first_sequence_number,
|
|
Info(0, random_.Rand<bool>(), random_.Rand<bool>()));
|
|
|
|
for (size_t i = 1; i < association_count; ++i) {
|
|
const uint16_t sequence_number =
|
|
associations[i - 1].sequence_number + random_.Rand(1, 100);
|
|
RTC_DCHECK(allow_obsoletion ||
|
|
AheadOf(sequence_number, associations[0].sequence_number));
|
|
|
|
const uint32_t timestamp =
|
|
associations[i - 1].info.timestamp + random_.Rand(1, 10000);
|
|
|
|
associations.emplace_back(
|
|
sequence_number,
|
|
Info(timestamp, random_.Rand<bool>(), random_.Rand<bool>()));
|
|
}
|
|
|
|
return associations;
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(All,
|
|
RtpSequenceNumberMapTestWithParams,
|
|
::testing::Combine(
|
|
// Association count.
|
|
::testing::Values(1, 2, 100),
|
|
// First sequence number.
|
|
::testing::Values(0,
|
|
100,
|
|
kUint16Max - 100,
|
|
kUint16Max - 1,
|
|
kUint16Max)));
|
|
|
|
TEST_F(RtpSequenceNumberMapTest, GetBeforeAssociationsRecordedReturnsNullOpt) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
constexpr uint16_t kArbitrarySequenceNumber = 321;
|
|
EXPECT_FALSE(uut.Get(kArbitrarySequenceNumber));
|
|
}
|
|
|
|
// Version #1 - any old unknown sequence number.
|
|
TEST_F(RtpSequenceNumberMapTest, GetUnknownSequenceNumberReturnsNullOpt1) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
constexpr uint16_t kKnownSequenceNumber = 10;
|
|
constexpr uint32_t kArbitrary = 987;
|
|
uut.InsertPacket(kKnownSequenceNumber, {kArbitrary, false, false});
|
|
|
|
constexpr uint16_t kUnknownSequenceNumber = kKnownSequenceNumber + 1;
|
|
EXPECT_FALSE(uut.Get(kUnknownSequenceNumber));
|
|
}
|
|
|
|
// Version #2 - intentionally pick a value in the range of currently held
|
|
// values, so as to trigger lower_bound / upper_bound.
|
|
TEST_F(RtpSequenceNumberMapTest, GetUnknownSequenceNumberReturnsNullOpt2) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
const std::vector<Association> setup = {CreateAssociation(1000, 500), //
|
|
CreateAssociation(1020, 501)};
|
|
for (const Association& association : setup) {
|
|
uut.InsertPacket(association.sequence_number, association.info);
|
|
}
|
|
|
|
EXPECT_FALSE(uut.Get(1001));
|
|
}
|
|
|
|
TEST_P(RtpSequenceNumberMapTestWithParams,
|
|
GetKnownSequenceNumberReturnsCorrectValue) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
const size_t association_count = std::get<0>(GetParam());
|
|
const uint16_t first_sequence_number = std::get<1>(GetParam());
|
|
|
|
const std::vector<Association> associations =
|
|
ProduceRandomAssociationSequence(association_count, first_sequence_number,
|
|
/*allow_obsoletion=*/false);
|
|
|
|
for (const Association& association : associations) {
|
|
uut.InsertPacket(association.sequence_number, association.info);
|
|
}
|
|
|
|
VerifyAssociations(uut, associations);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest, InsertFrameOnSinglePacketFrame) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
constexpr uint16_t kSequenceNumber = 888;
|
|
constexpr uint32_t kTimestamp = 98765;
|
|
uut.InsertFrame(kSequenceNumber, 1, kTimestamp);
|
|
|
|
EXPECT_EQ(uut.Get(kSequenceNumber), Info(kTimestamp, true, true));
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest, InsertFrameOnMultiPacketFrameNoWrapAround) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
constexpr uint16_t kFirstSequenceNumber = 0;
|
|
constexpr uint32_t kTimestamp = 98765;
|
|
uut.InsertFrame(kFirstSequenceNumber, 3, kTimestamp);
|
|
|
|
EXPECT_EQ(uut.Get(kFirstSequenceNumber + 0), Info(kTimestamp, true, false));
|
|
EXPECT_EQ(uut.Get(kFirstSequenceNumber + 1), Info(kTimestamp, false, false));
|
|
EXPECT_EQ(uut.Get(kFirstSequenceNumber + 2), Info(kTimestamp, false, true));
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest, InsertFrameOnMultiPacketFrameWithWrapAround) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
constexpr uint16_t kFirstSequenceNumber = kUint16Max;
|
|
constexpr uint32_t kTimestamp = 98765;
|
|
uut.InsertFrame(kFirstSequenceNumber, 3, kTimestamp);
|
|
|
|
// Suppress "truncation of constant value" warning; wrap-around is intended.
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4309)
|
|
#endif
|
|
EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 0u)),
|
|
Info(kTimestamp, true, false));
|
|
EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 1u)),
|
|
Info(kTimestamp, false, false));
|
|
EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 2u)),
|
|
Info(kTimestamp, false, true));
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
GetObsoleteSequenceNumberReturnsNullOptSingleValueObsoleted) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
const std::vector<Association> associations = {
|
|
CreateAssociation(0, 10), //
|
|
CreateAssociation(0x8000, 20), //
|
|
CreateAssociation(0x8001u, 30)};
|
|
|
|
uut.InsertPacket(associations[0].sequence_number, associations[0].info);
|
|
|
|
// First association not yet obsolete, and therefore remembered.
|
|
RTC_DCHECK(AheadOf(associations[1].sequence_number,
|
|
associations[0].sequence_number));
|
|
uut.InsertPacket(associations[1].sequence_number, associations[1].info);
|
|
VerifyAssociations(uut, {associations[0], associations[1]});
|
|
|
|
// Test focus - new entry obsoletes first entry.
|
|
RTC_DCHECK(!AheadOf(associations[2].sequence_number,
|
|
associations[0].sequence_number));
|
|
uut.InsertPacket(associations[2].sequence_number, associations[2].info);
|
|
VerifyAssociations(uut, {associations[1], associations[2]});
|
|
}
|
|
|
|
void RtpSequenceNumberMapTest::
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
bool with_wrap_around,
|
|
bool last_element_kept) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
std::vector<Association> associations;
|
|
if (with_wrap_around) {
|
|
associations = {CreateAssociation(kUint16Max - 1, 10), //
|
|
CreateAssociation(kUint16Max, 20), //
|
|
CreateAssociation(0, 30), //
|
|
CreateAssociation(1, 40), //
|
|
CreateAssociation(2, 50)};
|
|
} else {
|
|
associations = {CreateAssociation(1, 10), //
|
|
CreateAssociation(2, 20), //
|
|
CreateAssociation(3, 30), //
|
|
CreateAssociation(4, 40), //
|
|
CreateAssociation(5, 50)};
|
|
}
|
|
|
|
for (auto association : associations) {
|
|
uut.InsertPacket(association.sequence_number, association.info);
|
|
}
|
|
VerifyAssociations(uut, associations);
|
|
|
|
// Define a new association that will obsolete either all previous entries,
|
|
// or all previous entries except for the last one, depending on the
|
|
// parameter instantiation of this test.
|
|
RTC_DCHECK_EQ(
|
|
static_cast<uint16_t>(
|
|
associations[associations.size() - 1].sequence_number),
|
|
static_cast<uint16_t>(
|
|
associations[associations.size() - 2].sequence_number + 1u));
|
|
uint16_t new_sequence_number;
|
|
if (last_element_kept) {
|
|
new_sequence_number =
|
|
associations[associations.size() - 1].sequence_number + 0x8000;
|
|
RTC_DCHECK(AheadOf(new_sequence_number,
|
|
associations[associations.size() - 1].sequence_number));
|
|
} else {
|
|
new_sequence_number =
|
|
associations[associations.size() - 1].sequence_number + 0x8001;
|
|
RTC_DCHECK(!AheadOf(new_sequence_number,
|
|
associations[associations.size() - 1].sequence_number));
|
|
}
|
|
RTC_DCHECK(!AheadOf(new_sequence_number,
|
|
associations[associations.size() - 2].sequence_number));
|
|
|
|
// Record the new association.
|
|
const Association new_association =
|
|
CreateAssociation(new_sequence_number, 60);
|
|
uut.InsertPacket(new_association.sequence_number, new_association.info);
|
|
|
|
// Make sure all obsoleted elements were removed.
|
|
const size_t obsoleted_count =
|
|
associations.size() - (last_element_kept ? 1 : 0);
|
|
for (size_t i = 0; i < obsoleted_count; ++i) {
|
|
EXPECT_FALSE(uut.Get(associations[i].sequence_number));
|
|
}
|
|
|
|
// Make sure the expected elements were not removed, and return the
|
|
// expected value.
|
|
if (last_element_kept) {
|
|
EXPECT_EQ(uut.Get(associations.back().sequence_number),
|
|
associations.back().info);
|
|
}
|
|
EXPECT_EQ(uut.Get(new_association.sequence_number), new_association.info);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted0) {
|
|
const bool with_wrap_around = false;
|
|
const bool last_element_kept = false;
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
with_wrap_around, last_element_kept);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted1) {
|
|
const bool with_wrap_around = true;
|
|
const bool last_element_kept = false;
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
with_wrap_around, last_element_kept);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted2) {
|
|
const bool with_wrap_around = false;
|
|
const bool last_element_kept = true;
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
with_wrap_around, last_element_kept);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted3) {
|
|
const bool with_wrap_around = true;
|
|
const bool last_element_kept = true;
|
|
GetObsoleteSequenceNumberReturnsNullOptMultipleEntriesObsoleted(
|
|
with_wrap_around, last_element_kept);
|
|
}
|
|
|
|
void RtpSequenceNumberMapTest::RepeatedSequenceNumberInvalidatesAll(
|
|
size_t index_of_repeated) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
const std::vector<Association> setup = {CreateAssociation(100, 500), //
|
|
CreateAssociation(101, 501), //
|
|
CreateAssociation(102, 502)};
|
|
RTC_DCHECK_LT(index_of_repeated, setup.size());
|
|
for (const Association& association : setup) {
|
|
uut.InsertPacket(association.sequence_number, association.info);
|
|
}
|
|
|
|
const Association new_association =
|
|
CreateAssociation(setup[index_of_repeated].sequence_number, 503);
|
|
uut.InsertPacket(new_association.sequence_number, new_association.info);
|
|
|
|
// All entries from setup invalidated.
|
|
// New entry valid and mapped to new value.
|
|
for (size_t i = 0; i < setup.size(); ++i) {
|
|
if (i == index_of_repeated) {
|
|
EXPECT_EQ(uut.Get(new_association.sequence_number), new_association.info);
|
|
} else {
|
|
EXPECT_FALSE(uut.Get(setup[i].sequence_number));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
RepeatedSequenceNumberInvalidatesAllRepeatFirst) {
|
|
RepeatedSequenceNumberInvalidatesAll(0);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
RepeatedSequenceNumberInvalidatesAllRepeatMiddle) {
|
|
RepeatedSequenceNumberInvalidatesAll(1);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
RepeatedSequenceNumberInvalidatesAllRepeatLast) {
|
|
RepeatedSequenceNumberInvalidatesAll(2);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
SequenceNumberInsideMemorizedRangeInvalidatesAll) {
|
|
RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
|
|
|
|
const std::vector<Association> setup = {CreateAssociation(1000, 500), //
|
|
CreateAssociation(1020, 501), //
|
|
CreateAssociation(1030, 502)};
|
|
for (const Association& association : setup) {
|
|
uut.InsertPacket(association.sequence_number, association.info);
|
|
}
|
|
|
|
const Association new_association = CreateAssociation(1010, 503);
|
|
uut.InsertPacket(new_association.sequence_number, new_association.info);
|
|
|
|
// All entries from setup invalidated.
|
|
// New entry valid and mapped to new value.
|
|
for (size_t i = 0; i < setup.size(); ++i) {
|
|
EXPECT_FALSE(uut.Get(setup[i].sequence_number));
|
|
}
|
|
EXPECT_EQ(uut.Get(new_association.sequence_number), new_association.info);
|
|
}
|
|
|
|
TEST_F(RtpSequenceNumberMapTest, MaxEntriesObserved) {
|
|
constexpr size_t kMaxEntries = 100;
|
|
RtpSequenceNumberMap uut(kMaxEntries);
|
|
|
|
std::vector<Association> associations;
|
|
associations.reserve(kMaxEntries);
|
|
uint32_t timestamp = 789;
|
|
for (size_t i = 0; i < kMaxEntries; ++i) {
|
|
associations.push_back(CreateAssociation(i, ++timestamp));
|
|
uut.InsertPacket(associations[i].sequence_number, associations[i].info);
|
|
}
|
|
VerifyAssociations(uut, associations); // Sanity.
|
|
|
|
const Association new_association =
|
|
CreateAssociation(kMaxEntries, ++timestamp);
|
|
uut.InsertPacket(new_association.sequence_number, new_association.info);
|
|
associations.push_back(new_association);
|
|
|
|
// The +1 is for |new_association|.
|
|
const size_t kExpectedAssociationCount = 3 * kMaxEntries / 4 + 1;
|
|
const auto expected_begin =
|
|
std::prev(associations.end(), kExpectedAssociationCount);
|
|
VerifyAssociations(uut, expected_begin, associations.end());
|
|
}
|
|
|
|
void RtpSequenceNumberMapTest::MaxEntriesReachedAtSameTimeAsObsoletionOfItem(
|
|
size_t max_entries,
|
|
size_t obsoleted_count) {
|
|
RtpSequenceNumberMap uut(max_entries);
|
|
|
|
std::vector<Association> associations;
|
|
associations.reserve(max_entries);
|
|
uint32_t timestamp = 789;
|
|
for (size_t i = 0; i < max_entries; ++i) {
|
|
associations.push_back(CreateAssociation(i, ++timestamp));
|
|
uut.InsertPacket(associations[i].sequence_number, associations[i].info);
|
|
}
|
|
VerifyAssociations(uut, associations); // Sanity.
|
|
|
|
const uint16_t new_association_sequence_number =
|
|
static_cast<uint16_t>(obsoleted_count) + (1 << 15);
|
|
const Association new_association =
|
|
CreateAssociation(new_association_sequence_number, ++timestamp);
|
|
uut.InsertPacket(new_association.sequence_number, new_association.info);
|
|
associations.push_back(new_association);
|
|
|
|
// The +1 is for |new_association|.
|
|
const size_t kExpectedAssociationCount =
|
|
std::min(3 * max_entries / 4, max_entries - obsoleted_count) + 1;
|
|
const auto expected_begin =
|
|
std::prev(associations.end(), kExpectedAssociationCount);
|
|
VerifyAssociations(uut, expected_begin, associations.end());
|
|
}
|
|
|
|
// Version #1 - #(obsoleted entries) < #(entries after paring down below max).
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem1) {
|
|
constexpr size_t kMaxEntries = 100;
|
|
constexpr size_t kObsoletionTarget = (kMaxEntries / 4) - 1;
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem(kMaxEntries, kObsoletionTarget);
|
|
}
|
|
|
|
// Version #2 - #(obsoleted entries) == #(entries after paring down below max).
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem2) {
|
|
constexpr size_t kMaxEntries = 100;
|
|
constexpr size_t kObsoletionTarget = kMaxEntries / 4;
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem(kMaxEntries, kObsoletionTarget);
|
|
}
|
|
|
|
// Version #3 - #(obsoleted entries) > #(entries after paring down below max).
|
|
TEST_F(RtpSequenceNumberMapTest,
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem3) {
|
|
constexpr size_t kMaxEntries = 100;
|
|
constexpr size_t kObsoletionTarget = (kMaxEntries / 4) + 1;
|
|
MaxEntriesReachedAtSameTimeAsObsoletionOfItem(kMaxEntries, kObsoletionTarget);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|