Add SafeClamp(), which accepts args of different types

Specifically, just like SafeMin() and SafeMax() it handles all
combinations of integer and all
combinations of floating-point arguments by picking a
result type that is guaranteed to be able to hold the result.

This CL also replaces a bunch of std::min + std:max call pairs with
calls to SafeClamp()---the ones that could easily be found by grep
because "min" and "max" were on the same line. :-)

BUG=webrtc:7459

Review-Url: https://codereview.webrtc.org/2808513003
Cr-Commit-Position: refs/heads/master@{#18542}
This commit is contained in:
kwiberg 2017-06-12 11:40:47 -07:00 committed by Commit Bot
parent d1114c7fef
commit 0703856b53
23 changed files with 443 additions and 97 deletions

View File

@ -14,6 +14,8 @@
// rtc::SafeMin(x, y)
// rtc::SafeMax(x, y)
//
// (These are both constexpr.)
//
// Accept two arguments of either any two integral or any two floating-point
// types, and return the smaller and larger value, respectively, with no
// truncation or wrap-around. If only one of the input types is statically
@ -21,14 +23,48 @@
// if either one would do, the result type is the smaller type. (One of these
// two cases always applies.)
//
// (The case with one floating-point and one integral type is not allowed,
// because the floating-point type will have greater range, but may not have
// sufficient precision to represent the integer value exactly.)
// * The case with one floating-point and one integral type is not allowed,
// because the floating-point type will have greater range, but may not
// have sufficient precision to represent the integer value exactly.)
//
// Clamp (a.k.a. constrain to a given interval)
// ============================================
//
// rtc::SafeClamp(x, a, b)
//
// Accepts three arguments of any mix of integral types or any mix of
// floating-point types, and returns the value in the closed interval [a, b]
// that is closest to x (that is, if x < a it returns a; if x > b it returns b;
// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is
// no truncation or wrap-around. The result type
//
// 1. is statically guaranteed to be able to represent the result;
//
// 2. is no larger than the largest of the three argument types; and
//
// 3. has the same signedness as the type of the third argument, if this is
// possible without violating the First or Second Law.
//
// There is always at least one type that meets criteria 1 and 2. If more than
// one type meets these criteria equally well, the result type is one of the
// types that is smallest. Note that unlike SafeMin() and SafeMax(),
// SafeClamp() will sometimes pick a return type that isn't the type of any of
// its arguments.
//
// * In this context, a type A is smaller than a type B if it has a smaller
// range; that is, if A::max() - A::min() < B::max() - B::min(). For
// example, int8_t < int16_t == uint16_t < int32_t, and all integral types
// are smaller than all floating-point types.)
//
// * As for SafeMin and SafeMax, mixing integer and floating-point arguments
// is not allowed, because floating-point types have greater range than
// integer types, but do not have sufficient precision to represent the
// values of most integer types exactly.
//
// Requesting a specific return type
// =================================
//
// Both functions allow callers to explicitly specify the return type as a
// All three functions allow callers to explicitly specify the return type as a
// template parameter, overriding the default return type. E.g.
//
// rtc::SafeMin<int>(x, y) // returns an int
@ -187,6 +223,115 @@ constexpr R2 SafeMax(T1 a, T2 b) {
return safe_cmp::Gt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
}
namespace safe_minmax_impl {
// Given three types T, L, and H, let ::type be a suitable return value for
// SafeClamp(T, L, H). See the docs at the top of this file for details.
template <typename T,
typename L,
typename H,
bool int1 = IsIntlike<T>::value,
bool int2 = IsIntlike<L>::value,
bool int3 = IsIntlike<H>::value>
struct ClampType {
static_assert(int1 == int2 && int1 == int3,
"You may not mix integral and floating-point arguments");
};
// Specialization for when all three types are floating-point.
template <typename T, typename L, typename H>
struct ClampType<T, L, H, false, false, false> {
using type = typename std::common_type<T, L, H>::type;
};
// Specialization for when all three types are integral.
template <typename T, typename L, typename H>
struct ClampType<T, L, H, true, true, true> {
private:
// Range of the return value. The return type must be able to represent this
// full range.
static constexpr auto r_min =
SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest));
static constexpr auto r_max =
SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max));
// Is the given type an acceptable return type? (That is, can it represent
// all possible return values, and is it no larger than the largest of the
// input types?)
template <typename A>
struct AcceptableType {
private:
static constexpr bool not_too_large = sizeof(A) <= sizeof(L) ||
sizeof(A) <= sizeof(H) ||
sizeof(A) <= sizeof(T);
static constexpr bool range_contained =
safe_cmp::Le(Limits<A>::lowest, r_min) &&
safe_cmp::Le(r_max, Limits<A>::max);
public:
static constexpr bool value = not_too_large && range_contained;
};
using best_signed_type = typename std::conditional<
AcceptableType<int8_t>::value,
int8_t,
typename std::conditional<
AcceptableType<int16_t>::value,
int16_t,
typename std::conditional<AcceptableType<int32_t>::value,
int32_t,
int64_t>::type>::type>::type;
using best_unsigned_type = typename std::conditional<
AcceptableType<uint8_t>::value,
uint8_t,
typename std::conditional<
AcceptableType<uint16_t>::value,
uint16_t,
typename std::conditional<AcceptableType<uint32_t>::value,
uint32_t,
uint64_t>::type>::type>::type;
public:
// Pick the best type, preferring the same signedness as T but falling back
// to the other one if necessary.
using type = typename std::conditional<
std::is_signed<T>::value,
typename std::conditional<AcceptableType<best_signed_type>::value,
best_signed_type,
best_unsigned_type>::type,
typename std::conditional<AcceptableType<best_unsigned_type>::value,
best_unsigned_type,
best_signed_type>::type>::type;
static_assert(AcceptableType<type>::value, "");
};
} // namespace safe_minmax_impl
template <
typename R = safe_minmax_impl::DefaultType,
typename T = safe_minmax_impl::DefaultType,
typename L = safe_minmax_impl::DefaultType,
typename H = safe_minmax_impl::DefaultType,
typename R2 = typename safe_minmax_impl::TypeOr<
R,
typename safe_minmax_impl::ClampType<
typename safe_minmax_impl::UnderlyingType<T>::type,
typename safe_minmax_impl::UnderlyingType<L>::type,
typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type>
R2 SafeClamp(T x, L min, H max) {
static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value,
"The first argument must be integral or floating-point");
static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value,
"The second argument must be integral or floating-point");
static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value,
"The third argument must be integral or floating-point");
RTC_DCHECK_LE(min, max);
return safe_cmp::Le(x, min)
? static_cast<R2>(min)
: safe_cmp::Ge(x, max) ? static_cast<R2>(max) : static_cast<R2>(x);
}
} // namespace rtc
#endif // WEBRTC_BASE_SAFE_MINMAX_H_

View File

@ -18,8 +18,9 @@ namespace rtc {
namespace {
// Functions that check that SafeMin() and SafeMax() return the specified type.
// The functions that end in "R" use an explicitly given return type.
// Functions that check that SafeMin(), SafeMax(), and SafeClamp() return the
// specified type. The functions that end in "R" use an explicitly given return
// type.
template <typename T1, typename T2, typename Tmin, typename Tmax>
constexpr bool TypeCheckMinMax() {
@ -41,6 +42,21 @@ constexpr bool TypeCheckMaxR() {
decltype(SafeMax<R>(std::declval<T1>(), std::declval<T2>())), R>::value;
}
template <typename T, typename L, typename H, typename R>
constexpr bool TypeCheckClamp() {
return std::is_same<decltype(SafeClamp(std::declval<T>(), std::declval<L>(),
std::declval<H>())),
R>::value;
}
template <typename T, typename L, typename H, typename R>
constexpr bool TypeCheckClampR() {
return std::is_same<decltype(SafeClamp<R>(std::declval<T>(),
std::declval<L>(),
std::declval<H>())),
R>::value;
}
// clang-format off
// SafeMin/SafeMax: Check that all combinations of signed/unsigned 8/64 bits
@ -62,6 +78,73 @@ static_assert(TypeCheckMinMax<uint64_t, uint8_t, uint8_t, uint64_t>(), "");
static_assert(TypeCheckMinMax<uint64_t, int64_t, int64_t, uint64_t>(), "");
static_assert(TypeCheckMinMax<uint64_t, uint64_t, uint64_t, uint64_t>(), "");
// SafeClamp: Check that all combinations of signed/unsigned 8/64 bits give the
// correct result type.
static_assert(TypeCheckClamp< int8_t, int8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, int8_t, uint8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, int8_t, int64_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, int8_t, uint64_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint8_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint8_t, int64_t, int16_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint8_t, uint64_t, int16_t>(), "");
static_assert(TypeCheckClamp< int8_t, int64_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, int64_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClamp< int8_t, int64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int8_t, int64_t, uint64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint64_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint64_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int8_t, uint64_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int8_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int8_t, int64_t, int16_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int8_t, uint64_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint8_t, int8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint8_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint8_t, int64_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint8_t, uint64_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int64_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int64_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< uint8_t, int64_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint64_t, int8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint64_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint64_t, int64_t, uint64_t>(), "");
static_assert(TypeCheckClamp< uint8_t, uint64_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int64_t, int8_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClamp< int64_t, int8_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int8_t, uint64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint8_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint8_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint8_t, uint64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int64_t, int8_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int64_t, uint8_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, int64_t, uint64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint64_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint64_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp< int64_t, uint64_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int8_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int8_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int8_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int8_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint8_t, int8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint8_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint8_t, int64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint8_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int64_t, int8_t, int8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int64_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int64_t, int64_t, int64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, int64_t, uint64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint64_t, int8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint64_t, uint8_t, uint8_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint64_t, int64_t, uint64_t>(), "");
static_assert(TypeCheckClamp<uint64_t, uint64_t, uint64_t, uint64_t>(), "");
enum DefaultE { kFoo = -17 };
enum UInt8E : uint8_t { kBar = 17 };
@ -76,6 +159,35 @@ static_assert(TypeCheckMinMax< UInt8E, unsigned, uint8_t, unsigned>(), "");
static_assert(TypeCheckMinMax< UInt8E, DefaultE, int, int>(), "");
static_assert(TypeCheckMinMax< UInt8E, UInt8E, uint8_t, uint8_t>(), "");
// SafeClamp: Check that we can use enum types.
static_assert(TypeCheckClamp<unsigned, unsigned, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp<unsigned, unsigned, DefaultE, unsigned>(), "");
static_assert(TypeCheckClamp<unsigned, unsigned, UInt8E, uint8_t>(), "");
static_assert(TypeCheckClamp<unsigned, DefaultE, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp<unsigned, DefaultE, DefaultE, int>(), "");
static_assert(TypeCheckClamp<unsigned, DefaultE, UInt8E, uint8_t>(), "");
static_assert(TypeCheckClamp<unsigned, UInt8E, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp<unsigned, UInt8E, DefaultE, unsigned>(), "");
static_assert(TypeCheckClamp<unsigned, UInt8E, UInt8E, uint8_t>(), "");
static_assert(TypeCheckClamp<DefaultE, unsigned, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp<DefaultE, unsigned, DefaultE, int>(), "");
static_assert(TypeCheckClamp<DefaultE, unsigned, UInt8E, int16_t>(), "");
static_assert(TypeCheckClamp<DefaultE, DefaultE, unsigned, int>(), "");
static_assert(TypeCheckClamp<DefaultE, DefaultE, DefaultE, int>(), "");
static_assert(TypeCheckClamp<DefaultE, DefaultE, UInt8E, int>(), "");
static_assert(TypeCheckClamp<DefaultE, UInt8E, unsigned, int>(), "");
static_assert(TypeCheckClamp<DefaultE, UInt8E, DefaultE, int>(), "");
static_assert(TypeCheckClamp<DefaultE, UInt8E, UInt8E, int16_t>(), "");
static_assert(TypeCheckClamp< UInt8E, unsigned, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp< UInt8E, unsigned, DefaultE, unsigned>(), "");
static_assert(TypeCheckClamp< UInt8E, unsigned, UInt8E, uint8_t>(), "");
static_assert(TypeCheckClamp< UInt8E, DefaultE, unsigned, unsigned>(), "");
static_assert(TypeCheckClamp< UInt8E, DefaultE, DefaultE, int>(), "");
static_assert(TypeCheckClamp< UInt8E, DefaultE, UInt8E, uint8_t>(), "");
static_assert(TypeCheckClamp< UInt8E, UInt8E, unsigned, uint8_t>(), "");
static_assert(TypeCheckClamp< UInt8E, UInt8E, DefaultE, uint8_t>(), "");
static_assert(TypeCheckClamp< UInt8E, UInt8E, UInt8E, uint8_t>(), "");
using ld = long double;
// SafeMin/SafeMax: Check that all floating-point combinations give the
@ -90,6 +202,36 @@ static_assert(TypeCheckMinMax< ld, float, ld, ld>(), "");
static_assert(TypeCheckMinMax< ld, double, ld, ld>(), "");
static_assert(TypeCheckMinMax< ld, ld, ld, ld>(), "");
// SafeClamp: Check that all floating-point combinations give the correct
// result type.
static_assert(TypeCheckClamp< float, float, float, float>(), "");
static_assert(TypeCheckClamp< float, float, double, double>(), "");
static_assert(TypeCheckClamp< float, float, ld, ld>(), "");
static_assert(TypeCheckClamp< float, double, float, double>(), "");
static_assert(TypeCheckClamp< float, double, double, double>(), "");
static_assert(TypeCheckClamp< float, double, ld, ld>(), "");
static_assert(TypeCheckClamp< float, ld, float, ld>(), "");
static_assert(TypeCheckClamp< float, ld, double, ld>(), "");
static_assert(TypeCheckClamp< float, ld, ld, ld>(), "");
static_assert(TypeCheckClamp<double, float, float, double>(), "");
static_assert(TypeCheckClamp<double, float, double, double>(), "");
static_assert(TypeCheckClamp<double, float, ld, ld>(), "");
static_assert(TypeCheckClamp<double, double, float, double>(), "");
static_assert(TypeCheckClamp<double, double, double, double>(), "");
static_assert(TypeCheckClamp<double, double, ld, ld>(), "");
static_assert(TypeCheckClamp<double, ld, float, ld>(), "");
static_assert(TypeCheckClamp<double, ld, double, ld>(), "");
static_assert(TypeCheckClamp<double, ld, ld, ld>(), "");
static_assert(TypeCheckClamp< ld, float, float, ld>(), "");
static_assert(TypeCheckClamp< ld, float, double, ld>(), "");
static_assert(TypeCheckClamp< ld, float, ld, ld>(), "");
static_assert(TypeCheckClamp< ld, double, float, ld>(), "");
static_assert(TypeCheckClamp< ld, double, double, ld>(), "");
static_assert(TypeCheckClamp< ld, double, ld, ld>(), "");
static_assert(TypeCheckClamp< ld, ld, float, ld>(), "");
static_assert(TypeCheckClamp< ld, ld, double, ld>(), "");
static_assert(TypeCheckClamp< ld, ld, ld, ld>(), "");
// clang-format on
// SafeMin/SafeMax: Check some cases of explicitly specified return type. The
@ -103,12 +245,24 @@ static_assert(TypeCheckMinR<uint32_t, uint64_t, uint32_t>(), "");
static_assert(TypeCheckMaxR<uint32_t, int32_t, uint32_t>(), "");
// static_assert(TypeCheckMaxR<uint32_t, int32_t, int32_t>(), "");
// SafeClamp: Check some cases of explicitly specified return type. The
// commented-out lines give compilation errors due to the requested return type
// being too small.
static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int16_t>(), "");
static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int32_t>(), "");
// static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, uint32_t>(), "");
template <typename T1, typename T2, typename Tmin, typename Tmax>
constexpr bool CheckMinMax(T1 a, T2 b, Tmin min, Tmax max) {
return TypeCheckMinMax<T1, T2, Tmin, Tmax>() && SafeMin(a, b) == min &&
SafeMax(a, b) == max;
}
template <typename T, typename L, typename H, typename R>
bool CheckClamp(T x, L min, H max, R clamped) {
return TypeCheckClamp<T, L, H, R>() && SafeClamp(x, min, max) == clamped;
}
// SafeMin/SafeMax: Check a few values.
static_assert(CheckMinMax(int8_t{1}, int8_t{-1}, int8_t{-1}, int8_t{1}), "");
static_assert(CheckMinMax(uint8_t{1}, int8_t{-1}, int8_t{-1}, uint8_t{1}), "");
@ -127,22 +281,64 @@ static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
// static_assert(CheckMinMax(1.f, 2, 1.f, 2.f), "");
static_assert(CheckMinMax(1.f, 0.0, 0.0, 1.0), "");
// SafeClamp: Check a few values.
TEST(SafeMinmaxTest, Clamp) {
EXPECT_TRUE(CheckClamp(int32_t{-1000000}, std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max(),
std::numeric_limits<int16_t>::min()));
EXPECT_TRUE(CheckClamp(uint32_t{1000000}, std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max(),
std::numeric_limits<int16_t>::max()));
EXPECT_TRUE(CheckClamp(3.f, -1.0, 1.f, 1.0));
EXPECT_TRUE(CheckClamp(3.0, -1.f, 1.f, 1.0));
}
} // namespace
// clang-format off
// These functions aren't used in the tests, but it's useful to look at the
// compiler output for them, and verify that (1) the same-signedness *Safe
// functions result in exactly the same code as their *Ref counterparts, and
// that (2) the mixed-signedness *Safe functions have just a few extra
// compiler output for them, and verify that (1) the same-signedness Test*Safe
// functions result in exactly the same code as their Test*Ref counterparts,
// and that (2) the mixed-signedness Test*Safe functions have just a few extra
// arithmetic and logic instructions (but no extra control flow instructions).
// clang-format off
int32_t TestMinRef( int32_t a, int32_t b) { return std::min(a, b); }
uint32_t TestMinRef( uint32_t a, uint32_t b) { return std::min(a, b); }
int32_t TestMinSafe( int32_t a, int32_t b) { return SafeMin(a, b); }
int32_t TestMinSafe( int32_t a, uint32_t b) { return SafeMin(a, b); }
int32_t TestMinSafe(uint32_t a, int32_t b) { return SafeMin(a, b); }
uint32_t TestMinSafe(uint32_t a, uint32_t b) { return SafeMin(a, b); }
// clang-format on
int32_t TestClampRef(int32_t x, int32_t a, int32_t b) {
return std::max(a, std::min(x, b));
}
uint32_t TestClampRef(uint32_t x, uint32_t a, uint32_t b) {
return std::max(a, std::min(x, b));
}
int32_t TestClampSafe(int32_t x, int32_t a, int32_t b) {
return SafeClamp(x, a, b);
}
int32_t TestClampSafe(int32_t x, int32_t a, uint32_t b) {
return SafeClamp(x, a, b);
}
int32_t TestClampSafe(int32_t x, uint32_t a, int32_t b) {
return SafeClamp(x, a, b);
}
uint32_t TestClampSafe(int32_t x, uint32_t a, uint32_t b) {
return SafeClamp(x, a, b);
}
int32_t TestClampSafe(uint32_t x, int32_t a, int32_t b) {
return SafeClamp(x, a, b);
}
uint32_t TestClampSafe(uint32_t x, int32_t a, uint32_t b) {
return SafeClamp(x, a, b);
}
int32_t TestClampSafe(uint32_t x, uint32_t a, int32_t b) {
return SafeClamp(x, a, b);
}
uint32_t TestClampSafe(uint32_t x, uint32_t a, uint32_t b) {
return SafeClamp(x, a, b);
}
} // namespace rtc

View File

@ -20,6 +20,7 @@
#include "webrtc/base/numerics/exp_filter.h"
#include "webrtc/base/protobuf_utils.h"
#include "webrtc/base/safe_conversions.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/base/string_to_number.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/common_types.h"
@ -690,8 +691,8 @@ void AudioEncoderOpus::SetProjectedPacketLossRate(float fraction) {
}
void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
config_.bitrate_bps = rtc::Optional<int>(std::max(
std::min(bits_per_second, kOpusMaxBitrateBps), kOpusMinBitrateBps));
config_.bitrate_bps = rtc::Optional<int>(rtc::SafeClamp<int>(
bits_per_second, kOpusMinBitrateBps, kOpusMaxBitrateBps));
RTC_DCHECK(config_.IsOk());
RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps()));
const auto new_complexity = config_.GetNewComplexity();

View File

@ -20,6 +20,7 @@
#endif
#include "webrtc/base/arraysize.h"
#include "webrtc/base/random.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/aec3/aec3_fft.h"
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
#include "webrtc/modules/audio_processing/aec3/cascaded_biquad_filter.h"
@ -350,9 +351,8 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) {
fft.Ifft(S, &s);
std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2, e.begin(),
[&](float a, float b) { return a - b * kScale; });
std::for_each(e.begin(), e.end(), [](float& a) {
a = std::max(std::min(a, 32767.0f), -32768.0f);
});
std::for_each(e.begin(), e.end(),
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
fft.ZeroPaddedFft(e, &E);
gain.Compute(render_buffer, render_signal_analyzer, E,

View File

@ -14,6 +14,7 @@
#include <algorithm>
#include <numeric>
#include "webrtc/base/safe_minmax.h"
#include "webrtc/system_wrappers/include/metrics.h"
namespace webrtc {
@ -273,7 +274,7 @@ int TransformDbMetricForReporting(bool negate,
if (negate) {
new_value = -new_value;
}
return static_cast<int>(std::max(min_value, std::min(max_value, new_value)));
return static_cast<int>(rtc::SafeClamp(new_value, min_value, max_value));
}
} // namespace aec3

View File

@ -12,6 +12,8 @@
#include <algorithm>
#include "webrtc/base/safe_minmax.h"
namespace webrtc {
namespace {
@ -48,7 +50,7 @@ void ErleEstimator::Update(
if (new_erle > erle_[k]) {
hold_counters_[k - 1] = 100;
erle_[k] += 0.1f * (new_erle - erle_[k]);
erle_[k] = std::max(kMinErle, std::min(erle_[k], max_erle));
erle_[k] = rtc::SafeClamp(erle_[k], kMinErle, max_erle);
}
}
}

View File

@ -15,6 +15,7 @@
#include <string>
#include "webrtc/base/random.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h"
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
#include "webrtc/modules/audio_processing/aec3/render_buffer.h"
@ -99,9 +100,8 @@ void RunFilterUpdateTest(int num_blocks_to_process,
std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
e_main.begin(),
[&](float a, float b) { return a - b * kScale; });
std::for_each(e_main.begin(), e_main.end(), [](float& a) {
a = std::max(std::min(a, 32767.0f), -32768.0f);
});
std::for_each(e_main.begin(), e_main.end(),
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
fft.ZeroPaddedFft(e_main, &E_main);
// Apply the shadow filter.
@ -110,9 +110,8 @@ void RunFilterUpdateTest(int num_blocks_to_process,
std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
e_shadow.begin(),
[&](float a, float b) { return a - b * kScale; });
std::for_each(e_shadow.begin(), e_shadow.end(), [](float& a) {
a = std::max(std::min(a, 32767.0f), -32768.0f);
});
std::for_each(e_shadow.begin(), e_shadow.end(),
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
fft.ZeroPaddedFft(e_shadow, &E_shadow);
// Compute spectra for future use.

View File

@ -16,9 +16,10 @@
#include <vector>
#include "webrtc/base/random.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h"
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
#include "webrtc/modules/audio_processing/aec3/aec3_common.h"
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
#include "webrtc/modules/audio_processing/test/echo_canceller_test_tools.h"
#include "webrtc/test/gtest.h"
@ -75,9 +76,8 @@ void RunFilterUpdateTest(int num_blocks_to_process,
std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
e_shadow.begin(),
[&](float a, float b) { return a - b * kScale; });
std::for_each(e_shadow.begin(), e_shadow.end(), [](float& a) {
a = std::max(std::min(a, 32767.0f), -32768.0f);
});
std::for_each(e_shadow.begin(), e_shadow.end(),
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
fft.ZeroPaddedFft(e_shadow, &E_shadow);
shadow_gain.Compute(render_buffer, render_signal_analyzer, E_shadow,

View File

@ -14,6 +14,7 @@
#include "webrtc/base/array_view.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
namespace webrtc {
@ -30,9 +31,8 @@ void PredictionError(const Aec3Fft& fft,
constexpr float kScale = 1.0f / kFftLengthBy2;
std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2, e->begin(),
[&](float a, float b) { return a - b * kScale; });
std::for_each(e->begin(), e->end(), [](float& a) {
a = std::max(std::min(a, 32767.0f), -32768.0f);
});
std::for_each(e->begin(), e->end(),
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
fft.ZeroPaddedFft(*e, E);
}
} // namespace

View File

@ -16,6 +16,7 @@
#include <functional>
#include <numeric>
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/utility/ooura_fft.h"
namespace webrtc {
@ -122,7 +123,7 @@ void SuppressionFilter::ApplyGain(
std::transform((*e)[0].begin(), (*e)[0].end(), e_extended.begin(),
(*e)[0].begin(), std::plus<float>());
std::for_each((*e)[0].begin(), (*e)[0].end(), [](float& x_k) {
x_k = std::max(std::min(x_k, 32767.0f), -32768.0f);
x_k = rtc::SafeClamp(x_k, -32768.f, 32767.f);
});
std::copy(e_extended.begin() + kFftLengthBy2, e_extended.begin() + kFftLength,
std::begin(e_output_old_[0]));
@ -154,7 +155,7 @@ void SuppressionFilter::ApplyGain(
if (e->size() > 2) {
RTC_DCHECK_EQ(3, e->size());
std::for_each((*e)[2].begin(), (*e)[2].end(), [&](float& a) {
a = std::max(std::min(a * high_bands_gain, 32767.0f), -32768.0f);
a = rtc::SafeClamp(a * high_bands_gain, -32768.f, 32767.f);
});
}

View File

@ -18,6 +18,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/agc/gain_map_internal.h"
#include "webrtc/modules/audio_processing/gain_control_impl.h"
#include "webrtc/modules/include/module_common_types.h"
@ -56,7 +57,7 @@ const int kMaxResidualGainChange = 15;
const int kSurplusCompressionGain = 6;
int ClampLevel(int mic_level) {
return std::min(std::max(kMinMicLevel, mic_level), kMaxMicLevel);
return rtc::SafeClamp(mic_level, kMinMicLevel, kMaxMicLevel);
}
int LevelFromGainError(int gain_error, int level) {
@ -380,8 +381,9 @@ void AgcManagerDirect::UpdateGain() {
rms_error += kMinCompressionGain;
// Handle as much error as possible with the compressor first.
int raw_compression = std::max(std::min(rms_error, max_compression_gain_),
kMinCompressionGain);
int raw_compression =
rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_);
// Deemphasize the compression gain error. Move halfway between the current
// target and the newly received target. This serves to soften perceptible
// intra-talkspurt adjustments, at the cost of some adaptation speed.
@ -400,9 +402,9 @@ void AgcManagerDirect::UpdateGain() {
// Residual error will be handled by adjusting the volume slider. Use the
// raw rather than deemphasized compression here as we would otherwise
// shrink the amount of slack the compressor provides.
int residual_gain = rms_error - raw_compression;
residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange),
kMaxResidualGainChange);
const int residual_gain =
rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange,
kMaxResidualGainChange);
LOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", "
<< "target_compression=" << target_compression_ << ", "
<< "residual_gain=" << residual_gain;

View File

@ -680,15 +680,13 @@ void ApmTest::ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
// limit them w.r.t. AEC delay estimation support.
const size_t samples_per_ms =
rtc::SafeMin<size_t>(16u, frame_->samples_per_channel_ / 10);
int expected_median = std::min(std::max(delay_ms - system_delay_ms,
delay_min), delay_max);
int expected_median_high = std::min(
std::max(expected_median + static_cast<int>(96 / samples_per_ms),
delay_min),
const int expected_median =
rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
const int expected_median_high = rtc::SafeClamp<int>(
expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
delay_max);
int expected_median_low = std::min(
std::max(expected_median - static_cast<int>(96 / samples_per_ms),
delay_min),
const int expected_median_low = rtc::SafeClamp<int>(
expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
delay_max);
// Verify delay metrics.
int median;

View File

@ -18,6 +18,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/common_audio/include/audio_util.h"
#include "webrtc/common_audio/window_generator.h"
@ -287,23 +288,23 @@ std::vector<std::vector<float>> IntelligibilityEnhancer::CreateErbBank(
}
for (size_t i = 1; i <= bank_size_; ++i) {
static const size_t kOne = 1; // Avoids repeated static_cast<>s below.
size_t lll =
static_cast<size_t>(round(center_freqs_[std::max(kOne, i - lf) - 1] *
num_freqs / (0.5f * sample_rate_hz_)));
size_t ll = static_cast<size_t>(round(center_freqs_[std::max(kOne, i) - 1] *
num_freqs / (0.5f * sample_rate_hz_)));
lll = std::min(num_freqs, std::max(lll, kOne)) - 1;
ll = std::min(num_freqs, std::max(ll, kOne)) - 1;
size_t lll = static_cast<size_t>(
round(center_freqs_[rtc::SafeMax<size_t>(1, i - lf) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
size_t ll = static_cast<size_t>(
round(center_freqs_[rtc::SafeMax<size_t>(1, i) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
lll = rtc::SafeClamp<size_t>(lll, 1, num_freqs) - 1;
ll = rtc::SafeClamp<size_t>(ll, 1, num_freqs) - 1;
size_t rrr = static_cast<size_t>(
round(center_freqs_[std::min(bank_size_, i + rf) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
round(center_freqs_[rtc::SafeMin<size_t>(bank_size_, i + rf) - 1] *
num_freqs / (0.5f * sample_rate_hz_)));
size_t rr = static_cast<size_t>(
round(center_freqs_[std::min(bank_size_, i + 1) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
rrr = std::min(num_freqs, std::max(rrr, kOne)) - 1;
rr = std::min(num_freqs, std::max(rr, kOne)) - 1;
round(center_freqs_[rtc::SafeMin<size_t>(bank_size_, i + 1) - 1] *
num_freqs / (0.5f * sample_rate_hz_)));
rrr = rtc::SafeClamp<size_t>(rrr, 1, num_freqs) - 1;
rr = rtc::SafeClamp<size_t>(rr, 1, num_freqs) - 1;
float step = ll == lll ? 0.f : 1.f / (ll - lll);
float element = 0.f;

View File

@ -16,6 +16,8 @@
#include <algorithm>
#include <limits>
#include "webrtc/base/safe_minmax.h"
namespace webrtc {
namespace intelligibility {
@ -28,9 +30,9 @@ const float kMaxFactor = 100.f;
// Return |current| changed towards |target|, with the relative change being at
// most |limit|.
float UpdateFactor(float target, float current, float limit) {
float gain = target / (current + std::numeric_limits<float>::epsilon());
gain = std::min(std::max(gain, 1.f - limit), 1.f + limit);
return std::min(std::max(current * gain, kMinFactor), kMaxFactor);;
const float gain = target / (current + std::numeric_limits<float>::epsilon());
const float clamped_gain = rtc::SafeClamp(gain, 1 - limit, 1 + limit);
return rtc::SafeClamp(current * clamped_gain, kMinFactor, kMaxFactor);
}
} // namespace

View File

@ -62,11 +62,11 @@ int64_t AimdRateControl::GetFeedbackInterval() const {
// Estimate how often we can send RTCP if we allocate up to 5% of bandwidth
// to feedback.
static const int kRtcpSize = 80;
int64_t interval = static_cast<int64_t>(
const int64_t interval = static_cast<int64_t>(
kRtcpSize * 8.0 * 1000.0 / (0.05 * current_bitrate_bps_) + 0.5);
const int64_t kMinFeedbackIntervalMs = 200;
return std::min(std::max(interval, kMinFeedbackIntervalMs),
kMaxFeedbackIntervalMs);
return rtc::SafeClamp(interval, kMinFeedbackIntervalMs,
kMaxFeedbackIntervalMs);
}
bool AimdRateControl::TimeToReduceFurther(int64_t time_now,

View File

@ -19,6 +19,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
@ -144,11 +145,7 @@ void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) {
int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
threshold_ +=
k * (fabs(modified_offset) - threshold_) * time_delta_ms;
const double kMinThreshold = 6;
const double kMaxThreshold = 600;
threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);
threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);
last_update_ms_ = now_ms;
}

View File

@ -15,10 +15,11 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/pacing/packet_router.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace webrtc {
@ -104,8 +105,9 @@ void RemoteEstimatorProxy::OnBitrateChanged(int bitrate_bps) {
// Let TWCC reports occupy 5% of total bandwidth.
rtc::CritScope cs(&lock_);
send_interval_ms_ = static_cast<int>(0.5 + kTwccReportSize * 8.0 * 1000.0 /
(std::max(std::min(0.05 * bitrate_bps, kMaxTwccRate), kMinTwccRate)));
send_interval_ms_ = static_cast<int>(
0.5 + kTwccReportSize * 8.0 * 1000.0 /
rtc::SafeClamp(0.05 * bitrate_bps, kMinTwccRate, kMaxTwccRate));
}
void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,

View File

@ -15,6 +15,7 @@
#include <sstream>
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/safe_minmax.h"
namespace webrtc {
namespace testing {
@ -406,8 +407,8 @@ namespace {
inline int64_t TruncatedNSigmaGaussian(Random* const random,
int64_t mean,
int64_t std_dev) {
int64_t gaussian_random = random->Gaussian(mean, std_dev);
return std::max(std::min(gaussian_random, kN * std_dev), -kN * std_dev);
const int64_t gaussian_random = random->Gaussian(mean, std_dev);
return rtc::SafeClamp(gaussian_random, -kN * std_dev, kN * std_dev);
}
}

View File

@ -17,8 +17,9 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/rate_limiter.h"
#include "webrtc/base/trace_event.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/base/trace_event.h"
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
@ -467,16 +468,16 @@ size_t RTPSender::SendPadData(size_t bytes,
if (audio_configured_) {
// Allow smaller padding packets for audio.
padding_bytes_in_packet =
std::min(std::max(bytes, kMinAudioPaddingLength), max_payload_size);
if (padding_bytes_in_packet > kMaxPaddingLength)
padding_bytes_in_packet = kMaxPaddingLength;
padding_bytes_in_packet = rtc::SafeClamp<size_t>(
bytes, kMinAudioPaddingLength,
rtc::SafeMin(max_payload_size, kMaxPaddingLength));
} else {
// Always send full padding packets. This is accounted for by the
// RtpPacketSender, which will make sure we don't send too much padding even
// if a single packet is larger than requested.
// We do this to avoid frequently sending small packets on higher bitrates.
padding_bytes_in_packet = std::min(max_payload_size, kMaxPaddingLength);
padding_bytes_in_packet =
rtc::SafeMin<size_t>(max_payload_size, kMaxPaddingLength);
}
size_t bytes_sent = 0;
while (bytes_sent < bytes) {

View File

@ -21,6 +21,7 @@
#include "webrtc/base/messagedigest.h"
#include "webrtc/base/network.h"
#include "webrtc/base/ptr_util.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/p2p/base/common.h"
@ -69,7 +70,7 @@ const int DEFAULT_RTT = 3000; // 3 seconds
// Computes our estimate of the RTT given the current estimate.
inline int ConservativeRTTEstimate(int rtt) {
return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
return rtc::SafeClamp(2 * rtt, MINIMUM_RTT, MAXIMUM_RTT);
}
// Weighting of the old rtt value to new data.

View File

@ -23,6 +23,7 @@
#include "webrtc/base/byteorder.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/base/socket.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/base/timeutils.h"
@ -155,10 +156,6 @@ inline uint16_t bytes_to_short(const void* buf) {
return rtc::NetworkToHost16(*static_cast<const uint16_t*>(buf));
}
uint32_t bound(uint32_t lower, uint32_t middle, uint32_t upper) {
return std::min(std::max(lower, middle), upper);
}
//////////////////////////////////////////////////////////////////////
// Debugging Statistics
//////////////////////////////////////////////////////////////////////
@ -725,9 +722,8 @@ bool PseudoTcp::process(Segment& seg) {
m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
}
m_rx_rto =
bound(MIN_RTO, m_rx_srtt + std::max<uint32_t>(1, 4 * m_rx_rttvar),
MAX_RTO);
m_rx_rto = rtc::SafeClamp(m_rx_srtt + rtc::SafeMax(1, 4 * m_rx_rttvar),
MIN_RTO, MAX_RTO);
#if _DEBUGMSG >= _DBG_VERBOSE
LOG(LS_INFO) << "rtt: " << rtt
<< " srtt: " << m_rx_srtt

View File

@ -17,6 +17,7 @@
#include <memory>
#include "webrtc/base/flags.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/modules/audio_processing/agc/agc.h"
#include "webrtc/modules/audio_processing/agc/loudness_histogram.h"
#include "webrtc/modules/audio_processing/agc/utility.h"
@ -121,9 +122,7 @@ class AgcStat {
for (size_t n = 0; n < features.num_frames; n++) {
double p_active = p[n] * video_vad_[n];
double p_passive = (1 - p[n]) * (1 - video_vad_[n]);
p[n] = p_active / (p_active + p_passive);
// Limit probabilities.
p[n] = std::min(std::max(p[n], 0.01), 0.99);
p[n] = rtc::SafeClamp(p_active / (p_active + p_passive), 0.01, 0.99);
}
if (vad_->VoicingProbability(features, p) < 0)
return -1;

View File

@ -15,6 +15,7 @@
#include "webrtc/api/call/audio_sink.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/safe_minmax.h"
#include "webrtc/call/rtp_transport_controller_send_interface.h"
#include "webrtc/voice_engine/channel.h"
@ -290,7 +291,7 @@ void ChannelProxy::SetMinimumPlayoutDelay(int delay_ms) {
RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread());
// Limit to range accepted by both VoE and ACM, so we're at least getting as
// close as possible, instead of failing.
delay_ms = std::max(0, std::min(delay_ms, 10000));
delay_ms = rtc::SafeClamp(delay_ms, 0, 10000);
int error = channel()->SetMinimumPlayoutDelay(delay_ms);
if (0 != error) {
LOG(LS_WARNING) << "Error setting minimum playout delay.";