Uprev to branch-heads/74
To commit
'Merge to M74: Revert "Remove rtc::TimeMillis() call from ALR detector."'
https://webrtc.googlesource.com/src/+/303fc7963064a46a27e8287e531ded8cec21ff77
Existing aec.ini config files should be modified base on the parameters
change as below:
Added:
AEC_DELAY_DELAY_HEADROOM_SAMPLES "delay:delay_headroom_samples"
AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS "delay:hysteresis_limit_blocks"
AEC_EP_STRENGTH_DEFAULT_GAIN "ep_strength:default_gain"
Removed:
AEC_BUFFERING_USE_NEW_RENDER_BUFFERING "buffering:use_new_render_buffering"
AEC_DELAY_API_CALL_JITTER_BLOCKS "delay:api_call_jitter_blocks"
AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS "delay:min_echo_path_delay_blocks"
AEC_DELAY_DELAY_HEADROOM_BLOCKS "delay:delay_headroom_blocks"
AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS "delay:hysteresis_limit_1_blocks"
AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS "delay:hysteresis_limit_2_blocks"
AEC_DELAY_SKEW_HYSTERESIS_BLOCKS "delay:skew_hysteresis_blocks"
AEC_EP_STRENGTH_LF "ep_strength:lf"
AEC_EP_STRENGTH_MF "ep_strength:mf"
AEC_EP_STRENGTH_HF "ep_strength:hf"
AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN "echo_removal_control:initial_gain"
AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN "echo_removal_control:first_non_zero_gain"
AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS "echo_removal_control:non_zero_gain_blocks"
AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS "echo_removal_control:full_gain_blocks"
BUG=chromium:947914
TEST=emerge-atlas webrtc-apm
CQ-DEPEND=CL:1545342
Change-Id: Ifb701bfc14844c32b8d7561c4b48fd61be3f7157
Reviewed-on: https://chromium-review.googlesource.com/1545814
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Per Ã…hgren <peah@chromium.org>
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index edd0274..8e3c177 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt
index 1d09b19..bba0f3e 100644
--- a/absl/CMakeLists.txt
+++ b/absl/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index d04dc71..8d266db 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt
index fdf45c5..c51eb10 100644
--- a/absl/algorithm/CMakeLists.txt
+++ b/absl/algorithm/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,50 +14,50 @@
# limitations under the License.
#
-list(APPEND ALGORITHM_PUBLIC_HEADERS
- "algorithm.h"
- "container.h"
-)
-
-
-#
-## TESTS
-#
-
-# test algorithm_test
-list(APPEND ALGORITHM_TEST_SRC
- "algorithm_test.cc"
- ${ALGORITHM_PUBLIC_HEADERS}
- ${ALGORITHM_INTERNAL_HEADERS}
-)
-
-absl_header_library(
- TARGET
- absl_algorithm
- EXPORT_NAME
+absl_cc_library(
+ NAME
algorithm
+ HDRS
+ "algorithm.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ PUBLIC
)
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
algorithm_test
- SOURCES
- ${ALGORITHM_TEST_SRC}
- PUBLIC_LIBRARIES
+ SRCS
+ "algorithm_test.cc"
+ DEPS
absl::algorithm
+ gmock_main
)
-
-
-
-# test container_test
-set(CONTAINER_TEST_SRC "container_test.cc")
-
-absl_test(
- TARGET
- container_test
- SOURCES
- ${CONTAINER_TEST_SRC}
- PUBLIC_LIBRARIES
+absl_cc_library(
+ NAME
+ algorithm_container
+ HDRS
+ "container.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
absl::algorithm
+ absl::core_headers
+ absl::meta
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ container_test
+ SRCS
+ "container_test.cc"
+ DEPS
+ absl::algorithm_container
+ absl::base
+ absl::core_headers
+ absl::memory
+ absl::span
+ gmock_main
)
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
index 3d65864..bb90215 100644
--- a/absl/algorithm/algorithm.h
+++ b/absl/algorithm/algorithm.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -94,7 +94,7 @@
// then the predicate is never invoked and the function returns false.
//
// This is a C++11-compatible implementation of C++14 `std::equal`. See
-// http://en.cppreference.com/w/cpp/algorithm/equal for more information.
+// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
template <typename InputIter1, typename InputIter2, typename Pred>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, Pred&& pred) {
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc
index e4322bc..81fccb6 100644
--- a/absl/algorithm/algorithm_test.cc
+++ b/absl/algorithm/algorithm_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 53ab156..752e47b 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,7 +36,6 @@
// For template parameter and variable naming, `C` indicates the container type
// to which the function is applied, `Pred` indicates the predicate object type
// to be used by the function and `T` indicates the applicable element type.
-//
#ifndef ABSL_ALGORITHM_CONTAINER_H_
#define ABSL_ALGORITHM_CONTAINER_H_
@@ -46,6 +45,8 @@
#include <iterator>
#include <numeric>
#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -54,7 +55,6 @@
#include "absl/meta/type_traits.h"
namespace absl {
-
namespace container_algorithm_internal {
// NOTE: it is important to defer to ADL lookup for building with C++ modules,
@@ -101,6 +101,17 @@
template <typename C>
ContainerIter<C> c_end(C& c) { return end(c); }
+template <typename T>
+struct IsUnorderedContainer : std::false_type {};
+
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+ std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
+ : std::true_type {};
+
} // namespace container_algorithm_internal
// PUBLIC API
@@ -636,7 +647,6 @@
// and `unique()` are omitted, because it's not clear whether or not such
// functions should call erase on their supplied sequences afterwards. Either
// behavior would be surprising for a different set of users.
-//
// c_remove_copy()
//
@@ -1154,7 +1164,13 @@
// Container-based version of the <algorithm> `std::set_union()` function
// to return an iterator containing the union of two containers; duplicate
// values are not copied into the output.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
return std::set_union(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
@@ -1164,7 +1180,13 @@
// Overload of c_set_union() for performing a merge using a `comp` other than
// `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
Compare&& comp) {
return std::set_union(container_algorithm_internal::c_begin(c1),
@@ -1178,7 +1200,13 @@
//
// Container-based version of the <algorithm> `std::set_intersection()` function
// to return an iterator containing the intersection of two containers.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output) {
return std::set_intersection(container_algorithm_internal::c_begin(c1),
@@ -1189,7 +1217,13 @@
// Overload of c_set_intersection() for performing a merge using a `comp` other
// than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output, Compare&& comp) {
return std::set_intersection(container_algorithm_internal::c_begin(c1),
@@ -1204,7 +1238,13 @@
// Container-based version of the <algorithm> `std::set_difference()` function
// to return an iterator containing elements present in the first container but
// not in the second.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_difference(const C1& c1, const C2& c2,
OutputIterator output) {
return std::set_difference(container_algorithm_internal::c_begin(c1),
@@ -1215,7 +1255,13 @@
// Overload of c_set_difference() for performing a merge using a `comp` other
// than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_difference(const C1& c1, const C2& c2,
OutputIterator output, Compare&& comp) {
return std::set_difference(container_algorithm_internal::c_begin(c1),
@@ -1230,7 +1276,13 @@
// Container-based version of the <algorithm> `std::set_symmetric_difference()`
// function to return an iterator containing elements present in either one
// container or the other, but not both.
-template <typename C1, typename C2, typename OutputIterator>
+template <typename C1, typename C2, typename OutputIterator,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
OutputIterator output) {
return std::set_symmetric_difference(
@@ -1242,7 +1294,13 @@
// Overload of c_set_symmetric_difference() for performing a merge using a
// `comp` other than `operator<`.
-template <typename C1, typename C2, typename OutputIterator, typename Compare>
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+ void>::type,
+ typename = typename std::enable_if<
+ !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+ void>::type>
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
OutputIterator output,
Compare&& comp) {
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 1502b17..04282b8 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc
index 19c0780..7bf62c9 100644
--- a/absl/algorithm/equal_benchmark.cc
+++ b/absl/algorithm/equal_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index f7d8101..804f62a 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
@@ -67,6 +67,7 @@
name = "core_headers",
hdrs = [
"attributes.h",
+ "const_init.h",
"macros.h",
"optimization.h",
"port.h",
@@ -75,7 +76,6 @@
copts = ABSL_DEFAULT_COPTS,
deps = [
":config",
- ":dynamic_annotations",
],
)
@@ -89,6 +89,10 @@
"internal/low_level_alloc.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }),
visibility = [
"//absl:__subpackages__",
],
@@ -108,6 +112,7 @@
"internal/identity.h",
"internal/inline_variable.h",
"internal/invoke.h",
+ "internal/scheduling_mode.h",
],
copts = ABSL_DEFAULT_COPTS,
visibility = [
@@ -141,6 +146,10 @@
"log_severity.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }),
deps = [
":base_internal",
":config",
@@ -188,7 +197,6 @@
deps = [
":base",
":config",
- ":core_headers",
],
)
@@ -231,13 +239,12 @@
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [
- ":base",
":config",
":pretty_function",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/strings",
- "//absl/types:optional",
+ "//absl/utility",
"@com_google_googletest//:gtest",
],
)
@@ -316,6 +323,33 @@
)
cc_library(
+ name = "spinlock_benchmark_common",
+ testonly = 1,
+ srcs = ["internal/spinlock_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ visibility = [
+ "//absl/base:__pkg__",
+ ],
+ deps = [
+ ":base",
+ ":base_internal",
+ "//absl/synchronization",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+ alwayslink = 1,
+)
+
+cc_binary(
+ name = "spinlock_benchmark",
+ testonly = 1,
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":spinlock_benchmark_common",
+ ],
+)
+
+cc_library(
name = "endian",
hdrs = [
"internal/endian.h",
@@ -397,10 +431,6 @@
size = "small",
srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
tags = ["no_test_ios_x86_64"],
deps = [":malloc_internal"],
)
@@ -410,10 +440,6 @@
size = "small",
srcs = ["internal/thread_identity_test.cc"],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
tags = [
"no_test_wasm",
],
@@ -457,3 +483,25 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "scoped_set_env",
+ testonly = 1,
+ srcs = ["internal/scoped_set_env.cc"],
+ hdrs = ["internal/scoped_set_env.h"],
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [":base"],
+)
+
+cc_test(
+ name = "scoped_set_env_test",
+ size = "small",
+ srcs = ["internal/scoped_set_env_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":scoped_set_env",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/base/BUILD.gn b/absl/base/BUILD.gn
index 6c540f3..c7fa3f3 100644
--- a/absl/base/BUILD.gn
+++ b/absl/base/BUILD.gn
@@ -88,6 +88,7 @@
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"attributes.h",
+ "const_init.h",
"macros.h",
"optimization.h",
"port.h",
@@ -95,7 +96,6 @@
]
deps = [
":config",
- ":dynamic_annotations",
]
}
@@ -136,6 +136,7 @@
"internal/identity.h",
"internal/inline_variable.h",
"internal/invoke.h",
+ "internal/scheduling_mode.h",
]
visibility = []
visibility += [ "../*" ]
@@ -196,7 +197,6 @@
deps = [
":base",
":config",
- ":core_headers",
]
visibility = []
visibility += [ "../*" ]
@@ -251,13 +251,12 @@
# "internal/exception_safety_testing.h",
# ]
# deps = [
-# ":base",
# ":config",
# ":pretty_function",
# "../memory",
# "../meta:type_traits",
# "../strings",
-# "../types:optional",
+# "../utility",
# "//testing/gtest",
# ]
# }
@@ -314,3 +313,23 @@
visibility = []
visibility += [ "../*" ]
}
+
+source_set("scoped_set_env") {
+ testonly = true
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public = [
+ "internal/scoped_set_env.h",
+ ]
+ sources = [
+ "internal/scoped_set_env.cc",
+ ]
+ deps = [
+ ":base",
+ ]
+ visibility = []
+ visibility += [ "../*" ]
+}
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 04a6eb3..d8a311c 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,374 +14,427 @@
# limitations under the License.
#
-list(APPEND BASE_PUBLIC_HEADERS
- "attributes.h"
- "call_once.h"
- "casts.h"
- "config.h"
- "dynamic_annotations.h"
- "log_severity.h"
- "macros.h"
- "optimization.h"
- "policy_checks.h"
- "port.h"
- "thread_annotations.h"
+absl_cc_library(
+ NAME
+ spinlock_wait
+ HDRS
+ "internal/scheduling_mode.h"
+ "internal/spinlock_wait.h"
+ SRCS
+ "internal/spinlock_akaros.inc"
+ "internal/spinlock_linux.inc"
+ "internal/spinlock_posix.inc"
+ "internal/spinlock_wait.cc"
+ "internal/spinlock_win32.inc"
+ DEPS
+ absl::core_headers
)
-
-list(APPEND BASE_INTERNAL_HEADERS
- "internal/atomic_hook.h"
- "internal/bits.h"
- "internal/cycleclock.h"
- "internal/direct_mmap.h"
- "internal/endian.h"
- "internal/exception_testing.h"
- "internal/exception_safety_testing.h"
- "internal/hide_ptr.h"
- "internal/identity.h"
- "internal/invoke.h"
- "internal/inline_variable.h"
- "internal/low_level_alloc.h"
- "internal/low_level_scheduling.h"
- "internal/per_thread_tls.h"
- "internal/pretty_function.h"
- "internal/raw_logging.h"
- "internal/scheduling_mode.h"
- "internal/spinlock.h"
- "internal/spinlock_wait.h"
- "internal/sysinfo.h"
- "internal/thread_identity.h"
- "internal/throw_delegate.h"
- "internal/tsan_mutex_interface.h"
- "internal/unaligned_access.h"
- "internal/unscaledcycleclock.h"
+absl_cc_library(
+ NAME
+ config
+ HDRS
+ "config.h"
+ "policy_checks.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ PUBLIC
)
-
-# absl_base main library
-list(APPEND BASE_SRC
- "internal/cycleclock.cc"
- "internal/raw_logging.cc"
- "internal/spinlock.cc"
- "internal/sysinfo.cc"
- "internal/thread_identity.cc"
- "internal/unscaledcycleclock.cc"
- "internal/low_level_alloc.cc"
- ${BASE_PUBLIC_HEADERS}
- ${BASE_INTERNAL_HEADERS}
+absl_cc_library(
+ NAME
+ dynamic_annotations
+ HDRS
+ "dynamic_annotations.h"
+ SRCS
+ "dynamic_annotations.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEFINES
+ "__CLANG_SUPPORT_DYN_ANNOTATION__"
+ PUBLIC
)
-absl_library(
- TARGET
- absl_base
- SOURCES
- ${BASE_SRC}
- PUBLIC_LIBRARIES
- absl_dynamic_annotations
- absl_spinlock_wait
- EXPORT_NAME
- base
+absl_cc_library(
+ NAME
+ core_headers
+ HDRS
+ "attributes.h"
+ "const_init.h"
+ "macros.h"
+ "optimization.h"
+ "port.h"
+ "thread_annotations.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ PUBLIC
)
-# throw delegate library
-set(THROW_DELEGATE_SRC "internal/throw_delegate.cc")
-
-absl_library(
- TARGET
- absl_throw_delegate
- SOURCES
- ${THROW_DELEGATE_SRC}
- PUBLIC_LIBRARIES
- ${THROW_DELEGATE_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
- ${ABSL_EXCEPTIONS_FLAG}
- EXPORT_NAME
- throw_delegate
-)
-
-if(BUILD_TESTING)
- # exception-safety testing library
- set(EXCEPTION_SAFETY_TESTING_SRC
- "internal/exception_safety_testing.h"
- "internal/exception_safety_testing.cc"
- )
- set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
- ${ABSL_TEST_COMMON_LIBRARIES}
+absl_cc_library(
+ NAME
+ malloc_internal
+ HDRS
+ "internal/direct_mmap.h"
+ "internal/low_level_alloc.h"
+ SRCS
+ "internal/low_level_alloc.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
absl::base
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::spinlock_wait
+)
+
+absl_cc_library(
+ NAME
+ base_internal
+ HDRS
+ "internal/hide_ptr.h"
+ "internal/identity.h"
+ "internal/inline_variable.h"
+ "internal/invoke.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ base
+ HDRS
+ "call_once.h"
+ "casts.h"
+ "internal/atomic_hook.h"
+ "internal/cycleclock.h"
+ "internal/low_level_scheduling.h"
+ "internal/per_thread_tls.h"
+ "internal/raw_logging.h"
+ "internal/spinlock.h"
+ "internal/sysinfo.h"
+ "internal/thread_identity.h"
+ "internal/tsan_mutex_interface.h"
+ "internal/unscaledcycleclock.h"
+ "log_severity.h"
+ SRCS
+ "internal/cycleclock.cc"
+ "internal/raw_logging.cc"
+ "internal/spinlock.cc"
+ "internal/sysinfo.cc"
+ "internal/thread_identity.cc"
+ "internal/unscaledcycleclock.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base_internal
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::spinlock_wait
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ throw_delegate
+ HDRS
+ "internal/throw_delegate.h"
+ SRCS
+ "internal/throw_delegate.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ DEPS
+ absl::base
+)
+
+absl_cc_library(
+ NAME
+ exception_testing
+ HDRS
+ "internal/exception_testing.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ gtest
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ pretty_function
+ HDRS
+ "internal/pretty_function.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ exception_safety_testing
+ HDRS
+ "internal/exception_safety_testing.h"
+ SRCS
+ "internal/exception_safety_testing.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::config
+ absl::pretty_function
absl::memory
absl::meta
absl::strings
- absl::optional
+ absl::utility
gtest
- )
-
-absl_library(
- TARGET
- absl_base_internal_exception_safety_testing
- SOURCES
- ${EXCEPTION_SAFETY_TESTING_SRC}
- PUBLIC_LIBRARIES
- ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
- ${ABSL_EXCEPTIONS_FLAG}
-)
-endif()
-
-
-# dynamic_annotations library
-set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc")
-
-absl_library(
- TARGET
- absl_dynamic_annotations
- SOURCES
- ${DYNAMIC_ANNOTATIONS_SRC}
+ TESTONLY
)
-
-# spinlock_wait library
-set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc")
-
-absl_library(
- TARGET
- absl_spinlock_wait
- SOURCES
- ${SPINLOCK_WAIT_SRC}
-)
-
-
-# malloc_internal library
-list(APPEND MALLOC_INTERNAL_SRC
- "internal/low_level_alloc.cc"
-)
-
-absl_library(
- TARGET
- absl_malloc_internal
- SOURCES
- ${MALLOC_INTERNAL_SRC}
- PUBLIC_LIBRARIES
- absl_dynamic_annotations
-)
-
-
-
-#
-## TESTS
-#
-
-# call once test
-set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
-set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
-
-absl_test(
- TARGET
- atomic_hook_test
- SOURCES
- ${ATOMIC_HOOK_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# call once test
-set(CALL_ONCE_TEST_SRC "call_once_test.cc")
-set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- call_once_test
- SOURCES
- ${CALL_ONCE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CALL_ONCE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test bit_cast_test
-set(BIT_CAST_TEST_SRC "bit_cast_test.cc")
-
-absl_test(
- TARGET
- bit_cast_test
- SOURCES
- ${BIT_CAST_TEST_SRC}
-)
-
-
-# test absl_throw_delegate_test
-set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc")
-set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
-
-absl_test(
- TARGET
- throw_delegate_test
- SOURCES
- ${THROW_DELEGATE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test invoke_test
-set(INVOKE_TEST_SRC "invoke_test.cc")
-set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- invoke_test
- SOURCES
- ${INVOKE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INVOKE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test inline_variable_test
-list(APPEND INLINE_VARIABLE_TEST_SRC
- "internal/inline_variable_testing.h"
- "inline_variable_test.cc"
- "inline_variable_test_a.cc"
- "inline_variable_test_b.cc"
-)
-
-set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base)
-
-absl_test(
- TARGET
- inline_variable_test
- SOURCES
- ${INLINE_VARIABLE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test spinlock_test_common
-set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc")
-set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- spinlock_test_common
- SOURCES
- ${SPINLOCK_TEST_COMMON_SRC}
- PUBLIC_LIBRARIES
- ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES}
-)
-
-
-# test spinlock_test
-set(SPINLOCK_TEST_SRC "spinlock_test_common.cc")
-set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- spinlock_test
- SOURCES
- ${SPINLOCK_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPINLOCK_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test endian_test
-set(ENDIAN_TEST_SRC "internal/endian_test.cc")
-
-absl_test(
- TARGET
- endian_test
- SOURCES
- ${ENDIAN_TEST_SRC}
-)
-
-
-# test config_test
-set(CONFIG_TEST_SRC "config_test.cc")
-set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-absl_test(
- TARGET
- config_test
- SOURCES
- ${CONFIG_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CONFIG_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test raw_logging_test
-set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc")
-set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base absl::strings)
-
-absl_test(
- TARGET
- raw_logging_test
- SOURCES
- ${RAW_LOGGING_TEST_SRC}
- PUBLIC_LIBRARIES
- ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test sysinfo_test
-set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc")
-set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- sysinfo_test
- SOURCES
- ${SYSINFO_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SYSINFO_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test low_level_alloc_test
-set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc")
-set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base)
-
-absl_test(
- TARGET
- low_level_alloc_test
- SOURCES
- ${LOW_LEVEL_ALLOC_TEST_SRC}
- PUBLIC_LIBRARIES
- ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test thread_identity_test
-set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc")
-set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
-
-absl_test(
- TARGET
- thread_identity_test
- SOURCES
- ${THREAD_IDENTITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES}
-)
-
-#test exceptions_safety_testing_test
-set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
-set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
- absl::base
- absl_base_internal_exception_safety_testing
- absl::memory
- absl::meta
- absl::strings
- absl::optional
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
absl_exception_safety_testing_test
- SOURCES
- ${EXCEPTION_SAFETY_TESTING_TEST_SRC}
- PUBLIC_LIBRARIES
- ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "exception_safety_testing_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::exception_safety_testing
+ absl::memory
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ atomic_hook_test
+ SRCS
+ "internal/atomic_hook_test.cc"
+ DEPS
+ absl::base
+ absl::core_headers
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ bit_cast_test
+ SRCS
+ "bit_cast_test.cc"
+ DEPS
+ absl::base
+ absl::core_headers
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ throw_delegate_test
+ SRCS
+ "throw_delegate_test.cc"
+ DEPS
+ absl::base
+ absl::throw_delegate
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ inline_variable_test
+ SRCS
+ "internal/inline_variable_testing.h"
+ "inline_variable_test.cc"
+ "inline_variable_test_a.cc"
+ "inline_variable_test_b.cc"
+ DEPS
+ absl::base_internal
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ invoke_test
+ SRCS
+ "invoke_test.cc"
+ DEPS
+ absl::base_internal
+ absl::memory
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
+ spinlock_test_common
+ SRCS
+ "spinlock_test_common.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::spinlock_wait
+ absl::synchronization
+ gtest
+ TESTONLY
+)
+
+# On bazel BUILD this target use "alwayslink = 1" which is not implemented here
+absl_cc_test(
+ NAME
+ spinlock_test
+ SRCS
+ "spinlock_test_common.cc"
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::spinlock_wait
+ absl::synchronization
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
+ endian
+ HDRS
+ "internal/endian.h"
+ "internal/unaligned_access.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ endian_test
+ SRCS
+ "internal/endian_test.cc"
+ DEPS
+ absl::base
+ absl::config
+ absl::endian
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ config_test
+ SRCS
+ "config_test.cc"
+ DEPS
+ absl::config
+ absl::synchronization
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ call_once_test
+ SRCS
+ "call_once_test.cc"
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::synchronization
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ raw_logging_test
+ SRCS
+ "raw_logging_test.cc"
+ DEPS
+ absl::base
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ sysinfo_test
+ SRCS
+ "internal/sysinfo_test.cc"
+ DEPS
+ absl::base
+ absl::synchronization
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ low_level_alloc_test
+ SRCS
+ "internal/low_level_alloc_test.cc"
+ DEPS
+ absl::malloc_internal
+ Threads::Threads
+)
+
+absl_cc_test(
+ NAME
+ thread_identity_test
+ SRCS
+ "internal/thread_identity_test.cc"
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::synchronization
+ Threads::Threads
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
+ bits
+ HDRS
+ "internal/bits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+)
+
+absl_cc_test(
+ NAME
+ bits_test
+ SRCS
+ "internal/bits_test.cc"
+ DEPS
+ absl::bits
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
+ scoped_set_env
+ SRCS
+ "internal/scoped_set_env.cc"
+ HDRS
+ "internal/scoped_set_env.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+)
+
+absl_cc_test(
+ NAME
+ scoped_set_env_test
+ SRCS
+ "internal/scoped_set_env_test.cc"
+ DEPS
+ absl::scoped_set_env
+ gtest_main
)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index e850022..48195d6 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -80,7 +80,7 @@
//
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
-// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
+// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
#if defined(__cplusplus) && defined(__has_cpp_attribute)
// NOTE: requiring __cplusplus above should not be necessary, but
@@ -102,7 +102,7 @@
//
// Tells the compiler to perform `printf` format string checking if the
// compiler supports it; see the 'format' attribute in
-// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
+// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
@@ -155,7 +155,12 @@
// ABSL_ATTRIBUTE_WEAK
//
// Tags a function as weak for the purposes of compilation and linking.
-#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
+// Weak attributes currently do not work properly in LLVM's Windows backend,
+// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
+// for futher information.
+#if (ABSL_HAVE_ATTRIBUTE(weak) || \
+ (defined(__GNUC__) && !defined(__clang__))) && \
+ !(defined(__llvm__) && defined(_WIN32))
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
@@ -282,6 +287,17 @@
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
#endif
+// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+//
+// Tells the SafeStack to not instrument a given function.
+// See https://clang.llvm.org/docs/SafeStack.html for details.
+#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
+ __attribute__((no_sanitize("safe-stack")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+#endif
+
// ABSL_ATTRIBUTE_RETURNS_NONNULL
//
// Tells the compiler that a particular function never returns a null pointer.
@@ -296,13 +312,13 @@
// ABSL_HAVE_ATTRIBUTE_SECTION
//
-// Indicates whether labeled sections are supported. Labeled sections are not
-// supported on Darwin/iOS.
+// Indicates whether labeled sections are supported. Weak symbol support is
+// a prerequisite. Labeled sections are not supported on Darwin/iOS.
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
(defined(__GNUC__) && !defined(__clang__))) && \
- !defined(__APPLE__)
+ !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
// ABSL_ATTRIBUTE_SECTION
@@ -397,17 +413,28 @@
// ABSL_MUST_USE_RESULT
//
-// Tells the compiler to warn about unused return values for functions declared
-// with this macro. The macro must appear as the very first part of a function
-// declaration or definition:
+// Tells the compiler to warn about unused results.
//
-// Example:
+// When annotating a function, it must appear as the first part of the
+// declaration or definition. The compiler will warn if the return value from
+// such a function is unused:
//
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
+// AllocateSprocket(); // Triggers a warning.
//
-// This placement has the broadest compatibility with GCC, Clang, and MSVC, with
-// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11
-// and C++17 attributes.
+// When annotating a class, it is equivalent to annotating every function which
+// returns an instance.
+//
+// class ABSL_MUST_USE_RESULT Sprocket {};
+// Sprocket(); // Triggers a warning.
+//
+// Sprocket MakeSprocket();
+// MakeSprocket(); // Triggers a warning.
+//
+// Note that references and pointers are not instances:
+//
+// Sprocket* SprocketPointer();
+// SprocketPointer(); // Does *not* trigger a warning.
//
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
// warning. For that, warn_unused_result is used only for clang but not for gcc.
diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc
index 8cd878d..4846add 100644
--- a/absl/base/bit_cast_test.cc
+++ b/absl/base/bit_cast_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index 532ee2e..8c4f297 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -150,12 +150,8 @@
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
old_control != kOnceDone) {
- ABSL_RAW_LOG(
- FATAL,
- "Unexpected value for control word: %lx. Either the control word "
- "has non-static storage duration (where GoogleOnceDynamic might "
- "be appropriate), or there's been a memory corruption.",
- static_cast<unsigned long>(old_control)); // NOLINT
+ ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
+ static_cast<unsigned long>(old_control)); // NOLINT
}
}
#endif // NDEBUG
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
index cd58ee1..9c2a0c4 100644
--- a/absl/base/call_once_test.cc
+++ b/absl/base/call_once_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,6 +18,8 @@
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
@@ -25,7 +27,8 @@
namespace {
absl::once_flag once;
-Mutex counters_mu;
+
+ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
int running_thread_count GUARDED_BY(counters_mu) = 0;
int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
diff --git a/absl/base/casts.h b/absl/base/casts.h
index 20fd34d..00196d2 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -105,7 +105,7 @@
//
// Such implicit cast chaining may be useful within template logic.
template <typename To>
-inline To implicit_cast(typename absl::internal::identity_t<To> to) {
+constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
return to;
}
diff --git a/absl/base/config.h b/absl/base/config.h
index d4eb7d0..3b81e26 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -118,7 +118,7 @@
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
-// either libc++ or libstdc++, and Visual Studio.
+// either libc++ or libstdc++, and Visual Studio (but not NVCC).
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
@@ -127,7 +127,7 @@
(!defined(__clang__) && defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
- defined(_MSC_VER)
+ (defined(_MSC_VER) && !defined(__NVCC__))
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
@@ -139,12 +139,18 @@
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__)
-// Notes: Xcode's clang did not support `thread_local` until version
-// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing
-// `thread_local` for 32-bit iOS simulator targeting iOS 9.x.
-// `__has_feature` is only supported by Clang so it has be inside
+// Notes:
+// * Xcode's clang did not support `thread_local` until version 8, and
+// even then not for all iOS < 9.0.
+// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
+// targeting iOS 9.x.
+// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
+// making __has_feature unreliable there.
+//
+// Otherwise, `__has_feature` is only supported by Clang so it has be inside
// `defined(__APPLE__)` check.
-#if __has_feature(cxx_thread_local)
+#if __has_feature(cxx_thread_local) && \
+ !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
@@ -268,7 +274,8 @@
#error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
- defined(__wasm__) || defined(__Fuchsia__) || defined(__sun)
+ defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
+ defined(__ASYLO__)
#define ABSL_HAVE_MMAP 1
#endif
@@ -322,6 +329,8 @@
#define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER)
// feature tests for Microsoft's library
+#elif defined(__EMSCRIPTEN__)
+// emscripten doesn't support signals
#elif defined(__native_client__)
#else
// other standard libraries
@@ -356,6 +365,18 @@
#error "absl endian detection needs to be set up for your compiler"
#endif
+// MacOS 10.13 doesn't let you use <any>, <optional>, or <variant> even though
+// the headers exist and are publicly noted to work. See
+// https://github.com/abseil/abseil-cpp/issues/207 and
+// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
+#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
+ defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400
+#define ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 1
+#else
+#define ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 0
+#endif
+
// ABSL_HAVE_STD_ANY
//
// Checks whether C++17 std::any is available by checking whether <any> exists.
@@ -364,7 +385,8 @@
#endif
#ifdef __has_include
-#if __has_include(<any>) && __cplusplus >= 201703L
+#if __has_include(<any>) && __cplusplus >= 201703L && \
+ !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_ANY 1
#endif
#endif
@@ -377,7 +399,8 @@
#endif
#ifdef __has_include
-#if __has_include(<optional>) && __cplusplus >= 201703L
+#if __has_include(<optional>) && __cplusplus >= 201703L && \
+ !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_OPTIONAL 1
#endif
#endif
@@ -390,7 +413,8 @@
#endif
#ifdef __has_include
-#if __has_include(<variant>) && __cplusplus >= 201703L
+#if __has_include(<variant>) && __cplusplus >= 201703L && \
+ !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_VARIANT 1
#endif
#endif
@@ -423,4 +447,12 @@
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
+// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
+// SEH exception from emplace for variant<SomeStruct> when constructing the
+// struct can throw. This defeats some of variant_test and
+// variant_exception_safety_test.
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
+#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
+#endif
+
#endif // ABSL_BASE_CONFIG_H_
diff --git a/absl/base/config_test.cc b/absl/base/config_test.cc
index c839712..7e0c033 100644
--- a/absl/base/config_test.cc
+++ b/absl/base/config_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/const_init.h b/absl/base/const_init.h
new file mode 100644
index 0000000..17858a7
--- /dev/null
+++ b/absl/base/const_init.h
@@ -0,0 +1,72 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// kConstInit
+// -----------------------------------------------------------------------------
+//
+// A constructor tag used to mark an object as safe for use as a global
+// variable, avoiding the usual lifetime issues that can affect globals.
+
+#ifndef ABSL_BASE_CONST_INIT_H_
+#define ABSL_BASE_CONST_INIT_H_
+
+// In general, objects with static storage duration (such as global variables)
+// can trigger tricky object lifetime situations. Attempting to access them
+// from the constructors or destructors of other global objects can result in
+// undefined behavior, unless their constructors and destructors are designed
+// with this issue in mind.
+//
+// The normal way to deal with this issue in C++11 is to use constant
+// initialization and trivial destructors.
+//
+// Constant initialization is guaranteed to occur before any other code
+// executes. Constructors that are declared 'constexpr' are eligible for
+// constant initialization. You can annotate a variable declaration with the
+// ABSL_CONST_INIT macro to express this intent. For compilers that support
+// it, this annotation will cause a compilation error for declarations that
+// aren't subject to constant initialization (perhaps because a runtime value
+// was passed as a constructor argument).
+//
+// On program shutdown, lifetime issues can be avoided on global objects by
+// ensuring that they contain trivial destructors. A class has a trivial
+// destructor unless it has a user-defined destructor, a virtual method or base
+// class, or a data member or base class with a non-trivial destructor of its
+// own. Objects with static storage duration and a trivial destructor are not
+// cleaned up on program shutdown, and are thus safe to access from other code
+// running during shutdown.
+//
+// For a few core Abseil classes, we make a best effort to allow for safe global
+// instances, even though these classes have non-trivial destructors. These
+// objects can be created with the absl::kConstInit tag. For example:
+// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
+//
+// The line above declares a global variable of type absl::Mutex which can be
+// accessed at any point during startup or shutdown. global_mutex's destructor
+// will still run, but will not invalidate the object. Note that C++ specifies
+// that accessing an object after its destructor has run results in undefined
+// behavior, but this pattern works on the toolchains we support.
+//
+// The absl::kConstInit tag should only be used to define objects with static
+// or thread_local storage duration.
+
+namespace absl {
+
+enum ConstInitType {
+ kConstInit,
+};
+
+} // namespace absl
+
+#endif // ABSL_BASE_CONST_INIT_H_
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc
index b97fa3a..1411093 100644
--- a/absl/base/dynamic_annotations.cc
+++ b/absl/base/dynamic_annotations.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
index 88048b0..8ac7498 100644
--- a/absl/base/dynamic_annotations.h
+++ b/absl/base/dynamic_annotations.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -139,6 +139,7 @@
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
+
/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
appropriate feature ID. */
#if defined(__clang__) && (!defined(SWIG)) \
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 106bc34..2ed3860 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -770,6 +770,18 @@
.Test(invoker));
}
+TEST(ExceptionSafetyTesterTest, ResetsCountdown) {
+ auto test =
+ testing::MakeExceptionSafetyTester()
+ .WithInitialValue(ThrowingValue<>())
+ .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); })
+ .WithOperation([](ThrowingValue<>*) {});
+ ASSERT_TRUE(test.Test());
+ // If the countdown isn't reset because there were no exceptions thrown, then
+ // this will fail with a termination from an unhandled exception
+ EXPECT_TRUE(test.Test());
+}
+
struct NonCopyable : public NonNegative {
NonCopyable(const NonCopyable&) = delete;
NonCopyable() : NonNegative{0} {}
diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc
index 5499189..471f706 100644
--- a/absl/base/inline_variable_test.cc
+++ b/absl/base/inline_variable_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc
index a3bf3b6..d0b8e7d 100644
--- a/absl/base/inline_variable_test_a.cc
+++ b/absl/base/inline_variable_test_a.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc
index b4b9393..931d56d 100644
--- a/absl/base/inline_variable_test_b.cc
+++ b/absl/base/inline_variable_test_b.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h
index b458511..803e905 100644
--- a/absl/base/internal/atomic_hook.h
+++ b/absl/base/internal/atomic_hook.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/atomic_hook_test.cc b/absl/base/internal/atomic_hook_test.cc
index cf74075..ecc8040 100644
--- a/absl/base/internal/atomic_hook_test.cc
+++ b/absl/base/internal/atomic_hook_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h
index bc7faae..b0780f2 100644
--- a/absl/base/internal/bits.h
+++ b/absl/base/internal/bits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/bits_test.cc b/absl/base/internal/bits_test.cc
index e5d991d..7855fa6 100644
--- a/absl/base/internal/bits_test.cc
+++ b/absl/base/internal/bits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc
index a742df0..4b553c2 100644
--- a/absl/base/internal/cycleclock.cc
+++ b/absl/base/internal/cycleclock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,6 +22,7 @@
#include "absl/base/internal/cycleclock.h"
+#include <atomic>
#include <chrono> // NOLINT(build/c++11)
#include "absl/base/internal/unscaledcycleclock.h"
@@ -52,17 +53,26 @@
#endif
static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
+static std::atomic<CycleClockSourceFunc> cycle_clock_source;
} // namespace
int64_t CycleClock::Now() {
- return base_internal::UnscaledCycleClock::Now() >> kShift;
+ auto fn = cycle_clock_source.load(std::memory_order_relaxed);
+ if (fn == nullptr) {
+ return base_internal::UnscaledCycleClock::Now() >> kShift;
+ }
+ return fn() >> kShift;
}
double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
+void CycleClockSource::Register(CycleClockSourceFunc source) {
+ cycle_clock_source.store(source, std::memory_order_relaxed);
+}
+
#else
int64_t CycleClock::Now() {
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h
index 60e9715..794564e 100644
--- a/absl/base/internal/cycleclock.h
+++ b/absl/base/internal/cycleclock.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,7 +28,6 @@
// not necessarily "CPU cycles" and code should not rely on that behavior, even
// if experimentally observed.
//
-//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
@@ -71,6 +70,20 @@
CycleClock& operator=(const CycleClock&) = delete;
};
+using CycleClockSourceFunc = int64_t (*)();
+
+class CycleClockSource {
+ private:
+ // CycleClockSource::Register()
+ //
+ // Register a function that provides an alternate source for the unscaled CPU
+ // cycle count value. The source function must be async signal safe, must not
+ // call CycleClock::Now(), and must have a frequency that matches that of the
+ // unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
+ // the default source.
+ static void Register(CycleClockSourceFunc source);
+};
+
} // namespace base_internal
} // namespace absl
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h
index 0426e11..0401ddf 100644
--- a/absl/base/internal/direct_mmap.h
+++ b/absl/base/internal/direct_mmap.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -75,7 +75,11 @@
// On these architectures, implement mmap with mmap2.
static int pagesize = 0;
if (pagesize == 0) {
+#if defined(__wasm__) || defined(__asmjs__)
pagesize = getpagesize();
+#else
+ pagesize = sysconf(_SC_PAGESIZE);
+#endif
}
if (offset < 0 || offset % pagesize != 0) {
errno = EINVAL;
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
index edc10f1..6b828b6 100644
--- a/absl/base/internal/endian.h
+++ b/absl/base/internal/endian.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -75,21 +75,21 @@
if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int);
} else {
- register uint64_t result;
+ uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result;
}
#elif defined(__GLIBC__)
return bswap_64(host_int);
#else
- return (((x & uint64_t{(0xFF}) << 56) |
- ((x & uint64_t{(0xFF00}) << 40) |
- ((x & uint64_t{(0xFF0000}) << 24) |
- ((x & uint64_t{(0xFF000000}) << 8) |
- ((x & uint64_t{(0xFF00000000}) >> 8) |
- ((x & uint64_t{(0xFF0000000000}) >> 24) |
- ((x & uint64_t{(0xFF000000000000}) >> 40) |
- ((x & uint64_t{(0xFF00000000000000}) >> 56));
+ return (((host_int & uint64_t{0xFF}) << 56) |
+ ((host_int & uint64_t{0xFF00}) << 40) |
+ ((host_int & uint64_t{0xFF0000}) << 24) |
+ ((host_int & uint64_t{0xFF000000}) << 8) |
+ ((host_int & uint64_t{0xFF00000000}) >> 8) |
+ ((host_int & uint64_t{0xFF0000000000}) >> 24) |
+ ((host_int & uint64_t{0xFF000000000000}) >> 40) |
+ ((host_int & uint64_t{0xFF00000000000000}) >> 56));
#endif // bswap_64
}
@@ -97,8 +97,10 @@
#if defined(__GLIBC__)
return bswap_32(host_int);
#else
- return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) |
- ((x & 0xFF000000) >> 24));
+ return (((host_int & uint32_t{0xFF}) << 24) |
+ ((host_int & uint32_t{0xFF00}) << 8) |
+ ((host_int & uint32_t{0xFF0000}) >> 8) |
+ ((host_int & uint32_t{0xFF000000}) >> 24));
#endif
}
@@ -106,7 +108,8 @@
#if defined(__GLIBC__)
return bswap_16(host_int);
#else
- return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)};
+ return (((host_int & uint16_t{0xFF}) << 8) |
+ ((host_int & uint16_t{0xFF00}) >> 8));
#endif
}
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
index e276915..98a099e 100644
--- a/absl/base/internal/endian_test.cc
+++ b/absl/base/internal/endian_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc
index f1d081f..6ef4325 100644
--- a/absl/base/internal/exception_safety_testing.cc
+++ b/absl/base/internal/exception_safety_testing.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,6 +23,10 @@
exceptions_internal::StrongGuaranteeTagType strong_guarantee;
+exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester() {
+ return {};
+}
+
namespace exceptions_internal {
int countdown = -1;
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index 5665a1b..be38ba5 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -33,7 +33,7 @@
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
-#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
namespace testing {
@@ -127,10 +127,8 @@
void* address = it.first;
TrackedAddress& tracked_address = it.second;
if (tracked_address.is_alive) {
- ADD_FAILURE() << "Object at address " << address
- << " with countdown of " << countdown_
- << " was not destroyed [" << tracked_address.description
- << "]";
+ ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
+ countdown_, "Object was not destroyed.");
}
}
}
@@ -141,11 +139,11 @@
TrackedAddress& tracked_address =
current_tracker_instance_->address_map_[address];
if (tracked_address.is_alive) {
- ADD_FAILURE() << "Object at address " << address << " with countdown of "
- << current_tracker_instance_->countdown_
- << " was re-constructed. Previously: ["
- << tracked_address.description << "] Now: [" << description
- << "]";
+ ADD_FAILURE() << ErrorMessage(
+ address, tracked_address.description,
+ current_tracker_instance_->countdown_,
+ "Object was re-constructed. Current object was constructed by " +
+ description);
}
tracked_address = {true, std::move(description)};
}
@@ -159,10 +157,9 @@
TrackedAddress& tracked_address = it->second;
if (!tracked_address.is_alive) {
- ADD_FAILURE() << "Object at address " << address << " with countdown of "
- << current_tracker_instance_->countdown_
- << " was re-destroyed or created prior to construction "
- << "tracking [" << tracked_address.description << "]";
+ ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
+ current_tracker_instance_->countdown_,
+ "Object was re-destroyed.");
}
tracked_address.is_alive = false;
}
@@ -172,6 +169,18 @@
return current_tracker_instance_ != nullptr;
}
+ static std::string ErrorMessage(void* address,
+ const std::string& address_description,
+ int countdown,
+ const std::string& error_description) {
+ return absl::Substitute(
+ "With coundtown at $0:\n"
+ " $1\n"
+ " Object originally constructed by $2\n"
+ " Object address: $3\n",
+ countdown, error_description, address_description, address);
+ }
+
std::unordered_map<void*, TrackedAddress> address_map_;
int countdown_;
@@ -190,70 +199,6 @@
~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
};
-
-template <typename Factory, typename Operation, typename Contract>
-absl::optional<testing::AssertionResult> TestSingleContractAtCountdownImpl(
- const Factory& factory, const Operation& operation, int count,
- const Contract& contract) {
- auto t_ptr = factory();
- absl::optional<testing::AssertionResult> current_res;
- SetCountdown(count);
- try {
- operation(t_ptr.get());
- } catch (const exceptions_internal::TestException& e) {
- current_res.emplace(contract(t_ptr.get()));
- if (!current_res.value()) {
- *current_res << e.what() << " failed contract check";
- }
- }
- UnsetCountdown();
- return current_res;
-}
-
-template <typename Factory, typename Operation>
-absl::optional<testing::AssertionResult> TestSingleContractAtCountdownImpl(
- const Factory& factory, const Operation& operation, int count,
- StrongGuaranteeTagType) {
- using TPtr = typename decltype(factory())::pointer;
- auto t_is_strong = [&](TPtr t) { return *t == *factory(); };
- return TestSingleContractAtCountdownImpl(factory, operation, count,
- t_is_strong);
-}
-
-template <typename Factory, typename Operation, typename Contract>
-int TestSingleContractAtCountdown(
- const Factory& factory, const Operation& operation, int count,
- const Contract& contract,
- absl::optional<testing::AssertionResult>* reduced_res) {
- // If reduced_res is empty, it means the current call to
- // TestSingleContractAtCountdown(...) is the first test being run so we do
- // want to run it. Alternatively, if it's not empty (meaning a previous test
- // has run) we want to check if it passed. If the previous test did pass, we
- // want to contine running tests so we do want to run the current one. If it
- // failed, we want to short circuit so as not to overwrite the AssertionResult
- // output. If that's the case, we do not run the current test and instead we
- // simply return.
- if (!reduced_res->has_value() || reduced_res->value()) {
- *reduced_res =
- TestSingleContractAtCountdownImpl(factory, operation, count, contract);
- }
- return 0;
-}
-
-template <typename Factory, typename Operation, typename... Contracts>
-inline absl::optional<testing::AssertionResult> TestAllContractsAtCountdown(
- const Factory& factory, const Operation& operation, int count,
- const Contracts&... contracts) {
- absl::optional<testing::AssertionResult> reduced_res;
-
- // Run each checker, short circuiting after the first failure
- int dummy[] = {
- 0, (TestSingleContractAtCountdown(factory, operation, count, contracts,
- &reduced_res))...};
- static_cast<void>(dummy);
- return reduced_res;
-}
-
} // namespace exceptions_internal
extern exceptions_internal::NoThrowTag nothrow_ctor;
@@ -613,8 +558,8 @@
// We provide both regular and templated operator delete because if only the
// templated version is provided as we did with operator new, the compiler has
// no way of knowing which overload of operator delete to call. See
- // http://en.cppreference.com/w/cpp/memory/new/operator_delete and
- // http://en.cppreference.com/w/cpp/language/delete for the gory details.
+ // https://en.cppreference.com/w/cpp/memory/new/operator_delete and
+ // https://en.cppreference.com/w/cpp/language/delete for the gory details.
void operator delete(void* p) noexcept { ::operator delete(p); }
template <typename... Args>
@@ -773,7 +718,7 @@
}
size_type max_size() const noexcept {
- return std::numeric_limits<difference_type>::max() / sizeof(value_type);
+ return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
}
ThrowingAllocator select_on_container_copy_construction() noexcept(
@@ -871,7 +816,7 @@
namespace exceptions_internal {
-// Dummy struct for ExceptionSafetyTester<> partial state.
+// Dummy struct for ExceptionSafetyTestBuilder<> partial state.
struct UninitializedT {};
template <typename T>
@@ -893,20 +838,97 @@
template <typename Factory = UninitializedT,
typename Operation = UninitializedT, typename... Contracts>
-class ExceptionSafetyTester;
+class ExceptionSafetyTestBuilder;
} // namespace exceptions_internal
-exceptions_internal::ExceptionSafetyTester<> MakeExceptionSafetyTester();
+/*
+ * Constructs an empty ExceptionSafetyTestBuilder. All
+ * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation
+ * methods return new instances of ExceptionSafetyTestBuilder.
+ *
+ * In order to test a T for exception safety, a factory for that T, a testable
+ * operation, and at least one contract callback returning an assertion
+ * result must be applied using the respective methods.
+ */
+exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
namespace exceptions_internal {
+template <typename T>
+struct IsUniquePtr : std::false_type {};
+
+template <typename T, typename D>
+struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
+
+template <typename Factory>
+struct FactoryPtrTypeHelper {
+ using type = decltype(std::declval<const Factory&>()());
+
+ static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr");
+};
+
+template <typename Factory>
+using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type;
+
+template <typename Factory>
+using FactoryElementType = typename FactoryPtrType<Factory>::element_type;
+
+template <typename T>
+class ExceptionSafetyTest {
+ using Factory = std::function<std::unique_ptr<T>()>;
+ using Operation = std::function<void(T*)>;
+ using Contract = std::function<AssertionResult(T*)>;
+
+ public:
+ template <typename... Contracts>
+ explicit ExceptionSafetyTest(const Factory& f, const Operation& op,
+ const Contracts&... contracts)
+ : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
+
+ AssertionResult Test() const {
+ for (int count = 0;; ++count) {
+ exceptions_internal::ConstructorTracker ct(count);
+
+ for (const auto& contract : contracts_) {
+ auto t_ptr = factory_();
+ try {
+ SetCountdown(count);
+ operation_(t_ptr.get());
+ // Unset for the case that the operation throws no exceptions, which
+ // would leave the countdown set and break the *next* exception safety
+ // test after this one.
+ UnsetCountdown();
+ return AssertionSuccess();
+ } catch (const exceptions_internal::TestException& e) {
+ if (!contract(t_ptr.get())) {
+ return AssertionFailure() << e.what() << " failed contract check";
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ template <typename ContractFn>
+ Contract WrapContract(const ContractFn& contract) {
+ return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); };
+ }
+
+ Contract WrapContract(StrongGuaranteeTagType) {
+ return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); };
+ }
+
+ Factory factory_;
+ Operation operation_;
+ std::vector<Contract> contracts_;
+};
/*
* Builds a tester object that tests if performing a operation on a T follows
* exception safety guarantees. Verification is done via contract assertion
* callbacks applied to T instances post-throw.
*
- * Template parameters for ExceptionSafetyTester:
+ * Template parameters for ExceptionSafetyTestBuilder:
*
* - Factory: The factory object (passed in via tester.WithFactory(...) or
* tester.WithInitialValue(...)) must be invocable with the signature
@@ -933,13 +955,13 @@
* please.
*/
template <typename Factory, typename Operation, typename... Contracts>
-class ExceptionSafetyTester {
+class ExceptionSafetyTestBuilder {
public:
/*
- * Returns a new ExceptionSafetyTester with an included T factory based on the
- * provided T instance. The existing factory will not be included in the newly
- * created tester instance. The created factory returns a new T instance by
- * copy-constructing the provided const T& t.
+ * Returns a new ExceptionSafetyTestBuilder with an included T factory based
+ * on the provided T instance. The existing factory will not be included in
+ * the newly created tester instance. The created factory returns a new T
+ * instance by copy-constructing the provided const T& t.
*
* Preconditions for tester.WithInitialValue(const T& t):
*
@@ -948,41 +970,41 @@
* tester.WithFactory(...).
*/
template <typename T>
- ExceptionSafetyTester<DefaultFactory<T>, Operation, Contracts...>
+ ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...>
WithInitialValue(const T& t) const {
return WithFactory(DefaultFactory<T>(t));
}
/*
- * Returns a new ExceptionSafetyTester with the provided T factory included.
- * The existing factory will not be included in the newly-created tester
- * instance. This method is intended for use with types lacking a copy
+ * Returns a new ExceptionSafetyTestBuilder with the provided T factory
+ * included. The existing factory will not be included in the newly-created
+ * tester instance. This method is intended for use with types lacking a copy
* constructor. Types that can be copy-constructed should instead use the
* method tester.WithInitialValue(...).
*/
template <typename NewFactory>
- ExceptionSafetyTester<absl::decay_t<NewFactory>, Operation, Contracts...>
+ ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...>
WithFactory(const NewFactory& new_factory) const {
return {new_factory, operation_, contracts_};
}
/*
- * Returns a new ExceptionSafetyTester with the provided testable operation
- * included. The existing operation will not be included in the newly created
- * tester.
+ * Returns a new ExceptionSafetyTestBuilder with the provided testable
+ * operation included. The existing operation will not be included in the
+ * newly created tester.
*/
template <typename NewOperation>
- ExceptionSafetyTester<Factory, absl::decay_t<NewOperation>, Contracts...>
+ ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
WithOperation(const NewOperation& new_operation) const {
return {factory_, new_operation, contracts_};
}
/*
- * Returns a new ExceptionSafetyTester with the provided MoreContracts...
+ * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts...
* combined with the Contracts... that were already included in the instance
* on which the method was called. Contracts... cannot be removed or replaced
- * once added to an ExceptionSafetyTester instance. A fresh object must be
- * created in order to get an empty Contracts... list.
+ * once added to an ExceptionSafetyTestBuilder instance. A fresh object must
+ * be created in order to get an empty Contracts... list.
*
* In addition to passing in custom contract assertion callbacks, this method
* accepts `testing::strong_guarantee` as an argument which checks T instances
@@ -991,8 +1013,8 @@
* properly rolled back.
*/
template <typename... MoreContracts>
- ExceptionSafetyTester<Factory, Operation, Contracts...,
- absl::decay_t<MoreContracts>...>
+ ExceptionSafetyTestBuilder<Factory, Operation, Contracts...,
+ absl::decay_t<MoreContracts>...>
WithContracts(const MoreContracts&... more_contracts) const {
return {
factory_, operation_,
@@ -1039,48 +1061,27 @@
typename LazyOperation = Operation,
typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>>
testing::AssertionResult Test() const {
- return TestImpl(operation_, absl::index_sequence_for<Contracts...>());
+ return Test(operation_);
}
private:
template <typename, typename, typename...>
- friend class ExceptionSafetyTester;
+ friend class ExceptionSafetyTestBuilder;
- friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester();
+ friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
- ExceptionSafetyTester() {}
+ ExceptionSafetyTestBuilder() {}
- ExceptionSafetyTester(const Factory& f, const Operation& o,
- const std::tuple<Contracts...>& i)
+ ExceptionSafetyTestBuilder(const Factory& f, const Operation& o,
+ const std::tuple<Contracts...>& i)
: factory_(f), operation_(o), contracts_(i) {}
template <typename SelectedOperation, size_t... Indices>
- testing::AssertionResult TestImpl(const SelectedOperation& selected_operation,
+ testing::AssertionResult TestImpl(SelectedOperation selected_operation,
absl::index_sequence<Indices...>) const {
- // Starting from 0 and counting upwards until one of the exit conditions is
- // hit...
- for (int count = 0;; ++count) {
- exceptions_internal::ConstructorTracker ct(count);
-
- // Run the full exception safety test algorithm for the current countdown
- auto reduced_res =
- TestAllContractsAtCountdown(factory_, selected_operation, count,
- std::get<Indices>(contracts_)...);
- // If there is no value in the optional, no contracts were run because no
- // exception was thrown. This means that the test is complete and the loop
- // can exit successfully.
- if (!reduced_res.has_value()) {
- return testing::AssertionSuccess();
- }
- // If the optional is not empty and the value is falsy, an contract check
- // failed so the test must exit to propegate the failure.
- if (!reduced_res.value()) {
- return reduced_res.value();
- }
- // If the optional is not empty and the value is not falsy, it means
- // exceptions were thrown but the contracts passed so the test must
- // continue to run.
- }
+ return ExceptionSafetyTest<FactoryElementType<Factory>>(
+ factory_, selected_operation, std::get<Indices>(contracts_)...)
+ .Test();
}
Factory factory_;
@@ -1090,20 +1091,6 @@
} // namespace exceptions_internal
-/*
- * Constructs an empty ExceptionSafetyTester. All ExceptionSafetyTester
- * objects are immutable and all With[thing] mutation methods return new
- * instances of ExceptionSafetyTester.
- *
- * In order to test a T for exception safety, a factory for that T, a testable
- * operation, and at least one contract callback returning an assertion
- * result must be applied using the respective methods.
- */
-inline exceptions_internal::ExceptionSafetyTester<>
-MakeExceptionSafetyTester() {
- return {};
-}
-
} // namespace testing
#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h
index 0cf7918..01b5465 100644
--- a/absl/base/internal/exception_testing.h
+++ b/absl/base/internal/exception_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h
index 45cf438..cf8f408 100644
--- a/absl/base/internal/hide_ptr.h
+++ b/absl/base/internal/hide_ptr.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h
index a1a5d70..086447c 100644
--- a/absl/base/internal/identity.h
+++ b/absl/base/internal/identity.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h
index f7bb8c5..130d8c2 100644
--- a/absl/base/internal/inline_variable.h
+++ b/absl/base/internal/inline_variable.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h
index a0dd2bb..15dc481 100644
--- a/absl/base/internal/inline_variable_testing.h
+++ b/absl/base/internal/inline_variable_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
index 8c3f4f6..8da2869 100644
--- a/absl/base/internal/invoke.h
+++ b/absl/base/internal/invoke.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index 159f945..e4030ed 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -208,7 +208,7 @@
int32_t allocation_count GUARDED_BY(mu);
// flags passed to NewArena
const uint32_t flags;
- // Result of getpagesize()
+ // Result of sysconf(_SC_PAGESIZE)
const size_t pagesize;
// Lowest power of two >= max(16, sizeof(AllocList))
const size_t roundup;
@@ -324,8 +324,10 @@
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
-#else
+#elif defined(__wasm__) || defined(__asmjs__)
return getpagesize();
+#else
+ return sysconf(_SC_PAGESIZE);
#endif
}
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
index fba9466..b35673d 100644
--- a/absl/base/internal/low_level_alloc.h
+++ b/absl/base/internal/low_level_alloc.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -119,4 +119,5 @@
} // namespace base_internal
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
index cf2b363..34a080c 100644
--- a/absl/base/internal/low_level_alloc_test.cc
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -137,6 +137,7 @@
TEST_ASSERT(LowLevelAlloc::DeleteArena(arena));
}
}
+
// LowLevelAlloc is designed to be safe to call before main().
static struct BeforeMain {
BeforeMain() {
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h
index e716f2b..0fcc8d3 100644
--- a/absl/base/internal/low_level_scheduling.h
+++ b/absl/base/internal/low_level_scheduling.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -86,6 +86,7 @@
//------------------------------------------------------------------------------
// End of public interfaces.
//------------------------------------------------------------------------------
+
inline bool SchedulingGuard::ReschedulingIsAllowed() {
return false;
}
@@ -98,7 +99,7 @@
return;
}
-
} // namespace base_internal
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/absl/base/internal/per_thread_tls.h b/absl/base/internal/per_thread_tls.h
index 2428bdc..cf5e97a 100644
--- a/absl/base/internal/per_thread_tls.h
+++ b/absl/base/internal/per_thread_tls.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,13 +16,17 @@
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
// This header defines two macros:
+//
// If the platform supports thread-local storage:
-// ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
-// thread-local variable ABSL_PER_THREAD_TLS is 1
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
+// thread-local variable
+// * ABSL_PER_THREAD_TLS is 1
//
// Otherwise:
-// ABSL_PER_THREAD_TLS_KEYWORD is empty
-// ABSL_PER_THREAD_TLS is 0
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is empty
+// * ABSL_PER_THREAD_TLS is 0
//
// Microsoft C supports thread-local storage.
// GCC supports it if the appropriate version of glibc is available,
diff --git a/absl/base/internal/pretty_function.h b/absl/base/internal/pretty_function.h
index 01b0547..35d5167 100644
--- a/absl/base/internal/pretty_function.h
+++ b/absl/base/internal/pretty_function.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
index d9485a6..b5a05e8 100644
--- a/absl/base/internal/raw_logging.cc
+++ b/absl/base/internal/raw_logging.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
index 79a7bb9..6a4c093 100644
--- a/absl/base/internal/raw_logging.h
+++ b/absl/base/internal/raw_logging.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -38,6 +38,7 @@
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// This will print an almost standard log line like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+
#define ABSL_RAW_LOG(severity, ...) \
do { \
constexpr const char* absl_raw_logging_internal_basename = \
@@ -79,13 +80,13 @@
absl_raw_logging_internal_basename, __LINE__, message); \
} while (0)
-#define ABSL_INTERNAL_CHECK(condition, message) \
- do { \
- if (ABSL_PREDICT_FALSE(!(condition))) { \
+#define ABSL_INTERNAL_CHECK(condition, message) \
+ do { \
+ if (ABSL_PREDICT_FALSE(!(condition))) { \
std::string death_message = "Check " #condition " failed: "; \
death_message += std::string(message); \
- ABSL_INTERNAL_LOG(FATAL, death_message); \
- } \
+ ABSL_INTERNAL_LOG(FATAL, death_message); \
+ } \
} while (0)
#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h
index 1b6497a..d5b4b7f 100644
--- a/absl/base/internal/scheduling_mode.h
+++ b/absl/base/internal/scheduling_mode.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/scoped_set_env.cc b/absl/base/internal/scoped_set_env.cc
new file mode 100644
index 0000000..3ac3f68
--- /dev/null
+++ b/absl/base/internal/scoped_set_env.cc
@@ -0,0 +1,79 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/scoped_set_env.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <cstdlib>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace base_internal {
+
+namespace {
+
+#ifdef _WIN32
+const int kMaxEnvVarValueSize = 1024;
+#endif
+
+void SetEnvVar(const char* name, const char* value) {
+#ifdef _WIN32
+ SetEnvironmentVariableA(name, value);
+#else
+ if (value == nullptr) {
+ ::unsetenv(name);
+ } else {
+ ::setenv(name, value, 1);
+ }
+#endif
+}
+
+} // namespace
+
+ScopedSetEnv::ScopedSetEnv(const char* var_name, const char* new_value)
+ : var_name_(var_name), was_unset_(false) {
+#ifdef _WIN32
+ char buf[kMaxEnvVarValueSize];
+ auto get_res = GetEnvironmentVariableA(var_name_.c_str(), buf, sizeof(buf));
+ ABSL_INTERNAL_CHECK(get_res < sizeof(buf), "value exceeds buffer size");
+
+ if (get_res == 0) {
+ was_unset_ = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
+ } else {
+ old_value_.assign(buf, get_res);
+ }
+
+ SetEnvironmentVariableA(var_name_.c_str(), new_value);
+#else
+ const char* val = ::getenv(var_name_.c_str());
+ if (val == nullptr) {
+ was_unset_ = true;
+ } else {
+ old_value_ = val;
+ }
+#endif
+
+ SetEnvVar(var_name_.c_str(), new_value);
+}
+
+ScopedSetEnv::~ScopedSetEnv() {
+ SetEnvVar(var_name_.c_str(), was_unset_ ? nullptr : old_value_.c_str());
+}
+
+} // namespace base_internal
+} // namespace absl
diff --git a/absl/base/internal/scoped_set_env.h b/absl/base/internal/scoped_set_env.h
new file mode 100644
index 0000000..855b22f
--- /dev/null
+++ b/absl/base/internal/scoped_set_env.h
@@ -0,0 +1,41 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+
+#include <string>
+
+namespace absl {
+namespace base_internal {
+
+class ScopedSetEnv {
+ public:
+ ScopedSetEnv(const char* var_name, const char* new_value);
+ ~ScopedSetEnv();
+
+ private:
+ std::string var_name_;
+ std::string old_value_;
+
+ // True if the environment variable was initially not set.
+ bool was_unset_;
+};
+
+} // namespace base_internal
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
diff --git a/absl/base/internal/scoped_set_env_test.cc b/absl/base/internal/scoped_set_env_test.cc
new file mode 100644
index 0000000..5cbad24
--- /dev/null
+++ b/absl/base/internal/scoped_set_env_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/scoped_set_env.h"
+
+namespace {
+
+using absl::base_internal::ScopedSetEnv;
+
+std::string GetEnvVar(const char* name) {
+#ifdef _WIN32
+ char buf[1024];
+ auto get_res = GetEnvironmentVariableA(name, buf, sizeof(buf));
+ if (get_res >= sizeof(buf)) {
+ return "TOO_BIG";
+ }
+
+ if (get_res == 0) {
+ return "UNSET";
+ }
+
+ return std::string(buf, get_res);
+#else
+ const char* val = ::getenv(name);
+ if (val == nullptr) {
+ return "UNSET";
+ }
+
+ return val;
+#endif
+}
+
+TEST(ScopedSetEnvTest, SetNonExistingVarToString) {
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+}
+
+TEST(ScopedSetEnvTest, SetNonExistingVarToNull) {
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr);
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+}
+
+TEST(ScopedSetEnvTest, SetExistingVarToString) {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "new_value");
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "new_value");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+}
+
+TEST(ScopedSetEnvTest, SetExistingVarToNull) {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr);
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+}
+
+} // namespace
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 1b97efb..7354438 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -95,13 +95,9 @@
}
// Monitor the lock to see if its value changes within some time period
-// (adaptive_spin_count loop iterations). A timestamp indicating
-// when the thread initially started waiting for the lock is passed in via
-// the initial_wait_timestamp value. The total wait time in cycles for the
-// lock is returned in the wait_cycles parameter. The last value read
-// from the lock is returned from the method.
-uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
- uint32_t *wait_cycles) {
+// (adaptive_spin_count loop iterations). The last value read from the lock
+// is returned from the method.
+uint32_t SpinLock::SpinLoop() {
// We are already in the slow path of SpinLock, initialize the
// adaptive_spin_count here.
ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
@@ -115,22 +111,21 @@
do {
lock_value = lockword_.load(std::memory_order_relaxed);
} while ((lock_value & kSpinLockHeld) != 0 && --c > 0);
- uint32_t spin_loop_wait_cycles =
- EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now());
- *wait_cycles = spin_loop_wait_cycles;
-
- return TryLockInternal(lock_value, spin_loop_wait_cycles);
+ return lock_value;
}
void SpinLock::SlowLock() {
+ uint32_t lock_value = SpinLoop();
+ lock_value = TryLockInternal(lock_value, 0);
+ if ((lock_value & kSpinLockHeld) == 0) {
+ return;
+ }
// The lock was not obtained initially, so this thread needs to wait for
// it. Record the current timestamp in the local variable wait_start_time
// so the total wait time can be stored in the lockword once this thread
// obtains the lock.
int64_t wait_start_time = CycleClock::Now();
- uint32_t wait_cycles;
- uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles);
-
+ uint32_t wait_cycles = 0;
int lock_wait_call_count = 0;
while ((lock_value & kSpinLockHeld) != 0) {
// If the lock is currently held, but not marked as having a sleeper, mark
@@ -141,7 +136,7 @@
// owner to think it experienced contention.
if (lockword_.compare_exchange_strong(
lock_value, lock_value | kSpinLockSleeper,
- std::memory_order_acquire, std::memory_order_relaxed)) {
+ std::memory_order_relaxed, std::memory_order_relaxed)) {
// Successfully transitioned to kSpinLockSleeper. Pass
// kSpinLockSleeper to the SpinLockWait routine to properly indicate
// the last lock_value observed.
@@ -170,7 +165,9 @@
ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
// Spin again after returning from the wait routine to give this thread
// some chance of obtaining the lock.
- lock_value = SpinLoop(wait_start_time, &wait_cycles);
+ lock_value = SpinLoop();
+ wait_cycles = EncodeWaitCycles(wait_start_time, CycleClock::Now());
+ lock_value = TryLockInternal(lock_value, wait_cycles);
}
}
@@ -206,14 +203,20 @@
(wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
// Return a representation of the time spent waiting that can be stored in
- // the lock word's upper bits. bit_cast is required as Atomic32 is signed.
- const uint32_t clamped = static_cast<uint32_t>(
+ // the lock word's upper bits.
+ uint32_t clamped = static_cast<uint32_t>(
std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
- // bump up value if necessary to avoid returning kSpinLockSleeper.
- const uint32_t after_spinlock_sleeper =
- kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
- return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped;
+ if (clamped == 0) {
+ return kSpinLockSleeper; // Just wake waiters, but don't record contention.
+ }
+ // Bump up value if necessary to avoid returning kSpinLockSleeper.
+ const uint32_t kMinWaitTime =
+ kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
+ if (clamped == kSpinLockSleeper) {
+ return kMinWaitTime;
+ }
+ return clamped;
}
uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 212abc6..4a31639 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -101,8 +101,8 @@
inline void Unlock() UNLOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
- lockword_.store(lock_value & kSpinLockCooperative,
- std::memory_order_release);
+ lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
+ std::memory_order_release);
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
base_internal::SchedulingGuard::EnableRescheduling(true);
@@ -161,7 +161,7 @@
void InitLinkerInitializedAndCooperative();
void SlowLock() ABSL_ATTRIBUTE_COLD;
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
- uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles);
+ uint32_t SpinLoop();
inline bool TryLockImpl() {
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc
index 051c8cf..bc46894 100644
--- a/absl/base/internal/spinlock_akaros.inc
+++ b/absl/base/internal/spinlock_akaros.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc
new file mode 100644
index 0000000..0451c65
--- /dev/null
+++ b/absl/base/internal/spinlock_benchmark.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See also //absl/synchronization:mutex_benchmark for a comparison of SpinLock
+// and Mutex performance under varying levels of contention.
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+template <absl::base_internal::SchedulingMode scheduling_mode>
+static void BM_SpinLock(benchmark::State& state) {
+ // Ensure a ThreadIdentity is installed.
+ ABSL_INTERNAL_CHECK(
+ absl::synchronization_internal::GetOrCreateCurrentThreadIdentity() !=
+ nullptr,
+ "GetOrCreateCurrentThreadIdentity() failed");
+
+ static auto* spinlock = new absl::base_internal::SpinLock(scheduling_mode);
+ for (auto _ : state) {
+ absl::base_internal::SpinLockHolder holder(spinlock);
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_SpinLock,
+ absl::base_internal::SCHEDULE_KERNEL_ONLY)
+ ->UseRealTime()
+ ->Threads(1)
+ ->ThreadPerCpu();
+
+BENCHMARK_TEMPLATE(BM_SpinLock,
+ absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL)
+ ->UseRealTime()
+ ->Threads(1)
+ ->ThreadPerCpu();
+
+} // namespace
diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc
index 94c861d..28e29d1 100644
--- a/absl/base/internal/spinlock_linux.inc
+++ b/absl/base/internal/spinlock_linux.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -51,17 +51,12 @@
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode) {
- if (loop != 0) {
- int save_errno = errno;
- struct timespec tm;
- tm.tv_sec = 0;
- // Increase the delay; we expect (but do not rely on) explicit wakeups.
- // We don't rely on explicit wakeups because we intentionally allow for
- // a race on the kSpinLockSleeper bit.
- tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop);
- syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
- errno = save_errno;
- }
+ int save_errno = errno;
+ struct timespec tm;
+ tm.tv_sec = 0;
+ tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+ syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
+ errno = save_errno;
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc
index 0098c1c..f025b5f 100644
--- a/absl/base/internal/spinlock_posix.inc
+++ b/absl/base/internal/spinlock_posix.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc
index 0fde9c0..fac8a21 100644
--- a/absl/base/internal/spinlock_wait.cc
+++ b/absl/base/internal/spinlock_wait.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -38,14 +38,15 @@
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[],
base_internal::SchedulingMode scheduling_mode) {
- for (int loop = 0; ; loop++) {
+ int loop = 0;
+ for (;;) {
uint32_t v = w->load(std::memory_order_acquire);
int i;
for (i = 0; i != n && v != trans[i].from; i++) {
}
if (i == n) {
- SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition
- } else if (trans[i].to == v || // null transition
+ SpinLockDelay(w, v, ++loop, scheduling_mode); // no matching transition
+ } else if (trans[i].to == v || // null transition
w->compare_exchange_strong(v, trans[i].to,
std::memory_order_acquire,
std::memory_order_relaxed)) {
@@ -64,17 +65,14 @@
r = 0x5deece66dLL * r + 0xb; // numbers from nrand48()
delay_rand.store(r, std::memory_order_relaxed);
- r <<= 16; // 48-bit random number now in top 48-bits.
if (loop < 0 || loop > 32) { // limit loop to 0..32
loop = 32;
}
- // loop>>3 cannot exceed 4 because loop cannot exceed 32.
- // Select top 20..24 bits of lower 48 bits,
- // giving approximately 0ms to 16ms.
- // Mean is exponential in loop for first 32 iterations, then 8ms.
- // The futex path multiplies this by 16, since we expect explicit wakeups
- // almost always on that path.
- return static_cast<int>(r >> (44 - (loop >> 3)));
+ const int kMinDelay = 128 << 10; // 128us
+ // Double delay every 8 iterations, up to 16x (2ms).
+ int delay = kMinDelay << (loop / 8);
+ // Randomize in delay..2*delay range, for resulting 128us..4ms range.
+ return delay | ((delay - 1) & static_cast<int>(r));
}
} // namespace base_internal
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h
index 5c6cc7f..6642ce1 100644
--- a/absl/base/internal/spinlock_wait.h
+++ b/absl/base/internal/spinlock_wait.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc
index 32c8fc0..78654b5 100644
--- a/absl/base/internal/spinlock_win32.inc
+++ b/absl/base/internal/spinlock_win32.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index db41bac..4dd3add 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h
index 5bd1c50..b864a59 100644
--- a/absl/base/internal/sysinfo.h
+++ b/absl/base/internal/sysinfo.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
index e0d9aab..247f3d8 100644
--- a/absl/base/internal/sysinfo_test.cc
+++ b/absl/base/internal/sysinfo_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc
index cff9c1b..91273a6 100644
--- a/absl/base/internal/thread_identity.cc
+++ b/absl/base/internal/thread_identity.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
index a51722f..b34674a 100644
--- a/absl/base/internal/thread_identity.h
+++ b/absl/base/internal/thread_identity.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -42,9 +42,9 @@
class SpinLock;
struct ThreadIdentity;
-// Used by the implementation of base::Mutex and base::CondVar.
+// Used by the implementation of absl::Mutex and absl::CondVar.
struct PerThreadSynch {
- // The internal representation of base::Mutex and base::CondVar rely
+ // The internal representation of absl::Mutex and absl::CondVar rely
// on the alignment of PerThreadSynch. Both store the address of the
// PerThreadSynch in the high-order bits of their internal state,
// which means the low kLowZeroBits of the address of PerThreadSynch
@@ -237,4 +237,5 @@
} // namespace base_internal
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc
index 242522b..0ae10f2 100644
--- a/absl/base/internal/thread_identity_benchmark.cc
+++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
index ecb8af6..13bfbe3 100644
--- a/absl/base/internal/thread_identity_test.cc
+++ b/absl/base/internal/thread_identity_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc
index 46dc573..8e928b8 100644
--- a/absl/base/internal/throw_delegate.cc
+++ b/absl/base/internal/throw_delegate.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -30,8 +30,8 @@
#ifdef ABSL_HAVE_EXCEPTIONS
throw error;
#else
- ABSL_RAW_LOG(ERROR, "%s", error.what());
- abort();
+ ABSL_RAW_LOG(FATAL, "%s", error.what());
+ std::abort();
#endif
}
} // namespace
diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h
index 70e2d77..03c700b 100644
--- a/absl/base/internal/throw_delegate.h
+++ b/absl/base/internal/throw_delegate.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h
index 6bb4fae..2a51060 100644
--- a/absl/base/internal/tsan_mutex_interface.h
+++ b/absl/base/internal/tsan_mutex_interface.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
index f9df3b7..2d66737 100644
--- a/absl/base/internal/unaligned_access.h
+++ b/absl/base/internal/unaligned_access.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index a12d68b..593762b 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
index 049f1ca..58950cc 100644
--- a/absl/base/internal/unscaledcycleclock.h
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -83,6 +83,7 @@
defined(_M_IX86) || defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif
+
namespace absl {
namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime;
@@ -114,6 +115,7 @@
} // namespace base_internal
} // namespace absl
+
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
index 466bf11..691f553 100644
--- a/absl/base/invoke_test.cc
+++ b/absl/base/invoke_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h
index 5770d36..b19a7ff 100644
--- a/absl/base/log_severity.h
+++ b/absl/base/log_severity.h
@@ -4,14 +4,13 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/macros.h b/absl/base/macros.h
index ca3d5ed..5b43d7c 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,7 +24,6 @@
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
-//
#ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_
@@ -199,4 +198,14 @@
: [] { assert(false && #expr); }()) // NOLINT
#endif
+#ifdef ABSL_HAVE_EXCEPTIONS
+#define ABSL_INTERNAL_TRY try
+#define ABSL_INTERNAL_CATCH_ANY catch (...)
+#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
+#else // ABSL_HAVE_EXCEPTIONS
+#define ABSL_INTERNAL_TRY if (true)
+#define ABSL_INTERNAL_CATCH_ANY else if (false)
+#define ABSL_INTERNAL_RETHROW do {} while (false)
+#endif // ABSL_HAVE_EXCEPTIONS
+
#endif // ABSL_BASE_MACROS_H_
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 2fddfc8..6974f1f 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -111,9 +111,9 @@
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
//
-// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to
-// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is
-// not known to work, the macro expands to nothing.
+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
+// or `__declspec` attribute. For compilers where this is not known to work,
+// the macro expands to nothing.
//
// No further guarantees are made here. The result of applying the macro
// to variables and types is always implementation-defined.
@@ -122,6 +122,14 @@
// of causing bugs that are difficult to diagnose, crash, etc. It does not
// of itself guarantee that objects are aligned to a cache line.
//
+// NOTE: Some compilers are picky about the locations of annotations such as
+// this attribute, so prefer to put it at the beginning of your declaration.
+// For example,
+//
+// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
+//
+// class ABSL_CACHELINE_ALIGNED Bar { ...
+//
// Recommendations:
//
// 1) Consult compiler documentation; this comment is not kept in sync as
@@ -131,8 +139,10 @@
// 3) Prefer applying this attribute to individual variables. Avoid
// applying it to types. This tends to localize the effect.
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
-
-#else // not GCC
+#elif defined(_MSC_VER)
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
+#else
#define ABSL_CACHELINE_SIZE 64
#define ABSL_CACHELINE_ALIGNED
#endif
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
index 0a07fc0..699fb1a 100644
--- a/absl/base/policy_checks.h
+++ b/absl/base/policy_checks.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/port.h b/absl/base/port.h
index 1c67257..6c28068 100644
--- a/absl/base/port.h
+++ b/absl/base/port.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc
index b21cf65..3d30bd3 100644
--- a/absl/base/raw_logging_test.cc
+++ b/absl/base/raw_logging_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
index 1b50884..e62b2ea 100644
--- a/absl/base/spinlock_test_common.cc
+++ b/absl/base/spinlock_test_common.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -54,6 +54,7 @@
static constexpr int kArrayLength = 10;
static uint32_t values[kArrayLength];
+
static SpinLock static_spinlock(base_internal::kLinkerInitialized);
static SpinLock static_cooperative_spinlock(
base_internal::kLinkerInitialized,
@@ -155,7 +156,8 @@
// Test corner cases
int64_t start_time = time_distribution(generator);
- EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time));
+ EXPECT_EQ(kSpinLockSleeper,
+ SpinLockTest::EncodeWaitCycles(start_time, start_time));
EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0));
EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask));
EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask,
@@ -188,6 +190,7 @@
SpinLockTest::DecodeWaitCycles(before_max_value);
EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
}
+
TEST(SpinLockWithThreads, StaticSpinLock) {
ThreadedTest(&static_spinlock);
}
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index fbb2797..0b2c306 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,6 @@
// code. The annotations can also help program analysis tools to identify
// potential thread safety issues.
//
-//
// These annotations are implemented using compiler attributes. Using the macros
// defined here instead of raw attributes allow for portability and future
// compatibility.
@@ -34,6 +33,7 @@
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+
#if defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
@@ -108,13 +108,23 @@
// The mutex is expected to be held both on entry to, and exit from, the
// function.
//
+// An exclusive lock allows read-write access to the guarded data member(s), and
+// only one thread can acquire a lock exclusively at any one time. A shared lock
+// allows read-only access, and any number of threads can acquire a shared lock
+// concurrently.
+//
+// Generally, non-const methods should be annotated with
+// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// SHARED_LOCKS_REQUIRED.
+//
// Example:
//
// Mutex mu1, mu2;
// int a GUARDED_BY(mu1);
// int b GUARDED_BY(mu2);
//
-// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... };
+// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
diff --git a/absl/base/throw_delegate_test.cc b/absl/base/throw_delegate_test.cc
index 0f15df0..a74dd3c 100644
--- a/absl/base/throw_delegate_test.cc
+++ b/absl/base/throw_delegate_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/compiler_config_setting.bzl b/absl/compiler_config_setting.bzl
index b77c4f5..6696229 100644
--- a/absl/compiler_config_setting.bzl
+++ b/absl/compiler_config_setting.bzl
@@ -5,35 +5,34 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
"""Creates config_setting that allows selecting based on 'compiler' value."""
def create_llvm_config(name, visibility):
- # The "do_not_use_tools_cpp_compiler_present" attribute exists to
- # distinguish between older versions of Bazel that do not support
- # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
- # In the future, the only way to select on the compiler will be through
- # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
- # be removed.
- if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
- native.config_setting(
- name = name,
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "llvm",
- },
- visibility = visibility,
- )
- else:
- native.config_setting(
- name = name,
- values = {"compiler": "llvm"},
- visibility = visibility,
- )
+ # The "do_not_use_tools_cpp_compiler_present" attribute exists to
+ # distinguish between older versions of Bazel that do not support
+ # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
+ # In the future, the only way to select on the compiler will be through
+ # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
+ # be removed.
+ if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
+ native.config_setting(
+ name = name,
+ flag_values = {
+ "@bazel_tools//tools/cpp:compiler": "llvm",
+ },
+ visibility = visibility,
+ )
+ else:
+ native.config_setting(
+ name = name,
+ values = {"compiler": "llvm"},
+ visibility = visibility,
+ )
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index f2210e3..cd914ba 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,11 +15,11 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
- "ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
@@ -41,6 +41,8 @@
copts = ABSL_TEST_COPTS,
deps = [
":compressed_tuple",
+ "//absl/memory",
+ "//absl/utility",
"@com_google_googletest//:gtest_main",
],
)
@@ -110,10 +112,20 @@
)
cc_library(
+ name = "inlined_vector_internal",
+ hdrs = ["internal/inlined_vector.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_library(
name = "inlined_vector",
hdrs = ["inlined_vector.h"],
copts = ABSL_DEFAULT_COPTS,
deps = [
+ ":inlined_vector_internal",
"//absl/algorithm",
"//absl/base:core_headers",
"//absl/base:throw_delegate",
@@ -121,12 +133,21 @@
],
)
+cc_library(
+ name = "counting_allocator",
+ testonly = 1,
+ hdrs = ["internal/counting_allocator.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+)
+
cc_test(
name = "inlined_vector_test",
srcs = ["inlined_vector_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [
+ ":counting_allocator",
":inlined_vector",
":test_instance_tracker",
"//absl/base",
@@ -144,6 +165,7 @@
srcs = ["inlined_vector_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
+ ":counting_allocator",
":inlined_vector",
":test_instance_tracker",
"//absl/base",
@@ -212,6 +234,7 @@
":container_memory",
":hash_function_defaults",
":raw_hash_map",
+ "//absl/algorithm:container",
"//absl/memory",
],
)
@@ -219,13 +242,14 @@
cc_test(
name = "flat_hash_map_test",
srcs = ["flat_hash_map_test.cc"],
- copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"],
+ copts = ABSL_TEST_COPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":flat_hash_map",
":hash_generator_testing",
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"//absl/types:any",
"@com_google_googletest//:gtest_main",
@@ -240,6 +264,7 @@
":container_memory",
":hash_function_defaults",
":raw_hash_set",
+ "//absl/algorithm:container",
"//absl/base:core_headers",
"//absl/memory",
],
@@ -255,6 +280,7 @@
":hash_generator_testing",
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"//absl/memory",
"//absl/strings",
@@ -271,6 +297,7 @@
":hash_function_defaults",
":node_hash_policy",
":raw_hash_map",
+ "//absl/algorithm:container",
"//absl/memory",
],
)
@@ -278,7 +305,7 @@
cc_test(
name = "node_hash_map_test",
srcs = ["node_hash_map_test.cc"],
- copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"],
+ copts = ABSL_TEST_COPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":hash_generator_testing",
@@ -286,6 +313,7 @@
":tracked",
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -296,10 +324,10 @@
hdrs = ["node_hash_set.h"],
copts = ABSL_DEFAULT_COPTS,
deps = [
- ":container_memory",
":hash_function_defaults",
":node_hash_policy",
":raw_hash_set",
+ "//absl/algorithm:container",
"//absl/memory",
],
)
@@ -310,10 +338,10 @@
copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
tags = NOTEST_TAGS_NONMOBILE,
deps = [
- ":hash_generator_testing",
":node_hash_set",
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -432,6 +460,39 @@
)
cc_library(
+ name = "hashtablez_sampler",
+ srcs = [
+ "internal/hashtablez_sampler.cc",
+ "internal/hashtablez_sampler_force_weak_definition.cc",
+ ],
+ hdrs = ["internal/hashtablez_sampler.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":have_sse",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/debugging:stacktrace",
+ "//absl/memory",
+ "//absl/synchronization",
+ "//absl/utility",
+ ],
+)
+
+cc_test(
+ name = "hashtablez_sampler_test",
+ srcs = ["internal/hashtablez_sampler_test.cc"],
+ deps = [
+ ":hashtablez_sampler",
+ ":have_sse",
+ "//absl/base:core_headers",
+ "//absl/synchronization",
+ "//absl/synchronization:thread_pool",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
name = "node_hash_policy",
hdrs = ["internal/node_hash_policy.h"],
copts = ABSL_DEFAULT_COPTS,
@@ -459,15 +520,35 @@
)
cc_library(
+ name = "have_sse",
+ hdrs = ["internal/have_sse.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+)
+
+cc_library(
+ name = "common",
+ hdrs = ["internal/common.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ "//absl/types:optional",
+ ],
+)
+
+cc_library(
name = "raw_hash_set",
srcs = ["internal/raw_hash_set.cc"],
hdrs = ["internal/raw_hash_set.h"],
copts = ABSL_DEFAULT_COPTS,
deps = [
+ ":common",
":compressed_tuple",
":container_memory",
":hash_policy_traits",
":hashtable_debug_hooks",
+ ":hashtablez_sampler",
+ ":have_sse",
":layout",
"//absl/base:bits",
"//absl/base:config",
@@ -475,7 +556,6 @@
"//absl/base:endian",
"//absl/memory",
"//absl/meta:type_traits",
- "//absl/types:optional",
"//absl/utility",
],
)
@@ -592,6 +672,29 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "unordered_set_members_test",
+ testonly = 1,
+ hdrs = ["internal/unordered_set_members_test.h"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "unordered_map_members_test",
+ testonly = 1,
+ hdrs = ["internal/unordered_map_members_test.h"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ "//absl/meta:type_traits",
"@com_google_googletest//:gtest",
],
)
@@ -628,6 +731,7 @@
deps = [
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -641,6 +745,7 @@
deps = [
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"@com_google_googletest//:gtest_main",
],
diff --git a/absl/container/BUILD.gn b/absl/container/BUILD.gn
index a2fbd54..3b8ece7 100644
--- a/absl/container/BUILD.gn
+++ b/absl/container/BUILD.gn
@@ -49,6 +49,21 @@
]
}
+source_set("inlined_vector_internal") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/inlined_vector.h",
+ ]
+ deps = [
+ "../meta:type_traits",
+ ]
+}
+
source_set("inlined_vector") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
@@ -60,6 +75,7 @@
"inlined_vector.h",
]
deps = [
+ ":inlined_vector_internal",
"../algorithm",
"../base:core_headers",
"../base:throw_delegate",
@@ -67,6 +83,21 @@
]
}
+source_set("counting_allocator") {
+ testonly = true
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/counting_allocator.h",
+ ]
+ visibility = []
+ visibility += [ ":*" ]
+}
+
source_set("test_instance_tracker") {
testonly = true
configs -= [ "//build/config/compiler:chromium_code" ]
@@ -99,6 +130,7 @@
":container_memory",
":hash_function_defaults",
":raw_hash_map",
+ "../algorithm:container",
"../memory",
]
}
@@ -117,6 +149,7 @@
":container_memory",
":hash_function_defaults",
":raw_hash_set",
+ "../algorithm:container",
"../base:core_headers",
"../memory",
]
@@ -137,6 +170,7 @@
":hash_function_defaults",
":node_hash_policy",
":raw_hash_map",
+ "../algorithm:container",
"../memory",
]
}
@@ -156,6 +190,7 @@
":hash_function_defaults",
":node_hash_policy",
":raw_hash_set",
+ "../algorithm:container",
"../memory",
]
}
@@ -273,6 +308,31 @@
]
}
+source_set("hashtablez_sampler") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/hashtablez_sampler.h",
+ ]
+ sources = [
+ "internal/hashtablez_sampler.cc",
+ "internal/hashtablez_sampler_force_weak_definition.cc",
+ ]
+ deps = [
+ ":have_sse",
+ "../base",
+ "../base:core_headers",
+ "../debugging:stacktrace",
+ "../memory",
+ "../synchronization",
+ "../utility",
+ ]
+}
+
source_set("node_hash_policy") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
@@ -301,6 +361,36 @@
]
}
+source_set("have_sse") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/have_sse.h",
+ ]
+ visibility = []
+ visibility += [ ":*" ]
+}
+
+source_set("common") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/common.h",
+ ]
+ deps = [
+ "../meta:type_traits",
+ "../types:optional",
+ ]
+}
+
source_set("raw_hash_set") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
@@ -315,10 +405,13 @@
"internal/raw_hash_set.h",
]
deps = [
+ ":common",
":compressed_tuple",
":container_memory",
":hash_policy_traits",
":hashtable_debug_hooks",
+ ":hashtablez_sampler",
+ ":have_sse",
":layout",
"../base:bits",
"../base:config",
@@ -326,7 +419,6 @@
"../base:endian",
"../memory",
"../meta:type_traits",
- "../types:optional",
"../utility",
]
}
@@ -431,6 +523,41 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
+ "../meta:type_traits",
+ "//testing/gtest",
+ ]
+}
+
+source_set("unordered_set_members_test") {
+ testonly = true
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/unordered_set_members_test.h",
+ ]
+ deps = [
+ "../meta:type_traits",
+ "//testing/gtest",
+ ]
+}
+
+source_set("unordered_map_members_test") {
+ testonly = true
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ public = [
+ "internal/unordered_map_members_test.h",
+ ]
+ deps = [
+ "../meta:type_traits",
"//testing/gtest",
]
}
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 9e40690..292fea2 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,163 +14,772 @@
# limitations under the License.
#
-
-list(APPEND CONTAINER_PUBLIC_HEADERS
- "fixed_array.h"
- "flat_hash_map.h"
- "flat_hash_set.h"
- "inlined_vector.h"
- "node_hash_map.h"
- "node_hash_set.h"
-)
-
-
-list(APPEND CONTAINER_INTERNAL_HEADERS
- "internal/compressed_tuple.h"
- "internal/container_memory.h"
- "internal/hash_function_defaults.h"
- "internal/hash_generator_testing.h"
- "internal/hash_policy_testing.h"
- "internal/hash_policy_traits.h"
- "internal/hashtable_debug.h"
- "internal/layout.h"
- "internal/node_hash_policy.h"
- "internal/raw_hash_map.h"
- "internal/raw_hash_set.h"
- "internal/test_instance_tracker.h"
- "internal/tracked.h"
- "internal/unordered_map_constructor_test.h"
- "internal/unordered_map_lookup_test.h"
- "internal/unordered_map_modifiers_test.h"
- "internal/unordered_set_constructor_test.h"
- "internal/unordered_set_lookup_test.h"
- "internal/unordered_set_modifiers_test.h"
-)
-
-
-absl_library(
- TARGET
- absl_container
- SOURCES
- "internal/raw_hash_set.cc"
- EXPORT_NAME
+# This is deprecated and will be removed in the future. It also doesn't do
+# anything anyways. Prefer to use the library associated with the API you are
+# using.
+absl_cc_library(
+ NAME
container
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-list(APPEND TEST_INSTANCE_TRACKER_LIB_SRC
- "internal/test_instance_tracker.cc"
- ${CONTAINER_PUBLIC_HEADERS}
- ${CONTAINER_INTERNAL_HEADERS}
+absl_cc_library(
+ NAME
+ compressed_tuple
+ HDRS
+ "internal/compressed_tuple.h"
+ DEPS
+ absl::utility
+ PUBLIC
)
-
-absl_library(
- TARGET
- test_instance_tracker_lib
- SOURCES
- ${TEST_INSTANCE_TRACKER_LIB_SRC}
- PUBLIC_LIBRARIES
- absl::container
+absl_cc_test(
+ NAME
+ compressed_tuple_test
+ SRCS
+ "internal/compressed_tuple_test.cc"
+ DEPS
+ absl::compressed_tuple
+ absl::memory
+ absl::utility
+ gmock_main
)
+absl_cc_library(
+ NAME
+ fixed_array
+ HDRS
+ "fixed_array.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::compressed_tuple
+ absl::algorithm
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::throw_delegate
+ absl::memory
+ PUBLIC
+)
-
-# test fixed_array_test
-set(FIXED_ARRAY_TEST_SRC "fixed_array_test.cc")
-set(FIXED_ARRAY_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
fixed_array_test
- SOURCES
- ${FIXED_ARRAY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "fixed_array_test.cc"
+ COPTS
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::fixed_array
+ absl::exception_testing
+ absl::hash_testing
+ absl::memory
+ gmock_main
)
-
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
fixed_array_test_noexceptions
- SOURCES
- ${FIXED_ARRAY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "fixed_array_test.cc"
+ DEPS
+ absl::fixed_array
+ absl::exception_testing
+ absl::hash_testing
+ absl::memory
+ gmock_main
)
-
-# test fixed_array_exception_safety_test
-set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc")
-set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::container
- absl_base_internal_exception_safety_testing
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
fixed_array_exception_safety_test
- SOURCES
- ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "fixed_array_exception_safety_test.cc"
+ COPTS
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::fixed_array
+ absl::exception_safety_testing
+ gmock_main
)
+absl_cc_library(
+ NAME
+ inlined_vector_internal
+ HDRS
+ "internal/inlined_vector.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::type_traits
+ PUBLIC
+)
-# test inlined_vector_test
-set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc")
-set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
+absl_cc_library(
+ NAME
+ inlined_vector
+ HDRS
+ "inlined_vector.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::algorithm
+ absl::core_headers
+ absl::throw_delegate
+ absl::memory
+ PUBLIC
+)
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ counting_allocator
+ HDRS
+ "internal/counting_allocator.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_test(
+ NAME
inlined_vector_test
- SOURCES
- ${INLINED_VECTOR_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "inlined_vector_test.cc"
+ COPTS
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::counting_allocator
+ absl::inlined_vector
+ absl::test_instance_tracker
+ absl::base
+ absl::core_headers
+ absl::exception_testing
+ absl::hash_testing
+ absl::memory
+ absl::strings
+ gmock_main
)
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
inlined_vector_test_noexceptions
- SOURCES
- ${INLINED_VECTOR_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
- ${ABSL_NOEXCEPTION_CXXFLAGS}
+ SRCS
+ "inlined_vector_test.cc"
+ DEPS
+ absl::inlined_vector
+ absl::test_instance_tracker
+ absl::base
+ absl::core_headers
+ absl::exception_testing
+ absl::hash_testing
+ absl::memory
+ absl::strings
+ gmock_main
)
+absl_cc_library(
+ NAME
+ test_instance_tracker
+ HDRS
+ "internal/test_instance_tracker.h"
+ SRCS
+ "internal/test_instance_tracker.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ TESTONLY
+)
-# test test_instance_tracker_test
-set(TEST_INSTANCE_TRACKER_TEST_SRC "internal/test_instance_tracker_test.cc")
-set(TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
-
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
test_instance_tracker_test
- SOURCES
- ${TEST_INSTANCE_TRACKER_TEST_SRC}
- PUBLIC_LIBRARIES
- ${TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/test_instance_tracker_test.cc"
+ DEPS
+ absl::test_instance_tracker
+ gmock_main
)
+absl_cc_library(
+ NAME
+ flat_hash_map
+ HDRS
+ "flat_hash_map.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::container_memory
+ absl::hash_function_defaults
+ absl::raw_hash_map
+ absl::algorithm_container
+ absl::memory
+ PUBLIC
+)
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
+ flat_hash_map_test
+ SRCS
+ "flat_hash_map_test.cc"
+ DEPS
+ absl::flat_hash_map
+ absl::hash_generator_testing
+ absl::unordered_map_constructor_test
+ absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
+ absl::unordered_map_modifiers_test
+ absl::any
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ flat_hash_set
+ HDRS
+ "flat_hash_set.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::container_memory
+ absl::hash_function_defaults
+ absl::raw_hash_set
+ absl::algorithm_container
+ absl::core_headers
+ absl::memory
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ flat_hash_set_test
+ SRCS
+ "flat_hash_set_test.cc"
+ COPTS
+ "-DUNORDERED_SET_CXX17"
+ DEPS
+ absl::flat_hash_set
+ absl::hash_generator_testing
+ absl::unordered_set_constructor_test
+ absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
+ absl::unordered_set_modifiers_test
+ absl::memory
+ absl::strings
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ node_hash_map
+ HDRS
+ "node_hash_map.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::container_memory
+ absl::hash_function_defaults
+ absl::node_hash_policy
+ absl::raw_hash_map
+ absl::algorithm_container
+ absl::memory
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ node_hash_map_test
+ SRCS
+ "node_hash_map_test.cc"
+ DEPS
+ absl::hash_generator_testing
+ absl::node_hash_map
+ absl::tracked
+ absl::unordered_map_constructor_test
+ absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
+ absl::unordered_map_modifiers_test
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ node_hash_set
+ HDRS
+ "node_hash_set.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::hash_function_defaults
+ absl::node_hash_policy
+ absl::raw_hash_set
+ absl::algorithm_container
+ absl::memory
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ node_hash_set_test
+ SRCS
+ "node_hash_set_test.cc"
+ COPTS
+ "-DUNORDERED_SET_CXX17"
+ DEPS
+ absl::hash_generator_testing
+ absl::node_hash_set
+ absl::unordered_set_constructor_test
+ absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
+ absl::unordered_set_modifiers_test
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ container_memory
+ HDRS
+ "internal/container_memory.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::memory
+ absl::utility
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ container_memory_test
+ SRCS
+ "internal/container_memory_test.cc"
+ DEPS
+ absl::container_memory
+ absl::strings
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ hash_function_defaults
+ HDRS
+ "internal/hash_function_defaults.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::hash
+ absl::strings
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ hash_function_defaults_test
+ SRCS
+ "internal/hash_function_defaults_test.cc"
+ DEPS
+ absl::hash_function_defaults
+ absl::hash
+ absl::strings
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ hash_generator_testing
+ HDRS
+ "internal/hash_generator_testing.h"
+ SRCS
+ "internal/hash_generator_testing.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_policy_testing
+ absl::meta
+ absl::strings
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ hash_policy_testing
+ HDRS
+ "internal/hash_policy_testing.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash
+ absl::strings
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ hash_policy_testing_test
+ SRCS
+ "internal/hash_policy_testing_test.cc"
+ DEPS
+ absl::hash_policy_testing
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ hash_policy_traits
+ HDRS
+ "internal/hash_policy_traits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::meta
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ hash_policy_traits_test
+ SRCS
+ "internal/hash_policy_traits_test.cc"
+ DEPS
+ absl::hash_policy_traits
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ hashtablez_sampler
+ HDRS
+ "internal/hashtablez_sampler.h"
+ SRCS
+ "internal/hashtablez_sampler.cc"
+ "internal/hashtablez_sampler_force_weak_definition.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::have_sse
+ absl::synchronization
+)
+
+absl_cc_test(
+ NAME
+ hashtablez_sampler_test
+ SRCS
+ "internal/hashtablez_sampler_test.cc"
+ DEPS
+ absl::hashtablez_sampler
+ absl::have_sse
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ hashtable_debug
+ HDRS
+ "internal/hashtable_debug.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::hashtable_debug_hooks
+)
+
+absl_cc_library(
+ NAME
+ hashtable_debug_hooks
+ HDRS
+ "internal/hashtable_debug_hooks.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ have_sse
+ HDRS
+ "internal/have_sse.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ node_hash_policy
+ HDRS
+ "internal/node_hash_policy.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ node_hash_policy_test
+ SRCS
+ "internal/node_hash_policy_test.cc"
+ DEPS
+ absl::hash_policy_traits
+ absl::node_hash_policy
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ raw_hash_map
+ HDRS
+ "internal/raw_hash_map.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::container_memory
+ absl::raw_hash_set
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ container_common
+ HDRS
+ "internal/commom.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::type_traits
+)
+
+absl_cc_library(
+ NAME
+ raw_hash_set
+ HDRS
+ "internal/raw_hash_set.h"
+ SRCS
+ "internal/raw_hash_set.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bits
+ absl::compressed_tuple
+ absl::config
+ absl::container_common
+ absl::container_memory
+ absl::core_headers
+ absl::endian
+ absl::hash_policy_traits
+ absl::hashtable_debug_hooks
+ absl::have_sse
+ absl::layout
+ absl::memory
+ absl::meta
+ absl::optional
+ absl::utility
+ absl::hashtablez_sampler
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
raw_hash_set_test
- SOURCES
+ SRCS
"internal/raw_hash_set_test.cc"
- PUBLIC_LIBRARIES
- absl::base absl::hash absl_throw_delegate test_instance_tracker_lib
+ DEPS
+ absl::container_memory
+ absl::hash_function_defaults
+ absl::hash_policy_testing
+ absl::hashtable_debug
+ absl::raw_hash_set
+ absl::base
+ absl::core_headers
+ absl::strings
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ raw_hash_set_allocator_test
+ SRCS
+ "internal/raw_hash_set_allocator_test.cc"
+ DEPS
+ absl::raw_hash_set
+ absl::tracked
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ layout
+ HDRS
+ "internal/layout.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::meta
+ absl::strings
+ absl::span
+ absl::utility
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ layout_test
+ SRCS
+ "internal/layout_test.cc"
+ DEPS
+ absl::layout
+ absl::base
+ absl::core_headers
+ absl::span
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ tracked
+ HDRS
+ "internal/tracked.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_map_constructor_test
+ HDRS
+ "internal/unordered_map_constructor_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_map_lookup_test
+ HDRS
+ "internal/unordered_map_lookup_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_map_members_test
+ HDRS
+ "internal/unordered_map_members_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_map_modifiers_test
+ HDRS
+ "internal/unordered_map_modifiers_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_set_constructor_test
+ HDRS
+ "internal/unordered_set_constructor_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_set_lookup_test
+ HDRS
+ "internal/unordered_set_lookup_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_set_members_test
+ HDRS
+ "internal/unordered_set_members_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ unordered_set_modifiers_test
+ HDRS
+ "internal/unordered_set_modifiers_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash_generator_testing
+ absl::hash_policy_testing
+ gmock
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ unordered_set_test
+ SRCS
+ "internal/unordered_set_test.cc"
+ DEPS
+ absl::unordered_set_constructor_test
+ absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
+ absl::unordered_set_modifiers_test
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ unordered_map_test
+ SRCS
+ "internal/unordered_map_test.cc"
+ DEPS
+ absl::unordered_map_constructor_test
+ absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
+ absl::unordered_map_modifiers_test
+ gmock_main
)
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index 6d9fa5f..60da048 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -188,7 +188,7 @@
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
// over the number of bytes taken by T.
constexpr size_type max_size() const {
- return std::numeric_limits<difference_type>::max() / sizeof(value_type);
+ return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
}
// FixedArray::empty()
@@ -515,4 +515,5 @@
static_cast<void>(n); // Mark used when not in asan mode
}
} // namespace absl
+
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc
index b4f0cf2..ff56f46 100644
--- a/absl/container/fixed_array_benchmark.cc
+++ b/absl/container/fixed_array_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc
index da63dbf..826eca6 100644
--- a/absl/container/fixed_array_exception_safety_test.cc
+++ b/absl/container/fixed_array_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index 205ff41..a4f2498 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -150,7 +150,7 @@
}
{
- // Arrays of > default size should be on the stack
+ // Arrays of > default size should be on the heap
absl::FixedArray<int, 100> array(101);
EXPECT_FALSE(IsOnStack(array));
}
@@ -365,7 +365,8 @@
TEST(IteratorConstructorTest, NonPod) {
char const* kInput[] =
{ "red", "orange", "yellow", "green", "blue", "indigo", "violet" };
- absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ absl::FixedArray<std::string> const fixed(kInput,
+ kInput + ABSL_ARRAYSIZE(kInput));
ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
ASSERT_EQ(kInput[i], fixed[i]);
@@ -869,4 +870,21 @@
}
#endif // ADDRESS_SANITIZER
+TEST(FixedArrayTest, AbslHashValueWorks) {
+ using V = absl::FixedArray<int>;
+ std::vector<V> cases;
+
+ // Generate a variety of vectors some of these are small enough for the inline
+ // space but are stored out of line.
+ for (int i = 0; i < 10; ++i) {
+ V v(i);
+ for (int j = 0; j < i; ++j) {
+ v[j] = j;
+ }
+ cases.push_back(v);
+ }
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
} // namespace
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index e5570d1..00cc4dc 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -35,6 +35,7 @@
#include <type_traits>
#include <utility>
+#include "absl/algorithm/container.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
@@ -69,7 +70,7 @@
// By default, `flat_hash_map` uses the `absl::Hash` hashing framework.
// All fundamental and Abseil types that support the `absl::Hash` framework have
// a compatible equality operator for comparing insertions into `flat_hash_map`.
-// If your type is not yet supported by the `asbl::Hash` framework, see
+// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
@@ -109,6 +110,46 @@
using Base = typename flat_hash_map::raw_hash_map;
public:
+ // Constructors and Assignment Operators
+ //
+ // A flat_hash_map supports the same overload set as `std::unordered_map`
+ // for construction and assignment:
+ //
+ // * Default constructor
+ //
+ // // No allocation for the table's elements is made.
+ // absl::flat_hash_map<int, std::string> map1;
+ //
+ // * Initializer List constructor
+ //
+ // absl::flat_hash_map<int, std::string> map2 =
+ // {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+ //
+ // * Copy constructor
+ //
+ // absl::flat_hash_map<int, std::string> map3(map2);
+ //
+ // * Copy assignment operator
+ //
+ // // Hash functor and Comparator are copied as well
+ // absl::flat_hash_map<int, std::string> map4;
+ // map4 = map3;
+ //
+ // * Move constructor
+ //
+ // // Move is guaranteed efficient
+ // absl::flat_hash_map<int, std::string> map5(std::move(map4));
+ //
+ // * Move assignment operator
+ //
+ // // May be efficient if allocators are compatible
+ // absl::flat_hash_map<int, std::string> map6;
+ // map6 = std::move(map5);
+ //
+ // * Range constructor
+ //
+ // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+ // absl::flat_hash_map<int, std::string> map7(v.begin(), v.end());
flat_hash_map() {}
using Base::Base;
@@ -178,8 +219,12 @@
// Erases the element at `position` of the `flat_hash_map`, returning
// `void`.
//
- // NOTE: this return behavior is different than that of STL containers in
- // general and `std::unordered_map` in particular.
+ // NOTE: returning `void` in this case is different than that of STL
+ // containers in general and `std::unordered_map` in particular (which
+ // return an iterator to the element following the erased element). If that
+ // iterator is needed, simply post increment the iterator:
+ //
+ // map.erase(it++);
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -486,25 +531,26 @@
template <class K, class V>
struct FlatHashMapPolicy {
- using slot_type = container_internal::slot_type<K, V>;
+ using slot_policy = container_internal::map_slot_policy<K, V>;
+ using slot_type = typename slot_policy::slot_type;
using key_type = K;
using mapped_type = V;
using init_type = std::pair</*non const*/ key_type, mapped_type>;
template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
- slot_type::construct(alloc, slot, std::forward<Args>(args)...);
+ slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
}
template <class Allocator>
static void destroy(Allocator* alloc, slot_type* slot) {
- slot_type::destroy(alloc, slot);
+ slot_policy::destroy(alloc, slot);
}
template <class Allocator>
static void transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) {
- slot_type::transfer(alloc, new_slot, old_slot);
+ slot_policy::transfer(alloc, new_slot, old_slot);
}
template <class F, class... Args>
@@ -524,5 +570,16 @@
};
} // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+ absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+} // namespace container_algorithm_internal
+
} // namespace absl
+
#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index 10a781f..ebcb560 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,6 +17,7 @@
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
#include "absl/types/any.h"
@@ -30,19 +31,20 @@
using ::testing::UnorderedElementsAre;
template <class K, class V>
-using Map =
- flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, Alloc<>>;
+using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<std::pair<const K, V>>>;
static_assert(!std::is_standard_layout<NonStandardLayout>(), "");
using MapTypes =
- ::testing::Types<Map<int, int>, Map<std::string, int>, Map<Enum, std::string>,
- Map<EnumClass, int>, Map<int, NonStandardLayout>,
- Map<NonStandardLayout, int>>;
+ ::testing::Types<Map<int, int>, Map<std::string, int>,
+ Map<Enum, std::string>, Map<EnumClass, int>,
+ Map<int, NonStandardLayout>, Map<NonStandardLayout, int>>;
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ModifiersTest, MapTypes);
TEST(FlatHashMap, StandardLayout) {
struct Int {
@@ -94,7 +96,7 @@
}
}
-// Demonstration of the "Lazy Key" pattern. This uses heterogenous insert to
+// Demonstration of the "Lazy Key" pattern. This uses heterogeneous insert to
// avoid creating expensive key elements when the item is already present in the
// map.
struct LazyInt {
@@ -139,6 +141,7 @@
int conversions = 0;
int hashes = 0;
flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes});
+ m.reserve(3);
m[LazyInt(1, &conversions)] = 1;
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1)));
@@ -203,7 +206,9 @@
m.insert(std::move(node));
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
}
-#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
+
+#if (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && \
+ !defined(__EMSCRIPTEN__)
TEST(FlatHashMap, Any) {
absl::flat_hash_map<int, absl::any> m;
m.emplace(1, 7);
@@ -234,7 +239,8 @@
ASSERT_NE(it2, m2.end());
EXPECT_EQ(7, it2->second);
}
-#endif // __ANDROID__
+#endif // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) &&
+ // !defined(__EMSCRIPTEN__)
} // namespace
} // namespace container_internal
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index 98aead1..6bf5183 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,6 +32,7 @@
#include <type_traits>
#include <utility>
+#include "absl/algorithm/container.h"
#include "absl/base/macros.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
@@ -66,7 +67,7 @@
// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
// fundamental and Abseil types that support the `absl::Hash` framework have a
// compatible equality operator for comparing insertions into `flat_hash_map`.
-// If your type is not yet supported by the `asbl::Hash` framework, see
+// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
@@ -84,7 +85,7 @@
// {"huey", "dewey", "louie"};
//
// // Insert a new element into the flat hash set
-// ducks.insert("donald"};
+// ducks.insert("donald");
//
// // Force a rehash of the flat hash set
// ducks.rehash(0);
@@ -102,6 +103,46 @@
using Base = typename flat_hash_set::raw_hash_set;
public:
+ // Constructors and Assignment Operators
+ //
+ // A flat_hash_set supports the same overload set as `std::unordered_map`
+ // for construction and assignment:
+ //
+ // * Default constructor
+ //
+ // // No allocation for the table's elements is made.
+ // absl::flat_hash_set<std::string> set1;
+ //
+ // * Initializer List constructor
+ //
+ // absl::flat_hash_set<std::string> set2 =
+ // {{"huey"}, {"dewey"}, {"louie"},};
+ //
+ // * Copy constructor
+ //
+ // absl::flat_hash_set<std::string> set3(set2);
+ //
+ // * Copy assignment operator
+ //
+ // // Hash functor and Comparator are copied as well
+ // absl::flat_hash_set<std::string> set4;
+ // set4 = set3;
+ //
+ // * Move constructor
+ //
+ // // Move is guaranteed efficient
+ // absl::flat_hash_set<std::string> set5(std::move(set4));
+ //
+ // * Move assignment operator
+ //
+ // // May be efficient if allocators are compatible
+ // absl::flat_hash_set<std::string> set6;
+ // set6 = std::move(set5);
+ //
+ // * Range constructor
+ //
+ // std::vector<std::string> v = {"a", "b"};
+ // absl::flat_hash_set<std::string> set7(v.begin(), v.end());
flat_hash_set() {}
using Base::Base;
@@ -171,8 +212,12 @@
// Erases the element at `position` of the `flat_hash_set`, returning
// `void`.
//
- // NOTE: this return behavior is different than that of STL containers in
- // general and `std::unordered_map` in particular.
+ // NOTE: returning `void` in this case is different than that of STL
+ // containers in general and `std::unordered_set` in particular (which
+ // return an iterator to the element following the erased element). If that
+ // iterator is needed, simply post increment the iterator:
+ //
+ // set.erase(it++);
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -238,8 +283,7 @@
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;
@@ -253,8 +297,7 @@
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;
@@ -435,5 +478,16 @@
static size_t space_used(const T*) { return 0; }
};
} // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
+ : std::true_type {};
+
+} // namespace container_algorithm_internal
+
} // namespace absl
+
#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index e52fd53..b55be59 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,6 +19,7 @@
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h"
+#include "absl/container/internal/unordered_set_members_test.h"
#include "absl/container/internal/unordered_set_modifiers_test.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
@@ -40,9 +41,10 @@
using SetTypes =
::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>;
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ModifiersTest, SetTypes);
TEST(FlatHashSet, EmplaceString) {
std::vector<std::string> v = {"a", "b"};
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 12756bb..7798805 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,17 +20,17 @@
// vector" which behaves in an equivalent fashion to a `std::vector`, except
// that storage for small sequences of the vector are provided inline without
// requiring any heap allocation.
-
-// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one
-// of its template parameters. Vectors of length <= N are provided inline.
-// Typically N is very small (e.g., 4) so that sequences that are expected to be
-// short do not require allocations.
-
-// An `absl::InlinedVector` does not usually require a specific allocator; if
+//
+// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
+// its template parameters. Instances where `size() <= N` hold contained
+// elements in inline space. Typically `N` is very small so that sequences that
+// are expected to be short do not require allocations.
+//
+// An `absl::InlinedVector` does not usually require a specific allocator. If
// the inlined vector grows beyond its initial constraints, it will need to
-// allocate (as any normal `std::vector` would) and it will generally use the
-// default allocator in that case; optionally, a custom allocator may be
-// specified using an `absl::InlinedVector<T,N,A>` construction.
+// allocate (as any normal `std::vector` would). This is usually performed with
+// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
+// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
#define ABSL_CONTAINER_INLINED_VECTOR_H_
@@ -50,10 +50,10 @@
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
+#include "absl/container/internal/inlined_vector.h"
#include "absl/memory/memory.h"
namespace absl {
-
// -----------------------------------------------------------------------------
// InlinedVector
// -----------------------------------------------------------------------------
@@ -61,323 +61,633 @@
// An `absl::InlinedVector` is designed to be a drop-in replacement for
// `std::vector` for use cases where the vector's size is sufficiently small
// that it can be inlined. If the inlined vector does grow beyond its estimated
-// size, it will trigger an initial allocation on the heap, and will behave as a
-// `std:vector`. The API of the `absl::InlinedVector` within this file is
+// capacity, it will trigger an initial allocation on the heap, and will behave
+// as a `std:vector`. The API of the `absl::InlinedVector` within this file is
// designed to cover the same API footprint as covered by `std::vector`.
-template <typename T, size_t N, typename A = std::allocator<T> >
+template <typename T, size_t N, typename A = std::allocator<T>>
class InlinedVector {
- using AllocatorTraits = std::allocator_traits<A>;
+ static_assert(
+ N > 0, "InlinedVector cannot be instantiated with `0` inlined elements.");
+
+ using Storage = inlined_vector_internal::Storage<InlinedVector>;
+ using Tag = typename Storage::Tag;
+ using AllocatorAndTag = typename Storage::AllocatorAndTag;
+ using Allocation = typename Storage::Allocation;
+
+ template <typename Iterator>
+ using IsAtLeastForwardIterator = std::is_convertible<
+ typename std::iterator_traits<Iterator>::iterator_category,
+ std::forward_iterator_tag>;
+
+ template <typename Iterator>
+ using EnableIfAtLeastForwardIterator =
+ absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>;
+
+ template <typename Iterator>
+ using DisableIfAtLeastForwardIterator =
+ absl::enable_if_t<!IsAtLeastForwardIterator<Iterator>::value>;
+
+ using rvalue_reference = typename Storage::rvalue_reference;
public:
- using allocator_type = A;
- using value_type = typename allocator_type::value_type;
- using pointer = typename allocator_type::pointer;
- using const_pointer = typename allocator_type::const_pointer;
- using reference = typename allocator_type::reference;
- using const_reference = typename allocator_type::const_reference;
- using size_type = typename allocator_type::size_type;
- using difference_type = typename allocator_type::difference_type;
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using allocator_type = typename Storage::allocator_type;
+ using value_type = typename Storage::value_type;
+ using pointer = typename Storage::pointer;
+ using const_pointer = typename Storage::const_pointer;
+ using reference = typename Storage::reference;
+ using const_reference = typename Storage::const_reference;
+ using size_type = typename Storage::size_type;
+ using difference_type = typename Storage::difference_type;
+ using iterator = typename Storage::iterator;
+ using const_iterator = typename Storage::const_iterator;
+ using reverse_iterator = typename Storage::reverse_iterator;
+ using const_reverse_iterator = typename Storage::const_reverse_iterator;
+ // ---------------------------------------------------------------------------
+ // InlinedVector Constructors and Destructor
+ // ---------------------------------------------------------------------------
+
+ // Creates an empty inlined vector with a default initialized allocator.
InlinedVector() noexcept(noexcept(allocator_type()))
- : allocator_and_tag_(allocator_type()) {}
+ : storage_(allocator_type()) {}
+ // Creates an empty inlined vector with a specified allocator.
explicit InlinedVector(const allocator_type& alloc) noexcept
- : allocator_and_tag_(alloc) {}
+ : storage_(alloc) {}
- // Create a vector with n copies of value_type().
+ // Creates an inlined vector with `n` copies of `value_type()`.
explicit InlinedVector(size_type n,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
+ : storage_(alloc) {
InitAssign(n);
}
- // Create a vector with n copies of elem
- InlinedVector(size_type n, const value_type& elem,
+ // Creates an inlined vector with `n` copies of `v`.
+ InlinedVector(size_type n, const_reference v,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- InitAssign(n, elem);
+ : storage_(alloc) {
+ InitAssign(n, v);
}
- // Create and initialize with the elements [first .. last).
- // The unused enable_if argument restricts this constructor so that it is
- // elided when value_type is an integral type. This prevents ambiguous
- // interpretation between a call to this constructor with two integral
- // arguments and a call to the preceding (n, elem) constructor.
- template <typename InputIterator>
- InlinedVector(
- InputIterator first, InputIterator last,
- const allocator_type& alloc = allocator_type(),
- typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
- nullptr)
- : allocator_and_tag_(alloc) {
- AppendRange(first, last);
- }
-
- InlinedVector(std::initializer_list<value_type> init,
+ // Creates an inlined vector of copies of the values in `list`.
+ InlinedVector(std::initializer_list<value_type> list,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- AppendRange(init.begin(), init.end());
+ : storage_(alloc) {
+ AppendForwardRange(list.begin(), list.end());
}
- InlinedVector(const InlinedVector& v);
- InlinedVector(const InlinedVector& v, const allocator_type& alloc);
+ // Creates an inlined vector with elements constructed from the provided
+ // forward iterator range [`first`, `last`).
+ //
+ // NOTE: The `enable_if` prevents ambiguous interpretation between a call to
+ // this constructor with two integral arguments and a call to the above
+ // `InlinedVector(size_type, const_reference)` constructor.
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ InlinedVector(ForwardIterator first, ForwardIterator last,
+ const allocator_type& alloc = allocator_type())
+ : storage_(alloc) {
+ AppendForwardRange(first, last);
+ }
- // This move constructor does not allocate and only moves the underlying
- // objects, so its `noexcept` specification depends on whether moving the
- // underlying objects can throw or not. We assume
- // a) move constructors should only throw due to allocation failure and
- // b) if `value_type`'s move constructor allocates, it uses the same
- // allocation function as the `InlinedVector`'s allocator, so the move
+ // Creates an inlined vector with elements constructed from the provided input
+ // iterator range [`first`, `last`).
+ template <typename InputIterator,
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+ InlinedVector(InputIterator first, InputIterator last,
+ const allocator_type& alloc = allocator_type())
+ : storage_(alloc) {
+ std::copy(first, last, std::back_inserter(*this));
+ }
+
+ // Creates a copy of an `other` inlined vector using `other`'s allocator.
+ InlinedVector(const InlinedVector& other)
+ : InlinedVector(other, other.allocator()) {}
+
+ // Creates a copy of an `other` inlined vector using a specified allocator.
+ InlinedVector(const InlinedVector& other, const allocator_type& alloc)
+ : storage_(alloc) {
+ reserve(other.size());
+ if (allocated()) {
+ UninitializedCopy(other.begin(), other.end(), allocated_space());
+ tag().set_allocated_size(other.size());
+ } else {
+ UninitializedCopy(other.begin(), other.end(), inlined_space());
+ tag().set_inline_size(other.size());
+ }
+ }
+
+ // Creates an inlined vector by moving in the contents of an `other` inlined
+ // vector without performing any allocations. If `other` contains allocated
+ // memory, the newly-created instance will take ownership of that memory
+ // (leaving `other` itself empty). However, if `other` does not contain any
+ // allocated memory, the new inlined vector will will perform element-wise
+ // move construction of `other`s elements.
+ //
+ // NOTE: since no allocation is performed for the inlined vector in either
+ // case, the `noexcept(...)` specification depends on whether moving the
+ // underlying objects can throw. We assume:
+ // a) Move constructors should only throw due to allocation failure.
+ // b) If `value_type`'s move constructor allocates, it uses the same
+ // allocation function as the `InlinedVector`'s allocator. Thus, the move
// constructor is non-throwing if the allocator is non-throwing or
// `value_type`'s move constructor is specified as `noexcept`.
- InlinedVector(InlinedVector&& v) noexcept(
+ InlinedVector(InlinedVector&& other) noexcept(
absl::allocator_is_nothrow<allocator_type>::value ||
- std::is_nothrow_move_constructible<value_type>::value);
+ std::is_nothrow_move_constructible<value_type>::value)
+ : storage_(other.allocator()) {
+ if (other.allocated()) {
+ // We can just steal the underlying buffer from the source.
+ // That leaves the source empty, so we clear its size.
+ init_allocation(other.allocation());
+ tag().set_allocated_size(other.size());
+ other.tag() = Tag();
+ } else {
+ UninitializedCopy(
+ std::make_move_iterator(other.inlined_space()),
+ std::make_move_iterator(other.inlined_space() + other.size()),
+ inlined_space());
+ tag().set_inline_size(other.size());
+ }
+ }
- // This move constructor allocates and also moves the underlying objects, so
- // its `noexcept` specification depends on whether the allocation can throw
- // and whether moving the underlying objects can throw. Based on the same
- // assumptions above, the `noexcept` specification is dominated by whether the
- // allocation can throw regardless of whether `value_type`'s move constructor
- // is specified as `noexcept`.
- InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept(
- absl::allocator_is_nothrow<allocator_type>::value);
+ // Creates an inlined vector by moving in the contents of an `other` inlined
+ // vector, performing allocations with the specified `alloc` allocator. If
+ // `other`'s allocator is not equal to `alloc` and `other` contains allocated
+ // memory, this move constructor will create a new allocation.
+ //
+ // NOTE: since allocation is performed in this case, this constructor can
+ // only be `noexcept` if the specified allocator is also `noexcept`. If this
+ // is the case, or if `other` contains allocated memory, this constructor
+ // performs element-wise move construction of its contents.
+ //
+ // Only in the case where `other`'s allocator is equal to `alloc` and `other`
+ // contains allocated memory will the newly created inlined vector take
+ // ownership of `other`'s allocated memory.
+ InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
+ absl::allocator_is_nothrow<allocator_type>::value)
+ : storage_(alloc) {
+ if (other.allocated()) {
+ if (alloc == other.allocator()) {
+ // We can just steal the allocation from the source.
+ tag() = other.tag();
+ init_allocation(other.allocation());
+ other.tag() = Tag();
+ } else {
+ // We need to use our own allocator
+ reserve(other.size());
+ UninitializedCopy(std::make_move_iterator(other.begin()),
+ std::make_move_iterator(other.end()),
+ allocated_space());
+ tag().set_allocated_size(other.size());
+ }
+ } else {
+ UninitializedCopy(
+ std::make_move_iterator(other.inlined_space()),
+ std::make_move_iterator(other.inlined_space() + other.size()),
+ inlined_space());
+ tag().set_inline_size(other.size());
+ }
+ }
~InlinedVector() { clear(); }
- InlinedVector& operator=(const InlinedVector& v) {
- if (this == &v) {
- return *this;
+ // ---------------------------------------------------------------------------
+ // InlinedVector Member Accessors
+ // ---------------------------------------------------------------------------
+
+ // `InlinedVector::empty()`
+ //
+ // Checks if the inlined vector has no elements.
+ bool empty() const noexcept { return !size(); }
+
+ // `InlinedVector::size()`
+ //
+ // Returns the number of elements in the inlined vector.
+ size_type size() const noexcept { return tag().size(); }
+
+ // `InlinedVector::max_size()`
+ //
+ // Returns the maximum number of elements the vector can hold.
+ size_type max_size() const noexcept {
+ // One bit of the size storage is used to indicate whether the inlined
+ // vector is allocated. As a result, the maximum size of the container that
+ // we can express is half of the max for `size_type`.
+ return (std::numeric_limits<size_type>::max)() / 2;
+ }
+
+ // `InlinedVector::capacity()`
+ //
+ // Returns the number of elements that can be stored in the inlined vector
+ // without requiring a reallocation of underlying memory.
+ //
+ // NOTE: For most inlined vectors, `capacity()` should equal the template
+ // parameter `N`. For inlined vectors which exceed this capacity, they
+ // will no longer be inlined and `capacity()` will equal its capacity on the
+ // allocated heap.
+ size_type capacity() const noexcept {
+ return allocated() ? allocation().capacity() : static_cast<size_type>(N);
+ }
+
+ // `InlinedVector::data()`
+ //
+ // Returns a `pointer` to elements of the inlined vector. This pointer can be
+ // used to access and modify the contained elements.
+ // Only results within the range [`0`, `size()`) are defined.
+ pointer data() noexcept {
+ return allocated() ? allocated_space() : inlined_space();
+ }
+
+ // Overload of `InlinedVector::data()` to return a `const_pointer` to elements
+ // of the inlined vector. This pointer can be used to access (but not modify)
+ // the contained elements.
+ const_pointer data() const noexcept {
+ return allocated() ? allocated_space() : inlined_space();
+ }
+
+ // `InlinedVector::operator[]()`
+ //
+ // Returns a `reference` to the `i`th element of the inlined vector using the
+ // array operator.
+ reference operator[](size_type i) {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // Overload of `InlinedVector::operator[]()` to return a `const_reference` to
+ // the `i`th element of the inlined vector.
+ const_reference operator[](size_type i) const {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // `InlinedVector::at()`
+ //
+ // Returns a `reference` to the `i`th element of the inlined vector.
+ reference at(size_type i) {
+ if (ABSL_PREDICT_FALSE(i >= size())) {
+ base_internal::ThrowStdOutOfRange(
+ "`InlinedVector::at(size_type)` failed bounds check");
}
+ return data()[i];
+ }
+
+ // Overload of `InlinedVector::at()` to return a `const_reference` to the
+ // `i`th element of the inlined vector.
+ const_reference at(size_type i) const {
+ if (ABSL_PREDICT_FALSE(i >= size())) {
+ base_internal::ThrowStdOutOfRange(
+ "`InlinedVector::at(size_type) const` failed bounds check");
+ }
+ return data()[i];
+ }
+
+ // `InlinedVector::front()`
+ //
+ // Returns a `reference` to the first element of the inlined vector.
+ reference front() {
+ assert(!empty());
+ return at(0);
+ }
+
+ // Overload of `InlinedVector::front()` returns a `const_reference` to the
+ // first element of the inlined vector.
+ const_reference front() const {
+ assert(!empty());
+ return at(0);
+ }
+
+ // `InlinedVector::back()`
+ //
+ // Returns a `reference` to the last element of the inlined vector.
+ reference back() {
+ assert(!empty());
+ return at(size() - 1);
+ }
+
+ // Overload of `InlinedVector::back()` to return a `const_reference` to the
+ // last element of the inlined vector.
+ const_reference back() const {
+ assert(!empty());
+ return at(size() - 1);
+ }
+
+ // `InlinedVector::begin()`
+ //
+ // Returns an `iterator` to the beginning of the inlined vector.
+ iterator begin() noexcept { return data(); }
+
+ // Overload of `InlinedVector::begin()` to return a `const_iterator` to
+ // the beginning of the inlined vector.
+ const_iterator begin() const noexcept { return data(); }
+
+ // `InlinedVector::end()`
+ //
+ // Returns an `iterator` to the end of the inlined vector.
+ iterator end() noexcept { return data() + size(); }
+
+ // Overload of `InlinedVector::end()` to return a `const_iterator` to the
+ // end of the inlined vector.
+ const_iterator end() const noexcept { return data() + size(); }
+
+ // `InlinedVector::cbegin()`
+ //
+ // Returns a `const_iterator` to the beginning of the inlined vector.
+ const_iterator cbegin() const noexcept { return begin(); }
+
+ // `InlinedVector::cend()`
+ //
+ // Returns a `const_iterator` to the end of the inlined vector.
+ const_iterator cend() const noexcept { return end(); }
+
+ // `InlinedVector::rbegin()`
+ //
+ // Returns a `reverse_iterator` from the end of the inlined vector.
+ reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+
+ // Overload of `InlinedVector::rbegin()` to return a
+ // `const_reverse_iterator` from the end of the inlined vector.
+ const_reverse_iterator rbegin() const noexcept {
+ return const_reverse_iterator(end());
+ }
+
+ // `InlinedVector::rend()`
+ //
+ // Returns a `reverse_iterator` from the beginning of the inlined vector.
+ reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+
+ // Overload of `InlinedVector::rend()` to return a `const_reverse_iterator`
+ // from the beginning of the inlined vector.
+ const_reverse_iterator rend() const noexcept {
+ return const_reverse_iterator(begin());
+ }
+
+ // `InlinedVector::crbegin()`
+ //
+ // Returns a `const_reverse_iterator` from the end of the inlined vector.
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+ // `InlinedVector::crend()`
+ //
+ // Returns a `const_reverse_iterator` from the beginning of the inlined
+ // vector.
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // `InlinedVector::get_allocator()`
+ //
+ // Returns a copy of the allocator of the inlined vector.
+ allocator_type get_allocator() const { return allocator(); }
+
+ // ---------------------------------------------------------------------------
+ // InlinedVector Member Mutators
+ // ---------------------------------------------------------------------------
+
+ // `InlinedVector::operator=()`
+ //
+ // Replaces the contents of the inlined vector with copies of the elements in
+ // the provided `std::initializer_list`.
+ InlinedVector& operator=(std::initializer_list<value_type> list) {
+ AssignForwardRange(list.begin(), list.end());
+ return *this;
+ }
+
+ // Overload of `InlinedVector::operator=()` to replace the contents of the
+ // inlined vector with the contents of `other`.
+ InlinedVector& operator=(const InlinedVector& other) {
+ if (ABSL_PREDICT_FALSE(this == &other)) return *this;
+
// Optimized to avoid reallocation.
// Prefer reassignment to copy construction for elements.
- if (size() < v.size()) { // grow
- reserve(v.size());
- std::copy(v.begin(), v.begin() + size(), begin());
- std::copy(v.begin() + size(), v.end(), std::back_inserter(*this));
+ if (size() < other.size()) { // grow
+ reserve(other.size());
+ std::copy(other.begin(), other.begin() + size(), begin());
+ std::copy(other.begin() + size(), other.end(), std::back_inserter(*this));
} else { // maybe shrink
- erase(begin() + v.size(), end());
- std::copy(v.begin(), v.end(), begin());
+ erase(begin() + other.size(), end());
+ std::copy(other.begin(), other.end(), begin());
}
return *this;
}
- InlinedVector& operator=(InlinedVector&& v) {
- if (this == &v) {
- return *this;
- }
- if (v.allocated()) {
+ // Overload of `InlinedVector::operator=()` to replace the contents of the
+ // inlined vector with the contents of `other`.
+ //
+ // NOTE: As a result of calling this overload, `other` may be empty or it's
+ // contents may be left in a moved-from state.
+ InlinedVector& operator=(InlinedVector&& other) {
+ if (ABSL_PREDICT_FALSE(this == &other)) return *this;
+
+ if (other.allocated()) {
clear();
- tag().set_allocated_size(v.size());
- init_allocation(v.allocation());
- v.tag() = Tag();
+ tag().set_allocated_size(other.size());
+ init_allocation(other.allocation());
+ other.tag() = Tag();
} else {
if (allocated()) clear();
// Both are inlined now.
- if (size() < v.size()) {
- auto mid = std::make_move_iterator(v.begin() + size());
- std::copy(std::make_move_iterator(v.begin()), mid, begin());
- UninitializedCopy(mid, std::make_move_iterator(v.end()), end());
+ if (size() < other.size()) {
+ auto mid = std::make_move_iterator(other.begin() + size());
+ std::copy(std::make_move_iterator(other.begin()), mid, begin());
+ UninitializedCopy(mid, std::make_move_iterator(other.end()), end());
} else {
- auto new_end = std::copy(std::make_move_iterator(v.begin()),
- std::make_move_iterator(v.end()), begin());
+ auto new_end = std::copy(std::make_move_iterator(other.begin()),
+ std::make_move_iterator(other.end()), begin());
Destroy(new_end, end());
}
- tag().set_inline_size(v.size());
+ tag().set_inline_size(other.size());
}
return *this;
}
- InlinedVector& operator=(std::initializer_list<value_type> init) {
- AssignRange(init.begin(), init.end());
- return *this;
- }
-
- // InlinedVector::assign()
+ // `InlinedVector::assign()`
//
- // Replaces the contents of the inlined vector with copies of those in the
- // iterator range [first, last).
- template <typename InputIterator>
- void assign(
- InputIterator first, InputIterator last,
- typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
- nullptr) {
- AssignRange(first, last);
- }
-
- // Overload of `InlinedVector::assign()` to take values from elements of an
- // initializer list
- void assign(std::initializer_list<value_type> init) {
- AssignRange(init.begin(), init.end());
- }
-
- // Overload of `InlinedVector::assign()` to replace the first `n` elements of
- // the inlined vector with `elem` values.
- void assign(size_type n, const value_type& elem) {
+ // Replaces the contents of the inlined vector with `n` copies of `v`.
+ void assign(size_type n, const_reference v) {
if (n <= size()) { // Possibly shrink
- std::fill_n(begin(), n, elem);
+ std::fill_n(begin(), n, v);
erase(begin() + n, end());
return;
}
// Grow
reserve(n);
- std::fill_n(begin(), size(), elem);
+ std::fill_n(begin(), size(), v);
if (allocated()) {
- UninitializedFill(allocated_space() + size(), allocated_space() + n,
- elem);
+ UninitializedFill(allocated_space() + size(), allocated_space() + n, v);
tag().set_allocated_size(n);
} else {
- UninitializedFill(inlined_space() + size(), inlined_space() + n, elem);
+ UninitializedFill(inlined_space() + size(), inlined_space() + n, v);
tag().set_inline_size(n);
}
}
- // InlinedVector::size()
- //
- // Returns the number of elements in the inlined vector.
- size_type size() const noexcept { return tag().size(); }
-
- // InlinedVector::empty()
- //
- // Checks if the inlined vector has no elements.
- bool empty() const noexcept { return (size() == 0); }
-
- // InlinedVector::capacity()
- //
- // Returns the number of elements that can be stored in an inlined vector
- // without requiring a reallocation of underlying memory. Note that for
- // most inlined vectors, `capacity()` should equal its initial size `N`; for
- // inlined vectors which exceed this capacity, they will no longer be inlined,
- // and `capacity()` will equal its capacity on the allocated heap.
- size_type capacity() const noexcept {
- return allocated() ? allocation().capacity() : N;
+ // Overload of `InlinedVector::assign()` to replace the contents of the
+ // inlined vector with copies of the values in the provided
+ // `std::initializer_list`.
+ void assign(std::initializer_list<value_type> list) {
+ AssignForwardRange(list.begin(), list.end());
}
- // InlinedVector::max_size()
- //
- // Returns the maximum number of elements the vector can hold.
- size_type max_size() const noexcept {
- // One bit of the size storage is used to indicate whether the inlined
- // vector is allocated; as a result, the maximum size of the container that
- // we can express is half of the max for our size type.
- return std::numeric_limits<size_type>::max() / 2;
+ // Overload of `InlinedVector::assign()` to replace the contents of the
+ // inlined vector with the forward iterator range [`first`, `last`).
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ void assign(ForwardIterator first, ForwardIterator last) {
+ AssignForwardRange(first, last);
}
- // InlinedVector::data()
- //
- // Returns a const T* pointer to elements of the inlined vector. This pointer
- // can be used to access (but not modify) the contained elements.
- // Only results within the range `[0,size())` are defined.
- const_pointer data() const noexcept {
- return allocated() ? allocated_space() : inlined_space();
+ // Overload of `InlinedVector::assign()` to replace the contents of the
+ // inlined vector with the input iterator range [`first`, `last`).
+ template <typename InputIterator,
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+ void assign(InputIterator first, InputIterator last) {
+ size_type assign_index = 0;
+ for (; (assign_index < size()) && (first != last);
+ static_cast<void>(++assign_index), static_cast<void>(++first)) {
+ *(data() + assign_index) = *first;
+ }
+ erase(data() + assign_index, data() + size());
+ std::copy(first, last, std::back_inserter(*this));
}
- // Overload of InlinedVector::data() to return a T* pointer to elements of the
- // inlined vector. This pointer can be used to access and modify the contained
- // elements.
- pointer data() noexcept {
- return allocated() ? allocated_space() : inlined_space();
- }
-
- // InlinedVector::clear()
+ // `InlinedVector::resize()`
//
- // Removes all elements from the inlined vector.
- void clear() noexcept {
+ // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
+ // the inlined vector's current size, extra elements are destroyed. If `n` is
+ // larger than the initial size, new elements are value-initialized.
+ void resize(size_type n) {
size_type s = size();
+ if (n < s) {
+ erase(begin() + n, end());
+ return;
+ }
+ reserve(n);
+ assert(capacity() >= n);
+
+ // Fill new space with elements constructed in-place.
if (allocated()) {
- Destroy(allocated_space(), allocated_space() + s);
- allocation().Dealloc(allocator());
- } else if (s != 0) { // do nothing for empty vectors
- Destroy(inlined_space(), inlined_space() + s);
+ UninitializedFill(allocated_space() + s, allocated_space() + n);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space() + s, inlined_space() + n);
+ tag().set_inline_size(n);
}
- tag() = Tag();
}
- // InlinedVector::at()
- //
- // Returns the ith element of an inlined vector.
- const value_type& at(size_type i) const {
- if (ABSL_PREDICT_FALSE(i >= size())) {
- base_internal::ThrowStdOutOfRange(
- "InlinedVector::at failed bounds check");
- }
- return data()[i];
- }
-
- // InlinedVector::operator[]
- //
- // Returns the ith element of an inlined vector using the array operator.
- const value_type& operator[](size_type i) const {
- assert(i < size());
- return data()[i];
- }
-
- // Overload of InlinedVector::at() to return the ith element of an inlined
- // vector.
- value_type& at(size_type i) {
- if (i >= size()) {
- base_internal::ThrowStdOutOfRange(
- "InlinedVector::at failed bounds check");
- }
- return data()[i];
- }
-
- // Overload of InlinedVector::operator[] to return the ith element of an
- // inlined vector.
- value_type& operator[](size_type i) {
- assert(i < size());
- return data()[i];
- }
-
- // InlinedVector::back()
- //
- // Returns a reference to the last element of an inlined vector.
- value_type& back() {
- assert(!empty());
- return at(size() - 1);
- }
-
- // Overload of InlinedVector::back() returns a reference to the last element
- // of an inlined vector of const values.
- const value_type& back() const {
- assert(!empty());
- return at(size() - 1);
- }
-
- // InlinedVector::front()
- //
- // Returns a reference to the first element of an inlined vector.
- value_type& front() {
- assert(!empty());
- return at(0);
- }
-
- // Overload of InlinedVector::front() returns a reference to the first element
- // of an inlined vector of const values.
- const value_type& front() const {
- assert(!empty());
- return at(0);
- }
-
- // InlinedVector::emplace_back()
- //
- // Constructs and appends an object to the inlined vector.
- //
- // Returns a reference to the inserted element.
- template <typename... Args>
- value_type& emplace_back(Args&&... args) {
+ // Overload of `InlinedVector::resize()` to resize the inlined vector to
+ // contain `n` elements where, if `n` is larger than `size()`, the new values
+ // will be copy-constructed from `v`.
+ void resize(size_type n, const_reference v) {
size_type s = size();
- assert(s <= capacity());
+ if (n < s) {
+ erase(begin() + n, end());
+ return;
+ }
+ reserve(n);
+ assert(capacity() >= n);
+
+ // Fill new space with copies of `v`.
+ if (allocated()) {
+ UninitializedFill(allocated_space() + s, allocated_space() + n, v);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space() + s, inlined_space() + n, v);
+ tag().set_inline_size(n);
+ }
+ }
+
+ // `InlinedVector::insert()`
+ //
+ // Copies `v` into `pos`, returning an `iterator` pointing to the newly
+ // inserted element.
+ iterator insert(const_iterator pos, const_reference v) {
+ return emplace(pos, v);
+ }
+
+ // Overload of `InlinedVector::insert()` for moving `v` into `pos`, returning
+ // an iterator pointing to the newly inserted element.
+ iterator insert(const_iterator pos, rvalue_reference v) {
+ return emplace(pos, std::move(v));
+ }
+
+ // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies
+ // of `v` starting at `pos`. Returns an `iterator` pointing to the first of
+ // the newly inserted elements.
+ iterator insert(const_iterator pos, size_type n, const_reference v) {
+ return InsertWithCount(pos, n, v);
+ }
+
+ // Overload of `InlinedVector::insert()` for copying the contents of the
+ // `std::initializer_list` into the vector starting at `pos`. Returns an
+ // `iterator` pointing to the first of the newly inserted elements.
+ iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
+ return insert(pos, list.begin(), list.end());
+ }
+
+ // Overload of `InlinedVector::insert()` for inserting elements constructed
+ // from the forward iterator range [`first`, `last`). Returns an `iterator`
+ // pointing to the first of the newly inserted elements.
+ //
+ // NOTE: The `enable_if` is intended to disambiguate the two three-argument
+ // overloads of `insert()`.
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ iterator insert(const_iterator pos, ForwardIterator first,
+ ForwardIterator last) {
+ return InsertWithForwardRange(pos, first, last);
+ }
+
+ // Overload of `InlinedVector::insert()` for inserting elements constructed
+ // from the input iterator range [`first`, `last`). Returns an `iterator`
+ // pointing to the first of the newly inserted elements.
+ template <typename InputIterator,
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+ iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
+ size_type initial_insert_index = std::distance(cbegin(), pos);
+ for (size_type insert_index = initial_insert_index; first != last;
+ static_cast<void>(++insert_index), static_cast<void>(++first)) {
+ insert(data() + insert_index, *first);
+ }
+ return iterator(data() + initial_insert_index);
+ }
+
+ // `InlinedVector::emplace()`
+ //
+ // Constructs and inserts an object in the inlined vector at the given `pos`,
+ // returning an `iterator` pointing to the newly emplaced element.
+ template <typename... Args>
+ iterator emplace(const_iterator pos, Args&&... args) {
+ assert(pos >= begin());
+ assert(pos <= end());
+ if (ABSL_PREDICT_FALSE(pos == end())) {
+ emplace_back(std::forward<Args>(args)...);
+ return end() - 1;
+ }
+
+ T new_t = T(std::forward<Args>(args)...);
+
+ auto range = ShiftRight(pos, 1);
+ if (range.first == range.second) {
+ // constructing into uninitialized memory
+ Construct(range.first, std::move(new_t));
+ } else {
+ // assigning into moved-from object
+ *range.first = T(std::move(new_t));
+ }
+
+ return range.first;
+ }
+
+ // `InlinedVector::emplace_back()`
+ //
+ // Constructs and appends a new element to the end of the inlined vector,
+ // returning a `reference` to the emplaced element.
+ template <typename... Args>
+ reference emplace_back(Args&&... args) {
+ size_type s = size();
if (ABSL_PREDICT_FALSE(s == capacity())) {
return GrowAndEmplaceBack(std::forward<Args>(args)...);
}
- assert(s < capacity());
-
- value_type* space;
+ pointer space;
if (allocated()) {
tag().set_allocated_size(s + 1);
space = allocated_space();
@@ -388,19 +698,22 @@
return Construct(space + s, std::forward<Args>(args)...);
}
- // InlinedVector::push_back()
+ // `InlinedVector::push_back()`
//
- // Appends a const element to the inlined vector.
- void push_back(const value_type& t) { emplace_back(t); }
+ // Appends a copy of `v` to the end of the inlined vector.
+ void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
- // Overload of InlinedVector::push_back() to append a move-only element to the
- // inlined vector.
- void push_back(value_type&& t) { emplace_back(std::move(t)); }
+ // Overload of `InlinedVector::push_back()` for moving `v` into a newly
+ // appended element.
+ void push_back(rvalue_reference v) {
+ static_cast<void>(emplace_back(std::move(v)));
+ }
- // InlinedVector::pop_back()
+ // `InlinedVector::pop_back()`
//
- // Removes the last element (which is destroyed) in the inlined vector.
- void pop_back() {
+ // Destroys the element at the end of the inlined vector and shrinks the size
+ // by `1` (unless the inlined vector is empty, in which case this is a no-op).
+ void pop_back() noexcept {
assert(!empty());
size_type s = size();
if (allocated()) {
@@ -412,161 +725,75 @@
}
}
- // InlinedVector::resize()
+ // `InlinedVector::erase()`
//
- // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
- // the inlined vector's current size, extra elements are destroyed. If `n` is
- // larger than the initial size, new elements are value-initialized.
- void resize(size_type n);
-
- // Overload of InlinedVector::resize() to resize the inlined vector to contain
- // `n` elements. If `n` is larger than the current size, enough copies of
- // `elem` are appended to increase its size to `n`.
- void resize(size_type n, const value_type& elem);
-
- // InlinedVector::begin()
+ // Erases the element at `pos` of the inlined vector, returning an `iterator`
+ // pointing to the first element following the erased element.
//
- // Returns an iterator to the beginning of the inlined vector.
- iterator begin() noexcept { return data(); }
+ // NOTE: May return the end iterator, which is not dereferencable.
+ iterator erase(const_iterator pos) {
+ assert(pos >= begin());
+ assert(pos < end());
- // Overload of InlinedVector::begin() for returning a const iterator to the
- // beginning of the inlined vector.
- const_iterator begin() const noexcept { return data(); }
-
- // InlinedVector::cbegin()
- //
- // Returns a const iterator to the beginning of the inlined vector.
- const_iterator cbegin() const noexcept { return begin(); }
-
- // InlinedVector::end()
- //
- // Returns an iterator to the end of the inlined vector.
- iterator end() noexcept { return data() + size(); }
-
- // Overload of InlinedVector::end() for returning a const iterator to the end
- // of the inlined vector.
- const_iterator end() const noexcept { return data() + size(); }
-
- // InlinedVector::cend()
- //
- // Returns a const iterator to the end of the inlined vector.
- const_iterator cend() const noexcept { return end(); }
-
- // InlinedVector::rbegin()
- //
- // Returns a reverse iterator from the end of the inlined vector.
- reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
-
- // Overload of InlinedVector::rbegin() for returning a const reverse iterator
- // from the end of the inlined vector.
- const_reverse_iterator rbegin() const noexcept {
- return const_reverse_iterator(end());
- }
-
- // InlinedVector::crbegin()
- //
- // Returns a const reverse iterator from the end of the inlined vector.
- const_reverse_iterator crbegin() const noexcept { return rbegin(); }
-
- // InlinedVector::rend()
- //
- // Returns a reverse iterator from the beginning of the inlined vector.
- reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
-
- // Overload of InlinedVector::rend() for returning a const reverse iterator
- // from the beginning of the inlined vector.
- const_reverse_iterator rend() const noexcept {
- return const_reverse_iterator(begin());
- }
-
- // InlinedVector::crend()
- //
- // Returns a reverse iterator from the beginning of the inlined vector.
- const_reverse_iterator crend() const noexcept { return rend(); }
-
- // InlinedVector::emplace()
- //
- // Constructs and inserts an object to the inlined vector at the given
- // `position`, returning an iterator pointing to the newly emplaced element.
- template <typename... Args>
- iterator emplace(const_iterator position, Args&&... args);
-
- // InlinedVector::insert()
- //
- // Inserts an element of the specified value at `position`, returning an
- // iterator pointing to the newly inserted element.
- iterator insert(const_iterator position, const value_type& v) {
- return emplace(position, v);
- }
-
- // Overload of InlinedVector::insert() for inserting an element of the
- // specified rvalue, returning an iterator pointing to the newly inserted
- // element.
- iterator insert(const_iterator position, value_type&& v) {
- return emplace(position, std::move(v));
- }
-
- // Overload of InlinedVector::insert() for inserting `n` elements of the
- // specified value at `position`, returning an iterator pointing to the first
- // of the newly inserted elements.
- iterator insert(const_iterator position, size_type n, const value_type& v) {
- return InsertWithCount(position, n, v);
- }
-
- // Overload of `InlinedVector::insert()` to disambiguate the two
- // three-argument overloads of `insert()`, returning an iterator pointing to
- // the first of the newly inserted elements.
- template <typename InputIterator,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<InputIterator>::iterator_category,
- std::input_iterator_tag>::value>::type>
- iterator insert(const_iterator position, InputIterator first,
- InputIterator last) {
- using IterType =
- typename std::iterator_traits<InputIterator>::iterator_category;
- return InsertWithRange(position, first, last, IterType());
- }
-
- // Overload of InlinedVector::insert() for inserting a list of elements at
- // `position`, returning an iterator pointing to the first of the newly
- // inserted elements.
- iterator insert(const_iterator position,
- std::initializer_list<value_type> init) {
- return insert(position, init.begin(), init.end());
- }
-
- // InlinedVector::erase()
- //
- // Erases the element at `position` of the inlined vector, returning an
- // iterator pointing to the following element or the container's end if the
- // last element was erased.
- iterator erase(const_iterator position) {
- assert(position >= begin());
- assert(position < end());
-
- iterator pos = const_cast<iterator>(position);
- std::move(pos + 1, end(), pos);
+ iterator position = const_cast<iterator>(pos);
+ std::move(position + 1, end(), position);
pop_back();
- return pos;
+ return position;
}
- // Overload of InlinedVector::erase() for erasing all elements in the
- // iterator range [first, last) in the inlined vector, returning an iterator
- // pointing to the first element following the range erased, or the
- // container's end if range included the container's last element.
- iterator erase(const_iterator first, const_iterator last);
+ // Overload of `InlinedVector::erase()` for erasing all elements in the
+ // range [`from`, `to`) in the inlined vector. Returns an `iterator` pointing
+ // to the first element following the range erased or the end iterator if `to`
+ // was the end iterator.
+ iterator erase(const_iterator from, const_iterator to) {
+ assert(begin() <= from);
+ assert(from <= to);
+ assert(to <= end());
- // InlinedVector::reserve()
+ iterator range_start = const_cast<iterator>(from);
+ iterator range_end = const_cast<iterator>(to);
+
+ size_type s = size();
+ ptrdiff_t erase_gap = std::distance(range_start, range_end);
+ if (erase_gap > 0) {
+ pointer space;
+ if (allocated()) {
+ space = allocated_space();
+ tag().set_allocated_size(s - erase_gap);
+ } else {
+ space = inlined_space();
+ tag().set_inline_size(s - erase_gap);
+ }
+ std::move(range_end, space + s, range_start);
+ Destroy(space + s - erase_gap, space + s);
+ }
+ return range_start;
+ }
+
+ // `InlinedVector::clear()`
+ //
+ // Destroys all elements in the inlined vector, sets the size of `0` and
+ // deallocates the heap allocation if the inlined vector was allocated.
+ void clear() noexcept {
+ size_type s = size();
+ if (allocated()) {
+ Destroy(allocated_space(), allocated_space() + s);
+ allocation().Dealloc(allocator());
+ } else if (s != 0) { // do nothing for empty vectors
+ Destroy(inlined_space(), inlined_space() + s);
+ }
+ tag() = Tag();
+ }
+
+ // `InlinedVector::reserve()`
//
// Enlarges the underlying representation of the inlined vector so it can hold
// at least `n` elements. This method does not change `size()` or the actual
// contents of the vector.
//
- // Note that if `n` does not exceed the inlined vector's initial size `N`,
- // `reserve()` will have no effect; if it does exceed its initial size,
- // `reserve()` will trigger an initial allocation and move the inlined vector
- // onto the heap. If the vector already exists on the heap and the requested
- // size exceeds it, a reallocation will be performed.
+ // NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no
+ // effects. Otherwise, `reserve()` will reallocate, performing an n-time
+ // element-wise move of everything contained.
void reserve(size_type n) {
if (n > capacity()) {
// Make room for new elements
@@ -574,26 +801,25 @@
}
}
- // InlinedVector::shrink_to_fit()
+ // `InlinedVector::shrink_to_fit()`
//
- // Reduces memory usage by freeing unused memory.
- // After this call `capacity()` will be equal to `max(N, size())`.
+ // Reduces memory usage by freeing unused memory. After this call, calls to
+ // `capacity()` will be equal to `max(N, size())`.
//
// If `size() <= N` and the elements are currently stored on the heap, they
- // will be moved to the inlined storage and the heap memory deallocated.
- // If `size() > N` and `size() < capacity()` the elements will be moved to
- // a reallocated storage on heap.
+ // will be moved to the inlined storage and the heap memory will be
+ // deallocated.
+ //
+ // If `size() > N` and `size() < capacity()` the elements will be moved to a
+ // smaller heap allocation.
void shrink_to_fit() {
const auto s = size();
- if (!allocated() || s == capacity()) {
- // There's nothing to deallocate.
- return;
- }
+ if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return;
if (s <= N) {
// Move the elements to the inlined storage.
- // We have to do this using a temporary, because inlined_storage and
- // allocation_storage are in a union field.
+ // We have to do this using a temporary, because `inlined_storage` and
+ // `allocation_storage` are in a union field.
auto temp = std::move(*this);
assign(std::make_move_iterator(temp.begin()),
std::make_move_iterator(temp.end()));
@@ -601,8 +827,8 @@
}
// Reallocate storage and move elements.
- // We can't simply use the same approach as above, because assign() would
- // call into reserve() internally and reserve larger capacity than we need.
+ // We can't simply use the same approach as above, because `assign()` would
+ // call into `reserve()` internally and reserve larger capacity than we need
Allocation new_allocation(allocator(), s);
UninitializedCopy(std::make_move_iterator(allocated_space()),
std::make_move_iterator(allocated_space() + s),
@@ -610,129 +836,62 @@
ResetAllocation(new_allocation, s);
}
- // InlinedVector::swap()
+ // `InlinedVector::swap()`
//
// Swaps the contents of this inlined vector with the contents of `other`.
- void swap(InlinedVector& other);
+ void swap(InlinedVector& other) {
+ if (ABSL_PREDICT_FALSE(this == &other)) return;
- // InlinedVector::get_allocator()
- //
- // Returns the allocator of this inlined vector.
- allocator_type get_allocator() const { return allocator(); }
-
- template <typename H>
- friend H AbslHashValue(H h, const InlinedVector& v) {
- return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
- v.size());
+ SwapImpl(other);
}
private:
- static_assert(N > 0, "inlined vector with nonpositive size");
+ template <typename H, typename TheT, size_t TheN, typename TheA>
+ friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H;
- // It holds whether the vector is allocated or not in the lowest bit.
- // The size is held in the high bits:
- // size_ = (size << 1) | is_allocated;
- //
- // Maintainer's Note: size_type is user defined. The contract is limited to
- // arithmetic operators to avoid depending on compliant overloaded bitwise
- // operators.
- class Tag {
- public:
- Tag() : size_(0) {}
- size_type size() const { return size_ / 2; }
- void add_size(size_type n) { size_ += n * 2; }
- void set_inline_size(size_type n) { size_ = n * 2; }
- void set_allocated_size(size_type n) { size_ = (n * 2) + 1; }
- bool allocated() const { return size_ % 2; }
+ const Tag& tag() const { return storage_.allocator_and_tag_.tag(); }
- private:
- size_type size_;
- };
-
- // Derives from allocator_type to use the empty base class optimization.
- // If the allocator_type is stateless, we can 'store'
- // our instance of it for free.
- class AllocatorAndTag : private allocator_type {
- public:
- explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {}
- Tag& tag() { return tag_; }
- const Tag& tag() const { return tag_; }
- allocator_type& allocator() { return *this; }
- const allocator_type& allocator() const { return *this; }
-
- private:
- Tag tag_;
- };
-
- class Allocation {
- public:
- Allocation(allocator_type& a, // NOLINT(runtime/references)
- size_type capacity)
- : capacity_(capacity),
- buffer_(AllocatorTraits::allocate(a, capacity_)) {}
-
- void Dealloc(allocator_type& a) { // NOLINT(runtime/references)
- AllocatorTraits::deallocate(a, buffer(), capacity());
- }
-
- size_type capacity() const { return capacity_; }
- const value_type* buffer() const { return buffer_; }
- value_type* buffer() { return buffer_; }
-
- private:
- size_type capacity_;
- value_type* buffer_;
- };
-
- const Tag& tag() const { return allocator_and_tag_.tag(); }
- Tag& tag() { return allocator_and_tag_.tag(); }
+ Tag& tag() { return storage_.allocator_and_tag_.tag(); }
Allocation& allocation() {
- return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation);
+ return reinterpret_cast<Allocation&>(
+ storage_.rep_.allocation_storage.allocation);
}
+
const Allocation& allocation() const {
return reinterpret_cast<const Allocation&>(
- rep_.allocation_storage.allocation);
+ storage_.rep_.allocation_storage.allocation);
}
+
void init_allocation(const Allocation& allocation) {
- new (&rep_.allocation_storage.allocation) Allocation(allocation);
+ new (&storage_.rep_.allocation_storage.allocation) Allocation(allocation);
}
// TODO(absl-team): investigate whether the reinterpret_cast is appropriate.
- value_type* inlined_space() {
- return reinterpret_cast<value_type*>(
- std::addressof(rep_.inlined_storage.inlined[0]));
- }
- const value_type* inlined_space() const {
- return reinterpret_cast<const value_type*>(
- std::addressof(rep_.inlined_storage.inlined[0]));
+ pointer inlined_space() {
+ return reinterpret_cast<pointer>(
+ std::addressof(storage_.rep_.inlined_storage.inlined[0]));
}
- value_type* allocated_space() { return allocation().buffer(); }
- const value_type* allocated_space() const { return allocation().buffer(); }
+ const_pointer inlined_space() const {
+ return reinterpret_cast<const_pointer>(
+ std::addressof(storage_.rep_.inlined_storage.inlined[0]));
+ }
+
+ pointer allocated_space() { return allocation().buffer(); }
+
+ const_pointer allocated_space() const { return allocation().buffer(); }
const allocator_type& allocator() const {
- return allocator_and_tag_.allocator();
+ return storage_.allocator_and_tag_.allocator();
}
- allocator_type& allocator() { return allocator_and_tag_.allocator(); }
+
+ allocator_type& allocator() {
+ return storage_.allocator_and_tag_.allocator();
+ }
bool allocated() const { return tag().allocated(); }
- // Enlarge the underlying representation so we can store size_ + delta elems.
- // The size is not changed, and any newly added memory is not initialized.
- void EnlargeBy(size_type delta);
-
- // Shift all elements from position to end() n places to the right.
- // If the vector needs to be enlarged, memory will be allocated.
- // Returns iterators pointing to the start of the previously-initialized
- // portion and the start of the uninitialized portion of the created gap.
- // The number of initialized spots is pair.second - pair.first;
- // the number of raw spots is n - (pair.second - pair.first).
- //
- // Updates the size of the InlinedVector internally.
- std::pair<iterator, iterator> ShiftRight(const_iterator position,
- size_type n);
-
void ResetAllocation(Allocation new_allocation, size_type new_size) {
if (allocated()) {
Destroy(allocated_space(), allocated_space() + size());
@@ -747,13 +906,137 @@
}
template <typename... Args>
- value_type& GrowAndEmplaceBack(Args&&... args) {
+ reference Construct(pointer p, Args&&... args) {
+ std::allocator_traits<allocator_type>::construct(
+ allocator(), p, std::forward<Args>(args)...);
+ return *p;
+ }
+
+ template <typename Iterator>
+ void UninitializedCopy(Iterator src, Iterator src_last, pointer dst) {
+ for (; src != src_last; ++dst, ++src) Construct(dst, *src);
+ }
+
+ template <typename... Args>
+ void UninitializedFill(pointer dst, pointer dst_last, const Args&... args) {
+ for (; dst != dst_last; ++dst) Construct(dst, args...);
+ }
+
+ // Destroy [`from`, `to`) in place.
+ void Destroy(pointer from, pointer to) {
+ for (pointer cur = from; cur != to; ++cur) {
+ std::allocator_traits<allocator_type>::destroy(allocator(), cur);
+ }
+#if !defined(NDEBUG)
+ // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
+ // Cast to `void*` to tell the compiler that we don't care that we might be
+ // scribbling on a vtable pointer.
+ if (from != to) {
+ auto len = sizeof(value_type) * std::distance(from, to);
+ std::memset(reinterpret_cast<void*>(from), 0xab, len);
+ }
+#endif // !defined(NDEBUG)
+ }
+
+ // Enlarge the underlying representation so we can store `size_ + delta` elems
+ // in allocated space. The size is not changed, and any newly added memory is
+ // not initialized.
+ void EnlargeBy(size_type delta) {
+ const size_type s = size();
+ assert(s <= capacity());
+
+ size_type target = (std::max)(N, s + delta);
+
+ // Compute new capacity by repeatedly doubling current capacity
+ // TODO(psrc): Check and avoid overflow?
+ size_type new_capacity = capacity();
+ while (new_capacity < target) {
+ new_capacity <<= 1;
+ }
+
+ Allocation new_allocation(allocator(), new_capacity);
+
+ UninitializedCopy(std::make_move_iterator(data()),
+ std::make_move_iterator(data() + s),
+ new_allocation.buffer());
+
+ ResetAllocation(new_allocation, s);
+ }
+
+ // Shift all elements from `position` to `end()` by `n` places to the right.
+ // If the vector needs to be enlarged, memory will be allocated.
+ // Returns `iterator`s pointing to the start of the previously-initialized
+ // portion and the start of the uninitialized portion of the created gap.
+ // The number of initialized spots is `pair.second - pair.first`. The number
+ // of raw spots is `n - (pair.second - pair.first)`.
+ //
+ // Updates the size of the InlinedVector internally.
+ std::pair<iterator, iterator> ShiftRight(const_iterator position,
+ size_type n) {
+ iterator start_used = const_cast<iterator>(position);
+ iterator start_raw = const_cast<iterator>(position);
+ size_type s = size();
+ size_type required_size = s + n;
+
+ if (required_size > capacity()) {
+ // Compute new capacity by repeatedly doubling current capacity
+ size_type new_capacity = capacity();
+ while (new_capacity < required_size) {
+ new_capacity <<= 1;
+ }
+ // Move everyone into the new allocation, leaving a gap of `n` for the
+ // requested shift.
+ Allocation new_allocation(allocator(), new_capacity);
+ size_type index = position - begin();
+ UninitializedCopy(std::make_move_iterator(data()),
+ std::make_move_iterator(data() + index),
+ new_allocation.buffer());
+ UninitializedCopy(std::make_move_iterator(data() + index),
+ std::make_move_iterator(data() + s),
+ new_allocation.buffer() + index + n);
+ ResetAllocation(new_allocation, s);
+
+ // New allocation means our iterator is invalid, so we'll recalculate.
+ // Since the entire gap is in new space, there's no used space to reuse.
+ start_raw = begin() + index;
+ start_used = start_raw;
+ } else {
+ // If we had enough space, it's a two-part move. Elements going into
+ // previously-unoccupied space need an `UninitializedCopy()`. Elements
+ // going into a previously-occupied space are just a `std::move()`.
+ iterator pos = const_cast<iterator>(position);
+ iterator raw_space = end();
+ size_type slots_in_used_space = raw_space - pos;
+ size_type new_elements_in_used_space = (std::min)(n, slots_in_used_space);
+ size_type new_elements_in_raw_space = n - new_elements_in_used_space;
+ size_type old_elements_in_used_space =
+ slots_in_used_space - new_elements_in_used_space;
+
+ UninitializedCopy(
+ std::make_move_iterator(pos + old_elements_in_used_space),
+ std::make_move_iterator(raw_space),
+ raw_space + new_elements_in_raw_space);
+ std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
+
+ // If the gap is entirely in raw space, the used space starts where the
+ // raw space starts, leaving no elements in used space. If the gap is
+ // entirely in used space, the raw space starts at the end of the gap,
+ // leaving all elements accounted for within the used space.
+ start_used = pos;
+ start_raw = pos + new_elements_in_used_space;
+ }
+ tag().add_size(n);
+ return std::make_pair(start_used, start_raw);
+ }
+
+ template <typename... Args>
+ reference GrowAndEmplaceBack(Args&&... args) {
assert(size() == capacity());
const size_type s = size();
Allocation new_allocation(allocator(), 2 * capacity());
- value_type& new_element =
+ reference new_element =
Construct(new_allocation.buffer() + s, std::forward<Args>(args)...);
UninitializedCopy(std::make_move_iterator(data()),
std::make_move_iterator(data() + s),
@@ -764,628 +1047,268 @@
return new_element;
}
- void InitAssign(size_type n);
- void InitAssign(size_type n, const value_type& t);
-
- template <typename... Args>
- value_type& Construct(pointer p, Args&&... args) {
- AllocatorTraits::construct(allocator(), p, std::forward<Args>(args)...);
- return *p;
+ void InitAssign(size_type n) {
+ if (n > N) {
+ Allocation new_allocation(allocator(), n);
+ init_allocation(new_allocation);
+ UninitializedFill(allocated_space(), allocated_space() + n);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space(), inlined_space() + n);
+ tag().set_inline_size(n);
+ }
}
- template <typename Iter>
- void UninitializedCopy(Iter src, Iter src_last, value_type* dst) {
- for (; src != src_last; ++dst, ++src) Construct(dst, *src);
+ void InitAssign(size_type n, const_reference v) {
+ if (n > N) {
+ Allocation new_allocation(allocator(), n);
+ init_allocation(new_allocation);
+ UninitializedFill(allocated_space(), allocated_space() + n, v);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space(), inlined_space() + n, v);
+ tag().set_inline_size(n);
+ }
}
- template <typename... Args>
- void UninitializedFill(value_type* dst, value_type* dst_last,
- const Args&... args) {
- for (; dst != dst_last; ++dst) Construct(dst, args...);
+ template <typename ForwardIt>
+ void AssignForwardRange(ForwardIt first, ForwardIt last) {
+ static_assert(IsAtLeastForwardIterator<ForwardIt>::value, "");
+
+ auto length = std::distance(first, last);
+
+ // Prefer reassignment to copy construction for elements.
+ if (static_cast<size_type>(length) <= size()) {
+ erase(std::copy(first, last, begin()), end());
+ return;
+ }
+
+ reserve(length);
+ iterator out = begin();
+ for (; out != end(); ++first, ++out) *out = *first;
+ if (allocated()) {
+ UninitializedCopy(first, last, out);
+ tag().set_allocated_size(length);
+ } else {
+ UninitializedCopy(first, last, out);
+ tag().set_inline_size(length);
+ }
}
- // Destroy [ptr, ptr_last) in place.
- void Destroy(value_type* ptr, value_type* ptr_last);
+ template <typename ForwardIt>
+ void AppendForwardRange(ForwardIt first, ForwardIt last) {
+ static_assert(IsAtLeastForwardIterator<ForwardIt>::value, "");
- template <typename Iter>
- void AppendRange(Iter first, Iter last, std::input_iterator_tag) {
- std::copy(first, last, std::back_inserter(*this));
- }
-
- // Faster path for forward iterators.
- template <typename Iter>
- void AppendRange(Iter first, Iter last, std::forward_iterator_tag);
-
- template <typename Iter>
- void AppendRange(Iter first, Iter last) {
- using IterTag = typename std::iterator_traits<Iter>::iterator_category;
- AppendRange(first, last, IterTag());
- }
-
- template <typename Iter>
- void AssignRange(Iter first, Iter last, std::input_iterator_tag);
-
- // Faster path for forward iterators.
- template <typename Iter>
- void AssignRange(Iter first, Iter last, std::forward_iterator_tag);
-
- template <typename Iter>
- void AssignRange(Iter first, Iter last) {
- using IterTag = typename std::iterator_traits<Iter>::iterator_category;
- AssignRange(first, last, IterTag());
+ auto length = std::distance(first, last);
+ reserve(size() + length);
+ if (allocated()) {
+ UninitializedCopy(first, last, allocated_space() + size());
+ tag().set_allocated_size(size() + length);
+ } else {
+ UninitializedCopy(first, last, inlined_space() + size());
+ tag().set_inline_size(size() + length);
+ }
}
iterator InsertWithCount(const_iterator position, size_type n,
- const value_type& v);
+ const_reference v) {
+ assert(position >= begin() && position <= end());
+ if (ABSL_PREDICT_FALSE(n == 0)) return const_cast<iterator>(position);
- template <typename InputIter>
- iterator InsertWithRange(const_iterator position, InputIter first,
- InputIter last, std::input_iterator_tag);
- template <typename ForwardIter>
- iterator InsertWithRange(const_iterator position, ForwardIter first,
- ForwardIter last, std::forward_iterator_tag);
+ value_type copy = v;
+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+ std::fill(it_pair.first, it_pair.second, copy);
+ UninitializedFill(it_pair.second, it_pair.first + n, copy);
- AllocatorAndTag allocator_and_tag_;
+ return it_pair.first;
+ }
- // Either the inlined or allocated representation
- union Rep {
- // Use struct to perform indirection that solves a bizarre compilation
- // error on Visual Studio (all known versions).
- struct {
- typename std::aligned_storage<sizeof(value_type),
- alignof(value_type)>::type inlined[N];
- } inlined_storage;
- struct {
- typename std::aligned_storage<sizeof(Allocation),
- alignof(Allocation)>::type allocation;
- } allocation_storage;
- } rep_;
+ template <typename ForwardIt>
+ iterator InsertWithForwardRange(const_iterator position, ForwardIt first,
+ ForwardIt last) {
+ static_assert(IsAtLeastForwardIterator<ForwardIt>::value, "");
+ assert(position >= begin() && position <= end());
+
+ if (ABSL_PREDICT_FALSE(first == last))
+ return const_cast<iterator>(position);
+
+ auto n = std::distance(first, last);
+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+ size_type used_spots = it_pair.second - it_pair.first;
+ auto open_spot = std::next(first, used_spots);
+ std::copy(first, open_spot, it_pair.first);
+ UninitializedCopy(open_spot, last, it_pair.second);
+ return it_pair.first;
+ }
+
+ void SwapImpl(InlinedVector& other) {
+ using std::swap; // Augment ADL with `std::swap`.
+
+ if (allocated() && other.allocated()) {
+ // Both out of line, so just swap the tag, allocation, and allocator.
+ swap(tag(), other.tag());
+ swap(allocation(), other.allocation());
+ swap(allocator(), other.allocator());
+ return;
+ }
+ if (!allocated() && !other.allocated()) {
+ // Both inlined: swap up to smaller size, then move remaining elements.
+ InlinedVector* a = this;
+ InlinedVector* b = &other;
+ if (size() < other.size()) {
+ swap(a, b);
+ }
+
+ const size_type a_size = a->size();
+ const size_type b_size = b->size();
+ assert(a_size >= b_size);
+ // `a` is larger. Swap the elements up to the smaller array size.
+ std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size,
+ b->inlined_space());
+
+ // Move the remaining elements:
+ // [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b`
+ b->UninitializedCopy(a->inlined_space() + b_size,
+ a->inlined_space() + a_size,
+ b->inlined_space() + b_size);
+ a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
+
+ swap(a->tag(), b->tag());
+ swap(a->allocator(), b->allocator());
+ assert(b->size() == a_size);
+ assert(a->size() == b_size);
+ return;
+ }
+
+ // One is out of line, one is inline.
+ // We first move the elements from the inlined vector into the
+ // inlined space in the other vector. We then put the other vector's
+ // pointer/capacity into the originally inlined vector and swap
+ // the tags.
+ InlinedVector* a = this;
+ InlinedVector* b = &other;
+ if (a->allocated()) {
+ swap(a, b);
+ }
+ assert(!a->allocated());
+ assert(b->allocated());
+ const size_type a_size = a->size();
+ const size_type b_size = b->size();
+ // In an optimized build, `b_size` would be unused.
+ static_cast<void>(b_size);
+
+ // Made Local copies of `size()`, don't need `tag()` accurate anymore
+ swap(a->tag(), b->tag());
+
+ // Copy `b_allocation` out before `b`'s union gets clobbered by
+ // `inline_space`
+ Allocation b_allocation = b->allocation();
+
+ b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
+ b->inlined_space());
+ a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
+
+ a->allocation() = b_allocation;
+
+ if (a->allocator() != b->allocator()) {
+ swap(a->allocator(), b->allocator());
+ }
+
+ assert(b->size() == a_size);
+ assert(a->size() == b_size);
+ }
+
+ Storage storage_;
};
// -----------------------------------------------------------------------------
// InlinedVector Non-Member Functions
// -----------------------------------------------------------------------------
-// swap()
+// `swap()`
//
// Swaps the contents of two inlined vectors. This convenience function
-// simply calls InlinedVector::swap(other_inlined_vector).
+// simply calls `InlinedVector::swap()`.
template <typename T, size_t N, typename A>
-void swap(InlinedVector<T, N, A>& a,
- InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+auto swap(InlinedVector<T, N, A>& a,
+ InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) -> void {
a.swap(b);
}
-// operator==()
+// `operator==()`
//
// Tests the equivalency of the contents of two inlined vectors.
template <typename T, size_t N, typename A>
-bool operator==(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator==(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) -> bool {
return absl::equal(a.begin(), a.end(), b.begin(), b.end());
}
-// operator!=()
+// `operator!=()`
//
// Tests the inequality of the contents of two inlined vectors.
template <typename T, size_t N, typename A>
-bool operator!=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator!=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) -> bool {
return !(a == b);
}
-// operator<()
+// `operator<()`
//
// Tests whether the contents of one inlined vector are less than the contents
// of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A>
-bool operator<(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
+ -> bool {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
-// operator>()
+// `operator>()`
//
// Tests whether the contents of one inlined vector are greater than the
// contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A>
-bool operator>(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
+ -> bool {
return b < a;
}
-// operator<=()
+// `operator<=()`
//
// Tests whether the contents of one inlined vector are less than or equal to
// the contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A>
-bool operator<=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator<=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) -> bool {
return !(b < a);
}
-// operator>=()
+// `operator>=()`
//
// Tests whether the contents of one inlined vector are greater than or equal to
// the contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A>
-bool operator>=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+auto operator>=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) -> bool {
return !(a < b);
}
+// AbslHashValue()
+//
+// Provides `absl::Hash` support for inlined vectors. You do not normally call
+// this function directly.
+template <typename H, typename TheT, size_t TheN, typename TheA>
+auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H {
+ auto p = v.data();
+ auto n = v.size();
+ return H::combine(H::combine_contiguous(std::move(h), p, n), n);
+}
+} // namespace absl
+
// -----------------------------------------------------------------------------
// Implementation of InlinedVector
-// -----------------------------------------------------------------------------
//
-// Do not depend on any implementation details below this line.
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v)
- : allocator_and_tag_(v.allocator()) {
- reserve(v.size());
- if (allocated()) {
- UninitializedCopy(v.begin(), v.end(), allocated_space());
- tag().set_allocated_size(v.size());
- } else {
- UninitializedCopy(v.begin(), v.end(), inlined_space());
- tag().set_inline_size(v.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v,
- const allocator_type& alloc)
- : allocator_and_tag_(alloc) {
- reserve(v.size());
- if (allocated()) {
- UninitializedCopy(v.begin(), v.end(), allocated_space());
- tag().set_allocated_size(v.size());
- } else {
- UninitializedCopy(v.begin(), v.end(), inlined_space());
- tag().set_inline_size(v.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(InlinedVector&& v) noexcept(
- absl::allocator_is_nothrow<allocator_type>::value ||
- std::is_nothrow_move_constructible<value_type>::value)
- : allocator_and_tag_(v.allocator_and_tag_) {
- if (v.allocated()) {
- // We can just steal the underlying buffer from the source.
- // That leaves the source empty, so we clear its size.
- init_allocation(v.allocation());
- v.tag() = Tag();
- } else {
- UninitializedCopy(std::make_move_iterator(v.inlined_space()),
- std::make_move_iterator(v.inlined_space() + v.size()),
- inlined_space());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(
- InlinedVector&& v,
- const allocator_type&
- alloc) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
- : allocator_and_tag_(alloc) {
- if (v.allocated()) {
- if (alloc == v.allocator()) {
- // We can just steal the allocation from the source.
- tag() = v.tag();
- init_allocation(v.allocation());
- v.tag() = Tag();
- } else {
- // We need to use our own allocator
- reserve(v.size());
- UninitializedCopy(std::make_move_iterator(v.begin()),
- std::make_move_iterator(v.end()), allocated_space());
- tag().set_allocated_size(v.size());
- }
- } else {
- UninitializedCopy(std::make_move_iterator(v.inlined_space()),
- std::make_move_iterator(v.inlined_space() + v.size()),
- inlined_space());
- tag().set_inline_size(v.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::InitAssign(size_type n, const value_type& t) {
- if (n > static_cast<size_type>(N)) {
- Allocation new_allocation(allocator(), n);
- init_allocation(new_allocation);
- UninitializedFill(allocated_space(), allocated_space() + n, t);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space(), inlined_space() + n, t);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::InitAssign(size_type n) {
- if (n > static_cast<size_type>(N)) {
- Allocation new_allocation(allocator(), n);
- init_allocation(new_allocation);
- UninitializedFill(allocated_space(), allocated_space() + n);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space(), inlined_space() + n);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::resize(size_type n) {
- size_type s = size();
- if (n < s) {
- erase(begin() + n, end());
- return;
- }
- reserve(n);
- assert(capacity() >= n);
-
- // Fill new space with elements constructed in-place.
- if (allocated()) {
- UninitializedFill(allocated_space() + s, allocated_space() + n);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space() + s, inlined_space() + n);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::resize(size_type n, const value_type& elem) {
- size_type s = size();
- if (n < s) {
- erase(begin() + n, end());
- return;
- }
- reserve(n);
- assert(capacity() >= n);
-
- // Fill new space with copies of 'elem'.
- if (allocated()) {
- UninitializedFill(allocated_space() + s, allocated_space() + n, elem);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space() + s, inlined_space() + n, elem);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-template <typename... Args>
-typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace(
- const_iterator position, Args&&... args) {
- assert(position >= begin());
- assert(position <= end());
- if (position == end()) {
- emplace_back(std::forward<Args>(args)...);
- return end() - 1;
- }
-
- T new_t = T(std::forward<Args>(args)...);
-
- auto range = ShiftRight(position, 1);
- if (range.first == range.second) {
- // constructing into uninitialized memory
- Construct(range.first, std::move(new_t));
- } else {
- // assigning into moved-from object
- *range.first = T(std::move(new_t));
- }
-
- return range.first;
-}
-
-template <typename T, size_t N, typename A>
-typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::erase(
- const_iterator first, const_iterator last) {
- assert(begin() <= first);
- assert(first <= last);
- assert(last <= end());
-
- iterator range_start = const_cast<iterator>(first);
- iterator range_end = const_cast<iterator>(last);
-
- size_type s = size();
- ptrdiff_t erase_gap = std::distance(range_start, range_end);
- if (erase_gap > 0) {
- pointer space;
- if (allocated()) {
- space = allocated_space();
- tag().set_allocated_size(s - erase_gap);
- } else {
- space = inlined_space();
- tag().set_inline_size(s - erase_gap);
- }
- std::move(range_end, space + s, range_start);
- Destroy(space + s - erase_gap, space + s);
- }
- return range_start;
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::swap(InlinedVector& other) {
- using std::swap; // Augment ADL with std::swap.
- if (&other == this) {
- return;
- }
- if (allocated() && other.allocated()) {
- // Both out of line, so just swap the tag, allocation, and allocator.
- swap(tag(), other.tag());
- swap(allocation(), other.allocation());
- swap(allocator(), other.allocator());
- return;
- }
- if (!allocated() && !other.allocated()) {
- // Both inlined: swap up to smaller size, then move remaining elements.
- InlinedVector* a = this;
- InlinedVector* b = &other;
- if (size() < other.size()) {
- swap(a, b);
- }
-
- const size_type a_size = a->size();
- const size_type b_size = b->size();
- assert(a_size >= b_size);
- // 'a' is larger. Swap the elements up to the smaller array size.
- std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size,
- b->inlined_space());
-
- // Move the remaining elements: A[b_size,a_size) -> B[b_size,a_size)
- b->UninitializedCopy(a->inlined_space() + b_size,
- a->inlined_space() + a_size,
- b->inlined_space() + b_size);
- a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
-
- swap(a->tag(), b->tag());
- swap(a->allocator(), b->allocator());
- assert(b->size() == a_size);
- assert(a->size() == b_size);
- return;
- }
- // One is out of line, one is inline.
- // We first move the elements from the inlined vector into the
- // inlined space in the other vector. We then put the other vector's
- // pointer/capacity into the originally inlined vector and swap
- // the tags.
- InlinedVector* a = this;
- InlinedVector* b = &other;
- if (a->allocated()) {
- swap(a, b);
- }
- assert(!a->allocated());
- assert(b->allocated());
- const size_type a_size = a->size();
- const size_type b_size = b->size();
- // In an optimized build, b_size would be unused.
- (void)b_size;
-
- // Made Local copies of size(), don't need tag() accurate anymore
- swap(a->tag(), b->tag());
-
- // Copy b_allocation out before b's union gets clobbered by inline_space.
- Allocation b_allocation = b->allocation();
-
- b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
- b->inlined_space());
- a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
-
- a->allocation() = b_allocation;
-
- if (a->allocator() != b->allocator()) {
- swap(a->allocator(), b->allocator());
- }
-
- assert(b->size() == a_size);
- assert(a->size() == b_size);
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::EnlargeBy(size_type delta) {
- const size_type s = size();
- assert(s <= capacity());
-
- size_type target = std::max(static_cast<size_type>(N), s + delta);
-
- // Compute new capacity by repeatedly doubling current capacity
- // TODO(psrc): Check and avoid overflow?
- size_type new_capacity = capacity();
- while (new_capacity < target) {
- new_capacity <<= 1;
- }
-
- Allocation new_allocation(allocator(), new_capacity);
-
- UninitializedCopy(std::make_move_iterator(data()),
- std::make_move_iterator(data() + s),
- new_allocation.buffer());
-
- ResetAllocation(new_allocation, s);
-}
-
-template <typename T, size_t N, typename A>
-auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n)
- -> std::pair<iterator, iterator> {
- iterator start_used = const_cast<iterator>(position);
- iterator start_raw = const_cast<iterator>(position);
- size_type s = size();
- size_type required_size = s + n;
-
- if (required_size > capacity()) {
- // Compute new capacity by repeatedly doubling current capacity
- size_type new_capacity = capacity();
- while (new_capacity < required_size) {
- new_capacity <<= 1;
- }
- // Move everyone into the new allocation, leaving a gap of n for the
- // requested shift.
- Allocation new_allocation(allocator(), new_capacity);
- size_type index = position - begin();
- UninitializedCopy(std::make_move_iterator(data()),
- std::make_move_iterator(data() + index),
- new_allocation.buffer());
- UninitializedCopy(std::make_move_iterator(data() + index),
- std::make_move_iterator(data() + s),
- new_allocation.buffer() + index + n);
- ResetAllocation(new_allocation, s);
-
- // New allocation means our iterator is invalid, so we'll recalculate.
- // Since the entire gap is in new space, there's no used space to reuse.
- start_raw = begin() + index;
- start_used = start_raw;
- } else {
- // If we had enough space, it's a two-part move. Elements going into
- // previously-unoccupied space need an UninitializedCopy. Elements
- // going into a previously-occupied space are just a move.
- iterator pos = const_cast<iterator>(position);
- iterator raw_space = end();
- size_type slots_in_used_space = raw_space - pos;
- size_type new_elements_in_used_space = std::min(n, slots_in_used_space);
- size_type new_elements_in_raw_space = n - new_elements_in_used_space;
- size_type old_elements_in_used_space =
- slots_in_used_space - new_elements_in_used_space;
-
- UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space),
- std::make_move_iterator(raw_space),
- raw_space + new_elements_in_raw_space);
- std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
-
- // If the gap is entirely in raw space, the used space starts where the raw
- // space starts, leaving no elements in used space. If the gap is entirely
- // in used space, the raw space starts at the end of the gap, leaving all
- // elements accounted for within the used space.
- start_used = pos;
- start_raw = pos + new_elements_in_used_space;
- }
- tag().add_size(n);
- return std::make_pair(start_used, start_raw);
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::Destroy(value_type* ptr, value_type* ptr_last) {
- for (value_type* p = ptr; p != ptr_last; ++p) {
- AllocatorTraits::destroy(allocator(), p);
- }
-
- // Overwrite unused memory with 0xab so we can catch uninitialized usage.
- // Cast to void* to tell the compiler that we don't care that we might be
- // scribbling on a vtable pointer.
-#ifndef NDEBUG
- if (ptr != ptr_last) {
- memset(reinterpret_cast<void*>(ptr), 0xab, sizeof(*ptr) * (ptr_last - ptr));
- }
-#endif
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iter>
-void InlinedVector<T, N, A>::AppendRange(Iter first, Iter last,
- std::forward_iterator_tag) {
- using Length = typename std::iterator_traits<Iter>::difference_type;
- Length length = std::distance(first, last);
- reserve(size() + length);
- if (allocated()) {
- UninitializedCopy(first, last, allocated_space() + size());
- tag().set_allocated_size(size() + length);
- } else {
- UninitializedCopy(first, last, inlined_space() + size());
- tag().set_inline_size(size() + length);
- }
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iter>
-void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
- std::input_iterator_tag) {
- // Optimized to avoid reallocation.
- // Prefer reassignment to copy construction for elements.
- iterator out = begin();
- for (; first != last && out != end(); ++first, ++out) {
- *out = *first;
- }
- erase(out, end());
- std::copy(first, last, std::back_inserter(*this));
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iter>
-void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
- std::forward_iterator_tag) {
- using Length = typename std::iterator_traits<Iter>::difference_type;
- Length length = std::distance(first, last);
- // Prefer reassignment to copy construction for elements.
- if (static_cast<size_type>(length) <= size()) {
- erase(std::copy(first, last, begin()), end());
- return;
- }
- reserve(length);
- iterator out = begin();
- for (; out != end(); ++first, ++out) *out = *first;
- if (allocated()) {
- UninitializedCopy(first, last, out);
- tag().set_allocated_size(length);
- } else {
- UninitializedCopy(first, last, out);
- tag().set_inline_size(length);
- }
-}
-
-template <typename T, size_t N, typename A>
-auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
- size_type n, const value_type& v)
- -> iterator {
- assert(position >= begin() && position <= end());
- if (n == 0) return const_cast<iterator>(position);
-
- value_type copy = v;
- std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
- std::fill(it_pair.first, it_pair.second, copy);
- UninitializedFill(it_pair.second, it_pair.first + n, copy);
-
- return it_pair.first;
-}
-
-template <typename T, size_t N, typename A>
-template <typename InputIter>
-auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
- InputIter first, InputIter last,
- std::input_iterator_tag)
- -> iterator {
- assert(position >= begin() && position <= end());
- size_type index = position - cbegin();
- size_type i = index;
- while (first != last) insert(begin() + i++, *first++);
- return begin() + index;
-}
-
-// Overload of InlinedVector::InsertWithRange()
-template <typename T, size_t N, typename A>
-template <typename ForwardIter>
-auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
- ForwardIter first,
- ForwardIter last,
- std::forward_iterator_tag)
- -> iterator {
- assert(position >= begin() && position <= end());
- if (first == last) {
- return const_cast<iterator>(position);
- }
- using Length = typename std::iterator_traits<ForwardIter>::difference_type;
- Length n = std::distance(first, last);
- std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
- size_type used_spots = it_pair.second - it_pair.first;
- ForwardIter open_spot = std::next(first, used_spots);
- std::copy(first, open_spot, it_pair.first);
- UninitializedCopy(open_spot, last, it_pair.second);
- return it_pair.first;
-}
-
-} // namespace absl
+// Do not depend on any below implementation details!
+// -----------------------------------------------------------------------------
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index a3ad0f8..867a29e 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,17 +23,13 @@
namespace {
-using IntVec = absl::InlinedVector<int, 8>;
-
void BM_InlinedVectorFill(benchmark::State& state) {
- const int len = state.range(0);
+ absl::InlinedVector<int, 8> v;
+ int val = 10;
for (auto _ : state) {
- IntVec v;
- for (int i = 0; i < len; i++) {
- v.push_back(i);
- }
+ benchmark::DoNotOptimize(v);
+ v.push_back(val);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
@@ -43,23 +39,25 @@
for (int i = 0; i < len; i++) {
ia[i] = i;
}
+ auto* from = ia.get();
+ auto* to = from + len;
for (auto _ : state) {
- IntVec v(ia.get(), ia.get() + len);
+ benchmark::DoNotOptimize(from);
+ benchmark::DoNotOptimize(to);
+ absl::InlinedVector<int, 8> v(from, to);
benchmark::DoNotOptimize(v);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
void BM_StdVectorFill(benchmark::State& state) {
- const int len = state.range(0);
+ std::vector<int> v;
+ int val = 10;
for (auto _ : state) {
- std::vector<int> v;
- for (int i = 0; i < len; i++) {
- v.push_back(i);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(val);
+ v.push_back(val);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
@@ -89,7 +87,7 @@
const int len = state.range(0);
const int no_sso = GetNonShortStringOptimizationSize();
std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
- std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+ std::string(no_sso, 'C'), std::string(no_sso, 'D')};
for (auto _ : state) {
absl::InlinedVector<std::string, 8> v;
@@ -105,7 +103,7 @@
const int len = state.range(0);
const int no_sso = GetNonShortStringOptimizationSize();
std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
- std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+ std::string(no_sso, 'C'), std::string(no_sso, 'D')};
for (auto _ : state) {
std::vector<std::string> v;
@@ -124,7 +122,7 @@
void* user_data;
};
-void BM_InlinedVectorTenAssignments(benchmark::State& state) {
+void BM_InlinedVectorAssignments(benchmark::State& state) {
const int len = state.range(0);
using BufferVec = absl::InlinedVector<Buffer, 2>;
@@ -133,18 +131,25 @@
BufferVec dst;
for (auto _ : state) {
- for (int i = 0; i < 10; ++i) {
- dst = src;
- }
+ benchmark::DoNotOptimize(dst);
+ benchmark::DoNotOptimize(src);
+ dst = src;
}
}
-BENCHMARK(BM_InlinedVectorTenAssignments)
- ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
+BENCHMARK(BM_InlinedVectorAssignments)
+ ->Arg(0)
+ ->Arg(1)
+ ->Arg(2)
+ ->Arg(3)
+ ->Arg(4)
+ ->Arg(20);
void BM_CreateFromContainer(benchmark::State& state) {
for (auto _ : state) {
- absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
- benchmark::DoNotOptimize(x);
+ absl::InlinedVector<int, 4> src{1, 2, 3};
+ benchmark::DoNotOptimize(src);
+ absl::InlinedVector<int, 4> dst(std::move(src));
+ benchmark::DoNotOptimize(dst);
}
}
BENCHMARK(BM_CreateFromContainer);
@@ -159,15 +164,14 @@
struct LargeCopyableSwappable {
LargeCopyableSwappable() : d(1024, 17) {}
+
LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
- LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
using std::swap;
swap(*this, o);
return *this;
}
- LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
using std::swap;
@@ -215,6 +219,8 @@
Vec b;
for (auto _ : state) {
using std::swap;
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
swap(a, b);
}
}
@@ -260,60 +266,44 @@
void BM_InlinedVectorIndexInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorIndexInlined);
void BM_InlinedVectorIndexExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorIndexExternal);
void BM_StdVectorIndex(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorIndex);
-#define UNROLL_2(x) \
- benchmark::DoNotOptimize(x); \
- benchmark::DoNotOptimize(x);
-
-#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
-#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
-#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
-
void BM_InlinedVectorDataInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorDataInlined);
void BM_InlinedVectorDataExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
@@ -322,7 +312,8 @@
void BM_StdVectorData(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
@@ -331,54 +322,54 @@
void BM_InlinedVectorSizeInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorSizeInlined);
void BM_InlinedVectorSizeExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorSizeExternal);
void BM_StdVectorSize(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorSize);
void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorEmptyInlined);
void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorEmptyExternal);
void BM_StdVectorEmpty(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorEmpty);
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 08dcd3e..6037001 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -30,6 +30,7 @@
#include "absl/base/internal/exception_testing.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
+#include "absl/container/internal/counting_allocator.h"
#include "absl/container/internal/test_instance_tracker.h"
#include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h"
@@ -37,6 +38,7 @@
namespace {
+using absl::container_internal::CountingAllocator;
using absl::test_internal::CopyableMovableInstance;
using absl::test_internal::CopyableOnlyInstance;
using absl::test_internal::InstanceTracker;
@@ -68,7 +70,7 @@
// test_instance_tracker.h.
template <typename T>
class InstanceTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(InstanceTest);
+TYPED_TEST_SUITE_P(InstanceTest);
// A simple reference counted class to make sure that the proper elements are
// destroyed in the erase(begin, end) test.
@@ -138,57 +140,6 @@
return v;
}
-// This is a stateful allocator, but the state lives outside of the
-// allocator (in whatever test is using the allocator). This is odd
-// but helps in tests where the allocator is propagated into nested
-// containers - that chain of allocators uses the same state and is
-// thus easier to query for aggregate allocation information.
-template <typename T>
-class CountingAllocator : public std::allocator<T> {
- public:
- using Alloc = std::allocator<T>;
- using pointer = typename Alloc::pointer;
- using size_type = typename Alloc::size_type;
-
- CountingAllocator() : bytes_used_(nullptr) {}
- explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
-
- template <typename U>
- CountingAllocator(const CountingAllocator<U>& x)
- : Alloc(x), bytes_used_(x.bytes_used_) {}
-
- pointer allocate(size_type n,
- std::allocator<void>::const_pointer hint = nullptr) {
- assert(bytes_used_ != nullptr);
- *bytes_used_ += n * sizeof(T);
- return Alloc::allocate(n, hint);
- }
-
- void deallocate(pointer p, size_type n) {
- Alloc::deallocate(p, n);
- assert(bytes_used_ != nullptr);
- *bytes_used_ -= n * sizeof(T);
- }
-
- template<typename U>
- class rebind {
- public:
- using other = CountingAllocator<U>;
- };
-
- friend bool operator==(const CountingAllocator& a,
- const CountingAllocator& b) {
- return a.bytes_used_ == b.bytes_used_;
- }
-
- friend bool operator!=(const CountingAllocator& a,
- const CountingAllocator& b) {
- return !(a == b);
- }
-
- int64_t* bytes_used_;
-};
-
TEST(IntVec, SimpleOps) {
for (int len = 0; len < 20; len++) {
IntVec v;
@@ -906,6 +857,8 @@
InstanceTracker tracker;
InstanceVec a, b;
const size_t inlined_capacity = a.capacity();
+ auto min_len = std::min(l1, l2);
+ auto max_len = std::max(l1, l2);
for (int i = 0; i < l1; i++) a.push_back(Instance(i));
for (int i = 0; i < l2; i++) b.push_back(Instance(100+i));
EXPECT_EQ(tracker.instances(), l1 + l2);
@@ -919,15 +872,15 @@
EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped.
EXPECT_EQ(tracker.moves(), 0);
} else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
- EXPECT_EQ(tracker.swaps(), std::min(l1, l2));
- // TODO(bsamwel): This should use moves when the type is movable.
- EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2));
+ EXPECT_EQ(tracker.swaps(), min_len);
+ EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
+ max_len - min_len);
} else {
// One is allocated and the other isn't. The allocation is transferred
// without copying elements, and the inlined instances are copied/moved.
EXPECT_EQ(tracker.swaps(), 0);
- // TODO(bsamwel): This should use moves when the type is movable.
- EXPECT_EQ(tracker.copies(), std::min(l1, l2));
+ EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
+ min_len);
}
EXPECT_EQ(l1, b.size());
@@ -1726,39 +1679,58 @@
std::scoped_allocator_adaptor<CountingAllocator<StdVector>>;
using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>;
+ // MSVC 2017's std::vector allocates different amounts of memory in debug
+ // versus opt mode.
+ int64_t test_allocated = 0;
+ StdVector v(CountingAllocator<int>{&test_allocated});
+ // The amount of memory allocated by a default constructed vector<int>
+ auto default_std_vec_allocated = test_allocated;
+ v.push_back(1);
+ // The amound of memory allocated by a copy-constructed vector<int> with one
+ // element.
+ int64_t one_element_std_vec_copy_allocated = test_allocated;
+
int64_t allocated = 0;
AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}});
EXPECT_EQ(allocated, 0);
// This default constructs a vector<int>, but the allocator should pass itself
- // into the vector<int>.
+ // into the vector<int>, so check allocation compared to that.
// The absl::InlinedVector does not allocate any memory.
- // The vector<int> does not allocate any memory.
+ // The vector<int> may allocate any memory.
+ auto expected = default_std_vec_allocated;
vec.resize(1);
- EXPECT_EQ(allocated, 0);
+ EXPECT_EQ(allocated, expected);
// We make vector<int> allocate memory.
// It must go through the allocator even though we didn't construct the
- // vector directly.
+ // vector directly. This assumes that vec[0] doesn't need to grow its
+ // allocation.
+ expected += sizeof(int);
vec[0].push_back(1);
- EXPECT_EQ(allocated, sizeof(int) * 1);
+ EXPECT_EQ(allocated, expected);
// Another allocating vector.
+ expected += one_element_std_vec_copy_allocated;
vec.push_back(vec[0]);
- EXPECT_EQ(allocated, sizeof(int) * 2);
+ EXPECT_EQ(allocated, expected);
// Overflow the inlined memory.
// The absl::InlinedVector will now allocate.
+ expected += sizeof(StdVector) * 8 + default_std_vec_allocated * 3;
vec.resize(5);
- EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8);
+ EXPECT_EQ(allocated, expected);
// Adding one more in external mode should also work.
+ expected += one_element_std_vec_copy_allocated;
vec.push_back(vec[0]);
- EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8);
+ EXPECT_EQ(allocated, expected);
- // And extending these should still work.
+ // And extending these should still work. This assumes that vec[0] does not
+ // need to grow its allocation.
+ expected += sizeof(int);
vec[0].push_back(1);
- EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8);
+ EXPECT_EQ(allocated, expected);
vec.clear();
EXPECT_EQ(allocated, 0);
@@ -1790,4 +1762,23 @@
}
}
+TEST(InlinedVectorTest, AbslHashValueWorks) {
+ using V = absl::InlinedVector<int, 4>;
+ std::vector<V> cases;
+
+ // Generate a variety of vectors some of these are small enough for the inline
+ // space but are stored out of line.
+ for (int i = 0; i < 10; ++i) {
+ V v;
+ for (int j = 0; j < i; ++j) {
+ v.push_back(j);
+ }
+ cases.push_back(v);
+ v.resize(i % 4);
+ cases.push_back(v);
+ }
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
} // anonymous namespace
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
new file mode 100644
index 0000000..b06e711
--- /dev/null
+++ b/absl/container/internal/common.h
@@ -0,0 +1,183 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+
+#include <cassert>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+namespace container_internal {
+
+template <class, class = void>
+struct IsTransparent : std::false_type {};
+template <class T>
+struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
+ : std::true_type {};
+
+template <bool is_transparent>
+struct KeyArg {
+ // Transparent. Forward `K`.
+ template <typename K, typename key_type>
+ using type = K;
+};
+
+template <>
+struct KeyArg<false> {
+ // Not transparent. Always use `key_type`.
+ template <typename K, typename key_type>
+ using type = key_type;
+};
+
+// The node_handle concept from C++17.
+// We specialize node_handle for sets and maps. node_handle_base holds the
+// common API of both.
+template <typename PolicyTraits, typename Alloc>
+class node_handle_base {
+ protected:
+ using slot_type = typename PolicyTraits::slot_type;
+
+ public:
+ using allocator_type = Alloc;
+
+ constexpr node_handle_base() {}
+ node_handle_base(node_handle_base&& other) noexcept {
+ *this = std::move(other);
+ }
+ ~node_handle_base() { destroy(); }
+ node_handle_base& operator=(node_handle_base&& other) noexcept {
+ destroy();
+ if (!other.empty()) {
+ alloc_ = other.alloc_;
+ PolicyTraits::transfer(alloc(), slot(), other.slot());
+ other.reset();
+ }
+ return *this;
+ }
+
+ bool empty() const noexcept { return !alloc_; }
+ explicit operator bool() const noexcept { return !empty(); }
+ allocator_type get_allocator() const { return *alloc_; }
+
+ protected:
+ friend struct CommonAccess;
+
+ node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
+ PolicyTraits::transfer(alloc(), slot(), s);
+ }
+
+ void destroy() {
+ if (!empty()) {
+ PolicyTraits::destroy(alloc(), slot());
+ reset();
+ }
+ }
+
+ void reset() {
+ assert(alloc_.has_value());
+ alloc_ = absl::nullopt;
+ }
+
+ slot_type* slot() const {
+ assert(!empty());
+ return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
+ }
+ allocator_type* alloc() { return std::addressof(*alloc_); }
+
+ private:
+ absl::optional<allocator_type> alloc_;
+ mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
+ slot_space_;
+};
+
+// For sets.
+template <typename Policy, typename PolicyTraits, typename Alloc,
+ typename = void>
+class node_handle : public node_handle_base<PolicyTraits, Alloc> {
+ using Base = typename node_handle::node_handle_base;
+
+ public:
+ using value_type = typename PolicyTraits::value_type;
+
+ constexpr node_handle() {}
+
+ value_type& value() const { return PolicyTraits::element(this->slot()); }
+
+ private:
+ friend struct CommonAccess;
+
+ node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
+};
+
+// For maps.
+template <typename Policy, typename PolicyTraits, typename Alloc>
+class node_handle<Policy, PolicyTraits, Alloc,
+ absl::void_t<typename Policy::mapped_type>>
+ : public node_handle_base<PolicyTraits, Alloc> {
+ using Base = typename node_handle::node_handle_base;
+
+ public:
+ using key_type = typename Policy::key_type;
+ using mapped_type = typename Policy::mapped_type;
+
+ constexpr node_handle() {}
+
+ auto key() const -> decltype(PolicyTraits::key(this->slot())) {
+ return PolicyTraits::key(this->slot());
+ }
+
+ mapped_type& mapped() const {
+ return PolicyTraits::value(&PolicyTraits::element(this->slot()));
+ }
+
+ private:
+ friend struct CommonAccess;
+
+ node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
+};
+
+// Provide access to non-public node-handle functions.
+struct CommonAccess {
+ template <typename Node>
+ static auto GetSlot(const Node& node) -> decltype(node.slot()) {
+ return node.slot();
+ }
+
+ template <typename Node>
+ static void Reset(Node* node) {
+ node->reset();
+ }
+
+ template <typename T, typename... Args>
+ static T Make(Args&&... args) {
+ return T(std::forward<Args>(args)...);
+ }
+};
+
+// Implement the insert_return_type<> concept of C++17.
+template <class Iterator, class NodeType>
+struct InsertReturnType {
+ Iterator position;
+ bool inserted;
+ NodeType node;
+};
+
+} // namespace container_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h
index cc52614..b9bd91a 100644
--- a/absl/container/internal/compressed_tuple.h
+++ b/absl/container/internal/compressed_tuple.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,7 +27,7 @@
// const T2& t2 = value.get<2>();
// ...
//
-// http://en.cppreference.com/w/cpp/language/ebo
+// https://en.cppreference.com/w/cpp/language/ebo
#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
@@ -89,8 +89,10 @@
T value;
constexpr Storage() = default;
explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
- constexpr const T& get() const { return value; }
- T& get() { return value; }
+ constexpr const T& get() const& { return value; }
+ T& get() & { return value; }
+ constexpr const T&& get() const&& { return absl::move(*this).value; }
+ T&& get() && { return std::move(*this).value; }
};
template <typename D, size_t I>
@@ -99,8 +101,10 @@
using T = internal_compressed_tuple::ElemT<D, I>;
constexpr Storage() = default;
explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
- constexpr const T& get() const { return *this; }
- T& get() { return *this; }
+ constexpr const T& get() const& { return *this; }
+ T& get() & { return *this; }
+ constexpr const T&& get() const&& { return absl::move(*this); }
+ T&& get() && { return std::move(*this); }
};
template <typename D, typename I>
@@ -137,7 +141,7 @@
// const T2& t2 = value.get<2>();
// ...
//
-// http://en.cppreference.com/w/cpp/language/ebo
+// https://en.cppreference.com/w/cpp/language/ebo
template <typename... Ts>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
: private internal_compressed_tuple::CompressedTupleImpl<
@@ -152,14 +156,26 @@
: CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
template <int I>
- ElemT<I>& get() {
+ ElemT<I>& get() & {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
}
template <int I>
- constexpr const ElemT<I>& get() const {
+ constexpr const ElemT<I>& get() const& {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
}
+
+ template <int I>
+ ElemT<I>&& get() && {
+ return std::move(*this)
+ .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
+ }
+
+ template <int I>
+ constexpr const ElemT<I>&& get() const&& {
+ return absl::move(*this)
+ .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
+ }
};
// Explicit specialization for a zero-element tuple
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 45030c6..28e7741 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,17 +14,25 @@
#include "absl/container/internal/compressed_tuple.h"
+#include <memory>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+#include "absl/utility/utility.h"
namespace absl {
namespace container_internal {
namespace {
+enum class CallType { kConstRef, kConstMove };
+
template <int>
-struct Empty {};
+struct Empty {
+ constexpr CallType value() const& { return CallType::kConstRef; }
+ constexpr CallType value() const&& { return CallType::kConstMove; }
+};
template <typename T>
struct NotEmpty {
@@ -140,15 +148,44 @@
EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
}
+TEST(CompressedTupleTest, MoveOnlyElements) {
+ CompressedTuple<std::unique_ptr<std::string>> str_tup(
+ absl::make_unique<std::string>("str"));
+
+ CompressedTuple<CompressedTuple<std::unique_ptr<std::string>>,
+ std::unique_ptr<int>>
+ x(std::move(str_tup), absl::make_unique<int>(5));
+
+ EXPECT_EQ(*x.get<0>().get<0>(), "str");
+ EXPECT_EQ(*x.get<1>(), 5);
+
+ std::unique_ptr<std::string> x0 = std::move(x.get<0>()).get<0>();
+ std::unique_ptr<int> x1 = std::move(x).get<1>();
+
+ EXPECT_EQ(*x0, "str");
+ EXPECT_EQ(*x1, 5);
+}
+
TEST(CompressedTupleTest, Constexpr) {
- constexpr CompressedTuple<int, double, CompressedTuple<int>> x(
- 7, 1.25, CompressedTuple<int>(5));
+ constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x(
+ 7, 1.25, CompressedTuple<int>(5), {});
constexpr int x0 = x.get<0>();
constexpr double x1 = x.get<1>();
constexpr int x2 = x.get<2>().get<0>();
+ constexpr CallType x3 = x.get<3>().value();
+
EXPECT_EQ(x0, 7);
EXPECT_EQ(x1, 1.25);
EXPECT_EQ(x2, 5);
+ EXPECT_EQ(x3, CallType::kConstRef);
+
+#if defined(__clang__)
+ // An apparent bug in earlier versions of gcc claims these are ambiguous.
+ constexpr int x2m = absl::move(x.get<2>()).get<0>();
+ constexpr CallType x3m = absl::move(x).get<3>().value();
+ EXPECT_EQ(x2m, 5);
+ EXPECT_EQ(x3m, CallType::kConstMove);
+#endif
}
#if defined(__clang__) || defined(__GNUC__)
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index 56c5d2d..e5bb977 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -286,13 +286,48 @@
} // namespace memory_internal
-// If kMutableKeys is false, only the value member is accessed.
+// The internal storage type for key-value containers like flat_hash_map.
//
-// If kMutableKeys is true, key is accessed through all slots while value and
-// mutable_value are accessed only via INITIALIZED slots. Slots are created and
-// destroyed via mutable_value so that the key can be moved later.
+// It is convenient for the value_type of a flat_hash_map<K, V> to be
+// pair<const K, V>; the "const K" prevents accidental modification of the key
+// when dealing with the reference returned from find() and similar methods.
+// However, this creates other problems; we want to be able to emplace(K, V)
+// efficiently with move operations, and similarly be able to move a
+// pair<K, V> in insert().
+//
+// The solution is this union, which aliases the const and non-const versions
+// of the pair. This also allows flat_hash_map<const K, V> to work, even though
+// that has the same efficiency issues with move in emplace() and insert() -
+// but people do it anyway.
+//
+// If kMutableKeys is false, only the value member can be accessed.
+//
+// If kMutableKeys is true, key can be accessed through all slots while value
+// and mutable_value must be accessed only via INITIALIZED slots. Slots are
+// created and destroyed via mutable_value so that the key can be moved later.
+//
+// Accessing one of the union fields while the other is active is safe as
+// long as they are layout-compatible, which is guaranteed by the definition of
+// kMutableKeys. For C++11, the relevant section of the standard is
+// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
template <class K, class V>
-union slot_type {
+union map_slot_type {
+ map_slot_type() {}
+ ~map_slot_type() = delete;
+ using value_type = std::pair<const K, V>;
+ using mutable_value_type = std::pair<K, V>;
+
+ value_type value;
+ mutable_value_type mutable_value;
+ K key;
+};
+
+template <class K, class V>
+struct map_slot_policy {
+ using slot_type = map_slot_type<K, V>;
+ using value_type = std::pair<const K, V>;
+ using mutable_value_type = std::pair<K, V>;
+
private:
static void emplace(slot_type* slot) {
// The construction of union doesn't do anything at runtime but it allows us
@@ -302,19 +337,17 @@
// If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
// or the other via slot_type. We are also free to access the key via
// slot_type::key in this case.
- using kMutableKeys =
- std::integral_constant<bool,
- memory_internal::IsLayoutCompatible<K, V>::value>;
+ using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
public:
- slot_type() {}
- ~slot_type() = delete;
- using value_type = std::pair<const K, V>;
- using mutable_value_type = std::pair<K, V>;
+ static value_type& element(slot_type* slot) { return slot->value; }
+ static const value_type& element(const slot_type* slot) {
+ return slot->value;
+ }
- value_type value;
- mutable_value_type mutable_value;
- K key;
+ static const K& key(const slot_type* slot) {
+ return kMutableKeys::value ? slot->key : slot->value.first;
+ }
template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index f1c4058..d6b0495 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/counting_allocator.h b/absl/container/internal/counting_allocator.h
new file mode 100644
index 0000000..4e717be
--- /dev/null
+++ b/absl/container/internal/counting_allocator.h
@@ -0,0 +1,79 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+
+#include <cassert>
+#include <cstdint>
+#include <memory>
+
+namespace absl {
+namespace container_internal {
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator : public std::allocator<T> {
+ public:
+ using Alloc = std::allocator<T>;
+ using pointer = typename Alloc::pointer;
+ using size_type = typename Alloc::size_type;
+
+ CountingAllocator() : bytes_used_(nullptr) {}
+ explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+
+ template <typename U>
+ CountingAllocator(const CountingAllocator<U>& x)
+ : Alloc(x), bytes_used_(x.bytes_used_) {}
+
+ pointer allocate(size_type n,
+ std::allocator<void>::const_pointer hint = nullptr) {
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ += n * sizeof(T);
+ return Alloc::allocate(n, hint);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ Alloc::deallocate(p, n);
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ -= n * sizeof(T);
+ }
+
+ template<typename U>
+ class rebind {
+ public:
+ using other = CountingAllocator<U>;
+ };
+
+ friend bool operator==(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return a.bytes_used_ == b.bytes_used_;
+ }
+
+ friend bool operator!=(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return !(a == b);
+ }
+
+ int64_t* bytes_used_;
+};
+
+} // namespace container_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h
index 1f0d794..cb8f03c 100644
--- a/absl/container/internal/hash_function_defaults.h
+++ b/absl/container/internal/hash_function_defaults.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -39,8 +39,8 @@
// equal functions are still bound to T. This is important because some type U
// can be hashed by/tested for equality differently depending on T. A notable
// example is `const char*`. `const char*` is treated as a c-style string when
-// the hash function is hash<string> but as a pointer when the hash function is
-// hash<void*>.
+// the hash function is hash<std::string> but as a pointer when the hash
+// function is hash<void*>.
//
#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
@@ -83,6 +83,7 @@
}
};
};
+
template <>
struct HashEq<std::string> : StringHashEq {};
template <>
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc
index 464baae..82708db 100644
--- a/absl/container/internal/hash_function_defaults_test.cc
+++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -77,14 +77,14 @@
hash_default_eq<T> key_eq;
};
-TYPED_TEST_CASE(EqString, StringTypes);
+TYPED_TEST_SUITE(EqString, StringTypes);
template <class T>
struct HashString : ::testing::Test {
hash_default_hash<T> hasher;
};
-TYPED_TEST_CASE(HashString, StringTypes);
+TYPED_TEST_SUITE(HashString, StringTypes);
TYPED_TEST(EqString, Works) {
auto eq = this->key_eq;
@@ -121,14 +121,14 @@
hash_default_eq<T> key_eq;
};
-TYPED_TEST_CASE(EqPointer, PointerTypes);
+TYPED_TEST_SUITE(EqPointer, PointerTypes);
template <class T>
struct HashPointer : ::testing::Test {
hash_default_hash<T> hasher;
};
-TYPED_TEST_CASE(HashPointer, PointerTypes);
+TYPED_TEST_SUITE(HashPointer, PointerTypes);
TYPED_TEST(EqPointer, Works) {
int dummy;
@@ -202,15 +202,11 @@
EXPECT_NE(hash(&dummy), hash(cuptr));
}
-// Cartesian product of (string, std::string, absl::string_view)
-// with (string, std::string, absl::string_view, const char*).
+// Cartesian product of (std::string, absl::string_view)
+// with (std::string, absl::string_view, const char*).
using StringTypesCartesianProduct = Types<
// clang-format off
- std::pair<std::string, std::string>,
- std::pair<std::string, absl::string_view>,
- std::pair<std::string, const char*>,
-
std::pair<absl::string_view, std::string>,
std::pair<absl::string_view, absl::string_view>,
std::pair<absl::string_view, const char*>>;
@@ -248,7 +244,7 @@
EXPECT_NE(this->hash(this->a1), this->hash(this->b2));
}
-TYPED_TEST_CASE(StringLikeTest, StringTypesCartesianProduct);
+TYPED_TEST_SUITE(StringLikeTest, StringTypesCartesianProduct);
} // namespace
} // namespace container_internal
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index 0d6a9df..37a23d6 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -39,9 +39,9 @@
} // namespace
-std::mt19937_64* GetThreadLocalRng() {
+std::mt19937_64* GetSharedRng() {
RandomDeviceSeedSeq seed_seq;
- thread_local auto* rng = new std::mt19937_64(seed_seq);
+ static auto* rng = new std::mt19937_64(seed_seq);
return rng;
}
@@ -51,7 +51,7 @@
std::string res;
res.resize(32);
std::generate(res.begin(), res.end(),
- [&]() { return chars(*GetThreadLocalRng()); });
+ [&]() { return chars(*GetSharedRng()); });
return res;
}
@@ -63,7 +63,7 @@
auto& res = arena->back();
res.resize(32);
std::generate(res.begin(), res.end(),
- [&]() { return chars(*GetThreadLocalRng()); });
+ [&]() { return chars(*GetSharedRng()); });
return res;
}
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h
index 50d7710..27fb84f 100644
--- a/absl/container/internal/hash_generator_testing.h
+++ b/absl/container/internal/hash_generator_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -43,7 +43,7 @@
} // namespace generator_internal
-std::mt19937_64* GetThreadLocalRng();
+std::mt19937_64* GetSharedRng();
enum Enum {
kEnumEmpty,
@@ -66,7 +66,7 @@
struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> {
T operator()() const {
std::uniform_int_distribution<T> dist;
- return dist(*GetThreadLocalRng());
+ return dist(*GetSharedRng());
}
};
@@ -76,7 +76,7 @@
std::uniform_int_distribution<typename std::underlying_type<Enum>::type>
dist;
while (true) {
- auto variate = dist(*GetThreadLocalRng());
+ auto variate = dist(*GetSharedRng());
if (variate != kEnumEmpty && variate != kEnumDeleted)
return static_cast<Enum>(variate);
}
@@ -90,7 +90,7 @@
typename std::underlying_type<EnumClass>::type>
dist;
while (true) {
- EnumClass variate = static_cast<EnumClass>(dist(*GetThreadLocalRng()));
+ EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng()));
if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted)
return static_cast<EnumClass>(variate);
}
diff --git a/absl/container/internal/hash_policy_testing.h b/absl/container/internal/hash_policy_testing.h
index ffc76ea..c57407a 100644
--- a/absl/container/internal/hash_policy_testing.h
+++ b/absl/container/internal/hash_policy_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -139,7 +139,7 @@
friend bool operator!=(const Alloc& a, const Alloc& b) { return !(a == b); }
private:
- size_t id_ = std::numeric_limits<size_t>::max();
+ size_t id_ = (std::numeric_limits<size_t>::max)();
};
template <class Map>
@@ -169,7 +169,11 @@
// take allocator arguments. This test is defined ad-hoc for the platforms
// we care about (notably Crosstool 17) because libstdcxx's useless
// versioning scheme precludes a more principled solution.
-#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425
+// From GCC-4.9 Changelog: (src: https://gcc.gnu.org/gcc-4.9/changes.html)
+// "the unordered associative containers in <unordered_map> and <unordered_set>
+// meet the allocator-aware container requirements;"
+#if (defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425 ) || \
+( __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9 ))
#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0
#else
#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1
diff --git a/absl/container/internal/hash_policy_testing_test.cc b/absl/container/internal/hash_policy_testing_test.cc
index c215c42..0c95eb5 100644
--- a/absl/container/internal/hash_policy_testing_test.cc
+++ b/absl/container/internal/hash_policy_testing_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h
index 029e47e..fd007de 100644
--- a/absl/container/internal/hash_policy_traits.h
+++ b/absl/container/internal/hash_policy_traits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -84,7 +84,7 @@
}
// Transfers the `old_slot` to `new_slot`. Any memory allocated by the
- // allocator inside `old_slot` to `new_slot` can be transfered.
+ // allocator inside `old_slot` to `new_slot` can be transferred.
//
// OPTIONAL: defaults to:
//
diff --git a/absl/container/internal/hash_policy_traits_test.cc b/absl/container/internal/hash_policy_traits_test.cc
index 423f154..e643d18 100644
--- a/absl/container/internal/hash_policy_traits_test.cc
+++ b/absl/container/internal/hash_policy_traits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/hashtable_debug.h b/absl/container/internal/hashtable_debug.h
index c3bd65c..7193000 100644
--- a/absl/container/internal/hashtable_debug.h
+++ b/absl/container/internal/hashtable_debug.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -60,7 +60,7 @@
size_t num_probes = GetHashtableDebugNumProbes(
container,
absl::container_internal::hashtable_debug_internal::GetKey<C>(*it, 0));
- v.resize(std::max(v.size(), num_probes + 1));
+ v.resize((std::max)(v.size(), num_probes + 1));
v[num_probes]++;
}
return v;
diff --git a/absl/container/internal/hashtable_debug_hooks.h b/absl/container/internal/hashtable_debug_hooks.h
index 8f21972..371ce81 100644
--- a/absl/container/internal/hashtable_debug_hooks.h
+++ b/absl/container/internal/hashtable_debug_hooks.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
new file mode 100644
index 0000000..6667d3a
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -0,0 +1,308 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include <atomic>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/memory/memory.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace container_internal {
+constexpr int HashtablezInfo::kMaxStackDepth;
+
+namespace {
+ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
+ false
+};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
+
+// Returns the next pseudo-random value.
+// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
+// This is the lrand64 generator.
+uint64_t NextRandom(uint64_t rnd) {
+ const uint64_t prng_mult = uint64_t{0x5DEECE66D};
+ const uint64_t prng_add = 0xB;
+ const uint64_t prng_mod_power = 48;
+ const uint64_t prng_mod_mask = ~(~uint64_t{0} << prng_mod_power);
+ return (prng_mult * rnd + prng_add) & prng_mod_mask;
+}
+
+// Generates a geometric variable with the specified mean.
+// This is done by generating a random number between 0 and 1 and applying
+// the inverse cumulative distribution function for an exponential.
+// Specifically: Let m be the inverse of the sample period, then
+// the probability distribution function is m*exp(-mx) so the CDF is
+// p = 1 - exp(-mx), so
+// q = 1 - p = exp(-mx)
+// log_e(q) = -mx
+// -log_e(q)/m = x
+// log_2(q) * (-log_e(2) * 1/m) = x
+// In the code, q is actually in the range 1 to 2**26, hence the -26 below
+//
+int64_t GetGeometricVariable(int64_t mean) {
+#if ABSL_HAVE_THREAD_LOCAL
+ thread_local
+#else // ABSL_HAVE_THREAD_LOCAL
+ // SampleSlow and hence GetGeometricVariable is guarded by a single mutex when
+ // there are not thread locals. Thus, a single global rng is acceptable for
+ // that case.
+ static
+#endif // ABSL_HAVE_THREAD_LOCAL
+ uint64_t rng = []() {
+ // We don't get well distributed numbers from this so we call
+ // NextRandom() a bunch to mush the bits around. We use a global_rand
+ // to handle the case where the same thread (by memory address) gets
+ // created and destroyed repeatedly.
+ ABSL_CONST_INIT static std::atomic<uint32_t> global_rand(0);
+ uint64_t r = reinterpret_cast<uint64_t>(&rng) +
+ global_rand.fetch_add(1, std::memory_order_relaxed);
+ for (int i = 0; i < 20; ++i) {
+ r = NextRandom(r);
+ }
+ return r;
+ }();
+
+ rng = NextRandom(rng);
+
+ // Take the top 26 bits as the random number
+ // (This plus the 1<<58 sampling bound give a max possible step of
+ // 5194297183973780480 bytes.)
+ const uint64_t prng_mod_power = 48; // Number of bits in prng
+ // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
+ // under piii debug for some binaries.
+ double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0;
+ // Put the computed p-value through the CDF of a geometric.
+ double interval = (log2(q) - 26) * (-std::log(2.0) * mean);
+
+ // Very large values of interval overflow int64_t. If we happen to
+ // hit such improbable condition, we simply cheat and clamp interval
+ // to largest supported value.
+ if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
+ return std::numeric_limits<int64_t>::max() / 2;
+ }
+
+ // Small values of interval are equivalent to just sampling next time.
+ if (interval < 1) {
+ return 1;
+ }
+ return static_cast<int64_t>(interval);
+}
+
+} // namespace
+
+HashtablezSampler& HashtablezSampler::Global() {
+ static auto* sampler = new HashtablezSampler();
+ return *sampler;
+}
+
+HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback(
+ DisposeCallback f) {
+ return dispose_.exchange(f, std::memory_order_relaxed);
+}
+
+HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
+HashtablezInfo::~HashtablezInfo() = default;
+
+void HashtablezInfo::PrepareForSampling() {
+ capacity.store(0, std::memory_order_relaxed);
+ size.store(0, std::memory_order_relaxed);
+ num_erases.store(0, std::memory_order_relaxed);
+ max_probe_length.store(0, std::memory_order_relaxed);
+ total_probe_length.store(0, std::memory_order_relaxed);
+ hashes_bitwise_or.store(0, std::memory_order_relaxed);
+ hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
+
+ create_time = absl::Now();
+ // The inliner makes hardcoded skip_count difficult (especially when combined
+ // with LTO). We use the ability to exclude stacks by regex when encoding
+ // instead.
+ depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
+ /* skip_count= */ 0);
+ dead = nullptr;
+}
+
+HashtablezSampler::HashtablezSampler()
+ : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) {
+ absl::MutexLock l(&graveyard_.init_mu);
+ graveyard_.dead = &graveyard_;
+}
+
+HashtablezSampler::~HashtablezSampler() {
+ HashtablezInfo* s = all_.load(std::memory_order_acquire);
+ while (s != nullptr) {
+ HashtablezInfo* next = s->next;
+ delete s;
+ s = next;
+ }
+}
+
+void HashtablezSampler::PushNew(HashtablezInfo* sample) {
+ sample->next = all_.load(std::memory_order_relaxed);
+ while (!all_.compare_exchange_weak(sample->next, sample,
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ }
+}
+
+void HashtablezSampler::PushDead(HashtablezInfo* sample) {
+ if (auto* dispose = dispose_.load(std::memory_order_relaxed)) {
+ dispose(*sample);
+ }
+
+ absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+ absl::MutexLock sample_lock(&sample->init_mu);
+ sample->dead = graveyard_.dead;
+ graveyard_.dead = sample;
+}
+
+HashtablezInfo* HashtablezSampler::PopDead() {
+ absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+
+ // The list is circular, so eventually it collapses down to
+ // graveyard_.dead == &graveyard_
+ // when it is empty.
+ HashtablezInfo* sample = graveyard_.dead;
+ if (sample == &graveyard_) return nullptr;
+
+ absl::MutexLock sample_lock(&sample->init_mu);
+ graveyard_.dead = sample->dead;
+ sample->PrepareForSampling();
+ return sample;
+}
+
+HashtablezInfo* HashtablezSampler::Register() {
+ int64_t size = size_estimate_.fetch_add(1, std::memory_order_relaxed);
+ if (size > g_hashtablez_max_samples.load(std::memory_order_relaxed)) {
+ size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+ dropped_samples_.fetch_add(1, std::memory_order_relaxed);
+ return nullptr;
+ }
+
+ HashtablezInfo* sample = PopDead();
+ if (sample == nullptr) {
+ // Resurrection failed. Hire a new warlock.
+ sample = new HashtablezInfo();
+ PushNew(sample);
+ }
+
+ return sample;
+}
+
+void HashtablezSampler::Unregister(HashtablezInfo* sample) {
+ PushDead(sample);
+ size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+}
+
+int64_t HashtablezSampler::Iterate(
+ const std::function<void(const HashtablezInfo& stack)>& f) {
+ HashtablezInfo* s = all_.load(std::memory_order_acquire);
+ while (s != nullptr) {
+ absl::MutexLock l(&s->init_mu);
+ if (s->dead == nullptr) {
+ f(*s);
+ }
+ s = s->next;
+ }
+
+ return dropped_samples_.load(std::memory_order_relaxed);
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample) {
+ if (kAbslContainerInternalSampleEverything) {
+ *next_sample = 1;
+ return HashtablezSampler::Global().Register();
+ }
+
+ bool first = *next_sample < 0;
+ *next_sample = GetGeometricVariable(
+ g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
+
+ // g_hashtablez_enabled can be dynamically flipped, we need to set a threshold
+ // low enough that we will start sampling in a reasonable time, so we just use
+ // the default sampling rate.
+ if (!g_hashtablez_enabled.load(std::memory_order_relaxed)) return nullptr;
+
+ // We will only be negative on our first count, so we should just retry in
+ // that case.
+ if (first) {
+ if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+ return SampleSlow(next_sample);
+ }
+
+ return HashtablezSampler::Global().Register();
+}
+
+#if ABSL_PER_THREAD_TLS == 1
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
+#endif // ABSL_PER_THREAD_TLS == 1
+
+void UnsampleSlow(HashtablezInfo* info) {
+ HashtablezSampler::Global().Unregister(info);
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+ size_t distance_from_desired) {
+ // SwissTables probe in groups of 16, so scale this to count items probes and
+ // not offset from desired.
+ size_t probe_length = distance_from_desired;
+#if SWISSTABLE_HAVE_SSE2
+ probe_length /= 16;
+#else
+ probe_length /= 8;
+#endif
+
+ info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
+ info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
+ info->max_probe_length.store(
+ std::max(info->max_probe_length.load(std::memory_order_relaxed),
+ probe_length),
+ std::memory_order_relaxed);
+ info->total_probe_length.fetch_add(probe_length, std::memory_order_relaxed);
+ info->size.fetch_add(1, std::memory_order_relaxed);
+}
+
+void SetHashtablezEnabled(bool enabled) {
+ g_hashtablez_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetHashtablezSampleParameter(int32_t rate) {
+ if (rate > 0) {
+ g_hashtablez_sample_parameter.store(rate, std::memory_order_release);
+ } else {
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez sample rate: %lld",
+ static_cast<long long>(rate)); // NOLINT(runtime/int)
+ }
+}
+
+void SetHashtablezMaxSamples(int32_t max) {
+ if (max > 0) {
+ g_hashtablez_max_samples.store(max, std::memory_order_release);
+ } else {
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: %lld",
+ static_cast<long long>(max)); // NOLINT(runtime/int)
+ }
+}
+
+} // namespace container_internal
+} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
new file mode 100644
index 0000000..a308e78
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -0,0 +1,288 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: hashtablez_sampler.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the API for a low level library to sample hashtables
+// and collect runtime statistics about them.
+//
+// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
+// store information about a single sample.
+//
+// `Record*` methods store information into samples.
+// `Sample()` and `Unsample()` make use of a single global sampler with
+// properties controlled by the flags hashtablez_enabled,
+// hashtablez_sample_rate, and hashtablez_max_samples.
+//
+// WARNING
+//
+// Using this sampling API may cause sampled Swiss tables to use the global
+// allocator (operator `new`) in addition to any custom allocator. If you
+// are using a table in an unusual circumstance where allocation or calling a
+// linux syscall is unacceptable, this could interfere.
+//
+// This utility is internal-only. Use at your own risk.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+namespace container_internal {
+
+// Stores information about a sampled hashtable. All mutations to this *must*
+// be made through `Record*` functions below. All reads from this *must* only
+// occur in the callback to `HashtablezSampler::Iterate`.
+struct HashtablezInfo {
+ // Constructs the object but does not fill in any fields.
+ HashtablezInfo();
+ ~HashtablezInfo();
+ HashtablezInfo(const HashtablezInfo&) = delete;
+ HashtablezInfo& operator=(const HashtablezInfo&) = delete;
+
+ // Puts the object into a clean state, fills in the logically `const` members,
+ // blocking for any readers that are currently sampling the object.
+ void PrepareForSampling() EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+ // These fields are mutated by the various Record* APIs and need to be
+ // thread-safe.
+ std::atomic<size_t> capacity;
+ std::atomic<size_t> size;
+ std::atomic<size_t> num_erases;
+ std::atomic<size_t> max_probe_length;
+ std::atomic<size_t> total_probe_length;
+ std::atomic<size_t> hashes_bitwise_or;
+ std::atomic<size_t> hashes_bitwise_and;
+
+ // `HashtablezSampler` maintains intrusive linked lists for all samples. See
+ // comments on `HashtablezSampler::all_` for details on these. `init_mu`
+ // guards the ability to restore the sample to a pristine state. This
+ // prevents races with sampling and resurrecting an object.
+ absl::Mutex init_mu;
+ HashtablezInfo* next;
+ HashtablezInfo* dead GUARDED_BY(init_mu);
+
+ // All of the fields below are set by `PrepareForSampling`, they must not be
+ // mutated in `Record*` functions. They are logically `const` in that sense.
+ // These are guarded by init_mu, but that is not externalized to clients, who
+ // can only read them during `HashtablezSampler::Iterate` which will hold the
+ // lock.
+ static constexpr int kMaxStackDepth = 64;
+ absl::Time create_time;
+ int32_t depth;
+ void* stack[kMaxStackDepth];
+};
+
+inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
+#if SWISSTABLE_HAVE_SSE2
+ total_probe_length /= 16;
+#else
+ total_probe_length /= 8;
+#endif
+ info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
+ info->num_erases.store(0, std::memory_order_relaxed);
+}
+
+inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
+ size_t capacity) {
+ info->size.store(size, std::memory_order_relaxed);
+ info->capacity.store(capacity, std::memory_order_relaxed);
+ if (size == 0) {
+ // This is a clear, reset the total/num_erases too.
+ RecordRehashSlow(info, 0);
+ }
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+ size_t distance_from_desired);
+
+inline void RecordEraseSlow(HashtablezInfo* info) {
+ info->size.fetch_sub(1, std::memory_order_relaxed);
+ info->num_erases.fetch_add(1, std::memory_order_relaxed);
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(HashtablezInfo* info);
+
+class HashtablezInfoHandle {
+ public:
+ explicit HashtablezInfoHandle() : info_(nullptr) {}
+ explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
+ ~HashtablezInfoHandle() {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ UnsampleSlow(info_);
+ }
+
+ HashtablezInfoHandle(const HashtablezInfoHandle&) = delete;
+ HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;
+
+ HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept
+ : info_(absl::exchange(o.info_, nullptr)) {}
+ HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept {
+ if (ABSL_PREDICT_FALSE(info_ != nullptr)) {
+ UnsampleSlow(info_);
+ }
+ info_ = absl::exchange(o.info_, nullptr);
+ return *this;
+ }
+
+ inline void RecordStorageChanged(size_t size, size_t capacity) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordStorageChangedSlow(info_, size, capacity);
+ }
+
+ inline void RecordRehash(size_t total_probe_length) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordRehashSlow(info_, total_probe_length);
+ }
+
+ inline void RecordInsert(size_t hash, size_t distance_from_desired) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordInsertSlow(info_, hash, distance_from_desired);
+ }
+
+ inline void RecordErase() {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordEraseSlow(info_);
+ }
+
+ friend inline void swap(HashtablezInfoHandle& lhs,
+ HashtablezInfoHandle& rhs) {
+ std::swap(lhs.info_, rhs.info_);
+ }
+
+ private:
+ friend class HashtablezInfoHandlePeer;
+ HashtablezInfo* info_;
+};
+
+#if ABSL_PER_THREAD_TLS == 1
+extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
+#endif // ABSL_PER_THREAD_TLS
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline HashtablezInfoHandle Sample() {
+#if ABSL_PER_THREAD_TLS == 0
+ static auto* mu = new absl::Mutex;
+ static int64_t global_next_sample = 0;
+ absl::MutexLock l(mu);
+#endif // !ABSL_HAVE_THREAD_LOCAL
+
+ if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
+ return HashtablezInfoHandle(nullptr);
+ }
+ return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+}
+
+// Holds samples and their associated stack traces with a soft limit of
+// `SetHashtablezMaxSamples()`.
+//
+// Thread safe.
+class HashtablezSampler {
+ public:
+ // Returns a global Sampler.
+ static HashtablezSampler& Global();
+
+ HashtablezSampler();
+ ~HashtablezSampler();
+
+ // Registers for sampling. Returns an opaque registration info.
+ HashtablezInfo* Register();
+
+ // Unregisters the sample.
+ void Unregister(HashtablezInfo* sample);
+
+ // The dispose callback will be called on all samples the moment they are
+ // being unregistered. Only affects samples that are unregistered after the
+ // callback has been set.
+ // Returns the previous callback.
+ using DisposeCallback = void (*)(const HashtablezInfo&);
+ DisposeCallback SetDisposeCallback(DisposeCallback f);
+
+ // Iterates over all the registered `StackInfo`s. Returning the number of
+ // samples that have been dropped.
+ int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f);
+
+ private:
+ void PushNew(HashtablezInfo* sample);
+ void PushDead(HashtablezInfo* sample);
+ HashtablezInfo* PopDead();
+
+ std::atomic<size_t> dropped_samples_;
+ std::atomic<size_t> size_estimate_;
+
+ // Intrusive lock free linked lists for tracking samples.
+ //
+ // `all_` records all samples (they are never removed from this list) and is
+ // terminated with a `nullptr`.
+ //
+ // `graveyard_.dead` is a circular linked list. When it is empty,
+ // `graveyard_.dead == &graveyard`. The list is circular so that
+ // every item on it (even the last) has a non-null dead pointer. This allows
+ // `Iterate` to determine if a given sample is live or dead using only
+ // information on the sample itself.
+ //
+ // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead
+ // looks like this (G is the Graveyard):
+ //
+ // +---+ +---+ +---+ +---+ +---+
+ // all -->| A |--->| B |--->| C |--->| D |--->| E |
+ // | | | | | | | | | |
+ // +---+ | | +->| |-+ | | +->| |-+ | |
+ // | G | +---+ | +---+ | +---+ | +---+ | +---+
+ // | | | | | |
+ // | | --------+ +--------+ |
+ // +---+ |
+ // ^ |
+ // +--------------------------------------+
+ //
+ std::atomic<HashtablezInfo*> all_;
+ HashtablezInfo graveyard_;
+
+ std::atomic<DisposeCallback> dispose_;
+};
+
+// Enables or disables sampling for Swiss tables.
+void SetHashtablezEnabled(bool enabled);
+
+// Sets the rate at which Swiss tables will be sampled.
+void SetHashtablezSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetHashtablezMaxSamples(int32_t max);
+
+// Configuration override.
+// This allows process-wide sampling without depending on order of
+// initialization of static storage duration objects.
+// The definition of this constant is weak, which allows us to inject a
+// different value for it at link time.
+extern "C" const bool kAbslContainerInternalSampleEverything;
+
+} // namespace container_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
new file mode 100644
index 0000000..4ca6ffd
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include "absl/base/attributes.h"
+
+namespace absl {
+namespace container_internal {
+
+// See hashtablez_sampler.h for details.
+extern "C" ABSL_ATTRIBUTE_WEAK const bool
+ kAbslContainerInternalSampleEverything = false;
+
+} // namespace container_internal
+} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
new file mode 100644
index 0000000..d2435ed
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -0,0 +1,355 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include <atomic>
+#include <limits>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/synchronization/blocking_counter.h"
+#include "absl/synchronization/internal/thread_pool.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/synchronization/notification.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+#if SWISSTABLE_HAVE_SSE2
+constexpr int kProbeLength = 16;
+#else
+constexpr int kProbeLength = 8;
+#endif
+
+namespace absl {
+namespace container_internal {
+class HashtablezInfoHandlePeer {
+ public:
+ static bool IsSampled(const HashtablezInfoHandle& h) {
+ return h.info_ != nullptr;
+ }
+
+ static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
+};
+
+namespace {
+using ::absl::synchronization_internal::ThreadPool;
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+std::vector<size_t> GetSizes(HashtablezSampler* s) {
+ std::vector<size_t> res;
+ s->Iterate([&](const HashtablezInfo& info) {
+ res.push_back(info.size.load(std::memory_order_acquire));
+ });
+ return res;
+}
+
+HashtablezInfo* Register(HashtablezSampler* s, size_t size) {
+ auto* info = s->Register();
+ assert(info != nullptr);
+ info->size.store(size);
+ return info;
+}
+
+TEST(HashtablezInfoTest, PrepareForSampling) {
+ absl::Time test_start = absl::Now();
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+
+ EXPECT_EQ(info.capacity.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ EXPECT_EQ(info.total_probe_length.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+ EXPECT_GE(info.create_time, test_start);
+
+ info.capacity.store(1, std::memory_order_relaxed);
+ info.size.store(1, std::memory_order_relaxed);
+ info.num_erases.store(1, std::memory_order_relaxed);
+ info.max_probe_length.store(1, std::memory_order_relaxed);
+ info.total_probe_length.store(1, std::memory_order_relaxed);
+ info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
+ info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
+ info.create_time = test_start - absl::Hours(20);
+
+ info.PrepareForSampling();
+ EXPECT_EQ(info.capacity.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ EXPECT_EQ(info.total_probe_length.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+ EXPECT_GE(info.create_time, test_start);
+}
+
+TEST(HashtablezInfoTest, RecordStorageChanged) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ RecordStorageChangedSlow(&info, 17, 47);
+ EXPECT_EQ(info.size.load(), 17);
+ EXPECT_EQ(info.capacity.load(), 47);
+ RecordStorageChangedSlow(&info, 20, 20);
+ EXPECT_EQ(info.size.load(), 20);
+ EXPECT_EQ(info.capacity.load(), 20);
+}
+
+TEST(HashtablezInfoTest, RecordInsert) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 6);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
+ RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 6);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
+ RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 12);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
+}
+
+TEST(HashtablezInfoTest, RecordErase) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 1);
+ RecordEraseSlow(&info);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 1);
+}
+
+TEST(HashtablezInfoTest, RecordRehash) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ RecordInsertSlow(&info, 0x1, 0);
+ RecordInsertSlow(&info, 0x2, kProbeLength);
+ RecordInsertSlow(&info, 0x4, kProbeLength);
+ RecordInsertSlow(&info, 0x8, 2 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 4);
+ EXPECT_EQ(info.total_probe_length.load(), 4);
+
+ RecordEraseSlow(&info);
+ RecordEraseSlow(&info);
+ EXPECT_EQ(info.size.load(), 2);
+ EXPECT_EQ(info.total_probe_length.load(), 4);
+ EXPECT_EQ(info.num_erases.load(), 2);
+
+ RecordRehashSlow(&info, 3 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 2);
+ EXPECT_EQ(info.total_probe_length.load(), 3);
+ EXPECT_EQ(info.num_erases.load(), 0);
+}
+
+TEST(HashtablezSamplerTest, SmallSampleParameter) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+
+ for (int i = 0; i < 1000; ++i) {
+ int64_t next_sample = 0;
+ HashtablezInfo* sample = SampleSlow(&next_sample);
+ EXPECT_GT(next_sample, 0);
+ EXPECT_NE(sample, nullptr);
+ UnsampleSlow(sample);
+ }
+}
+
+TEST(HashtablezSamplerTest, LargeSampleParameter) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max());
+
+ for (int i = 0; i < 1000; ++i) {
+ int64_t next_sample = 0;
+ HashtablezInfo* sample = SampleSlow(&next_sample);
+ EXPECT_GT(next_sample, 0);
+ EXPECT_NE(sample, nullptr);
+ UnsampleSlow(sample);
+ }
+}
+
+TEST(HashtablezSamplerTest, Sample) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+ int64_t num_sampled = 0;
+ int64_t total = 0;
+ double sample_rate;
+ for (int i = 0; i < 1000000; ++i) {
+ HashtablezInfoHandle h = Sample();
+ ++total;
+ if (HashtablezInfoHandlePeer::IsSampled(h)) {
+ ++num_sampled;
+ }
+ sample_rate = static_cast<double>(num_sampled) / total;
+ if (0.005 < sample_rate && sample_rate < 0.015) break;
+ }
+ EXPECT_NEAR(sample_rate, 0.01, 0.005);
+}
+
+TEST(HashtablezSamplerTest, Handle) {
+ auto& sampler = HashtablezSampler::Global();
+ HashtablezInfoHandle h(sampler.Register());
+ auto* info = HashtablezInfoHandlePeer::GetInfo(&h);
+ info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed);
+
+ bool found = false;
+ sampler.Iterate([&](const HashtablezInfo& h) {
+ if (&h == info) {
+ EXPECT_EQ(h.hashes_bitwise_and.load(), 0x12345678);
+ found = true;
+ }
+ });
+ EXPECT_TRUE(found);
+
+ h = HashtablezInfoHandle();
+ found = false;
+ sampler.Iterate([&](const HashtablezInfo& h) {
+ if (&h == info) {
+ // this will only happen if some other thread has resurrected the info
+ // the old handle was using.
+ if (h.hashes_bitwise_and.load() == 0x12345678) {
+ found = true;
+ }
+ }
+ });
+ EXPECT_FALSE(found);
+}
+
+TEST(HashtablezSamplerTest, Registration) {
+ HashtablezSampler sampler;
+ auto* info1 = Register(&sampler, 1);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1));
+
+ auto* info2 = Register(&sampler, 2);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1, 2));
+ info1->size.store(3);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(3, 2));
+
+ sampler.Unregister(info1);
+ sampler.Unregister(info2);
+}
+
+TEST(HashtablezSamplerTest, Unregistration) {
+ HashtablezSampler sampler;
+ std::vector<HashtablezInfo*> infos;
+ for (size_t i = 0; i < 3; ++i) {
+ infos.push_back(Register(&sampler, i));
+ }
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 1, 2));
+
+ sampler.Unregister(infos[1]);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2));
+
+ infos.push_back(Register(&sampler, 3));
+ infos.push_back(Register(&sampler, 4));
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 3, 4));
+ sampler.Unregister(infos[3]);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 4));
+
+ sampler.Unregister(infos[0]);
+ sampler.Unregister(infos[2]);
+ sampler.Unregister(infos[4]);
+ EXPECT_THAT(GetSizes(&sampler), IsEmpty());
+}
+
+TEST(HashtablezSamplerTest, MultiThreaded) {
+ HashtablezSampler sampler;
+ Notification stop;
+ ThreadPool pool(10);
+
+ for (int i = 0; i < 10; ++i) {
+ pool.Schedule([&sampler, &stop]() {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+
+ std::vector<HashtablezInfo*> infoz;
+ while (!stop.HasBeenNotified()) {
+ if (infoz.empty()) {
+ infoz.push_back(sampler.Register());
+ }
+ switch (std::uniform_int_distribution<>(0, 2)(gen)) {
+ case 0: {
+ infoz.push_back(sampler.Register());
+ break;
+ }
+ case 1: {
+ size_t p =
+ std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
+ HashtablezInfo* info = infoz[p];
+ infoz[p] = infoz.back();
+ infoz.pop_back();
+ sampler.Unregister(info);
+ break;
+ }
+ case 2: {
+ absl::Duration oldest = absl::ZeroDuration();
+ sampler.Iterate([&](const HashtablezInfo& info) {
+ oldest = std::max(oldest, absl::Now() - info.create_time);
+ });
+ ASSERT_GE(oldest, absl::ZeroDuration());
+ break;
+ }
+ }
+ }
+ });
+ }
+ // The threads will hammer away. Give it a little bit of time for tsan to
+ // spot errors.
+ absl::SleepFor(absl::Seconds(3));
+ stop.Notify();
+}
+
+TEST(HashtablezSamplerTest, Callback) {
+ HashtablezSampler sampler;
+
+ auto* info1 = Register(&sampler, 1);
+ auto* info2 = Register(&sampler, 2);
+
+ static const HashtablezInfo* expected;
+
+ auto callback = [](const HashtablezInfo& info) {
+ // We can't use `info` outside of this callback because the object will be
+ // disposed as soon as we return from here.
+ EXPECT_EQ(&info, expected);
+ };
+
+ // Set the callback.
+ EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
+ expected = info1;
+ sampler.Unregister(info1);
+
+ // Unset the callback.
+ EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
+ expected = nullptr; // no more calls.
+ sampler.Unregister(info2);
+}
+
+} // namespace
+} // namespace container_internal
+} // namespace absl
diff --git a/absl/container/internal/have_sse.h b/absl/container/internal/have_sse.h
new file mode 100644
index 0000000..4341441
--- /dev/null
+++ b/absl/container/internal/have_sse.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Shared config probing for SSE instructions used in Swiss tables.
+#ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+#define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+
+#ifndef SWISSTABLE_HAVE_SSE2
+#if defined(__SSE2__) || \
+ (defined(_MSC_VER) && \
+ (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
+#define SWISSTABLE_HAVE_SSE2 1
+#else
+#define SWISSTABLE_HAVE_SSE2 0
+#endif
+#endif
+
+#ifndef SWISSTABLE_HAVE_SSSE3
+#ifdef __SSSE3__
+#define SWISSTABLE_HAVE_SSSE3 1
+#else
+#define SWISSTABLE_HAVE_SSSE3 0
+#endif
+#endif
+
+#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
+#error "Bad configuration!"
+#endif
+
+#if SWISSTABLE_HAVE_SSE2
+#include <emmintrin.h>
+#endif
+
+#if SWISSTABLE_HAVE_SSSE3
+#include <tmmintrin.h>
+#endif
+
+#endif // ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
new file mode 100644
index 0000000..24059d9
--- /dev/null
+++ b/absl/container/internal/inlined_vector.h
@@ -0,0 +1,126 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+
+#include <cstddef>
+#include <iterator>
+#include <memory>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+namespace inlined_vector_internal {
+
+template <typename InlinedVector>
+class Storage;
+
+template <template <typename, size_t, typename> class InlinedVector, typename T,
+ size_t N, typename A>
+class Storage<InlinedVector<T, N, A>> {
+ public:
+ using allocator_type = A;
+ using value_type = typename allocator_type::value_type;
+ using pointer = typename allocator_type::pointer;
+ using const_pointer = typename allocator_type::const_pointer;
+ using reference = typename allocator_type::reference;
+ using const_reference = typename allocator_type::const_reference;
+ using rvalue_reference = typename allocator_type::value_type&&;
+ using size_type = typename allocator_type::size_type;
+ using difference_type = typename allocator_type::difference_type;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ explicit Storage(const allocator_type& a) : allocator_and_tag_(a) {}
+
+ // TODO(johnsoncj): Make the below types and members private after migration
+
+ // Holds whether the vector is allocated or not in the lowest bit and the size
+ // in the high bits:
+ // `size_ = (size << 1) | is_allocated;`
+ class Tag {
+ size_type size_;
+
+ public:
+ Tag() : size_(0) {}
+ size_type size() const { return size_ / 2; }
+ void add_size(size_type n) { size_ += n * 2; }
+ void set_inline_size(size_type n) { size_ = n * 2; }
+ void set_allocated_size(size_type n) { size_ = (n * 2) + 1; }
+ bool allocated() const { return size_ % 2; }
+ };
+
+ // Derives from `allocator_type` to use the empty base class optimization.
+ // If the `allocator_type` is stateless, we can store our instance for free.
+ class AllocatorAndTag : private allocator_type {
+ Tag tag_;
+
+ public:
+ explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {}
+ Tag& tag() { return tag_; }
+ const Tag& tag() const { return tag_; }
+ allocator_type& allocator() { return *this; }
+ const allocator_type& allocator() const { return *this; }
+ };
+
+ class Allocation {
+ size_type capacity_;
+ pointer buffer_;
+
+ public:
+ Allocation(allocator_type& a, size_type capacity)
+ : capacity_(capacity), buffer_(Create(a, capacity)) {}
+ void Dealloc(allocator_type& a) {
+ std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_);
+ }
+ size_type capacity() const { return capacity_; }
+ const_pointer buffer() const { return buffer_; }
+ pointer buffer() { return buffer_; }
+ static pointer Create(allocator_type& a, size_type n) {
+ return std::allocator_traits<allocator_type>::allocate(a, n);
+ }
+ };
+
+ // Stores either the inlined or allocated representation
+ union Rep {
+ using ValueTypeBuffer =
+ absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>;
+ using AllocationBuffer =
+ absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>;
+
+ // Structs wrap the buffers to perform indirection that solves a bizarre
+ // compilation error on Visual Studio (all known versions).
+ struct InlinedRep {
+ ValueTypeBuffer inlined[N];
+ };
+
+ struct AllocatedRep {
+ AllocationBuffer allocation;
+ };
+
+ InlinedRep inlined_storage;
+ AllocatedRep allocation_storage;
+ };
+
+ AllocatorAndTag allocator_and_tag_;
+ Rep rep_;
+};
+
+} // namespace inlined_vector_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h
index 676c7d6..bbdde50 100644
--- a/absl/container/internal/layout.h
+++ b/absl/container/internal/layout.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -232,13 +232,17 @@
template <class T, size_t N>
struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
+// Note: workaround for https://gcc.gnu.org/PR88115
template <class T>
-struct AlignOf : NotAligned<T>, std::integral_constant<size_t, alignof(T)> {};
+struct AlignOf : NotAligned<T> {
+ static constexpr size_t value = alignof(T);
+};
template <class T, size_t N>
-struct AlignOf<Aligned<T, N>> : std::integral_constant<size_t, N> {
+struct AlignOf<Aligned<T, N>> {
static_assert(N % alignof(T) == 0,
"Custom alignment can't be lower than the type's alignment");
+ static constexpr size_t value = N;
};
// Does `Ts...` contain `T`?
@@ -249,8 +253,10 @@
using CopyConst =
typename std::conditional<std::is_const<From>::value, const To, To>::type;
+// Note: We're not qualifying this with absl:: because it doesn't compile under
+// MSVC.
template <class T>
-using SliceType = absl::Span<T>;
+using SliceType = Span<T>;
// This namespace contains no types. It prevents functions defined in it from
// being found by ADL.
@@ -290,7 +296,7 @@
#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
#endif
- if (status == 0 && demangled != nullptr) { // Demangling succeeeded.
+ if (status == 0 && demangled != nullptr) { // Demangling succeeded.
absl::StrAppend(&out, "<", demangled, ">");
free(demangled);
} else {
@@ -396,7 +402,7 @@
static_assert(N < NumOffsets, "Index out of bounds");
return adl_barrier::Align(
Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1],
- ElementAlignment<N>());
+ ElementAlignment<N>::value);
}
// Offset in bytes of the array with the specified element type. There must
@@ -445,7 +451,7 @@
return Size<ElementIndex<T>()>();
}
- // The number of elements of all arrays for which they are known.
+ // The number of elements of all arrays for which they are known.
constexpr std::array<size_t, NumSizes> Sizes() const {
return {{Size<SizeSeq>()...}};
}
@@ -610,7 +616,7 @@
#ifdef ADDRESS_SANITIZER
PoisonPadding<Char, N - 1>(p);
// The `if` is an optimization. It doesn't affect the observable behaviour.
- if (ElementAlignment<N - 1>() % ElementAlignment<N>()) {
+ if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
size_t start =
Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1];
ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
@@ -637,7 +643,8 @@
std::string DebugString() const {
const auto offsets = Offsets();
const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...};
- const std::string types[] = {adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
+ const std::string types[] = {
+ adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
for (size_t i = 0; i != NumOffsets - 1; ++i) {
absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],
@@ -690,7 +697,7 @@
//
// It's allowed to pass fewer array sizes than the number of arrays. E.g.,
// if all you need is to the offset of the second array, you only need to
- // pass one argument -- the number of elements in the first arrays.
+ // pass one argument -- the number of elements in the first array.
//
// // int[3] followed by 4 bytes of padding and an unknown number of
// // doubles.
diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc
index f35157a..33b72bd 100644
--- a/absl/container/internal/layout_test.cc
+++ b/absl/container/internal/layout_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -45,7 +45,25 @@
return val;
}
-using Int128 = int64_t[2];
+// Helper classes to test different size and alignments.
+struct alignas(8) Int128 {
+ uint64_t a, b;
+ friend bool operator==(Int128 lhs, Int128 rhs) {
+ return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
+ }
+
+ static std::string Name() {
+ return internal_layout::adl_barrier::TypeName<Int128>();
+ }
+};
+
+// int64_t is *not* 8-byte aligned on all platforms!
+struct alignas(8) Int64 {
+ int64_t a;
+ friend bool operator==(Int64 lhs, Int64 rhs) {
+ return lhs.a == rhs.a;
+ }
+};
// Properties of types that this test relies on.
static_assert(sizeof(int8_t) == 1, "");
@@ -54,6 +72,8 @@
static_assert(alignof(int16_t) == 2, "");
static_assert(sizeof(int32_t) == 4, "");
static_assert(alignof(int32_t) == 4, "");
+static_assert(sizeof(Int64) == 8, "");
+static_assert(alignof(Int64) == 8, "");
static_assert(sizeof(Int128) == 16, "");
static_assert(alignof(Int128) == 8, "");
@@ -1271,14 +1291,14 @@
TEST(Layout, Alignment) {
static_assert(Layout<int8_t>::Alignment() == 1, "");
static_assert(Layout<int32_t>::Alignment() == 4, "");
- static_assert(Layout<int64_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64>::Alignment() == 8, "");
static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, "");
- static_assert(Layout<int8_t, int32_t, int64_t>::Alignment() == 8, "");
- static_assert(Layout<int8_t, int64_t, int32_t>::Alignment() == 8, "");
- static_assert(Layout<int32_t, int8_t, int64_t>::Alignment() == 8, "");
- static_assert(Layout<int32_t, int64_t, int8_t>::Alignment() == 8, "");
- static_assert(Layout<int64_t, int8_t, int32_t>::Alignment() == 8, "");
- static_assert(Layout<int64_t, int32_t, int8_t>::Alignment() == 8, "");
+ static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, "");
+ static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, "");
+ static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, "");
+ static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64, int32_t, int8_t>::Alignment() == 8, "");
}
TEST(Layout, ConstexprPartial) {
@@ -1313,7 +1333,7 @@
}
TEST(Layout, PoisonPadding) {
- using L = Layout<int8_t, int64_t, int32_t, Int128>;
+ using L = Layout<int8_t, Int64, int32_t, Int128>;
constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize();
{
@@ -1361,12 +1381,6 @@
}
TEST(Layout, DebugString) {
- const std::string int64_type =
-#ifdef _MSC_VER
- "__int64";
-#else // _MSC_VER
- std::is_same<int64_t, long long>::value ? "long long" : "long"; // NOLINT
-#endif // _MSC_VER
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial();
EXPECT_EQ("@0<signed char>(1)", x.DebugString());
@@ -1384,24 +1398,24 @@
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
- "@16<" +
- int64_type + " [2]>(16)",
+ "@16" +
+ Int128::Name() + "(16)",
x.DebugString());
}
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
- "@16<" +
- int64_type + " [2]>(16)[4]",
+ "@16" +
+ Int128::Name() + "(16)[4]",
x.DebugString());
}
{
constexpr Layout<int8_t, int32_t, int8_t, Int128> x(1, 2, 3, 4);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
- "@16<" +
- int64_type + " [2]>(16)[4]",
+ "@16" +
+ Int128::Name() + "(16)[4]",
x.DebugString());
}
}
@@ -1528,8 +1542,7 @@
const char* c_str() const {
// Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
// The argument in Partial(1) specifies that we have size_t[1] in front of
- // the
- // characters.
+ // the characters.
return L::Partial(1).Pointer<char>(p_.get());
}
diff --git a/absl/container/internal/node_hash_policy.h b/absl/container/internal/node_hash_policy.h
index 065e700..19b4fc0 100644
--- a/absl/container/internal/node_hash_policy.h
+++ b/absl/container/internal/node_hash_policy.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/node_hash_policy_test.cc b/absl/container/internal/node_hash_policy_test.cc
index 43d287e..f1d3ec3 100644
--- a/absl/container/internal/node_hash_policy_test.cc
+++ b/absl/container/internal/node_hash_policy_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h
index 1edc007..0014cf8 100644
--- a/absl/container/internal/raw_hash_map.h
+++ b/absl/container/internal/raw_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -39,11 +39,14 @@
using MappedConstReference = decltype(P::value(
std::addressof(std::declval<typename raw_hash_map::const_reference>())));
+ using KeyArgImpl =
+ KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
+
public:
using key_type = typename Policy::key_type;
using mapped_type = typename Policy::mapped_type;
- template <typename K>
- using key_arg = typename raw_hash_map::raw_hash_set::template key_arg<K>;
+ template <class K>
+ using key_arg = typename KeyArgImpl::template type<K, key_type>;
static_assert(!std::is_reference<key_type>::value, "");
// TODO(alkis): remove this assertion and verify that reference mapped_type is
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 1015312..ac2d10a 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,7 @@
#include "absl/container/internal/raw_hash_set.h"
+#include <atomic>
#include <cstddef>
#include "absl/base/config.h"
@@ -29,7 +30,7 @@
static thread_local size_t counter = 0;
size_t value = ++counter;
#else // ABSL_HAVE_THREAD_LOCAL
- static std::atomic<size_t> counter;
+ static std::atomic<size_t> counter(0);
size_t value = counter.fetch_add(1, std::memory_order_relaxed);
#endif // ABSL_HAVE_THREAD_LOCAL
return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 70da90f..85e3334 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -91,30 +91,6 @@
#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
-#ifndef SWISSTABLE_HAVE_SSE2
-#ifdef __SSE2__
-#define SWISSTABLE_HAVE_SSE2 1
-#else
-#define SWISSTABLE_HAVE_SSE2 0
-#endif
-#endif
-
-#ifndef SWISSTABLE_HAVE_SSSE3
-#ifdef __SSSE3__
-#define SWISSTABLE_HAVE_SSSE3 1
-#else
-#define SWISSTABLE_HAVE_SSSE3 0
-#endif
-#endif
-
-#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
-#error "Bad configuration!"
-#endif
-
-#if SWISSTABLE_HAVE_SSE2
-#include <x86intrin.h>
-#endif
-
#include <algorithm>
#include <cmath>
#include <cstdint>
@@ -129,14 +105,16 @@
#include "absl/base/internal/bits.h"
#include "absl/base/internal/endian.h"
#include "absl/base/port.h"
+#include "absl/container/internal/common.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_policy_traits.h"
#include "absl/container/internal/hashtable_debug_hooks.h"
+#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/container/internal/have_sse.h"
#include "absl/container/internal/layout.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
-#include "absl/types/optional.h"
#include "absl/utility/utility.h"
namespace absl {
@@ -187,12 +165,6 @@
std::declval<Ts>()...))>,
Policy, Hash, Eq, Ts...> : std::true_type {};
-template <class, class = void>
-struct IsTransparent : std::false_type {};
-template <class T>
-struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
- : std::true_type {};
-
// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
template <class T>
constexpr bool IsNoThrowSwappable() {
@@ -202,14 +174,17 @@
template <typename T>
int TrailingZeros(T x) {
- return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(x)
- : base_internal::CountTrailingZerosNonZero32(x);
+ return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(
+ static_cast<uint64_t>(x))
+ : base_internal::CountTrailingZerosNonZero32(
+ static_cast<uint32_t>(x));
}
template <typename T>
int LeadingZeros(T x) {
- return sizeof(T) == 8 ? base_internal::CountLeadingZeros64(x)
- : base_internal::CountLeadingZeros32(x);
+ return sizeof(T) == 8
+ ? base_internal::CountLeadingZeros64(static_cast<uint64_t>(x))
+ : base_internal::CountLeadingZeros32(static_cast<uint32_t>(x));
}
// An abstraction over a bitmask. It provides an easy way to iterate through the
@@ -337,10 +312,27 @@
inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
#if SWISSTABLE_HAVE_SSE2
-struct Group {
+
+// https://github.com/abseil/abseil-cpp/issues/209
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
+// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
+// Work around this by using the portable implementation of Group
+// when using -funsigned-char under GCC.
+inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) {
+#if defined(__GNUC__) && !defined(__clang__)
+ if (std::is_unsigned<char>::value) {
+ const __m128i mask = _mm_set1_epi8(0x80);
+ const __m128i diff = _mm_subs_epi8(b, a);
+ return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask);
+ }
+#endif
+ return _mm_cmpgt_epi8(a, b);
+}
+
+struct GroupSse2Impl {
static constexpr size_t kWidth = 16; // the number of slots per group
- explicit Group(const ctrl_t* pos) {
+ explicit GroupSse2Impl(const ctrl_t* pos) {
ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
}
@@ -366,23 +358,24 @@
BitMask<uint32_t, kWidth> MatchEmptyOrDeleted() const {
auto special = _mm_set1_epi8(kSentinel);
return BitMask<uint32_t, kWidth>(
- _mm_movemask_epi8(_mm_cmpgt_epi8(special, ctrl)));
+ _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)));
}
// Returns the number of trailing empty or deleted elements in the group.
uint32_t CountLeadingEmptyOrDeleted() const {
auto special = _mm_set1_epi8(kSentinel);
- return TrailingZeros(_mm_movemask_epi8(_mm_cmpgt_epi8(special, ctrl)) + 1);
+ return TrailingZeros(
+ _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1);
}
void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
- auto msbs = _mm_set1_epi8(0x80);
+ auto msbs = _mm_set1_epi8(static_cast<char>(-128));
auto x126 = _mm_set1_epi8(126);
#if SWISSTABLE_HAVE_SSSE3
auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
#else
auto zero = _mm_setzero_si128();
- auto special_mask = _mm_cmpgt_epi8(zero, ctrl);
+ auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
#endif
_mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
@@ -390,11 +383,13 @@
__m128i ctrl;
};
-#else
-struct Group {
+#endif // SWISSTABLE_HAVE_SSE2
+
+struct GroupPortableImpl {
static constexpr size_t kWidth = 8;
- explicit Group(const ctrl_t* pos) : ctrl(little_endian::Load64(pos)) {}
+ explicit GroupPortableImpl(const ctrl_t* pos)
+ : ctrl(little_endian::Load64(pos)) {}
BitMask<uint64_t, kWidth, 3> Match(h2_t hash) const {
// For the technique, see:
@@ -441,15 +436,17 @@
uint64_t ctrl;
};
-#endif // SWISSTABLE_HAVE_SSE2
+
+#if SWISSTABLE_HAVE_SSE2
+using Group = GroupSse2Impl;
+#else
+using Group = GroupPortableImpl;
+#endif
template <class Policy, class Hash, class Eq, class Alloc>
class raw_hash_set;
-
-inline bool IsValidCapacity(size_t n) {
- return ((n + 1) & n) == 0 && n >= Group::kWidth - 1;
-}
+inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
// PRECONDITION:
// IsValidCapacity(capacity)
@@ -471,152 +468,32 @@
ctrl[capacity] = kSentinel;
}
-// Rounds up the capacity to the next power of 2 minus 1 and ensures it is
-// greater or equal to Group::kWidth - 1.
+// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
inline size_t NormalizeCapacity(size_t n) {
- constexpr size_t kMinCapacity = Group::kWidth - 1;
- return n <= kMinCapacity
- ? kMinCapacity
- : std::numeric_limits<size_t>::max() >> LeadingZeros(n);
+ return n ? ~size_t{} >> LeadingZeros(n) : 1;
}
-// The node_handle concept from C++17.
-// We specialize node_handle for sets and maps. node_handle_base holds the
-// common API of both.
-template <typename Policy, typename Alloc>
-class node_handle_base {
- protected:
- using PolicyTraits = hash_policy_traits<Policy>;
- using slot_type = typename PolicyTraits::slot_type;
-
- public:
- using allocator_type = Alloc;
-
- constexpr node_handle_base() {}
- node_handle_base(node_handle_base&& other) noexcept {
- *this = std::move(other);
+// We use 7/8th as maximum load factor.
+// For 16-wide groups, that gives an average of two empty slots per group.
+inline size_t CapacityToGrowth(size_t capacity) {
+ assert(IsValidCapacity(capacity));
+ // `capacity*7/8`
+ if (Group::kWidth == 8 && capacity == 7) {
+ // x-x/8 does not work when x==7.
+ return 6;
}
- ~node_handle_base() { destroy(); }
- node_handle_base& operator=(node_handle_base&& other) {
- destroy();
- if (!other.empty()) {
- alloc_ = other.alloc_;
- PolicyTraits::transfer(alloc(), slot(), other.slot());
- other.reset();
- }
- return *this;
+ return capacity - capacity / 8;
+}
+// From desired "growth" to a lowerbound of the necessary capacity.
+// Might not be a valid one and required NormalizeCapacity().
+inline size_t GrowthToLowerboundCapacity(size_t growth) {
+ // `growth*8/7`
+ if (Group::kWidth == 8 && growth == 7) {
+ // x+(x-1)/7 does not work when x==7.
+ return 8;
}
-
- bool empty() const noexcept { return !alloc_; }
- explicit operator bool() const noexcept { return !empty(); }
- allocator_type get_allocator() const { return *alloc_; }
-
- protected:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
- PolicyTraits::transfer(alloc(), slot(), s);
- }
-
- void destroy() {
- if (!empty()) {
- PolicyTraits::destroy(alloc(), slot());
- reset();
- }
- }
-
- void reset() {
- assert(alloc_.has_value());
- alloc_ = absl::nullopt;
- }
-
- slot_type* slot() const {
- assert(!empty());
- return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
- }
- allocator_type* alloc() { return std::addressof(*alloc_); }
-
- private:
- absl::optional<allocator_type> alloc_;
- mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
- slot_space_;
-};
-
-// For sets.
-template <typename Policy, typename Alloc, typename = void>
-class node_handle : public node_handle_base<Policy, Alloc> {
- using Base = typename node_handle::node_handle_base;
-
- public:
- using value_type = typename Base::PolicyTraits::value_type;
-
- constexpr node_handle() {}
-
- value_type& value() const {
- return Base::PolicyTraits::element(this->slot());
- }
-
- private:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// For maps.
-template <typename Policy, typename Alloc>
-class node_handle<Policy, Alloc, absl::void_t<typename Policy::mapped_type>>
- : public node_handle_base<Policy, Alloc> {
- using Base = typename node_handle::node_handle_base;
-
- public:
- using key_type = typename Policy::key_type;
- using mapped_type = typename Policy::mapped_type;
-
- constexpr node_handle() {}
-
- auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) {
- return Base::PolicyTraits::key(this->slot());
- }
-
- mapped_type& mapped() const {
- return Base::PolicyTraits::value(
- &Base::PolicyTraits::element(this->slot()));
- }
-
- private:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// Implement the insert_return_type<> concept of C++17.
-template <class Iterator, class NodeType>
-struct insert_return_type {
- Iterator position;
- bool inserted;
- NodeType node;
-};
-
-// Helper trait to allow or disallow arbitrary keys when the hash and
-// eq functions are transparent.
-// It is very important that the inner template is an alias and that the type it
-// produces is not a dependent type. Otherwise, type deduction would fail.
-template <bool is_transparent>
-struct KeyArg {
- // Transparent. Forward `K`.
- template <typename K, typename key_type>
- using type = K;
-};
-
-template <>
-struct KeyArg<false> {
- // Not transparent. Always use `key_type`.
- template <typename K, typename key_type>
- using type = key_type;
-};
+ return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
+}
// Policy: a policy defines how to perform different operations on
// the slots of the hashtable (see hash_policy_traits.h for the full interface
@@ -632,14 +509,14 @@
// if they are equal, false if they are not. If two keys compare equal, then
// their hash values as defined by Hash MUST be equal.
//
-// Allocator: an Allocator [http://devdocs.io/cpp/concept/allocator] with which
+// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which
// the storage of the hashtable will be allocated and the elements will be
// constructed and destroyed.
template <class Policy, class Hash, class Eq, class Alloc>
class raw_hash_set {
using PolicyTraits = hash_policy_traits<Policy>;
- using KeyArgImpl = container_internal::KeyArg<IsTransparent<Eq>::value &&
- IsTransparent<Hash>::value>;
+ using KeyArgImpl =
+ KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
public:
using init_type = typename PolicyTraits::init_type;
@@ -662,7 +539,7 @@
allocator_type>::template rebind_traits<value_type>::const_pointer;
// Alias used for heterogeneous lookup functions.
- // `key_arg<K>` evaluates to `K` when the functors are tranparent and to
+ // `key_arg<K>` evaluates to `K` when the functors are transparent and to
// `key_type` otherwise. It permits template argument deduction on `K` for the
// transparent case.
template <class K>
@@ -780,7 +657,11 @@
}
ctrl_t* ctrl_ = nullptr;
- slot_type* slot_;
+ // To avoid uninitialized member warnigs, put slot_ in an anonymous union.
+ // The member is not initialized on singleton and end iterators.
+ union {
+ slot_type* slot_;
+ };
};
class const_iterator {
@@ -820,7 +701,8 @@
iterator inner_;
};
- using node_type = container_internal::node_handle<Policy, Alloc>;
+ using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
+ using insert_return_type = InsertReturnType<iterator, node_type>;
raw_hash_set() noexcept(
std::is_nothrow_default_constructible<hasher>::value&&
@@ -833,7 +715,7 @@
: ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) {
if (bucket_count) {
capacity_ = NormalizeCapacity(bucket_count);
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor);
+ reset_growth_left();
initialize_slots();
}
}
@@ -875,8 +757,8 @@
// that accept std::initializer_list<T> and std::initializer_list<init_type>.
// This is advantageous for performance.
//
- // // Turns {"abc", "def"} into std::initializer_list<std::string>, then copies
- // // the strings into the set.
+ // // Turns {"abc", "def"} into std::initializer_list<std::string>, then
+ // // copies the strings into the set.
// std::unordered_set<std::string> s = {"abc", "def"};
//
// // Turns {"abc", "def"} into std::initializer_list<const char*>, then
@@ -939,9 +821,10 @@
// than a full `insert`.
for (const auto& v : that) {
const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
- const size_t i = find_first_non_full(hash);
- set_ctrl(i, H2(hash));
- emplace_at(i, v);
+ auto target = find_first_non_full(hash);
+ set_ctrl(target.offset, H2(hash));
+ emplace_at(target.offset, v);
+ infoz_.RecordInsert(hash, target.probe_length);
}
size_ = that.size();
growth_left() -= that.size();
@@ -955,6 +838,7 @@
slots_(absl::exchange(that.slots_, nullptr)),
size_(absl::exchange(that.size_, 0)),
capacity_(absl::exchange(that.capacity_, 0)),
+ infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())),
// Hash, equality and allocator are copied instead of moved because
// `that` must be left valid. If Hash is std::function<Key>, moving it
// would create a nullptr functor that cannot be called.
@@ -975,6 +859,7 @@
std::swap(size_, that.size_);
std::swap(capacity_, that.capacity_);
std::swap(growth_left(), that.growth_left());
+ std::swap(infoz_, that.infoz_);
} else {
reserve(that.size());
// Note: this will copy elements of dense_set and unordered_set instead of
@@ -1022,9 +907,9 @@
bool empty() const { return !size(); }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
- size_t max_size() const { return std::numeric_limits<size_t>::max(); }
+ size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
- void clear() {
+ ABSL_ATTRIBUTE_REINITIALIZES void clear() {
// Iterating over this container is O(bucket_count()). When bucket_count()
// is much greater than size(), iteration becomes prohibitively expensive.
// For clear() it is more important to reuse the allocated array when the
@@ -1042,9 +927,10 @@
}
size_ = 0;
reset_ctrl();
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor);
+ reset_growth_left();
}
assert(empty());
+ infoz_.RecordStorageChanged(0, capacity_);
}
// This overload kicks in when the argument is an rvalue of insertable and
@@ -1124,13 +1010,14 @@
insert(ilist.begin(), ilist.end());
}
- insert_return_type<iterator, node_type> insert(node_type&& node) {
+ insert_return_type insert(node_type&& node) {
if (!node) return {end(), false, node_type()};
- const auto& elem = PolicyTraits::element(node.slot());
+ const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
auto res = PolicyTraits::apply(
- InsertSlot<false>{*this, std::move(*node.slot())}, elem);
+ InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
+ elem);
if (res.second) {
- node.reset();
+ CommonAccess::Reset(&node);
return {res.first, true, node_type()};
} else {
return {res.first, false, std::move(node)};
@@ -1294,7 +1181,8 @@
}
node_type extract(const_iterator position) {
- node_type node(alloc_ref(), position.inner_.slot_);
+ auto node =
+ CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_);
erase_meta_only(position);
return node;
}
@@ -1319,6 +1207,7 @@
swap(growth_left(), that.growth_left());
swap(hash_ref(), that.hash_ref());
swap(eq_ref(), that.eq_ref());
+ swap(infoz_, that.infoz_);
if (AllocTraits::propagate_on_container_swap::value) {
swap(alloc_ref(), that.alloc_ref());
} else {
@@ -1329,17 +1218,21 @@
void rehash(size_t n) {
if (n == 0 && capacity_ == 0) return;
- if (n == 0 && size_ == 0) return destroy_slots();
- auto m = NormalizeCapacity(std::max(n, NumSlotsFast(size())));
+ if (n == 0 && size_ == 0) {
+ destroy_slots();
+ infoz_.RecordStorageChanged(0, 0);
+ return;
+ }
+ // bitor is a faster way of doing `max` here. We will round up to the next
+ // power-of-2-minus-1, so bitor is good enough.
+ auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size()));
// n == 0 unconditionally rehashes as per the standard.
if (n == 0 || m > capacity_) {
resize(m);
}
}
- void reserve(size_t n) {
- rehash(NumSlotsFast(n));
- }
+ void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
// Extension API: support for heterogeneous keys.
//
@@ -1517,13 +1410,6 @@
slot_type&& slot;
};
- // Computes std::ceil(n / kMaxLoadFactor). Faster than calling std::ceil.
- static inline size_t NumSlotsFast(size_t n) {
- return static_cast<size_t>(
- (n * kMaxLoadFactorDenominator + (kMaxLoadFactorNumerator - 1)) /
- kMaxLoadFactorNumerator);
- }
-
// "erases" the object from the container, except that it doesn't actually
// destroy the object. It only updates all the metadata of the class.
// This can be used in conjunction with Policy::transfer to move the object to
@@ -1546,17 +1432,23 @@
set_ctrl(index, was_never_full ? kEmpty : kDeleted);
growth_left() += was_never_full;
+ infoz_.RecordErase();
}
void initialize_slots() {
assert(capacity_);
+ if (slots_ == nullptr) {
+ infoz_ = Sample();
+ }
+
auto layout = MakeLayout(capacity_);
char* mem = static_cast<char*>(
Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize()));
ctrl_ = reinterpret_cast<ctrl_t*>(layout.template Pointer<0>(mem));
slots_ = layout.template Pointer<1>(mem);
reset_ctrl();
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_;
+ reset_growth_left();
+ infoz_.RecordStorageChanged(size_, capacity_);
}
void destroy_slots() {
@@ -1585,11 +1477,14 @@
capacity_ = new_capacity;
initialize_slots();
+ size_t total_probe_length = 0;
for (size_t i = 0; i != old_capacity; ++i) {
if (IsFull(old_ctrl[i])) {
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(old_slots + i));
- size_t new_i = find_first_non_full(hash);
+ auto target = find_first_non_full(hash);
+ size_t new_i = target.offset;
+ total_probe_length += target.probe_length;
set_ctrl(new_i, H2(hash));
PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i);
}
@@ -1601,10 +1496,12 @@
Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
layout.AllocSize());
}
+ infoz_.RecordRehash(total_probe_length);
}
void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
assert(IsValidCapacity(capacity_));
+ assert(!is_small());
// Algorithm:
// - mark all DELETED slots as EMPTY
// - mark all FULL slots as DELETED
@@ -1624,12 +1521,15 @@
ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_);
typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
raw;
+ size_t total_probe_length = 0;
slot_type* slot = reinterpret_cast<slot_type*>(&raw);
for (size_t i = 0; i != capacity_; ++i) {
if (!IsDeleted(ctrl_[i])) continue;
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(slots_ + i));
- size_t new_i = find_first_non_full(hash);
+ auto target = find_first_non_full(hash);
+ size_t new_i = target.offset;
+ total_probe_length += target.probe_length;
// Verify if the old and new i fall within the same group wrt the hash.
// If they do, we don't need to move the object as it falls already in the
@@ -1661,13 +1561,14 @@
--i; // repeat
}
}
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_;
+ reset_growth_left();
+ infoz_.RecordRehash(total_probe_length);
}
void rehash_and_grow_if_necessary() {
if (capacity_ == 0) {
- resize(Group::kWidth - 1);
- } else if (size() <= kMaxLoadFactor / 2 * capacity_) {
+ resize(1);
+ } else if (size() <= CapacityToGrowth(capacity()) / 2) {
// Squash DELETED without growing if there is enough capacity.
drop_deletes_without_resize();
} else {
@@ -1702,24 +1603,26 @@
// - the input is already a set
// - there are enough slots
// - the element with the hash is not in the table
- size_t find_first_non_full(size_t hash) {
+ struct FindInfo {
+ size_t offset;
+ size_t probe_length;
+ };
+ FindInfo find_first_non_full(size_t hash) {
auto seq = probe(hash);
while (true) {
Group g{ctrl_ + seq.offset()};
auto mask = g.MatchEmptyOrDeleted();
if (mask) {
#if !defined(NDEBUG)
- // We want to force small tables to have random entries too, so
- // in debug build we will randomly insert in either the front or back of
+ // We want to add entropy even when ASLR is not enabled.
+ // In debug build we will randomly insert in either the front or back of
// the group.
// TODO(kfm,sbenza): revisit after we do unconditional mixing
- if (ShouldInsertBackwards(hash, ctrl_))
- return seq.offset(mask.HighestBitSet());
- else
- return seq.offset(mask.LowestBitSet());
-#else
- return seq.offset(mask.LowestBitSet());
+ if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) {
+ return {seq.offset(mask.HighestBitSet()), seq.index()};
+ }
#endif
+ return {seq.offset(mask.LowestBitSet()), seq.index()};
}
assert(seq.index() < capacity_ && "full table!");
seq.next();
@@ -1758,15 +1661,17 @@
}
size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
- size_t target = find_first_non_full(hash);
- if (ABSL_PREDICT_FALSE(growth_left() == 0 && !IsDeleted(ctrl_[target]))) {
+ auto target = find_first_non_full(hash);
+ if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
+ !IsDeleted(ctrl_[target.offset]))) {
rehash_and_grow_if_necessary();
target = find_first_non_full(hash);
}
++size_;
- growth_left() -= IsEmpty(ctrl_[target]);
- set_ctrl(target, H2(hash));
- return target;
+ growth_left() -= IsEmpty(ctrl_[target.offset]);
+ set_ctrl(target.offset, H2(hash));
+ infoz_.RecordInsert(hash, target.probe_length);
+ return target.offset;
}
// Constructs the value in the space pointed by the iterator. This only works
@@ -1804,6 +1709,10 @@
SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
}
+ void reset_growth_left() {
+ growth_left() = CapacityToGrowth(capacity()) - size_;
+ }
+
// Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at
// the end too.
void set_ctrl(size_t i, ctrl_t h) {
@@ -1816,11 +1725,28 @@
}
ctrl_[i] = h;
- ctrl_[((i - Group::kWidth) & capacity_) + Group::kWidth] = h;
+ ctrl_[((i - Group::kWidth) & capacity_) + 1 +
+ ((Group::kWidth - 1) & capacity_)] = h;
}
size_t& growth_left() { return settings_.template get<0>(); }
+ // The representation of the object has two modes:
+ // - small: For capacities < kWidth-1
+ // - large: For the rest.
+ //
+ // Differences:
+ // - In small mode we are able to use the whole capacity. The extra control
+ // bytes give us at least one "empty" control byte to stop the iteration.
+ // This is important to make 1 a valid capacity.
+ //
+ // - In small mode only the first `capacity()` control bytes after the
+ // sentinel are valid. The rest contain dummy kEmpty values that do not
+ // represent a real slot. This is important to take into account on
+ // find_first_non_full(), where we never try ShouldInsertBackwards() for
+ // small tables.
+ bool is_small() const { return capacity_ < Group::kWidth - 1; }
+
hasher& hash_ref() { return settings_.template get<1>(); }
const hasher& hash_ref() const { return settings_.template get<1>(); }
key_equal& eq_ref() { return settings_.template get<2>(); }
@@ -1830,12 +1756,6 @@
return settings_.template get<3>();
}
- // On average each group has 2 empty slot (for the vectorized case).
- static constexpr int64_t kMaxLoadFactorNumerator = 14;
- static constexpr int64_t kMaxLoadFactorDenominator = 16;
- static constexpr float kMaxLoadFactor =
- 1.0 * kMaxLoadFactorNumerator / kMaxLoadFactorDenominator;
-
// TODO(alkis): Investigate removing some of these fields:
// - ctrl/slots can be derived from each other
// - size can be moved into the slot array
@@ -1843,6 +1763,7 @@
slot_type* slots_ = nullptr; // [capacity * slot_type]
size_t size_ = 0; // number of full slots
size_t capacity_ = 0; // total number of slots
+ HashtablezInfoHandle infoz_;
absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher,
key_equal, allocator_type>
settings_{0, hasher{}, key_equal{}, allocator_type{}};
@@ -1895,10 +1816,9 @@
}
static size_t LowerBoundAllocatedByteSize(size_t size) {
- size_t capacity = container_internal::NormalizeCapacity(
- std::ceil(size / Set::kMaxLoadFactor));
+ size_t capacity = GrowthToLowerboundCapacity(size);
if (capacity == 0) return 0;
- auto layout = Set::MakeLayout(capacity);
+ auto layout = Set::MakeLayout(NormalizeCapacity(capacity));
size_t m = layout.AllocSize();
size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
if (per_slot != ~size_t{}) {
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc
index 891fa45..a5eff0b 100644
--- a/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index cd33a3a..02fd0bf 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +14,6 @@
#include "absl/container/internal/raw_hash_set.h"
-#include <array>
#include <cmath>
#include <cstdint>
#include <deque>
@@ -49,18 +48,47 @@
using ::testing::DoubleNear;
using ::testing::ElementsAre;
+using ::testing::Ge;
+using ::testing::Lt;
using ::testing::Optional;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
TEST(Util, NormalizeCapacity) {
- constexpr size_t kMinCapacity = Group::kWidth - 1;
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(0));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(1));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(2));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(kMinCapacity));
- EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 1));
- EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 2));
+ EXPECT_EQ(1, NormalizeCapacity(0));
+ EXPECT_EQ(1, NormalizeCapacity(1));
+ EXPECT_EQ(3, NormalizeCapacity(2));
+ EXPECT_EQ(3, NormalizeCapacity(3));
+ EXPECT_EQ(7, NormalizeCapacity(4));
+ EXPECT_EQ(7, NormalizeCapacity(7));
+ EXPECT_EQ(15, NormalizeCapacity(8));
+ EXPECT_EQ(15, NormalizeCapacity(15));
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1));
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
+}
+
+TEST(Util, GrowthAndCapacity) {
+ // Verify that GrowthToCapacity gives the minimum capacity that has enough
+ // growth.
+ for (size_t growth = 0; growth < 10000; ++growth) {
+ SCOPED_TRACE(growth);
+ size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
+ // The capacity is large enough for `growth`
+ EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
+ if (growth != 0 && capacity > 1) {
+ // There is no smaller capacity that works.
+ EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
+ }
+ }
+
+ for (size_t capacity = Group::kWidth - 1; capacity < 10000;
+ capacity = 2 * capacity + 1) {
+ SCOPED_TRACE(capacity);
+ size_t growth = CapacityToGrowth(capacity);
+ EXPECT_THAT(growth, Lt(capacity));
+ EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity);
+ EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity);
+ }
}
TEST(Util, probe_seq) {
@@ -107,14 +135,14 @@
}
TEST(BitMask, LeadingTrailing) {
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).LeadingZeros()), 3);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).TrailingZeros()), 6);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).LeadingZeros()), 15);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).TrailingZeros()), 0);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).LeadingZeros()), 0);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).TrailingZeros()), 15);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
@@ -130,45 +158,50 @@
for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h));
}
-#if SWISSTABLE_HAVE_SSE2
TEST(Group, Match) {
- ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
- 7, 5, 3, 1, 1, 1, 1, 1};
- EXPECT_THAT(Group{group}.Match(0), ElementsAre());
- EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
- EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
- EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
- EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
+ if (Group::kWidth == 16) {
+ ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+ 7, 5, 3, 1, 1, 1, 1, 1};
+ EXPECT_THAT(Group{group}.Match(0), ElementsAre());
+ EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
+ EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
+ EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
+ EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
+ } else if (Group::kWidth == 8) {
+ ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+ EXPECT_THAT(Group{group}.Match(0), ElementsAre());
+ EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
+ EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
+ } else {
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+ }
}
TEST(Group, MatchEmpty) {
- ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
- 7, 5, 3, 1, 1, 1, 1, 1};
- EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4));
+ if (Group::kWidth == 16) {
+ ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+ 7, 5, 3, 1, 1, 1, 1, 1};
+ EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4));
+ } else if (Group::kWidth == 8) {
+ ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+ EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0));
+ } else {
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+ }
}
TEST(Group, MatchEmptyOrDeleted) {
- ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
- 7, 5, 3, 1, 1, 1, 1, 1};
- EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4));
+ if (Group::kWidth == 16) {
+ ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7,
+ 7, 5, 3, 1, 1, 1, 1, 1};
+ EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4));
+ } else if (Group::kWidth == 8) {
+ ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
+ EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3));
+ } else {
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
+ }
}
-#else
-TEST(Group, Match) {
- ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
- EXPECT_THAT(Group{group}.Match(0), ElementsAre());
- EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
- EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
-}
-TEST(Group, MatchEmpty) {
- ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
- EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0));
-}
-
-TEST(Group, MatchEmptyOrDeleted) {
- ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1};
- EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3));
-}
-#endif
TEST(Batch, DropDeletes) {
constexpr size_t kCapacity = 63;
@@ -338,6 +371,7 @@
size_t size;
size_t capacity;
size_t growth_left;
+ void* infoz;
};
struct StatelessHash {
size_t operator()(absl::string_view) const { return 0; }
@@ -386,7 +420,8 @@
!defined(UNDEFINED_BEHAVIOR_SANITIZER)
const auto now = [] { return absl::base_internal::CycleClock::Now(); };
- static constexpr int size = 1000000;
+ // Make size enough to not fit in L2 cache (16.7 Mb)
+ static constexpr int size = 1 << 22;
for (int i = 0; i < size; ++i) t.insert(i);
int64_t no_prefetch = 0, prefetch = 0;
@@ -687,7 +722,7 @@
Modulo1000HashTable t;
// Adding the same length (and the same hash) strings
// to have at least kMinFullGroups groups
- // with Group::kWidth collisions. Then feel upto MaxDensitySize;
+ // with Group::kWidth collisions. Then fill up to MaxDensitySize;
const size_t kMinFullGroups = 7;
std::vector<int> keys;
for (size_t i = 0; i < MaxDensitySize(Group::kWidth * kMinFullGroups); ++i) {
@@ -779,7 +814,7 @@
TEST(Table, ClearBug) {
IntTable t;
constexpr size_t capacity = container_internal::Group::kWidth - 1;
- constexpr size_t max_size = capacity / 2;
+ constexpr size_t max_size = capacity / 2 + 1;
for (size_t i = 0; i < max_size; ++i) {
t.insert(i);
}
@@ -810,6 +845,25 @@
EXPECT_TRUE(t.find(0) == t.end());
}
+TEST(Table, EraseMaintainsValidIterator) {
+ IntTable t;
+ const int kNumElements = 100;
+ for (int i = 0; i < kNumElements; i ++) {
+ EXPECT_TRUE(t.emplace(i).second);
+ }
+ EXPECT_EQ(t.size(), kNumElements);
+
+ int num_erase_calls = 0;
+ auto it = t.begin();
+ while (it != t.end()) {
+ t.erase(it++);
+ num_erase_calls++;
+ }
+
+ EXPECT_TRUE(t.empty());
+ EXPECT_EQ(num_erase_calls, kNumElements);
+}
+
// Collect N bad keys by following algorithm:
// 1. Create an empty table and reserve it to 2 * N.
// 2. Insert N random elements.
@@ -1029,7 +1083,6 @@
{{0.95, 0.1}},
{{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
}
- break;
case 16:
if (kRandomizesInserts) {
return {0.1,
@@ -1042,12 +1095,11 @@
{{0.95, 0.05}},
{{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}};
}
- break;
- default:
- ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
}
+ ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
+
TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
ProbeStatsPerSize stats;
std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
@@ -1125,7 +1177,6 @@
{{0.95, 0.3}},
{{0.95, 0}, {0.99, 3}, {0.999, 15}, {0.9999, 25}}};
}
- break;
case 16:
if (kRandomizesInserts) {
return {0.1,
@@ -1138,12 +1189,11 @@
{{0.95, 0.1}},
{{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}};
}
- break;
- default:
- ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
}
+ ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
+
TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
ProbeStatsPerSize stats;
std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
@@ -1431,7 +1481,8 @@
TEST(Table, Equality) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v = {{"a", "b"}, {"aa", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v = {{"a", "b"},
+ {"aa", "bb"}};
t.insert(std::begin(v), std::end(v));
StringTable u = t;
EXPECT_EQ(u, t);
@@ -1439,20 +1490,24 @@
TEST(Table, Equality2) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"}, {"aa", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"},
+ {"aa", "bb"}};
t.insert(std::begin(v1), std::end(v1));
StringTable u;
- std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}};
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
+ {"aa", "aa"}};
u.insert(std::begin(v2), std::end(v2));
EXPECT_NE(u, t);
}
TEST(Table, Equality3) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"}, {"bb", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"},
+ {"bb", "bb"}};
t.insert(std::begin(v1), std::end(v1));
StringTable u;
- std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}};
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
+ {"aa", "aa"}};
u.insert(std::begin(v2), std::end(v2));
EXPECT_NE(u, t);
}
@@ -1677,7 +1732,7 @@
EXPECT_FALSE(node.empty());
StringTable t2;
- auto res = t2.insert(std::move(node));
+ StringTable::insert_return_type res = t2.insert(std::move(node));
EXPECT_TRUE(res.inserted);
EXPECT_THAT(*res.position, Pair(k0, ""));
EXPECT_FALSE(res.node);
@@ -1707,73 +1762,49 @@
EXPECT_FALSE(node);
}
-StringTable MakeSimpleTable(size_t size) {
- StringTable t;
- for (size_t i = 0; i < size; ++i) t.emplace(std::string(1, 'A' + i), "");
+IntTable MakeSimpleTable(size_t size) {
+ IntTable t;
+ while (t.size() < size) t.insert(t.size());
return t;
}
-std::string OrderOfIteration(const StringTable& t) {
- std::string order;
- for (auto& p : t) order += p.first;
- return order;
+std::vector<int> OrderOfIteration(const IntTable& t) {
+ return {t.begin(), t.end()};
}
+// These IterationOrderChanges tests depend on non-deterministic behavior.
+// We are injecting non-determinism from the pointer of the table, but do so in
+// a way that only the page matters. We have to retry enough times to make sure
+// we are touching different memory pages to cause the ordering to change.
+// We also need to keep the old tables around to avoid getting the same memory
+// blocks over and over.
TEST(Table, IterationOrderChangesByInstance) {
- // Needs to be more than kWidth elements to be able to affect order.
- const StringTable reference = MakeSimpleTable(20);
+ for (size_t size : {2, 6, 12, 20}) {
+ const auto reference_table = MakeSimpleTable(size);
+ const auto reference = OrderOfIteration(reference_table);
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed. It should not take many tries
- // for that.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- std::vector<StringTable> garbage;
- for (int i = 0; i < 10; ++i) {
- auto trial = MakeSimpleTable(20);
- if (OrderOfIteration(trial) != OrderOfIteration(reference)) {
- // We are done.
- return;
+ std::vector<IntTable> tables;
+ bool found_difference = false;
+ for (int i = 0; !found_difference && i < 500; ++i) {
+ tables.push_back(MakeSimpleTable(size));
+ found_difference = OrderOfIteration(tables.back()) != reference;
}
- garbage.push_back(std::move(trial));
+ if (!found_difference) {
+ FAIL()
+ << "Iteration order remained the same across many attempts with size "
+ << size;
+ }
}
- FAIL();
}
TEST(Table, IterationOrderChangesOnRehash) {
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed. It should not take many tries
- // for that.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- std::vector<StringTable> garbage;
- for (int i = 0; i < 10; ++i) {
- // Needs to be more than kWidth elements to be able to affect order.
- StringTable t = MakeSimpleTable(20);
- const std::string reference = OrderOfIteration(t);
+ std::vector<IntTable> garbage;
+ for (int i = 0; i < 500; ++i) {
+ auto t = MakeSimpleTable(20);
+ const auto reference = OrderOfIteration(t);
// Force rehash to the same size.
t.rehash(0);
- std::string trial = OrderOfIteration(t);
- if (trial != reference) {
- // We are done.
- return;
- }
- garbage.push_back(std::move(t));
- }
- FAIL();
-}
-
-TEST(Table, IterationOrderChangesForSmallTables) {
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- StringTable reference_table = MakeSimpleTable(5);
- const std::string reference = OrderOfIteration(reference_table);
- std::vector<StringTable> garbage;
- for (int i = 0; i < 50; ++i) {
- StringTable t = MakeSimpleTable(5);
- std::string trial = OrderOfIteration(t);
+ auto trial = OrderOfIteration(t);
if (trial != reference) {
// We are done.
return;
@@ -1783,136 +1814,22 @@
FAIL() << "Iteration order remained the same across many attempts.";
}
-// Fill the table to 3 different load factors (min, median, max) and evaluate
-// the percentage of perfect hits using the debug API.
-template <class Table, class AddFn>
-std::vector<double> CollectPerfectRatios(Table t, AddFn add) {
- using Key = typename Table::key_type;
+// Verify that pointers are invalidated as soon as a second element is inserted.
+// This prevents dependency on pointer stability on small tables.
+TEST(Table, UnstablePointers) {
+ IntTable table;
- // First, fill enough to have a good distribution.
- constexpr size_t kMinSize = 10000;
- std::vector<Key> keys;
- while (t.size() < kMinSize) keys.push_back(add(t));
- // Then, insert until we reach min load factor.
- double lf = t.load_factor();
- while (lf <= t.load_factor()) keys.push_back(add(t));
-
- // We are now at min load factor. Take a snapshot.
- size_t perfect = 0;
- auto update_perfect = [&](Key k) {
- perfect += GetHashtableDebugNumProbes(t, k) == 0;
+ const auto addr = [&](int i) {
+ return reinterpret_cast<uintptr_t>(&*table.find(i));
};
- for (const auto& k : keys) update_perfect(k);
- std::vector<double> perfect_ratios;
- // Keep going until we hit max load factor.
- while (t.load_factor() < .6) {
- perfect_ratios.push_back(1.0 * perfect / t.size());
- update_perfect(add(t));
- }
- while (t.load_factor() > .5) {
- perfect_ratios.push_back(1.0 * perfect / t.size());
- update_perfect(add(t));
- }
- return perfect_ratios;
-}
+ table.insert(0);
+ const uintptr_t old_ptr = addr(0);
-std::vector<std::pair<double, double>> StringTablePefectRatios() {
- constexpr bool kRandomizesInserts =
-#if NDEBUG
- false;
-#else // NDEBUG
- true;
-#endif // NDEBUG
+ // This causes a rehash.
+ table.insert(1);
- // The effective load factor is larger in non-opt mode because we insert
- // elements out of order.
- switch (container_internal::Group::kWidth) {
- case 8:
- if (kRandomizesInserts) {
- return {{0.986, 0.02}, {0.95, 0.02}, {0.89, 0.02}};
- } else {
- return {{0.995, 0.01}, {0.97, 0.01}, {0.89, 0.02}};
- }
- break;
- case 16:
- if (kRandomizesInserts) {
- return {{0.973, 0.01}, {0.965, 0.01}, {0.92, 0.02}};
- } else {
- return {{0.995, 0.005}, {0.99, 0.005}, {0.94, 0.01}};
- }
- break;
- default:
- // Ignore anything else.
- return {};
- }
-}
-
-// This is almost a change detector, but it allows us to know how we are
-// affecting the probe distribution.
-TEST(Table, EffectiveLoadFactorStrings) {
- std::vector<double> perfect_ratios =
- CollectPerfectRatios(StringTable(), [](StringTable& t) {
- return t.emplace(std::to_string(t.size()), "").first->first;
- });
-
- auto ratios = StringTablePefectRatios();
- if (ratios.empty()) return;
-
- EXPECT_THAT(perfect_ratios.front(),
- DoubleNear(ratios[0].first, ratios[0].second));
- EXPECT_THAT(perfect_ratios[perfect_ratios.size() / 2],
- DoubleNear(ratios[1].first, ratios[1].second));
- EXPECT_THAT(perfect_ratios.back(),
- DoubleNear(ratios[2].first, ratios[2].second));
-}
-
-std::vector<std::pair<double, double>> IntTablePefectRatios() {
- constexpr bool kRandomizesInserts =
-#ifdef NDEBUG
- false;
-#else // NDEBUG
- true;
-#endif // NDEBUG
-
- // The effective load factor is larger in non-opt mode because we insert
- // elements out of order.
- switch (container_internal::Group::kWidth) {
- case 8:
- if (kRandomizesInserts) {
- return {{0.99, 0.02}, {0.985, 0.02}, {0.95, 0.05}};
- } else {
- return {{0.99, 0.01}, {0.99, 0.01}, {0.95, 0.02}};
- }
- break;
- case 16:
- if (kRandomizesInserts) {
- return {{0.98, 0.02}, {0.978, 0.02}, {0.96, 0.02}};
- } else {
- return {{0.998, 0.003}, {0.995, 0.01}, {0.975, 0.02}};
- }
- break;
- default:
- // Ignore anything else.
- return {};
- }
-}
-
-// This is almost a change detector, but it allows us to know how we are
-// affecting the probe distribution.
-TEST(Table, EffectiveLoadFactorInts) {
- std::vector<double> perfect_ratios = CollectPerfectRatios(
- IntTable(), [](IntTable& t) { return *t.emplace(t.size()).first; });
-
- auto ratios = IntTablePefectRatios();
- if (ratios.empty()) return;
-
- EXPECT_THAT(perfect_ratios.front(),
- DoubleNear(ratios[0].first, ratios[0].second));
- EXPECT_THAT(perfect_ratios[perfect_ratios.size() / 2],
- DoubleNear(ratios[1].first, ratios[1].second));
- EXPECT_THAT(perfect_ratios.back(),
- DoubleNear(ratios[2].first, ratios[2].second));
+ EXPECT_NE(old_ptr, addr(0));
}
// Confirm that we assert if we try to erase() end().
@@ -1931,9 +1848,31 @@
EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
}
+TEST(RawHashSamplerTest, Sample) {
+ // Enable the feature even if the prod default is off.
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+
+ auto& sampler = HashtablezSampler::Global();
+ size_t start_size = 0;
+ start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
+
+ std::vector<IntTable> tables;
+ for (int i = 0; i < 1000000; ++i) {
+ tables.emplace_back();
+ tables.back().insert(1);
+ }
+ size_t end_size = 0;
+ end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
+
+ EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
+ 0.01, 0.005);
+}
+
#ifdef ADDRESS_SANITIZER
TEST(Sanitizer, PoisoningUnused) {
IntTable t;
+ t.reserve(5);
// Insert something to force an allocation.
int64_t& v1 = *t.insert(0).first;
diff --git a/absl/container/internal/test_instance_tracker.cc b/absl/container/internal/test_instance_tracker.cc
index b18e0bb..5a66cb4 100644
--- a/absl/container/internal/test_instance_tracker.cc
+++ b/absl/container/internal/test_instance_tracker.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/test_instance_tracker.h b/absl/container/internal/test_instance_tracker.h
index ec45f57..032d16d 100644
--- a/absl/container/internal/test_instance_tracker.h
+++ b/absl/container/internal/test_instance_tracker.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/test_instance_tracker_test.cc b/absl/container/internal/test_instance_tracker_test.cc
index 0ae5763..091f428 100644
--- a/absl/container/internal/test_instance_tracker_test.cc
+++ b/absl/container/internal/test_instance_tracker_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/tracked.h b/absl/container/internal/tracked.h
index 7d14af0..75173ab 100644
--- a/absl/container/internal/tracked.h
+++ b/absl/container/internal/tracked.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h
index 2ffb646..68817e4 100644
--- a/absl/container/internal/unordered_map_constructor_test.h
+++ b/absl/container/internal/unordered_map_constructor_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,7 +29,7 @@
template <class UnordMap>
class ConstructorTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ConstructorTest);
+TYPED_TEST_SUITE_P(ConstructorTest);
TYPED_TEST_P(ConstructorTest, NoArgs) {
TypeParam m;
@@ -83,8 +83,28 @@
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+template <typename T>
+struct is_std_unordered_map : std::false_type {};
+
+template <typename... T>
+struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {};
+
#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+using has_cxx14_std_apis = std::true_type;
+#else
+using has_cxx14_std_apis = std::false_type;
+#endif
+
+template <typename T>
+using expect_cxx14_apis =
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
+ has_cxx14_std_apis>;
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
@@ -92,11 +112,17 @@
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::true_type) {
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
@@ -107,18 +133,38 @@
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketAlloc) {
+TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+using has_alloc_std_constructors = std::true_type;
+#else
+using has_alloc_std_constructors = std::false_type;
+#endif
+
+template <typename T>
+using expect_alloc_constructors =
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
+ has_alloc_std_constructors>;
+
+template <typename TypeParam>
+void AllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void AllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, Alloc) {
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
@@ -140,8 +186,11 @@
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
@@ -152,11 +201,17 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -170,7 +225,10 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, CopyConstructor) {
@@ -190,8 +248,11 @@
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -206,7 +267,10 @@
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on copy constructors.
@@ -229,8 +293,11 @@
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -246,7 +313,10 @@
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on move constructors.
@@ -269,8 +339,11 @@
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::Generator<T> gen;
@@ -280,11 +353,17 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -297,7 +376,10 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, Assignment) {
@@ -390,15 +472,16 @@
REGISTER_TYPED_TEST_CASE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
- BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc,
- BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
- MoveAssignment, AssignmentFromInitializerList,
- AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting,
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
+ MoveAssignmentOverwritesExisting,
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_map_lookup_test.h b/absl/container/internal/unordered_map_lookup_test.h
index 1f1b6b4..ebd3612 100644
--- a/absl/container/internal/unordered_map_lookup_test.h
+++ b/absl/container/internal/unordered_map_lookup_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,7 +26,7 @@
template <class UnordMap>
class LookupTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(LookupTest);
+TYPED_TEST_SUITE_P(LookupTest);
TYPED_TEST_P(LookupTest, At) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -111,4 +111,5 @@
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_map_members_test.h b/absl/container/internal/unordered_map_members_test.h
new file mode 100644
index 0000000..1bf31ab
--- /dev/null
+++ b/absl/container/internal/unordered_map_members_test.h
@@ -0,0 +1,85 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
+#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
+
+#include <type_traits>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+namespace container_internal {
+
+template <class UnordMap>
+class MembersTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(MembersTest);
+
+template <typename T>
+void UseType() {}
+
+TYPED_TEST_P(MembersTest, Typedefs) {
+ EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type,
+ typename TypeParam::mapped_type>,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((absl::conjunction<
+ absl::negation<std::is_signed<typename TypeParam::size_type>>,
+ std::is_integral<typename TypeParam::size_type>>()));
+ EXPECT_TRUE((absl::conjunction<
+ std::is_signed<typename TypeParam::difference_type>,
+ std::is_integral<typename TypeParam::difference_type>>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::hasher&>()(
+ std::declval<const typename TypeParam::key_type&>())),
+ size_t>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::key_equal&>()(
+ std::declval<const typename TypeParam::key_type&>(),
+ std::declval<const typename TypeParam::key_type&>())),
+ bool>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::value_type&,
+ typename TypeParam::reference>()));
+ EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&,
+ typename TypeParam::const_reference>()));
+ EXPECT_TRUE((std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::pointer,
+ typename TypeParam::pointer>()));
+ EXPECT_TRUE(
+ (std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::const_pointer,
+ typename TypeParam::const_pointer>()));
+}
+
+TYPED_TEST_P(MembersTest, SimpleFunctions) {
+ EXPECT_GT(TypeParam().max_size(), 0);
+}
+
+TYPED_TEST_P(MembersTest, BeginEnd) {
+ TypeParam t = {typename TypeParam::value_type{}};
+ EXPECT_EQ(t.begin(), t.cbegin());
+ EXPECT_EQ(t.end(), t.cend());
+ EXPECT_NE(t.begin(), t.end());
+ EXPECT_NE(t.cbegin(), t.cend());
+}
+
+REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
+
+} // namespace container_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_modifiers_test.h b/absl/container/internal/unordered_map_modifiers_test.h
index b6c633a..52a1092 100644
--- a/absl/container/internal/unordered_map_modifiers_test.h
+++ b/absl/container/internal/unordered_map_modifiers_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,7 +26,7 @@
template <class UnordMap>
class ModifiersTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ModifiersTest);
+TYPED_TEST_SUITE_P(ModifiersTest);
TYPED_TEST_P(ModifiersTest, Clear) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -269,4 +269,5 @@
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_test.cc b/absl/container/internal/unordered_map_test.cc
index 40e799c..72567ea 100644
--- a/absl/container/internal/unordered_map_test.cc
+++ b/absl/container/internal/unordered_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,6 +16,7 @@
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
@@ -29,9 +30,10 @@
StatefulTestingEqual,
Alloc<std::pair<const std::string, std::string>>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ModifiersTest, MapTypes);
} // namespace
} // namespace container_internal
diff --git a/absl/container/internal/unordered_set_constructor_test.h b/absl/container/internal/unordered_set_constructor_test.h
index cb59370..f484468 100644
--- a/absl/container/internal/unordered_set_constructor_test.h
+++ b/absl/container/internal/unordered_set_constructor_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,12 +16,14 @@
#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
#include <algorithm>
+#include <unordered_set>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"
+#include "absl/meta/type_traits.h"
namespace absl {
namespace container_internal {
@@ -29,7 +31,7 @@
template <class UnordMap>
class ConstructorTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ConstructorTest);
+TYPED_TEST_SUITE_P(ConstructorTest);
TYPED_TEST_P(ConstructorTest, NoArgs) {
TypeParam m;
@@ -91,8 +93,28 @@
EXPECT_GE(cm.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+template <typename T>
+struct is_std_unordered_set : std::false_type {};
+
+template <typename... T>
+struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {};
+
#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+using has_cxx14_std_apis = std::true_type;
+#else
+using has_cxx14_std_apis = std::false_type;
+#endif
+
+template <typename T>
+using expect_cxx14_apis =
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
+ has_cxx14_std_apis>;
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
@@ -100,11 +122,17 @@
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::true_type) {
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
@@ -115,18 +143,38 @@
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketAlloc) {
+TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+using has_alloc_std_constructors = std::true_type;
+#else
+using has_alloc_std_constructors = std::false_type;
+#endif
+
+template <typename T>
+using expect_alloc_constructors =
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
+ has_alloc_std_constructors>;
+
+template <typename TypeParam>
+void AllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void AllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, Alloc) {
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
@@ -148,8 +196,11 @@
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
@@ -160,11 +211,17 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -178,7 +235,10 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, CopyConstructor) {
@@ -196,10 +256,14 @@
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
+ EXPECT_NE(TypeParam(0, hasher, equal, alloc), n);
}
-TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -214,7 +278,10 @@
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on copy constructors.
@@ -237,8 +304,11 @@
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -254,7 +324,10 @@
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on move constructors.
@@ -277,8 +350,11 @@
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::Generator<T> gen;
@@ -288,11 +364,17 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -305,10 +387,13 @@
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, Assignment) {
+TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+TYPED_TEST_P(ConstructorTest, CopyAssignment) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -394,15 +479,16 @@
REGISTER_TYPED_TEST_CASE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
- BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc,
- BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
- InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
- MoveAssignment, AssignmentFromInitializerList,
- AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting,
+ InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment,
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
+ MoveAssignmentOverwritesExisting,
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_set_lookup_test.h b/absl/container/internal/unordered_set_lookup_test.h
index aca9c6a..05b32b5 100644
--- a/absl/container/internal/unordered_set_lookup_test.h
+++ b/absl/container/internal/unordered_set_lookup_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,7 +26,7 @@
template <class UnordSet>
class LookupTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(LookupTest);
+TYPED_TEST_SUITE_P(LookupTest);
TYPED_TEST_P(LookupTest, Count) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -85,4 +85,5 @@
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_set_members_test.h b/absl/container/internal/unordered_set_members_test.h
new file mode 100644
index 0000000..b96c945
--- /dev/null
+++ b/absl/container/internal/unordered_set_members_test.h
@@ -0,0 +1,84 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
+#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
+
+#include <type_traits>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+namespace container_internal {
+
+template <class UnordSet>
+class MembersTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(MembersTest);
+
+template <typename T>
+void UseType() {}
+
+TYPED_TEST_P(MembersTest, Typedefs) {
+ EXPECT_TRUE((std::is_same<typename TypeParam::key_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((absl::conjunction<
+ absl::negation<std::is_signed<typename TypeParam::size_type>>,
+ std::is_integral<typename TypeParam::size_type>>()));
+ EXPECT_TRUE((absl::conjunction<
+ std::is_signed<typename TypeParam::difference_type>,
+ std::is_integral<typename TypeParam::difference_type>>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::hasher&>()(
+ std::declval<const typename TypeParam::key_type&>())),
+ size_t>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::key_equal&>()(
+ std::declval<const typename TypeParam::key_type&>(),
+ std::declval<const typename TypeParam::key_type&>())),
+ bool>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::value_type&,
+ typename TypeParam::reference>()));
+ EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&,
+ typename TypeParam::const_reference>()));
+ EXPECT_TRUE((std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::pointer,
+ typename TypeParam::pointer>()));
+ EXPECT_TRUE(
+ (std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::const_pointer,
+ typename TypeParam::const_pointer>()));
+}
+
+TYPED_TEST_P(MembersTest, SimpleFunctions) {
+ EXPECT_GT(TypeParam().max_size(), 0);
+}
+
+TYPED_TEST_P(MembersTest, BeginEnd) {
+ TypeParam t = {typename TypeParam::value_type{}};
+ EXPECT_EQ(t.begin(), t.cbegin());
+ EXPECT_EQ(t.end(), t.cend());
+ EXPECT_NE(t.begin(), t.end());
+ EXPECT_NE(t.cbegin(), t.cend());
+}
+
+REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
+
+} // namespace container_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_modifiers_test.h b/absl/container/internal/unordered_set_modifiers_test.h
index 9beacf3..79a8d42 100644
--- a/absl/container/internal/unordered_set_modifiers_test.h
+++ b/absl/container/internal/unordered_set_modifiers_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,7 +26,7 @@
template <class UnordSet>
class ModifiersTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ModifiersTest);
+TYPED_TEST_SUITE_P(ModifiersTest);
TYPED_TEST_P(ModifiersTest, Clear) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -184,4 +184,5 @@
} // namespace container_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_test.cc b/absl/container/internal/unordered_set_test.cc
index 1281ce5..6478fac 100644
--- a/absl/container/internal/unordered_set_test.cc
+++ b/absl/container/internal/unordered_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,21 +16,23 @@
#include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h"
+#include "absl/container/internal/unordered_set_members_test.h"
#include "absl/container/internal/unordered_set_modifiers_test.h"
namespace absl {
namespace container_internal {
namespace {
-using SetTypes =
- ::testing::Types<std::unordered_set<int, StatefulTestingHash,
- StatefulTestingEqual, Alloc<int>>,
- std::unordered_set<std::string, StatefulTestingHash,
- StatefulTestingEqual, Alloc<std::string>>>;
+using SetTypes = ::testing::Types<
+ std::unordered_set<int, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<int>>,
+ std::unordered_set<std::string, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<std::string>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ModifiersTest, SetTypes);
} // namespace
} // namespace container_internal
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 6369ec3..a841f5a 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -40,6 +40,7 @@
#include <type_traits>
#include <utility>
+#include "absl/algorithm/container.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/node_hash_policy.h"
@@ -71,7 +72,7 @@
// By default, `node_hash_map` uses the `absl::Hash` hashing framework.
// All fundamental and Abseil types that support the `absl::Hash` framework have
// a compatible equality operator for comparing insertions into `node_hash_map`.
-// If your type is not yet supported by the `asbl::Hash` framework, see
+// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
@@ -91,7 +92,7 @@
// std::string search_key = "b";
// auto result = ducks.find(search_key);
// if (result != ducks.end()) {
-// std::cout << "Result: " << search_key->second << std::endl;
+// std::cout << "Result: " << result->second << std::endl;
// }
template <class Key, class Value,
class Hash = absl::container_internal::hash_default_hash<Key>,
@@ -104,6 +105,46 @@
using Base = typename node_hash_map::raw_hash_map;
public:
+ // Constructors and Assignment Operators
+ //
+ // A node_hash_map supports the same overload set as `std::unordered_map`
+ // for construction and assignment:
+ //
+ // * Default constructor
+ //
+ // // No allocation for the table's elements is made.
+ // absl::node_hash_map<int, std::string> map1;
+ //
+ // * Initializer List constructor
+ //
+ // absl::node_hash_map<int, std::string> map2 =
+ // {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+ //
+ // * Copy constructor
+ //
+ // absl::node_hash_map<int, std::string> map3(map2);
+ //
+ // * Copy assignment operator
+ //
+ // // Hash functor and Comparator are copied as well
+ // absl::node_hash_map<int, std::string> map4;
+ // map4 = map3;
+ //
+ // * Move constructor
+ //
+ // // Move is guaranteed efficient
+ // absl::node_hash_map<int, std::string> map5(std::move(map4));
+ //
+ // * Move assignment operator
+ //
+ // // May be efficient if allocators are compatible
+ // absl::node_hash_map<int, std::string> map6;
+ // map6 = std::move(map5);
+ //
+ // * Range constructor
+ //
+ // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+ // absl::node_hash_map<int, std::string> map7(v.begin(), v.end());
node_hash_map() {}
using Base::Base;
@@ -526,5 +567,16 @@
static const Value& value(const value_type* elem) { return elem->second; }
};
} // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+ absl::node_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+} // namespace container_algorithm_internal
+
} // namespace absl
+
#endif // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
index bd78964..0f2714a 100644
--- a/absl/container/node_hash_map_test.cc
+++ b/absl/container/node_hash_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,6 +17,7 @@
#include "absl/container/internal/tracked.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
@@ -34,9 +35,10 @@
StatefulTestingEqual,
Alloc<std::pair<const std::string, std::string>>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ModifiersTest, MapTypes);
using M = absl::node_hash_map<std::string, Tracked<int>>;
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index 90d4ce0..0cd1fe5 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -37,6 +37,7 @@
#include <type_traits>
+#include "absl/algorithm/container.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/node_hash_policy.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
@@ -67,7 +68,7 @@
// By default, `node_hash_set` uses the `absl::Hash` hashing framework.
// All fundamental and Abseil types that support the `absl::Hash` framework have
// a compatible equality operator for comparing insertions into `node_hash_set`.
-// If your type is not yet supported by the `asbl::Hash` framework, see
+// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
@@ -96,6 +97,46 @@
using Base = typename node_hash_set::raw_hash_set;
public:
+ // Constructors and Assignment Operators
+ //
+ // A node_hash_set supports the same overload set as `std::unordered_map`
+ // for construction and assignment:
+ //
+ // * Default constructor
+ //
+ // // No allocation for the table's elements is made.
+ // absl::node_hash_set<std::string> set1;
+ //
+ // * Initializer List constructor
+ //
+ // absl::node_hash_set<std::string> set2 =
+ // {{"huey"}, {"dewey"}, {"louie"},};
+ //
+ // * Copy constructor
+ //
+ // absl::node_hash_set<std::string> set3(set2);
+ //
+ // * Copy assignment operator
+ //
+ // // Hash functor and Comparator are copied as well
+ // absl::node_hash_set<std::string> set4;
+ // set4 = set3;
+ //
+ // * Move constructor
+ //
+ // // Move is guaranteed efficient
+ // absl::node_hash_set<std::string> set5(std::move(set4));
+ //
+ // * Move assignment operator
+ //
+ // // May be efficient if allocators are compatible
+ // absl::node_hash_set<std::string> set6;
+ // set6 = std::move(set5);
+ //
+ // * Range constructor
+ //
+ // std::vector<std::string> v = {"a", "b"};
+ // absl::node_hash_set<std::string> set7(v.begin(), v.end());
node_hash_set() {}
using Base::Base;
@@ -232,8 +273,7 @@
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;
@@ -247,8 +287,7 @@
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;
@@ -435,5 +474,15 @@
static size_t element_space_used(const T*) { return sizeof(T); }
};
} // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::node_hash_set<Key, Hash, KeyEqual, Allocator>>
+ : std::true_type {};
+
+} // namespace container_algorithm_internal
} // namespace absl
+
#endif // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/absl/container/node_hash_set_test.cc b/absl/container/node_hash_set_test.cc
index 7e498f0..0ea76e7 100644
--- a/absl/container/node_hash_set_test.cc
+++ b/absl/container/node_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,6 +16,7 @@
#include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h"
+#include "absl/container/internal/unordered_set_members_test.h"
#include "absl/container/internal/unordered_set_modifiers_test.h"
namespace absl {
@@ -29,14 +30,15 @@
using SetTypes = ::testing::Types<
node_hash_set<int, StatefulTestingHash, StatefulTestingEqual, Alloc<int>>,
node_hash_set<std::string, StatefulTestingHash, StatefulTestingEqual,
- Alloc<int>>,
+ Alloc<std::string>>,
node_hash_set<Enum, StatefulTestingHash, StatefulTestingEqual, Alloc<Enum>>,
node_hash_set<EnumClass, StatefulTestingHash, StatefulTestingEqual,
Alloc<EnumClass>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ModifiersTest, SetTypes);
TEST(NodeHashSet, MoveableNotCopyableCompiles) {
node_hash_set<std::unique_ptr<void*>> t;
diff --git a/absl/copts.bzl b/absl/copts.bzl
deleted file mode 100644
index 5c508f1..0000000
--- a/absl/copts.bzl
+++ /dev/null
@@ -1,164 +0,0 @@
-"""absl specific copts.
-
-Flags specified here must not impact ABI. Code compiled with and without these
-opts will be linked together, and in some cases headers compiled with and
-without these options will be part of the same program.
-"""
-GCC_FLAGS = [
- "-Wall",
- "-Wextra",
- "-Wcast-qual",
- "-Wconversion-null",
- "-Wmissing-declarations",
- "-Woverlength-strings",
- "-Wpointer-arith",
- "-Wunused-local-typedefs",
- "-Wunused-result",
- "-Wvarargs",
- "-Wvla", # variable-length array
- "-Wwrite-strings",
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
-]
-
-GCC_TEST_FLAGS = [
- "-Wno-conversion-null",
- "-Wno-missing-declarations",
- "-Wno-sign-compare",
- "-Wno-unused-function",
- "-Wno-unused-parameter",
- "-Wno-unused-private-field",
-]
-
-# Docs on single flags is preceded by a comment.
-# Docs on groups of flags is preceded by ###.
-
-LLVM_FLAGS = [
- "-Wall",
- "-Wextra",
- "-Weverything",
- # Abseil does not support C++98
- "-Wno-c++98-compat-pedantic",
- # Turns off all implicit conversion warnings. Most are re-enabled below.
- "-Wno-conversion",
- "-Wno-covered-switch-default",
- "-Wno-deprecated",
- "-Wno-disabled-macro-expansion",
- "-Wno-double-promotion",
- ###
- # Turned off as they include valid C++ code.
- "-Wno-comma",
- "-Wno-extra-semi",
- "-Wno-packed",
- "-Wno-padded",
- ###
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
- ###
- "-Wno-float-conversion",
- "-Wno-float-equal",
- "-Wno-format-nonliteral",
- # Too aggressive: warns on Clang extensions enclosed in Clang-only
- # compilation paths.
- "-Wno-gcc-compat",
- ###
- # Some internal globals are necessary. Don't do this at home.
- "-Wno-global-constructors",
- "-Wno-exit-time-destructors",
- ###
- "-Wno-nested-anon-types",
- "-Wno-non-modular-include-in-module",
- "-Wno-old-style-cast",
- # Warns on preferred usage of non-POD types such as string_view
- "-Wno-range-loop-analysis",
- "-Wno-reserved-id-macro",
- "-Wno-shorten-64-to-32",
- "-Wno-switch-enum",
- "-Wno-thread-safety-negative",
- "-Wno-undef",
- "-Wno-unknown-warning-option",
- "-Wno-unreachable-code",
- # Causes warnings on include guards
- "-Wno-unused-macros",
- "-Wno-weak-vtables",
- ###
- # Implicit conversion warnings turned off by -Wno-conversion
- # which are re-enabled below.
- "-Wbitfield-enum-conversion",
- "-Wbool-conversion",
- "-Wconstant-conversion",
- "-Wenum-conversion",
- "-Wint-conversion",
- "-Wliteral-conversion",
- "-Wnon-literal-null-conversion",
- "-Wnull-conversion",
- "-Wobjc-literal-conversion",
- "-Wno-sign-conversion",
- "-Wstring-conversion",
- ###
-]
-
-LLVM_TEST_FLAGS = [
- "-Wno-c99-extensions",
- "-Wno-missing-noreturn",
- "-Wno-missing-prototypes",
- "-Wno-missing-variable-declarations",
- "-Wno-null-conversion",
- "-Wno-shadow",
- "-Wno-shift-sign-overflow",
- "-Wno-sign-compare",
- "-Wno-unused-function",
- "-Wno-unused-member-function",
- "-Wno-unused-parameter",
- "-Wno-unused-private-field",
- "-Wno-unused-template",
- "-Wno-used-but-marked-unused",
- "-Wno-zero-as-null-pointer-constant",
- # gtest depends on this GNU extension being offered.
- "-Wno-gnu-zero-variadic-macro-arguments",
-]
-
-MSVC_FLAGS = [
- "/W3",
- "/wd4005", # macro-redefinition
- "/wd4068", # unknown pragma
- "/wd4180", # qualifier applied to function type has no meaning; ignored
- "/wd4244", # conversion from 'type1' to 'type2', possible loss of data
- "/wd4267", # conversion from 'size_t' to 'type', possible loss of data
- "/wd4800", # forcing value to bool 'true' or 'false' (performance warning)
- "/DNOMINMAX", # Don't define min and max macros (windows.h)
- "/DWIN32_LEAN_AND_MEAN", # Don't bloat namespace with incompatible winsock versions.
- "/D_CRT_SECURE_NO_WARNINGS", # Don't warn about usage of insecure C functions
-]
-
-MSVC_TEST_FLAGS = [
- "/wd4018", # signed/unsigned mismatch
- "/wd4101", # unreferenced local variable
- "/wd4503", # decorated name length exceeded, name was truncated
-]
-
-# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
-ABSL_DEFAULT_COPTS = select({
- "//absl:windows": MSVC_FLAGS,
- "//absl:llvm_compiler": LLVM_FLAGS,
- "//conditions:default": GCC_FLAGS,
-})
-
-# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
-# to their (included header) dependencies and fail to build outside absl
-ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
- "//absl:windows": MSVC_TEST_FLAGS,
- "//absl:llvm_compiler": LLVM_TEST_FLAGS,
- "//conditions:default": GCC_TEST_FLAGS,
-})
-
-ABSL_EXCEPTIONS_FLAG = select({
- "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"],
- "//conditions:default": ["-fexceptions"],
-})
-
-ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({
- "//conditions:default": [],
-})
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
new file mode 100644
index 0000000..5084958
--- /dev/null
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -0,0 +1,52 @@
+# See absl/copts/copts.py and absl/copts/generate_copts.py
+include(GENERATED_AbseilCopts)
+
+set(ABSL_LSAN_LINKOPTS "")
+set(ABSL_HAVE_LSAN OFF)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_GCC_EXCEPTIONS_FLAGS}")
+elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ # MATCHES so we get both Clang and AppleClang
+ if (MSVC)
+ # clang-cl is half MSVC, half LLVM
+ set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}")
+ else()
+ set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}")
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # AppleClang doesn't have lsan
+ # https://developer.apple.com/documentation/code_diagnostics
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5)
+ set(ABSL_LSAN_LINKOPTS "-fsanitize=leak")
+ set(ABSL_HAVE_LSAN ON)
+ endif()
+ endif()
+ endif()
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_MSVC_EXCEPTIONS_FLAGS}")
+else()
+ message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags")
+ set(ABSL_DEFAULT_COPTS "")
+ set(ABSL_TEST_COPTS "")
+ set(ABSL_EXCEPTIONS_FLAG "")
+endif()
+
+# This flag is used internally for Bazel builds and is kept here for consistency
+set(ABSL_EXCEPTIONS_FLAG_LINKOPTS "")
+
+if("${CMAKE_CXX_STANDARD}" EQUAL 98)
+ message(FATAL_ERROR "Abseil requires at least C++11")
+elseif(NOT "${CMAKE_CXX_STANDARD}")
+ message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
+ set(ABSL_CXX_STANDARD 11)
+else()
+ set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
+endif()
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
new file mode 100644
index 0000000..9031bfa
--- /dev/null
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -0,0 +1,208 @@
+# GENERATED! DO NOT MANUALLY EDIT THIS FILE.
+#
+# (1) Edit absl/copts/copts.py.
+# (2) Run `python <path_to_absl>/copts/generate_copts.py`.
+
+list(APPEND ABSL_CLANG_CL_EXCEPTIONS_FLAGS
+ "/U_HAS_EXCEPTIONS"
+ "/D_HAS_EXCEPTIONS=1"
+ "/EHsc"
+)
+
+list(APPEND ABSL_CLANG_CL_FLAGS
+ "/W3"
+ "-Wno-c++98-compat-pedantic"
+ "-Wno-conversion"
+ "-Wno-covered-switch-default"
+ "-Wno-deprecated"
+ "-Wno-disabled-macro-expansion"
+ "-Wno-double-promotion"
+ "-Wno-comma"
+ "-Wno-extra-semi"
+ "-Wno-extra-semi-stmt"
+ "-Wno-packed"
+ "-Wno-padded"
+ "-Wno-sign-compare"
+ "-Wno-float-conversion"
+ "-Wno-float-equal"
+ "-Wno-format-nonliteral"
+ "-Wno-gcc-compat"
+ "-Wno-global-constructors"
+ "-Wno-exit-time-destructors"
+ "-Wno-nested-anon-types"
+ "-Wno-non-modular-include-in-module"
+ "-Wno-old-style-cast"
+ "-Wno-range-loop-analysis"
+ "-Wno-reserved-id-macro"
+ "-Wno-shorten-64-to-32"
+ "-Wno-switch-enum"
+ "-Wno-thread-safety-negative"
+ "-Wno-undef"
+ "-Wno-unknown-warning-option"
+ "-Wno-unreachable-code"
+ "-Wno-unused-macros"
+ "-Wno-weak-vtables"
+ "-Wbitfield-enum-conversion"
+ "-Wbool-conversion"
+ "-Wconstant-conversion"
+ "-Wenum-conversion"
+ "-Wint-conversion"
+ "-Wliteral-conversion"
+ "-Wnon-literal-null-conversion"
+ "-Wnull-conversion"
+ "-Wobjc-literal-conversion"
+ "-Wno-sign-conversion"
+ "-Wstring-conversion"
+ "/DNOMINMAX"
+ "/DWIN32_LEAN_AND_MEAN"
+ "/D_CRT_SECURE_NO_WARNINGS"
+ "/D_SCL_SECURE_NO_WARNINGS"
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+)
+
+list(APPEND ABSL_CLANG_CL_TEST_FLAGS
+ "-Wno-c99-extensions"
+ "-Wno-missing-noreturn"
+ "-Wno-missing-prototypes"
+ "-Wno-missing-variable-declarations"
+ "-Wno-null-conversion"
+ "-Wno-shadow"
+ "-Wno-shift-sign-overflow"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-member-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+ "-Wno-unused-template"
+ "-Wno-used-but-marked-unused"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wno-gnu-zero-variadic-macro-arguments"
+)
+
+list(APPEND ABSL_GCC_EXCEPTIONS_FLAGS
+ "-fexceptions"
+)
+
+list(APPEND ABSL_GCC_FLAGS
+ "-Wall"
+ "-Wextra"
+ "-Wcast-qual"
+ "-Wconversion-null"
+ "-Wmissing-declarations"
+ "-Woverlength-strings"
+ "-Wpointer-arith"
+ "-Wunused-local-typedefs"
+ "-Wunused-result"
+ "-Wvarargs"
+ "-Wvla"
+ "-Wwrite-strings"
+ "-Wno-missing-field-initializers"
+ "-Wno-sign-compare"
+)
+
+list(APPEND ABSL_GCC_TEST_FLAGS
+ "-Wno-conversion-null"
+ "-Wno-missing-declarations"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+)
+
+list(APPEND ABSL_LLVM_EXCEPTIONS_FLAGS
+ "-fexceptions"
+)
+
+list(APPEND ABSL_LLVM_FLAGS
+ "-Wall"
+ "-Wextra"
+ "-Weverything"
+ "-Wno-c++98-compat-pedantic"
+ "-Wno-conversion"
+ "-Wno-covered-switch-default"
+ "-Wno-deprecated"
+ "-Wno-disabled-macro-expansion"
+ "-Wno-double-promotion"
+ "-Wno-comma"
+ "-Wno-extra-semi"
+ "-Wno-extra-semi-stmt"
+ "-Wno-packed"
+ "-Wno-padded"
+ "-Wno-sign-compare"
+ "-Wno-float-conversion"
+ "-Wno-float-equal"
+ "-Wno-format-nonliteral"
+ "-Wno-gcc-compat"
+ "-Wno-global-constructors"
+ "-Wno-exit-time-destructors"
+ "-Wno-nested-anon-types"
+ "-Wno-non-modular-include-in-module"
+ "-Wno-old-style-cast"
+ "-Wno-range-loop-analysis"
+ "-Wno-reserved-id-macro"
+ "-Wno-shorten-64-to-32"
+ "-Wno-switch-enum"
+ "-Wno-thread-safety-negative"
+ "-Wno-undef"
+ "-Wno-unknown-warning-option"
+ "-Wno-unreachable-code"
+ "-Wno-unused-macros"
+ "-Wno-weak-vtables"
+ "-Wbitfield-enum-conversion"
+ "-Wbool-conversion"
+ "-Wconstant-conversion"
+ "-Wenum-conversion"
+ "-Wint-conversion"
+ "-Wliteral-conversion"
+ "-Wnon-literal-null-conversion"
+ "-Wnull-conversion"
+ "-Wobjc-literal-conversion"
+ "-Wno-sign-conversion"
+ "-Wstring-conversion"
+)
+
+list(APPEND ABSL_LLVM_TEST_FLAGS
+ "-Wno-c99-extensions"
+ "-Wno-missing-noreturn"
+ "-Wno-missing-prototypes"
+ "-Wno-missing-variable-declarations"
+ "-Wno-null-conversion"
+ "-Wno-shadow"
+ "-Wno-shift-sign-overflow"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-member-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+ "-Wno-unused-template"
+ "-Wno-used-but-marked-unused"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wno-gnu-zero-variadic-macro-arguments"
+)
+
+list(APPEND ABSL_MSVC_EXCEPTIONS_FLAGS
+ "/U_HAS_EXCEPTIONS"
+ "/D_HAS_EXCEPTIONS=1"
+ "/EHsc"
+)
+
+list(APPEND ABSL_MSVC_FLAGS
+ "/W3"
+ "/DNOMINMAX"
+ "/DWIN32_LEAN_AND_MEAN"
+ "/D_CRT_SECURE_NO_WARNINGS"
+ "/D_SCL_SECURE_NO_WARNINGS"
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+ "/wd4005"
+ "/wd4068"
+ "/wd4180"
+ "/wd4244"
+ "/wd4267"
+ "/wd4800"
+)
+
+list(APPEND ABSL_MSVC_TEST_FLAGS
+ "/wd4018"
+ "/wd4101"
+ "/wd4503"
+)
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
new file mode 100644
index 0000000..e05a58e
--- /dev/null
+++ b/absl/copts/GENERATED_copts.bzl
@@ -0,0 +1,209 @@
+"""GENERATED! DO NOT MANUALLY EDIT THIS FILE.
+
+(1) Edit absl/copts/copts.py.
+(2) Run `python <path_to_absl>/copts/generate_copts.py`.
+"""
+
+ABSL_CLANG_CL_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS",
+ "/D_HAS_EXCEPTIONS=1",
+ "/EHsc",
+]
+
+ABSL_CLANG_CL_FLAGS = [
+ "/W3",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ "-Wno-sign-compare",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ "-Wno-gcc-compat",
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-undef",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+ "/DNOMINMAX",
+ "/DWIN32_LEAN_AND_MEAN",
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+]
+
+ABSL_CLANG_CL_TEST_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+ABSL_GCC_EXCEPTIONS_FLAGS = [
+ "-fexceptions",
+]
+
+ABSL_GCC_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion-null",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvarargs",
+ "-Wvla",
+ "-Wwrite-strings",
+ "-Wno-missing-field-initializers",
+ "-Wno-sign-compare",
+]
+
+ABSL_GCC_TEST_FLAGS = [
+ "-Wno-conversion-null",
+ "-Wno-missing-declarations",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+]
+
+ABSL_LLVM_EXCEPTIONS_FLAGS = [
+ "-fexceptions",
+]
+
+ABSL_LLVM_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Weverything",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ "-Wno-sign-compare",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ "-Wno-gcc-compat",
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-undef",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+]
+
+ABSL_LLVM_TEST_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+ABSL_MSVC_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS",
+ "/D_HAS_EXCEPTIONS=1",
+ "/EHsc",
+]
+
+ABSL_MSVC_FLAGS = [
+ "/W3",
+ "/DNOMINMAX",
+ "/DWIN32_LEAN_AND_MEAN",
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+ "/wd4005",
+ "/wd4068",
+ "/wd4180",
+ "/wd4244",
+ "/wd4267",
+ "/wd4800",
+]
+
+ABSL_MSVC_TEST_FLAGS = [
+ "/wd4018",
+ "/wd4101",
+ "/wd4503",
+]
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
new file mode 100644
index 0000000..1655add
--- /dev/null
+++ b/absl/copts/configure_copts.bzl
@@ -0,0 +1,42 @@
+"""absl specific copts.
+
+This file simply selects the correct options from the generated files. To
+change Abseil copts, edit absl/copts/copts.py
+"""
+
+load(
+ "//absl:copts/GENERATED_copts.bzl",
+ "ABSL_GCC_EXCEPTIONS_FLAGS",
+ "ABSL_GCC_FLAGS",
+ "ABSL_GCC_TEST_FLAGS",
+ "ABSL_LLVM_EXCEPTIONS_FLAGS",
+ "ABSL_LLVM_FLAGS",
+ "ABSL_LLVM_TEST_FLAGS",
+ "ABSL_MSVC_EXCEPTIONS_FLAGS",
+ "ABSL_MSVC_FLAGS",
+ "ABSL_MSVC_TEST_FLAGS",
+)
+
+ABSL_DEFAULT_COPTS = select({
+ "//absl:windows": ABSL_MSVC_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_FLAGS,
+ "//conditions:default": ABSL_GCC_FLAGS,
+})
+
+# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
+# to their (included header) dependencies and fail to build outside absl
+ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
+ "//absl:windows": ABSL_MSVC_TEST_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS,
+ "//conditions:default": ABSL_GCC_TEST_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG = select({
+ "//absl:windows": ABSL_MSVC_EXCEPTIONS_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_EXCEPTIONS_FLAGS,
+ "//conditions:default": ABSL_GCC_EXCEPTIONS_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({
+ "//conditions:default": [],
+})
diff --git a/absl/copts/copts.py b/absl/copts/copts.py
new file mode 100644
index 0000000..3c9d429
--- /dev/null
+++ b/absl/copts/copts.py
@@ -0,0 +1,178 @@
+"""Abseil compiler options.
+
+This is the source of truth for Abseil compiler options. To modify Abseil
+compilation options:
+
+ (1) Edit the appropriate list in this file based on the platform the flag is
+ needed on.
+ (2) Run `<path_to_absl>/copts/generate_copts.py`.
+
+The generated copts are consumed by configure_copts.bzl and
+AbseilConfigureCopts.cmake.
+"""
+
+# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
+MSVC_BIG_WARNING_FLAGS = [
+ "/W3",
+]
+
+LLVM_BIG_WARNING_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Weverything",
+]
+
+# Docs on single flags is preceded by a comment.
+# Docs on groups of flags is preceded by ###.
+LLVM_DISABLE_WARNINGS_FLAGS = [
+ # Abseil does not support C++98
+ "-Wno-c++98-compat-pedantic",
+ # Turns off all implicit conversion warnings. Most are re-enabled below.
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ ###
+ # Turned off as they include valid C++ code.
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ ###
+ # Google style does not use unsigned integers, though STL containers
+ # have unsigned types.
+ "-Wno-sign-compare",
+ ###
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ # Too aggressive: warns on Clang extensions enclosed in Clang-only
+ # compilation paths.
+ "-Wno-gcc-compat",
+ ###
+ # Some internal globals are necessary. Don't do this at home.
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ ###
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ # Warns on preferred usage of non-POD types such as string_view
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-undef",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ # Causes warnings on include guards
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ ###
+ # Implicit conversion warnings turned off by -Wno-conversion
+ # which are re-enabled below.
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+]
+
+LLVM_TEST_DISABLE_WARNINGS_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ # gtest depends on this GNU extension being offered.
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+MSVC_STYLE_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"
+]
+
+MSVC_DEFINES = [
+ "/DNOMINMAX", # Don't define min and max macros (windows.h)
+ # Don't bloat namespace with incompatible winsock versions.
+ "/DWIN32_LEAN_AND_MEAN",
+ # Don't warn about usage of insecure C functions.
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ # Introduced in VS 2017 15.8, allow overaligned types in aligned_storage
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+]
+
+COPT_VARS = {
+ "ABSL_GCC_FLAGS": [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion-null",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvarargs",
+ "-Wvla", # variable-length array
+ "-Wwrite-strings",
+ # gcc-4.x has spurious missing field initializer warnings.
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
+ # Remove when gcc-4.x is no longer supported.
+ "-Wno-missing-field-initializers",
+ # Google style does not use unsigned integers, though STL containers
+ # have unsigned types.
+ "-Wno-sign-compare",
+ ],
+ "ABSL_GCC_TEST_FLAGS": [
+ "-Wno-conversion-null",
+ "-Wno-missing-declarations",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ ],
+ "ABSL_GCC_EXCEPTIONS_FLAGS": ["-fexceptions"],
+ "ABSL_LLVM_FLAGS": LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS,
+ "ABSL_LLVM_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS,
+ "ABSL_LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"],
+ "ABSL_CLANG_CL_FLAGS": (MSVC_BIG_WARNING_FLAGS +
+ LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES),
+ "ABSL_CLANG_CL_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS,
+ "ABSL_CLANG_CL_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS,
+ "ABSL_MSVC_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [
+ "/wd4005", # macro-redefinition
+ "/wd4068", # unknown pragma
+ "/wd4180", # qualifier applied to function type has no meaning; ignored
+ "/wd4244", # conversion from 'type1' to 'type2', possible loss of data
+ "/wd4267", # conversion from 'size_t' to 'type', possible loss of data
+ # forcing value to bool 'true' or 'false' (performance warning)
+ "/wd4800",
+ ],
+ "ABSL_MSVC_TEST_FLAGS": [
+ "/wd4018", # signed/unsigned mismatch
+ "/wd4101", # unreferenced local variable
+ "/wd4503", # decorated name length exceeded, name was truncated
+ ],
+ "ABSL_MSVC_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS,
+}
diff --git a/absl/copts/generate_copts.py b/absl/copts/generate_copts.py
new file mode 100755
index 0000000..28b677e
--- /dev/null
+++ b/absl/copts/generate_copts.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+"""Generate Abseil compile compile option configs.
+
+Usage: <path_to_absl>/copts/generate_copts.py
+
+The configs are generated from copts.py.
+"""
+
+from os import path
+import sys
+from copts import COPT_VARS
+
+
+# Helper functions
+def file_header_lines():
+ return [
+ "GENERATED! DO NOT MANUALLY EDIT THIS FILE.", "",
+ "(1) Edit absl/copts/copts.py.",
+ "(2) Run `python <path_to_absl>/copts/generate_copts.py`."
+ ]
+
+
+def flatten(*lists):
+ return [item for sublist in lists for item in sublist]
+
+
+def relative_filename(filename):
+ return path.join(path.dirname(__file__), filename)
+
+
+# Style classes. These contain all the syntactic styling needed to generate a
+# copt file for different build tools.
+class CMakeStyle(object):
+ """Style object for CMake copts file."""
+
+ def separator(self):
+ return ""
+
+ def list_introducer(self, name):
+ return "list(APPEND " + name
+
+ def list_closer(self):
+ return ")\n"
+
+ def docstring(self):
+ return "\n".join((("# " + line).strip() for line in file_header_lines()))
+
+ def filename(self):
+ return "GENERATED_AbseilCopts.cmake"
+
+
+class StarlarkStyle(object):
+ """Style object for Starlark copts file."""
+
+ def separator(self):
+ return ","
+
+ def list_introducer(self, name):
+ return name + " = ["
+
+ def list_closer(self):
+ return "]\n"
+
+ def docstring(self):
+ docstring_quotes = "\"\"\""
+ return docstring_quotes + "\n".join(
+ flatten(file_header_lines(), [docstring_quotes]))
+
+ def filename(self):
+ return "GENERATED_copts.bzl"
+
+
+# Copt file generation
+def copt_list(name, arg_list, style):
+ make_line = lambda s: " \"" + s + "\"" + style.separator()
+ external_str_list = [make_line(s) for s in arg_list]
+
+ return "\n".join(
+ flatten(
+ [style.list_introducer(name)],
+ external_str_list,
+ [style.list_closer()]))
+
+
+def generate_copt_file(style):
+ """Creates a generated copt file using the given style object.
+
+ Args:
+ style: either StarlarkStyle() or CMakeStyle()
+ """
+ with open(relative_filename(style.filename()), "w") as f:
+ f.write(style.docstring())
+ f.write("\n")
+ for var_name, arg_list in sorted(COPT_VARS.items()):
+ f.write("\n")
+ f.write(copt_list(var_name, arg_list, style))
+
+
+def main(argv):
+ if len(argv) > 1:
+ raise RuntimeError("generate_copts needs no command line args")
+
+ generate_copt_file(StarlarkStyle())
+ generate_copt_file(CMakeStyle())
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index e1e7fce..c9184f9 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
@@ -149,6 +149,7 @@
copts = ABSL_DEFAULT_COPTS,
deps = [
"//absl/base",
+ "//absl/base:core_headers",
"//absl/base:dynamic_annotations",
],
)
@@ -180,22 +181,8 @@
cc_library(
name = "leak_check",
- srcs = select({
- # The leak checking interface depends on weak function
- # declarations that may not necessarily have definitions.
- # Windows doesn't support this, and ios requires
- # guaranteed definitions for weak symbols.
- "//absl:ios": [],
- "//absl:windows": [],
- "//conditions:default": [
- "leak_check.cc",
- ],
- }),
- hdrs = select({
- "//absl:ios": [],
- "//absl:windows": [],
- "//conditions:default": ["leak_check.h"],
- }),
+ srcs = ["leak_check.cc"],
+ hdrs = ["leak_check.h"],
deps = ["//absl/base:core_headers"],
)
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index 4af2ec8..dccd4a5 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,204 +14,292 @@
# limitations under the License.
#
-list(APPEND DEBUGGING_PUBLIC_HEADERS
- "failure_signal_handler.h"
- "leak_check.h"
- "stacktrace.h"
- "symbolize.h"
-)
-
-# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in
-# Bazel
-list(APPEND DEBUGGING_INTERNAL_HEADERS
- "internal/address_is_readable.h"
- "internal/demangle.h"
- "internal/elf_mem_image.h"
- "internal/examine_stack.h"
- "internal/stacktrace_config.h"
- "internal/symbolize.h"
- "internal/vdso_support.h"
-)
-
-list(APPEND DEBUGGING_INTERNAL_SRC
- "internal/address_is_readable.cc"
- "internal/elf_mem_image.cc"
- "internal/vdso_support.cc"
-)
-
-
-list(APPEND STACKTRACE_SRC
- "stacktrace.cc"
- ${DEBUGGING_INTERNAL_SRC}
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
-)
-
-list(APPEND SYMBOLIZE_SRC
- "symbolize.cc"
- "symbolize_elf.inc"
- "symbolize_unimplemented.inc"
- "symbolize_win32.inc"
- "internal/demangle.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
- ${DEBUGGING_INTERNAL_SRC}
-)
-
-list(APPEND FAILURE_SIGNAL_HANDLER_SRC
- "failure_signal_handler.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
-)
-
-list(APPEND EXAMINE_STACK_SRC
- "internal/examine_stack.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
-)
-
-absl_library(
- TARGET
- absl_stacktrace
- SOURCES
- ${STACKTRACE_SRC}
- EXPORT_NAME
+absl_cc_library(
+ NAME
stacktrace
+ HDRS
+ "stacktrace.h"
+ SRCS
+ "stacktrace.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::debugging_internal
+ absl::base
+ absl::core_headers
+ PUBLIC
)
-absl_library(
- TARGET
- absl_symbolize
- SOURCES
- ${SYMBOLIZE_SRC}
- PUBLIC_LIBRARIES
- absl::base
- absl_malloc_internal
- EXPORT_NAME
+absl_cc_library(
+ NAME
symbolize
-)
-
-absl_library(
- TARGET
- absl_failure_signal_handler
- SOURCES
- ${FAILURE_SIGNAL_HANDLER_SRC}
- PUBLIC_LIBRARIES
- absl_base absl::examine_stack absl::stacktrace absl_synchronization
- EXPORT_NAME
- failure_signal_handler
-)
-
-# Internal-only. Projects external to Abseil should not depend
-# directly on this library.
-absl_library(
- TARGET
- absl_examine_stack
- SOURCES
- ${EXAMINE_STACK_SRC}
- EXPORT_NAME
- examine_stack
-)
-
-list(APPEND LEAK_CHECK_SRC
- "leak_check.cc"
-)
-
-
-# leak_check library
-absl_library(
- TARGET
- absl_leak_check
- SOURCES
- ${LEAK_CHECK_SRC}
- PUBLIC_LIBRARIES
- absl_base
- EXPORT_NAME
- leak_check
-)
-
-
-# component target
-absl_header_library(
- TARGET
- absl_debugging
- PUBLIC_LIBRARIES
- absl_stacktrace absl_leak_check
- EXPORT_NAME
- debugging
-)
-
-#
-## TESTS
-#
-
-list(APPEND STACK_CONSUMPTION_SRC
- "internal/stack_consumption.cc"
- "internal/stack_consumption.h"
-)
-
-absl_library(
- TARGET
- absl_stack_consumption
- SOURCES
- ${STACK_CONSUMPTION_SRC}
-)
-
-absl_test(
- TARGET
- absl_stack_consumption_test
- SOURCES
- "internal/stack_consumption_test.cc"
- PUBLIC_LIBRARIES
- absl_stack_consumption
+ HDRS
+ "symbolize.h"
+ "internal/symbolize.h"
+ SRCS
+ "symbolize.cc"
+ "symbolize_elf.inc"
+ "symbolize_unimplemented.inc"
+ "symbolize_win32.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::debugging_internal
+ absl::demangle_internal
absl::base
+ absl::core_headers
+ absl::malloc_internal
+ PUBLIC
)
-list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
-
-absl_test(
- TARGET
- demangle_test
- SOURCES
- ${DEMANGLE_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_symbolize absl_stack_consumption
-)
-
-list(APPEND SYMBOLIZE_TEST_SRC "symbolize_test.cc")
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
symbolize_test
- SOURCES
- ${SYMBOLIZE_TEST_SRC}
- PUBLIC_LIBRARIES
- absl::base absl::memory absl_symbolize absl_stack_consumption
+ SRCS
+ "symbolize_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::stack_consumption
+ absl::symbolize
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock
)
-list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
+absl_cc_library(
+ NAME
+ examine_stack
+ HDRS
+ "internal/examine_stack.h"
+ SRCS
+ "internal/examine_stack.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::stacktrace
+ absl::symbolize
+ absl::base
+ absl::core_headers
+)
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ failure_signal_handler
+ HDRS
+ "failure_signal_handler.h"
+ SRCS
+ "failure_signal_handler.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::examine_stack
+ absl::stacktrace
+ absl::base
+ absl::config
+ absl::core_headers
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
failure_signal_handler_test
- SOURCES
- ${FAILURE_SIGNAL_HANDLER_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_examine_stack
- absl_failure_signal_handler
- absl_stacktrace
- absl_symbolize
+ SRCS
+ "failure_signal_handler_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::failure_signal_handler
+ absl::stacktrace
+ absl::symbolize
absl::base
absl::strings
+ Threads::Threads
+ gmock
)
-# test leak_check_test
-list(APPEND LEAK_CHECK_TEST_SRC "leak_check_test.cc")
+absl_cc_library(
+ NAME
+ debugging_internal
+ HDRS
+ "internal/address_is_readable.h"
+ "internal/elf_mem_image.h"
+ "internal/stacktrace_aarch64-inl.inc"
+ "internal/stacktrace_arm-inl.inc"
+ "internal/stacktrace_config.h"
+ "internal/stacktrace_generic-inl.inc"
+ "internal/stacktrace_powerpc-inl.inc"
+ "internal/stacktrace_unimplemented-inl.inc"
+ "internal/stacktrace_win32-inl.inc"
+ "internal/stacktrace_x86-inl.inc"
+ "internal/vdso_support.h"
+ SRCS
+ "internal/address_is_readable.cc"
+ "internal/elf_mem_image.cc"
+ "internal/vdso_support.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::dynamic_annotations
+)
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ demangle_internal
+ HDRS
+ "internal/demangle.h"
+ SRCS
+ "internal/demangle.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ demangle_test
+ SRCS
+ "internal/demangle_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::demangle_internal
+ absl::stack_consumption
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ leak_check
+ HDRS
+ "leak_check.h"
+ SRCS
+ "leak_check.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ leak_check_disable
+ SRCS
+ "leak_check_disable.cc"
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ leak_check_api_enabled_for_testing
+ HDRS
+ "leak_check.h"
+ SRCS
+ "leak_check.cc"
+ COPTS
+ $<$<BOOL:${ABSL_HAVE_LSAN}>:-DLEAK_SANITIZER>
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ leak_check_api_disabled_for_testing
+ HDRS
+ "leak_check.h"
+ SRCS
+ "leak_check.cc"
+ COPTS
+ "-ULEAK_SANITIZER"
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
leak_check_test
- SOURCES
- ${LEAK_CHECK_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_leak_check
+ SRCS
+ "leak_check_test.cc"
+ COPTS
+ "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
+ LINKOPTS
+ "${ABSL_LSAN_LINKOPTS}"
+ DEPS
+ absl::leak_check_api_enabled_for_testing
+ absl::base
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ leak_check_no_lsan_test
+ SRCS
+ "leak_check_test.cc"
+ COPTS
+ "-UABSL_EXPECT_LEAK_SANITIZER"
+ DEPS
+ absl::leak_check_api_disabled_for_testing
+ absl::base
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ disabled_leak_check_test
+ SRCS
+ "leak_check_fail_test.cc"
+ LINKOPTS
+ "${ABSL_LSAN_LINKOPTS}"
+ DEPS
+ absl::leak_check_api_enabled_for_testing
+ absl::leak_check_disable
+ absl::base
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ stack_consumption
+ HDRS
+ "internal/stack_consumption.h"
+ SRCS
+ "internal/stack_consumption.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ stack_consumption_test
+ SRCS
+ "internal/stack_consumption_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::stack_consumption
+ absl::base
+ absl::core_headers
+ gmock_main
+)
+
+# component target
+absl_cc_library(
+ NAME
+ debugging
+ DEPS
+ absl::stacktrace
+ absl::leak_check
+ PUBLIC
)
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index d4b957b..c6a4d96 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -119,7 +119,11 @@
#ifndef _WIN32
static bool SetupAlternateStackOnce() {
+#if defined(__wasm__) || defined (__asjms__)
const size_t page_mask = getpagesize() - 1;
+#else
+ const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
+#endif
size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
defined(THREAD_SANITIZER)
diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h
index c57954e..1beb78b 100644
--- a/absl/debugging/failure_signal_handler.h
+++ b/absl/debugging/failure_signal_handler.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc
index ba52091..bb2cc48 100644
--- a/absl/debugging/failure_signal_handler_test.cc
+++ b/absl/debugging/failure_signal_handler_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -133,16 +133,17 @@
};
std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
- std::string result = absl::debugging_internal::FailureSignalToString(info.param);
+ std::string result =
+ absl::debugging_internal::FailureSignalToString(info.param);
if (result.empty()) {
result = absl::StrCat(info.param);
}
return result;
}
-INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
- ::testing::ValuesIn(kFailureSignals),
- SignalParamToString);
+INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
+ ::testing::ValuesIn(kFailureSignals),
+ SignalParamToString);
#endif // GTEST_HAS_DEATH_TEST
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc
index 7455aa0..99c4c64 100644
--- a/absl/debugging/internal/address_is_readable.cc
+++ b/absl/debugging/internal/address_is_readable.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h
index 9d48030..ca8003e 100644
--- a/absl/debugging/internal/address_is_readable.h
+++ b/absl/debugging/internal/address_is_readable.h
@@ -4,14 +4,13 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 4835445..52a553f 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -749,8 +749,8 @@
// <local-source-name> ::= L <source-name> [<discriminator>]
//
// References:
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
-// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+// https://gcc.gnu.org/viewcvs?view=rev&revision=124467
static bool ParseLocalSourceName(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
@@ -1168,6 +1168,12 @@
}
state->parse_state = copy;
+ // nullptr_t, i.e. decltype(nullptr).
+ if (ParseTwoCharToken(state, "Dn")) {
+ return true;
+ }
+ state->parse_state = copy;
+
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
@@ -1636,6 +1642,15 @@
}
state->parse_state = copy;
+ // Pointer-to-member access expressions. This parses the same as a binary
+ // operator, but it's implemented separately because "ds" shouldn't be
+ // accepted in other contexts that parse an operator name.
+ if (ParseTwoCharToken(state, "ds") && ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ state->parse_state = copy;
+
// Parameter pack expansion
if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) {
return true;
diff --git a/absl/debugging/internal/demangle.h b/absl/debugging/internal/demangle.h
index 2e75564..81bb0df 100644
--- a/absl/debugging/internal/demangle.h
+++ b/absl/debugging/internal/demangle.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index b9d9008..883b92d 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -176,6 +176,7 @@
TEST(DemangleRegression, NegativeLength) {
TestOnInput("_ZZn4");
}
+
TEST(DemangleRegression, DeeplyNestedArrayType) {
const int depth = 100000;
std::string data = "_ZStI";
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc
index 3f747e7..e7408bc 100644
--- a/absl/debugging/internal/elf_mem_image.cc
+++ b/absl/debugging/internal/elf_mem_image.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 3b57726..99b3758 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index faf8883..1ebc788 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h
index a16c03b..56c9763 100644
--- a/absl/debugging/internal/examine_stack.h
+++ b/absl/debugging/internal/examine_stack.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
index 2b3b972..4b05f49 100644
--- a/absl/debugging/internal/stack_consumption.cc
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h
index 4c5fa0f..b860a3c 100644
--- a/absl/debugging/internal/stack_consumption.h
+++ b/absl/debugging/internal/stack_consumption.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc
index 5ce3846..68bfa12 100644
--- a/absl/debugging/internal/stack_consumption_test.cc
+++ b/absl/debugging/internal/stack_consumption_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index dd713da..d4e8480 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -41,8 +41,9 @@
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_aarch64-inl.inc"
# elif defined(__arm__)
+// Note: When using glibc this may require -funwind-tables to function properly.
#define ABSL_STACKTRACE_INL_HEADER \
- "absl/debugging/internal/stacktrace_arm-inl.inc"
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
# else
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
index 2c9ca41..2e876fe 100644
--- a/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -12,13 +12,48 @@
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
#include <execinfo.h>
+#include <atomic>
#include <cstring>
#include "absl/debugging/stacktrace.h"
+// Sometimes, we can try to get a stack trace from within a stack
+// trace, because we don't block signals inside this code (which would be too
+// expensive: the two extra system calls per stack trace do matter here).
+// That can cause a self-deadlock.
+// Protect against such reentrant call by failing to get a stack trace.
+//
+// We use __thread here because the code here is extremely low level -- it is
+// called while collecting stack traces from within malloc and mmap, and thus
+// can not call anything which might call malloc or mmap itself.
+static __thread int recursive = 0;
+
+// The stack trace function might be invoked very early in the program's
+// execution (e.g. from the very first malloc if using tcmalloc). Also, the
+// glibc implementation itself will trigger malloc the first time it is called.
+// As such, we suppress usage of backtrace during this early stage of execution.
+static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy.
+// Waiting until static initializers run seems to be late enough.
+// This file is included into stacktrace.cc so this will only run once.
+static int stacktraces_enabler = []() {
+ void* unused_stack[1];
+ // Force the first backtrace to happen early to get the one-time shared lib
+ // loading (allocation) out of the way. After the first call it is much safer
+ // to use backtrace from a signal handler if we crash somewhere later.
+ backtrace(unused_stack, 1);
+ disable_stacktraces.store(false, std::memory_order_relaxed);
+ return 0;
+}();
+
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
const void *ucp, int *min_dropped_frames) {
+ if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
+ return 0;
+ }
+ ++recursive;
+
+ static_cast<void>(ucp); // Unused.
static const int kStackLength = 64;
void * stack[kStackLength];
int size;
@@ -45,6 +80,8 @@
}
}
+ --recursive;
+
return result_count;
}
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
index 860ac2b..9e0f2aa 100644
--- a/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,8 +14,8 @@
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
// for x86. For apple machines, at least, it seems to be; see
-// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
-// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// https://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+// https://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
index a8f8a56..b46491f 100644
--- a/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,7 +32,7 @@
// server.
//
// This code is inspired by a patch from David Vitek:
-// http://code.google.com/p/google-perftools/issues/detail?id=83
+// https://code.google.com/p/google-perftools/issues/detail?id=83
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
index ac85b92..25aa8bd 100644
--- a/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -33,6 +33,7 @@
#include "absl/debugging/internal/address_is_readable.h"
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
#include "absl/debugging/stacktrace.h"
+
#include "absl/base/internal/raw_logging.h"
#if defined(__linux__) && defined(__i386__)
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 8d926fe..3e53789 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,7 +20,6 @@
#include <cstddef>
#include <cstdint>
-#include "absl/base/port.h" // Needed for string vs std::string
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
@@ -42,9 +41,9 @@
// Returns true on success; otherwise returns false in case of errors.
//
// This is not async-signal-safe.
-bool ForEachSection(
- int fd, const std::function<bool(const std::string& name, const ElfW(Shdr) &)>&
- callback);
+bool ForEachSection(int fd,
+ const std::function<bool(const std::string& name,
+ const ElfW(Shdr) &)>& callback);
// Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false.
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
index e8129e8..23c3084 100644
--- a/absl/debugging/internal/vdso_support.cc
+++ b/absl/debugging/internal/vdso_support.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/internal/vdso_support.h b/absl/debugging/internal/vdso_support.h
index 8002c74..9895b48 100644
--- a/absl/debugging/internal/vdso_support.h
+++ b/absl/debugging/internal/vdso_support.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
index e01e5f8..ffe3d1b 100644
--- a/absl/debugging/leak_check.cc
+++ b/absl/debugging/leak_check.cc
@@ -4,13 +4,14 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+
// Wrappers around lsan_interface functions.
// When lsan is not linked in, these functions are not available,
// therefore Abseil code which depends on these functions is conditioned on the
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
index c930684..4d489c5 100644
--- a/absl/debugging/leak_check.h
+++ b/absl/debugging/leak_check.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc
index df22c1c..924d6e3 100644
--- a/absl/debugging/leak_check_disable.cc
+++ b/absl/debugging/leak_check_disable.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc
index bf541fe..2887cea 100644
--- a/absl/debugging/leak_check_fail_test.cc
+++ b/absl/debugging/leak_check_fail_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
index febd1ee..93a7edd 100644
--- a/absl/debugging/leak_check_test.cc
+++ b/absl/debugging/leak_check_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
index 463fad2..9de8782 100644
--- a/absl/debugging/stacktrace.cc
+++ b/absl/debugging/stacktrace.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -46,6 +46,7 @@
#include ABSL_STACKTRACE_INL_HEADER
#else
# error Cannot calculate stack trace: will need to write for your environment
+
# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
# include "absl/debugging/internal/stacktrace_arm-inl.inc"
# include "absl/debugging/internal/stacktrace_generic-inl.inc"
@@ -80,29 +81,29 @@
} // anonymous namespace
-ABSL_ATTRIBUTE_NOINLINE
-int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) {
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
+ void** result, int* sizes, int max_depth, int skip_count) {
return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
nullptr);
}
-ABSL_ATTRIBUTE_NOINLINE
-int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
- int skip_count, const void* uc,
- int* min_dropped_frames) {
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames) {
return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
min_dropped_frames);
}
-ABSL_ATTRIBUTE_NOINLINE
-int GetStackTrace(void** result, int max_depth, int skip_count) {
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
+ void** result, int max_depth, int skip_count) {
return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
nullptr);
}
-ABSL_ATTRIBUTE_NOINLINE
-int GetStackTraceWithContext(void** result, int max_depth, int skip_count,
- const void* uc, int* min_dropped_frames) {
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+GetStackTraceWithContext(void** result, int max_depth, int skip_count,
+ const void* uc, int* min_dropped_frames) {
return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
min_dropped_frames);
}
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
index 8b831e2..3fc1c03 100644
--- a/absl/debugging/stacktrace.h
+++ b/absl/debugging/stacktrace.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index a35e24c..24e3a7f 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/symbolize.h b/absl/debugging/symbolize.h
index 24e6e64..a73dbd9 100644
--- a/absl/debugging/symbolize.h
+++ b/absl/debugging/symbolize.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index b16a42a..34def5c 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -333,7 +333,11 @@
} // namespace
static int SymbolizerSize() {
+#if defined(__wasm__) || defined(__asmjs__)
int pagesize = getpagesize();
+#else
+ int pagesize = sysconf(_SC_PAGESIZE);
+#endif
return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize;
}
@@ -921,6 +925,14 @@
return p;
}
+// Normally we are only interested in "r?x" maps.
+// On the PowerPC, function pointers point to descriptors in the .opd
+// section. The descriptors themselves are not executable code, so
+// we need to relax the check below to "r??".
+static bool ShouldUseMapping(const char *const flags) {
+ return flags[0] == 'r' && (kPlatformUsesOPDSections || flags[2] == 'x');
+}
+
// Read /proc/self/maps and run "callback" for each mmapped file found. If
// "callback" returns false, stop scanning and return true. Else continue
// scanning /proc/self/maps. Return true if no parse error is found.
@@ -990,12 +1002,8 @@
return false;
}
- // Check flags. Normally we are only interested in "r-x" maps. On
- // the PowerPC, function pointers point to descriptors in the .opd
- // section. The descriptors themselves are not executable code. So
- // we need to relax the check below to "r**".
- if (memcmp(flags_start, "r-x", 3) != 0 && // Not a "r-x" map.
- !(kPlatformUsesOPDSections && flags_start[0] == 'r')) {
+ // Check flags.
+ if (!ShouldUseMapping(flags_start)) {
continue; // We skip this map.
}
++cursor; // Skip ' '.
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index 8029fbe..fc3ed93 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -392,16 +392,20 @@
extern "C" {
inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+ __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+ __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
#endif
return pc;
}
void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+ __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+ __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
#endif
return pc;
}
diff --git a/absl/debugging/symbolize_unimplemented.inc b/absl/debugging/symbolize_unimplemented.inc
index 2a3f4ac..7c580fe 100644
--- a/absl/debugging/symbolize_unimplemented.inc
+++ b/absl/debugging/symbolize_unimplemented.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,6 +26,9 @@
bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) {
return false;
}
+bool GetFileMappingHint(const void **, const void **, uint64_t *, const char **) {
+ return false;
+}
} // namespace debugging_internal
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index e3fff74..17ea618 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index 50aa550..69860d9 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
@@ -93,7 +93,6 @@
srcs = ["internal/city.cc"],
hdrs = [
"internal/city.h",
- "internal/city_crc.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
diff --git a/absl/hash/BUILD.gn b/absl/hash/BUILD.gn
index 40b6b3a..cbe3abf 100644
--- a/absl/hash/BUILD.gn
+++ b/absl/hash/BUILD.gn
@@ -91,7 +91,6 @@
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"internal/city.h",
- "internal/city_crc.h",
]
sources = [
"internal/city.cc",
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index 35081e3..4cafc13 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,67 +14,98 @@
# limitations under the License.
#
-list(APPEND HASH_PUBLIC_HEADERS
- "hash.h"
-)
-
-list(APPEND HASH_INTERNAL_HEADERS
- "internal/city.h"
- "internal/city_crc.h"
- "internal/hash.h"
-)
-
-# absl_hash library
-list(APPEND HASH_SRC
- "internal/city.cc"
- "internal/hash.cc"
- ${HASH_PUBLIC_HEADERS}
- ${HASH_INTERNAL_HEADERS}
-)
-
-set(HASH_PUBLIC_LIBRARIES absl::hash absl::container absl::strings absl::str_format absl::utility)
-
-absl_library(
- TARGET
- absl_hash
- SOURCES
- ${HASH_SRC}
- PUBLIC_LIBRARIES
- ${HASH_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
hash
+ HDRS
+ "hash.h"
+ SRCS
+ "internal/hash.cc"
+ "internal/hash.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::endian
+ absl::fixed_array
+ absl::meta
+ absl::int128
+ absl::strings
+ absl::optional
+ absl::variant
+ absl::utility
+ absl::city
+ PUBLIC
)
-#
-## TESTS
-#
+absl_cc_library(
+ NAME
+ hash_testing
+ HDRS
+ "hash_testing.h"
+ DEPS
+ absl::spy_hash_state
+ absl::meta
+ absl::strings
+ absl::variant
+ gmock
+ TESTONLY
+)
-# testing support
-set(HASH_TEST_HEADERS hash_testing.h internal/spy_hash_state.h)
-set(HASH_TEST_PUBLIC_LIBRARIES absl::hash absl::container absl::numeric absl::strings absl::str_format)
-
-# hash_test
-set(HASH_TEST_SRC "hash_test.cc" ${HASH_TEST_HEADERS})
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
hash_test
- SOURCES
- ${HASH_TEST_SRC}
- PUBLIC_LIBRARIES
- ${HASH_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "hash_test.cc"
+ DEPS
+ absl::hash
+ absl::hash_testing
+ absl::core_headers
+ absl::flat_hash_set
+ absl::spy_hash_state
+ absl::meta
+ absl::int128
+ gmock_main
)
-# hash_test
-set(CITY_TEST_SRC "internal/city_test.cc")
+absl_cc_library(
+ NAME
+ spy_hash_state
+ HDRS
+ "internal/spy_hash_state.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::hash
+ absl::strings
+ absl::str_format
+ TESTONLY
+)
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ city
+ HDRS
+ "internal/city.h"
+ SRCS
+ "internal/city.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ absl::endian
+)
+
+absl_cc_test(
+ NAME
city_test
- SOURCES
- ${CITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${HASH_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/city_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::city
+ gmock_main
)
-
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index c7ba4c2..c0ede35 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,8 +25,8 @@
// * `AbslHashValue`, an extension point that allows you to extend types to
// support Abseil hashing without requiring you to define a hashing
// algorithm.
-// * `HashState`, a type-erased class which implement the manipulation of the
-// hash state (H) itself. containing member functions `combine()` and
+// * `HashState`, a type-erased class which implements the manipulation of the
+// hash state (H) itself, contains member functions `combine()` and
// `combine_contiguous()`, which you can use to contribute to an existing
// hash state when hashing your types.
//
@@ -69,7 +69,7 @@
// `absl::Hash`
// -----------------------------------------------------------------------------
//
-// `absl::Hash<T>` is a convenient general-purpose hash functor for a type `T`
+// `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T`
// satisfying any of the following conditions (in order):
//
// * T is an arithmetic or pointer type
@@ -98,7 +98,7 @@
// * absl::string_view
// * absl::InlinedVector
// * absl::FixedArray
-// * absl::unit128
+// * absl::uint128
// * absl::Time, absl::Duration, and absl::TimeZone
//
// Note: the list above is not meant to be exhaustive. Additional type support
@@ -142,7 +142,7 @@
//
// The "hash state" concept contains two member functions for mixing hash state:
//
-// * `H::combine()`
+// * `H::combine(state, values...)`
//
// Combines an arbitrary number of values into a hash state, returning the
// updated state. Note that the existing hash state is move-only and must be
@@ -160,7 +160,7 @@
// state = H::combine(std::move(state), value2);
// state = H::combine(std::move(state), value3);
//
-// * `H::combine_contiguous()`
+// * `H::combine_contiguous(state, data, size)`
//
// Combines a contiguous array of `size` elements into a hash state,
// returning the updated state. Note that the existing hash state is
@@ -243,7 +243,7 @@
// absl::HashState::combine(std::move(state), v1_, v2_);
// }
// int v1_;
-// string v2_;
+// std::string v2_;
// };
class HashState : public hash_internal::HashStateBase<HashState> {
public:
@@ -309,4 +309,5 @@
};
} // namespace absl
+
#endif // ABSL_HASH_HASH_H_
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 7b6fb2e..af95938 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,6 +15,7 @@
#include "absl/hash/hash.h"
#include <array>
+#include <bitset>
#include <cstring>
#include <deque>
#include <forward_list>
@@ -50,7 +51,7 @@
template <typename T>
class HashValueIntTest : public testing::Test {
};
-TYPED_TEST_CASE_P(HashValueIntTest);
+TYPED_TEST_SUITE_P(HashValueIntTest);
template <typename T>
SpyHashState SpyHash(const T& value) {
@@ -84,6 +85,345 @@
uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
+enum LegacyEnum { kValue1, kValue2, kValue3 };
+
+enum class EnumClass { kValue4, kValue5, kValue6 };
+
+TEST(HashValueTest, EnumAndBool) {
+ EXPECT_TRUE((is_hashable<LegacyEnum>::value));
+ EXPECT_TRUE((is_hashable<EnumClass>::value));
+ EXPECT_TRUE((is_hashable<bool>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(true, false)));
+}
+
+TEST(HashValueTest, FloatingPoint) {
+ EXPECT_TRUE((is_hashable<float>::value));
+ EXPECT_TRUE((is_hashable<double>::value));
+ EXPECT_TRUE((is_hashable<long double>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(),
+ -std::numeric_limits<float>::infinity())));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(),
+ -std::numeric_limits<double>::infinity())));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ // Add some values with small exponent to test that NORMAL values also
+ // append their category.
+ .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L,
+ 17 * static_cast<long double>(std::numeric_limits<double>::max()),
+ std::numeric_limits<long double>::infinity(),
+ -std::numeric_limits<long double>::infinity())));
+}
+
+TEST(HashValueTest, Pointer) {
+ EXPECT_TRUE((is_hashable<int*>::value));
+
+ int i;
+ int* ptr = &i;
+ int* n = nullptr;
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(&i, ptr, nullptr, ptr + 1, n)));
+}
+
+TEST(HashValueTest, PointerAlignment) {
+ // We want to make sure that pointer alignment will not cause bits to be
+ // stuck.
+
+ constexpr size_t kTotalSize = 1 << 20;
+ std::unique_ptr<char[]> data(new char[kTotalSize]);
+ constexpr size_t kLog2NumValues = 5;
+ constexpr size_t kNumValues = 1 << kLog2NumValues;
+
+ for (size_t align = 1; align < kTotalSize / kNumValues;
+ align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) {
+ SCOPED_TRACE(align);
+ ASSERT_LE(align * kNumValues, kTotalSize);
+
+ size_t bits_or = 0;
+ size_t bits_and = ~size_t{};
+
+ for (size_t i = 0; i < kNumValues; ++i) {
+ size_t hash = absl::Hash<void*>()(data.get() + i * align);
+ bits_or |= hash;
+ bits_and &= hash;
+ }
+
+ // Limit the scope to the bits we would be using for Swisstable.
+ constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
+ size_t stuck_bits = (~bits_or | bits_and) & kMask;
+ EXPECT_EQ(stuck_bits, 0) << "0x" << std::hex << stuck_bits;
+ }
+}
+
+TEST(HashValueTest, PairAndTuple) {
+ EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
+ EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
+ EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value));
+ EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
+ std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42),
+ std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0),
+ std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9),
+ std::make_tuple(0, 0, -42))));
+
+ // Test that tuples of lvalue references work (so we need a few lvalues):
+ int a = 0, b = 1, c = 17, d = 23;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d))));
+
+ // Test that tuples of rvalue references work:
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
+ std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
+ std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
+ std::forward_as_tuple(0, 0, -42))));
+}
+
+TEST(HashValueTest, CombineContiguousWorks) {
+ std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
+ std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)};
+
+ auto vh1 = SpyHash(v1);
+ auto vh2 = SpyHash(v2);
+ EXPECT_NE(vh1, vh2);
+}
+
+struct DummyDeleter {
+ template <typename T>
+ void operator() (T* ptr) {}
+};
+
+struct SmartPointerEq {
+ template <typename T, typename U>
+ bool operator()(const T& t, const U& u) const {
+ return GetPtr(t) == GetPtr(u);
+ }
+
+ template <typename T>
+ static auto GetPtr(const T& t) -> decltype(&*t) {
+ return t ? &*t : nullptr;
+ }
+
+ static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; }
+};
+
+TEST(HashValueTest, SmartPointers) {
+ EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value));
+ EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value));
+ EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value));
+
+ int i, j;
+ std::unique_ptr<int, DummyDeleter> unique1(&i);
+ std::unique_ptr<int, DummyDeleter> unique2(&i);
+ std::unique_ptr<int, DummyDeleter> unique_other(&j);
+ std::unique_ptr<int, DummyDeleter> unique_null;
+
+ std::shared_ptr<int> shared1(&i, DummyDeleter());
+ std::shared_ptr<int> shared2(&i, DummyDeleter());
+ std::shared_ptr<int> shared_other(&j, DummyDeleter());
+ std::shared_ptr<int> shared_null;
+
+ // Sanity check of the Eq function.
+ ASSERT_TRUE(SmartPointerEq{}(unique1, shared1));
+ ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other));
+ ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr));
+ ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::forward_as_tuple(&i, nullptr, //
+ unique1, unique2, unique_null, //
+ absl::make_unique<int>(), //
+ shared1, shared2, shared_null, //
+ std::make_shared<int>()),
+ SmartPointerEq{}));
+}
+
+TEST(HashValueTest, FunctionPointer) {
+ using Func = int (*)();
+ EXPECT_TRUE(is_hashable<Func>::value);
+
+ Func p1 = [] { return 2; }, p2 = [] { return 1; };
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(p1, p2, nullptr)));
+}
+
+struct WrapInTuple {
+ template <typename T>
+ std::tuple<int, T, size_t> operator()(const T& t) const {
+ return std::make_tuple(7, t, 0xdeadbeef);
+ }
+};
+
+TEST(HashValueTest, Strings) {
+ EXPECT_TRUE((is_hashable<std::string>::value));
+
+ const std::string small = "foo";
+ const std::string dup = "foofoo";
+ const std::string large = "large";
+ const std::string huge = std::string(5000, 'a');
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::string(), absl::string_view(),
+ std::string(""), absl::string_view(""),
+ std::string(small), absl::string_view(small),
+ std::string(dup), absl::string_view(dup),
+ std::string(large), absl::string_view(large),
+ std::string(huge), absl::string_view(huge))));
+
+ // Also check that nested types maintain the same hash.
+ const WrapInTuple t{};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ //
+ t(std::string()), t(absl::string_view()),
+ t(std::string("")), t(absl::string_view("")),
+ t(std::string(small)), t(absl::string_view(small)),
+ t(std::string(dup)), t(absl::string_view(dup)),
+ t(std::string(large)), t(absl::string_view(large)),
+ t(std::string(huge)), t(absl::string_view(huge)))));
+
+ // Make sure that hashing a `const char*` does not use its std::string-value.
+ EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
+ SpyHash(absl::string_view("ABC")));
+}
+
+TEST(HashValueTest, StdArray) {
+ EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
+}
+
+TEST(HashValueTest, StdBitset) {
+ EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"),
+ std::bitset<2>("11")}));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()}));
+
+ constexpr int kNumBits = 256;
+ std::array<std::string, 6> bit_strings;
+ bit_strings.fill(std::string(kNumBits, '1'));
+ bit_strings[1][0] = '0';
+ bit_strings[2][1] = '0';
+ bit_strings[3][kNumBits / 3] = '0';
+ bit_strings[4][kNumBits - 2] = '0';
+ bit_strings[5][kNumBits - 1] = '0';
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<kNumBits>(bit_strings[0].c_str()),
+ std::bitset<kNumBits>(bit_strings[1].c_str()),
+ std::bitset<kNumBits>(bit_strings[2].c_str()),
+ std::bitset<kNumBits>(bit_strings[3].c_str()),
+ std::bitset<kNumBits>(bit_strings[4].c_str()),
+ std::bitset<kNumBits>(bit_strings[5].c_str())}));
+} // namespace
+
+template <typename T>
+class HashValueSequenceTest : public testing::Test {
+};
+TYPED_TEST_SUITE_P(HashValueSequenceTest);
+
+TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
+ EXPECT_TRUE((is_hashable<TypeParam>::value));
+
+ using ValueType = typename TypeParam::value_type;
+ auto a = static_cast<ValueType>(0);
+ auto b = static_cast<ValueType>(23);
+ auto c = static_cast<ValueType>(42);
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(TypeParam(), TypeParam{}, TypeParam{a, b, c},
+ TypeParam{a, b}, TypeParam{b, c})));
+}
+
+REGISTER_TYPED_TEST_CASE_P(HashValueSequenceTest, BasicUsage);
+using IntSequenceTypes =
+ testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>,
+ std::vector<int>, std::vector<bool>, std::set<int>,
+ std::multiset<int>>;
+INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
+
+// Private type that only supports AbslHashValue to make sure our chosen hash
+// implentation is recursive within absl::Hash.
+// It uses std::abs() on the value to provide different bitwise representations
+// of the same logical value.
+struct Private {
+ int i;
+ template <typename H>
+ friend H AbslHashValue(H h, Private p) {
+ return H::combine(std::move(h), std::abs(p.i));
+ }
+
+ friend bool operator==(Private a, Private b) {
+ return std::abs(a.i) == std::abs(b.i);
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, Private p) {
+ return o << p.i;
+ }
+};
+
+TEST(HashValueTest, PrivateSanity) {
+ // Sanity check that Private is working as the tests below expect it to work.
+ EXPECT_TRUE(is_hashable<Private>::value);
+ EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
+ EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
+}
+
+TEST(HashValueTest, Optional) {
+ EXPECT_TRUE(is_hashable<absl::optional<Private>>::value);
+
+ using O = absl::optional<Private>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
+}
+
+TEST(HashValueTest, Variant) {
+ using V = absl::variant<Private, std::string>;
+ EXPECT_TRUE(is_hashable<V>::value);
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD"))));
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+ struct S {};
+ EXPECT_FALSE(is_hashable<absl::variant<S>>::value);
+#endif
+}
+
+TEST(HashValueTest, Maps) {
+ EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
+
+ using M = std::map<int, std::string>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ M{}, M{{0, "foo"}}, M{{1, "foo"}}, M{{0, "bar"}}, M{{1, "bar"}},
+ M{{0, "foo"}, {42, "bar"}}, M{{1, "foo"}, {42, "bar"}},
+ M{{1, "foo"}, {43, "bar"}}, M{{1, "foo"}, {43, "baz"}})));
+
+ using MM = std::multimap<int, std::string>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ MM{}, MM{{0, "foo"}}, MM{{1, "foo"}}, MM{{0, "bar"}}, MM{{1, "bar"}},
+ MM{{0, "foo"}, {0, "bar"}}, MM{{0, "bar"}, {0, "foo"}},
+ MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}},
+ MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
+}
+
template <typename T, typename = void>
struct IsHashCallble : std::false_type {};
@@ -108,7 +448,8 @@
EXPECT_TRUE(IsHashCallble<int>::value);
EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value);
}
-#if ABSL_HASH_INTERNAL_CAN_POISON_ && !defined(__APPLE__)
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
TEST(IsHashableTest, PoisonHash) {
struct X {};
EXPECT_FALSE((is_hashable<X>::value));
@@ -120,7 +461,7 @@
EXPECT_FALSE(IsHashCallble<X>::value);
EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value);
}
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
// Hashable types
//
@@ -159,8 +500,16 @@
Int(4));
}
};
+enum class InvokeTag {
+ kUniquelyRepresented,
+ kHashValue,
+#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ kLegacyHash,
+#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ kStdHash,
+ kNone
+};
-using InvokeTag = absl::hash_internal::InvokeHashTag;
template <InvokeTag T>
using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
@@ -245,13 +594,13 @@
}
void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
-#if ABSL_HASH_INTERNAL_CAN_POISON_
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
// is_hashable is false if we don't support any of the hooks.
using type = CustomHashType<>;
EXPECT_FALSE(is_hashable<type>());
EXPECT_FALSE(is_hashable<const type>());
EXPECT_FALSE(is_hashable<const type&>());
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
}
template <InvokeTag Tag, typename... T>
@@ -273,7 +622,7 @@
template <typename T>
class HashIntTest : public testing::Test {
};
-TYPED_TEST_CASE_P(HashIntTest);
+TYPED_TEST_SUITE_P(HashIntTest);
TYPED_TEST_P(HashIntTest, BasicUsage) {
EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0));
@@ -352,7 +701,8 @@
}
TEST(HashTest, StandardHashContainerUsage) {
- std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"}, { 42, "bar" }};
+ std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"},
+ {42, "bar"}};
EXPECT_NE(map.find(0), map.end());
EXPECT_EQ(map.find(1), map.end());
@@ -422,4 +772,24 @@
SpyHash(std::make_pair(size_t{7}, 17)));
}
+struct ValueWithBoolConversion {
+ operator bool() const { return false; }
+ int i;
+};
+
+} // namespace
+namespace std {
+template <>
+struct hash<ValueWithBoolConversion> {
+ size_t operator()(ValueWithBoolConversion v) { return v.i; }
+};
+} // namespace std
+
+namespace {
+
+TEST(HashTest, DoesNotUseImplicitConversionsToBool) {
+ EXPECT_NE(absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{0}),
+ absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{1}));
+}
+
} // namespace
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h
index 1e3cda6..c45bc15 100644
--- a/absl/hash/hash_testing.h
+++ b/absl/hash/hash_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -90,7 +90,7 @@
// template <typename H>
// friend H AbslHashValue(H state, Bad2 x) {
// // Uses a and b.
-// return H::combine(x.a, x.b);
+// return H::combine(std::move(state), x.a, x.b);
// }
// friend bool operator==(Bad2 x, Bad2 y) {
// // Only uses a.
@@ -107,7 +107,7 @@
// template <typename H>
// friend H AbslHashValue(H state, Bad3 x) {
// // Only uses a.
-// return H::combine(x.a);
+// return H::combine(std::move(state), x.a);
// }
// friend bool operator==(Bad3 x, Bad3 y) {
// // Uses a and b.
@@ -123,19 +123,21 @@
// int *p, size;
// template <typename H>
// friend H AbslHashValue(H state, Bad4 x) {
-// return H::combine_range(x.p, x.p + x.size);
+// return H::combine_contiguous(std::move(state), x.p, x.p + x.size);
// }
// friend bool operator==(Bad4 x, Bad4 y) {
-// return std::equal(x.p, x.p + x.size, y.p, y.p + y.size);
+// // Compare two ranges for equality. C++14 code can instead use std::equal.
+// return absl::equal(x.p, x.p + x.size, y.p, y.p + y.size);
// }
// };
//
// An easy solution to this is to combine the size after combining the range,
// like so:
-// template <typename H>
-// friend H AbslHashValue(H state, Bad4 x) {
-// return H::combine(H::combine_range(x.p, x.p + x.size), x.size);
-// }
+// template <typename H>
+// friend H AbslHashValue(H state, Bad4 x) {
+// return H::combine(
+// H::combine_contiguous(std::move(state), x.p, x.p + x.size), x.size);
+// }
//
template <int&... ExplicitBarrier, typename Container>
ABSL_MUST_USE_RESULT testing::AssertionResult
@@ -188,7 +190,9 @@
struct Info {
const V& value;
size_t index;
- std::string ToString() const { return absl::visit(PrintVisitor{index}, value); }
+ std::string ToString() const {
+ return absl::visit(PrintVisitor{index}, value);
+ }
SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
};
@@ -227,7 +231,8 @@
// Now we verify that AbslHashValue is also correctly implemented.
for (const auto& c : classes) {
- // All elements of the equivalence class must have the same hash expansion.
+ // All elements of the equivalence class must have the same hash
+ // expansion.
const SpyHashState expected = c[0].expand();
for (const Info& v : c) {
if (v.expand() != v.expand()) {
@@ -285,7 +290,7 @@
};
template <typename... T>
-struct MakeTypeSet : TypeSet<>{};
+struct MakeTypeSet : TypeSet<> {};
template <typename T, typename... Ts>
struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {};
@@ -346,8 +351,7 @@
ABSL_MUST_USE_RESULT testing::AssertionResult
VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
- hash_internal::ContainerAsVector<Container>::Do(values),
- equals);
+ hash_internal::ContainerAsVector<Container>::Do(values), equals);
}
template <int&..., typename T>
diff --git a/absl/hash/internal/city.cc b/absl/hash/internal/city.cc
index 8f72dd1..dc7650a 100644
--- a/absl/hash/internal/city.cc
+++ b/absl/hash/internal/city.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -340,251 +340,5 @@
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
-// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
-// of any length representable in signed long. Based on City and Murmur.
-static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
- uint64_t a = Uint128Low64(seed);
- uint64_t b = Uint128High64(seed);
- uint64_t c = 0;
- uint64_t d = 0;
- int64_t l = len - 16;
- if (l <= 0) { // len <= 16
- a = ShiftMix(a * k1) * k1;
- c = b * k1 + HashLen0to16(s, len);
- d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
- } else { // len > 16
- c = HashLen16(Fetch64(s + len - 8) + k1, a);
- d = HashLen16(b + len, c + Fetch64(s + len - 16));
- a += d;
- do {
- a ^= ShiftMix(Fetch64(s) * k1) * k1;
- a *= k1;
- b ^= a;
- c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
- c *= k1;
- d ^= c;
- s += 16;
- l -= 16;
- } while (l > 0);
- }
- a = HashLen16(a, c);
- b = HashLen16(d, b);
- return uint128(a ^ b, HashLen16(b, a));
-}
-
-uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
- if (len < 128) {
- return CityMurmur(s, len, seed);
- }
-
- // We expect len >= 128 to be the common case. Keep 56 bytes of state:
- // v, w, x, y, and z.
- std::pair<uint64_t, uint64_t> v, w;
- uint64_t x = Uint128Low64(seed);
- uint64_t y = Uint128High64(seed);
- uint64_t z = len * k1;
- v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
- v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
- w.first = Rotate(y + z, 35) * k1 + x;
- w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
-
- // This is the same inner loop as CityHash64(), manually unrolled.
- do {
- x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
- y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
- x ^= w.second;
- y += v.first + Fetch64(s + 40);
- z = Rotate(z + w.first, 33) * k1;
- v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
- w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
- std::swap(z, x);
- s += 64;
- x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
- y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
- x ^= w.second;
- y += v.first + Fetch64(s + 40);
- z = Rotate(z + w.first, 33) * k1;
- v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
- w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
- std::swap(z, x);
- s += 64;
- len -= 128;
- } while (ABSL_PREDICT_TRUE(len >= 128));
- x += Rotate(v.first + z, 49) * k0;
- y = y * k0 + Rotate(w.second, 37);
- z = z * k0 + Rotate(w.first, 27);
- w.first *= 9;
- v.first *= k0;
- // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
- for (size_t tail_done = 0; tail_done < len;) {
- tail_done += 32;
- y = Rotate(x + y, 42) * k0 + v.second;
- w.first += Fetch64(s + len - tail_done + 16);
- x = x * k0 + w.first;
- z += w.second + Fetch64(s + len - tail_done);
- w.second += v.first;
- v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
- v.first *= k0;
- }
- // At this point our 56 bytes of state should contain more than
- // enough information for a strong 128-bit hash. We use two
- // different 56-byte-to-8-byte hashes to get a 16-byte final result.
- x = HashLen16(x, v.first);
- y = HashLen16(y + z, w.first);
- return uint128(HashLen16(x + v.second, w.second) + y,
- HashLen16(x + w.second, y + v.second));
-}
-
-uint128 CityHash128(const char *s, size_t len) {
- return len >= 16
- ? CityHash128WithSeed(s + 16, len - 16,
- uint128(Fetch64(s), Fetch64(s + 8) + k0))
- : CityHash128WithSeed(s, len, uint128(k0, k1));
-}
} // namespace hash_internal
} // namespace absl
-
-#ifdef __SSE4_2__
-#include <nmmintrin.h>
-#include "absl/hash/internal/city_crc.h"
-
-namespace absl {
-namespace hash_internal {
-
-// Requires len >= 240.
-static void CityHashCrc256Long(const char *s, size_t len, uint32_t seed,
- uint64_t *result) {
- uint64_t a = Fetch64(s + 56) + k0;
- uint64_t b = Fetch64(s + 96) + k0;
- uint64_t c = result[0] = HashLen16(b, len);
- uint64_t d = result[1] = Fetch64(s + 120) * k0 + len;
- uint64_t e = Fetch64(s + 184) + seed;
- uint64_t f = 0;
- uint64_t g = 0;
- uint64_t h = c + d;
- uint64_t x = seed;
- uint64_t y = 0;
- uint64_t z = 0;
-
- // 240 bytes of input per iter.
- size_t iters = len / 240;
- len -= iters * 240;
- do {
-#undef CHUNK
-#define CHUNK(r) \
- PERMUTE3(x, z, y); \
- b += Fetch64(s); \
- c += Fetch64(s + 8); \
- d += Fetch64(s + 16); \
- e += Fetch64(s + 24); \
- f += Fetch64(s + 32); \
- a += b; \
- h += f; \
- b += c; \
- f += d; \
- g += e; \
- e += z; \
- g += x; \
- z = _mm_crc32_u64(z, b + g); \
- y = _mm_crc32_u64(y, e + h); \
- x = _mm_crc32_u64(x, f + a); \
- e = Rotate(e, r); \
- c += e; \
- s += 40
-
- CHUNK(0);
- PERMUTE3(a, h, c);
- CHUNK(33);
- PERMUTE3(a, h, f);
- CHUNK(0);
- PERMUTE3(b, h, f);
- CHUNK(42);
- PERMUTE3(b, h, d);
- CHUNK(0);
- PERMUTE3(b, h, e);
- CHUNK(33);
- PERMUTE3(a, h, e);
- } while (--iters > 0);
-
- while (len >= 40) {
- CHUNK(29);
- e ^= Rotate(a, 20);
- h += Rotate(b, 30);
- g ^= Rotate(c, 40);
- f += Rotate(d, 34);
- PERMUTE3(c, h, g);
- len -= 40;
- }
- if (len > 0) {
- s = s + len - 40;
- CHUNK(33);
- e ^= Rotate(a, 43);
- h += Rotate(b, 42);
- g ^= Rotate(c, 41);
- f += Rotate(d, 40);
- }
- result[0] ^= h;
- result[1] ^= g;
- g += h;
- a = HashLen16(a, g + z);
- x += y << 32;
- b += x;
- c = HashLen16(c, z) + h;
- d = HashLen16(d, e + result[0]);
- g += e;
- h += HashLen16(x, f);
- e = HashLen16(a, d) + g;
- z = HashLen16(b, c) + a;
- y = HashLen16(g, h) + c;
- result[0] = e + z + y + x;
- a = ShiftMix((a + y) * k0) * k0 + b;
- result[1] += a + result[0];
- a = ShiftMix(a * k0) * k0 + c;
- result[2] = a + result[1];
- a = ShiftMix((a + e) * k0) * k0;
- result[3] = a + result[2];
-}
-
-// Requires len < 240.
-static void CityHashCrc256Short(const char *s, size_t len, uint64_t *result) {
- char buf[240];
- memcpy(buf, s, len);
- memset(buf + len, 0, 240 - len);
- CityHashCrc256Long(buf, 240, ~static_cast<uint32_t>(len), result);
-}
-
-void CityHashCrc256(const char *s, size_t len, uint64_t *result) {
- if (ABSL_PREDICT_TRUE(len >= 240)) {
- CityHashCrc256Long(s, len, 0, result);
- } else {
- CityHashCrc256Short(s, len, result);
- }
-}
-
-uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
- if (len <= 900) {
- return CityHash128WithSeed(s, len, seed);
- } else {
- uint64_t result[4];
- CityHashCrc256(s, len, result);
- uint64_t u = Uint128High64(seed) + result[0];
- uint64_t v = Uint128Low64(seed) + result[1];
- return uint128(HashLen16(u, v + result[2]),
- HashLen16(Rotate(v, 32), u * k0 + result[3]));
- }
-}
-
-uint128 CityHashCrc128(const char *s, size_t len) {
- if (len <= 900) {
- return CityHash128(s, len);
- } else {
- uint64_t result[4];
- CityHashCrc256(s, len, result);
- return uint128(result[2], result[3]);
- }
-}
-
-} // namespace hash_internal
-} // namespace absl
-
-#endif
diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h
index 55b37b8..b43d340 100644
--- a/absl/hash/internal/city.h
+++ b/absl/hash/internal/city.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// http://code.google.com/p/cityhash/
+// https://code.google.com/p/cityhash/
//
// This file provides a few functions for hashing strings. All of them are
// high-quality functions in the sense that they pass standard tests such
@@ -23,15 +23,6 @@
// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
// tables and most other hashing (excluding cryptography).
//
-// For 64-bit x86 code, on long strings, the picture is more complicated.
-// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
-// CityHashCrc128 appears to be faster than all competitors of comparable
-// quality. CityHash128 is also good but not quite as fast. We believe our
-// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
-// other 64-bit CPUs, but for long strings we know that Spooky is slightly
-// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
-// Note that CityHashCrc128 is declared in citycrc.h.
-//
// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
// is of comparable quality. We believe our nearest competitor is Murmur3A.
// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
@@ -58,7 +49,6 @@
#include <stdlib.h> // for size_t.
#include <utility>
-
namespace absl {
namespace hash_internal {
@@ -79,13 +69,6 @@
uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
uint64_t seed1);
-// Hash function for a byte array.
-uint128 CityHash128(const char *s, size_t len);
-
-// Hash function for a byte array. For convenience, a 128-bit seed is also
-// hashed into the result.
-uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
-
// Hash function for a byte array. Most useful in 32-bit binaries.
uint32_t CityHash32(const char *s, size_t len);
diff --git a/absl/hash/internal/city_crc.h b/absl/hash/internal/city_crc.h
deleted file mode 100644
index 6be6557..0000000
--- a/absl/hash/internal/city_crc.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// This file declares the subset of the CityHash functions that require
-// _mm_crc32_u64(). See the CityHash README for details.
-//
-// Functions in the CityHash family are not suitable for cryptography.
-
-#ifndef ABSL_HASH_INTERNAL_CITY_CRC_H_
-#define ABSL_HASH_INTERNAL_CITY_CRC_H_
-
-#include "absl/hash/internal/city.h"
-
-namespace absl {
-namespace hash_internal {
-
-// Hash function for a byte array.
-uint128 CityHashCrc128(const char *s, size_t len);
-
-// Hash function for a byte array. For convenience, a 128-bit seed is also
-// hashed into the result.
-uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed);
-
-// Hash function for a byte array. Sets result[0] ... result[3].
-void CityHashCrc256(const char *s, size_t len, uint64_t *result);
-
-} // namespace hash_internal
-} // namespace absl
-
-#endif // ABSL_HASH_INTERNAL_CITY_CRC_H_
diff --git a/absl/hash/internal/city_test.cc b/absl/hash/internal/city_test.cc
index 678da53..71b4ecc 100644
--- a/absl/hash/internal/city_test.cc
+++ b/absl/hash/internal/city_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,9 +18,6 @@
#include <cstdio>
#include <iostream>
#include "gtest/gtest.h"
-#ifdef __SSE4_2__
-#include "absl/hash/internal/city_crc.h"
-#endif
namespace absl {
namespace hash_internal {
@@ -28,7 +25,6 @@
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
static const uint64_t kSeed0 = 1234567;
static const uint64_t kSeed1 = k0;
-static const uint128 kSeed128(kSeed0, kSeed1);
static const int kDataSize = 1 << 20;
static const int kTestSize = 300;
@@ -49,1754 +45,539 @@
}
#define C(x) 0x##x##ULL
-static const uint64_t testdata[kTestSize][16] = {
+static const uint64_t testdata[kTestSize][4] = {
{C(9ae16a3b2f90404f), C(75106db890237a4a), C(3feac5f636039766),
- C(3df09dfc64c09a2b), C(3cb540c392e51e29), C(6b56343feac0663),
- C(5b7bc50fd8e8ad92), C(3df09dfc64c09a2b), C(3cb540c392e51e29),
- C(6b56343feac0663), C(5b7bc50fd8e8ad92), C(95162f24e6a5f930),
- C(6808bdf4f1eb06e0), C(b3b1f3a67b624d82), C(c9a62f12bd4cd80b),
C(dc56d17a)},
{C(541150e87f415e96), C(1aef0d24b3148a1a), C(bacc300e1e82345a),
- C(c3cdc41e1df33513), C(2c138ff2596d42f6), C(f58e9082aed3055f),
- C(162e192b2957163d), C(c3cdc41e1df33513), C(2c138ff2596d42f6),
- C(f58e9082aed3055f), C(162e192b2957163d), C(fb99e85e0d16f90c),
- C(608462c15bdf27e8), C(e7d2c5c943572b62), C(1baaa9327642798c),
C(99929334)},
- {C(f3786a4b25827c1), C(34ee1a2bf767bd1c), C(2f15ca2ebfb631f2),
- C(3149ba1dac77270d), C(70e2e076e30703c), C(59bcc9659bc5296),
- C(9ecbc8132ae2f1d7), C(3149ba1dac77270d), C(70e2e076e30703c),
- C(59bcc9659bc5296), C(9ecbc8132ae2f1d7), C(a01d30789bad7cf2),
- C(ae03fe371981a0e0), C(127e3883b8788934), C(d0ac3d4c0a6fca32),
- C(4252edb7)},
+ {C(f3786a4b25827c1), C(34ee1a2bf767bd1c), C(2f15ca2ebfb631f2), C(4252edb7)},
{C(ef923a7a1af78eab), C(79163b1e1e9a9b18), C(df3b2aca6e1e4a30),
- C(2193fb7620cbf23b), C(8b6a8ff06cda8302), C(1a44469afd3e091f),
- C(8b0449376612506), C(2193fb7620cbf23b), C(8b6a8ff06cda8302),
- C(1a44469afd3e091f), C(8b0449376612506), C(e9d9d41c32ad91d1),
- C(b44ab09f58e3c608), C(19e9175f9fcf784), C(839b3c9581b4a480), C(ebc34f3c)},
+ C(ebc34f3c)},
{C(11df592596f41d88), C(843ec0bce9042f9c), C(cce2ea1e08b1eb30),
- C(4d09e42f09cc3495), C(666236631b9f253b), C(d28b3763cd02b6a3),
- C(43b249e57c4d0c1b), C(4d09e42f09cc3495), C(666236631b9f253b),
- C(d28b3763cd02b6a3), C(43b249e57c4d0c1b), C(3887101c8adea101),
- C(8a9355d4efc91df0), C(3e610944cc9fecfd), C(5bf9eb60b08ac0ce),
C(26f2b463)},
{C(831f448bdc5600b3), C(62a24be3120a6919), C(1b44098a41e010da),
- C(dc07df53b949c6b), C(d2b11b2081aeb002), C(d212b02c1b13f772),
- C(c0bed297b4be1912), C(dc07df53b949c6b), C(d2b11b2081aeb002),
- C(d212b02c1b13f772), C(c0bed297b4be1912), C(682d3d2ad304e4af),
- C(40e9112a655437a1), C(268b09f7ee09843f), C(6b9698d43859ca47),
C(b042c047)},
- {C(3eca803e70304894), C(d80de767e4a920a), C(a51cfbb292efd53d),
- C(d183dcda5f73edfa), C(3a93cbf40f30128c), C(1a92544d0b41dbda),
- C(aec2c4bee81975e1), C(d183dcda5f73edfa), C(3a93cbf40f30128c),
- C(1a92544d0b41dbda), C(aec2c4bee81975e1), C(5f91814d1126ba4b),
- C(f8ac57eee87fcf1f), C(c55c644a5d0023cd), C(adb761e827825ff2),
- C(e73bb0a8)},
+ {C(3eca803e70304894), C(d80de767e4a920a), C(a51cfbb292efd53d), C(e73bb0a8)},
{C(1b5a063fb4c7f9f1), C(318dbc24af66dee9), C(10ef7b32d5c719af),
- C(b140a02ef5c97712), C(b7d00ef065b51b33), C(635121d532897d98),
- C(532daf21b312a6d6), C(b140a02ef5c97712), C(b7d00ef065b51b33),
- C(635121d532897d98), C(532daf21b312a6d6), C(c0b09b75d943910),
- C(8c84dfb5ef2a8e96), C(e5c06034b0353433), C(3170faf1c33a45dd),
C(91dfdd75)},
{C(a0f10149a0e538d6), C(69d008c20f87419f), C(41b36376185b3e9e),
- C(26b6689960ccf81d), C(55f23b27bb9efd94), C(3a17f6166dd765db),
- C(c891a8a62931e782), C(26b6689960ccf81d), C(55f23b27bb9efd94),
- C(3a17f6166dd765db), C(c891a8a62931e782), C(23852dc37ddd2607),
- C(8b7f1b1ec897829e), C(d1d69452a54eed8a), C(56431f2bd766ec24),
C(c87f95de)},
{C(fb8d9c70660b910b), C(a45b0cc3476bff1b), C(b28d1996144f0207),
- C(98ec31113e5e35d2), C(5e4aeb853f1b9aa7), C(bcf5c8fe4465b7c8),
- C(b1ea3a8243996f15), C(98ec31113e5e35d2), C(5e4aeb853f1b9aa7),
- C(bcf5c8fe4465b7c8), C(b1ea3a8243996f15), C(cabbccedb6407571),
- C(d1e40a84c445ec3a), C(33302aa908cf4039), C(9f15f79211b5cdf8),
C(3f5538ef)},
{C(236827beae282a46), C(e43970221139c946), C(4f3ac6faa837a3aa),
- C(71fec0f972248915), C(2170ec2061f24574), C(9eb346b6caa36e82),
- C(2908f0fdbca48e73), C(71fec0f972248915), C(2170ec2061f24574),
- C(9eb346b6caa36e82), C(2908f0fdbca48e73), C(8101c99f07c64abb),
- C(b9f4b02b1b6a96a7), C(583a2b10cd222f88), C(199dae4cf9db24c), C(70eb1a1f)},
+ C(70eb1a1f)},
{C(c385e435136ecf7c), C(d9d17368ff6c4a08), C(1b31eed4e5251a67),
- C(df01a322c43a6200), C(298b65a1714b5a7e), C(933b83f0aedf23c),
- C(157bcb44d63f765a), C(df01a322c43a6200), C(298b65a1714b5a7e),
- C(933b83f0aedf23c), C(157bcb44d63f765a), C(d6e9fc7a272d8b51),
- C(3ee5073ef1a9b777), C(63149e31fac02c59), C(2f7979ff636ba1d8),
C(cfd63b83)},
{C(e3f6828b6017086d), C(21b4d1900554b3b0), C(bef38be1809e24f1),
- C(d93251758985ee6c), C(32a9e9f82ba2a932), C(3822aacaa95f3329),
- C(db349b2f90a490d8), C(d93251758985ee6c), C(32a9e9f82ba2a932),
- C(3822aacaa95f3329), C(db349b2f90a490d8), C(8d49194a894a19ca),
- C(79a78b06e42738e6), C(7e0f1eda3d390c66), C(1c291d7e641100a5),
C(894a52ef)},
{C(851fff285561dca0), C(4d1277d73cdf416f), C(28ccffa61010ebe2),
- C(77a4ccacd131d9ee), C(e1d08eeb2f0e29aa), C(70b9e3051383fa45),
- C(582d0120425caba), C(77a4ccacd131d9ee), C(e1d08eeb2f0e29aa),
- C(70b9e3051383fa45), C(582d0120425caba), C(a740eef1846e4564),
- C(572dddb74ac3ae00), C(fdb5ca9579163bbd), C(a649b9b799c615d2),
C(9cde6a54)},
{C(61152a63595a96d9), C(d1a3a91ef3a7ba45), C(443b6bb4a493ad0c),
- C(a154296d11362d06), C(d0f0bf1f1cb02fc1), C(ccb87e09309f90d1),
- C(b24a8e4881911101), C(a154296d11362d06), C(d0f0bf1f1cb02fc1),
- C(ccb87e09309f90d1), C(b24a8e4881911101), C(1a481b4528559f58),
- C(bf837a3150896995), C(4989ef6b941a3757), C(2e725ab72d0b2948),
C(6c4898d5)},
{C(44473e03be306c88), C(30097761f872472a), C(9fd1b669bfad82d7),
- C(3bab18b164396783), C(47e385ff9d4c06f), C(18062081bf558df),
- C(63416eb68f104a36), C(3bab18b164396783), C(47e385ff9d4c06f),
- C(18062081bf558df), C(63416eb68f104a36), C(4abda1560c47ac80),
- C(1ea0e63dc6587aee), C(33ec79d92ebc1de), C(94f9dccef771e048), C(13e1978e)},
- {C(3ead5f21d344056), C(fb6420393cfb05c3), C(407932394cbbd303),
- C(ac059617f5906673), C(94d50d3dcd3069a7), C(2b26c3b92dea0f0),
- C(99b7374cc78fc3fb), C(ac059617f5906673), C(94d50d3dcd3069a7),
- C(2b26c3b92dea0f0), C(99b7374cc78fc3fb), C(1a8e3c73cdd40ee8),
- C(cbb5fca06747f45b), C(ceec44238b291841), C(28bf35cce9c90a25), C(51b4ba8)},
+ C(13e1978e)},
+ {C(3ead5f21d344056), C(fb6420393cfb05c3), C(407932394cbbd303), C(51b4ba8)},
{C(6abbfde37ee03b5b), C(83febf188d2cc113), C(cda7b62d94d5b8ee),
- C(a4375590b8ae7c82), C(168fd42f9ecae4ff), C(23bbde43de2cb214),
- C(a8c333112a243c8c), C(a4375590b8ae7c82), C(168fd42f9ecae4ff),
- C(23bbde43de2cb214), C(a8c333112a243c8c), C(10ac012e8c518b49),
- C(64a44605d8b29458), C(a67e701d2a679075), C(3a3a20f43ec92303),
C(b6b06e40)},
- {C(943e7ed63b3c080), C(1ef207e9444ef7f8), C(ef4a9f9f8c6f9b4a),
- C(6b54fc38d6a84108), C(32f4212a47a4665), C(6b5a9a8f64ee1da6),
- C(9f74e86c6da69421), C(6b54fc38d6a84108), C(32f4212a47a4665),
- C(6b5a9a8f64ee1da6), C(9f74e86c6da69421), C(946dd0cb30c1a08e),
- C(fdf376956907eaaa), C(a59074c6eec03028), C(b1a3abcf283f34ac), C(240a2f2)},
+ {C(943e7ed63b3c080), C(1ef207e9444ef7f8), C(ef4a9f9f8c6f9b4a), C(240a2f2)},
{C(d72ce05171ef8a1a), C(c6bd6bd869203894), C(c760e6396455d23a),
- C(f86af0b40dcce7b), C(8d3c15d613394d3c), C(491e400491cd4ece),
- C(7c19d3530ea3547f), C(f86af0b40dcce7b), C(8d3c15d613394d3c),
- C(491e400491cd4ece), C(7c19d3530ea3547f), C(1362963a1dc32af9),
- C(fb9bc11762e1385c), C(9e164ef1f5376083), C(6c15819b5e828a7e),
C(5dcefc30)},
{C(4182832b52d63735), C(337097e123eea414), C(b5a72ca0456df910),
- C(7ebc034235bc122f), C(d9a7783d4edd8049), C(5f8b04a15ae42361),
- C(fc193363336453dd), C(7ebc034235bc122f), C(d9a7783d4edd8049),
- C(5f8b04a15ae42361), C(fc193363336453dd), C(9b6c50224ef8c4f8),
- C(ba225c7942d16c3f), C(6f6d55226a73c412), C(abca061fe072152a),
C(7a48b105)},
{C(d6cdae892584a2cb), C(58de0fa4eca17dcd), C(43df30b8f5f1cb00),
- C(9e4ea5a4941e097d), C(547e048d5a9daaba), C(eb6ecbb0b831d185),
- C(e0168df5fad0c670), C(9e4ea5a4941e097d), C(547e048d5a9daaba),
- C(eb6ecbb0b831d185), C(e0168df5fad0c670), C(afa9705f98c2c96a),
- C(749436f48137a96b), C(759c041fc21df486), C(b23bf400107aa2ec),
C(fd55007b)},
{C(5c8e90bc267c5ee4), C(e9ae044075d992d9), C(f234cbfd1f0a1e59),
- C(ce2744521944f14c), C(104f8032f99dc152), C(4e7f425bfac67ca7),
- C(9461b911a1c6d589), C(ce2744521944f14c), C(104f8032f99dc152),
- C(4e7f425bfac67ca7), C(9461b911a1c6d589), C(5e5ecc726db8b60d),
- C(cce68b0586083b51), C(8a7f8e54a9cba0fc), C(42f010181d16f049),
C(6b95894c)},
{C(bbd7f30ac310a6f3), C(b23b570d2666685f), C(fb13fb08c9814fe7),
- C(4ee107042e512374), C(1e2c8c0d16097e13), C(210c7500995aa0e6),
- C(6c13190557106457), C(4ee107042e512374), C(1e2c8c0d16097e13),
- C(210c7500995aa0e6), C(6c13190557106457), C(a99b31c96777f381),
- C(8312ae8301d386c0), C(ed5042b2a4fa96a3), C(d71d1bb23907fe97),
C(3360e827)},
- {C(36a097aa49519d97), C(8204380a73c4065), C(77c2004bdd9e276a),
- C(6ee1f817ce0b7aee), C(e9dcb3507f0596ca), C(6bc63c666b5100e2),
- C(e0b056f1821752af), C(6ee1f817ce0b7aee), C(e9dcb3507f0596ca),
- C(6bc63c666b5100e2), C(e0b056f1821752af), C(8ea1114e60292678),
- C(904b80b46becc77), C(46cd9bb6e9dff52f), C(4c91e3b698355540), C(45177e0b)},
- {C(dc78cb032c49217), C(112464083f83e03a), C(96ae53e28170c0f5),
- C(d367ff54952a958), C(cdad930657371147), C(aa24dc2a9573d5fe),
- C(eb136daa89da5110), C(d367ff54952a958), C(cdad930657371147),
- C(aa24dc2a9573d5fe), C(eb136daa89da5110), C(de623005f6d46057),
- C(b50c0c92b95e9b7f), C(a8aa54050b81c978), C(573fb5c7895af9b5),
- C(7c6fffe4)},
+ {C(36a097aa49519d97), C(8204380a73c4065), C(77c2004bdd9e276a), C(45177e0b)},
+ {C(dc78cb032c49217), C(112464083f83e03a), C(96ae53e28170c0f5), C(7c6fffe4)},
{C(441593e0da922dfe), C(936ef46061469b32), C(204a1921197ddd87),
- C(50d8a70e7a8d8f56), C(256d150ae75dab76), C(e81f4c4a1989036a),
- C(d0f8db365f9d7e00), C(50d8a70e7a8d8f56), C(256d150ae75dab76),
- C(e81f4c4a1989036a), C(d0f8db365f9d7e00), C(753d686677b14522),
- C(9f76e0cb6f2d0a66), C(ab14f95988ec0d39), C(97621d9da9c9812f),
C(bbc78da4)},
{C(2ba3883d71cc2133), C(72f2bbb32bed1a3c), C(27e1bd96d4843251),
- C(a90f761e8db1543a), C(c339e23c09703cd8), C(f0c6624c4b098fd3),
- C(1bae2053e41fa4d9), C(a90f761e8db1543a), C(c339e23c09703cd8),
- C(f0c6624c4b098fd3), C(1bae2053e41fa4d9), C(3589e273c22ba059),
- C(63798246e5911a0b), C(18e710ec268fc5dc), C(714a122de1d074f3),
C(c5c25d39)},
{C(f2b6d2adf8423600), C(7514e2f016a48722), C(43045743a50396ba),
- C(23dacb811652ad4f), C(c982da480e0d4c7d), C(3a9c8ed5a399d0a9),
- C(951b8d084691d4e4), C(23dacb811652ad4f), C(c982da480e0d4c7d),
- C(3a9c8ed5a399d0a9), C(951b8d084691d4e4), C(d9f87b4988cff2f7),
- C(217a191d986aa3bc), C(6ad23c56b480350), C(dd78673938ceb2e7), C(b6e5d06e)},
+ C(b6e5d06e)},
{C(38fffe7f3680d63c), C(d513325255a7a6d1), C(31ed47790f6ca62f),
- C(c801faaa0a2e331f), C(491dbc58279c7f88), C(9c0178848321c97a),
- C(9d934f814f4d6a3c), C(c801faaa0a2e331f), C(491dbc58279c7f88),
- C(9c0178848321c97a), C(9d934f814f4d6a3c), C(606a3e4fc8763192),
- C(bc15cb36a677ee84), C(52d5904157e1fe71), C(1588dd8b1145b79b),
C(6178504e)},
- {C(b7477bf0b9ce37c6), C(63b1c580a7fd02a4), C(f6433b9f10a5dac),
- C(68dd76db9d64eca7), C(36297682b64b67), C(42b192d71f414b7a),
- C(79692cef44fa0206), C(68dd76db9d64eca7), C(36297682b64b67),
- C(42b192d71f414b7a), C(79692cef44fa0206), C(f0979252f4776d07),
- C(4b87cd4f1c9bbf52), C(51b84bbc6312c710), C(150720fbf85428a7),
- C(bd4c3637)},
+ {C(b7477bf0b9ce37c6), C(63b1c580a7fd02a4), C(f6433b9f10a5dac), C(bd4c3637)},
{C(55bdb0e71e3edebd), C(c7ab562bcf0568bc), C(43166332f9ee684f),
- C(b2e25964cd409117), C(a010599d6287c412), C(fa5d6461e768dda2),
- C(cb3ce74e8ec4f906), C(b2e25964cd409117), C(a010599d6287c412),
- C(fa5d6461e768dda2), C(cb3ce74e8ec4f906), C(6120abfd541a2610),
- C(aa88b148cc95794d), C(2686ca35df6590e3), C(c6b02d18616ce94d),
C(6e7ac474)},
- {C(782fa1b08b475e7), C(fb7138951c61b23b), C(9829105e234fb11e),
- C(9a8c431f500ef06e), C(d848581a580b6c12), C(fecfe11e13a2bdb4),
- C(6c4fa0273d7db08c), C(9a8c431f500ef06e), C(d848581a580b6c12),
- C(fecfe11e13a2bdb4), C(6c4fa0273d7db08c), C(482f43bf5ae59fcb),
- C(f651fbca105d79e6), C(f09f78695d865817), C(7a99d0092085cf47),
- C(1fb4b518)},
+ {C(782fa1b08b475e7), C(fb7138951c61b23b), C(9829105e234fb11e), C(1fb4b518)},
{C(c5dc19b876d37a80), C(15ffcff666cfd710), C(e8c30c72003103e2),
- C(7870765b470b2c5d), C(78a9103ff960d82), C(7bb50ffc9fac74b3),
- C(477e70ab2b347db2), C(7870765b470b2c5d), C(78a9103ff960d82),
- C(7bb50ffc9fac74b3), C(477e70ab2b347db2), C(a625238bdf7c07cf),
- C(1128d515174809f5), C(b0f1647e82f45873), C(17792d1c4f222c39),
C(31d13d6d)},
{C(5e1141711d2d6706), C(b537f6dee8de6933), C(3af0a1fbbe027c54),
- C(ea349dbc16c2e441), C(38a7455b6a877547), C(5f97b9750e365411),
- C(e8cde7f93af49a3), C(ea349dbc16c2e441), C(38a7455b6a877547),
- C(5f97b9750e365411), C(e8cde7f93af49a3), C(ba101925ec1f7e26),
- C(d5e84cab8192c71e), C(e256427726fdd633), C(a4f38e2c6116890d),
C(26fa72e3)},
- {C(782edf6da001234f), C(f48cbd5c66c48f3), C(808754d1e64e2a32),
- C(5d9dde77353b1a6d), C(11f58c54581fa8b1), C(da90fa7c28c37478),
- C(5e9a2eafc670a88a), C(5d9dde77353b1a6d), C(11f58c54581fa8b1),
- C(da90fa7c28c37478), C(5e9a2eafc670a88a), C(e35e1bc172e011ef),
- C(bf9255a4450ae7fe), C(55f85194e26bc55f), C(4f327873e14d0e54),
- C(6a7433bf)},
+ {C(782edf6da001234f), C(f48cbd5c66c48f3), C(808754d1e64e2a32), C(6a7433bf)},
{C(d26285842ff04d44), C(8f38d71341eacca9), C(5ca436f4db7a883c),
- C(bf41e5376b9f0eec), C(2252d21eb7e1c0e9), C(f4b70a971855e732),
- C(40c7695aa3662afd), C(bf41e5376b9f0eec), C(2252d21eb7e1c0e9),
- C(f4b70a971855e732), C(40c7695aa3662afd), C(770fe19e16ab73bb),
- C(d603ebda6393d749), C(e58c62439aa50dbd), C(96d51e5a02d2d7cf),
C(4e6df758)},
{C(c6ab830865a6bae6), C(6aa8e8dd4b98815c), C(efe3846713c371e5),
- C(a1924cbf0b5f9222), C(7f4872369c2b4258), C(cd6da30530f3ea89),
- C(b7f8b9a704e6cea1), C(a1924cbf0b5f9222), C(7f4872369c2b4258),
- C(cd6da30530f3ea89), C(b7f8b9a704e6cea1), C(fa06ff40433fd535),
- C(fb1c36fe8f0737f1), C(bb7050561171f80), C(b1bc23235935d897), C(d57f63ea)},
- {C(44b3a1929232892), C(61dca0e914fc217), C(a607cc142096b964),
- C(f7dbc8433c89b274), C(2f5f70581c9b7d32), C(39bf5e5fec82dcca),
- C(8ade56388901a619), C(f7dbc8433c89b274), C(2f5f70581c9b7d32),
- C(39bf5e5fec82dcca), C(8ade56388901a619), C(c1c6a725caab3ea9),
- C(c1c7906c2f80b898), C(9c3871a04cc884e6), C(df01813cbbdf217f),
- C(52ef73b3)},
- {C(4b603d7932a8de4f), C(fae64c464b8a8f45), C(8fafab75661d602a),
- C(8ffe870ef4adc087), C(65bea2be41f55b54), C(82f3503f636aef1),
- C(5f78a282378b6bb0), C(8ffe870ef4adc087), C(65bea2be41f55b54),
- C(82f3503f636aef1), C(5f78a282378b6bb0), C(7bf2422c0beceddb),
- C(9d238d4780114bd), C(7ad198311906597f), C(ec8f892c0422aca3), C(3cb36c3)},
+ C(d57f63ea)},
+ {C(44b3a1929232892), C(61dca0e914fc217), C(a607cc142096b964), C(52ef73b3)},
+ {C(4b603d7932a8de4f), C(fae64c464b8a8f45), C(8fafab75661d602a), C(3cb36c3)},
{C(4ec0b54cf1566aff), C(30d2c7269b206bf4), C(77c22e82295e1061),
- C(3df9b04434771542), C(feddce785ccb661f), C(a644aff716928297),
- C(dd46aee73824b4ed), C(3df9b04434771542), C(feddce785ccb661f),
- C(a644aff716928297), C(dd46aee73824b4ed), C(bf8d71879da29b02),
- C(fc82dccbfc8022a0), C(31bfcd0d9f48d1d3), C(c64ee24d0e7b5f8b),
C(72c39bea)},
{C(ed8b7a4b34954ff7), C(56432de31f4ee757), C(85bd3abaa572b155),
- C(7d2c38a926dc1b88), C(5245b9eb4cd6791d), C(fb53ab03b9ad0855),
- C(3664026c8fc669d7), C(7d2c38a926dc1b88), C(5245b9eb4cd6791d),
- C(fb53ab03b9ad0855), C(3664026c8fc669d7), C(45024d5080bc196),
- C(b236ebec2cc2740), C(27231ad0e3443be4), C(145780b63f809250), C(a65aa25c)},
+ C(a65aa25c)},
{C(5d28b43694176c26), C(714cc8bc12d060ae), C(3437726273a83fe6),
- C(864b1b28ec16ea86), C(6a78a5a4039ec2b9), C(8e959533e35a766),
- C(347b7c22b75ae65f), C(864b1b28ec16ea86), C(6a78a5a4039ec2b9),
- C(8e959533e35a766), C(347b7c22b75ae65f), C(5005892bb61e647c),
- C(fe646519b4a1894d), C(cd801026f74a8a53), C(8713463e9a1ab9ce),
C(74740539)},
{C(6a1ef3639e1d202e), C(919bc1bd145ad928), C(30f3f7e48c28a773),
- C(2e8c49d7c7aaa527), C(5e2328fc8701db7c), C(89ef1afca81f7de8),
- C(b1857db11985d296), C(2e8c49d7c7aaa527), C(5e2328fc8701db7c),
- C(89ef1afca81f7de8), C(b1857db11985d296), C(17763d695f616115),
- C(b8f7bf1fcdc8322c), C(cf0c61938ab07a27), C(1122d3e6edb4e866),
C(c3ae3c26)},
- {C(159f4d9e0307b111), C(3e17914a5675a0c), C(af849bd425047b51),
- C(3b69edadf357432b), C(3a2e311c121e6bf2), C(380fad1e288d57e5),
- C(bf7c7e8ef0e3b83a), C(3b69edadf357432b), C(3a2e311c121e6bf2),
- C(380fad1e288d57e5), C(bf7c7e8ef0e3b83a), C(92966d5f4356ae9b),
- C(2a03fc66c4d6c036), C(2516d8bddb0d5259), C(b3ffe9737ff5090), C(f29db8a2)},
+ {C(159f4d9e0307b111), C(3e17914a5675a0c), C(af849bd425047b51), C(f29db8a2)},
{C(cc0a840725a7e25b), C(57c69454396e193a), C(976eaf7eee0b4540),
- C(cd7a46850b95e901), C(c57f7d060dda246f), C(6b9406ead64079bf),
- C(11b28e20a573b7bd), C(cd7a46850b95e901), C(c57f7d060dda246f),
- C(6b9406ead64079bf), C(11b28e20a573b7bd), C(2d6db356e9369ace),
- C(dc0afe10fba193), C(5cdb10885dbbfce), C(5c700e205782e35a), C(1ef4cbf4)},
+ C(1ef4cbf4)},
{C(a2b27ee22f63c3f1), C(9ebde0ce1b3976b2), C(2fe6a92a257af308),
- C(8c1df927a930af59), C(a462f4423c9e384e), C(236542255b2ad8d9),
- C(595d201a2c19d5bc), C(8c1df927a930af59), C(a462f4423c9e384e),
- C(236542255b2ad8d9), C(595d201a2c19d5bc), C(22c87d4604a67f3),
- C(585a06eb4bc44c4f), C(b4175a7ac7eabcd8), C(a457d3eeba14ab8c),
C(a9be6c41)},
- {C(d8f2f234899bcab3), C(b10b037297c3a168), C(debea2c510ceda7f),
- C(9498fefb890287ce), C(ae68c2be5b1a69a6), C(6189dfba34ed656c),
- C(91658f95836e5206), C(9498fefb890287ce), C(ae68c2be5b1a69a6),
- C(6189dfba34ed656c), C(91658f95836e5206), C(c0bb4fff32aecd4d),
- C(94125f505a50eef9), C(6ac406e7cfbce5bb), C(344a4b1dcdb7f5d8), C(fa31801)},
+ {C(d8f2f234899bcab3), C(b10b037297c3a168), C(debea2c510ceda7f), C(fa31801)},
{C(584f28543864844f), C(d7cee9fc2d46f20d), C(a38dca5657387205),
- C(7a0b6dbab9a14e69), C(c6d0a9d6b0e31ac4), C(a674d85812c7cf6),
- C(63538c0351049940), C(7a0b6dbab9a14e69), C(c6d0a9d6b0e31ac4),
- C(a674d85812c7cf6), C(63538c0351049940), C(9710e5f0bc93d1d),
- C(c2bea5bd7c54ddd4), C(48739af2bed0d32d), C(ba2c4e09e21fba85),
C(8331c5d8)},
- {C(a94be46dd9aa41af), C(a57e5b7723d3f9bd), C(34bf845a52fd2f),
- C(843b58463c8df0ae), C(74b258324e916045), C(bdd7353230eb2b38),
- C(fad31fced7abade5), C(843b58463c8df0ae), C(74b258324e916045),
- C(bdd7353230eb2b38), C(fad31fced7abade5), C(2436aeafb0046f85),
- C(65bc9af9e5e33161), C(92733b1b3ae90628), C(f48143eaf78a7a89),
- C(e9876db8)},
+ {C(a94be46dd9aa41af), C(a57e5b7723d3f9bd), C(34bf845a52fd2f), C(e9876db8)},
{C(9a87bea227491d20), C(a468657e2b9c43e7), C(af9ba60db8d89ef7),
- C(cc76f429ea7a12bb), C(5f30eaf2bb14870a), C(434e824cb3e0cd11),
- C(431a4d382e39d16e), C(cc76f429ea7a12bb), C(5f30eaf2bb14870a),
- C(434e824cb3e0cd11), C(431a4d382e39d16e), C(9e51f913c4773a8),
- C(32ab1925823d0add), C(99c61b54c1d8f69d), C(38cfb80f02b43b1f),
C(27b0604e)},
{C(27688c24958d1a5c), C(e3b4a1c9429cf253), C(48a95811f70d64bc),
- C(328063229db22884), C(67e9c95f8ba96028), C(7c6bf01c60436075),
- C(fa55161e7d9030b2), C(328063229db22884), C(67e9c95f8ba96028),
- C(7c6bf01c60436075), C(fa55161e7d9030b2), C(dadbc2f0dab91681),
- C(da39d7a4934ca11), C(162e845d24c1b45c), C(eb5b9dcd8c6ed31b), C(dcec07f2)},
+ C(dcec07f2)},
{C(5d1d37790a1873ad), C(ed9cd4bcc5fa1090), C(ce51cde05d8cd96a),
- C(f72c26e624407e66), C(a0eb541bdbc6d409), C(c3f40a2f40b3b213),
- C(6a784de68794492d), C(f72c26e624407e66), C(a0eb541bdbc6d409),
- C(c3f40a2f40b3b213), C(6a784de68794492d), C(10a38a23dbef7937),
- C(6a5560f853252278), C(c3387bbf3c7b82ba), C(fbee7c12eb072805),
C(cff0a82a)},
{C(1f03fd18b711eea9), C(566d89b1946d381a), C(6e96e83fc92563ab),
- C(405f66cf8cae1a32), C(d7261740d8f18ce6), C(fea3af64a413d0b2),
- C(d64d1810e83520fe), C(405f66cf8cae1a32), C(d7261740d8f18ce6),
- C(fea3af64a413d0b2), C(d64d1810e83520fe), C(e1334a00a580c6e8),
- C(454049e1b52c15f), C(8895d823d9778247), C(efa7f2e88b826618), C(fec83621)},
- {C(f0316f286cf527b6), C(f84c29538de1aa5a), C(7612ed3c923d4a71),
- C(d4eccebe9393ee8a), C(2eb7867c2318cc59), C(1ce621fd700fe396),
- C(686450d7a346878a), C(d4eccebe9393ee8a), C(2eb7867c2318cc59),
- C(1ce621fd700fe396), C(686450d7a346878a), C(75a5f37579f8b4cb),
- C(500cc16eb6541dc7), C(b7b02317b539d9a6), C(3519ddff5bc20a29), C(743d8dc)},
+ C(fec83621)},
+ {C(f0316f286cf527b6), C(f84c29538de1aa5a), C(7612ed3c923d4a71), C(743d8dc)},
{C(297008bcb3e3401d), C(61a8e407f82b0c69), C(a4a35bff0524fa0e),
- C(7a61d8f552a53442), C(821d1d8d8cfacf35), C(7cc06361b86d0559),
- C(119b617a8c2be199), C(7a61d8f552a53442), C(821d1d8d8cfacf35),
- C(7cc06361b86d0559), C(119b617a8c2be199), C(2996487da6721759),
- C(61a901376070b91d), C(d88dee12ae9c9b3c), C(5665491be1fa53a7),
C(64d41d26)},
- {C(43c6252411ee3be), C(b4ca1b8077777168), C(2746dc3f7da1737f),
- C(2247a4b2058d1c50), C(1b3fa184b1d7bcc0), C(deb85613995c06ed),
- C(cbe1d957485a3ccd), C(2247a4b2058d1c50), C(1b3fa184b1d7bcc0),
- C(deb85613995c06ed), C(cbe1d957485a3ccd), C(dfe241f8f33c96b6),
- C(6597eb05019c2109), C(da344b2a63a219cf), C(79b8e3887612378a),
- C(acd90c81)},
+ {C(43c6252411ee3be), C(b4ca1b8077777168), C(2746dc3f7da1737f), C(acd90c81)},
{C(ce38a9a54fad6599), C(6d6f4a90b9e8755e), C(c3ecc79ff105de3f),
- C(e8b9ee96efa2d0e), C(90122905c4ab5358), C(84f80c832d71979c),
- C(229310f3ffbbf4c6), C(e8b9ee96efa2d0e), C(90122905c4ab5358),
- C(84f80c832d71979c), C(229310f3ffbbf4c6), C(cc9eb42100cd63a7),
- C(7a283f2f3da7b9f), C(359b061d314e7a72), C(d0d959720028862), C(7c746a4b)},
- {C(270a9305fef70cf), C(600193999d884f3a), C(f4d49eae09ed8a1),
- C(2e091b85660f1298), C(bfe37fae1cdd64c9), C(8dddfbab930f6494),
- C(2ccf4b08f5d417a), C(2e091b85660f1298), C(bfe37fae1cdd64c9),
- C(8dddfbab930f6494), C(2ccf4b08f5d417a), C(365c2ee85582fe6),
- C(dee027bcd36db62a), C(b150994d3c7e5838), C(fdfd1a0e692e436d),
- C(b1047e99)},
+ C(7c746a4b)},
+ {C(270a9305fef70cf), C(600193999d884f3a), C(f4d49eae09ed8a1), C(b1047e99)},
{C(e71be7c28e84d119), C(eb6ace59932736e6), C(70c4397807ba12c5),
- C(7a9d77781ac53509), C(4489c3ccfda3b39c), C(fa722d4f243b4964),
- C(25f15800bffdd122), C(7a9d77781ac53509), C(4489c3ccfda3b39c),
- C(fa722d4f243b4964), C(25f15800bffdd122), C(ed85e4157fbd3297),
- C(aab1967227d59efd), C(2199631212eb3839), C(3e4c19359aae1cc2),
C(d1fd1068)},
{C(b5b58c24b53aaa19), C(d2a6ab0773dd897f), C(ef762fe01ecb5b97),
- C(9deefbcfa4cab1f1), C(b58f5943cd2492ba), C(a96dcc4d1f4782a7),
- C(102b62a82309dde5), C(9deefbcfa4cab1f1), C(b58f5943cd2492ba),
- C(a96dcc4d1f4782a7), C(102b62a82309dde5), C(35fe52684763b338),
- C(afe2616651eaad1f), C(43e38715bdfa05e7), C(83c9ba83b5ec4a40),
C(56486077)},
{C(44dd59bd301995cf), C(3ccabd76493ada1a), C(540db4c87d55ef23),
- C(cfc6d7adda35797), C(14c7d1f32332cf03), C(2d553ffbff3be99d),
- C(c91c4ee0cb563182), C(cfc6d7adda35797), C(14c7d1f32332cf03),
- C(2d553ffbff3be99d), C(c91c4ee0cb563182), C(9aa5e507f49136f0),
- C(760c5dd1a82c4888), C(beea7e974a1cfb5c), C(640b247774fe4bf7),
C(6069be80)},
- {C(b4d4789eb6f2630b), C(bf6973263ce8ef0e), C(d1c75c50844b9d3),
- C(bce905900c1ec6ea), C(c30f304f4045487d), C(a5c550166b3a142b),
- C(2f482b4e35327287), C(bce905900c1ec6ea), C(c30f304f4045487d),
- C(a5c550166b3a142b), C(2f482b4e35327287), C(15b21ddddf355438),
- C(496471fa3006bab), C(2a8fd458d06c1a32), C(db91e8ae812f0b8d), C(2078359b)},
+ {C(b4d4789eb6f2630b), C(bf6973263ce8ef0e), C(d1c75c50844b9d3), C(2078359b)},
{C(12807833c463737c), C(58e927ea3b3776b4), C(72dd20ef1c2f8ad0),
- C(910b610de7a967bf), C(801bc862120f6bf5), C(9653efeed5897681),
- C(f5367ff83e9ebbb3), C(910b610de7a967bf), C(801bc862120f6bf5),
- C(9653efeed5897681), C(f5367ff83e9ebbb3), C(cf56d489afd1b0bf),
- C(c7c793715cae3de8), C(631f91d64abae47c), C(5f1f42fb14a444a2),
C(9ea21004)},
{C(e88419922b87176f), C(bcf32f41a7ddbf6f), C(d6ebefd8085c1a0f),
- C(d1d44fe99451ef72), C(ec951ba8e51e3545), C(c0ca86b360746e96),
- C(aa679cc066a8040b), C(d1d44fe99451ef72), C(ec951ba8e51e3545),
- C(c0ca86b360746e96), C(aa679cc066a8040b), C(51065861ece6ffc1),
- C(76777368a2997e11), C(87f278f46731100c), C(bbaa4140bdba4527),
C(9c9cfe88)},
{C(105191e0ec8f7f60), C(5918dbfcca971e79), C(6b285c8a944767b9),
- C(d3e86ac4f5eccfa4), C(e5399df2b106ca1), C(814aadfacd217f1d),
- C(2754e3def1c405a9), C(d3e86ac4f5eccfa4), C(e5399df2b106ca1),
- C(814aadfacd217f1d), C(2754e3def1c405a9), C(99290323b9f06e74),
- C(a9782e043f271461), C(13c8b3b8c275a860), C(6038d620e581e9e7),
C(b70a6ddd)},
{C(a5b88bf7399a9f07), C(fca3ddfd96461cc4), C(ebe738fdc0282fc6),
- C(69afbc800606d0fb), C(6104b97a9db12df7), C(fcc09198bb90bf9f),
- C(c5e077e41a65ba91), C(69afbc800606d0fb), C(6104b97a9db12df7),
- C(fcc09198bb90bf9f), C(c5e077e41a65ba91), C(db261835ee8aa08e),
- C(db0ee662e5796dc9), C(fc1880ecec499e5f), C(648866fbe1502034),
C(dea37298)},
{C(d08c3f5747d84f50), C(4e708b27d1b6f8ac), C(70f70fd734888606),
- C(909ae019d761d019), C(368bf4aab1b86ef9), C(308bd616d5460239),
- C(4fd33269f76783ea), C(909ae019d761d019), C(368bf4aab1b86ef9),
- C(308bd616d5460239), C(4fd33269f76783ea), C(7d53b37c19713eab),
- C(6bba6eabda58a897), C(91abb50efc116047), C(4e902f347e0e0e35),
C(8f480819)},
- {C(2f72d12a40044b4b), C(889689352fec53de), C(f03e6ad87eb2f36),
- C(ef79f28d874b9e2d), C(b512089e8e63b76c), C(24dc06833bf193a9),
- C(3c23308ba8e99d7e), C(ef79f28d874b9e2d), C(b512089e8e63b76c),
- C(24dc06833bf193a9), C(3c23308ba8e99d7e), C(5ceff7b85cacefb7),
- C(ef390338898cd73), C(b12967d7d2254f54), C(de874cbd8aef7b75), C(30b3b16)},
+ {C(2f72d12a40044b4b), C(889689352fec53de), C(f03e6ad87eb2f36), C(30b3b16)},
{C(aa1f61fdc5c2e11e), C(c2c56cd11277ab27), C(a1e73069fdf1f94f),
- C(8184bab36bb79df0), C(c81929ce8655b940), C(301b11bf8a4d8ce8),
- C(73126fd45ab75de9), C(8184bab36bb79df0), C(c81929ce8655b940),
- C(301b11bf8a4d8ce8), C(73126fd45ab75de9), C(4bd6f76e4888229a),
- C(9aae355b54a756d5), C(ca3de9726f6e99d5), C(83f80cac5bc36852),
C(f31bc4e8)},
{C(9489b36fe2246244), C(3355367033be74b8), C(5f57c2277cbce516),
- C(bc61414f9802ecaf), C(8edd1e7a50562924), C(48f4ab74a35e95f2),
- C(cc1afcfd99a180e7), C(bc61414f9802ecaf), C(8edd1e7a50562924),
- C(48f4ab74a35e95f2), C(cc1afcfd99a180e7), C(517dd5e3acf66110),
- C(7dd3ad9e8978b30d), C(1f6d5dfc70de812b), C(947daaba6441aaf3),
C(419f953b)},
{C(358d7c0476a044cd), C(e0b7b47bcbd8854f), C(ffb42ec696705519),
- C(d45e44c263e95c38), C(df61db53923ae3b1), C(f2bc948cc4fc027c),
- C(8a8000c6066772a3), C(d45e44c263e95c38), C(df61db53923ae3b1),
- C(f2bc948cc4fc027c), C(8a8000c6066772a3), C(9fd93c942d31fa17),
- C(d7651ecebe09cbd3), C(68682cefb6a6f165), C(541eb99a2dcee40e),
C(20e9e76d)},
{C(b0c48df14275265a), C(9da4448975905efa), C(d716618e414ceb6d),
- C(30e888af70df1e56), C(4bee54bd47274f69), C(178b4059e1a0afe5),
- C(6e2c96b7f58e5178), C(30e888af70df1e56), C(4bee54bd47274f69),
- C(178b4059e1a0afe5), C(6e2c96b7f58e5178), C(bb429d3b9275e9bc),
- C(c198013f09cafdc6), C(ec0a6ee4fb5de348), C(744e1e8ed2eb1eb0),
C(646f0ff8)},
{C(daa70bb300956588), C(410ea6883a240c6d), C(f5c8239fb5673eb3),
- C(8b1d7bb4903c105f), C(cfb1c322b73891d4), C(5f3b792b22f07297),
- C(fd64061f8be86811), C(8b1d7bb4903c105f), C(cfb1c322b73891d4),
- C(5f3b792b22f07297), C(fd64061f8be86811), C(1d2db712921cfc2b),
- C(cd1b2b2f2cee18ae), C(6b6f8790dc7feb09), C(46c179efa3f0f518),
C(eeb7eca8)},
- {C(4ec97a20b6c4c7c2), C(5913b1cd454f29fd), C(a9629f9daf06d685),
- C(852c9499156a8f3), C(3a180a6abfb79016), C(9fc3c4764037c3c9),
- C(2890c42fc0d972cf), C(852c9499156a8f3), C(3a180a6abfb79016),
- C(9fc3c4764037c3c9), C(2890c42fc0d972cf), C(1f92231d4e537651),
- C(fab8bb07aa54b7b9), C(e05d2d771c485ed4), C(d50b34bf808ca731), C(8112bb9)},
+ {C(4ec97a20b6c4c7c2), C(5913b1cd454f29fd), C(a9629f9daf06d685), C(8112bb9)},
{C(5c3323628435a2e8), C(1bea45ce9e72a6e3), C(904f0a7027ddb52e),
- C(939f31de14dcdc7b), C(a68fdf4379df068), C(f169e1f0b835279d),
- C(7498e432f9619b27), C(939f31de14dcdc7b), C(a68fdf4379df068),
- C(f169e1f0b835279d), C(7498e432f9619b27), C(1aa2a1f11088e785),
- C(d6ad72f45729de78), C(9a63814157c80267), C(55538e35c648e435),
C(85a6d477)},
{C(c1ef26bea260abdb), C(6ee423f2137f9280), C(df2118b946ed0b43),
- C(11b87fb1b900cc39), C(e33e59b90dd815b1), C(aa6cb5c4bafae741),
- C(739699951ca8c713), C(11b87fb1b900cc39), C(e33e59b90dd815b1),
- C(aa6cb5c4bafae741), C(739699951ca8c713), C(2b4389a967310077),
- C(1d5382568a31c2c9), C(55d1e787fbe68991), C(277c254bc31301e7),
C(56f76c84)},
{C(6be7381b115d653a), C(ed046190758ea511), C(de6a45ffc3ed1159),
- C(a64760e4041447d0), C(e3eac49f3e0c5109), C(dd86c4d4cb6258e2),
- C(efa9857afd046c7f), C(a64760e4041447d0), C(e3eac49f3e0c5109),
- C(dd86c4d4cb6258e2), C(efa9857afd046c7f), C(fab793dae8246f16),
- C(c9e3b121b31d094c), C(a2a0f55858465226), C(dba6f0ff39436344),
C(9af45d55)},
{C(ae3eece1711b2105), C(14fd3f4027f81a4a), C(abb7e45177d151db),
- C(501f3e9b18861e44), C(465201170074e7d8), C(96d5c91970f2cb12),
- C(40fd28c43506c95d), C(501f3e9b18861e44), C(465201170074e7d8),
- C(96d5c91970f2cb12), C(40fd28c43506c95d), C(e86c4b07802aaff3),
- C(f317d14112372a70), C(641b13e587711650), C(4915421ab1090eaa),
C(d1c33760)},
{C(376c28588b8fb389), C(6b045e84d8491ed2), C(4e857effb7d4e7dc),
- C(154dd79fd2f984b4), C(f11171775622c1c3), C(1fbe30982e78e6f0),
- C(a460a15dcf327e44), C(154dd79fd2f984b4), C(f11171775622c1c3),
- C(1fbe30982e78e6f0), C(a460a15dcf327e44), C(f359e0900cc3d582),
- C(7e11070447976d00), C(324e6daf276ea4b5), C(7aa6e2df0cc94fa2),
C(c56bbf69)},
{C(58d943503bb6748f), C(419c6c8e88ac70f6), C(586760cbf3d3d368),
- C(b7e164979d5ccfc1), C(12cb4230d26bf286), C(f1bf910d44bd84cb),
- C(b32c24c6a40272), C(b7e164979d5ccfc1), C(12cb4230d26bf286),
- C(f1bf910d44bd84cb), C(b32c24c6a40272), C(11ed12e34c48c039),
- C(b0c2538e51d0a6ac), C(4269bb773e1d553a), C(e35a9dbabd34867), C(abecfb9b)},
+ C(abecfb9b)},
{C(dfff5989f5cfd9a1), C(bcee2e7ea3a96f83), C(681c7874adb29017),
- C(3ff6c8ac7c36b63a), C(48bc8831d849e326), C(30b078e76b0214e2),
- C(42954e6ad721b920), C(3ff6c8ac7c36b63a), C(48bc8831d849e326),
- C(30b078e76b0214e2), C(42954e6ad721b920), C(f9aeb33d164b4472),
- C(7b353b110831dbdc), C(16f64c82f44ae17b), C(b71244cc164b3b2b),
C(8de13255)},
{C(7fb19eb1a496e8f5), C(d49e5dfdb5c0833f), C(c0d5d7b2f7c48dc7),
- C(1a57313a32f22dde), C(30af46e49850bf8b), C(aa0fe8d12f808f83),
- C(443e31d70873bb6b), C(1a57313a32f22dde), C(30af46e49850bf8b),
- C(aa0fe8d12f808f83), C(443e31d70873bb6b), C(bbeb67c49c9fdc13),
- C(18f1e2a88f59f9d5), C(fb1b05038e5def11), C(d0450b5ce4c39c52),
C(a98ee299)},
{C(5dba5b0dadccdbaa), C(4ba8da8ded87fcdc), C(f693fdd25badf2f0),
- C(e9029e6364286587), C(ae69f49ecb46726c), C(18e002679217c405),
- C(bd6d66e85332ae9f), C(e9029e6364286587), C(ae69f49ecb46726c),
- C(18e002679217c405), C(bd6d66e85332ae9f), C(6bf330b1c353dd2a),
- C(74e9f2e71e3a4152), C(3f85560b50f6c413), C(d33a52a47eaed2b4),
C(3015f556)},
{C(688bef4b135a6829), C(8d31d82abcd54e8e), C(f95f8a30d55036d7),
- C(3d8c90e27aa2e147), C(2ec937ce0aa236b4), C(89b563996d3a0b78),
- C(39b02413b23c3f08), C(3d8c90e27aa2e147), C(2ec937ce0aa236b4),
- C(89b563996d3a0b78), C(39b02413b23c3f08), C(8d475a2e64faf2d2),
- C(48567f7dca46ecaf), C(254cda08d5f87a6d), C(ec6ae9f729c47039),
C(5a430e29)},
{C(d8323be05433a412), C(8d48fa2b2b76141d), C(3d346f23978336a5),
- C(4d50c7537562033f), C(57dc7625b61dfe89), C(9723a9f4c08ad93a),
- C(5309596f48ab456b), C(4d50c7537562033f), C(57dc7625b61dfe89),
- C(9723a9f4c08ad93a), C(5309596f48ab456b), C(7e453088019d220f),
- C(8776067ba6ab9714), C(67e1d06bd195de39), C(74a1a32f8994b918),
C(2797add0)},
{C(3b5404278a55a7fc), C(23ca0b327c2d0a81), C(a6d65329571c892c),
- C(45504801e0e6066b), C(86e6c6d6152a3d04), C(4f3db1c53eca2952),
- C(d24d69b3e9ef10f3), C(45504801e0e6066b), C(86e6c6d6152a3d04),
- C(4f3db1c53eca2952), C(d24d69b3e9ef10f3), C(93a0de2219e66a70),
- C(8932c7115ccb1f8a), C(5ef503fdf2841a8c), C(38064dd9efa80a41),
C(27d55016)},
{C(2a96a3f96c5e9bbc), C(8caf8566e212dda8), C(904de559ca16e45e),
- C(f13bc2d9c2fe222e), C(be4ccec9a6cdccfd), C(37b2cbdd973a3ac9),
- C(7b3223cd9c9497be), C(f13bc2d9c2fe222e), C(be4ccec9a6cdccfd),
- C(37b2cbdd973a3ac9), C(7b3223cd9c9497be), C(d5904440f376f889),
- C(62b13187699c473c), C(4751b89251f26726), C(9500d84fa3a61ba8),
C(84945a82)},
{C(22bebfdcc26d18ff), C(4b4d8dcb10807ba1), C(40265eee30c6b896),
- C(3752b423073b119a), C(377dc5eb7c662bdb), C(2b9f07f93a6c25b9),
- C(96f24ede2bdc0718), C(3752b423073b119a), C(377dc5eb7c662bdb),
- C(2b9f07f93a6c25b9), C(96f24ede2bdc0718), C(f7699b12c31417bd),
- C(17b366f401c58b2), C(bf60188d5f437b37), C(484436e56df17f04), C(3ef7e224)},
+ C(3ef7e224)},
{C(627a2249ec6bbcc2), C(c0578b462a46735a), C(4974b8ee1c2d4f1f),
- C(ebdbb918eb6d837f), C(8fb5f218dd84147c), C(c77dd1f881df2c54),
- C(62eac298ec226dc3), C(ebdbb918eb6d837f), C(8fb5f218dd84147c),
- C(c77dd1f881df2c54), C(62eac298ec226dc3), C(43eded83c4b60bd0),
- C(9a0a403b5487503b), C(25f305d9147f0bda), C(3ad417f511bc1e64),
C(35ed8dc8)},
- {C(3abaf1667ba2f3e0), C(ee78476b5eeadc1), C(7e56ac0a6ca4f3f4),
- C(f1b9b413df9d79ed), C(a7621b6fd02db503), C(d92f7ba9928a4ffe),
- C(53f56babdcae96a6), C(f1b9b413df9d79ed), C(a7621b6fd02db503),
- C(d92f7ba9928a4ffe), C(53f56babdcae96a6), C(5302b89fc48713ab),
- C(d03e3b04dbe7a2f2), C(fa74ef8af6d376a7), C(103c8cdea1050ef2),
- C(6a75e43d)},
+ {C(3abaf1667ba2f3e0), C(ee78476b5eeadc1), C(7e56ac0a6ca4f3f4), C(6a75e43d)},
{C(3931ac68c5f1b2c9), C(efe3892363ab0fb0), C(40b707268337cd36),
- C(a53a6b64b1ac85c9), C(d50e7f86ee1b832b), C(7bab08fdd26ba0a4),
- C(7587743c18fe2475), C(a53a6b64b1ac85c9), C(d50e7f86ee1b832b),
- C(7bab08fdd26ba0a4), C(7587743c18fe2475), C(e3b5d5d490cf5761),
- C(dfc053f7d065edd5), C(42ffd8d5fb70129f), C(599ca38677cccdc3),
C(235d9805)},
- {C(b98fb0606f416754), C(46a6e5547ba99c1e), C(c909d82112a8ed2),
- C(dbfaae9642b3205a), C(f676a1339402bcb9), C(f4f12a5b1ac11f29),
- C(7db8bad81249dee4), C(dbfaae9642b3205a), C(f676a1339402bcb9),
- C(f4f12a5b1ac11f29), C(7db8bad81249dee4), C(b26e46f2da95922e),
- C(2aaedd5e12e3c611), C(a0e2d9082966074), C(c64da8a167add63d), C(f7d69572)},
+ {C(b98fb0606f416754), C(46a6e5547ba99c1e), C(c909d82112a8ed2), C(f7d69572)},
{C(7f7729a33e58fcc4), C(2e4bc1e7a023ead4), C(e707008ea7ca6222),
- C(47418a71800334a0), C(d10395d8fc64d8a4), C(8257a30062cb66f),
- C(6786f9b2dc1ff18a), C(47418a71800334a0), C(d10395d8fc64d8a4),
- C(8257a30062cb66f), C(6786f9b2dc1ff18a), C(5633f437bb2f180f),
- C(e5a3a405737d22d6), C(ca0ff1ef6f7f0b74), C(d0ae600684b16df8),
C(bacd0199)},
{C(42a0aa9ce82848b3), C(57232730e6bee175), C(f89bb3f370782031),
- C(caa33cf9b4f6619c), C(b2c8648ad49c209f), C(9e89ece0712db1c0),
- C(101d8274a711a54b), C(caa33cf9b4f6619c), C(b2c8648ad49c209f),
- C(9e89ece0712db1c0), C(101d8274a711a54b), C(538e79f1e70135cd),
- C(e1f5a76f983c844e), C(653c082fd66088fc), C(1b9c9b464b654958),
C(e428f50e)},
{C(6b2c6d38408a4889), C(de3ef6f68fb25885), C(20754f456c203361),
- C(941f5023c0c943f9), C(dfdeb9564fd66f24), C(2140cec706b9d406),
- C(7b22429b131e9c72), C(941f5023c0c943f9), C(dfdeb9564fd66f24),
- C(2140cec706b9d406), C(7b22429b131e9c72), C(94215c22eb940f45),
- C(d28b9ed474f7249a), C(6f25e88f2fbf9f56), C(b6718f9e605b38ac),
C(81eaaad3)},
{C(930380a3741e862a), C(348d28638dc71658), C(89dedcfd1654ea0d),
- C(7e7f61684080106), C(837ace9794582976), C(5ac8ca76a357eb1b),
- C(32b58308625661fb), C(7e7f61684080106), C(837ace9794582976),
- C(5ac8ca76a357eb1b), C(32b58308625661fb), C(c09705c4572025d9),
- C(f9187f6af0291303), C(1c0edd8ee4b02538), C(e6cb105daa0578a), C(addbd3e3)},
+ C(addbd3e3)},
{C(94808b5d2aa25f9a), C(cec72968128195e0), C(d9f4da2bdc1e130f),
- C(272d8dd74f3006cc), C(ec6c2ad1ec03f554), C(4ad276b249a5d5dd),
- C(549a22a17c0cde12), C(272d8dd74f3006cc), C(ec6c2ad1ec03f554),
- C(4ad276b249a5d5dd), C(549a22a17c0cde12), C(602119cb824d7cde),
- C(f4d3cef240ef35fa), C(e889895e01911bc7), C(785a7e5ac20e852b),
C(e66dbca0)},
{C(b31abb08ae6e3d38), C(9eb9a95cbd9e8223), C(8019e79b7ee94ea9),
- C(7b2271a7a3248e22), C(3b4f700e5a0ba523), C(8ebc520c227206fe),
- C(da3f861490f5d291), C(7b2271a7a3248e22), C(3b4f700e5a0ba523),
- C(8ebc520c227206fe), C(da3f861490f5d291), C(d08a689f9f3aa60e),
- C(547c1b97a068661f), C(4b15a67fa29172f0), C(eaf40c085191d80f),
C(afe11fd5)},
{C(dccb5534a893ea1a), C(ce71c398708c6131), C(fe2396315457c164),
- C(3f1229f4d0fd96fb), C(33130aa5fa9d43f2), C(e42693d5b34e63ab),
- C(2f4ef2be67f62104), C(3f1229f4d0fd96fb), C(33130aa5fa9d43f2),
- C(e42693d5b34e63ab), C(2f4ef2be67f62104), C(372e5153516e37b9),
- C(af9ec142ab12cc86), C(777920c09345e359), C(e7c4a383bef8adc6),
C(a71a406f)},
{C(6369163565814de6), C(8feb86fb38d08c2f), C(4976933485cc9a20),
- C(7d3e82d5ba29a90d), C(d5983cc93a9d126a), C(37e9dfd950e7b692),
- C(80673be6a7888b87), C(7d3e82d5ba29a90d), C(d5983cc93a9d126a),
- C(37e9dfd950e7b692), C(80673be6a7888b87), C(57f732dc600808bc),
- C(59477199802cc78b), C(f824810eb8f2c2de), C(c4a3437f05b3b61c),
C(9d90eaf5)},
{C(edee4ff253d9f9b3), C(96ef76fb279ef0ad), C(a4d204d179db2460),
- C(1f3dcdfa513512d6), C(4dc7ec07283117e4), C(4438bae88ae28bf9),
- C(aa7eae72c9244a0d), C(1f3dcdfa513512d6), C(4dc7ec07283117e4),
- C(4438bae88ae28bf9), C(aa7eae72c9244a0d), C(b9aedc8d3ecc72df),
- C(b75a8eb090a77d62), C(6b15677f9cd91507), C(51d8282cb3a9ddbf),
C(6665db10)},
{C(941993df6e633214), C(929bc1beca5b72c6), C(141fc52b8d55572d),
- C(b3b782ad308f21ed), C(4f2676485041dee0), C(bfe279aed5cb4bc8),
- C(2a62508a467a22ff), C(b3b782ad308f21ed), C(4f2676485041dee0),
- C(bfe279aed5cb4bc8), C(2a62508a467a22ff), C(e74d29eab742385d),
- C(56b05cd90ecfc293), C(c603728ea73f8844), C(8638fcd21bc692c4),
C(9c977cbf)},
{C(859838293f64cd4c), C(484403b39d44ad79), C(bf674e64d64b9339),
- C(44d68afda9568f08), C(478568ed51ca1d65), C(679c204ad3d9e766),
- C(b28e788878488dc1), C(44d68afda9568f08), C(478568ed51ca1d65),
- C(679c204ad3d9e766), C(b28e788878488dc1), C(d001a84d3a84fae6),
- C(d376958fe4cb913e), C(17435277e36c86f0), C(23657b263c347aa6),
C(ee83ddd4)},
- {C(c19b5648e0d9f555), C(328e47b2b7562993), C(e756b92ba4bd6a51),
- C(c3314e362764ddb8), C(6481c084ee9ec6b5), C(ede23fb9a251771),
- C(bd617f2643324590), C(c3314e362764ddb8), C(6481c084ee9ec6b5),
- C(ede23fb9a251771), C(bd617f2643324590), C(d2d30c9b95e030f5),
- C(8a517312ffc5795e), C(8b1f325033bd535e), C(3ee6e867e03f2892), C(26519cc)},
+ {C(c19b5648e0d9f555), C(328e47b2b7562993), C(e756b92ba4bd6a51), C(26519cc)},
{C(f963b63b9006c248), C(9e9bf727ffaa00bc), C(c73bacc75b917e3a),
- C(2c6aa706129cc54c), C(17a706f59a49f086), C(c7c1eec455217145),
- C(6adfdc6e07602d42), C(2c6aa706129cc54c), C(17a706f59a49f086),
- C(c7c1eec455217145), C(6adfdc6e07602d42), C(fb75fca30d848dd2),
- C(5228c9ed14653ed4), C(953958910153b1a2), C(a430103a24f42a5d),
C(a485a53f)},
{C(6a8aa0852a8c1f3b), C(c8f1e5e206a21016), C(2aa554aed1ebb524),
- C(fc3e3c322cd5d89b), C(b7e3911dc2bd4ebb), C(fcd6da5e5fae833a),
- C(51ed3c41f87f9118), C(fc3e3c322cd5d89b), C(b7e3911dc2bd4ebb),
- C(fcd6da5e5fae833a), C(51ed3c41f87f9118), C(f31750cbc19c420a),
- C(186dab1abada1d86), C(ca7f88cb894b3cd7), C(2859eeb1c373790c),
C(f62bc412)},
{C(740428b4d45e5fb8), C(4c95a4ce922cb0a5), C(e99c3ba78feae796),
- C(914f1ea2fdcebf5c), C(9566453c07cd0601), C(9841bf66d0462cd),
- C(79140c1c18536aeb), C(914f1ea2fdcebf5c), C(9566453c07cd0601),
- C(9841bf66d0462cd), C(79140c1c18536aeb), C(a963b930b05820c2),
- C(6a7d9fa0c8c45153), C(64214c40d07cf39b), C(7057daf1d806c014),
C(8975a436)},
- {C(658b883b3a872b86), C(2f0e303f0f64827a), C(975337e23dc45e1),
- C(99468a917986162b), C(7b31434aac6e0af0), C(f6915c1562c7d82f),
- C(e4071d82a6dd71db), C(99468a917986162b), C(7b31434aac6e0af0),
- C(f6915c1562c7d82f), C(e4071d82a6dd71db), C(5f5331f077b5d996),
- C(7b314ba21b747a4f), C(5a73cb9521da17f5), C(12ed435fae286d86),
- C(94ff7f41)},
- {C(6df0a977da5d27d4), C(891dd0e7cb19508), C(fd65434a0b71e680),
- C(8799e4740e573c50), C(9e739b52d0f341e8), C(cdfd34ba7d7b03eb),
- C(5061812ce6c88499), C(8799e4740e573c50), C(9e739b52d0f341e8),
- C(cdfd34ba7d7b03eb), C(5061812ce6c88499), C(612b8d8f2411dc5c),
- C(878bd883d29c7787), C(47a846727182bb), C(ec4949508c8b3b9a), C(760aa031)},
- {C(a900275464ae07ef), C(11f2cfda34beb4a3), C(9abf91e5a1c38e4),
- C(8063d80ab26f3d6d), C(4177b4b9b4f0393f), C(6de42ba8672b9640),
- C(d0bccdb72c51c18), C(8063d80ab26f3d6d), C(4177b4b9b4f0393f),
- C(6de42ba8672b9640), C(d0bccdb72c51c18), C(af3f611b7f22cf12),
- C(3863c41492645755), C(928c7a616a8f14f9), C(a82c78eb2eadc58b),
- C(3bda76df)},
+ {C(658b883b3a872b86), C(2f0e303f0f64827a), C(975337e23dc45e1), C(94ff7f41)},
+ {C(6df0a977da5d27d4), C(891dd0e7cb19508), C(fd65434a0b71e680), C(760aa031)},
+ {C(a900275464ae07ef), C(11f2cfda34beb4a3), C(9abf91e5a1c38e4), C(3bda76df)},
{C(810bc8aa0c40bcb0), C(448a019568d01441), C(f60ec52f60d3aeae),
- C(52c44837aa6dfc77), C(15d8d8fccdd6dc5b), C(345b793ccfa93055),
- C(932160fe802ca975), C(52c44837aa6dfc77), C(15d8d8fccdd6dc5b),
- C(345b793ccfa93055), C(932160fe802ca975), C(a624b0dd93fc18cd),
- C(d955b254c2037f1e), C(e540533d370a664c), C(2ba4ec12514e9d7), C(498e2e65)},
+ C(498e2e65)},
{C(22036327deb59ed7), C(adc05ceb97026a02), C(48bff0654262672b),
- C(c791b313aba3f258), C(443c7757a4727bee), C(e30e4b2372171bdf),
- C(f3db986c4156f3cb), C(c791b313aba3f258), C(443c7757a4727bee),
- C(e30e4b2372171bdf), C(f3db986c4156f3cb), C(a939aefab97c6e15),
- C(dbeb8acf1d5b0e6c), C(1e0eab667a795bba), C(80dd539902df4d50),
C(d38deb48)},
{C(7d14dfa9772b00c8), C(595735efc7eeaed7), C(29872854f94c3507),
- C(bc241579d8348401), C(16dc832804d728f0), C(e9cc71ae64e3f09e),
- C(bef634bc978bac31), C(bc241579d8348401), C(16dc832804d728f0),
- C(e9cc71ae64e3f09e), C(bef634bc978bac31), C(7f64b1fa2a9129e),
- C(71d831bd530ac7f3), C(c7ad0a8a6d5be6f1), C(82a7d3a815c7aaab),
C(82b3fb6b)},
{C(2d777cddb912675d), C(278d7b10722a13f9), C(f5c02bfb7cc078af),
- C(4283001239888836), C(f44ca39a6f79db89), C(ed186122d71bcc9f),
- C(8620017ab5f3ba3b), C(4283001239888836), C(f44ca39a6f79db89),
- C(ed186122d71bcc9f), C(8620017ab5f3ba3b), C(e787472187f176c),
- C(267e64c4728cf181), C(f1ba4b3007c15e30), C(8e3a75d5b02ecfc0),
C(e500e25f)},
{C(f2ec98824e8aa613), C(5eb7e3fb53fe3bed), C(12c22860466e1dd4),
- C(374dd4288e0b72e5), C(ff8916db706c0df4), C(cb1a9e85de5e4b8d),
- C(d4d12afb67a27659), C(374dd4288e0b72e5), C(ff8916db706c0df4),
- C(cb1a9e85de5e4b8d), C(d4d12afb67a27659), C(feb69095d1ba175a),
- C(e2003aab23a47fad), C(8163a3ecab894b49), C(46d356674ce041f6),
C(bd2bb07c)},
{C(5e763988e21f487f), C(24189de8065d8dc5), C(d1519d2403b62aa0),
- C(9136456740119815), C(4d8ff7733b27eb83), C(ea3040bc0c717ef8),
- C(7617ab400dfadbc), C(9136456740119815), C(4d8ff7733b27eb83),
- C(ea3040bc0c717ef8), C(7617ab400dfadbc), C(fb336770c10b17a1),
- C(6123b68b5b31f151), C(1e147d5f295eccf2), C(9ecbb1333556f977),
C(3a2b431d)},
{C(48949dc327bb96ad), C(e1fd21636c5c50b4), C(3f6eb7f13a8712b4),
- C(14cf7f02dab0eee8), C(6d01750605e89445), C(4f1cf4006e613b78),
- C(57c40c4db32bec3b), C(14cf7f02dab0eee8), C(6d01750605e89445),
- C(4f1cf4006e613b78), C(57c40c4db32bec3b), C(1fde5a347f4a326e),
- C(cb5a54308adb0e3f), C(14994b2ba447a23c), C(7067d0abb4257b68),
C(7322a83d)},
{C(b7c4209fb24a85c5), C(b35feb319c79ce10), C(f0d3de191833b922),
- C(570d62758ddf6397), C(5e0204fb68a7b800), C(4383a9236f8b5a2b),
- C(7bc1a64641d803a4), C(570d62758ddf6397), C(5e0204fb68a7b800),
- C(4383a9236f8b5a2b), C(7bc1a64641d803a4), C(5434d61285099f7a),
- C(d49449aacdd5dd67), C(97855ba0e9a7d75d), C(da67328062f3a62f),
C(a645ca1c)},
{C(9c9e5be0943d4b05), C(b73dc69e45201cbb), C(aab17180bfe5083d),
- C(c738a77a9a55f0e2), C(705221addedd81df), C(fd9bd8d397abcfa3),
- C(8ccf0004aa86b795), C(c738a77a9a55f0e2), C(705221addedd81df),
- C(fd9bd8d397abcfa3), C(8ccf0004aa86b795), C(2bb5db2280068206),
- C(8c22d29f307a01d), C(274a22de02f473c8), C(b8791870f4268182), C(8909a45a)},
+ C(8909a45a)},
{C(3898bca4dfd6638d), C(f911ff35efef0167), C(24bdf69e5091fc88),
- C(9b82567ab6560796), C(891b69462b41c224), C(8eccc7e4f3af3b51),
- C(381e54c3c8f1c7d0), C(9b82567ab6560796), C(891b69462b41c224),
- C(8eccc7e4f3af3b51), C(381e54c3c8f1c7d0), C(c80fbc489a558a55),
- C(1ba88e062a663af7), C(af7b1ef1c0116303), C(bd20e1a5a6b1a0cd),
C(bd30074c)},
- {C(5b5d2557400e68e7), C(98d610033574cee), C(dfd08772ce385deb),
- C(3c13e894365dc6c2), C(26fc7bbcda3f0ef), C(dbb71106cdbfea36),
- C(785239a742c6d26d), C(3c13e894365dc6c2), C(26fc7bbcda3f0ef),
- C(dbb71106cdbfea36), C(785239a742c6d26d), C(f810c415ae05b2f4),
- C(bb9b9e7398526088), C(70128f1bf830a32b), C(bcc73f82b6410899),
- C(c17cf001)},
+ {C(5b5d2557400e68e7), C(98d610033574cee), C(dfd08772ce385deb), C(c17cf001)},
{C(a927ed8b2bf09bb6), C(606e52f10ae94eca), C(71c2203feb35a9ee),
- C(6e65ec14a8fb565), C(34bff6f2ee5a7f79), C(2e329a5be2c011b),
- C(73161c93331b14f9), C(6e65ec14a8fb565), C(34bff6f2ee5a7f79),
- C(2e329a5be2c011b), C(73161c93331b14f9), C(15d13f2408aecf88),
- C(9f5b61b8a4b55b31), C(8fe25a43b296dba6), C(bdad03b7300f284e),
C(26ffd25a)},
{C(8d25746414aedf28), C(34b1629d28b33d3a), C(4d5394aea5f82d7b),
- C(379f76458a3c8957), C(79dd080f9843af77), C(c46f0a7847f60c1d),
- C(af1579c5797703cc), C(379f76458a3c8957), C(79dd080f9843af77),
- C(c46f0a7847f60c1d), C(af1579c5797703cc), C(8b7d31f338755c14),
- C(2eff97679512aaa8), C(df07d68e075179ed), C(c8fa6c7a729e7f1f),
C(f1d8ce3c)},
{C(b5bbdb73458712f2), C(1ff887b3c2a35137), C(7f7231f702d0ace9),
- C(1e6f0910c3d25bd8), C(ad9e250862102467), C(1c842a07abab30cd),
- C(cd8124176bac01ac), C(1e6f0910c3d25bd8), C(ad9e250862102467),
- C(1c842a07abab30cd), C(cd8124176bac01ac), C(ea6ebe7a79b67edc),
- C(73f598ac9db26713), C(4f4e72d7460b8fc), C(365dc4b9fdf13f21), C(3ee8fb17)},
+ C(3ee8fb17)},
{C(3d32a26e3ab9d254), C(fc4070574dc30d3a), C(f02629579c2b27c9),
- C(b1cf09b0184a4834), C(5c03db48eb6cc159), C(f18c7fcf34d1df47),
- C(dfb043419ecf1fa9), C(b1cf09b0184a4834), C(5c03db48eb6cc159),
- C(f18c7fcf34d1df47), C(dfb043419ecf1fa9), C(dcd78d13f9ca658f),
- C(4355d408ffe8e49f), C(81eefee908b593b4), C(590c213c20e981a3),
C(a77acc2a)},
- {C(9371d3c35fa5e9a5), C(42967cf4d01f30), C(652d1eeae704145c),
- C(ceaf1a0d15234f15), C(1450a54e45ba9b9), C(65e9c1fd885aa932),
- C(354d4bc034ba8cbe), C(ceaf1a0d15234f15), C(1450a54e45ba9b9),
- C(65e9c1fd885aa932), C(354d4bc034ba8cbe), C(8fd4ff484c08fb4b),
- C(bf46749866f69ba0), C(cf1c21ede82c9477), C(4217548c43da109), C(f4556dee)},
- {C(cbaa3cb8f64f54e0), C(76c3b48ee5c08417), C(9f7d24e87e61ce9),
- C(85b8e53f22e19507), C(bb57137739ca486b), C(c77f131cca38f761),
- C(c56ac3cf275be121), C(85b8e53f22e19507), C(bb57137739ca486b),
- C(c77f131cca38f761), C(c56ac3cf275be121), C(9ec1a6c9109d2685),
- C(3dad0922e76afdb0), C(fd58cbf952958103), C(7b04c908e78639a1),
- C(de287a64)},
+ {C(9371d3c35fa5e9a5), C(42967cf4d01f30), C(652d1eeae704145c), C(f4556dee)},
+ {C(cbaa3cb8f64f54e0), C(76c3b48ee5c08417), C(9f7d24e87e61ce9), C(de287a64)},
{C(b2e23e8116c2ba9f), C(7e4d9c0060101151), C(3310da5e5028f367),
- C(adc52dddb76f6e5e), C(4aad4e925a962b68), C(204b79b7f7168e64),
- C(df29ed6671c36952), C(adc52dddb76f6e5e), C(4aad4e925a962b68),
- C(204b79b7f7168e64), C(df29ed6671c36952), C(e02927cac396d210),
- C(5d500e71742b638a), C(5c9998af7f27b124), C(3fba9a2573dc2f7), C(878e55b9)},
- {C(8aa77f52d7868eb9), C(4d55bd587584e6e2), C(d2db37041f495f5),
- C(ce030d15b5fe2f4), C(86b4a7a0780c2431), C(ee070a9ae5b51db7),
- C(edc293d9595be5d8), C(ce030d15b5fe2f4), C(86b4a7a0780c2431),
- C(ee070a9ae5b51db7), C(edc293d9595be5d8), C(3dfc5ec108260a2b),
- C(8afe28c7123bf4e2), C(da82ef38023a7a5f), C(3e1f77b0174b77c3), C(7648486)},
+ C(878e55b9)},
+ {C(8aa77f52d7868eb9), C(4d55bd587584e6e2), C(d2db37041f495f5), C(7648486)},
{C(858fea922c7fe0c3), C(cfe8326bf733bc6f), C(4e5e2018cf8f7dfc),
- C(64fd1bc011e5bab7), C(5c9e858728015568), C(97ac42c2b00b29b1),
- C(7f89caf08c109aee), C(64fd1bc011e5bab7), C(5c9e858728015568),
- C(97ac42c2b00b29b1), C(7f89caf08c109aee), C(9a8af34fd0e9dacf),
- C(bbc54161aa1507e0), C(7cda723ccbbfe5ee), C(2c289d839fb93f58),
C(57ac0fb1)},
{C(46ef25fdec8392b1), C(e48d7b6d42a5cd35), C(56a6fe1c175299ca),
- C(fdfa836b41dcef62), C(2f8db8030e847e1b), C(5ba0a49ac4f9b0f8),
- C(dae897ed3e3fce44), C(fdfa836b41dcef62), C(2f8db8030e847e1b),
- C(5ba0a49ac4f9b0f8), C(dae897ed3e3fce44), C(9c432e31aef626e7),
- C(9a36e1c6cd6e3dd), C(5095a167c34d19d), C(a70005cfa6babbea), C(d01967ca)},
+ C(d01967ca)},
{C(8d078f726b2df464), C(b50ee71cdcabb299), C(f4af300106f9c7ba),
- C(7d222caae025158a), C(cc028d5fd40241b9), C(dd42515b639e6f97),
- C(e08e86531a58f87f), C(7d222caae025158a), C(cc028d5fd40241b9),
- C(dd42515b639e6f97), C(e08e86531a58f87f), C(d93612c835b37d7b),
- C(91dd61729b2fa7f4), C(ba765a1bdda09db7), C(55258b451b2b1297),
C(96ecdf74)},
{C(35ea86e6960ca950), C(34fe1fe234fc5c76), C(a00207a3dc2a72b7),
- C(80395e48739e1a67), C(74a67d8f7f43c3d7), C(dd2bdd1d62246c6e),
- C(a1f44298ba80acf6), C(80395e48739e1a67), C(74a67d8f7f43c3d7),
- C(dd2bdd1d62246c6e), C(a1f44298ba80acf6), C(ad86d86c187bf38),
- C(26feea1f2eee240d), C(ed7f1fd066b23897), C(a768cf1e0fbb502), C(779f5506)},
+ C(779f5506)},
{C(8aee9edbc15dd011), C(51f5839dc8462695), C(b2213e17c37dca2d),
- C(133b299a939745c5), C(796e2aac053f52b3), C(e8d9fe1521a4a222),
- C(819a8863e5d1c290), C(133b299a939745c5), C(796e2aac053f52b3),
- C(e8d9fe1521a4a222), C(819a8863e5d1c290), C(c0737f0fe34d36ad),
- C(e6d6d4a267a5cc31), C(98300a7911674c23), C(bef189661c257098),
C(3c94c2de)},
{C(c3e142ba98432dda), C(911d060cab126188), C(b753fbfa8365b844),
- C(fd1a9ba5e71b08a2), C(7ac0dc2ed7778533), C(b543161ff177188a),
- C(492fc08a6186f3f4), C(fd1a9ba5e71b08a2), C(7ac0dc2ed7778533),
- C(b543161ff177188a), C(492fc08a6186f3f4), C(fc4745f516afd3b6),
- C(88c30370a53080e), C(65a1bb34abc465e2), C(abbd14662911c8b3), C(39f98faf)},
+ C(39f98faf)},
{C(123ba6b99c8cd8db), C(448e582672ee07c4), C(cebe379292db9e65),
- C(938f5bbab544d3d6), C(d2a95f9f2d376d73), C(68b2f16149e81aa3),
- C(ad7e32f82d86c79d), C(938f5bbab544d3d6), C(d2a95f9f2d376d73),
- C(68b2f16149e81aa3), C(ad7e32f82d86c79d), C(4574015ae8626ce2),
- C(455aa6137386a582), C(658ad2542e8ec20), C(e31d7be2ca35d00), C(7af31199)},
+ C(7af31199)},
{C(ba87acef79d14f53), C(b3e0fcae63a11558), C(d5ac313a593a9f45),
- C(eea5f5a9f74af591), C(578710bcc36fbea2), C(7a8393432188931d),
- C(705cfc5ec7cc172), C(eea5f5a9f74af591), C(578710bcc36fbea2),
- C(7a8393432188931d), C(705cfc5ec7cc172), C(da85ebe5fc427976),
- C(bfa5c7a454df54c8), C(4632b72a81bf66d2), C(5dd72877db539ee2),
C(e341a9d6)},
- {C(bcd3957d5717dc3), C(2da746741b03a007), C(873816f4b1ece472),
- C(2b826f1a2c08c289), C(da50f56863b55e74), C(b18712f6b3eed83b),
- C(bdc7cc05ab4c685f), C(2b826f1a2c08c289), C(da50f56863b55e74),
- C(b18712f6b3eed83b), C(bdc7cc05ab4c685f), C(9e45fb833d1b0af),
- C(d7213081db29d82e), C(d2a6b6c6a09ed55e), C(98a7686cba323ca9),
- C(ca24aeeb)},
+ {C(bcd3957d5717dc3), C(2da746741b03a007), C(873816f4b1ece472), C(ca24aeeb)},
{C(61442ff55609168e), C(6447c5fc76e8c9cf), C(6a846de83ae15728),
- C(effc2663cffc777f), C(93214f8f463afbed), C(a156ef06066f4e4e),
- C(a407b6ed8769d51e), C(effc2663cffc777f), C(93214f8f463afbed),
- C(a156ef06066f4e4e), C(a407b6ed8769d51e), C(bb2f9ed29745c02a),
- C(981eecd435b36ad9), C(461a5a05fb9cdff4), C(bd6cb2a87b9f910c),
C(b2252b57)},
- {C(dbe4b1b2d174757f), C(506512da18712656), C(6857f3e0b8dd95f),
- C(5a4fc2728a9bb671), C(ebb971522ec38759), C(1a5a093e6cf1f72b),
- C(729b057fe784f504), C(5a4fc2728a9bb671), C(ebb971522ec38759),
- C(1a5a093e6cf1f72b), C(729b057fe784f504), C(71fcbf42a767f9cf),
- C(114cfe772da6cdd), C(60cdf9cb629d9d7a), C(e270d10ad088b24e), C(72c81da1)},
+ {C(dbe4b1b2d174757f), C(506512da18712656), C(6857f3e0b8dd95f), C(72c81da1)},
{C(531e8e77b363161c), C(eece0b43e2dae030), C(8294b82c78f34ed1),
- C(e777b1fd580582f2), C(7b880f58da112699), C(562c6b189a6333f4),
- C(139d64f88a611d4), C(e777b1fd580582f2), C(7b880f58da112699),
- C(562c6b189a6333f4), C(139d64f88a611d4), C(53d8ef17eda64fa4),
- C(bf3eded14dc60a04), C(2b5c559cf5ec07c5), C(8895f7339d03a48a),
C(6b9fce95)},
{C(f71e9c926d711e2b), C(d77af2853a4ceaa1), C(9aa0d6d76a36fae7),
- C(dd16cd0fbc08393), C(29a414a5d8c58962), C(72793d8d1022b5b2),
- C(2e8e69cf7cbffdf0), C(dd16cd0fbc08393), C(29a414a5d8c58962),
- C(72793d8d1022b5b2), C(2e8e69cf7cbffdf0), C(3721c0473aa99c9a),
- C(1cff4ed9c31cd91c), C(4990735033cc482b), C(7fdf8c701c72f577),
C(19399857)},
{C(cb20ac28f52df368), C(e6705ee7880996de), C(9b665cc3ec6972f2),
- C(4260e8c254e9924b), C(f197a6eb4591572d), C(8e867ff0fb7ab27c),
- C(f95502fb503efaf3), C(4260e8c254e9924b), C(f197a6eb4591572d),
- C(8e867ff0fb7ab27c), C(f95502fb503efaf3), C(30c41876b08e3e22),
- C(958e2419e3cd22f4), C(f0f3aa1fe119a107), C(481662310a379100),
C(3c57a994)},
{C(e4a794b4acb94b55), C(89795358057b661b), C(9c4cdcec176d7a70),
- C(4890a83ee435bc8b), C(d8c1c00fceb00914), C(9e7111ba234f900f),
- C(eb8dbab364d8b604), C(4890a83ee435bc8b), C(d8c1c00fceb00914),
- C(9e7111ba234f900f), C(eb8dbab364d8b604), C(b3261452963eebb),
- C(6cf94b02792c4f95), C(d88fa815ef1e8fc), C(2d687af66604c73), C(c053e729)},
+ C(c053e729)},
{C(cb942e91443e7208), C(e335de8125567c2a), C(d4d74d268b86df1f),
- C(8ba0fdd2ffc8b239), C(f413b366c1ffe02f), C(c05b2717c59a8a28),
- C(981188eab4fcc8fb), C(8ba0fdd2ffc8b239), C(f413b366c1ffe02f),
- C(c05b2717c59a8a28), C(981188eab4fcc8fb), C(e563f49a1d9072ba),
- C(3c6a3aa4a26367dc), C(ba0db13448653f34), C(31065d756074d7d6),
C(51cbbba7)},
{C(ecca7563c203f7ba), C(177ae2423ef34bb2), C(f60b7243400c5731),
- C(cf1edbfe7330e94e), C(881945906bcb3cc6), C(4acf0293244855da),
- C(65ae042c1c2a28c2), C(cf1edbfe7330e94e), C(881945906bcb3cc6),
- C(4acf0293244855da), C(65ae042c1c2a28c2), C(b25fa0a1cab33559),
- C(d98e8daa28124131), C(fce17f50b9c351b3), C(3f995ccf7386864b),
C(1acde79a)},
{C(1652cb940177c8b5), C(8c4fe7d85d2a6d6d), C(f6216ad097e54e72),
- C(f6521b912b368ae6), C(a9fe4eff81d03e73), C(d6f623629f80d1a3),
- C(2b9604f32cb7dc34), C(f6521b912b368ae6), C(a9fe4eff81d03e73),
- C(d6f623629f80d1a3), C(2b9604f32cb7dc34), C(2a43d84dcf59c7e2),
- C(d0a197c70c5dae0b), C(6e84d4bbc71d76a0), C(c7e94620378c6cb2),
C(2d160d13)},
{C(31fed0fc04c13ce8), C(3d5d03dbf7ff240a), C(727c5c9b51581203),
- C(6b5ffc1f54fecb29), C(a8e8e7ad5b9a21d9), C(c4d5a32cd6aac22d),
- C(d7e274ad22d4a79a), C(6b5ffc1f54fecb29), C(a8e8e7ad5b9a21d9),
- C(c4d5a32cd6aac22d), C(d7e274ad22d4a79a), C(368841ea5731a112),
- C(feaf7bc2e73ca48f), C(636fb272e9ea1f6), C(5d9cb7580c3f6207), C(787f5801)},
+ C(787f5801)},
{C(e7b668947590b9b3), C(baa41ad32938d3fa), C(abcbc8d4ca4b39e4),
- C(381ee1b7ea534f4e), C(da3759828e3de429), C(3e015d76729f9955),
- C(cbbec51a6485fbde), C(381ee1b7ea534f4e), C(da3759828e3de429),
- C(3e015d76729f9955), C(cbbec51a6485fbde), C(9b86605281f20727),
- C(fc6fcf508676982a), C(3b135f7a813a1040), C(d3a4706bea1db9c9),
C(c9629828)},
{C(1de2119923e8ef3c), C(6ab27c096cf2fe14), C(8c3658edca958891),
- C(4cc8ed3ada5f0f2), C(4a496b77c1f1c04e), C(9085b0a862084201),
- C(a1894bde9e3dee21), C(4cc8ed3ada5f0f2), C(4a496b77c1f1c04e),
- C(9085b0a862084201), C(a1894bde9e3dee21), C(367fb472dc5b277d),
- C(7d39ccca16fc6745), C(763f988d70db9106), C(a8b66f7fecb70f02),
C(be139231)},
{C(1269df1e69e14fa7), C(992f9d58ac5041b7), C(e97fcf695a7cbbb4),
- C(e5d0549802d15008), C(424c134ecd0db834), C(6fc44fd91be15c6c),
- C(a1a5ef95d50e537d), C(e5d0549802d15008), C(424c134ecd0db834),
- C(6fc44fd91be15c6c), C(a1a5ef95d50e537d), C(d1e3daf5d05f5308),
- C(4c7f81600eaa1327), C(109d1b8d1f9d0d2b), C(871e8699e0aeb862),
C(7df699ef)},
{C(820826d7aba567ff), C(1f73d28e036a52f3), C(41c4c5a73f3b0893),
- C(aa0d74d4a98db89b), C(36fd486d07c56e1d), C(d0ad23cbb6660d8a),
- C(1264a84665b35e19), C(aa0d74d4a98db89b), C(36fd486d07c56e1d),
- C(d0ad23cbb6660d8a), C(1264a84665b35e19), C(789682bf7d781b33),
- C(6bfa6abd2fb5722d), C(6779cb3623d33900), C(435ca5214e1ee5f0),
C(8ce6b96d)},
{C(ffe0547e4923cef9), C(3534ed49b9da5b02), C(548a273700fba03d),
- C(28ac84ca70958f7e), C(d8ae575a68faa731), C(2aaaee9b9dcffd4c),
- C(6c7faab5c285c6da), C(28ac84ca70958f7e), C(d8ae575a68faa731),
- C(2aaaee9b9dcffd4c), C(6c7faab5c285c6da), C(45d94235f99ba78f),
- C(ab5ea16f39497f5b), C(fb4d6c86fccbdca3), C(8104e6310a5fd2c7),
C(6f9ed99c)},
{C(72da8d1b11d8bc8b), C(ba94b56b91b681c6), C(4e8cc51bd9b0fc8c),
- C(43505ed133be672a), C(e8f2f9d973c2774e), C(677b9b9c7cad6d97),
- C(4e1f5d56ef17b906), C(43505ed133be672a), C(e8f2f9d973c2774e),
- C(677b9b9c7cad6d97), C(4e1f5d56ef17b906), C(eea3a6038f983767),
- C(87109f077f86db01), C(ecc1ca41f74d61cc), C(34a87e86e83bed17),
C(e0244796)},
- {C(d62ab4e3f88fc797), C(ea86c7aeb6283ae4), C(b5b93e09a7fe465),
- C(4344a1a0134afe2), C(ff5c17f02b62341d), C(3214c6a587ce4644),
- C(a905e7ed0629d05c), C(4344a1a0134afe2), C(ff5c17f02b62341d),
- C(3214c6a587ce4644), C(a905e7ed0629d05c), C(b5c72690cd716e82),
- C(7c6097649e6ebe7b), C(7ceee8c6e56a4dcd), C(80ca849dc53eb9e4),
- C(4ccf7e75)},
+ {C(d62ab4e3f88fc797), C(ea86c7aeb6283ae4), C(b5b93e09a7fe465), C(4ccf7e75)},
{C(d0f06c28c7b36823), C(1008cb0874de4bb8), C(d6c7ff816c7a737b),
- C(489b697fe30aa65f), C(4da0fb621fdc7817), C(dc43583b82c58107),
- C(4b0261debdec3cd6), C(489b697fe30aa65f), C(4da0fb621fdc7817),
- C(dc43583b82c58107), C(4b0261debdec3cd6), C(a9748d7b6c0e016c),
- C(7e8828f7ba4b034b), C(da0fa54348a2512a), C(ebf9745c0962f9ad),
C(915cef86)},
{C(99b7042460d72ec6), C(2a53e5e2b8e795c2), C(53a78132d9e1b3e3),
- C(c043e67e6fc64118), C(ff0abfe926d844d3), C(f2a9fe5db2e910fe),
- C(ce352cdc84a964dd), C(c043e67e6fc64118), C(ff0abfe926d844d3),
- C(f2a9fe5db2e910fe), C(ce352cdc84a964dd), C(b89bc028aa5e6063),
- C(a354e7fdac04459c), C(68d6547e6e980189), C(c968dddfd573773e),
C(5cb59482)},
- {C(4f4dfcfc0ec2bae5), C(841233148268a1b8), C(9248a76ab8be0d3),
- C(334c5a25b5903a8c), C(4c94fef443122128), C(743e7d8454655c40),
- C(1ab1e6d1452ae2cd), C(334c5a25b5903a8c), C(4c94fef443122128),
- C(743e7d8454655c40), C(1ab1e6d1452ae2cd), C(fec766de4a8e476c),
- C(cc0929da9567e71b), C(5f9ef5b5f150c35a), C(87659cabd649768f),
- C(6ca3f532)},
+ {C(4f4dfcfc0ec2bae5), C(841233148268a1b8), C(9248a76ab8be0d3), C(6ca3f532)},
{C(fe86bf9d4422b9ae), C(ebce89c90641ef9c), C(1c84e2292c0b5659),
- C(8bde625a10a8c50d), C(eb8271ded1f79a0b), C(14dc6844f0de7a3c),
- C(f85b2f9541e7e6da), C(8bde625a10a8c50d), C(eb8271ded1f79a0b),
- C(14dc6844f0de7a3c), C(f85b2f9541e7e6da), C(2fe22cfd1683b961),
- C(ea1d75c5b7aa01ca), C(9eef60a44876bb95), C(950c818e505c6f7f),
C(e24f3859)},
{C(a90d81060932dbb0), C(8acfaa88c5fbe92b), C(7c6f3447e90f7f3f),
- C(dd52fc14c8dd3143), C(1bc7508516e40628), C(3059730266ade626),
- C(ffa526822f391c2), C(dd52fc14c8dd3143), C(1bc7508516e40628),
- C(3059730266ade626), C(ffa526822f391c2), C(e25232d7afc8a406),
- C(d2b8a5a3f3b5f670), C(6630f33edb7dfe32), C(c71250ba68c4ea86),
C(adf5a9c7)},
{C(17938a1b0e7f5952), C(22cadd2f56f8a4be), C(84b0d1183d5ed7c1),
- C(c1336b92fef91bf6), C(80332a3945f33fa9), C(a0f68b86f726ff92),
- C(a3db5282cf5f4c0b), C(c1336b92fef91bf6), C(80332a3945f33fa9),
- C(a0f68b86f726ff92), C(a3db5282cf5f4c0b), C(82640b6fc4916607),
- C(2dc2a3aa1a894175), C(8b4c852bdee7cc9), C(10b9d0a08b55ff83), C(32264b75)},
+ C(32264b75)},
{C(de9e0cb0e16f6e6d), C(238e6283aa4f6594), C(4fb9c914c2f0a13b),
- C(497cb912b670f3b), C(d963a3f02ff4a5b6), C(4fccefae11b50391),
- C(42ba47db3f7672f), C(497cb912b670f3b), C(d963a3f02ff4a5b6),
- C(4fccefae11b50391), C(42ba47db3f7672f), C(1d6b655a1889feef),
- C(5f319abf8fafa19f), C(715c2e49deb14620), C(8d9153082ecdcea4),
C(a64b3376)},
- {C(6d4b876d9b146d1a), C(aab2d64ce8f26739), C(d315f93600e83fe5),
- C(2fe9fabdbe7fdd4), C(755db249a2d81a69), C(f27929f360446d71),
- C(79a1bf957c0c1b92), C(2fe9fabdbe7fdd4), C(755db249a2d81a69),
- C(f27929f360446d71), C(79a1bf957c0c1b92), C(3c8a28d4c936c9cd),
- C(df0d3d13b2c6a902), C(c76702dd97cd2edd), C(1aa220f7be16517), C(d33890e)},
+ {C(6d4b876d9b146d1a), C(aab2d64ce8f26739), C(d315f93600e83fe5), C(d33890e)},
{C(e698fa3f54e6ea22), C(bd28e20e7455358c), C(9ace161f6ea76e66),
- C(d53fb7e3c93a9e4), C(737ae71b051bf108), C(7ac71feb84c2df42),
- C(3d8075cd293a15b4), C(d53fb7e3c93a9e4), C(737ae71b051bf108),
- C(7ac71feb84c2df42), C(3d8075cd293a15b4), C(bf8cee5e095d8a7c),
- C(e7086b3c7608143a), C(e55b0c2fa938d70c), C(fffb5f58e643649c),
C(926d4b63)},
{C(7bc0deed4fb349f7), C(1771aff25dc722fa), C(19ff0644d9681917),
- C(cf7d7f25bd70cd2c), C(9464ed9baeb41b4f), C(b9064f5c3cb11b71),
- C(237e39229b012b20), C(cf7d7f25bd70cd2c), C(9464ed9baeb41b4f),
- C(b9064f5c3cb11b71), C(237e39229b012b20), C(dd54d3f5d982dffe),
- C(7fc7562dbfc81dbf), C(5b0dd1924f70945), C(f1760537d8261135), C(d51ba539)},
+ C(d51ba539)},
{C(db4b15e88533f622), C(256d6d2419b41ce9), C(9d7c5378396765d5),
- C(9040e5b936b8661b), C(276e08fa53ac27fd), C(8c944d39c2bdd2cc),
- C(e2514c9802a5743c), C(9040e5b936b8661b), C(276e08fa53ac27fd),
- C(8c944d39c2bdd2cc), C(e2514c9802a5743c), C(e82107b11ac90386),
- C(7d6a22bc35055e6), C(fd6ea9d1c438d8ae), C(be6015149e981553), C(7f37636d)},
+ C(7f37636d)},
{C(922834735e86ecb2), C(363382685b88328e), C(e9c92960d7144630),
- C(8431b1bfd0a2379c), C(90383913aea283f9), C(a6163831eb4924d2),
- C(5f3921b4f9084aee), C(8431b1bfd0a2379c), C(90383913aea283f9),
- C(a6163831eb4924d2), C(5f3921b4f9084aee), C(7a70061a1473e579),
- C(5b19d80dcd2c6331), C(6196b97931faad27), C(869bf6828e237c3f),
C(b98026c0)},
{C(30f1d72c812f1eb8), C(b567cd4a69cd8989), C(820b6c992a51f0bc),
- C(c54677a80367125e), C(3204fbdba462e606), C(8563278afc9eae69),
- C(262147dd4bf7e566), C(c54677a80367125e), C(3204fbdba462e606),
- C(8563278afc9eae69), C(262147dd4bf7e566), C(2178b63e7ee2d230),
- C(e9c61ad81f5bff26), C(9af7a81b3c501eca), C(44104a3859f0238f),
C(b877767e)},
- {C(168884267f3817e9), C(5b376e050f637645), C(1c18314abd34497a),
- C(9598f6ab0683fcc2), C(1c805abf7b80e1ee), C(dec9ac42ee0d0f32),
- C(8cd72e3912d24663), C(9598f6ab0683fcc2), C(1c805abf7b80e1ee),
- C(dec9ac42ee0d0f32), C(8cd72e3912d24663), C(1f025d405f1c1d87),
- C(bf7b6221e1668f8f), C(52316f64e692dbb0), C(7bf43df61ec51b39), C(aefae77)},
- {C(82e78596ee3e56a7), C(25697d9c87f30d98), C(7600a8342834924d),
- C(6ba372f4b7ab268b), C(8c3237cf1fe243df), C(3833fc51012903df),
- C(8e31310108c5683f), C(6ba372f4b7ab268b), C(8c3237cf1fe243df),
- C(3833fc51012903df), C(8e31310108c5683f), C(126593715c2de429),
- C(48ca8f35a3f54b90), C(b9322b632f4f8b0), C(926bb169b7337693), C(f686911)},
+ {C(168884267f3817e9), C(5b376e050f637645), C(1c18314abd34497a), C(aefae77)},
+ {C(82e78596ee3e56a7), C(25697d9c87f30d98), C(7600a8342834924d), C(f686911)},
{C(aa2d6cf22e3cc252), C(9b4dec4f5e179f16), C(76fb0fba1d99a99a),
- C(9a62af3dbba140da), C(27857ea044e9dfc1), C(33abce9da2272647),
- C(b22a7993aaf32556), C(9a62af3dbba140da), C(27857ea044e9dfc1),
- C(33abce9da2272647), C(b22a7993aaf32556), C(bf8f88f8019bedf0),
- C(ed2d7f01fb273905), C(6b45f15901b481cd), C(f88ebb413ba6a8d5),
C(3deadf12)},
{C(7bf5ffd7f69385c7), C(fc077b1d8bc82879), C(9c04e36f9ed83a24),
- C(82065c62e6582188), C(8ef787fd356f5e43), C(2922e53e36e17dfa),
- C(9805f223d385010b), C(82065c62e6582188), C(8ef787fd356f5e43),
- C(2922e53e36e17dfa), C(9805f223d385010b), C(692154f3491b787d),
- C(e7e64700e414fbf), C(757d4d4ab65069a0), C(cd029446a8e348e2), C(ccf02a4e)},
+ C(ccf02a4e)},
{C(e89c8ff9f9c6e34b), C(f54c0f669a49f6c4), C(fc3e46f5d846adef),
- C(22f2aa3df2221cc), C(f66fea90f5d62174), C(b75defaeaa1dd2a7),
- C(9b994cd9a7214fd5), C(22f2aa3df2221cc), C(f66fea90f5d62174),
- C(b75defaeaa1dd2a7), C(9b994cd9a7214fd5), C(fac675a31804b773),
- C(98bcb3b820c50fc6), C(e14af64d28cf0885), C(27466fbd2b360eb5),
C(176c1722)},
- {C(a18fbcdccd11e1f4), C(8248216751dfd65e), C(40c089f208d89d7c),
- C(229b79ab69ae97d), C(a87aabc2ec26e582), C(be2b053721eb26d2),
- C(10febd7f0c3d6fcb), C(229b79ab69ae97d), C(a87aabc2ec26e582),
- C(be2b053721eb26d2), C(10febd7f0c3d6fcb), C(9cc5b9b2f6e3bf7b),
- C(655d8495fe624a86), C(6381a9f3d1f2bd7e), C(79ebabbfc25c83e2), C(26f82ad)},
+ {C(a18fbcdccd11e1f4), C(8248216751dfd65e), C(40c089f208d89d7c), C(26f82ad)},
{C(2d54f40cc4088b17), C(59d15633b0cd1399), C(a8cc04bb1bffd15b),
- C(d332cdb073d8dc46), C(272c56466868cb46), C(7e7fcbe35ca6c3f3),
- C(ee8f51e5a70399d4), C(d332cdb073d8dc46), C(272c56466868cb46),
- C(7e7fcbe35ca6c3f3), C(ee8f51e5a70399d4), C(16737a9c7581fe7b),
- C(ed04bf52f4b75dcb), C(9707ffb36bd30c1a), C(1390f236fdc0de3e),
C(b5244f42)},
{C(69276946cb4e87c7), C(62bdbe6183be6fa9), C(3ba9773dac442a1a),
- C(702e2afc7f5a1825), C(8c49b11ea8151fdc), C(caf3fef61f5a86fa),
- C(ef0b2ee8649d7272), C(702e2afc7f5a1825), C(8c49b11ea8151fdc),
- C(caf3fef61f5a86fa), C(ef0b2ee8649d7272), C(9e34a4e08d9441e1),
- C(7bdc0cd64d5af533), C(a926b14d99e3d868), C(fca923a17788cce4),
C(49a689e5)},
- {C(668174a3f443df1d), C(407299392da1ce86), C(c2a3f7d7f2c5be28),
- C(a590b202a7a5807b), C(968d2593f7ccb54e), C(9dd8d669e3e95dec),
- C(ee0cc5dd58b6e93a), C(a590b202a7a5807b), C(968d2593f7ccb54e),
- C(9dd8d669e3e95dec), C(ee0cc5dd58b6e93a), C(ac65d5a9466fb483),
- C(221be538b2c9d806), C(5cbe9441784f9fd9), C(d4c7d5d6e3c122b8), C(59fcdd3)},
- {C(5e29be847bd5046), C(b561c7f19c8f80c3), C(5e5abd5021ccaeaf),
- C(7432d63888e0c306), C(74bbceeed479cb71), C(6471586599575fdf),
- C(6a859ad23365cba2), C(7432d63888e0c306), C(74bbceeed479cb71),
- C(6471586599575fdf), C(6a859ad23365cba2), C(f9ceec84acd18dcc),
- C(74a242ff1907437c), C(f70890194e1ee913), C(777dfcb4bb01f0ba),
- C(4f4b04e9)},
+ {C(668174a3f443df1d), C(407299392da1ce86), C(c2a3f7d7f2c5be28), C(59fcdd3)},
+ {C(5e29be847bd5046), C(b561c7f19c8f80c3), C(5e5abd5021ccaeaf), C(4f4b04e9)},
{C(cd0d79f2164da014), C(4c386bb5c5d6ca0c), C(8e771b03647c3b63),
- C(69db23875cb0b715), C(ada8dd91504ae37f), C(46bf18dbf045ed6a),
- C(e1b5f67b0645ab63), C(69db23875cb0b715), C(ada8dd91504ae37f),
- C(46bf18dbf045ed6a), C(e1b5f67b0645ab63), C(877be8f5dcddff4),
- C(6d471b5f9ca2e2d1), C(802c86d6f495b9bb), C(a1f9b9b22b3be704),
C(8b00f891)},
{C(e0e6fc0b1628af1d), C(29be5fb4c27a2949), C(1c3f781a604d3630),
- C(c4af7faf883033aa), C(9bd296c4e9453cac), C(ca45426c1f7e33f9),
- C(a6bbdcf7074d40c5), C(c4af7faf883033aa), C(9bd296c4e9453cac),
- C(ca45426c1f7e33f9), C(a6bbdcf7074d40c5), C(e13a005d7142733b),
- C(c02b7925c5eeefaf), C(d39119a60441e2d5), C(3c24c710df8f4d43),
C(16e114f3)},
{C(2058927664adfd93), C(6e8f968c7963baa5), C(af3dced6fff7c394),
- C(42e34cf3d53c7876), C(9cddbb26424dc5e), C(64f6340a6d8eddad),
- C(2196e488eb2a3a4b), C(42e34cf3d53c7876), C(9cddbb26424dc5e),
- C(64f6340a6d8eddad), C(2196e488eb2a3a4b), C(c9e9da25911a16fd),
- C(e21b4683f3e196a8), C(cb80bf1a4c6fdbb4), C(53792e9b3c3e67f8),
C(d6b6dadc)},
{C(dc107285fd8e1af7), C(a8641a0609321f3f), C(db06e89ffdc54466),
- C(bcc7a81ed5432429), C(b6d7bdc6ad2e81f1), C(93605ec471aa37db),
- C(a2a73f8a85a8e397), C(bcc7a81ed5432429), C(b6d7bdc6ad2e81f1),
- C(93605ec471aa37db), C(a2a73f8a85a8e397), C(10a012b8ca7ac24b),
- C(aac5fd63351595cf), C(5bb4c648a226dea0), C(9d11ecb2b5c05c5f),
C(897e20ac)},
- {C(fbba1afe2e3280f1), C(755a5f392f07fce), C(9e44a9a15402809a),
- C(6226a32e25099848), C(ea895661ecf53004), C(4d7e0158db2228b9),
- C(e5a7d82922f69842), C(6226a32e25099848), C(ea895661ecf53004),
- C(4d7e0158db2228b9), C(e5a7d82922f69842), C(2cea7713b69840ca),
- C(18de7b9ae938375b), C(f127cca08f3cc665), C(b1c22d727665ad2), C(f996e05d)},
+ {C(fbba1afe2e3280f1), C(755a5f392f07fce), C(9e44a9a15402809a), C(f996e05d)},
{C(bfa10785ddc1011b), C(b6e1c4d2f670f7de), C(517d95604e4fcc1f),
- C(ca6552a0dfb82c73), C(b024cdf09e34ba07), C(66cd8c5a95d7393b),
- C(e3939acf790d4a74), C(ca6552a0dfb82c73), C(b024cdf09e34ba07),
- C(66cd8c5a95d7393b), C(e3939acf790d4a74), C(97827541a1ef051e),
- C(ac2fce47ebe6500c), C(b3f06d3bddf3bd6a), C(1d74afb25e1ce5fe),
C(c4306af6)},
- {C(534cc35f0ee1eb4e), C(b703820f1f3b3dce), C(884aa164cf22363),
- C(f14ef7f47d8a57a3), C(80d1f86f2e061d7c), C(401d6c2f151b5a62),
- C(e988460224108944), C(f14ef7f47d8a57a3), C(80d1f86f2e061d7c),
- C(401d6c2f151b5a62), C(e988460224108944), C(7804d4135f68cd19),
- C(5487b4b39e69fe8e), C(8cc5999015358a27), C(8f3729b61c2d5601),
- C(6dcad433)},
- {C(7ca6e3933995dac), C(fd118c77daa8188), C(3aceb7b5e7da6545),
- C(c8389799445480db), C(5389f5df8aacd50d), C(d136581f22fab5f),
- C(c2f31f85991da417), C(c8389799445480db), C(5389f5df8aacd50d),
- C(d136581f22fab5f), C(c2f31f85991da417), C(aefbf9ff84035a43),
- C(8accbaf44adadd7c), C(e57f3657344b67f5), C(21490e5e8abdec51),
- C(3c07374d)},
+ {C(534cc35f0ee1eb4e), C(b703820f1f3b3dce), C(884aa164cf22363), C(6dcad433)},
+ {C(7ca6e3933995dac), C(fd118c77daa8188), C(3aceb7b5e7da6545), C(3c07374d)},
{C(f0d6044f6efd7598), C(e044d6ba4369856e), C(91968e4f8c8a1a4c),
- C(70bd1968996bffc2), C(4c613de5d8ab32ac), C(fe1f4f97206f79d8),
- C(ac0434f2c4e213a9), C(70bd1968996bffc2), C(4c613de5d8ab32ac),
- C(fe1f4f97206f79d8), C(ac0434f2c4e213a9), C(7490e9d82cfe22ca),
- C(5fbbf7f987454238), C(c39e0dc8368ce949), C(22201d3894676c71),
C(f0f4602c)},
{C(3d69e52049879d61), C(76610636ea9f74fe), C(e9bf5602f89310c0),
- C(8eeb177a86053c11), C(e390122c345f34a2), C(1e30e47afbaaf8d6),
- C(7b892f68e5f91732), C(8eeb177a86053c11), C(e390122c345f34a2),
- C(1e30e47afbaaf8d6), C(7b892f68e5f91732), C(b87922525fa44158),
- C(f440a1ee1a1a766b), C(ee8efad279d08c5c), C(421f910c5b60216e),
C(3e1ea071)},
- {C(79da242a16acae31), C(183c5f438e29d40), C(6d351710ae92f3de),
- C(27233b28b5b11e9b), C(c7dfe8988a942700), C(570ed11c4abad984),
- C(4b4c04632f48311a), C(27233b28b5b11e9b), C(c7dfe8988a942700),
- C(570ed11c4abad984), C(4b4c04632f48311a), C(12f33235442cbf9),
- C(a35315ca0b5b8cdb), C(d8abde62ead5506b), C(fc0fcf8478ad5266),
- C(67580f0c)},
+ {C(79da242a16acae31), C(183c5f438e29d40), C(6d351710ae92f3de), C(67580f0c)},
{C(461c82656a74fb57), C(d84b491b275aa0f7), C(8f262cb29a6eb8b2),
- C(49fa3070bc7b06d0), C(f12ed446bd0c0539), C(6d43ac5d1dd4b240),
- C(7609524fe90bec93), C(49fa3070bc7b06d0), C(f12ed446bd0c0539),
- C(6d43ac5d1dd4b240), C(7609524fe90bec93), C(391c2b2e076ec241),
- C(f5e62deda7839f7b), C(3c7b3186a10d870f), C(77ef4f2cba4f1005),
C(4e109454)},
- {C(53c1a66d0b13003), C(731f060e6fe797fc), C(daa56811791371e3),
- C(57466046cf6896ed), C(8ac37e0e8b25b0c6), C(3e6074b52ad3cf18),
- C(aa491ce7b45db297), C(57466046cf6896ed), C(8ac37e0e8b25b0c6),
- C(3e6074b52ad3cf18), C(aa491ce7b45db297), C(f7a9227c5e5e22c3),
- C(3d92e0841e29ce28), C(2d30da5b2859e59d), C(ff37fa1c9cbfafc2),
- C(88a474a7)},
- {C(d3a2efec0f047e9), C(1cabce58853e58ea), C(7a17b2eae3256be4),
- C(c2dcc9758c910171), C(cb5cddaeff4ddb40), C(5d7cc5869baefef1),
- C(9644c5853af9cfeb), C(c2dcc9758c910171), C(cb5cddaeff4ddb40),
- C(5d7cc5869baefef1), C(9644c5853af9cfeb), C(255c968184694ee1),
- C(4e4d726eda360927), C(7d27dd5b6d100377), C(9a300e2020ddea2c), C(5b5bedd)},
+ {C(53c1a66d0b13003), C(731f060e6fe797fc), C(daa56811791371e3), C(88a474a7)},
+ {C(d3a2efec0f047e9), C(1cabce58853e58ea), C(7a17b2eae3256be4), C(5b5bedd)},
{C(43c64d7484f7f9b2), C(5da002b64aafaeb7), C(b576c1e45800a716),
- C(3ee84d3d5b4ca00b), C(5cbc6d701894c3f9), C(d9e946f5ae1ca95),
- C(24ca06e67f0b1833), C(3ee84d3d5b4ca00b), C(5cbc6d701894c3f9),
- C(d9e946f5ae1ca95), C(24ca06e67f0b1833), C(3413d46b4152650e),
- C(cbdfdbc2ab516f9c), C(2aad8acb739e0c6c), C(2bfc950d9f9fa977),
C(1aaddfa7)},
{C(a7dec6ad81cf7fa1), C(180c1ab708683063), C(95e0fd7008d67cff),
- C(6b11c5073687208), C(7e0a57de0d453f3), C(e48c267d4f646867),
- C(2168e9136375f9cb), C(6b11c5073687208), C(7e0a57de0d453f3),
- C(e48c267d4f646867), C(2168e9136375f9cb), C(64da194aeeea7fdf),
- C(a3b9f01fa5885678), C(c316f8ee2eb2bd17), C(a7e4d80f83e4427f),
C(5be07fd8)},
- {C(5408a1df99d4aff), C(b9565e588740f6bd), C(abf241813b08006e),
- C(7da9e81d89fda7ad), C(274157cabe71440d), C(2c22d9a480b331f7),
- C(e835c8ac746472d5), C(7da9e81d89fda7ad), C(274157cabe71440d),
- C(2c22d9a480b331f7), C(e835c8ac746472d5), C(2038ce817a201ae4),
- C(46f3289dfe1c5e40), C(435578a42d4b7c56), C(f96d9f409fcf561), C(cbca8606)},
+ {C(5408a1df99d4aff), C(b9565e588740f6bd), C(abf241813b08006e), C(cbca8606)},
{C(a8b27a6bcaeeed4b), C(aec1eeded6a87e39), C(9daf246d6fed8326),
- C(d45a938b79f54e8f), C(366b219d6d133e48), C(5b14be3c25c49405),
- C(fdd791d48811a572), C(d45a938b79f54e8f), C(366b219d6d133e48),
- C(5b14be3c25c49405), C(fdd791d48811a572), C(3de67b8d9e95d335),
- C(903c01307cfbeed5), C(af7d65f32274f1d1), C(4dba141b5fc03c42),
C(bde64d01)},
{C(9a952a8246fdc269), C(d0dcfcac74ef278c), C(250f7139836f0f1f),
- C(c83d3c5f4e5f0320), C(694e7adeb2bf32e5), C(7ad09538a3da27f5),
- C(2b5c18f934aa5303), C(c83d3c5f4e5f0320), C(694e7adeb2bf32e5),
- C(7ad09538a3da27f5), C(2b5c18f934aa5303), C(c4dad7703d34326e),
- C(825569e2bcdc6a25), C(b83d267709ca900d), C(44ed05151f5d74e6),
C(ee90cf33)},
{C(c930841d1d88684f), C(5eb66eb18b7f9672), C(e455d413008a2546),
- C(bc271bc0df14d647), C(b071100a9ff2edbb), C(2b1a4c1cc31a119a),
- C(b5d7caa1bd946cef), C(bc271bc0df14d647), C(b071100a9ff2edbb),
- C(2b1a4c1cc31a119a), C(b5d7caa1bd946cef), C(e02623ae10f4aadd),
- C(d79f600389cd06fd), C(1e8da7965303e62b), C(86f50e10eeab0925),
C(4305c3ce)},
- {C(94dc6971e3cf071a), C(994c7003b73b2b34), C(ea16e85978694e5),
- C(336c1b59a1fc19f6), C(c173acaecc471305), C(db1267d24f3f3f36),
- C(e9a5ee98627a6e78), C(336c1b59a1fc19f6), C(c173acaecc471305),
- C(db1267d24f3f3f36), C(e9a5ee98627a6e78), C(718f334204305ae5),
- C(e3b53c148f98d22c), C(a184012df848926), C(6e96386127d51183), C(4b3a1d76)},
- {C(7fc98006e25cac9), C(77fee0484cda86a7), C(376ec3d447060456),
- C(84064a6dcf916340), C(fbf55a26790e0ebb), C(2e7f84151c31a5c2),
- C(9f7f6d76b950f9bf), C(84064a6dcf916340), C(fbf55a26790e0ebb),
- C(2e7f84151c31a5c2), C(9f7f6d76b950f9bf), C(125e094fbee2b146),
- C(5706aa72b2eef7c2), C(1c4a2daa905ee66e), C(83d48029b5451694),
- C(a8bb6d80)},
- {C(bd781c4454103f6), C(612197322f49c931), C(b9cf17fd7e5462d5),
- C(e38e526cd3324364), C(85f2b63a5b5e840a), C(485d7cef5aaadd87),
- C(d2b837a462f6db6d), C(e38e526cd3324364), C(85f2b63a5b5e840a),
- C(485d7cef5aaadd87), C(d2b837a462f6db6d), C(3e41cef031520d9a),
- C(82df73902d7f67e), C(3ba6fd54c15257cb), C(22f91f079be42d40), C(1f9fa607)},
+ {C(94dc6971e3cf071a), C(994c7003b73b2b34), C(ea16e85978694e5), C(4b3a1d76)},
+ {C(7fc98006e25cac9), C(77fee0484cda86a7), C(376ec3d447060456), C(a8bb6d80)},
+ {C(bd781c4454103f6), C(612197322f49c931), C(b9cf17fd7e5462d5), C(1f9fa607)},
{C(da60e6b14479f9df), C(3bdccf69ece16792), C(18ebf45c4fecfdc9),
- C(16818ee9d38c6664), C(5519fa9a1e35a329), C(cbd0001e4b08ed8),
- C(41a965e37a0c731b), C(16818ee9d38c6664), C(5519fa9a1e35a329),
- C(cbd0001e4b08ed8), C(41a965e37a0c731b), C(66e7b5dcca1ca28f),
- C(963b2d993614347d), C(9b6fc6f41d411106), C(aaaecaccf7848c0c),
C(8d0e4ed2)},
- {C(4ca56a348b6c4d3), C(60618537c3872514), C(2fbb9f0e65871b09),
- C(30278016830ddd43), C(f046646d9012e074), C(c62a5804f6e7c9da),
- C(98d51f5830e2bc1e), C(30278016830ddd43), C(f046646d9012e074),
- C(c62a5804f6e7c9da), C(98d51f5830e2bc1e), C(7b2cbe5d37e3f29e),
- C(7b8c3ed50bda4aa0), C(3ea60cc24639e038), C(f7706de9fb0b5801),
- C(1bf31347)},
+ {C(4ca56a348b6c4d3), C(60618537c3872514), C(2fbb9f0e65871b09), C(1bf31347)},
{C(ebd22d4b70946401), C(6863602bf7139017), C(c0b1ac4e11b00666),
- C(7d2782b82bd494b6), C(97159ba1c26b304b), C(42b3b0fd431b2ac2),
- C(faa81f82691c830c), C(7d2782b82bd494b6), C(97159ba1c26b304b),
- C(42b3b0fd431b2ac2), C(faa81f82691c830c), C(7cc6449234c7e185),
- C(aeaa6fa643ca86a5), C(1412db1c0f2e0133), C(4df2fe3e4072934f),
C(1ae3fc5b)},
- {C(3cc4693d6cbcb0c), C(501689ea1c70ffa), C(10a4353e9c89e364),
- C(58c8aba7475e2d95), C(3e2f291698c9427a), C(e8710d19c9de9e41),
- C(65dda22eb04cf953), C(58c8aba7475e2d95), C(3e2f291698c9427a),
- C(e8710d19c9de9e41), C(65dda22eb04cf953), C(d7729c48c250cffa),
- C(ef76162b2ddfba4b), C(52371e17f4d51f6d), C(ddd002112ff0c833),
- C(459c3930)},
+ {C(3cc4693d6cbcb0c), C(501689ea1c70ffa), C(10a4353e9c89e364), C(459c3930)},
{C(38908e43f7ba5ef0), C(1ab035d4e7781e76), C(41d133e8c0a68ff7),
- C(d1090893afaab8bc), C(96c4fe6922772807), C(4522426c2b4205eb),
- C(efad99a1262e7e0d), C(d1090893afaab8bc), C(96c4fe6922772807),
- C(4522426c2b4205eb), C(efad99a1262e7e0d), C(c7696029abdb465e),
- C(4e18eaf03d517651), C(d006bced54c86ac8), C(4330326d1021860c),
C(e00c4184)},
- {C(34983ccc6aa40205), C(21802cad34e72bc4), C(1943e8fb3c17bb8),
- C(fc947167f69c0da5), C(ae79cfdb91b6f6c1), C(7b251d04c26cbda3),
- C(128a33a79060d25e), C(fc947167f69c0da5), C(ae79cfdb91b6f6c1),
- C(7b251d04c26cbda3), C(128a33a79060d25e), C(1eca842dbfe018dd),
- C(50a4cd2ee0ba9c63), C(c2f5c97d8399682f), C(3f929fc7cbe8ecbb),
- C(ffc7a781)},
+ {C(34983ccc6aa40205), C(21802cad34e72bc4), C(1943e8fb3c17bb8), C(ffc7a781)},
{C(86215c45dcac9905), C(ea546afe851cae4b), C(d85b6457e489e374),
- C(b7609c8e70386d66), C(36e6ccc278d1636d), C(2f873307c08e6a1c),
- C(10f252a758505289), C(b7609c8e70386d66), C(36e6ccc278d1636d),
- C(2f873307c08e6a1c), C(10f252a758505289), C(c8977646e81ab4b6),
- C(8017b745cd80213b), C(960687db359bea0), C(ef4a470660799488), C(6a125480)},
+ C(6a125480)},
{C(420fc255c38db175), C(d503cd0f3c1208d1), C(d4684e74c825a0bc),
- C(4c10537443152f3d), C(720451d3c895e25d), C(aff60c4d11f513fd),
- C(881e8d6d2d5fb953), C(4c10537443152f3d), C(720451d3c895e25d),
- C(aff60c4d11f513fd), C(881e8d6d2d5fb953), C(9dec034a043f1f55),
- C(e27a0c22e7bfb39d), C(2220b959128324), C(53240272152dbd8b), C(88a1512b)},
+ C(88a1512b)},
{C(1d7a31f5bc8fe2f9), C(4763991092dcf836), C(ed695f55b97416f4),
- C(f265edb0c1c411d7), C(30e1e9ec5262b7e6), C(c2c3ba061ce7957a),
- C(d975f93b89a16409), C(f265edb0c1c411d7), C(30e1e9ec5262b7e6),
- C(c2c3ba061ce7957a), C(d975f93b89a16409), C(e9d703123f43450a),
- C(41383fedfed67c82), C(6e9f43ecbbbd6004), C(c7ccd23a24e77b8), C(549bbbe5)},
+ C(549bbbe5)},
{C(94129a84c376a26e), C(c245e859dc231933), C(1b8f74fecf917453),
- C(e9369d2e9007e74b), C(b1375915d1136052), C(926c2021fe1d2351),
- C(1d943addaaa2e7e6), C(e9369d2e9007e74b), C(b1375915d1136052),
- C(926c2021fe1d2351), C(1d943addaaa2e7e6), C(f5f515869c246738),
- C(7e309cd0e1c0f2a0), C(153c3c36cf523e3b), C(4931c66872ea6758),
C(c133d38c)},
- {C(1d3a9809dab05c8d), C(adddeb4f71c93e8), C(ef342eb36631edb),
- C(301d7a61c4b3dbca), C(861336c3f0552d61), C(12c6db947471300f),
- C(a679ef0ed761deb9), C(301d7a61c4b3dbca), C(861336c3f0552d61),
- C(12c6db947471300f), C(a679ef0ed761deb9), C(5f713b720efcd147),
- C(37ac330a333aa6b), C(3309dc9ec1616eef), C(52301d7a908026b5), C(fcace348)},
+ {C(1d3a9809dab05c8d), C(adddeb4f71c93e8), C(ef342eb36631edb), C(fcace348)},
{C(90fa3ccbd60848da), C(dfa6e0595b569e11), C(e585d067a1f5135d),
- C(6cef866ec295abea), C(c486c0d9214beb2d), C(d6e490944d5fe100),
- C(59df3175d72c9f38), C(6cef866ec295abea), C(c486c0d9214beb2d),
- C(d6e490944d5fe100), C(59df3175d72c9f38), C(3f23aeb4c04d1443),
- C(9bf0515cd8d24770), C(958554f60ccaade2), C(5182863c90132fe8),
C(ed7b6f9a)},
{C(2dbb4fc71b554514), C(9650e04b86be0f82), C(60f2304fba9274d3),
- C(fcfb9443e997cab), C(f13310d96dec2772), C(709cad2045251af2),
- C(afd0d30cc6376dad), C(fcfb9443e997cab), C(f13310d96dec2772),
- C(709cad2045251af2), C(afd0d30cc6376dad), C(59d4bed30d550d0d),
- C(58006d4e22d8aad1), C(eee12d2362d1f13b), C(35cf1d7faaf1d228),
C(6d907dda)},
{C(b98bf4274d18374a), C(1b669fd4c7f9a19a), C(b1f5972b88ba2b7a),
- C(73119c99e6d508be), C(5d4036a187735385), C(8fa66e192fd83831),
- C(2abf64b6b592ed57), C(73119c99e6d508be), C(5d4036a187735385),
- C(8fa66e192fd83831), C(2abf64b6b592ed57), C(d4501f95dd84b08c),
- C(bf1552439c8bea02), C(4f56fe753ba7e0ba), C(4ca8d35cc058cfcd),
C(7a4d48d5)},
{C(d6781d0b5e18eb68), C(b992913cae09b533), C(58f6021caaee3a40),
- C(aafcb77497b5a20b), C(411819e5e79b77a3), C(bd779579c51c77ce),
- C(58d11f5dcf5d075d), C(aafcb77497b5a20b), C(411819e5e79b77a3),
- C(bd779579c51c77ce), C(58d11f5dcf5d075d), C(9eae76cde1cb4233),
- C(32fe25a9bf657970), C(1c0c807948edb06a), C(b8f29a3dfaee254d),
C(e686f3db)},
- {C(226651cf18f4884c), C(595052a874f0f51c), C(c9b75162b23bab42),
- C(3f44f873be4812ec), C(427662c1dbfaa7b2), C(a207ff9638fb6558),
- C(a738d919e45f550f), C(3f44f873be4812ec), C(427662c1dbfaa7b2),
- C(a207ff9638fb6558), C(a738d919e45f550f), C(cb186ea05717e7d6),
- C(1ca7d68a5871fdc1), C(5d4c119ea8ef3750), C(72b6a10fa2ff9406), C(cce7c55)},
- {C(a734fb047d3162d6), C(e523170d240ba3a5), C(125a6972809730e8),
- C(d396a297799c24a1), C(8fee992e3069bad5), C(2e3a01b0697ccf57),
- C(ee9c7390bd901cfa), C(d396a297799c24a1), C(8fee992e3069bad5),
- C(2e3a01b0697ccf57), C(ee9c7390bd901cfa), C(56f2d9da0af28af2),
- C(3fdd37b2fe8437cb), C(3d13eeeb60d6aec0), C(2432ae62e800a5ce), C(f58b96b)},
+ {C(226651cf18f4884c), C(595052a874f0f51c), C(c9b75162b23bab42), C(cce7c55)},
+ {C(a734fb047d3162d6), C(e523170d240ba3a5), C(125a6972809730e8), C(f58b96b)},
{C(c6df6364a24f75a3), C(c294e2c84c4f5df8), C(a88df65c6a89313b),
- C(895fe8443183da74), C(c7f2f6f895a67334), C(a0d6b6a506691d31),
- C(24f51712b459a9f0), C(895fe8443183da74), C(c7f2f6f895a67334),
- C(a0d6b6a506691d31), C(24f51712b459a9f0), C(173a699481b9e088),
- C(1dee9b77bcbf45d3), C(32b98a646a8667d0), C(3adcd4ee28f42a0e),
C(1bbf6f60)},
- {C(d8d1364c1fbcd10), C(2d7cc7f54832deaa), C(4e22c876a7c57625),
- C(a3d5d1137d30c4bd), C(1e7d706a49bdfb9e), C(c63282b20ad86db2),
- C(aec97fa07916bfd6), C(a3d5d1137d30c4bd), C(1e7d706a49bdfb9e),
- C(c63282b20ad86db2), C(aec97fa07916bfd6), C(7c9ba3e52d44f73e),
- C(af62fd245811185d), C(8a9d2dacd8737652), C(bd2cce277d5fbec0),
- C(ce5e0cc2)},
+ {C(d8d1364c1fbcd10), C(2d7cc7f54832deaa), C(4e22c876a7c57625), C(ce5e0cc2)},
{C(aae06f9146db885f), C(3598736441e280d9), C(fba339b117083e55),
- C(b22bf08d9f8aecf7), C(c182730de337b922), C(2b9adc87a0450a46),
- C(192c29a9cfc00aad), C(b22bf08d9f8aecf7), C(c182730de337b922),
- C(2b9adc87a0450a46), C(192c29a9cfc00aad), C(9fd733f1d84a59d9),
- C(d86bd5c9839ace15), C(af20b57303172876), C(9f63cb7161b5364c),
C(584cfd6f)},
{C(8955ef07631e3bcc), C(7d70965ea3926f83), C(39aed4134f8b2db6),
- C(882efc2561715a9c), C(ef8132a18a540221), C(b20a3c87a8c257c1),
- C(f541b8628fad6c23), C(882efc2561715a9c), C(ef8132a18a540221),
- C(b20a3c87a8c257c1), C(f541b8628fad6c23), C(9552aed57a6e0467),
- C(4d9fdd56867611a7), C(c330279bf23b9eab), C(44dbbaea2fcb8eba),
C(8f9bbc33)},
{C(ad611c609cfbe412), C(d3c00b18bf253877), C(90b2172e1f3d0bfd),
- C(371a98b2cb084883), C(33a2886ee9f00663), C(be9568818ed6e6bd),
- C(f244a0fa2673469a), C(371a98b2cb084883), C(33a2886ee9f00663),
- C(be9568818ed6e6bd), C(f244a0fa2673469a), C(b447050bd3e559e9),
- C(d3b695dae7a13383), C(ded0bb65be471188), C(ca3c7a2b78922cae),
C(d7640d95)},
- {C(d5339adc295d5d69), C(b633cc1dcb8b586a), C(ee84184cf5b1aeaf),
- C(89f3aab99afbd636), C(f420e004f8148b9a), C(6818073faa797c7c),
- C(dd3b4e21cbbf42ca), C(89f3aab99afbd636), C(f420e004f8148b9a),
- C(6818073faa797c7c), C(dd3b4e21cbbf42ca), C(6a2b7db261164844),
- C(cbead63d1895852a), C(93d37e1eae05e2f9), C(5d06db2703fbc3ae), C(3d12a2b)},
+ {C(d5339adc295d5d69), C(b633cc1dcb8b586a), C(ee84184cf5b1aeaf), C(3d12a2b)},
{C(40d0aeff521375a8), C(77ba1ad7ecebd506), C(547c6f1a7d9df427),
- C(21c2be098327f49b), C(7e035065ac7bbef5), C(6d7348e63023fb35),
- C(9d427dc1b67c3830), C(21c2be098327f49b), C(7e035065ac7bbef5),
- C(6d7348e63023fb35), C(9d427dc1b67c3830), C(4e3d018a43858341),
- C(cf924bb44d6b43c5), C(4618b6a26e3446ae), C(54d3013fac3ed469),
C(aaeafed0)},
{C(8b2d54ae1a3df769), C(11e7adaee3216679), C(3483781efc563e03),
- C(9d097dd3152ab107), C(51e21d24126e8563), C(cba56cac884a1354),
- C(39abb1b595f0a977), C(9d097dd3152ab107), C(51e21d24126e8563),
- C(cba56cac884a1354), C(39abb1b595f0a977), C(81e6dd1c1109848f),
- C(1644b209826d7b15), C(6ac67e4e4b4812f0), C(b3a9f5622c935bf7),
C(95b9b814)},
{C(99c175819b4eae28), C(932e8ff9f7a40043), C(ec78dcab07ca9f7c),
- C(c1a78b82ba815b74), C(458cbdfc82eb322a), C(17f4a192376ed8d7),
- C(6f9e92968bc8ccef), C(c1a78b82ba815b74), C(458cbdfc82eb322a),
- C(17f4a192376ed8d7), C(6f9e92968bc8ccef), C(93e098c333b39905),
- C(d59b1cace44b7fdc), C(f7a64ed78c64c7c5), C(7c6eca5dd87ec1ce),
C(45fbe66e)},
{C(2a418335779b82fc), C(af0295987849a76b), C(c12bc5ff0213f46e),
- C(5aeead8d6cb25bb9), C(739315f7743ec3ff), C(9ab48d27111d2dcc),
- C(5b87bd35a975929b), C(5aeead8d6cb25bb9), C(739315f7743ec3ff),
- C(9ab48d27111d2dcc), C(5b87bd35a975929b), C(c3dd8d6d95a46bb3),
- C(7bf9093215a4f483), C(cb557d6ed84285bd), C(daf58422f261fdb5),
C(b4baa7a8)},
- {C(3b1fc6a3d279e67d), C(70ea1e49c226396), C(25505adcf104697c),
- C(ba1ffba29f0367aa), C(a20bec1dd15a8b6c), C(e9bf61d2dab0f774),
- C(f4f35bf5870a049c), C(ba1ffba29f0367aa), C(a20bec1dd15a8b6c),
- C(e9bf61d2dab0f774), C(f4f35bf5870a049c), C(26787efa5b92385),
- C(3d9533590ce30b59), C(a4da3e40530a01d4), C(6395deaefb70067c),
- C(83e962fe)},
- {C(d97eacdf10f1c3c9), C(b54f4654043a36e0), C(b128f6eb09d1234),
- C(d8ad7ec84a9c9aa2), C(e256cffed11f69e6), C(2cf65e4958ad5bda),
- C(cfbf9b03245989a7), C(d8ad7ec84a9c9aa2), C(e256cffed11f69e6),
- C(2cf65e4958ad5bda), C(cfbf9b03245989a7), C(9fa51e6686cf4444),
- C(9425c117a34609d5), C(b25f7e2c6f30e96), C(ea5477c3f2b5afd1), C(aac3531c)},
+ {C(3b1fc6a3d279e67d), C(70ea1e49c226396), C(25505adcf104697c), C(83e962fe)},
+ {C(d97eacdf10f1c3c9), C(b54f4654043a36e0), C(b128f6eb09d1234), C(aac3531c)},
{C(293a5c1c4e203cd4), C(6b3329f1c130cefe), C(f2e32f8ec76aac91),
- C(361e0a62c8187bff), C(6089971bb84d7133), C(93df7741588dd50b),
- C(c2a9b6abcd1d80b1), C(361e0a62c8187bff), C(6089971bb84d7133),
- C(93df7741588dd50b), C(c2a9b6abcd1d80b1), C(4d2f86869d79bc59),
- C(85cd24d8aa570ff), C(b0dcf6ef0e94bbb5), C(2037c69aa7a78421), C(2b1db7cc)},
+ C(2b1db7cc)},
{C(4290e018ffaedde7), C(a14948545418eb5e), C(72d851b202284636),
- C(4ec02f3d2f2b23f2), C(ab3580708aa7c339), C(cdce066fbab3f65),
- C(d8ed3ecf3c7647b9), C(4ec02f3d2f2b23f2), C(ab3580708aa7c339),
- C(cdce066fbab3f65), C(d8ed3ecf3c7647b9), C(6d2204b3e31f344a),
- C(61a4d87f80ee61d7), C(446c43dbed4b728f), C(73130ac94f58747e),
C(cf00cd31)},
{C(f919a59cbde8bf2f), C(a56d04203b2dc5a5), C(38b06753ac871e48),
- C(c2c9fc637dbdfcfa), C(292ab8306d149d75), C(7f436b874b9ffc07),
- C(a5b56b0129218b80), C(c2c9fc637dbdfcfa), C(292ab8306d149d75),
- C(7f436b874b9ffc07), C(a5b56b0129218b80), C(9188f7bdc47ec050),
- C(cfe9345d03a15ade), C(40b520fb2750c49e), C(c2e83d343968af2e),
C(7d3c43b8)},
{C(1d70a3f5521d7fa4), C(fb97b3fdc5891965), C(299d49bbbe3535af),
- C(e1a8286a7d67946e), C(52bd956f047b298), C(cbd74332dd4204ac),
- C(12b5be7752721976), C(e1a8286a7d67946e), C(52bd956f047b298),
- C(cbd74332dd4204ac), C(12b5be7752721976), C(278426e27f6204b6),
- C(932ca7a7cd610181), C(41647321f0a5914d), C(48f4aa61a0ae80db),
C(cbd5fac6)},
{C(6af98d7b656d0d7c), C(d2e99ae96d6b5c0c), C(f63bd1603ef80627),
- C(bde51033ac0413f8), C(bc0272f691aec629), C(6204332651bebc44),
- C(1cbf00de026ea9bd), C(bde51033ac0413f8), C(bc0272f691aec629),
- C(6204332651bebc44), C(1cbf00de026ea9bd), C(b9c7ed6a75f3ff1e),
- C(7e310b76a5808e4f), C(acbbd1aad5531885), C(fc245f2473adeb9c),
C(76d0fec4)},
- {C(395b7a8adb96ab75), C(582df7165b20f4a), C(e52bd30e9ff657f9),
- C(6c71064996cbec8b), C(352c535edeefcb89), C(ac7f0aba15cd5ecd),
- C(3aba1ca8353e5c60), C(6c71064996cbec8b), C(352c535edeefcb89),
- C(ac7f0aba15cd5ecd), C(3aba1ca8353e5c60), C(5c30a288a80ce646),
- C(c2940488b6617674), C(925f8cc66b370575), C(aa65d1283b9bb0ef),
- C(405e3402)},
+ {C(395b7a8adb96ab75), C(582df7165b20f4a), C(e52bd30e9ff657f9), C(405e3402)},
{C(3822dd82c7df012f), C(b9029b40bd9f122b), C(fd25b988468266c4),
- C(43e47bd5bab1e0ef), C(4a71f363421f282f), C(880b2f32a2b4e289),
- C(1299d4eda9d3eadf), C(43e47bd5bab1e0ef), C(4a71f363421f282f),
- C(880b2f32a2b4e289), C(1299d4eda9d3eadf), C(d713a40226f5564),
- C(4d8d34fedc769406), C(a85001b29cd9cac3), C(cae92352a41fd2b0),
C(c732c481)},
{C(79f7efe4a80b951a), C(dd3a3fddfc6c9c41), C(ab4c812f9e27aa40),
- C(832954ec9d0de333), C(94c390aa9bcb6b8a), C(f3b32afdc1f04f82),
- C(d229c3b72e4b9a74), C(832954ec9d0de333), C(94c390aa9bcb6b8a),
- C(f3b32afdc1f04f82), C(d229c3b72e4b9a74), C(1d11860d7ed624a6),
- C(cadee20b3441b984), C(75307079bf306f7b), C(87902aa3b9753ba4),
C(a8d123c9)},
- {C(ae6e59f5f055921a), C(e9d9b7bf68e82), C(5ce4e4a5b269cc59),
- C(4960111789727567), C(149b8a37c7125ab6), C(78c7a13ab9749382),
- C(1c61131260ca151a), C(4960111789727567), C(149b8a37c7125ab6),
- C(78c7a13ab9749382), C(1c61131260ca151a), C(1e93276b35c309a0),
- C(2618f56230acde58), C(af61130a18e4febf), C(7145deb18e89befe),
- C(1e80ad7d)},
+ {C(ae6e59f5f055921a), C(e9d9b7bf68e82), C(5ce4e4a5b269cc59), C(1e80ad7d)},
{C(8959dbbf07387d36), C(b4658afce48ea35d), C(8f3f82437d8cb8d6),
- C(6566d74954986ba5), C(99d5235cc82519a7), C(257a23805c2d825),
- C(ad75ccb968e93403), C(6566d74954986ba5), C(99d5235cc82519a7),
- C(257a23805c2d825), C(ad75ccb968e93403), C(b45bd4cf78e11f7f),
- C(80c5536bdc487983), C(a4fd76ecbf018c8a), C(3b9dac78a7a70d43),
C(52aeb863)},
{C(4739613234278a49), C(99ea5bcd340bf663), C(258640912e712b12),
- C(c8a2827404991402), C(7ee5e78550f02675), C(2ec53952db5ac662),
- C(1526405a9df6794b), C(c8a2827404991402), C(7ee5e78550f02675),
- C(2ec53952db5ac662), C(1526405a9df6794b), C(eddc6271170c5e1f),
- C(f5a85f986001d9d6), C(95427c677bf58d58), C(53ed666dfa85cb29),
C(ef7c0c18)},
{C(420e6c926bc54841), C(96dbbf6f4e7c75cd), C(d8d40fa70c3c67bb),
- C(3edbc10e4bfee91b), C(f0d681304c28ef68), C(77ea602029aaaf9c),
- C(90f070bd24c8483c), C(3edbc10e4bfee91b), C(f0d681304c28ef68),
- C(77ea602029aaaf9c), C(90f070bd24c8483c), C(28bc8e41e08ceb86),
- C(1eb56e48a65691ef), C(9fea5301c9202f0e), C(3fcb65091aa9f135),
C(b6ad4b68)},
{C(c8601bab561bc1b7), C(72b26272a0ff869a), C(56fdfc986d6bc3c4),
- C(83707730cad725d4), C(c9ca88c3a779674a), C(e1c696fbbd9aa933),
- C(723f3baab1c17a45), C(83707730cad725d4), C(c9ca88c3a779674a),
- C(e1c696fbbd9aa933), C(723f3baab1c17a45), C(f82abc7a1d851682),
- C(30683836818e857d), C(78bfa3e89a5ab23f), C(6928234482b31817),
C(c1e46b17)},
- {C(b2d294931a0e20eb), C(284ffd9a0815bc38), C(1f8a103aac9bbe6),
- C(1ef8e98e1ea57269), C(5971116272f45a8b), C(187ad68ce95d8eac),
- C(e94e93ee4e8ecaa6), C(1ef8e98e1ea57269), C(5971116272f45a8b),
- C(187ad68ce95d8eac), C(e94e93ee4e8ecaa6), C(a0ff2a58611838b5),
- C(b01e03849bfbae6f), C(d081e202e28ea3ab), C(51836bcee762bf13),
- C(57b8df25)},
+ {C(b2d294931a0e20eb), C(284ffd9a0815bc38), C(1f8a103aac9bbe6), C(57b8df25)},
{C(7966f53c37b6c6d7), C(8e6abcfb3aa2b88f), C(7f2e5e0724e5f345),
- C(3eeb60c3f5f8143d), C(a25aec05c422a24f), C(b026b03ad3cca4db),
- C(e6e030028cc02a02), C(3eeb60c3f5f8143d), C(a25aec05c422a24f),
- C(b026b03ad3cca4db), C(e6e030028cc02a02), C(16fe679338b34bfc),
- C(c1be385b5c8a9de4), C(65af5df6567530eb), C(ed3b303df4dc6335),
C(e9fa36d6)},
{C(be9bb0abd03b7368), C(13bca93a3031be55), C(e864f4f52b55b472),
- C(36a8d13a2cbb0939), C(254ac73907413230), C(73520d1522315a70),
- C(8c9fdb5cf1e1a507), C(36a8d13a2cbb0939), C(254ac73907413230),
- C(73520d1522315a70), C(8c9fdb5cf1e1a507), C(b3640570b926886),
- C(fba2344ee87f7bab), C(de57341ab448df05), C(385612ee094fa977),
C(8f8daefc)},
- {C(a08d128c5f1649be), C(a8166c3dbbe19aad), C(cb9f914f829ec62c),
- C(5b2b7ca856fad1c3), C(8093022d682e375d), C(ea5d163ba7ea231f),
- C(d6181d012c0de641), C(5b2b7ca856fad1c3), C(8093022d682e375d),
- C(ea5d163ba7ea231f), C(d6181d012c0de641), C(e7d40d0ab8b08159),
- C(2e82320f51b3a67e), C(27c2e356ea0b63a3), C(58842d01a2b1d077), C(6e1bb7e)},
+ {C(a08d128c5f1649be), C(a8166c3dbbe19aad), C(cb9f914f829ec62c), C(6e1bb7e)},
{C(7c386f0ffe0465ac), C(530419c9d843dbf3), C(7450e3a4f72b8d8c),
- C(48b218e3b721810d), C(d3757ac8609bc7fc), C(111ba02a88aefc8),
- C(e86343137d3bfc2a), C(48b218e3b721810d), C(d3757ac8609bc7fc),
- C(111ba02a88aefc8), C(e86343137d3bfc2a), C(44ad26b51661b507),
- C(db1268670274f51e), C(62a5e75beae875f3), C(e266e7a44c5f28c6),
C(fd0076f0)},
- {C(bb362094e7ef4f8), C(ff3c2a48966f9725), C(55152803acd4a7fe),
- C(15747d8c505ffd00), C(438a15f391312cd6), C(e46ca62c26d821f5),
- C(be78d74c9f79cb44), C(15747d8c505ffd00), C(438a15f391312cd6),
- C(e46ca62c26d821f5), C(be78d74c9f79cb44), C(a8aa19f3aa59f09a),
- C(effb3cddab2c9267), C(d78e41ad97cb16a5), C(ace6821513527d32),
- C(899b17b6)},
+ {C(bb362094e7ef4f8), C(ff3c2a48966f9725), C(55152803acd4a7fe), C(899b17b6)},
{C(cd80dea24321eea4), C(52b4fdc8130c2b15), C(f3ea100b154bfb82),
- C(d9ccef1d4be46988), C(5ede0c4e383a5e66), C(da69683716a54d1e),
- C(bfc3fdf02d242d24), C(d9ccef1d4be46988), C(5ede0c4e383a5e66),
- C(da69683716a54d1e), C(bfc3fdf02d242d24), C(20ed30274651b3f5),
- C(4c659824169e86c6), C(637226dae5b52a0e), C(7e050dbd1c71dc7f),
C(e3e84e31)},
{C(d599a04125372c3a), C(313136c56a56f363), C(1e993c3677625832),
- C(2870a99c76a587a4), C(99f74cc0b182dda4), C(8a5e895b2f0ca7b6),
- C(3d78882d5e0bb1dc), C(2870a99c76a587a4), C(99f74cc0b182dda4),
- C(8a5e895b2f0ca7b6), C(3d78882d5e0bb1dc), C(f466123732a3e25e),
- C(aca5e59716a40e50), C(261d2e7383d0e686), C(ce9362d6a42c15a7),
C(eef79b6b)},
- {C(dbbf541e9dfda0a), C(1479fceb6db4f844), C(31ab576b59062534),
- C(a3335c417687cf3a), C(92ff114ac45cda75), C(c3b8a627384f13b5),
- C(c4f25de33de8b3f7), C(a3335c417687cf3a), C(92ff114ac45cda75),
- C(c3b8a627384f13b5), C(c4f25de33de8b3f7), C(eacbf520578c5964),
- C(4cb19c5ab24f3215), C(e7d8a6f67f0c6e7), C(325c2413eb770ada), C(868e3315)},
- {C(c2ee3288be4fe2bf), C(c65d2f5ddf32b92), C(af6ecdf121ba5485),
- C(c7cd48f7abf1fe59), C(ce600656ace6f53a), C(8a94a4381b108b34),
- C(f9d1276c64bf59fb), C(c7cd48f7abf1fe59), C(ce600656ace6f53a),
- C(8a94a4381b108b34), C(f9d1276c64bf59fb), C(219ce70ff5a112a5),
- C(e6026c576e2d28d7), C(b8e467f25015e3a6), C(950cb904f37af710),
- C(4639a426)},
+ {C(dbbf541e9dfda0a), C(1479fceb6db4f844), C(31ab576b59062534), C(868e3315)},
+ {C(c2ee3288be4fe2bf), C(c65d2f5ddf32b92), C(af6ecdf121ba5485), C(4639a426)},
{C(d86603ced1ed4730), C(f9de718aaada7709), C(db8b9755194c6535),
- C(d803e1eead47604c), C(ad00f7611970a71b), C(bc50036b16ce71f5),
- C(afba96210a2ca7d6), C(d803e1eead47604c), C(ad00f7611970a71b),
- C(bc50036b16ce71f5), C(afba96210a2ca7d6), C(28f7a7be1d6765f0),
- C(97bd888b93938c68), C(6ad41d1b407ded49), C(b9bfec098dc543e4),
C(f3213646)},
{C(915263c671b28809), C(a815378e7ad762fd), C(abec6dc9b669f559),
- C(d17c928c5342477f), C(745130b795254ad5), C(8c5db926fe88f8ba),
- C(742a95c953e6d974), C(d17c928c5342477f), C(745130b795254ad5),
- C(8c5db926fe88f8ba), C(742a95c953e6d974), C(279db8057b5d3e96),
- C(98168411565b4ec4), C(50a72c54fa1125fa), C(27766a635db73638),
C(17f148e9)},
- {C(2b67cdd38c307a5e), C(cb1d45bb5c9fe1c), C(800baf2a02ec18ad),
- C(6531c1fe32bcb417), C(8c970d8df8cdbeb4), C(917ba5fc67e72b40),
- C(4b65e4e263e0a426), C(6531c1fe32bcb417), C(8c970d8df8cdbeb4),
- C(917ba5fc67e72b40), C(4b65e4e263e0a426), C(e0de33ce88a8b3a9),
- C(f8ef98a437e16b08), C(a5162c0c7c5f7b62), C(dbdac43361b2b881),
- C(bfd94880)},
+ {C(2b67cdd38c307a5e), C(cb1d45bb5c9fe1c), C(800baf2a02ec18ad), C(bfd94880)},
{C(2d107419073b9cd0), C(a96db0740cef8f54), C(ec41ee91b3ecdc1b),
- C(ffe319654c8e7ebc), C(6a67b8f13ead5a72), C(6dd10a34f80d532f),
- C(6e9cfaece9fbca4), C(ffe319654c8e7ebc), C(6a67b8f13ead5a72),
- C(6dd10a34f80d532f), C(6e9cfaece9fbca4), C(b4468eb6a30aa7e9),
- C(e87995bee483222a), C(d036c2c90c609391), C(853306e82fa32247),
C(bb1fa7f3)},
- {C(f3e9487ec0e26dfc), C(1ab1f63224e837fa), C(119983bb5a8125d8),
- C(8950cfcf4bdf622c), C(8847dca82efeef2f), C(646b75b026708169),
- C(21cab4b1687bd8b), C(8950cfcf4bdf622c), C(8847dca82efeef2f),
- C(646b75b026708169), C(21cab4b1687bd8b), C(243b489a9eae6231),
- C(5f3e634c4b779876), C(ff8abd1548eaf646), C(c7962f5f0151914b), C(88816b1)},
+ {C(f3e9487ec0e26dfc), C(1ab1f63224e837fa), C(119983bb5a8125d8), C(88816b1)},
{C(1160987c8fe86f7d), C(879e6db1481eb91b), C(d7dcb802bfe6885d),
- C(14453b5cc3d82396), C(4ef700c33ed278bc), C(1639c72ffc00d12e),
- C(fb140ee6155f700d), C(14453b5cc3d82396), C(4ef700c33ed278bc),
- C(1639c72ffc00d12e), C(fb140ee6155f700d), C(2e6b5c96a6620862),
- C(a1f136998cbe19c), C(74e058a3b6c5a712), C(93dcf6bd33928b17), C(5c2faeb3)},
+ C(5c2faeb3)},
{C(eab8112c560b967b), C(97f550b58e89dbae), C(846ed506d304051f),
- C(276aa37744b5a028), C(8c10800ee90ea573), C(e6e57d2b33a1e0b7),
- C(91f83563cd3b9dda), C(276aa37744b5a028), C(8c10800ee90ea573),
- C(e6e57d2b33a1e0b7), C(91f83563cd3b9dda), C(afbb4739570738a1),
- C(440ba98da5d8f69), C(fde4e9b0eda20350), C(e67dfa5a2138fa1), C(51b5fc6f)},
+ C(51b5fc6f)},
{C(1addcf0386d35351), C(b5f436561f8f1484), C(85d38e22181c9bb1),
- C(ff5c03f003c1fefe), C(e1098670afe7ff6), C(ea445030cf86de19),
- C(f155c68b5c2967f8), C(ff5c03f003c1fefe), C(e1098670afe7ff6),
- C(ea445030cf86de19), C(f155c68b5c2967f8), C(95d31b145dbb2e9e),
- C(914fe1ca3deb3265), C(6066020b1358ccc1), C(c74bb7e2dee15036),
C(33d94752)},
{C(d445ba84bf803e09), C(1216c2497038f804), C(2293216ea2237207),
- C(e2164451c651adfb), C(b2534e65477f9823), C(4d70691a69671e34),
- C(15be4963dbde8143), C(e2164451c651adfb), C(b2534e65477f9823),
- C(4d70691a69671e34), C(15be4963dbde8143), C(762e75c406c5e9a3),
- C(7b7579f7e0356841), C(480533eb066dfce5), C(90ae14ea6bfeb4ae),
C(b0c92948)},
{C(37235a096a8be435), C(d9b73130493589c2), C(3b1024f59378d3be),
- C(ad159f542d81f04e), C(49626a97a946096), C(d8d3998bf09fd304),
- C(d127a411eae69459), C(ad159f542d81f04e), C(49626a97a946096),
- C(d8d3998bf09fd304), C(d127a411eae69459), C(8f3253c4eb785a7b),
- C(4049062f37e62397), C(b9fa04d3b670e5c1), C(1211a7967ac9350f),
C(c7171590)},
{C(763ad6ea2fe1c99d), C(cf7af5368ac1e26b), C(4d5e451b3bb8d3d4),
- C(3712eb913d04e2f2), C(2f9500d319c84d89), C(4ac6eb21a8cf06f9),
- C(7d1917afcde42744), C(3712eb913d04e2f2), C(2f9500d319c84d89),
- C(4ac6eb21a8cf06f9), C(7d1917afcde42744), C(6b58604b5dd10903),
- C(c4288dfbc1e319fc), C(230f75ca96817c6e), C(8894cba3b763756c),
C(240a67fb)},
{C(ea627fc84cd1b857), C(85e372494520071f), C(69ec61800845780b),
- C(a3c1c5ca1b0367), C(eb6933997272bb3d), C(76a72cb62692a655),
- C(140bb5531edf756e), C(a3c1c5ca1b0367), C(eb6933997272bb3d),
- C(76a72cb62692a655), C(140bb5531edf756e), C(8d0d8067d1c925f4),
- C(7b3fa56d8d77a10c), C(2bd00287b0946d88), C(f08c8e4bd65b8970),
C(e1843cd5)},
{C(1f2ffd79f2cdc0c8), C(726a1bc31b337aaa), C(678b7f275ef96434),
- C(5aa82bfaa99d3978), C(c18f96cade5ce18d), C(38404491f9e34c03),
- C(891fb8926ba0418c), C(5aa82bfaa99d3978), C(c18f96cade5ce18d),
- C(38404491f9e34c03), C(891fb8926ba0418c), C(e5f69a6398114c15),
- C(7b8ded3623bc6b1d), C(2f3e5c5da5ff70e8), C(1ab142addea6a9ec),
C(fda1452b)},
{C(39a9e146ec4b3210), C(f63f75802a78b1ac), C(e2e22539c94741c3),
- C(8b305d532e61226e), C(caeae80da2ea2e), C(88a6289a76ac684e),
- C(8ce5b5f9df1cbd85), C(8b305d532e61226e), C(caeae80da2ea2e),
- C(88a6289a76ac684e), C(8ce5b5f9df1cbd85), C(8ae1fc4798e00d57),
- C(e7164b8fb364fc46), C(6a978c9bd3a66943), C(ef10d5ae4dd08dc), C(a2cad330)},
+ C(a2cad330)},
{C(74cba303e2dd9d6d), C(692699b83289fad1), C(dfb9aa7874678480),
- C(751390a8a5c41bdc), C(6ee5fbf87605d34), C(6ca73f610f3a8f7c),
- C(e898b3c996570ad), C(751390a8a5c41bdc), C(6ee5fbf87605d34),
- C(6ca73f610f3a8f7c), C(e898b3c996570ad), C(98168a5858fc7110),
- C(6f987fa27aa0daa2), C(f25e3e180d4b36a3), C(d0b03495aeb1be8a),
C(53467e16)},
{C(4cbc2b73a43071e0), C(56c5db4c4ca4e0b7), C(1b275a162f46bd3d),
- C(b87a326e413604bf), C(d8f9a5fa214b03ab), C(8a8bb8265771cf88),
- C(a655319054f6e70f), C(b87a326e413604bf), C(d8f9a5fa214b03ab),
- C(8a8bb8265771cf88), C(a655319054f6e70f), C(b499cb8e65a9af44),
- C(bee7fafcc8307491), C(5d2e55fa9b27cda2), C(63b120f5fb2d6ee5),
C(da14a8d0)},
{C(875638b9715d2221), C(d9ba0615c0c58740), C(616d4be2dfe825aa),
- C(5df25f13ea7bc284), C(165edfaafd2598fb), C(af7215c5c718c696),
- C(e9f2f9ca655e769), C(5df25f13ea7bc284), C(165edfaafd2598fb),
- C(af7215c5c718c696), C(e9f2f9ca655e769), C(e459cfcb565d3d2d),
- C(41d032631be2418a), C(c505db05fd946f60), C(54990394a714f5de),
C(67333551)},
{C(fb686b2782994a8d), C(edee60693756bb48), C(e6bc3cae0ded2ef5),
- C(58eb4d03b2c3ddf5), C(6d2542995f9189f1), C(c0beec58a5f5fea2),
- C(ed67436f42e2a78b), C(58eb4d03b2c3ddf5), C(6d2542995f9189f1),
- C(c0beec58a5f5fea2), C(ed67436f42e2a78b), C(dfec763cdb2b5193),
- C(724a8d5345bd2d6), C(94d4fd1b81457c23), C(28e87c50cdede453), C(a0ebd66e)},
+ C(a0ebd66e)},
{C(ab21d81a911e6723), C(4c31b07354852f59), C(835da384c9384744),
- C(7f759dddc6e8549a), C(616dd0ca022c8735), C(94717ad4bc15ceb3),
- C(f66c7be808ab36e), C(7f759dddc6e8549a), C(616dd0ca022c8735),
- C(94717ad4bc15ceb3), C(f66c7be808ab36e), C(af8286b550b2f4b7),
- C(745bd217d20a9f40), C(c73bfb9c5430f015), C(55e65922666e3fc2),
C(4b769593)},
{C(33d013cc0cd46ecf), C(3de726423aea122c), C(116af51117fe21a9),
- C(f271ba474edc562d), C(e6596e67f9dd3ebd), C(c0a288edf808f383),
- C(b3def70681c6babc), C(f271ba474edc562d), C(e6596e67f9dd3ebd),
- C(c0a288edf808f383), C(b3def70681c6babc), C(7da7864e9989b095),
- C(bf2f8718693cd8a1), C(264a9144166da776), C(61ad90676870beb6),
C(6aa75624)},
- {C(8ca92c7cd39fae5d), C(317e620e1bf20f1), C(4f0b33bf2194b97f),
- C(45744afcf131dbee), C(97222392c2559350), C(498a19b280c6d6ed),
- C(83ac2c36acdb8d49), C(45744afcf131dbee), C(97222392c2559350),
- C(498a19b280c6d6ed), C(83ac2c36acdb8d49), C(7a69645c294daa62),
- C(abe9d2be8275b3d2), C(39542019de371085), C(7f4efac8488cd6ad),
- C(602a3f96)},
- {C(fdde3b03f018f43e), C(38f932946c78660), C(c84084ce946851ee),
- C(b6dd09ba7851c7af), C(570de4e1bb13b133), C(c4e784eb97211642),
- C(8285a7fcdcc7c58d), C(b6dd09ba7851c7af), C(570de4e1bb13b133),
- C(c4e784eb97211642), C(8285a7fcdcc7c58d), C(d421f47990da899b),
- C(8aed409c997eaa13), C(7a045929c2e29ccf), C(b373682a6202c86b),
- C(cd183c4d)},
+ {C(8ca92c7cd39fae5d), C(317e620e1bf20f1), C(4f0b33bf2194b97f), C(602a3f96)},
+ {C(fdde3b03f018f43e), C(38f932946c78660), C(c84084ce946851ee), C(cd183c4d)},
{C(9c8502050e9c9458), C(d6d2a1a69964beb9), C(1675766f480229b5),
- C(216e1d6c86cb524c), C(d01cf6fd4f4065c0), C(fffa4ec5b482ea0f),
- C(a0e20ee6a5404ac1), C(216e1d6c86cb524c), C(d01cf6fd4f4065c0),
- C(fffa4ec5b482ea0f), C(a0e20ee6a5404ac1), C(c1b037e4eebaf85e),
- C(634e3d7c3ebf89eb), C(bcda972358c67d1), C(fd1352181e5b8578), C(960a4d07)},
+ C(960a4d07)},
{C(348176ca2fa2fdd2), C(3a89c514cc360c2d), C(9f90b8afb318d6d0),
- C(bceee07c11a9ac30), C(2e2d47dff8e77eb7), C(11a394cd7b6d614a),
- C(1d7c41d54e15cb4a), C(bceee07c11a9ac30), C(2e2d47dff8e77eb7),
- C(11a394cd7b6d614a), C(1d7c41d54e15cb4a), C(15baa5ae7312b0fc),
- C(f398f596cc984635), C(8ab8fdf87a6788e8), C(b2b5c1234ab47e2), C(9ae998c4)},
+ C(9ae998c4)},
{C(4a3d3dfbbaea130b), C(4e221c920f61ed01), C(553fd6cd1304531f),
- C(bd2b31b5608143fe), C(ab717a10f2554853), C(293857f04d194d22),
- C(d51be8fa86f254f0), C(bd2b31b5608143fe), C(ab717a10f2554853),
- C(293857f04d194d22), C(d51be8fa86f254f0), C(1eee39e07686907e),
- C(639039fe0e8d3052), C(d6ec1470cef97ff), C(370c82b860034f0f), C(74e2179d)},
+ C(74e2179d)},
{C(b371f768cdf4edb9), C(bdef2ace6d2de0f0), C(e05b4100f7f1baec),
- C(b9e0d415b4ebd534), C(c97c2a27efaa33d7), C(591cdb35f84ef9da),
- C(a57d02d0e8e3756c), C(b9e0d415b4ebd534), C(c97c2a27efaa33d7),
- C(591cdb35f84ef9da), C(a57d02d0e8e3756c), C(23f55f12d7c5c87b),
- C(4c7ca0fe23221101), C(dbc3020480334564), C(d985992f32c236b1),
C(ee9bae25)},
- {C(7a1d2e96934f61f), C(eb1760ae6af7d961), C(887eb0da063005df),
- C(2228d6725e31b8ab), C(9b98f7e4d0142e70), C(b6a8c2115b8e0fe7),
- C(b591e2f5ab9b94b1), C(2228d6725e31b8ab), C(9b98f7e4d0142e70),
- C(b6a8c2115b8e0fe7), C(b591e2f5ab9b94b1), C(6c1feaa8065318e0),
- C(4e7e2ca21c2e81fb), C(e9fe5d8ce7993c45), C(ee411fa2f12cf8df),
- C(b66edf10)},
+ {C(7a1d2e96934f61f), C(eb1760ae6af7d961), C(887eb0da063005df), C(b66edf10)},
{C(8be53d466d4728f2), C(86a5ac8e0d416640), C(984aa464cdb5c8bb),
- C(87049e68f5d38e59), C(7d8ce44ec6bd7751), C(cc28d08ab414839c),
- C(6c8f0bd34fe843e3), C(87049e68f5d38e59), C(7d8ce44ec6bd7751),
- C(cc28d08ab414839c), C(6c8f0bd34fe843e3), C(b8496dcdc01f3e47),
- C(2f03125c282ac26), C(82a8797ba3f5ef07), C(7c977a4d10bf52b8), C(d6209737)},
- {C(829677eb03abf042), C(43cad004b6bc2c0), C(f2f224756803971a),
- C(98d0dbf796480187), C(fbcb5f3e1bef5742), C(5af2a0463bf6e921),
- C(ad9555bf0120b3a3), C(98d0dbf796480187), C(fbcb5f3e1bef5742),
- C(5af2a0463bf6e921), C(ad9555bf0120b3a3), C(283e39b3dc99f447),
- C(bedaa1a4a0250c28), C(9d50546624ff9a57), C(4abaf523d1c090f6), C(b994a88)},
- {C(754435bae3496fc), C(5707fc006f094dcf), C(8951c86ab19d8e40),
- C(57c5208e8f021a77), C(f7653fbb69cd9276), C(a484410af21d75cb),
- C(f19b6844b3d627e8), C(57c5208e8f021a77), C(f7653fbb69cd9276),
- C(a484410af21d75cb), C(f19b6844b3d627e8), C(f37400fc3ffd9514),
- C(36ae0d821734edfd), C(5f37820af1f1f306), C(be637d40e6a5ad0), C(a05d43c0)},
+ C(d6209737)},
+ {C(829677eb03abf042), C(43cad004b6bc2c0), C(f2f224756803971a), C(b994a88)},
+ {C(754435bae3496fc), C(5707fc006f094dcf), C(8951c86ab19d8e40), C(a05d43c0)},
{C(fda9877ea8e3805f), C(31e868b6ffd521b7), C(b08c90681fb6a0fd),
- C(68110a7f83f5d3ff), C(6d77e045901b85a8), C(84ef681113036d8b),
- C(3b9f8e3928f56160), C(68110a7f83f5d3ff), C(6d77e045901b85a8),
- C(84ef681113036d8b), C(3b9f8e3928f56160), C(fc8b7f56c130835),
- C(a11f3e800638e841), C(d9572267f5cf28c1), C(7897c8149803f2aa),
C(c79f73a8)},
{C(2e36f523ca8f5eb5), C(8b22932f89b27513), C(331cd6ecbfadc1bb),
- C(d1bfe4df12b04cbf), C(f58c17243fd63842), C(3a453cdba80a60af),
- C(5737b2ca7470ea95), C(d1bfe4df12b04cbf), C(f58c17243fd63842),
- C(3a453cdba80a60af), C(5737b2ca7470ea95), C(54d44a3f4477030c),
- C(8168e02d4869aa7f), C(77f383a17778559d), C(95e1737d77a268fc),
C(a490aff5)},
{C(21a378ef76828208), C(a5c13037fa841da2), C(506d22a53fbe9812),
- C(61c9c95d91017da5), C(16f7c83ba68f5279), C(9c0619b0808d05f7),
- C(83c117ce4e6b70a3), C(61c9c95d91017da5), C(16f7c83ba68f5279),
- C(9c0619b0808d05f7), C(83c117ce4e6b70a3), C(cfb4c8af7fd01413),
- C(fdef04e602e72296), C(ed6124d337889b1), C(4919c86707b830da), C(dfad65b4)},
- {C(ccdd5600054b16ca), C(f78846e84204cb7b), C(1f9faec82c24eac9),
- C(58634004c7b2d19a), C(24bb5f51ed3b9073), C(46409de018033d00),
- C(4a9805eed5ac802e), C(58634004c7b2d19a), C(24bb5f51ed3b9073),
- C(46409de018033d00), C(4a9805eed5ac802e), C(e18de8db306baf82),
- C(46bbf75f1fa025ff), C(5faf2fb09be09487), C(3fbc62bd4e558fb3), C(1d07dfb)},
+ C(dfad65b4)},
+ {C(ccdd5600054b16ca), C(f78846e84204cb7b), C(1f9faec82c24eac9), C(1d07dfb)},
{C(7854468f4e0cabd0), C(3a3f6b4f098d0692), C(ae2423ec7799d30d),
- C(29c3529eb165eeba), C(443de3703b657c35), C(66acbce31ae1bc8d),
- C(1acc99effe1d547e), C(29c3529eb165eeba), C(443de3703b657c35),
- C(66acbce31ae1bc8d), C(1acc99effe1d547e), C(cf07f8a57906573d),
- C(31bafb0bbb9a86e7), C(40c69492702a9346), C(7df61fdaa0b858af),
C(416df9a0)},
{C(7f88db5346d8f997), C(88eac9aacc653798), C(68a4d0295f8eefa1),
- C(ae59ca86f4c3323d), C(25906c09906d5c4c), C(8dd2aa0c0a6584ae),
- C(232a7d96b38f40e9), C(ae59ca86f4c3323d), C(25906c09906d5c4c),
- C(8dd2aa0c0a6584ae), C(232a7d96b38f40e9), C(8986ee00a2ed0042),
- C(c49ae7e428c8a7d1), C(b7dd8280713ac9c2), C(e018720aed1ebc28),
C(1f8fb9cc)},
{C(bb3fb5fb01d60fcf), C(1b7cc0847a215eb6), C(1246c994437990a1),
- C(d4edc954c07cd8f3), C(224f47e7c00a30ab), C(d5ad7ad7f41ef0c6),
- C(59e089281d869fd7), C(d4edc954c07cd8f3), C(224f47e7c00a30ab),
- C(d5ad7ad7f41ef0c6), C(59e089281d869fd7), C(f29340d07a14b6f1),
- C(c87c5ef76d9c4ef3), C(463118794193a9a), C(2922dcb0540f0dbc), C(7abf48e3)},
+ C(7abf48e3)},
{C(2e783e1761acd84d), C(39158042bac975a0), C(1cd21c5a8071188d),
- C(b1b7ec44f9302176), C(5cb476450dc0c297), C(dc5ef652521ef6a2),
- C(3cc79a9e334e1f84), C(b1b7ec44f9302176), C(5cb476450dc0c297),
- C(dc5ef652521ef6a2), C(3cc79a9e334e1f84), C(769e2a283dbcc651),
- C(9f24b105c8511d3f), C(c31c15575de2f27e), C(ecfecf32c3ae2d66),
C(dea4e3dd)},
{C(392058251cf22acc), C(944ec4475ead4620), C(b330a10b5cb94166),
- C(54bc9bee7cbe1767), C(485820bdbe442431), C(54d6120ea2972e90),
- C(f437a0341f29b72a), C(54bc9bee7cbe1767), C(485820bdbe442431),
- C(54d6120ea2972e90), C(f437a0341f29b72a), C(8f30885c784d5704),
- C(aa95376b16c7906a), C(e826928cfaf93dc3), C(20e8f54d1c16d7d8),
C(c6064f22)},
- {C(adf5c1e5d6419947), C(2a9747bc659d28aa), C(95c5b8cb1f5d62c),
- C(80973ea532b0f310), C(a471829aa9c17dd9), C(c2ff3479394804ab),
- C(6bf44f8606753636), C(80973ea532b0f310), C(a471829aa9c17dd9),
- C(c2ff3479394804ab), C(6bf44f8606753636), C(5184d2973e6dd827),
- C(121b96369a332d9a), C(5c25d3475ab69e50), C(26d2961d62884168),
- C(743bed9c)},
+ {C(adf5c1e5d6419947), C(2a9747bc659d28aa), C(95c5b8cb1f5d62c), C(743bed9c)},
{C(6bc1db2c2bee5aba), C(e63b0ed635307398), C(7b2eca111f30dbbc),
- C(230d2b3e47f09830), C(ec8624a821c1caf4), C(ea6ec411cdbf1cb1),
- C(5f38ae82af364e27), C(230d2b3e47f09830), C(ec8624a821c1caf4),
- C(ea6ec411cdbf1cb1), C(5f38ae82af364e27), C(a519ef515ea7187c),
- C(6bad5efa7ebae05f), C(748abacb11a74a63), C(a28eef963d1396eb),
C(fce254d5)},
{C(b00f898229efa508), C(83b7590ad7f6985c), C(2780e70a0592e41d),
- C(7122413bdbc94035), C(e7f90fae33bf7763), C(4b6bd0fb30b12387),
- C(557359c0c44f48ca), C(7122413bdbc94035), C(e7f90fae33bf7763),
- C(4b6bd0fb30b12387), C(557359c0c44f48ca), C(d5656c3d6bc5f0d),
- C(983ff8e5e784da99), C(628479671b445bf), C(e179a1e27ce68f5d), C(e47ec9d1)},
+ C(e47ec9d1)},
{C(b56eb769ce0d9a8c), C(ce196117bfbcaf04), C(b26c3c3797d66165),
- C(5ed12338f630ab76), C(fab19fcb319116d), C(167f5f42b521724b),
- C(c4aa56c409568d74), C(5ed12338f630ab76), C(fab19fcb319116d),
- C(167f5f42b521724b), C(c4aa56c409568d74), C(75fff4b42f8e9778),
- C(94218f94710c1ea3), C(b7b05efb738b06a6), C(83fff2deabf9cd3), C(334a145c)},
+ C(334a145c)},
{C(70c0637675b94150), C(259e1669305b0a15), C(46e1dd9fd387a58d),
- C(fca4e5bc9292788e), C(cd509dc1facce41c), C(bbba575a59d82fe),
- C(4e2e71c15b45d4d3), C(fca4e5bc9292788e), C(cd509dc1facce41c),
- C(bbba575a59d82fe), C(4e2e71c15b45d4d3), C(5dc54582ead999c),
- C(72612d1571963c6f), C(30318a9d2d3d1829), C(785dd00f4cc9c9a0),
C(adec1e3c)},
{C(74c0b8a6821faafe), C(abac39d7491370e7), C(faf0b2a48a4e6aed),
- C(967e970df9673d2a), C(d465247cffa415c0), C(33a1df0ca1107722),
- C(49fc2a10adce4a32), C(967e970df9673d2a), C(d465247cffa415c0),
- C(33a1df0ca1107722), C(49fc2a10adce4a32), C(c5707e079a284308),
- C(573028266635dda6), C(f786f5eee6127fa0), C(b30d79cebfb51266),
C(f6a9fbf8)},
{C(5fb5e48ac7b7fa4f), C(a96170f08f5acbc7), C(bbf5c63d4f52a1e5),
- C(6cc09e60700563e9), C(d18f23221e964791), C(ffc23eeef7af26eb),
- C(693a954a3622a315), C(815308a32a9b0daf), C(efb2ab27bf6fd0bd),
- C(9f1ffc0986111118), C(f9a3aa1778ea3985), C(698fe54b2b93933b),
- C(dacc2b28404d0f10), C(815308a32a9b0daf), C(efb2ab27bf6fd0bd),
C(5398210c)},
};
void TestUnchanging(const uint64_t* expected, int offset, int len) {
- const uint128 u = CityHash128(data + offset, len);
- const uint128 v = CityHash128WithSeed(data + offset, len, kSeed128);
EXPECT_EQ(expected[0], CityHash64(data + offset, len));
- EXPECT_EQ(expected[15], CityHash32(data + offset, len));
+ EXPECT_EQ(expected[3], CityHash32(data + offset, len));
EXPECT_EQ(expected[1], CityHash64WithSeed(data + offset, len, kSeed0));
EXPECT_EQ(expected[2],
CityHash64WithSeeds(data + offset, len, kSeed0, kSeed1));
- EXPECT_EQ(expected[3], Uint128Low64(u));
- EXPECT_EQ(expected[4], Uint128High64(u));
- EXPECT_EQ(expected[5], Uint128Low64(v));
- EXPECT_EQ(expected[6], Uint128High64(v));
-#ifdef __SSE4_2__
- const uint128 y = CityHashCrc128(data + offset, len);
- const uint128 z = CityHashCrc128WithSeed(data + offset, len, kSeed128);
- uint64_t crc256_results[4];
- CityHashCrc256(data + offset, len, crc256_results);
- EXPECT_EQ(expected[7], Uint128Low64(y));
- EXPECT_EQ(expected[8], Uint128High64(y));
- EXPECT_EQ(expected[9], Uint128Low64(z));
- EXPECT_EQ(expected[10], Uint128High64(z));
- for (int i = 0; i < 4; i++) {
- EXPECT_EQ(expected[11 + i], crc256_results[i]);
- }
-#endif
}
TEST(CityHashTest, Unchanging) {
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index 4bf6409..4ab7a9f 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index 4543d67..9ab9890 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -221,7 +221,9 @@
}
// AbslHashValue() for hashing floating-point values
template <typename H, typename Float>
-typename std::enable_if<std::is_floating_point<Float>::value, H>::type
+typename std::enable_if<std::is_same<Float, float>::value ||
+ std::is_same<Float, double>::value,
+ H>::type
AbslHashValue(H hash_state, Float value) {
return hash_internal::hash_bytes(std::move(hash_state),
value == 0 ? 0 : value);
@@ -231,8 +233,9 @@
// For example, in x86 sizeof(long double)==16 but it only really uses 80-bits
// of it. This means we can't use hash_bytes on a long double and have to
// convert it to something else first.
-template <typename H>
-H AbslHashValue(H hash_state, long double value) {
+template <typename H, typename LongDouble>
+typename std::enable_if<std::is_same<LongDouble, long double>::value, H>::type
+AbslHashValue(H hash_state, LongDouble value) {
const int category = std::fpclassify(value);
switch (category) {
case FP_INFINITE:
@@ -264,7 +267,12 @@
// AbslHashValue() for hashing pointers
template <typename H, typename T>
H AbslHashValue(H hash_state, T* ptr) {
- return hash_internal::hash_bytes(std::move(hash_state), ptr);
+ auto v = reinterpret_cast<uintptr_t>(ptr);
+ // Due to alignment, pointers tend to have low bits as zero, and the next few
+ // bits follow a pattern since they are also multiples of some base value.
+ // Mixing the pointer twice helps prevent stuck low bits for certain alignment
+ // values.
+ return H::combine(std::move(hash_state), v, v);
}
// AbslHashValue() for hashing nullptr_t
@@ -303,13 +311,13 @@
// AbslHashValue for hashing tuples
template <typename H, typename... Ts>
-#if _MSC_VER
+#if defined(_MSC_VER)
// This SFINAE gets MSVC confused under some conditions. Let's just disable it
// for now.
H
-#else
+#else // _MSC_VER
typename std::enable_if<absl::conjunction<is_hashable<Ts>...>::value, H>::type
-#endif
+#endif // _MSC_VER
AbslHashValue(H hash_state, const std::tuple<Ts...>& t) {
return hash_internal::hash_tuple(std::move(hash_state), t,
absl::make_index_sequence<sizeof...(Ts)>());
@@ -494,6 +502,15 @@
}
return H::combine(std::move(hash_state), v.index());
}
+
+// -----------------------------------------------------------------------------
+// AbslHashValue for Other Types
+// -----------------------------------------------------------------------------
+
+// AbslHashValue for hashing std::bitset is not defined, for the same reason as
+// for vector<bool> (see std::vector above): It does not expose the raw bytes,
+// and a fallback to std::hash<> is most likely faster.
+
// -----------------------------------------------------------------------------
// hash_range_or_bytes()
@@ -518,51 +535,22 @@
return hash_state;
}
-// InvokeHashTag
-//
-// InvokeHash(H, const T&) invokes the appropriate hash implementation for a
-// hasher of type `H` and a value of type `T`. If `T` is not hashable, there
-// will be no matching overload of InvokeHash().
-// Note: Some platforms (eg MSVC) do not support the detect idiom on
-// std::hash. In those platforms the last fallback will be std::hash and
-// InvokeHash() will always have a valid overload even if std::hash<T> is not
-// valid.
-//
-// We try the following options in order:
-// * If is_uniquely_represented, hash bytes directly.
-// * ADL AbslHashValue(H, const T&) call.
-// * std::hash<T>
-
-// In MSVC we can't probe std::hash or stdext::hash because it triggers a
-// static_assert instead of failing substitution.
-#if defined(_MSC_VER)
-#undef ABSL_HASH_INTERNAL_CAN_POISON_
-#else // _MSC_VER
-#define ABSL_HASH_INTERNAL_CAN_POISON_ 1
-#endif // _MSC_VER
-
#if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
- ABSL_HASH_INTERNAL_CAN_POISON_
+ ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
+#else
+#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
#endif
-enum class InvokeHashTag {
- kUniquelyRepresented,
- kHashValue,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- kLegacyHash,
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- kStdHash,
- kNone
-};
-
// HashSelect
//
// Type trait to select the appropriate hash implementation to use.
-// HashSelect<T>::value is an instance of InvokeHashTag that indicates the best
-// available hashing mechanism.
-// See `Note` above about MSVC.
-template <typename T>
+// HashSelect::type<T> will give the proper hash implementation, to be invoked
+// as:
+// HashSelect::type<T>::Invoke(state, value)
+// Also, HashSelect::type<T>::value is a boolean equal to `true` if there is a
+// valid `Invoke` function. Types that are not hashable will have a ::value of
+// `false`.
struct HashSelect {
private:
struct State : HashStateBase<State> {
@@ -571,95 +559,75 @@
using State::HashStateBase::combine_contiguous;
};
- // `Probe<V, Tag>::value` evaluates to `V<T>::value` if it is a valid
- // expression, and `false` otherwise.
- // `Probe<V, Tag>::tag` always evaluates to `Tag`.
- template <template <typename> class V, InvokeHashTag Tag>
- struct Probe {
+ struct UniquelyRepresentedProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value)
+ -> absl::enable_if_t<is_uniquely_represented<T>::value, H> {
+ return hash_internal::hash_bytes(std::move(state), value);
+ }
+ };
+
+ struct HashValueProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+ std::is_same<H,
+ decltype(AbslHashValue(std::move(state), value))>::value,
+ H> {
+ return AbslHashValue(std::move(state), value);
+ }
+ };
+
+ struct LegacyHashProbe {
+#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+ std::is_convertible<
+ decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>()(value)),
+ size_t>::value,
+ H> {
+ return hash_internal::hash_bytes(
+ std::move(state),
+ ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
+ }
+#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ };
+
+ struct StdHashProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value)
+ -> absl::enable_if_t<type_traits_internal::IsHashable<T>::value, H> {
+ return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
+ }
+ };
+
+ template <typename Hash, typename T>
+ struct Probe : Hash {
private:
- template <typename U, typename std::enable_if<V<U>::value, int>::type = 0>
+ template <typename H, typename = decltype(H::Invoke(
+ std::declval<State>(), std::declval<const T&>()))>
static std::true_type Test(int);
template <typename U>
static std::false_type Test(char);
public:
- static constexpr InvokeHashTag kTag = Tag;
- static constexpr bool value = decltype(
- Test<absl::remove_const_t<absl::remove_reference_t<T>>>(0))::value;
+ static constexpr bool value = decltype(Test<Hash>(0))::value;
};
- template <typename U>
- using ProbeUniquelyRepresented = is_uniquely_represented<U>;
-
- template <typename U>
- using ProbeHashValue =
- std::is_same<State, decltype(AbslHashValue(std::declval<State>(),
- std::declval<const U&>()))>;
-
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- template <typename U>
- using ProbeLegacyHash =
- std::is_convertible<decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<
- U>()(std::declval<const U&>())),
- size_t>;
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-
- template <typename U>
- using ProbeStdHash =
-#if ABSL_HASH_INTERNAL_CAN_POISON_
- std::is_convertible<decltype(std::hash<U>()(std::declval<const U&>())),
- size_t>;
-#else // ABSL_HASH_INTERNAL_CAN_POISON_
- std::true_type;
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
-
- template <typename U>
- using ProbeNone = std::true_type;
-
public:
// Probe each implementation in order.
// disjunction provides short circuting wrt instantiation.
- static constexpr InvokeHashTag value = absl::disjunction<
- Probe<ProbeUniquelyRepresented, InvokeHashTag::kUniquelyRepresented>,
- Probe<ProbeHashValue, InvokeHashTag::kHashValue>,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- Probe<ProbeLegacyHash, InvokeHashTag::kLegacyHash>,
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- Probe<ProbeStdHash, InvokeHashTag::kStdHash>,
- Probe<ProbeNone, InvokeHashTag::kNone>>::kTag;
+ template <typename T>
+ using Apply = absl::disjunction< //
+ Probe<UniquelyRepresentedProbe, T>, //
+ Probe<HashValueProbe, T>, //
+ Probe<LegacyHashProbe, T>, //
+ Probe<StdHashProbe, T>, //
+ std::false_type>;
};
template <typename T>
-struct is_hashable : std::integral_constant<bool, HashSelect<T>::value !=
- InvokeHashTag::kNone> {};
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kUniquelyRepresented,
- H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(std::move(state), value);
-}
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kHashValue, H>
-InvokeHash(H state, const T& value) {
- return AbslHashValue(std::move(state), value);
-}
-
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kLegacyHash, H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(
- std::move(state), ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
-}
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kStdHash, H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
-}
+struct is_hashable
+ : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
// CityHashState
class CityHashState : public HashStateBase<CityHashState> {
@@ -869,7 +837,8 @@
template <typename H>
template <typename T, typename... Ts>
H HashStateBase<H>::combine(H state, const T& value, const Ts&... values) {
- return H::combine(hash_internal::InvokeHash(std::move(state), value),
+ return H::combine(hash_internal::HashSelect::template Apply<T>::Invoke(
+ std::move(state), value),
values...);
}
diff --git a/absl/hash/internal/print_hash_of.cc b/absl/hash/internal/print_hash_of.cc
index b6df31c..c392125 100644
--- a/absl/hash/internal/print_hash_of.cc
+++ b/absl/hash/internal/print_hash_of.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h
index 03d795b..c4cc8d0 100644
--- a/absl/hash/internal/spy_hash_state.h
+++ b/absl/hash/internal/spy_hash_state.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -39,8 +39,7 @@
template <typename T>
class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
public:
- SpyHashStateImpl()
- : error_(std::make_shared<absl::optional<std::string>>()) {
+ SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
static_assert(std::is_void<T>::value, "");
}
@@ -170,7 +169,6 @@
// AbslHashValue directly (because the hash state type does not match).
static bool direct_absl_hash_value_error_;
-
std::vector<std::string> hash_representation_;
// This is a shared_ptr because we want all instances of the particular
// SpyHashState run to share the field. This way we can set the error for
@@ -200,7 +198,7 @@
template <
typename T, typename U,
// Only trigger for when (T != U),
- absl::enable_if_t<!std::is_same<T, U>::value, int> = 0,
+ typename = absl::enable_if_t<!std::is_same<T, U>::value>,
// This statement works in two ways:
// - First, it instantiates RunOnStartup and forces the initialization of
// `run`, which set the global variable.
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
index 89a312e..7c6366f 100644
--- a/absl/memory/BUILD.bazel
+++ b/absl/memory/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt
index 5958f5c..0a81220 100644
--- a/absl/memory/CMakeLists.txt
+++ b/absl/memory/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,58 +14,45 @@
# limitations under the License.
#
-list(APPEND MEMORY_PUBLIC_HEADERS
- "memory.h"
-)
-
-
-absl_header_library(
- TARGET
- absl_memory
- EXPORT_NAME
+absl_cc_library(
+ NAME
memory
+ HDRS
+ "memory.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::meta
+ PUBLIC
)
-#
-## TESTS
-#
-
-# test memory_test
-list(APPEND MEMORY_TEST_SRC
- "memory_test.cc"
- ${MEMORY_PUBLIC_HEADERS}
-)
-set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory)
-
-
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
memory_test
- SOURCES
- ${MEMORY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMORY_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "memory_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::memory
+ absl::base
+ absl::core_headers
+ gmock_main
)
-
-# test memory_exception_safety_test
-set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc")
-set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::memory
- absl_base_internal_exception_safety_testing
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
memory_exception_safety_test
- SOURCES
- ${MEMORY_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "memory_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::memory
+ absl::exception_safety_testing
+ gmock_main
)
-
-
-
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
index 1eaec0f..5a4a1a1 100644
--- a/absl/memory/memory.h
+++ b/absl/memory/memory.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -47,19 +47,14 @@
// X* NewX(int, int);
// auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>.
//
-// The purpose of WrapUnique is to automatically deduce the pointer type. If you
-// wish to make the type explicit, for readability reasons or because you prefer
-// to use a base-class pointer rather than a derived one, just use
+// Do not call WrapUnique with an explicit type, as in
+// `WrapUnique<X>(NewX(1, 2))`. The purpose of WrapUnique is to automatically
+// deduce the pointer type. If you wish to make the type explicit, just use
// `std::unique_ptr` directly.
//
-// Example:
-// X* Factory(int, int);
-// auto x = std::unique_ptr<X>(Factory(1, 2));
+// auto x = std::unique_ptr<X>(NewX(1, 2));
// - or -
-// std::unique_ptr<X> x(Factory(1, 2));
-//
-// This has the added advantage of working whether Factory returns a raw
-// pointer or a `std::unique_ptr`.
+// std::unique_ptr<X> x(NewX(1, 2));
//
// While `absl::WrapUnique` is useful for capturing the output of a raw
// pointer factory, prefer 'absl::make_unique<T>(args...)' over
@@ -120,7 +115,7 @@
//
// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
// see Herb Sutter's explanation on
-// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/].
+// (Exception-Safe Function Calls)[https://herbsutter.com/gotw/_102/].
// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
//
// Example usage:
@@ -599,7 +594,7 @@
return a.max_size();
}
static size_type max_size_impl(char, const Alloc&) {
- return std::numeric_limits<size_type>::max() / sizeof(value_type);
+ return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
}
template <typename A>
@@ -646,7 +641,7 @@
: memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
std::false_type> {};
-#if ABSL_ALLOCATOR_NOTHROW
+#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
template <typename T>
struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
struct default_allocator_is_nothrow : std::true_type {};
@@ -655,59 +650,42 @@
#endif
namespace memory_internal {
-#ifdef ABSL_HAVE_EXCEPTIONS // ConstructRange
template <typename Allocator, typename Iterator, typename... Args>
void ConstructRange(Allocator& alloc, Iterator first, Iterator last,
const Args&... args) {
for (Iterator cur = first; cur != last; ++cur) {
- try {
- std::allocator_traits<Allocator>::construct(alloc, cur, args...);
- } catch (...) {
+ ABSL_INTERNAL_TRY {
+ std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
+ args...);
+ }
+ ABSL_INTERNAL_CATCH_ANY {
while (cur != first) {
--cur;
- std::allocator_traits<Allocator>::destroy(alloc, cur);
+ std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
}
- throw;
+ ABSL_INTERNAL_RETHROW;
}
}
}
-#else // ABSL_HAVE_EXCEPTIONS // ConstructRange
-template <typename Allocator, typename Iterator, typename... Args>
-void ConstructRange(Allocator& alloc, Iterator first, Iterator last,
- const Args&... args) {
- for (; first != last; ++first) {
- std::allocator_traits<Allocator>::construct(alloc, first, args...);
- }
-}
-#endif // ABSL_HAVE_EXCEPTIONS // ConstructRange
-#ifdef ABSL_HAVE_EXCEPTIONS // CopyRange
template <typename Allocator, typename Iterator, typename InputIterator>
void CopyRange(Allocator& alloc, Iterator destination, InputIterator first,
InputIterator last) {
for (Iterator cur = destination; first != last;
static_cast<void>(++cur), static_cast<void>(++first)) {
- try {
- std::allocator_traits<Allocator>::construct(alloc, cur, *first);
- } catch (...) {
+ ABSL_INTERNAL_TRY {
+ std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
+ *first);
+ }
+ ABSL_INTERNAL_CATCH_ANY {
while (cur != destination) {
--cur;
- std::allocator_traits<Allocator>::destroy(alloc, cur);
+ std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
}
- throw;
+ ABSL_INTERNAL_RETHROW;
}
}
}
-#else // ABSL_HAVE_EXCEPTIONS // CopyRange
-template <typename Allocator, typename Iterator, typename InputIterator>
-void CopyRange(Allocator& alloc, Iterator destination, InputIterator first,
- InputIterator last) {
- for (; first != last;
- static_cast<void>(++destination), static_cast<void>(++first)) {
- std::allocator_traits<Allocator>::construct(alloc, destination, *first);
- }
-}
-#endif // ABSL_HAVE_EXCEPTIONS // CopyRange
} // namespace memory_internal
} // namespace absl
diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc
index 00d2b19..a1c3970 100644
--- a/absl/memory/memory_exception_safety_test.cc
+++ b/absl/memory/memory_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
index 2e453e2..8905433 100644
--- a/absl/memory/memory_test.cc
+++ b/absl/memory/memory_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -69,6 +69,45 @@
EXPECT_EQ("hi", *p);
}
+// InitializationVerifier fills in a pattern when allocated so we can
+// distinguish between its default and value initialized states (without
+// accessing truly uninitialized memory).
+struct InitializationVerifier {
+ static constexpr int kDefaultScalar = 0x43;
+ static constexpr int kDefaultArray = 0x4B;
+
+ static void* operator new(size_t n) {
+ void* ret = ::operator new(n);
+ memset(ret, kDefaultScalar, n);
+ return ret;
+ }
+
+ static void* operator new[](size_t n) {
+ void* ret = ::operator new[](n);
+ memset(ret, kDefaultArray, n);
+ return ret;
+ }
+
+ int a;
+ int b;
+};
+
+TEST(Initialization, MakeUnique) {
+ auto p = absl::make_unique<InitializationVerifier>();
+
+ EXPECT_EQ(0, p->a);
+ EXPECT_EQ(0, p->b);
+}
+
+TEST(Initialization, MakeUniqueArray) {
+ auto p = absl::make_unique<InitializationVerifier[]>(2);
+
+ EXPECT_EQ(0, p[0].a);
+ EXPECT_EQ(0, p[0].b);
+ EXPECT_EQ(0, p[1].a);
+ EXPECT_EQ(0, p[1].b);
+}
+
struct MoveOnly {
MoveOnly() = default;
explicit MoveOnly(int i1) : ip1{new int{i1}} {}
@@ -145,7 +184,7 @@
explicit TakesStdType(const std::vector<int> &vec) {}
};
using absl::make_unique;
- make_unique<TakesStdType>(std::vector<int>());
+ (void)make_unique<TakesStdType>(std::vector<int>());
}
#if 0
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index dbc9717..1c39fa9 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -1,5 +1,5 @@
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index adb0ceb..74d4a54 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,39 +14,37 @@
# limitations under the License.
#
-list(APPEND META_PUBLIC_HEADERS
- "type_traits.h"
+absl_cc_library(
+ NAME
+ type_traits
+ HDRS
+ "type_traits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-# test type_traits_test
-list(APPEND TYPE_TRAITS_TEST_SRC
- "type_traits_test.cc"
- ${META_PUBLIC_HEADERS}
-)
-
-absl_header_library(
- TARGET
- absl_meta
- PUBLIC_LIBRARIES
- absl::base
- EXPORT_NAME
- meta
- )
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
type_traits_test
- SOURCES
- ${TYPE_TRAITS_TEST_SRC}
- PUBLIC_LIBRARIES
+ SRCS
+ "type_traits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
absl::base
- absl::meta
+ absl::core_headers
+ gmock_main
)
-
-
+# component target
+absl_cc_library(
+ NAME
+ meta
+ DEPS
+ absl::type_traits
+ PUBLIC
+)
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index 23ebd6e..fbdc921 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,7 +22,7 @@
// support type inference, classification, and transformation, as well as
// make it easier to write templates based on generic type behavior.
//
-// See http://en.cppreference.com/w/cpp/header/type_traits
+// See https://en.cppreference.com/w/cpp/header/type_traits
//
// WARNING: use of many of the constructs in this header will count as "complex
// template metaprogramming", so before proceeding, please carefully consider
@@ -246,7 +246,7 @@
// For the purposes of this check, the call to std::declval is considered
// trivial."
//
-// Notes from http://en.cppreference.com/w/cpp/types/is_constructible:
+// Notes from https://en.cppreference.com/w/cpp/types/is_constructible:
// In many implementations, is_nothrow_constructible also checks if the
// destructor throws because it is effectively noexcept(T(arg)). Same
// applies to is_trivially_constructible, which, in these implementations, also
@@ -413,24 +413,139 @@
using result_of_t = typename std::result_of<T>::type;
namespace type_traits_internal {
+// In MSVC we can't probe std::hash or stdext::hash because it triggers a
+// static_assert instead of failing substitution. Libc++ prior to 4.0
+// also used a static_assert.
+//
+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
+ _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
+#else
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
+#endif
+
+#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = size_t>
+struct IsHashable : std::true_type {};
+#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+template <typename Key, typename = void>
struct IsHashable : std::false_type {};
template <typename Key>
-struct IsHashable<Key,
- decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
- : std::true_type {};
+struct IsHashable<
+ Key,
+ absl::enable_if_t<std::is_convertible<
+ decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
+ std::size_t>::value>> : std::true_type {};
+#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
-template <typename Key>
-struct IsHashEnabled
- : absl::conjunction<std::is_default_constructible<std::hash<Key>>,
- std::is_copy_constructible<std::hash<Key>>,
- std::is_destructible<std::hash<Key>>,
- absl::is_copy_assignable<std::hash<Key>>,
- IsHashable<Key>> {};
+struct AssertHashEnabledHelper {
+ private:
+ static void Sink(...) {}
+ struct NAT {};
+
+ template <class Key>
+ static auto GetReturnType(int)
+ -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
+ template <class Key>
+ static NAT GetReturnType(...);
+
+ template <class Key>
+ static std::nullptr_t DoIt() {
+ static_assert(IsHashable<Key>::value,
+ "std::hash<Key> does not provide a call operator");
+ static_assert(
+ std::is_default_constructible<std::hash<Key>>::value,
+ "std::hash<Key> must be default constructible when it is enabled");
+ static_assert(
+ std::is_copy_constructible<std::hash<Key>>::value,
+ "std::hash<Key> must be copy constructible when it is enabled");
+ static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
+ "std::hash<Key> must be copy assignable when it is enabled");
+ // is_destructible is unchecked as it's implied by each of the
+ // is_constructible checks.
+ using ReturnType = decltype(GetReturnType<Key>(0));
+ static_assert(std::is_same<ReturnType, NAT>::value ||
+ std::is_same<ReturnType, size_t>::value,
+ "std::hash<Key> must return size_t");
+ return nullptr;
+ }
+
+ template <class... Ts>
+ friend void AssertHashEnabled();
+};
+
+template <class... Ts>
+inline void AssertHashEnabled() {
+ using Helper = AssertHashEnabledHelper;
+ Helper::Sink(Helper::DoIt<Ts>()...);
+}
} // namespace type_traits_internal
+// An internal namespace that is required to implement the C++17 swap traits.
+// It is not further nested in type_traits_internal to avoid long symbol names.
+namespace swap_internal {
+
+// Necessary for the traits.
+using std::swap;
+
+// This declaration prevents global `swap` and `absl::swap` overloads from being
+// considered unless ADL picks them up.
+void swap();
+
+template <class T>
+using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>()));
+
+// NOTE: This dance with the default template parameter is for MSVC.
+template <class T,
+ class IsNoexcept = std::integral_constant<
+ bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>>
+using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type;
+
+// IsSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T`.
+template <class T>
+struct IsSwappable
+ : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {};
+
+// IsNothrowSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T` and is noexcept.
+template <class T>
+struct IsNothrowSwappable
+ : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {};
+
+// Swap()
+//
+// Performs the swap idiom from a namespace where valid candidates may only be
+// found in `std` or via ADL.
+template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0>
+void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) {
+ swap(lhs, rhs);
+}
+
+// StdSwapIsUnconstrained
+//
+// Some standard library implementations are broken in that they do not
+// constrain `std::swap`. This will effectively tell us if we are dealing with
+// one of those implementations.
+using StdSwapIsUnconstrained = IsSwappable<void()>;
+
+} // namespace swap_internal
+
+namespace type_traits_internal {
+
+// Make the swap-related traits/function accessible from this namespace.
+using swap_internal::IsNothrowSwappable;
+using swap_internal::IsSwappable;
+using swap_internal::Swap;
+using swap_internal::StdSwapIsUnconstrained;
+
+} // namespace type_traits_internal
} // namespace absl
#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index f51f5de..912336e 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -953,4 +953,85 @@
#endif // _LIBCPP_VERSION
}
+namespace adl_namespace {
+
+struct DeletedSwap {
+};
+
+void swap(DeletedSwap&, DeletedSwap&) = delete;
+
+struct SpecialNoexceptSwap {
+ SpecialNoexceptSwap(SpecialNoexceptSwap&&) {}
+ SpecialNoexceptSwap& operator=(SpecialNoexceptSwap&&) { return *this; }
+ ~SpecialNoexceptSwap() = default;
+};
+
+void swap(SpecialNoexceptSwap&, SpecialNoexceptSwap&) noexcept {}
+
+} // namespace adl_namespace
+
+TEST(TypeTraitsTest, IsSwappable) {
+ using absl::type_traits_internal::IsSwappable;
+ using absl::type_traits_internal::StdSwapIsUnconstrained;
+
+ EXPECT_TRUE(IsSwappable<int>::value);
+
+ struct S {};
+ EXPECT_TRUE(IsSwappable<S>::value);
+
+ struct NoConstruct {
+ NoConstruct(NoConstruct&&) = delete;
+ NoConstruct& operator=(NoConstruct&&) { return *this; }
+ ~NoConstruct() = default;
+ };
+
+ EXPECT_EQ(IsSwappable<NoConstruct>::value, StdSwapIsUnconstrained::value);
+ struct NoAssign {
+ NoAssign(NoAssign&&) {}
+ NoAssign& operator=(NoAssign&&) = delete;
+ ~NoAssign() = default;
+ };
+
+ EXPECT_EQ(IsSwappable<NoAssign>::value, StdSwapIsUnconstrained::value);
+
+ EXPECT_FALSE(IsSwappable<adl_namespace::DeletedSwap>::value);
+
+ EXPECT_TRUE(IsSwappable<adl_namespace::SpecialNoexceptSwap>::value);
+}
+
+TEST(TypeTraitsTest, IsNothrowSwappable) {
+ using absl::type_traits_internal::IsNothrowSwappable;
+ using absl::type_traits_internal::StdSwapIsUnconstrained;
+
+ EXPECT_TRUE(IsNothrowSwappable<int>::value);
+
+ struct NonNoexceptMoves {
+ NonNoexceptMoves(NonNoexceptMoves&&) {}
+ NonNoexceptMoves& operator=(NonNoexceptMoves&&) { return *this; }
+ ~NonNoexceptMoves() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NonNoexceptMoves>::value);
+
+ struct NoConstruct {
+ NoConstruct(NoConstruct&&) = delete;
+ NoConstruct& operator=(NoConstruct&&) { return *this; }
+ ~NoConstruct() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NoConstruct>::value);
+
+ struct NoAssign {
+ NoAssign(NoAssign&&) {}
+ NoAssign& operator=(NoAssign&&) = delete;
+ ~NoAssign() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NoAssign>::value);
+
+ EXPECT_FALSE(IsNothrowSwappable<adl_namespace::DeletedSwap>::value);
+
+ EXPECT_TRUE(IsNothrowSwappable<adl_namespace::SpecialNoexceptSwap>::value);
+}
+
} // namespace
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index 324ce66..7cd7ee1 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,7 @@
# limitations under the License.
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index 3360b2e..d26141c 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,49 +14,45 @@
# limitations under the License.
#
-list(APPEND NUMERIC_PUBLIC_HEADERS
- "int128.h"
-)
-
-
-# library 128
-list(APPEND INT128_SRC
- "int128.cc"
- ${NUMERIC_PUBLIC_HEADERS}
-)
-absl_library(
- TARGET
- absl_int128
- SOURCES
- ${INT128_SRC}
- PUBLIC_LIBRARIES
- ${INT128_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
int128
+ HDRS
+ "int128.h"
+ SRCS
+ "int128.cc"
+ "int128_have_intrinsic.inc"
+ "int128_no_intrinsic.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ PUBLIC
)
-
-absl_header_library(
- TARGET
- absl_numeric
- PUBLIC_LIBRARIES
- absl::int128
- EXPORT_NAME
- numeric
-)
-
-# test int128_test
-set(INT128_TEST_SRC "int128_test.cc")
-set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
int128_test
- SOURCES
- ${INT128_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INT128_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "int128_stream_test.cc"
+ "int128_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::int128
+ absl::base
+ absl::core_headers
+ absl::hash_testing
+ absl::type_traits
+ gmock_main
)
-
-
+# component target
+absl_cc_library(
+ NAME
+ numeric
+ DEPS
+ absl::int128
+ PUBLIC
+)
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
index cd79534..93b62c5 100644
--- a/absl/numeric/int128.cc
+++ b/absl/numeric/int128.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,7 +17,7 @@
#include <stddef.h>
#include <cassert>
#include <iomanip>
-#include <iostream> // NOLINT(readability/streams)
+#include <ostream> // NOLINT(readability/streams)
#include <sstream>
#include <string>
#include <type_traits>
@@ -65,7 +65,7 @@
// Long division/modulo for uint128 implemented using the shift-subtract
// division algorithm adapted from:
-// http://stackoverflow.com/questions/5386377/division-without-using
+// https://stackoverflow.com/questions/5386377/division-without-using
void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
uint128* remainder_ret) {
assert(divisor != 0);
@@ -123,6 +123,28 @@
return MakeUint128(0, static_cast<uint64_t>(v));
}
+
+#if defined(__clang__) && !defined(__SSE3__)
+// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
+// Casting from long double to uint64_t is miscompiled and drops bits.
+// It is more work, so only use when we need the workaround.
+uint128 MakeUint128FromFloat(long double v) {
+ // Go 50 bits at a time, that fits in a double
+ static_assert(std::numeric_limits<double>::digits >= 50, "");
+ static_assert(std::numeric_limits<long double>::digits <= 150, "");
+ // Undefined behavior if v is not finite or cannot fit into uint128.
+ assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128));
+
+ v = std::ldexp(v, -100);
+ uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ v = std::ldexp(v - static_cast<double>(w0), 50);
+ uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ v = std::ldexp(v - static_cast<double>(w1), 50);
+ uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) |
+ static_cast<uint128>(w2);
+}
+#endif // __clang__ && !__SSE3__
} // namespace
uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index 79b62a7..2f5b8ad 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -37,8 +37,21 @@
#include "absl/base/macros.h"
#include "absl/base/port.h"
-namespace absl {
+#if defined(_MSC_VER)
+// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
+// a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t
+// builtin type. We need to make sure not to define operator wchar_t()
+// alongside operator unsigned short() in these instances.
+#define ABSL_INTERNAL_WCHAR_T __wchar_t
+#if defined(_M_X64)
+#include <intrin.h>
+#pragma intrinsic(_umul128)
+#endif // defined(_M_X64)
+#else // defined(_MSC_VER)
+#define ABSL_INTERNAL_WCHAR_T wchar_t
+#endif // defined(_MSC_VER)
+namespace absl {
// uint128
//
@@ -126,7 +139,7 @@
constexpr explicit operator unsigned char() const;
constexpr explicit operator char16_t() const;
constexpr explicit operator char32_t() const;
- constexpr explicit operator wchar_t() const;
+ constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const;
constexpr explicit operator short() const; // NOLINT(runtime/int)
// NOLINTNEXTLINE(runtime/int)
constexpr explicit operator unsigned short() const;
@@ -227,8 +240,8 @@
// TODO(strel) add operator>>(std::istream&, uint128)
constexpr uint128 Uint128Max() {
- return uint128(std::numeric_limits<uint64_t>::max(),
- std::numeric_limits<uint64_t>::max());
+ return uint128((std::numeric_limits<uint64_t>::max)(),
+ (std::numeric_limits<uint64_t>::max)());
}
} // namespace absl
@@ -266,9 +279,9 @@
#endif // ABSL_HAVE_INTRINSIC_INT128
static constexpr bool tinyness_before = false;
- static constexpr absl::uint128 min() { return 0; }
+ static constexpr absl::uint128 (min)() { return 0; }
static constexpr absl::uint128 lowest() { return 0; }
- static constexpr absl::uint128 max() { return absl::Uint128Max(); }
+ static constexpr absl::uint128 (max)() { return absl::Uint128Max(); }
static constexpr absl::uint128 epsilon() { return 0; }
static constexpr absl::uint128 round_error() { return 0; }
static constexpr absl::uint128 infinity() { return 0; }
@@ -384,13 +397,13 @@
constexpr uint128::uint128(int v)
: lo_{static_cast<uint64_t>(v)},
- hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+ hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
constexpr uint128::uint128(long v) // NOLINT(runtime/int)
: lo_{static_cast<uint64_t>(v)},
- hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+ hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
constexpr uint128::uint128(long long v) // NOLINT(runtime/int)
: lo_{static_cast<uint64_t>(v)},
- hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+ hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {}
// NOLINTNEXTLINE(runtime/int)
@@ -413,13 +426,13 @@
: hi_{high}, lo_{low} {}
constexpr uint128::uint128(int v)
- : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+ : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
lo_{static_cast<uint64_t>(v)} {}
constexpr uint128::uint128(long v) // NOLINT(runtime/int)
- : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+ : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
lo_{static_cast<uint64_t>(v)} {}
constexpr uint128::uint128(long long v) // NOLINT(runtime/int)
- : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+ : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
lo_{static_cast<uint64_t>(v)} {}
constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {}
@@ -463,8 +476,8 @@
return static_cast<char32_t>(lo_);
}
-constexpr uint128::operator wchar_t() const {
- return static_cast<wchar_t>(lo_);
+constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const {
+ return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_);
}
// NOLINTNEXTLINE(runtime/int)
@@ -661,6 +674,12 @@
// can be used for uint128 storage.
return static_cast<unsigned __int128>(lhs) *
static_cast<unsigned __int128>(rhs);
+#elif defined(_MSC_VER) && defined(_M_X64)
+ uint64_t carry;
+ uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry);
+ return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) +
+ Uint128High64(lhs) * Uint128Low64(rhs) + carry,
+ low);
#else // ABSL_HAVE_INTRINSIC128
uint64_t a32 = Uint128Low64(lhs) >> 32;
uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
@@ -708,4 +727,6 @@
} // namespace absl
+#undef ABSL_INTERNAL_WCHAR_T
+
#endif // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
index 1cb7d0e..a5502d9 100644
--- a/absl/numeric/int128_benchmark.cc
+++ b/absl/numeric/int128_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index ee2a093..c7ea683 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
-// included by int128.h.
+// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 0d0b3cf..046cb9b 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
-// is included by int128.h.
+// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc
index 09efaad..3cfa9dc 100644
--- a/absl/numeric/int128_stream_test.cc
+++ b/absl/numeric/int128_stream_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
index dfe3475..5e1b5ec 100644
--- a/absl/numeric/int128_test.cc
+++ b/absl/numeric/int128_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -51,7 +51,7 @@
class Uint128FloatTraitsTest : public ::testing::Test {};
typedef ::testing::Types<float, double, long double> FloatingPointTypes;
-TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes);
+TYPED_TEST_SUITE(Uint128IntegerTraitsTest, IntegerTypes);
TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) {
static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
@@ -62,7 +62,7 @@
"TypeParam must not be assignable from absl::uint128");
}
-TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes);
+TYPED_TEST_SUITE(Uint128FloatTraitsTest, FloatingPointTypes);
TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) {
static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
@@ -271,6 +271,20 @@
EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0);
EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5);
EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9);
+
+ absl::uint128 highest_precision_in_long_double =
+ ~absl::uint128{} >> (128 - std::numeric_limits<long double>::digits);
+ EXPECT_EQ(highest_precision_in_long_double,
+ static_cast<absl::uint128>(
+ static_cast<long double>(highest_precision_in_long_double)));
+ // Apply a mask just to make sure all the bits are the right place.
+ const absl::uint128 arbitrary_mask =
+ absl::MakeUint128(0xa29f622677ded751, 0xf8ca66add076f468);
+ EXPECT_EQ(highest_precision_in_long_double & arbitrary_mask,
+ static_cast<absl::uint128>(static_cast<long double>(
+ highest_precision_in_long_double & arbitrary_mask)));
+
+ EXPECT_EQ(static_cast<absl::uint128>(-0.1L), 0);
}
TEST(Uint128, OperatorAssignReturnRef) {
@@ -440,4 +454,29 @@
EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
}
+TEST(Uint128, Hash) {
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ // Some simple values
+ absl::uint128{0},
+ absl::uint128{1},
+ ~absl::uint128{},
+ // 64 bit limits
+ absl::uint128{std::numeric_limits<int64_t>::max()},
+ absl::uint128{std::numeric_limits<uint64_t>::max()} + 0,
+ absl::uint128{std::numeric_limits<uint64_t>::max()} + 1,
+ absl::uint128{std::numeric_limits<uint64_t>::max()} + 2,
+ // Keeping high same
+ absl::uint128{1} << 62,
+ absl::uint128{1} << 63,
+ // Keeping low same
+ absl::uint128{1} << 64,
+ absl::uint128{1} << 65,
+ // 128 bit limits
+ std::numeric_limits<absl::uint128>::max(),
+ std::numeric_limits<absl::uint128>::max() - 1,
+ std::numeric_limits<absl::uint128>::min() + 1,
+ std::numeric_limits<absl::uint128>::min(),
+ }));
+}
+
} // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 6d7c261..9640ff4 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -5,17 +5,16 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
@@ -413,6 +412,7 @@
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
+ ":pow10_helper",
":strings",
"//absl/base",
"//absl/base:core_headers",
@@ -471,6 +471,8 @@
srcs = ["charconv_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
+ ":pow10_helper",
+ ":str_format",
":strings",
"//absl/base",
"@com_google_googletest//:gtest_main",
@@ -659,3 +661,23 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "pow10_helper",
+ testonly = True,
+ srcs = ["internal/pow10_helper.cc"],
+ hdrs = ["internal/pow10_helper.h"],
+ visibility = ["//visibility:private"],
+)
+
+cc_test(
+ name = "pow10_helper_test",
+ srcs = ["internal/pow10_helper_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":pow10_helper",
+ ":str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/strings/BUILD.gn b/absl/strings/BUILD.gn
index 20af83c..6f5cef6 100644
--- a/absl/strings/BUILD.gn
+++ b/absl/strings/BUILD.gn
@@ -144,3 +144,21 @@
"../types:span",
]
}
+
+source_set("pow10_helper") {
+ testonly = true
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ sources = [
+ "internal/pow10_helper.cc",
+ ]
+ public = [
+ "internal/pow10_helper.h",
+ ]
+ visibility = []
+ visibility += [ ":*" ]
+}
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index f3e4162..d3393a3 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,93 +14,359 @@
# limitations under the License.
#
-
-list(APPEND STRINGS_PUBLIC_HEADERS
- "ascii.h"
- "charconv.h"
- "escaping.h"
- "match.h"
- "numbers.h"
- "str_cat.h"
- "string_view.h"
- "strip.h"
- "str_join.h"
- "str_replace.h"
- "str_split.h"
- "substitute.h"
-)
-
-
-list(APPEND STRINGS_INTERNAL_HEADERS
- "internal/char_map.h"
- "internal/charconv_bigint.h"
- "internal/charconv_parse.h"
- "internal/memutil.h"
- "internal/ostringstream.h"
- "internal/resize_uninitialized.h"
- "internal/stl_type_traits.h"
- "internal/str_join_internal.h"
- "internal/str_split_internal.h"
- "internal/utf8.h"
-)
-
-
-
-# add string library
-list(APPEND STRINGS_SRC
- "ascii.cc"
- "charconv.cc"
- "escaping.cc"
- "internal/charconv_bigint.cc"
- "internal/charconv_parse.cc"
- "internal/memutil.cc"
- "internal/memutil.h"
- "internal/utf8.cc"
- "internal/ostringstream.cc"
- "match.cc"
- "numbers.cc"
- "str_cat.cc"
- "str_replace.cc"
- "str_split.cc"
- "string_view.cc"
- "substitute.cc"
- ${STRINGS_PUBLIC_HEADERS}
- ${STRINGS_INTERNAL_HEADERS}
-)
-set(STRINGS_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
-
-absl_library(
- TARGET
- absl_strings
- SOURCES
- ${STRINGS_SRC}
- PUBLIC_LIBRARIES
- ${STRINGS_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
strings
+ HDRS
+ "ascii.h"
+ "charconv.h"
+ "escaping.h"
+ "match.h"
+ "numbers.h"
+ "str_cat.h"
+ "str_join.h"
+ "str_replace.h"
+ "str_split.h"
+ "string_view.h"
+ "strip.h"
+ "substitute.h"
+ SRCS
+ "ascii.cc"
+ "charconv.cc"
+ "escaping.cc"
+ "internal/charconv_bigint.cc"
+ "internal/charconv_bigint.h"
+ "internal/charconv_parse.cc"
+ "internal/charconv_parse.h"
+ "internal/memutil.cc"
+ "internal/memutil.h"
+ "internal/stl_type_traits.h"
+ "internal/str_join_internal.h"
+ "internal/str_split_internal.h"
+ "match.cc"
+ "numbers.cc"
+ "str_cat.cc"
+ "str_replace.cc"
+ "str_split.cc"
+ "string_view.cc"
+ "substitute.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::strings_internal
+ absl::base
+ absl::bits
+ absl::config
+ absl::core_headers
+ absl::endian
+ absl::throw_delegate
+ absl::memory
+ absl::type_traits
+ absl::int128
+ PUBLIC
)
-# add str_format library
-absl_header_library(
- TARGET
- absl_str_format
- PUBLIC_LIBRARIES
- str_format_internal
- EXPORT_NAME
+absl_cc_library(
+ NAME
+ strings_internal
+ HDRS
+ "internal/char_map.h"
+ "internal/ostringstream.h"
+ "internal/resize_uninitialized.h"
+ "internal/utf8.h"
+ SRCS
+ "internal/ostringstream.cc"
+ "internal/utf8.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::endian
+ absl::type_traits
+)
+
+absl_cc_test(
+ NAME
+ match_test
+ SRCS
+ "match_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ escaping_test
+ SRCS
+ "escaping_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ absl::fixed_array
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ ascii_test
+ SRCS
+ "ascii_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ memutil_test
+ SRCS
+ "internal/memutil.h"
+ "internal/memutil_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ utf8_test
+ SRCS
+ "internal/utf8_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ absl::base
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ string_view_test
+ SRCS
+ "string_view_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::strings
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ substitute_test
+ SRCS
+ "substitute_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_replace_test
+ SRCS
+ "str_replace_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_split_test
+ SRCS
+ "str_split_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::dynamic_annotations
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ ostringstream_test
+ SRCS
+ "internal/ostringstream_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ resize_uninitialized_test
+ SRCS
+ "internal/resize_uninitialized.h"
+ "internal/resize_uninitialized_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::type_traits
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_join_test
+ SRCS
+ "str_join_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_cat_test
+ SRCS
+ "str_cat_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ numbers_test
+ SRCS
+ "internal/numbers_test_common.h"
+ "numbers_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::pow10_helper
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ strip_test
+ SRCS
+ "strip_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ char_map_test
+ SRCS
+ "internal/char_map_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ charconv_test
+ SRCS
+ "charconv_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::str_format
+ absl::base
+ absl::pow10_helper
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ charconv_parse_test
+ SRCS
+ "internal/charconv_parse.h"
+ "internal/charconv_parse_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ charconv_bigint_test
+ SRCS
+ "internal/charconv_bigint.h"
+ "internal/charconv_bigint_test.cc"
+ "internal/charconv_parse.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
str_format
+ HDRS
+ "str_format.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::str_format_internal
+ PUBLIC
)
-# str_format_internal
-absl_library(
- TARGET
+absl_cc_library(
+ NAME
str_format_internal
- SOURCES
- "internal/str_format/arg.cc"
- "internal/str_format/bind.cc"
- "internal/str_format/extension.cc"
- "internal/str_format/float_conversion.cc"
- "internal/str_format/output.cc"
- "internal/str_format/parser.cc"
+ HDRS
"internal/str_format/arg.h"
"internal/str_format/bind.h"
"internal/str_format/checker.h"
@@ -108,356 +374,145 @@
"internal/str_format/float_conversion.h"
"internal/str_format/output.h"
"internal/str_format/parser.h"
- PUBLIC_LIBRARIES
- str_format_extension_internal
+ SRCS
+ "internal/str_format/arg.cc"
+ "internal/str_format/bind.cc"
+ "internal/str_format/extension.cc"
+ "internal/str_format/float_conversion.cc"
+ "internal/str_format/output.cc"
+ "internal/str_format/parser.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
absl::strings
- absl::base
- absl::numeric
- absl::container
+ absl::core_headers
+ absl::inlined_vector
+ absl::type_traits
+ absl::int128
absl::span
)
-# str_format_extension_internal
-absl_library(
- TARGET
- str_format_extension_internal
- SOURCES
- "internal/str_format/extension.cc"
- "internal/str_format/extension.h"
- "internal/str_format/output.cc"
- "internal/str_format/output.h"
- PUBLIC_LIBRARIES
- absl::base
- absl::strings
-)
-
-#
-## TESTS
-#
-
-# test match_test
-set(MATCH_TEST_SRC "match_test.cc")
-set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- match_test
- SOURCES
- ${MATCH_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MATCH_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test escaping_test
-set(ESCAPING_TEST_SRC "escaping_test.cc")
-set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
- escaping_test
- SOURCES
- ${ESCAPING_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ESCAPING_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test ascii_test
-set(ASCII_TEST_SRC "ascii_test.cc")
-set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- ascii_test
- SOURCES
- ${ASCII_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ASCII_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test memutil_test
-set(MEMUTIL_TEST_SRC "internal/memutil_test.cc")
-set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- memutil_test
- SOURCES
- ${MEMUTIL_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMUTIL_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test utf8_test
-set(UTF8_TEST_SRC "internal/utf8_test.cc")
-set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
- utf8_test
- SOURCES
- ${UTF8_TEST_SRC}
- PUBLIC_LIBRARIES
- ${UTF8_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test string_view_test
-set(STRING_VIEW_TEST_SRC "string_view_test.cc")
-set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_throw_delegate absl::base)
-
-absl_test(
- TARGET
- string_view_test
- SOURCES
- ${STRING_VIEW_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STRING_VIEW_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test substitute_test
-set(SUBSTITUTE_TEST_SRC "substitute_test.cc")
-set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
- substitute_test
- SOURCES
- ${SUBSTITUTE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test str_replace_test
-set(STR_REPLACE_TEST_SRC "str_replace_test.cc")
-set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate)
-
-absl_test(
- TARGET
- str_replace_test
- SOURCES
- ${STR_REPLACE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_REPLACE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test str_split_test
-set(STR_SPLIT_TEST_SRC "str_split_test.cc")
-set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate)
-
-absl_test(
- TARGET
- str_split_test
- SOURCES
- ${STR_SPLIT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_SPLIT_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test ostringstream_test
-set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc")
-set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- ostringstream_test
- SOURCES
- ${OSTRINGSTREAM_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test resize_uninitialized_test
-set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc")
-
-absl_test(
- TARGET
- resize_uninitialized_test
- SOURCES
- ${RESIZE_UNINITIALIZED_TEST_SRC}
-)
-
-
-# test str_join_test
-set(STR_JOIN_TEST_SRC "str_join_test.cc")
-set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- str_join_test
- SOURCES
- ${STR_JOIN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_JOIN_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test str_cat_test
-set(STR_CAT_TEST_SRC "str_cat_test.cc")
-set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- str_cat_test
- SOURCES
- ${STR_CAT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_CAT_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test numbers_test
-set(NUMBERS_TEST_SRC "numbers_test.cc")
-set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- numbers_test
- SOURCES
- ${NUMBERS_TEST_SRC}
- PUBLIC_LIBRARIES
- ${NUMBERS_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test strip_test
-set(STRIP_TEST_SRC "strip_test.cc")
-set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- strip_test
- SOURCES
- ${STRIP_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STRIP_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test char_map_test
-set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc")
-set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- char_map_test
- SOURCES
- ${CHAR_MAP_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHAR_MAP_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test charconv_test
-set(CHARCONV_TEST_SRC "charconv_test.cc")
-set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- charconv_test
- SOURCES
- ${CHARCONV_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test charconv_parse_test
-set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc")
-set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- charconv_parse_test
- SOURCES
- ${CHARCONV_PARSE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test charconv_bigint_test
-set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc")
-set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
- charconv_bigint_test
- SOURCES
- ${CHARCONV_BIGINT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES}
-)
-# test str_format_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_test
- SOURCES
+ SRCS
"str_format_test.cc"
- PUBLIC_LIBRARIES
- absl::base
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
absl::str_format
absl::strings
+ absl::core_headers
+ gmock_main
)
-# test str_format_bind_test
-absl_test(
- TARGET
- str_format_bind_test
- SOURCES
- "internal/str_format/bind_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
-)
-
-# test str_format_checker_test
-absl_test(
- TARGET
- str_format_checker_test
- SOURCES
- "internal/str_format/checker_test.cc"
- PUBLIC_LIBRARIES
+absl_cc_test(
+ NAME
+ str_format_extension_test
+ SRCS
+ "internal/str_format/extension_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
absl::str_format
+ absl::str_format_internal
+ gmock_main
)
-# test str_format_convert_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
+ str_format_arg_test
+ SRCS
+ "internal/str_format/arg_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format
+ absl::str_format_internal
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_format_bind_test
+ SRCS
+ "internal/str_format/bind_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_format_checker_test
+ SRCS
+ "internal/str_format/checker_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
str_format_convert_test
- SOURCES
+ SRCS
"internal/str_format/convert_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
- absl::numeric
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ absl::int128
+ gmock_main
)
-# test str_format_output_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_output_test
- SOURCES
+ SRCS
"internal/str_format/output_test.cc"
- PUBLIC_LIBRARIES
- str_format_extension_internal
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ gmock_main
)
-# test str_format_parser_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_parser_test
- SOURCES
+ SRCS
"internal/str_format/parser_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
- absl::base
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ absl::core_headers
+ gmock_main
)
+absl_cc_library(
+ NAME
+ pow10_helper
+ HDRS
+ "internal/pow10_helper.h"
+ SRCS
+ "internal/pow10_helper.cc"
+ TESTONLY
+)
+absl_cc_test(
+ NAME
+ pow10_helper_test
+ SRCS
+ "internal/pow10_helper_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::pow10_helper
+ absl::str_format
+ gmock_main
+)
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
index c9481e8..3f7c581 100644
--- a/absl/strings/ascii.cc
+++ b/absl/strings/ascii.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index 48a9da2..f9e4fd1 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc
index 8dea4b8..aca458c 100644
--- a/absl/strings/ascii_benchmark.cc
+++ b/absl/strings/ascii_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
index 9903b04..5ecd23f 100644
--- a/absl/strings/ascii_test.cc
+++ b/absl/strings/ascii_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc
index c7b8c98..bc07e7a 100644
--- a/absl/strings/charconv.cc
+++ b/absl/strings/charconv.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -551,9 +551,10 @@
int binary_exponent = Power10Exponent(parsed_decimal.exponent);
// Discard bits that are inaccurate due to truncation error. The magic
- // `mantissa_width` constants below are justified in charconv_algorithm.md.
- // They represent the number of bits in `wide_binary_mantissa` that are
- // guaranteed to be unaffected by error propagation.
+ // `mantissa_width` constants below are justified in
+ // https://abseil.io/about/design/charconv. They represent the number of bits
+ // in `wide_binary_mantissa` that are guaranteed to be unaffected by error
+ // propagation.
bool mantissa_exact;
int mantissa_width;
if (parsed_decimal.subrange_begin) {
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h
index 0735382..59f74bf 100644
--- a/absl/strings/charconv.h
+++ b/absl/strings/charconv.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc
index fd83f44..644b2ab 100644
--- a/absl/strings/charconv_benchmark.cc
+++ b/absl/strings/charconv_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index 89418fe..b58fad2 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,7 +19,9 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/strings/internal/pow10_helper.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
#ifdef _MSC_FULL_VER
#define ABSL_COMPILER_DOES_EXACT_ROUNDING 0
@@ -31,6 +33,8 @@
namespace {
+using absl::strings_internal::Pow10;
+
#if ABSL_COMPILER_DOES_EXACT_ROUNDING
// Tests that the given string is accepted by absl::from_chars, and that it
@@ -275,7 +279,8 @@
absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low);
EXPECT_EQ(expected_low, actual_low);
- std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent);
+ std::string high_rep =
+ absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent);
FloatType actual_high = 0;
absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(),
actual_high);
@@ -678,7 +683,8 @@
auto result =
absl::from_chars(input.data(), input.data() + input.size(), actual);
EXPECT_EQ(result.ec, std::errc());
- EXPECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual)
+ << absl::StrFormat("%a vs %a", expected, actual);
}
// test legal values near upper_bound
for (index = upper_bound, step = 1; index > lower_bound;
@@ -690,7 +696,8 @@
auto result =
absl::from_chars(input.data(), input.data() + input.size(), actual);
EXPECT_EQ(result.ec, std::errc());
- EXPECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual)
+ << absl::StrFormat("%a vs %a", expected, actual);
}
// Test underflow values below lower_bound
for (index = lower_bound - 1, step = 1; index > -1000000;
@@ -747,7 +754,7 @@
// acceptable exponents in this test.
TEST(FromChars, DecimalDoubleLimits) {
auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
- auto expected_gen = [](int index) { return std::pow(10.0, index); };
+ auto expected_gen = [](int index) { return Pow10(index); };
TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308);
}
@@ -759,7 +766,7 @@
// acceptable exponents in this test.
TEST(FromChars, DecimalFloatLimits) {
auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
- auto expected_gen = [](int index) { return std::pow(10.0, index); };
+ auto expected_gen = [](int index) { return Pow10(index); };
TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38);
}
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index 8d8b00b..bc8307e 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -179,7 +179,8 @@
ch = (ch << 4) + hex_digit_to_int(*++p);
if (ch > 0xFF) {
if (error) {
- *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) +
+ *error = "Value of \\" +
+ std::string(hex_start, p + 1 - hex_start) +
" exceeds 0xff";
}
return false;
@@ -294,7 +295,7 @@
// ----------------------------------------------------------------------
// CUnescapeInternal()
//
-// Same as above but uses a C++ string for output. 'source' and 'dest'
+// Same as above but uses a std::string for output. 'source' and 'dest'
// may be the same.
// ----------------------------------------------------------------------
bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
@@ -324,7 +325,8 @@
//
// Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
// ----------------------------------------------------------------------
-std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) {
+std::string CEscapeInternal(absl::string_view src, bool use_hex,
+ bool utf8_safe) {
std::string dest;
bool last_hex_escape = false; // true if last output char was \xNN.
@@ -786,7 +788,7 @@
// Base64 encodes three bytes of input at a time. If the input is not
// divisible by three, we pad as appropriate.
//
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// Special processing is performed if fewer than 24 bits are available
// at the end of the data being encoded. A full encoding quantum is
// always completed at the end of a quantity. When fewer than 24 input
@@ -800,12 +802,12 @@
size_t len = (input_len / 3) * 4;
if (input_len % 3 == 0) {
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (1) the final quantum of encoding input is an integral multiple of 24
// bits; here, the final unit of encoded output will be an integral
// multiple of 4 characters with no "=" padding,
} else if (input_len % 3 == 1) {
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (2) the final quantum of encoding input is exactly 8 bits; here, the
// final unit of encoded output will be two characters followed by two
// "=" padding characters, or
@@ -814,7 +816,7 @@
len += 2;
}
} else { // (input_len % 3 == 2)
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (3) the final quantum of encoding input is exactly 16 bits; here, the
// final unit of encoded output will be three characters followed by one
// "=" padding character.
@@ -843,8 +845,8 @@
// Three bytes of data encodes to four characters of cyphertext.
// So we can pump through three-byte chunks atomically.
- if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3
- while (cur_src < limit_src - 3) { // as long as we have >= 32 bits
+ if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3.
+ while (cur_src < limit_src - 3) { // While we have >= 32 bits.
uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
cur_dest[0] = base64[in >> 18];
@@ -1011,7 +1013,8 @@
}
}
-// This is a templated function so that T can be either a char* or a string.
+// This is a templated function so that T can be either a char* or a
+// std::string.
template <typename T>
void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
auto dest_ptr = &dest[0];
@@ -1028,7 +1031,8 @@
//
// See CUnescapeInternal() for implementation details.
// ----------------------------------------------------------------------
-bool CUnescape(absl::string_view source, std::string* dest, std::string* error) {
+bool CUnescape(absl::string_view source, std::string* dest,
+ std::string* error) {
return CUnescapeInternal(source, kUnescapeNulls, dest, error);
}
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h
index 2965973..fd9be78 100644
--- a/absl/strings/escaping.h
+++ b/absl/strings/escaping.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,7 +19,6 @@
//
// This header file contains string utilities involved in escaping and
// unescaping strings in various ways.
-//
#ifndef ABSL_STRINGS_ESCAPING_H_
#define ABSL_STRINGS_ESCAPING_H_
@@ -38,7 +37,7 @@
// CUnescape()
//
// Unescapes a `source` string and copies it into `dest`, rewriting C-style
-// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into
+// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into
// their proper code point equivalents, returning `true` if successful.
//
// The following unescape sequences can be handled:
@@ -56,7 +55,6 @@
// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and
// 0x99).
//
-//
// If any errors are encountered, this function returns `false`, leaving the
// `dest` output parameter in an unspecified state, and stores the first
// encountered error in `error`. To disable error reporting, set `error` to
@@ -80,7 +78,7 @@
// CEscape()
//
// Escapes a 'src' string using C-style escapes sequences
-// (http://en.cppreference.com/w/cpp/language/escape), escaping other
+// (https://en.cppreference.com/w/cpp/language/escape), escaping other
// non-printable/non-whitespace bytes as octal sequences (e.g. "\377").
//
// Example:
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc
index 0f791f4..10d5b03 100644
--- a/absl/strings/escaping_benchmark.cc
+++ b/absl/strings/escaping_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
index 9dc27f3..d433b4c 100644
--- a/absl/strings/escaping_test.cc
+++ b/absl/strings/escaping_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,18 +36,19 @@
TEST(CEscape, EscapeAndUnescape) {
const std::string inputs[] = {
- std::string("foo\nxx\r\b\0023"),
- std::string(""),
- std::string("abc"),
- std::string("\1chad_rules"),
- std::string("\1arnar_drools"),
- std::string("xxxx\r\t'\"\\"),
- std::string("\0xx\0", 4),
- std::string("\x01\x31"),
- std::string("abc\xb\x42\141bc"),
- std::string("123\1\x31\x32\x33"),
- std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
- std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
+ std::string("foo\nxx\r\b\0023"),
+ std::string(""),
+ std::string("abc"),
+ std::string("\1chad_rules"),
+ std::string("\1arnar_drools"),
+ std::string("xxxx\r\t'\"\\"),
+ std::string("\0xx\0", 4),
+ std::string("\x01\x31"),
+ std::string("abc\xb\x42\141bc"),
+ std::string("123\1\x31\x32\x33"),
+ std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
+ std::string(
+ "\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
};
// Do this twice, once for octal escapes and once for hex escapes.
for (int kind = 0; kind < 4; kind++) {
@@ -159,15 +160,14 @@
EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
EXPECT_EQ(out, val.unescaped);
}
- std::string bad[] =
- {"\\u1", // too short
- "\\U1", // too short
- "\\Uffffff", // exceeds 0x10ffff (largest Unicode)
- "\\U00110000", // exceeds 0x10ffff (largest Unicode)
- "\\uD835", // surrogate character (D800-DFFF)
- "\\U0000DD04", // surrogate character (D800-DFFF)
- "\\777", // exceeds 0xff
- "\\xABCD"}; // exceeds 0xff
+ std::string bad[] = {"\\u1", // too short
+ "\\U1", // too short
+ "\\Uffffff", // exceeds 0x10ffff (largest Unicode)
+ "\\U00110000", // exceeds 0x10ffff (largest Unicode)
+ "\\uD835", // surrogate character (D800-DFFF)
+ "\\U0000DD04", // surrogate character (D800-DFFF)
+ "\\777", // exceeds 0xff
+ "\\xABCD"}; // exceeds 0xff
for (const std::string& e : bad) {
std::string error;
std::string out;
@@ -258,9 +258,11 @@
// All escapes, including newlines and null escapes, should have been
// converted to the equivalent characters.
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0\n"
- "\0", 7), result_string_);
+ "0\n"
+ "\0\n"
+ "\0",
+ 7),
+ result_string_);
}
@@ -268,17 +270,21 @@
std::string original_string(kStringWithMultipleHexNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0\n"
- "\0", 7), result_string_);
+ "0\n"
+ "\0\n"
+ "\0",
+ 7),
+ result_string_);
}
TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
std::string original_string(kStringWithMultipleUnicodeNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0", 5), result_string_);
+ "0\n"
+ "\0",
+ 5),
+ result_string_);
}
static struct {
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h
index 8d92963..b9108b8 100644
--- a/absl/strings/internal/char_map.h
+++ b/absl/strings/internal/char_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc
index c45f315..5cef967 100644
--- a/absl/strings/internal/char_map_benchmark.cc
+++ b/absl/strings/internal/char_map_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc
index c3601e1..d330624 100644
--- a/absl/strings/internal/char_map_test.cc
+++ b/absl/strings/internal/char_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc
index 3e7296e..95d471d 100644
--- a/absl/strings/internal/charconv_bigint.cc
+++ b/absl/strings/internal/charconv_bigint.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h
index aa70af2..7da9a7e 100644
--- a/absl/strings/internal/charconv_bigint.h
+++ b/absl/strings/internal/charconv_bigint.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -57,17 +57,10 @@
"unsupported max_words value");
BigUnsigned() : size_(0), words_{} {}
- explicit BigUnsigned(uint32_t v) : size_(v > 0 ? 1 : 0), words_{v} {}
- explicit BigUnsigned(uint64_t v)
- : size_(0),
- words_{static_cast<uint32_t>(v & 0xffffffff),
- static_cast<uint32_t>(v >> 32)} {
- if (words_[1]) {
- size_ = 2;
- } else if (words_[0]) {
- size_ = 1;
- }
- }
+ explicit constexpr BigUnsigned(uint64_t v)
+ : size_((v >> 32) ? 2 : v ? 1 : 0),
+ words_{static_cast<uint32_t>(v & 0xffffffffu),
+ static_cast<uint32_t>(v >> 32)} {}
// Constructs a BigUnsigned from the given string_view containing a decimal
// value. If the input std::string is not a decimal integer, constructs a 0
@@ -110,12 +103,12 @@
SetToZero();
return;
}
- size_ = std::min(size_ + word_shift, max_words);
+ size_ = (std::min)(size_ + word_shift, max_words);
count %= 32;
if (count == 0) {
std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
} else {
- for (int i = std::min(size_, max_words - 1); i > word_shift; --i) {
+ for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) {
words_[i] = (words_[i - word_shift] << count) |
(words_[i - word_shift - 1] >> (32 - count));
}
@@ -274,7 +267,7 @@
void MultiplyBy(int other_size, const uint32_t* other_words) {
const int original_size = size_;
const int first_step =
- std::min(original_size + other_size - 2, max_words - 1);
+ (std::min)(original_size + other_size - 2, max_words - 1);
for (int step = first_step; step >= 0; --step) {
MultiplyStep(original_size, other_words, other_size, step);
}
@@ -293,7 +286,7 @@
value = 0;
}
}
- size_ = std::min(max_words, std::max(index + 1, size_));
+ size_ = (std::min)(max_words, (std::max)(index + 1, size_));
}
}
@@ -316,7 +309,7 @@
} else {
// Normally 32-bit AddWithCarry() sets size_, but since we don't call
// it when `high` is 0, do it ourselves here.
- size_ = std::min(max_words, std::max(index + 1, size_));
+ size_ = (std::min)(max_words, (std::max)(index + 1, size_));
}
}
}
@@ -355,7 +348,7 @@
// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs.
template <int N, int M>
int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
- int limit = std::max(lhs.size(), rhs.size());
+ int limit = (std::max)(lhs.size(), rhs.size());
for (int i = limit - 1; i >= 0; --i) {
const uint32_t lhs_word = lhs.GetWord(i);
const uint32_t rhs_word = rhs.GetWord(i);
@@ -370,7 +363,7 @@
template <int N, int M>
bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
- int limit = std::max(lhs.size(), rhs.size());
+ int limit = (std::max)(lhs.size(), rhs.size());
for (int i = 0; i < limit; ++i) {
if (lhs.GetWord(i) != rhs.GetWord(i)) {
return false;
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc
index 9b63578..745714a 100644
--- a/absl/strings/internal/charconv_bigint_test.cc
+++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
index 7e4dabc..f3c7232 100644
--- a/absl/strings/internal/charconv_parse.cc
+++ b/absl/strings/internal/charconv_parse.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/charconv_parse.h b/absl/strings/internal/charconv_parse.h
index 7a5c087..44d06b2 100644
--- a/absl/strings/internal/charconv_parse.h
+++ b/absl/strings/internal/charconv_parse.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc
index f48b9ae..9511c98 100644
--- a/absl/strings/internal/charconv_parse_test.cc
+++ b/absl/strings/internal/charconv_parse_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h
index cc41f43..bd80303 100644
--- a/absl/strings/internal/escaping_test_common.h
+++ b/absl/strings/internal/escaping_test_common.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc
index a0de70d..77aa63c 100644
--- a/absl/strings/internal/memutil.cc
+++ b/absl/strings/internal/memutil.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h
index 7de383b..7c071a8 100644
--- a/absl/strings/internal/memutil.h
+++ b/absl/strings/internal/memutil.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc
index 77915ad..dc95c3e 100644
--- a/absl/strings/internal/memutil_benchmark.cc
+++ b/absl/strings/internal/memutil_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc
index 09424de..d8681dd 100644
--- a/absl/strings/internal/memutil_test.cc
+++ b/absl/strings/internal/memutil_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h
index 20e3af5..2824720 100644
--- a/absl/strings/internal/numbers_test_common.h
+++ b/absl/strings/internal/numbers_test_common.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -64,11 +64,11 @@
inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() {
static const std::array<uint32_test_case, 27> test_cases{{
- {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+ {"0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()},
{"0x34234324", true, 16, 0x34234324},
{"34234324", true, 16, 0x34234324},
{"0", true, 16, 0},
- {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+ {" \t\n 0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()},
{" \f\v 46", true, 10, 46}, // must accept weird whitespace
{" \t\n 72717222", true, 8, 072717222},
{" \t\n 072717222", true, 8, 072717222},
@@ -77,7 +77,7 @@
// Base-10 version.
{"34234324", true, 0, 34234324},
- {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()},
+ {"4294967295", true, 0, (std::numeric_limits<uint32_t>::max)()},
{"34234324 \n\t", true, 10, 34234324},
// Unusual base
@@ -96,8 +96,8 @@
{" \t\n -123", false, 0, 0},
// Out of bounds.
- {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()},
- {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()},
+ {"4294967296", false, 0, (std::numeric_limits<uint32_t>::max)()},
+ {"0x100000000", false, 0, (std::numeric_limits<uint32_t>::max)()},
{nullptr, false, 0, 0},
}};
return test_cases;
@@ -119,7 +119,7 @@
{"000", true, 0, 0},
{"0", true, 0, 0},
{" \t\n 0xffffffffffffffff", true, 16,
- std::numeric_limits<uint64_t>::max()},
+ (std::numeric_limits<uint64_t>::max)()},
{"012345670123456701234", true, 8, int64_t{012345670123456701234}},
{"12345670123456701234", true, 8, int64_t{012345670123456701234}},
@@ -130,7 +130,7 @@
{"34234324487834466", true, 0, int64_t{34234324487834466}},
{" \t\n 18446744073709551615", true, 0,
- std::numeric_limits<uint64_t>::max()},
+ (std::numeric_limits<uint64_t>::max)()},
{"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}},
@@ -156,12 +156,13 @@
// Out of bounds.
{"18446744073709551616", false, 10, 0},
{"18446744073709551616", false, 0, 0},
- {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()},
+ {"0x10000000000000000", false, 16,
+ (std::numeric_limits<uint64_t>::max)()},
{"0X10000000000000000", false, 16,
- std::numeric_limits<uint64_t>::max()}, // 0X versus 0x.
- {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()},
+ (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x.
+ {"0x10000000000000000", false, 0, (std::numeric_limits<uint64_t>::max)()},
{"0X10000000000000000", false, 0,
- std::numeric_limits<uint64_t>::max()}, // 0X versus 0x.
+ (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x.
{"0x1234", true, 16, 0x1234},
diff --git a/absl/strings/internal/ostringstream.cc b/absl/strings/internal/ostringstream.cc
index 6ee2b10..d0f0f84 100644
--- a/absl/strings/internal/ostringstream.cc
+++ b/absl/strings/internal/ostringstream.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h
index e81a89a..2079201 100644
--- a/absl/strings/internal/ostringstream.h
+++ b/absl/strings/internal/ostringstream.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,18 +25,18 @@
namespace absl {
namespace strings_internal {
-// The same as std::ostringstream but appends to a user-specified string,
+// The same as std::ostringstream but appends to a user-specified std::string,
// and is faster. It is ~70% faster to create, ~50% faster to write to, and
-// completely free to extract the result string.
+// completely free to extract the result std::string.
//
-// string s;
+// std::string s;
// OStringStream strm(&s);
// strm << 42 << ' ' << 3.14; // appends to `s`
//
// The stream object doesn't have to be named. Starting from C++11 operator<<
// works with rvalues of std::ostream.
//
-// string s;
+// std::string s;
// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s`
//
// OStringStream is faster to create than std::ostringstream but it's still
@@ -45,14 +45,14 @@
//
// Creates unnecessary instances of OStringStream: slow.
//
-// string s;
+// std::string s;
// OStringStream(&s) << 42;
// OStringStream(&s) << ' ';
// OStringStream(&s) << 3.14;
//
// Creates a single instance of OStringStream and reuses it: fast.
//
-// string s;
+// std::string s;
// OStringStream strm(&s);
// strm << 42;
// strm << ' ';
@@ -64,8 +64,8 @@
// The argument can be null, in which case you'll need to call str(p) with a
// non-null argument before you can write to the stream.
//
- // The destructor of OStringStream doesn't use the std::string. It's OK to destroy
- // the std::string before the stream.
+ // The destructor of OStringStream doesn't use the std::string. It's OK to
+ // destroy the std::string before the stream.
explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
std::string* str() { return s_; }
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc
index c93f969..5979f18 100644
--- a/absl/strings/internal/ostringstream_benchmark.cc
+++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc
index 069a0e1..2879e50 100644
--- a/absl/strings/internal/ostringstream_test.cc
+++ b/absl/strings/internal/ostringstream_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/pow10_helper.cc b/absl/strings/internal/pow10_helper.cc
new file mode 100644
index 0000000..03ed8d0
--- /dev/null
+++ b/absl/strings/internal/pow10_helper.cc
@@ -0,0 +1,120 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/pow10_helper.h"
+
+#include <cmath>
+
+namespace absl {
+namespace strings_internal {
+
+namespace {
+
+// The exact value of 1e23 falls precisely halfway between two representable
+// doubles. Furthermore, the rounding rules we prefer (break ties by rounding
+// to the nearest even) dictate in this case that the number should be rounded
+// down, but this is not completely specified for floating-point literals in
+// C++. (It just says to use the default rounding mode of the standard
+// library.) We ensure the result we want by using a number that has an
+// unambiguous correctly rounded answer.
+constexpr double k1e23 = 9999999999999999e7;
+
+constexpr double kPowersOfTen[] = {
+ 0.0, 1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316,
+ 1e-315, 1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308, 1e-307,
+ 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299, 1e-298,
+ 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290, 1e-289,
+ 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, 1e-280,
+ 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
+ 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262,
+ 1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253,
+ 1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244,
+ 1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235,
+ 1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227, 1e-226,
+ 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218, 1e-217,
+ 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209, 1e-208,
+ 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200, 1e-199,
+ 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, 1e-190,
+ 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
+ 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172,
+ 1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163,
+ 1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154,
+ 1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145,
+ 1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137, 1e-136,
+ 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128, 1e-127,
+ 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119, 1e-118,
+ 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110, 1e-109,
+ 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, 1e-100,
+ 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91,
+ 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82,
+ 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73,
+ 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64,
+ 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55,
+ 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46,
+ 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37,
+ 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28,
+ 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19,
+ 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10,
+ 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
+ 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8,
+ 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17,
+ 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, k1e23, 1e+24, 1e+25, 1e+26,
+ 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35,
+ 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44,
+ 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53,
+ 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62,
+ 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71,
+ 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89,
+ 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98,
+ 1e+99, 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107,
+ 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116,
+ 1e+117, 1e+118, 1e+119, 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125,
+ 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134,
+ 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143,
+ 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152,
+ 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160, 1e+161,
+ 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170,
+ 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
+ 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188,
+ 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197,
+ 1e+198, 1e+199, 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206,
+ 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215,
+ 1e+216, 1e+217, 1e+218, 1e+219, 1e+220, 1e+221, 1e+222, 1e+223, 1e+224,
+ 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233,
+ 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240, 1e+241, 1e+242,
+ 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251,
+ 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
+ 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
+ 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278,
+ 1e+279, 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287,
+ 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296,
+ 1e+297, 1e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305,
+ 1e+306, 1e+307, 1e+308,
+};
+
+} // namespace
+
+double Pow10(int exp) {
+ if (exp < -324) {
+ return 0.0;
+ } else if (exp > 308) {
+ return INFINITY;
+ } else {
+ return kPowersOfTen[exp + 324];
+ }
+}
+
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h
new file mode 100644
index 0000000..9d1aa71
--- /dev/null
+++ b/absl/strings/internal/pow10_helper.h
@@ -0,0 +1,36 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This test helper library contains a table of powers of 10, to guarantee
+// precise values are computed across the full range of doubles. We can't rely
+// on the pow() function, because not all standard libraries ship a version
+// that is precise.
+#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+
+#include <vector>
+
+namespace absl {
+namespace strings_internal {
+
+// Computes the precise value of 10^exp. (I.e. the nearest representable
+// double to the exact value, rounding to nearest-even in the (single) case of
+// being exactly halfway between.)
+double Pow10(int exp);
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
diff --git a/absl/strings/internal/pow10_helper_test.cc b/absl/strings/internal/pow10_helper_test.cc
new file mode 100644
index 0000000..a4a68b5
--- /dev/null
+++ b/absl/strings/internal/pow10_helper_test.cc
@@ -0,0 +1,120 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/pow10_helper.h"
+
+#include <cmath>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+namespace strings_internal {
+
+namespace {
+
+struct TestCase {
+ int power; // Testing Pow10(power)
+ uint64_t significand; // Raw bits of the expected value
+ int radix; // significand is adjusted by 2^radix
+};
+
+TEST(Pow10HelperTest, Works) {
+ // The logic in pow10_helper.cc is so simple that theoretically we don't even
+ // need a test. However, we're paranoid and believe that there may be
+ // compilers that don't round floating-point literals correctly, even though
+ // it is specified by the standard. We check various edge cases, just to be
+ // sure.
+ constexpr TestCase kTestCases[] = {
+ // Subnormals
+ {-323, 0x2, -1074},
+ {-322, 0x14, -1074},
+ {-321, 0xca, -1074},
+ {-320, 0x7e8, -1074},
+ {-319, 0x4f10, -1074},
+ {-318, 0x316a2, -1074},
+ {-317, 0x1ee257, -1074},
+ {-316, 0x134d761, -1074},
+ {-315, 0xc1069cd, -1074},
+ {-314, 0x78a42205, -1074},
+ {-313, 0x4b6695433, -1074},
+ {-312, 0x2f201d49fb, -1074},
+ {-311, 0x1d74124e3d1, -1074},
+ {-310, 0x12688b70e62b, -1074},
+ {-309, 0xb8157268fdaf, -1074},
+ {-308, 0x730d67819e8d2, -1074},
+ // Values that are very close to rounding the other way.
+ // Comment shows difference of significand from the true value.
+ {-307, 0x11fa182c40c60d, -1072}, // -.4588
+ {-290, 0x18f2b061aea072, -1016}, // .4854
+ {-276, 0x11BA03F5B21000, -969}, // .4709
+ {-259, 0x1899C2F6732210, -913}, // .4830
+ {-252, 0x1D53844EE47DD1, -890}, // -.4743
+ {-227, 0x1E5297287C2F45, -807}, // -.4708
+ {-198, 0x1322E220A5B17E, -710}, // -.4714
+ {-195, 0x12B010D3E1CF56, -700}, // .4928
+ {-192, 0x123FF06EEA847A, -690}, // .4968
+ {-163, 0x1708D0F84D3DE7, -594}, // -.4977
+ {-145, 0x13FAAC3E3FA1F3, -534}, // -.4785
+ {-111, 0x133D4032C2C7F5, -421}, // .4774
+ {-106, 0x1D5B561574765B, -405}, // -.4869
+ {-104, 0x16EF5B40C2FC77, -398}, // -.4741
+ {-88, 0x197683DF2F268D, -345}, // -.4738
+ {-86, 0x13E497065CD61F, -338}, // .4736
+ {-76, 0x17288E1271F513, -305}, // -.4761
+ {-63, 0x1A53FC9631D10D, -262}, // .4929
+ {-30, 0x14484BFEEBC2A0, -152}, // .4758
+ {-21, 0x12E3B40A0E9B4F, -122}, // -.4916
+ {-5, 0x14F8B588E368F1, -69}, // .4829
+ {23, 0x152D02C7E14AF6, 24}, // -.5000 (exactly, round-to-even)
+ {29, 0x1431E0FAE6D721, 44}, // -.4870
+ {34, 0x1ED09BEAD87C03, 60}, // -.4721
+ {70, 0x172EBAD6DDC73D, 180}, // .4733
+ {105, 0x1BE7ABD3781ECA, 296}, // -.4850
+ {126, 0x17A2ECC414A03F, 366}, // -.4999
+ {130, 0x1CDA62055B2D9E, 379}, // .4855
+ {165, 0x115D847AD00087, 496}, // -.4913
+ {172, 0x14B378469B6732, 519}, // .4818
+ {187, 0x1262DFEEBBB0F9, 569}, // -.4805
+ {210, 0x18557F31326BBB, 645}, // -.4992
+ {212, 0x1302CB5E6F642A, 652}, // -.4838
+ {215, 0x1290BA9A38C7D1, 662}, // -.4881
+ {236, 0x1F736F9B3494E9, 731}, // .4707
+ {244, 0x176EC98994F489, 758}, // .4924
+ {250, 0x1658E3AB795204, 778}, // -.4963
+ {252, 0x117571DDF6C814, 785}, // .4873
+ {254, 0x1B4781EAD1989E, 791}, // -.4887
+ {260, 0x1A03FDE214CAF1, 811}, // .4784
+ {284, 0x1585041B2C477F, 891}, // .4798
+ {304, 0x1D2A1BE4048F90, 957}, // -.4987
+ // Out-of-range values
+ {-324, 0x0, 0},
+ {-325, 0x0, 0},
+ {-326, 0x0, 0},
+ {309, 1, 2000},
+ {310, 1, 2000},
+ {311, 1, 2000},
+ };
+ for (const TestCase& test_case : kTestCases) {
+ EXPECT_EQ(Pow10(test_case.power),
+ std::ldexp(test_case.significand, test_case.radix))
+ << absl::StrFormat("Failure for Pow10(%d): %a vs %a", test_case.power,
+ Pow10(test_case.power),
+ std::ldexp(test_case.significand, test_case.radix));
+ }
+}
+
+} // namespace
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
index a94e054..469962b 100644
--- a/absl/strings/internal/resize_uninitialized.h
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,6 +18,7 @@
#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
#include <string>
+#include <type_traits>
#include <utility>
#include "absl/base/port.h"
@@ -27,40 +28,42 @@
namespace strings_internal {
// Is a subclass of true_type or false_type, depending on whether or not
-// T has a resize_uninitialized member.
-template <typename T, typename = void>
-struct HasResizeUninitialized : std::false_type {};
-template <typename T>
-struct HasResizeUninitialized<
- T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>>
- : std::true_type {};
+// T has a __resize_default_init member.
+template <typename string_type, typename = void>
+struct ResizeUninitializedTraits {
+ using HasMember = std::false_type;
+ static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
+};
+// __resize_default_init is provided by libc++ >= 8.0 and by Google's internal
+// ::string implementation.
template <typename string_type>
-void ResizeUninit(string_type* s, size_t new_size, std::true_type) {
- s->resize_uninitialized(new_size);
-}
-template <typename string_type>
-void ResizeUninit(string_type* s, size_t new_size, std::false_type) {
- s->resize(new_size);
-}
+struct ResizeUninitializedTraits<
+ string_type, absl::void_t<decltype(std::declval<string_type&>()
+ .__resize_default_init(237))> > {
+ using HasMember = std::true_type;
+ static void Resize(string_type* s, size_t new_size) {
+ s->__resize_default_init(new_size);
+ }
+};
-// Returns true if the string implementation supports a resize where
-// the new characters added to the string are left untouched.
+// Returns true if the std::string implementation supports a resize where
+// the new characters added to the std::string are left untouched.
//
// (A better name might be "STLStringSupportsUninitializedResize", alluding to
// the previous function.)
template <typename string_type>
inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
- return HasResizeUninitialized<string_type>();
+ return ResizeUninitializedTraits<string_type>::HasMember::value;
}
// Like str->resize(new_size), except any new characters added to "*str" as a
// result of resizing may be left uninitialized, rather than being filled with
// '0' bytes. Typically used when code is then going to overwrite the backing
-// store of the string with known data. Uses a Google extension to ::string.
+// store of the std::string with known data.
template <typename string_type, typename = void>
inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
- ResizeUninit(s, new_size, HasResizeUninitialized<string_type>());
+ ResizeUninitializedTraits<string_type>::Resize(s, new_size);
}
} // namespace strings_internal
diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc
index ad282ef..c5be0b1 100644
--- a/absl/strings/internal/resize_uninitialized_test.cc
+++ b/absl/strings/internal/resize_uninitialized_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,44 +24,44 @@
void resize(size_t) { resize_call_count += 1; }
};
-int resize_uninitialized_call_count = 0;
+int resize_default_init_call_count = 0;
-struct resize_uninitializable_string {
+struct resize_default_init_string {
void resize(size_t) { resize_call_count += 1; }
- void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; }
+ void __resize_default_init(size_t) { resize_default_init_call_count += 1; }
};
TEST(ResizeUninit, WithAndWithout) {
resize_call_count = 0;
- resize_uninitialized_call_count = 0;
+ resize_default_init_call_count = 0;
{
resizable_string rs;
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_FALSE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
EXPECT_EQ(resize_call_count, 1);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
}
resize_call_count = 0;
- resize_uninitialized_call_count = 0;
+ resize_default_init_call_count = 0;
{
- resize_uninitializable_string rus;
+ resize_default_init_string rus;
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_TRUE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 1);
+ EXPECT_EQ(resize_default_init_call_count, 1);
}
}
diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h
index 04c4a53..202ab37 100644
--- a/absl/strings/internal/stl_type_traits.h
+++ b/absl/strings/internal/stl_type_traits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 3376d48..4d48af0 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -35,12 +35,14 @@
T, void_t<decltype(AbslFormatConvert(
std::declval<const T&>(), std::declval<ConversionSpec>(),
std::declval<FormatSink*>()))>> : std::true_type {};
+
template <typename T>
class StreamedWrapper;
// If 'v' can be converted (in the printf sense) according to 'conv',
// then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`.
+
// Raw pointers.
struct VoidPtr {
VoidPtr() = default;
@@ -54,7 +56,8 @@
FormatSinkImpl* sink);
// Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, ConversionSpec conv,
+ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
+ ConversionSpec conv,
FormatSinkImpl* sink);
ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
FormatSinkImpl* sink);
@@ -80,7 +83,7 @@
int precision = conv.precision();
if (precision >= 0)
- to_write = std::min(to_write, static_cast<size_t>(precision));
+ to_write = (std::min)(to_write, static_cast<size_t>(precision));
space_remaining = Excess(to_write, space_remaining);
@@ -335,12 +338,12 @@
using CommonType = typename std::conditional<std::is_signed<T>::value,
int64_t, uint64_t>::type;
if (static_cast<CommonType>(val) >
- static_cast<CommonType>(std::numeric_limits<int>::max())) {
- return std::numeric_limits<int>::max();
+ static_cast<CommonType>((std::numeric_limits<int>::max)())) {
+ return (std::numeric_limits<int>::max)();
} else if (std::is_signed<T>::value &&
static_cast<CommonType>(val) <
- static_cast<CommonType>(std::numeric_limits<int>::min())) {
- return std::numeric_limits<int>::min();
+ static_cast<CommonType>((std::numeric_limits<int>::min)())) {
+ return (std::numeric_limits<int>::min)();
}
return static_cast<int>(val);
}
@@ -409,7 +412,7 @@
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \
- ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \
+ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc
index 83d5904..3421fac 100644
--- a/absl/strings/internal/str_format/arg_test.cc
+++ b/absl/strings/internal/str_format/arg_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
#include "absl/strings/internal/str_format/arg.h"
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc
index c4eddd1..a31859e 100644
--- a/absl/strings/internal/str_format/bind.cc
+++ b/absl/strings/internal/str_format/bind.cc
@@ -25,12 +25,12 @@
explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
// Fill 'bound' with the results of applying the context's argument pack
- // to the specified 'props'. We synthesize a BoundConversion by
+ // to the specified 'unbound'. We synthesize a BoundConversion by
// lining up a UnboundConversion with a user argument. We also
// resolve any '*' specifiers for width and precision, so after
// this call, 'bound' has all the information it needs to be formatted.
// Returns false on failure.
- bool Bind(const UnboundConversion *props, BoundConversion *bound);
+ bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
private:
absl::Span<const FormatArgImpl> pack_;
@@ -53,7 +53,8 @@
// "A negative field width is taken as a '-' flag followed by a
// positive field width."
force_left = true;
- width = -width;
+ // Make sure we don't overflow the width when negating it.
+ width = -std::max(width, -std::numeric_limits<int>::max());
}
}
@@ -159,7 +160,7 @@
}
std::string Summarize(const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
typedef SummarizingConverter Converter;
std::string out;
{
@@ -187,7 +188,7 @@
}
std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
size_t orig = out->size();
if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
out->erase(orig);
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index 1b52df9..4f78295 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -153,7 +153,7 @@
// for testing
std::string Summarize(UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args);
+ absl::Span<const FormatArgImpl> args);
bool BindWithPack(const UnboundConversion* props,
absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
@@ -162,10 +162,10 @@
absl::Span<const FormatArgImpl> args);
std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args);
+ absl::Span<const FormatArgImpl> args);
inline std::string FormatPack(const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
std::string out;
AppendPack(&out, format, args);
return out;
@@ -176,7 +176,7 @@
int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
absl::Span<const FormatArgImpl> args);
-// Returned by Streamed(v). Converts via '%s' to the string created
+// Returned by Streamed(v). Converts via '%s' to the std::string created
// by std::ostream << v.
template <typename T>
class StreamedWrapper {
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc
index 4757573..ba6470e 100644
--- a/absl/strings/internal/str_format/bind_test.cc
+++ b/absl/strings/internal/str_format/bind_test.cc
@@ -1,6 +1,7 @@
#include "absl/strings/internal/str_format/bind.h"
#include <string.h>
+#include <limits>
#include "gtest/gtest.h"
@@ -91,6 +92,20 @@
}
}
+TEST_F(FormatBindTest, WidthUnderflowRegression) {
+ UnboundConversion props;
+ BoundConversion bound;
+ int next = 0;
+ const int args_i[] = {std::numeric_limits<int>::min(), 17};
+ const FormatArgImpl args[] = {FormatArgImpl(args_i[0]),
+ FormatArgImpl(args_i[1])};
+ ASSERT_TRUE(Extract("*d", &props, &next));
+ ASSERT_TRUE(BindWithPack(&props, args, &bound));
+
+ EXPECT_EQ(bound.width(), std::numeric_limits<int>::max());
+ EXPECT_EQ(bound.arg(), args + 1);
+}
+
TEST_F(FormatBindTest, FormatPack) {
struct Expectation {
int line;
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index 14d11ea..c1d8c76 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -62,32 +62,32 @@
ValidFormat<int>("%% %d"), //
ValidFormat<int>("%ld"), //
ValidFormat<int>("%lld"), //
- ValidFormat<std::string>("%s"), //
- ValidFormat<std::string>("%10s"), //
+ ValidFormat<std::string>("%s"), //
+ ValidFormat<std::string>("%10s"), //
ValidFormat<int>("%.10x"), //
ValidFormat<int, int>("%*.3x"), //
ValidFormat<int>("%1.d"), //
ValidFormat<int>("%.d"), //
ValidFormat<int, double>("%d %g"), //
- ValidFormat<int, std::string>("%*s"), //
+ ValidFormat<int, std::string>("%*s"), //
ValidFormat<int, double>("%.*f"), //
ValidFormat<void (*)(), volatile int*>("%p %p"), //
ValidFormat<string_view, const char*, double, void*>(
"string_view=%s const char*=%s double=%f void*=%p)"),
- ValidFormat<int>("%% %1$d"), //
- ValidFormat<int>("%1$ld"), //
- ValidFormat<int>("%1$lld"), //
- ValidFormat<std::string>("%1$s"), //
- ValidFormat<std::string>("%1$10s"), //
- ValidFormat<int>("%1$.10x"), //
- ValidFormat<int>("%1$*1$.*1$d"), //
- ValidFormat<int, int>("%1$*2$.3x"), //
- ValidFormat<int>("%1$1.d"), //
- ValidFormat<int>("%1$.d"), //
- ValidFormat<double, int>("%2$d %1$g"), //
- ValidFormat<int, std::string>("%2$*1$s"), //
- ValidFormat<int, double>("%2$.*1$f"), //
+ ValidFormat<int>("%% %1$d"), //
+ ValidFormat<int>("%1$ld"), //
+ ValidFormat<int>("%1$lld"), //
+ ValidFormat<std::string>("%1$s"), //
+ ValidFormat<std::string>("%1$10s"), //
+ ValidFormat<int>("%1$.10x"), //
+ ValidFormat<int>("%1$*1$.*1$d"), //
+ ValidFormat<int, int>("%1$*2$.3x"), //
+ ValidFormat<int>("%1$1.d"), //
+ ValidFormat<int>("%1$.d"), //
+ ValidFormat<double, int>("%2$d %1$g"), //
+ ValidFormat<int, std::string>("%2$*1$s"), //
+ ValidFormat<int, double>("%2$.*1$f"), //
ValidFormat<void*, string_view, const char*, double>(
"string_view=%2$s const char*=%3$s double=%4$f void*=%1$p "
"repeat=%3$s)")};
@@ -99,25 +99,25 @@
constexpr Case falses[] = {
ValidFormat<int>(""), //
- ValidFormat<e>("%s"), //
- ValidFormat<e2>("%s"), //
- ValidFormat<>("%s"), //
- ValidFormat<>("%r"), //
- ValidFormat<int>("%s"), //
- ValidFormat<int>("%.1.d"), //
- ValidFormat<int>("%*1d"), //
- ValidFormat<int>("%1-d"), //
+ ValidFormat<e>("%s"), //
+ ValidFormat<e2>("%s"), //
+ ValidFormat<>("%s"), //
+ ValidFormat<>("%r"), //
+ ValidFormat<int>("%s"), //
+ ValidFormat<int>("%.1.d"), //
+ ValidFormat<int>("%*1d"), //
+ ValidFormat<int>("%1-d"), //
ValidFormat<std::string, int>("%*s"), //
- ValidFormat<int>("%*d"), //
+ ValidFormat<int>("%*d"), //
ValidFormat<std::string>("%p"), //
- ValidFormat<int (*)(int)>("%d"), //
+ ValidFormat<int (*)(int)>("%d"), //
- ValidFormat<>("%3$d"), //
- ValidFormat<>("%1$r"), //
- ValidFormat<int>("%1$s"), //
- ValidFormat<int>("%1$.1.d"), //
- ValidFormat<int>("%1$*2$1d"), //
- ValidFormat<int>("%1$1-d"), //
+ ValidFormat<>("%3$d"), //
+ ValidFormat<>("%1$r"), //
+ ValidFormat<int>("%1$s"), //
+ ValidFormat<int>("%1$.1.d"), //
+ ValidFormat<int>("%1$*2$1d"), //
+ ValidFormat<int>("%1$1-d"), //
ValidFormat<std::string, int>("%2$*1$s"), //
ValidFormat<std::string>("%1$p"),
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 32f8a0f..99cc0af 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -232,7 +232,7 @@
template <typename T>
class TypedFormatConvertTest : public FormatConvertTest { };
-TYPED_TEST_CASE_P(TypedFormatConvertTest);
+TYPED_TEST_SUITE_P(TypedFormatConvertTest);
std::vector<std::string> AllFlagCombinations() {
const char kFlags[] = {'-', '#', '0', '+', ' '};
@@ -363,6 +363,7 @@
AllIntTypes;
INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
TypedFormatConvertTest, AllIntTypes);
+
TEST_F(FormatConvertTest, Uint128) {
absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
absl::uint128 max = absl::Uint128Max();
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc
index c217470..d7f5815 100644
--- a/absl/strings/internal/str_format/extension.cc
+++ b/absl/strings/internal/str_format/extension.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index 11b996a..eb81f8a 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-//
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
@@ -360,7 +359,7 @@
integral = d | i | u | o | x | X,
floating = a | e | f | g | A | E | F | G,
numeric = integral | floating,
- string = s, // absl:ignore(std::string)
+ string = s,
pointer = p
};
@@ -409,4 +408,4 @@
} // namespace absl
-#endif // ABSL_STRINGS_STR_FORMAT_EXTENSION_H_
+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 224fc92..4e23fef 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,6 +18,7 @@
#include <random>
#include <string>
+
#include "absl/strings/str_format.h"
#include "gtest/gtest.h"
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc
index 5c3795b..38987b6 100644
--- a/absl/strings/internal/str_format/output.cc
+++ b/absl/strings/internal/str_format/output.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,6 +20,16 @@
namespace absl {
namespace str_format_internal {
+namespace {
+struct ClearErrnoGuard {
+ ClearErrnoGuard() : old_value(errno) { errno = 0; }
+ ~ClearErrnoGuard() {
+ if (!errno) errno = old_value;
+ }
+ int old_value;
+};
+} // namespace
+
void BufferRawSink::Write(string_view v) {
size_t to_write = std::min(v.size(), size_);
std::memcpy(buffer_, v.data(), to_write);
@@ -30,14 +40,27 @@
void FILERawSink::Write(string_view v) {
while (!v.empty() && !error_) {
+ // Reset errno to zero in case the libc implementation doesn't set errno
+ // when a failure occurs.
+ ClearErrnoGuard guard;
+
if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) {
// Some progress was made.
count_ += result;
v.remove_prefix(result);
} else {
- // Some error occurred.
- if (errno != EINTR) {
+ if (errno == EINTR) {
+ continue;
+ } else if (errno) {
error_ = errno;
+ } else if (std::ferror(output_)) {
+ // Non-POSIX compliant libc implementations may not set errno, so we
+ // have check the streams error indicator.
+ error_ = EBADF;
+ } else {
+ // We're likely on a non-POSIX system that encountered EINTR but had no
+ // way of reporting it.
+ continue;
}
}
}
diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h
index 12ecd99..42da641 100644
--- a/absl/strings/internal/str_format/output.h
+++ b/absl/strings/internal/str_format/output.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc
index cc3c615..6e04abe 100644
--- a/absl/strings/internal/str_format/output_test.cc
+++ b/absl/strings/internal/str_format/output_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,7 +17,6 @@
#include <sstream>
#include <string>
-
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -28,12 +27,6 @@
std::string str = "ABC";
str_format_internal::InvokeFlush(&str, "DEF");
EXPECT_EQ(str, "ABCDEF");
-
-#if UTIL_FORMAT_HAS_GLOBAL_STRING
- std::string str2 = "ABC";
- str_format_internal::InvokeFlush(&str2, "DEF");
- EXPECT_EQ(str2, "ABCDEF");
-#endif // UTIL_FORMAT_HAS_GLOBAL_STRING
}
TEST(InvokeFlush, Stream) {
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc
index 5e3d0d0..10487f2 100644
--- a/absl/strings/internal/str_format/parser.cc
+++ b/absl/strings/internal/str_format/parser.cc
@@ -99,10 +99,11 @@
// digit doesn't match the expected characters.
int num_digits = std::numeric_limits<int>::digits10;
for (;;) {
- if (ABSL_PREDICT_FALSE(pos == end || !num_digits)) break;
+ if (ABSL_PREDICT_FALSE(pos == end)) break;
c = *pos++;
if (!std::isdigit(c)) break;
--num_digits;
+ if (ABSL_PREDICT_FALSE(!num_digits)) break;
digits = 10 * digits + c - '0';
}
return digits;
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
index ae40203..ff70575 100644
--- a/absl/strings/internal/str_format/parser_test.cc
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -246,6 +246,8 @@
EXPECT_FALSE(Run("1000000000.999999999d"));
EXPECT_FALSE(Run("999999999.1000000000d"));
+ EXPECT_FALSE(Run("9999999999d"));
+ EXPECT_FALSE(Run(".9999999999d"));
}
TEST_F(ConsumeUnboundConversionTest, Flags) {
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 0058fc8..7c35f4d 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -193,7 +193,7 @@
// and formats each element using the provided Formatter object.
template <typename Iterator, typename Formatter>
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
- Formatter&& f) {
+ Formatter&& f) {
std::string result;
absl::string_view sep("");
for (Iterator it = start; it != end; ++it) {
@@ -212,7 +212,7 @@
// This is an overload of the previous JoinAlgorithm() function. Here the
// Formatter argument is of type NoFormatter. Since NoFormatter is an internal
// type, this overload is only invoked when strings::Join() is called with a
-// range of string-like objects (e.g., string, absl::string_view), and an
+// range of string-like objects (e.g., std::string, absl::string_view), and an
// explicit Formatter argument was NOT specified.
//
// The optimization is that the needed space will be reserved in the output
@@ -224,7 +224,7 @@
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>::value>::type>
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
- NoFormatter) {
+ NoFormatter) {
std::string result;
if (start != end) {
// Sums size
@@ -276,14 +276,15 @@
template <typename... T, typename Formatter>
std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep,
- Formatter&& fmt) {
+ Formatter&& fmt) {
std::string result;
JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt);
return result;
}
template <typename Iterator>
-std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) {
+std::string JoinRange(Iterator first, Iterator last,
+ absl::string_view separator) {
// No formatter was explicitly given, so a default must be chosen.
typedef typename std::iterator_traits<Iterator>::value_type ValueType;
typedef typename DefaultFormatter<ValueType>::Type Formatter;
@@ -292,7 +293,7 @@
template <typename Range, typename Formatter>
std::string JoinRange(const Range& range, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
using std::begin;
using std::end;
return JoinAlgorithm(begin(range), end(range), separator, fmt);
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index 81e8d55..52f6222 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -96,8 +96,8 @@
}
}
- // Holds the data moved from temporary std::string arguments. Declared first so
- // that 'value' can refer to 'copy_'.
+ // Holds the data moved from temporary std::string arguments. Declared first
+ // so that 'value' can refer to 'copy_'.
std::string copy_;
absl::string_view value_;
};
@@ -376,10 +376,10 @@
// Partial specialization for a std::vector<std::string>.
//
- // Optimized for the common case of splitting to a std::vector<std::string>. In
- // this case we first split the results to a std::vector<absl::string_view> so
- // the returned std::vector<std::string> can have space reserved to avoid std::string
- // moves.
+ // Optimized for the common case of splitting to a std::vector<std::string>.
+ // In this case we first split the results to a std::vector<absl::string_view>
+ // so the returned std::vector<std::string> can have space reserved to avoid
+ // std::string moves.
template <typename A>
struct ConvertToContainer<std::vector<std::string, A>, std::string, false> {
std::vector<std::string, A> operator()(const Splitter& splitter) const {
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc
index 2415c2c..82d36c2 100644
--- a/absl/strings/internal/utf8.cc
+++ b/absl/strings/internal/utf8.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h
index d2c3c0b..0423630 100644
--- a/absl/strings/internal/utf8.h
+++ b/absl/strings/internal/utf8.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
// limitations under the License.
//
// UTF8 utilities, implemented to reduce dependencies.
-//
#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_
#define ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc
index 64cec70..88dd503 100644
--- a/absl/strings/internal/utf8_test.cc
+++ b/absl/strings/internal/utf8_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,12 +22,17 @@
namespace {
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
TEST(EncodeUTF8Char, BasicFunction) {
std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
- {0x00A3, u8"\u00A3"},
- {0x00010000, u8"\U00010000"},
- {0x0000FFFF, u8"\U0000FFFF"},
- {0x0010FFFD, u8"\U0010FFFD"}};
+ {0x00A3, u8"\u00A3"},
+ {0x00010000, u8"\U00010000"},
+ {0x0000FFFF, u8"\U0000FFFF"},
+ {0x0010FFFD, u8"\U0010FFFD"}};
for (auto &test : tests) {
char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
@@ -53,5 +58,9 @@
EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
absl::strings_internal::kMaxEncodedUTF8Size);
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif // !defined(__cpp_char8_t)
} // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc
index 3d10c57..7b24241 100644
--- a/absl/strings/match.cc
+++ b/absl/strings/match.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,15 +18,6 @@
namespace absl {
-namespace {
-bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
- return (piece1.size() == piece2.size() &&
- 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
- piece1.size()));
- // memcasecmp uses ascii_tolower().
-}
-} // namespace
-
bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
return (piece1.size() == piece2.size() &&
0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(),
@@ -36,12 +27,12 @@
bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
return (text.size() >= prefix.size()) &&
- CaseEqual(text.substr(0, prefix.size()), prefix);
+ EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
}
bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
return (text.size() >= suffix.size()) &&
- CaseEqual(text.substr(text.size() - suffix.size()), suffix);
+ EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
}
} // namespace absl
diff --git a/absl/strings/match.h b/absl/strings/match.h
index 6e8ed10..5251b7f 100644
--- a/absl/strings/match.h
+++ b/absl/strings/match.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -74,13 +74,13 @@
// StartsWithIgnoreCase()
//
-// Returns whether a given ASCII string `text` starts with `starts_with`,
+// Returns whether a given ASCII string `text` starts with `prefix`,
// ignoring case in the comparison.
bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
// EndsWithIgnoreCase()
//
-// Returns whether a given ASCII string `text` ends with `ends_with`, ignoring
+// Returns whether a given ASCII string `text` ends with `suffix`, ignoring
// case in the comparison.
bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc
index c21e00b..4c313dd 100644
--- a/absl/strings/match_test.cc
+++ b/absl/strings/match_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,7 +19,7 @@
namespace {
TEST(MatchTest, StartsWith) {
- const std::string s1("123" "\0" "456", 7);
+ const std::string s1("123\0abc", 7);
const absl::string_view a("foobar");
const absl::string_view b(s1);
const absl::string_view e;
@@ -36,7 +36,7 @@
}
TEST(MatchTest, EndsWith) {
- const std::string s1("123" "\0" "456", 7);
+ const std::string s1("123\0abc", 7);
const absl::string_view a("foobar");
const absl::string_view b(s1);
const absl::string_view e;
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index 9309f9d..558c339 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -35,17 +35,18 @@
#include "absl/strings/ascii.h"
#include "absl/strings/charconv.h"
#include "absl/strings/internal/memutil.h"
+#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
namespace absl {
-bool SimpleAtof(absl::string_view str, float* value) {
- *value = 0.0;
+bool SimpleAtof(absl::string_view str, float* out) {
+ *out = 0.0;
str = StripAsciiWhitespace(str);
if (!str.empty() && str[0] == '+') {
str.remove_prefix(1);
}
- auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
if (result.ec == std::errc::invalid_argument) {
return false;
}
@@ -56,22 +57,22 @@
// from_chars() with DR 3801's current wording will return max() on
// overflow. SimpleAtof returns infinity instead.
if (result.ec == std::errc::result_out_of_range) {
- if (*value > 1.0) {
- *value = std::numeric_limits<float>::infinity();
- } else if (*value < -1.0) {
- *value = -std::numeric_limits<float>::infinity();
+ if (*out > 1.0) {
+ *out = std::numeric_limits<float>::infinity();
+ } else if (*out < -1.0) {
+ *out = -std::numeric_limits<float>::infinity();
}
}
return true;
}
-bool SimpleAtod(absl::string_view str, double* value) {
- *value = 0.0;
+bool SimpleAtod(absl::string_view str, double* out) {
+ *out = 0.0;
str = StripAsciiWhitespace(str);
if (!str.empty() && str[0] == '+') {
str.remove_prefix(1);
}
- auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
if (result.ec == std::errc::invalid_argument) {
return false;
}
@@ -82,10 +83,10 @@
// from_chars() with DR 3801's current wording will return max() on
// overflow. SimpleAtod returns infinity instead.
if (result.ec == std::errc::result_out_of_range) {
- if (*value > 1.0) {
- *value = std::numeric_limits<double>::infinity();
- } else if (*value < -1.0) {
- *value = -std::numeric_limits<double>::infinity();
+ if (*out > 1.0) {
+ *out = std::numeric_limits<double>::infinity();
+ } else if (*out < -1.0) {
+ *out = -std::numeric_limits<double>::infinity();
}
}
return true;
@@ -93,14 +94,6 @@
namespace {
-// TODO(rogeeff): replace with the real released thing once we figure out what
-// it is.
-inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
- return (piece1.size() == piece2.size() &&
- 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
- piece1.size()));
-}
-
// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
// range 0 <= i < 100, and buf must have space for two characters. Example:
// char buf[2];
@@ -136,18 +129,18 @@
} // namespace
-bool SimpleAtob(absl::string_view str, bool* value) {
- ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr.");
- if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
- CaseEqual(str, "yes") || CaseEqual(str, "y") ||
- CaseEqual(str, "1")) {
- *value = true;
+bool SimpleAtob(absl::string_view str, bool* out) {
+ ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
+ if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
+ EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") ||
+ EqualsIgnoreCase(str, "1")) {
+ *out = true;
return true;
}
- if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
- CaseEqual(str, "no") || CaseEqual(str, "n") ||
- CaseEqual(str, "0")) {
- *value = false;
+ if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") ||
+ EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") ||
+ EqualsIgnoreCase(str, "0")) {
+ *out = false;
return true;
}
return false;
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index f9b2cce..e0f96df 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -44,7 +44,8 @@
// Converts the given string into an integer value, returning `true` if
// successful. The string must reflect a base-10 integer (optionally followed or
// preceded by ASCII whitespace) whose value falls within the range of the
-// integer type.
+// integer type. If any errors are encountered, this function returns `false`,
+// leaving `out` in an unspecified state.
template <typename int_type>
ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out);
@@ -52,25 +53,29 @@
//
// Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a float, which may be rounded on overflow or underflow.
-// See http://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`.
-ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value);
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`. If any errors are encountered, this function
+// returns `false`, leaving `out` in an unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out);
// SimpleAtod()
//
// Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a double, which may be rounded on overflow or underflow.
-// See http://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`.
-ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value);
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`. If any errors are encountered, this function
+// returns `false`, leaving `out` in an unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out);
// SimpleAtob()
//
// Converts the given string into a boolean, returning `true` if successful.
// The following case-insensitive strings are interpreted as boolean `true`:
// "true", "t", "yes", "y", "1". The following case-insensitive strings
-// are interpreted as boolean `false`: "false", "f", "no", "n", "0".
-ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value);
+// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any
+// errors are encountered, this function returns `false`, leaving `out` in an
+// unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out);
} // namespace absl
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc
index 0570b75..54dbedd 100644
--- a/absl/strings/numbers_benchmark.cc
+++ b/absl/strings/numbers_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 36fc0d6..ca2ee48 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -39,6 +39,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/internal/numbers_test_common.h"
+#include "absl/strings/internal/pow10_helper.h"
namespace {
@@ -190,7 +191,8 @@
EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x;
char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]);
- EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x;
+ EXPECT_EQ(expected, std::string(&buffer[1], generic_actual))
+ << " Input " << x;
char* my_actual =
absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]);
@@ -783,7 +785,7 @@
if (iters_per_float == 0) iters_per_float = 1;
for (float f : floats) {
if (f == last) continue;
- float testf = nextafter(last, std::numeric_limits<float>::max());
+ float testf = std::nextafter(last, std::numeric_limits<float>::max());
runnable(testf);
runnable(-testf);
last = testf;
@@ -797,7 +799,7 @@
last = testf;
}
}
- testf = nextafter(f, 0.0f);
+ testf = std::nextafter(f, 0.0f);
if (testf > last) {
runnable(testf);
runnable(-testf);
@@ -871,15 +873,15 @@
}
for (int exponent = -324; exponent <= 308; ++exponent) {
- double powten = pow(10.0, exponent);
+ double powten = absl::strings_internal::Pow10(exponent);
if (powten == 0) powten = 5e-324;
if (kFloatNumCases >= 1e9) {
// The exhaustive test takes a very long time, so log progress.
char buf[kSixDigitsToBufferSize];
ABSL_RAW_LOG(
INFO, "%s",
- absl::StrCat("Exp ", exponent, " powten=", powten, "(",
- powten, ") (",
+ absl::StrCat("Exp ", exponent, " powten=", powten, "(", powten,
+ ") (",
std::string(buf, SixDigitsToBuffer(powten, buf)), ")")
.c_str());
}
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index efa4fd7..2667976 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -78,9 +78,9 @@
// ----------------------------------------------------------------------
// StrCat()
-// This merges the given strings or integers, with no delimiter. This
+// This merges the given strings or integers, with no delimiter. This
// is designed to be the fastest possible way to construct a string out
-// of a mix of raw C strings, StringPieces, strings, and integer values.
+// of a mix of raw C strings, string_views, strings, and integer values.
// ----------------------------------------------------------------------
// Append is merely a version of memcpy that returns the address of the byte
@@ -119,7 +119,7 @@
}
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
- const AlphaNum& d) {
+ const AlphaNum& d) {
std::string result;
strings_internal::STLStringResizeUninitialized(
&result, a.size() + b.size() + c.size() + d.size());
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index da9ed9a..cba8ceb 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -42,7 +42,6 @@
// Floating point numbers are formatted with six-digit precision, which is
// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
//
-//
// You can convert to hexadecimal output rather than decimal output using the
// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
@@ -78,8 +77,8 @@
// Enum that specifies the number of significant digits to return in a `Hex` or
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
-// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
-// would produce hexadecimal strings such as " A"," F".
+// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
+// would produce hexadecimal strings such as " a"," f".
enum PadSpec : uint8_t {
kNoPad = 1,
kZeroPad2,
@@ -97,6 +96,10 @@
kZeroPad14,
kZeroPad15,
kZeroPad16,
+ kZeroPad17,
+ kZeroPad18,
+ kZeroPad19,
+ kZeroPad20,
kSpacePad2 = kZeroPad2 + 64,
kSpacePad3,
@@ -113,6 +116,10 @@
kSpacePad14,
kSpacePad15,
kSpacePad16,
+ kSpacePad17,
+ kSpacePad18,
+ kSpacePad19,
+ kSpacePad20,
};
// -----------------------------------------------------------------------------
@@ -237,6 +244,7 @@
AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit)
+
template <typename Allocator>
AlphaNum( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
@@ -309,16 +317,15 @@
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c);
+ const AlphaNum& c);
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c, const AlphaNum& d);
+ const AlphaNum& c, const AlphaNum& d);
// Support 5 or more arguments
template <typename... AV>
-ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c, const AlphaNum& d,
- const AlphaNum& e,
- const AV&... args) {
+ABSL_MUST_USE_RESULT inline std::string StrCat(
+ const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
+ const AlphaNum& e, const AV&... args) {
return strings_internal::CatPieces(
{a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
static_cast<const AlphaNum&>(args).Piece()...});
@@ -336,18 +343,18 @@
// not try to check each of its input arguments to be sure that they are not
// a subset of the string being appended to. That is, while this will work:
//
-// string s = "foo";
+// std::string s = "foo";
// s += s;
//
// This output is undefined:
//
-// string s = "foo";
+// std::string s = "foo";
// StrAppend(&s, s);
//
// This output is undefined as well, since `absl::string_view` does not own its
// data:
//
-// string s = "foobar";
+// std::string s = "foobar";
// absl::string_view p = s;
// StrAppend(&s, p);
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc
index b6df9e3..14c63b3 100644
--- a/absl/strings/str_cat_benchmark.cc
+++ b/absl/strings/str_cat_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
index 555d8db..beb15fa 100644
--- a/absl/strings/str_cat_test.cc
+++ b/absl/strings/str_cat_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -106,11 +106,7 @@
TEST(StrCat, Basics) {
std::string result;
- std::string strs[] = {
- "Hello",
- "Cruel",
- "World"
- };
+ std::string strs[] = {"Hello", "Cruel", "World"};
std::string stdstrs[] = {
"std::Hello",
@@ -164,9 +160,10 @@
result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!");
EXPECT_EQ(result, "12345678910, 10987654321!");
- std::string one = "1"; // Actually, it's the size of this std::string that we want; a
- // 64-bit build distinguishes between size_t and uint64_t,
- // even though they're both unsigned 64-bit values.
+ std::string one =
+ "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
result = absl::StrCat("And a ", one.size(), " and a ",
&result[2] - &result[0], " and a ", one, " 2 3 4", "!");
EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!");
@@ -306,11 +303,7 @@
TEST(StrAppend, Basics) {
std::string result = "existing text";
- std::string strs[] = {
- "Hello",
- "Cruel",
- "World"
- };
+ std::string strs[] = {"Hello", "Cruel", "World"};
std::string stdstrs[] = {
"std::Hello",
@@ -365,9 +358,10 @@
absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!");
EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
- std::string one = "1"; // Actually, it's the size of this std::string that we want; a
- // 64-bit build distinguishes between size_t and uint64_t,
- // even though they're both unsigned 64-bit values.
+ std::string one =
+ "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
old_size = result.size();
absl::StrAppend(&result, "And a ", one.size(), " and a ",
&result[2] - &result[0], " and a ", one, " 2 3 4", "!");
@@ -427,7 +421,7 @@
snprintf(expected, sizeof(expected), nopad_format, v);
EXPECT_EQ(expected, actual) << " decimal value " << v;
- for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) {
+ for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) {
std::string actual =
absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
snprintf(expected, sizeof(expected), zeropad_format,
@@ -435,7 +429,7 @@
EXPECT_EQ(expected, actual) << " decimal value " << v;
}
- for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) {
+ for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) {
std::string actual =
absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
snprintf(expected, sizeof(expected), spacepad_format,
@@ -453,7 +447,7 @@
snprintf(expected, sizeof(expected), nopad_format, v);
EXPECT_EQ(expected, actual) << " decimal value " << v;
- for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) {
+ for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) {
std::string actual =
absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
snprintf(expected, sizeof(expected), zeropad_format,
@@ -463,7 +457,7 @@
<< "' digits " << (spec - absl::kZeroPad2 + 2);
}
- for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) {
+ for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) {
std::string actual =
absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
snprintf(expected, sizeof(expected), spacepad_format,
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index 2d07725..539d951 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,7 +24,8 @@
//
// Example:
//
-// string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars);
+// std::string s = absl::StrFormat(
+// "%s %s You have $%d!", "Hello", name, dollars);
//
// The library consists of the following basic utilities:
//
@@ -89,7 +90,7 @@
// Example:
//
// absl::UntypedFormatSpec format("%d");
-// string out;
+// std::string out;
// CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)}));
class UntypedFormatSpec {
public:
@@ -135,8 +136,8 @@
// Example:
//
// int n = 0;
-// string s = absl::StrFormat("%s%d%n", "hello", 123,
-// absl::FormatCountCapture(&n));
+// std::string s = absl::StrFormat("%s%d%n", "hello", 123,
+// absl::FormatCountCapture(&n));
// EXPECT_EQ(8, n);
class FormatCountCapture {
public:
@@ -186,7 +187,7 @@
// A format string generally follows the POSIX syntax as used within the POSIX
// `printf` specification.
//
-// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.)
+// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.)
//
// In specific, the `FormatSpec` supports the following type specifiers:
// * `c` for characters
@@ -223,7 +224,7 @@
// "%p", *int -> "0x7ffdeb6ad2a4"
//
// int n = 0;
-// string s = absl::StrFormat(
+// std::string s = absl::StrFormat(
// "%s%d%n", "hello", 123, absl::FormatCountCapture(&n));
// EXPECT_EQ(8, n);
//
@@ -290,14 +291,14 @@
//
// Example:
//
-// string s = absl::StrFormat(
+// std::string s = absl::StrFormat(
// "Welcome to %s, Number %d!", "The Village", 6);
// EXPECT_EQ("Welcome to The Village, Number 6!", s);
//
// Returns an empty string in case of error.
template <typename... Args>
ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format,
- const Args&... args) {
+ const Args&... args) {
return str_format_internal::FormatPack(
str_format_internal::UntypedFormatSpecImpl::Extract(format),
{str_format_internal::FormatArgImpl(args)...});
@@ -311,11 +312,12 @@
//
// Example:
//
-// string orig("For example PI is approximately ");
+// std::string orig("For example PI is approximately ");
// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14);
template <typename... Args>
-std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format,
- const Args&... args) {
+std::string& StrAppendFormat(std::string* dst,
+ const FormatSpec<Args...>& format,
+ const Args&... args) {
return str_format_internal::AppendPack(
dst, str_format_internal::UntypedFormatSpecImpl::Extract(format),
{str_format_internal::FormatArgImpl(args)...});
@@ -434,7 +436,8 @@
// `absl::FormatRawSink` interface), using a format string and zero or more
// additional arguments.
//
-// By default, `string` and `std::ostream` are supported as destination objects.
+// By default, `std::string` and `std::ostream` are supported as destination
+// objects.
//
// `absl::Format()` is a generic version of `absl::StrFormat(), for custom
// sinks. The format string, like format strings for `StrFormat()`, is checked
@@ -483,9 +486,10 @@
//
// Example:
//
-// std::optional<string> FormatDynamic(const string& in_format,
-// const vector<string>& in_args) {
-// string out;
+// std::optional<std::string> FormatDynamic(
+// const std::string& in_format,
+// const vector<std::string>& in_args) {
+// std::string out;
// std::vector<absl::FormatArg> args;
// for (const auto& v : in_args) {
// // It is important that 'v' is a reference to the objects in in_args.
@@ -509,4 +513,5 @@
}
} // namespace absl
+
#endif // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index aa14e21..d4cffa0 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -242,6 +242,7 @@
std::string ReadFile() {
std::fseek(file_, 0, SEEK_END);
int size = std::ftell(file_);
+ EXPECT_GT(size, 0);
std::rewind(file_);
std::string str(2 * size, ' ');
int read_bytes = std::fread(&str[0], 1, str.size(), file_);
@@ -270,7 +271,7 @@
EXPECT_EQ(errno, EBADF);
}
-#if __GNUC__
+#if __GLIBC__
TEST_F(FormatEntryPointTest, FprintfTooLarge) {
std::FILE* f = std::fopen("/dev/null", "w");
int width = 2000000000;
@@ -297,7 +298,7 @@
EXPECT_EQ(result, 30);
EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
}
-#endif // __GNUC__
+#endif // __GLIBC__
TEST_F(FormatEntryPointTest, SNPrintF) {
char buffer[16];
@@ -340,7 +341,7 @@
EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
- // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
+ // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
// Formats std::string, char*, string_view, and Cord.
EXPECT_EQ(StrFormat("%s", "C"), "C");
EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
@@ -605,35 +606,21 @@
// Some codegen thunks that we can use to easily dump the generated assembly for
// different StrFormat calls.
-inline std::string CodegenAbslStrFormatInt(int i) {
+std::string CodegenAbslStrFormatInt(int i) { // NOLINT
return absl::StrFormat("%d", i);
}
-inline std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
- int64_t i64) {
+std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
+ int64_t i64) { // NOLINT
return absl::StrFormat("%d %s %d", i, s, i64);
}
-inline void CodegenAbslStrAppendFormatInt(std::string* out, int i) {
+void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
absl::StrAppendFormat(out, "%d", i);
}
-inline void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
- const std::string& s,
- int64_t i64) {
+void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
+ const std::string& s,
+ int64_t i64) { // NOLINT
absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
}
-
-auto absl_internal_str_format_force_codegen_funcs = std::make_tuple(
- CodegenAbslStrFormatInt, CodegenAbslStrFormatIntStringInt64,
- CodegenAbslStrAppendFormatInt, CodegenAbslStrAppendFormatIntStringInt64);
-
-bool absl_internal_str_format_force_codegen_always_false;
-// Force the compiler to generate the functions by making it look like we
-// escape the function pointers.
-// It can't statically know that
-// absl_internal_str_format_force_codegen_always_false is not changed by someone
-// else.
-bool absl_internal_str_format_force_codegen =
- absl_internal_str_format_force_codegen_always_false &&
- printf("%p", &absl_internal_str_format_force_codegen_funcs) == 0;
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
index f9611ad..7345b96 100644
--- a/absl/strings/str_join.h
+++ b/absl/strings/str_join.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,13 +18,13 @@
// -----------------------------------------------------------------------------
//
// This header file contains functions for joining a range of elements and
-// returning the result as a string. StrJoin operations are specified by passing
-// a range, a separator string to use between the elements joined, and an
-// optional Formatter responsible for converting each argument in the range to a
-// string. If omitted, a default `AlphaNumFormatter()` is called on the elements
-// to be joined, using the same formatting that `absl::StrCat()` uses. This
-// package defines a number of default formatters, and you can define your own
-// implementations.
+// returning the result as a std::string. StrJoin operations are specified by
+// passing a range, a separator string to use between the elements joined, and
+// an optional Formatter responsible for converting each argument in the range
+// to a string. If omitted, a default `AlphaNumFormatter()` is called on the
+// elements to be joined, using the same formatting that `absl::StrCat()` uses.
+// This package defines a number of default formatters, and you can define your
+// own implementations.
//
// Ranges are specified by passing a container with `std::begin()` and
// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
@@ -37,8 +37,8 @@
//
// Example:
//
-// std::vector<string> v = {"foo", "bar", "baz"};
-// string s = absl::StrJoin(v, "-");
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// See comments on the `absl::StrJoin()` function for more examples.
@@ -66,16 +66,16 @@
// -----------------------------------------------------------------------------
//
// A Formatter is a function object that is responsible for formatting its
-// argument as a string and appending it to a given output string. Formatters
-// may be implemented as function objects, lambdas, or normal functions. You may
-// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary
-// types.
+// argument as a string and appending it to a given output std::string.
+// Formatters may be implemented as function objects, lambdas, or normal
+// functions. You may provide your own Formatter to enable `absl::StrJoin()` to
+// work with arbitrary types.
//
// The following is an example of a custom Formatter that simply uses
-// `std::to_string()` to format an integer as a string.
+// `std::to_string()` to format an integer as a std::string.
//
// struct MyFormatter {
-// void operator()(string* out, int i) const {
+// void operator()(std::string* out, int i) const {
// out->append(std::to_string(i));
// }
// };
@@ -84,7 +84,7 @@
// argument to `absl::StrJoin()`:
//
// std::vector<int> v = {1, 2, 3, 4};
-// string s = absl::StrJoin(v, "-", MyFormatter());
+// std::string s = absl::StrJoin(v, "-", MyFormatter());
// EXPECT_EQ("1-2-3-4", s);
//
// The following standard formatters are provided within this file:
@@ -156,7 +156,7 @@
// StrJoin()
// -----------------------------------------------------------------------------
//
-// Joins a range of elements and returns the result as a string.
+// Joins a range of elements and returns the result as a std::string.
// `absl::StrJoin()` takes a range, a separator string to use between the
// elements joined, and an optional Formatter responsible for converting each
// argument in the range to a string.
@@ -167,22 +167,22 @@
// Example 1:
// // Joins a collection of strings. This pattern also works with a collection
// // of `absl::string_view` or even `const char*`.
-// std::vector<string> v = {"foo", "bar", "baz"};
-// string s = absl::StrJoin(v, "-");
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// Example 2:
// // Joins the values in the given `std::initializer_list<>` specified using
// // brace initialization. This pattern also works with an initializer_list
// // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
-// string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
+// std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// Example 3:
// // Joins a collection of ints. This pattern also works with floats,
// // doubles, int64s -- any `StrCat()`-compatible type.
// std::vector<int> v = {1, 2, 3, -4};
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3--4", s);
//
// Example 4:
@@ -193,7 +193,7 @@
// // `std::vector<int*>`.
// int x = 1, y = 2, z = 3;
// std::vector<int*> v = {&x, &y, &z};
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3", s);
//
// Example 5:
@@ -202,53 +202,53 @@
// v.emplace_back(new int(1));
// v.emplace_back(new int(2));
// v.emplace_back(new int(3));
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3", s);
//
// Example 6:
// // Joins a `std::map`, with each key-value pair separated by an equals
// // sign. This pattern would also work with, say, a
// // `std::vector<std::pair<>>`.
-// std::map<string, int> m = {
+// std::map<std::string, int> m = {
// std::make_pair("a", 1),
// std::make_pair("b", 2),
// std::make_pair("c", 3)};
-// string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
+// std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
// EXPECT_EQ("a=1,b=2,c=3", s);
//
// Example 7:
// // These examples show how `absl::StrJoin()` handles a few common edge
// // cases:
-// std::vector<string> v_empty;
+// std::vector<std::string> v_empty;
// EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
//
-// std::vector<string> v_one_item = {"foo"};
+// std::vector<std::string> v_one_item = {"foo"};
// EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
//
-// std::vector<string> v_empty_string = {""};
+// std::vector<std::string> v_empty_string = {""};
// EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
//
-// std::vector<string> v_one_item_empty_string = {"a", ""};
+// std::vector<std::string> v_one_item_empty_string = {"a", ""};
// EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
//
-// std::vector<string> v_two_empty_string = {"", ""};
+// std::vector<std::string> v_two_empty_string = {"", ""};
// EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
//
// Example 8:
// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
-// // a string using the `absl::AlphaNum` class.
-// string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+// // a std::string using the `absl::AlphaNum` class.
+// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
// EXPECT_EQ("123-abc-0.456", s);
template <typename Iterator, typename Formatter>
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinAlgorithm(start, end, sep, fmt);
}
template <typename Range, typename Formatter>
std::string StrJoin(const Range& range, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinRange(range, separator, fmt);
}
@@ -260,7 +260,7 @@
template <typename... T, typename Formatter>
std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinAlgorithm(value, separator, fmt);
}
@@ -280,7 +280,8 @@
}
template <typename... T>
-std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) {
+std::string StrJoin(const std::tuple<T...>& value,
+ absl::string_view separator) {
return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
}
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc
index 7fb0e49..d6f689f 100644
--- a/absl/strings/str_join_benchmark.cc
+++ b/absl/strings/str_join_benchmark.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -58,7 +58,8 @@
const int string_len = state.range(0);
const int num_pairs = state.range(1);
const std::string s(string_len, 'x');
- const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42));
+ const std::vector<std::pair<std::string, int>> v(num_pairs,
+ std::make_pair(s, 42));
for (auto _ : state) {
std::string s = absl::StrJoin(v, ",", absl::PairFormatter("="));
benchmark::DoNotOptimize(s);
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
index c941f9c..921d9c2 100644
--- a/absl/strings/str_join_test.cc
+++ b/absl/strings/str_join_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -118,7 +118,7 @@
{
// A std::map, which is a collection of std::pair<>s.
- std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} };
+ std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
}
@@ -140,7 +140,8 @@
}
{
- // A range of 1 element gives a std::string with that element but no separator.
+ // A range of 1 element gives a std::string with that element but no
+ // separator.
std::vector<std::string> v = {"foo"};
EXPECT_EQ("foo", absl::StrJoin(v, "-"));
}
@@ -173,9 +174,10 @@
TEST(StrJoin, CustomFormatter) {
std::vector<std::string> v{"One", "Two", "Three"};
{
- std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
- absl::StrAppend(out, "(", in, ")");
- });
+ std::string joined =
+ absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
+ absl::StrAppend(out, "(", in, ")");
+ });
EXPECT_EQ("(One)(Two)(Three)", joined);
}
{
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc
index 69efa35..280f63d 100644
--- a/absl/strings/str_replace.cc
+++ b/absl/strings/str_replace.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -68,11 +68,12 @@
// aren't inlined.
std::string StrReplaceAll(absl::string_view s,
- strings_internal::FixedMapping replacements) {
+ strings_internal::FixedMapping replacements) {
return StrReplaceAll<strings_internal::FixedMapping>(s, replacements);
}
-int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) {
+int StrReplaceAll(strings_internal::FixedMapping replacements,
+ std::string* target) {
return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
}
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h
index 3bfe4c6..30540d0 100644
--- a/absl/strings/str_replace.h
+++ b/absl/strings/str_replace.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,12 +29,12 @@
//
// Example:
//
-// string html_escaped = absl::StrReplaceAll(user_input, {
-// {"&", "&"},
-// {"<", "<"},
-// {">", ">"},
-// {"\"", """},
-// {"'", "'"}});
+// std::string html_escaped = absl::StrReplaceAll(user_input, {
+// {"&", "&"},
+// {"<", "<"},
+// {">", ">"},
+// {"\"", """},
+// {"'", "'"}});
#ifndef ABSL_STRINGS_STR_REPLACE_H_
#define ABSL_STRINGS_STR_REPLACE_H_
@@ -58,10 +58,11 @@
//
// Example:
//
-// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
-// {{"$count", absl::StrCat(5)},
-// {"$who", "Bob"},
-// {"#Noun", "Apples"}});
+// std::string s = absl::StrReplaceAll(
+// "$who bought $count #Noun. Thanks $who!",
+// {{"$count", absl::StrCat(5)},
+// {"$who", "Bob"},
+// {"#Noun", "Apples"}});
// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
ABSL_MUST_USE_RESULT std::string StrReplaceAll(
absl::string_view s,
@@ -78,20 +79,22 @@
// replacements["$who"] = "Bob";
// replacements["$count"] = "5";
// replacements["#Noun"] = "Apples";
-// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
-// replacements);
+// std::string s = absl::StrReplaceAll(
+// "$who bought $count #Noun. Thanks $who!",
+// replacements);
// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
//
// // A std::vector of std::pair elements can be more efficient.
-// std::vector<std::pair<const absl::string_view, string>> replacements;
+// std::vector<std::pair<const absl::string_view, std::string>> replacements;
// replacements.push_back({"&", "&"});
// replacements.push_back({"<", "<"});
// replacements.push_back({">", ">"});
-// string s = absl::StrReplaceAll("if (ptr < &foo)",
+// std::string s = absl::StrReplaceAll("if (ptr < &foo)",
// replacements);
// EXPECT_EQ("if (ptr < &foo)", s);
template <typename StrToStrMapping>
-std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements);
+std::string StrReplaceAll(absl::string_view s,
+ const StrToStrMapping& replacements);
// Overload of `StrReplaceAll()` to replace character sequences within a given
// output string *in place* with replacements provided within an initializer
@@ -99,7 +102,7 @@
//
// Example:
//
-// string s = std::string("$who bought $count #Noun. Thanks $who!");
+// std::string s = std::string("$who bought $count #Noun. Thanks $who!");
// int count;
// count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
// {"$who", "Bob"},
@@ -117,7 +120,7 @@
//
// Example:
//
-// string s = std::string("if (ptr < &foo)");
+// std::string s = std::string("if (ptr < &foo)");
// int count = absl::StrReplaceAll({{"&", "&"},
// {"<", "<"},
// {">", ">"}}, &s);
@@ -187,7 +190,8 @@
} // namespace strings_internal
template <typename StrToStrMapping>
-std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) {
+std::string StrReplaceAll(absl::string_view s,
+ const StrToStrMapping& replacements) {
auto subs = strings_internal::FindSubstitutions(s, replacements);
std::string result;
result.reserve(s.size());
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc
index 8386f2e..95b2dc1 100644
--- a/absl/strings/str_replace_benchmark.cc
+++ b/absl/strings/str_replace_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -54,7 +54,7 @@
size_t r = 0;
big_string = new std::string(1000 * 1000, ' ');
for (std::string phrase : {"the quick brown fox jumped over the lazy dogs",
- "pack my box with the five dozen liquor jugs"}) {
+ "pack my box with the five dozen liquor jugs"}) {
for (int i = 0; i < 10 * 1000; ++i) {
r = r * 237 + 41; // not very random.
memcpy(&(*big_string)[r % (big_string->size() - phrase.size())],
@@ -108,11 +108,11 @@
std::string src = *big_string;
for (auto _ : state) {
std::string dest = absl::StrReplaceAll(src, {{"the", "box"},
- {"brown", "quick"},
- {"jumped", "liquored"},
- {"dozen", "brown"},
- {"lazy", "pack"},
- {"liquor", "shakes"}});
+ {"brown", "quick"},
+ {"jumped", "liquored"},
+ {"dozen", "brown"},
+ {"lazy", "pack"},
+ {"liquor", "shakes"}});
ABSL_RAW_CHECK(dest == *after_replacing_many,
"not benchmarking intended behavior");
}
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc
index 5d003a2..1ca23af 100644
--- a/absl/strings/str_replace_test.cc
+++ b/absl/strings/str_replace_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -148,7 +148,7 @@
replacements["$count"] = "5";
replacements["#Noun"] = "Apples";
std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
- replacements);
+ replacements);
EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
}
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
index 0a68c52..2593130 100644
--- a/absl/strings/str_split.cc
+++ b/absl/strings/str_split.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index c7eb280..7333078 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -71,23 +71,23 @@
// - `ByLength`
// - `MaxSplits`
//
+// A Delimiter's `Find()` member function will be passed an input `text` that is
+// to be split and a position (`pos`) to begin searching for the next delimiter
+// in `text`. The returned absl::string_view should refer to the next occurrence
+// (after `pos`) of the represented delimiter; this returned absl::string_view
+// represents the next location where the input `text` should be broken.
//
-// A Delimiter's Find() member function will be passed the input text that is to
-// be split and the position to begin searching for the next delimiter in the
-// input text. The returned absl::string_view should refer to the next
-// occurrence (after pos) of the represented delimiter; this returned
-// absl::string_view represents the next location where the input string should
-// be broken. The returned absl::string_view may be zero-length if the Delimiter
-// does not represent a part of the string (e.g., a fixed-length delimiter). If
-// no delimiter is found in the given text, a zero-length absl::string_view
-// referring to text.end() should be returned (e.g.,
-// absl::string_view(text.end(), 0)). It is important that the returned
-// absl::string_view always be within the bounds of input text given as an
+// The returned absl::string_view may be zero-length if the Delimiter does not
+// represent a part of the string (e.g., a fixed-length delimiter). If no
+// delimiter is found in the input `text`, a zero-length absl::string_view
+// referring to `text.end()` should be returned (e.g.,
+// `text.substr(text.size())`). It is important that the returned
+// absl::string_view always be within the bounds of the input `text` given as an
// argument--it must not refer to a string that is physically located outside of
// the given string.
//
// The following example is a simple Delimiter object that is created with a
-// single char and will look for that char in the text passed to the Find()
+// single char and will look for that char in the text passed to the `Find()`
// function:
//
// struct SimpleDelimiter {
@@ -96,9 +96,9 @@
// absl::string_view Find(absl::string_view text, size_t pos) {
// auto found = text.find(c_, pos);
// if (found == absl::string_view::npos)
-// return absl::string_view(text.end(), 0);
+// return text.substr(text.size());
//
-// return absl::string_view(text, found, 1);
+// return text.substr(found, 1);
// }
// };
@@ -131,8 +131,7 @@
// ByChar
//
// A single character delimiter. `ByChar` is functionally equivalent to a
-// 1-char string within a `ByString` delimiter, but slightly more
-// efficient.
+// 1-char string within a `ByString` delimiter, but slightly more efficient.
//
// Example:
//
@@ -413,10 +412,10 @@
//
// The `StrSplit()` function adapts the returned collection to the collection
// specified by the caller (e.g. `std::vector` above). The returned collections
-// may contain `string`, `absl::string_view` (in which case the original string
-// being split must ensure that it outlives the collection), or any object that
-// can be explicitly created from an `absl::string_view`. This behavior works
-// for:
+// may contain `std::string`, `absl::string_view` (in which case the original
+// string being split must ensure that it outlives the collection), or any
+// object that can be explicitly created from an `absl::string_view`. This
+// behavior works for:
//
// 1) All standard STL containers including `std::vector`, `std::list`,
// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
@@ -460,7 +459,7 @@
// Example:
//
// // Stores first two split strings as the members in a std::pair.
-// std::pair<string, string> p = absl::StrSplit("a,b,c", ',');
+// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
// // p.first == "a", p.second == "b" // "c" is omitted.
//
// The `StrSplit()` function can be used multiple times to perform more
@@ -470,7 +469,7 @@
//
// // The input string "a=b=c,d=e,f=,g" becomes
// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
-// std::map<string, string> m;
+// std::map<std::string, std::string> m;
// for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
// m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
// }
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc
index 326ff74..28c25e8 100644
--- a/absl/strings/str_split_benchmark.cc
+++ b/absl/strings/str_split_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -35,16 +35,16 @@
return test;
}
-void BM_Split2StringPiece(benchmark::State& state) {
+void BM_Split2StringView(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
for (auto _ : state) {
std::vector<absl::string_view> result = absl::StrSplit(test, ';');
benchmark::DoNotOptimize(result);
}
}
-BENCHMARK_RANGE(BM_Split2StringPiece, 0, 1 << 20);
+BENCHMARK_RANGE(BM_Split2StringView, 0, 1 << 20);
-void BM_Split2StringPieceLifted(benchmark::State& state) {
+void BM_Split2StringViewLifted(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
std::vector<absl::string_view> result;
for (auto _ : state) {
@@ -52,7 +52,7 @@
}
benchmark::DoNotOptimize(result);
}
-BENCHMARK_RANGE(BM_Split2StringPieceLifted, 0, 1 << 20);
+BENCHMARK_RANGE(BM_Split2StringViewLifted, 0, 1 << 20);
void BM_Split2String(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
@@ -69,7 +69,8 @@
void BM_Split2SplitStringUsing(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
for (auto _ : state) {
- std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty());
+ std::vector<std::string> result =
+ absl::StrSplit(test, ';', absl::SkipEmpty());
benchmark::DoNotOptimize(result);
}
}
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
index 413ad31..ef6400e 100644
--- a/absl/strings/str_split_test.cc
+++ b/absl/strings/str_split_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -40,8 +40,8 @@
TEST(Split, TraitsTest) {
static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value,
"");
- static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value,
- "");
+ static_assert(
+ !absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, "");
static_assert(absl::strings_internal::SplitterIsConvertibleTo<
std::vector<std::string>>::value,
"");
@@ -182,7 +182,8 @@
{
// Uses the SkipWhitespace predicate.
using absl::SkipWhitespace;
- std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace());
+ std::vector<std::string> v =
+ absl::StrSplit(" a , ,,b,", ',', SkipWhitespace());
EXPECT_THAT(v, ElementsAre(" a ", "b"));
}
@@ -215,7 +216,8 @@
{
// Results stored in a std::multimap.
- std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+ std::multimap<std::string, std::string> m =
+ absl::StrSplit("a,1,b,2,a,3", ',');
EXPECT_EQ(3, m.size());
auto it = m.find("a");
EXPECT_EQ("1", it->second);
@@ -271,7 +273,8 @@
EXPECT_EQ("a", *it); // tests dereference
++it; // tests preincrement
EXPECT_NE(it, end);
- EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr
+ EXPECT_EQ("b",
+ std::string(it->data(), it->size())); // tests dereference as ptr
it++; // tests postincrement
EXPECT_EQ(it, end);
}
@@ -295,7 +298,8 @@
EXPECT_EQ("a", *it); // tests dereference
++it; // tests preincrement -- "b" should be skipped here.
EXPECT_NE(it, end);
- EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr
+ EXPECT_EQ("c",
+ std::string(it->data(), it->size())); // tests dereference as ptr
it++; // tests postincrement
EXPECT_EQ(it, end);
}
@@ -421,10 +425,13 @@
TestMapConversionOperator<std::map<std::string, std::string>>(splitter);
TestMapConversionOperator<
std::multimap<absl::string_view, absl::string_view>>(splitter);
- TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter);
- TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter);
+ TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(
+ splitter);
+ TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(
+ splitter);
TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
- TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter);
+ TestMapConversionOperator<std::unordered_map<std::string, std::string>>(
+ splitter);
// Tests conversion to std::pair
@@ -568,10 +575,9 @@
}
TEST(Split, Temporary) {
- // Use a std::string longer than the small-std::string-optimization length, so that when
- // the temporary is destroyed, if the splitter keeps a reference to the
- // std::string's contents, it'll reference freed memory instead of just dead
- // on-stack memory.
+ // Use a std::string longer than the SSO length, so that when the temporary is
+ // destroyed, if the splitter keeps a reference to the std::string's contents,
+ // it'll reference freed memory instead of just dead on-stack memory.
const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u";
EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input))
<< "Input should be larger than fits on the stack.";
@@ -647,6 +653,11 @@
}
}
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
TEST(Split, UTF8) {
// Tests splitting utf8 strings and utf8 delimiters.
std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
@@ -673,6 +684,10 @@
EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
}
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif // !defined(__cpp_char8_t)
TEST(Split, EmptyStringDelimiter) {
{
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
index 4ceeb6b..cb79d5d 100644
--- a/absl/strings/string_view.cc
+++ b/absl/strings/string_view.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -228,7 +228,7 @@
// member definitions that are required by the C++ standard, resulting in
// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks
// MSVC to choose only one definition for the symbol it decorates. See details
-// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
+// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
#ifdef _MSC_VER
#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany)
#else
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 6bcd3c4..f8b2001 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,7 +32,7 @@
#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
+#include <string_view> // IWYU pragma: export
namespace absl {
using std::string_view;
@@ -101,7 +101,6 @@
// example, when splitting a string, `std::vector<absl::string_view>` is a
// natural data type for the output.
//
-//
// When constructed from a source which is nul-terminated, the `string_view`
// itself will not include the nul-terminator unless a specific size (including
// the nul) is passed to the constructor. As a result, common idioms that work
@@ -277,7 +276,7 @@
// Checks if the `string_view` is empty (refers to no characters).
constexpr bool empty() const noexcept { return length_ == 0; }
- // std::string:view::operator[]
+ // string_view::operator[]
//
// Returns the ith element of an `string_view` using the array operator.
// Note that this operator does not perform any bounds checking.
@@ -355,7 +354,7 @@
string_view substr(size_type pos, size_type n = npos) const {
if (ABSL_PREDICT_FALSE(pos > length_))
base_internal::ThrowStdOutOfRange("absl::string_view::substr");
- n = std::min(n, length_ - pos);
+ n = (std::min)(n, length_ - pos);
return string_view(ptr_ + pos, n);
}
@@ -368,7 +367,7 @@
// on the respective sizes of the two `string_view`s to determine which is
// smaller, equal, or greater.
int compare(string_view x) const noexcept {
- auto min_length = std::min(length_, x.length_);
+ auto min_length = (std::min)(length_, x.length_);
if (min_length > 0) {
int r = memcmp(ptr_, x.ptr_, min_length);
if (r < 0) return -1;
@@ -490,7 +489,7 @@
private:
static constexpr size_type kMaxSize =
- std::numeric_limits<difference_type>::max();
+ (std::numeric_limits<difference_type>::max)();
static constexpr size_type CheckLengthInternal(size_type len) {
return ABSL_ASSERT(len <= kMaxSize), len;
@@ -508,6 +507,7 @@
if (len != y.size()) {
return false;
}
+
return x.data() == y.data() || len <= 0 ||
memcmp(x.data(), y.data(), len) == 0;
}
@@ -517,7 +517,7 @@
}
inline bool operator<(string_view x, string_view y) noexcept {
- auto min_size = std::min(x.size(), y.size());
+ auto min_size = (std::min)(x.size(), y.size());
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
return (r < 0) || (r == 0 && x.size() < y.size());
}
@@ -547,7 +547,7 @@
// Provided because std::string_view::substr throws if `pos > size()`
inline string_view ClippedSubstr(string_view s, size_t pos,
size_t n = string_view::npos) {
- pos = std::min(pos, static_cast<size_t>(s.size()));
+ pos = (std::min)(pos, static_cast<size_t>(s.size()));
return s.substr(pos, n);
}
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc
index fb46db1..46909cb 100644
--- a/absl/strings/string_view_benchmark.cc
+++ b/absl/strings/string_view_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -151,7 +151,7 @@
std::string haystack(state.range(0), '0');
absl::string_view s(haystack);
for (auto _ : state) {
- s.find("x"); // not present; length 1
+ benchmark::DoNotOptimize(s.find("x")); // not present; length 1
}
}
BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20);
@@ -160,7 +160,7 @@
std::string haystack(state.range(0), '0');
absl::string_view s(haystack);
for (auto _ : state) {
- s.find("xx"); // not present; length 2
+ benchmark::DoNotOptimize(s.find("xx")); // not present; length 2
}
}
BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20);
@@ -169,7 +169,7 @@
std::string haystack(state.range(0), '0');
absl::string_view s(haystack);
for (auto _ : state) {
- s.find('x'); // not present
+ benchmark::DoNotOptimize(s.find('x')); // not present
}
}
BENCHMARK(BM_find_one_char)->Range(1, 1 << 20);
@@ -178,7 +178,7 @@
std::string haystack(state.range(0), '0');
absl::string_view s(haystack);
for (auto _ : state) {
- s.rfind('x'); // not present
+ benchmark::DoNotOptimize(s.rfind('x')); // not present
}
}
BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20);
@@ -193,7 +193,7 @@
absl::string_view s(haystack);
for (auto _ : state) {
- s.find_first_of(needle);
+ benchmark::DoNotOptimize(s.find_first_of(needle));
}
}
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index a94e822..f5acf1d 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -284,9 +284,10 @@
}
#undef COMPARE
-// Sadly, our users often confuse string::npos with absl::string_view::npos;
-// So much so that we test here that they are the same. They need to
-// both be unsigned, and both be the maximum-valued integer of their type.
+// Sadly, our users often confuse std::string::npos with
+// absl::string_view::npos; So much so that we test here that they are the same.
+// They need to both be unsigned, and both be the maximum-valued integer of
+// their type.
template <typename T>
struct is_type {
@@ -678,9 +679,9 @@
EXPECT_EQ(a.substr(23, absl::string_view::npos), c);
// throw exception
#ifdef ABSL_HAVE_EXCEPTIONS
- EXPECT_THROW(a.substr(99, 2), std::out_of_range);
+ EXPECT_THROW((void)a.substr(99, 2), std::out_of_range);
#else
- EXPECT_DEATH(a.substr(99, 2), "absl::string_view::substr");
+ EXPECT_DEATH((void)a.substr(99, 2), "absl::string_view::substr");
#endif
}
@@ -755,7 +756,6 @@
std::string s1("123");
s1 += '\0';
s1 += "456";
- absl::string_view b(s1);
absl::string_view e;
std::string s2;
@@ -995,8 +995,8 @@
TEST(StringViewTest, Noexcept) {
EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
const std::string&>::value));
- EXPECT_TRUE(
- (std::is_nothrow_constructible<absl::string_view, const std::string&>::value));
+ EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
+ const std::string&>::value));
EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value);
constexpr absl::string_view sp;
EXPECT_TRUE(noexcept(sp.begin()));
diff --git a/absl/strings/strip.h b/absl/strings/strip.h
index 8d0d7c6..e1341e0 100644
--- a/absl/strings/strip.h
+++ b/absl/strings/strip.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc
index 40c4c60..e4e00cb 100644
--- a/absl/strings/strip_test.cc
+++ b/absl/strings/strip_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,9 +27,6 @@
namespace {
-using testing::ElementsAre;
-using testing::IsEmpty;
-
TEST(Strip, ConsumePrefixOneChar) {
absl::string_view input("abc");
EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index 3b20059..bc17695 100644
--- a/absl/strings/substitute.cc
+++ b/absl/strings/substitute.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 4de7b4e..507bc4f 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,18 +36,17 @@
// use at that location within the format string.
//
// Example 1:
-// string s = Substitute("$1 purchased $0 $2. Thanks $1!",
-// 5, "Bob", "Apples");
+// std::string s = Substitute("$1 purchased $0 $2. Thanks $1!",
+// 5, "Bob", "Apples");
// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s);
//
// Example 2:
-// string s = "Hi. ";
+// std::string s = "Hi. ";
// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
//
-//
// Supported types:
-// * absl::string_view, string, const char* (null is equivalent to "")
+// * absl::string_view, std::string, const char* (null is equivalent to "")
// * int32_t, int64_t, uint32_t, uint64
// * float, double
// * bool (Printed as "true" or "false")
@@ -456,7 +455,7 @@
// Example:
// template <typename... Args>
// void VarMsg(absl::string_view format, const Args&... args) {
-// string s = absl::Substitute(format, args...);
+// std::string s = absl::Substitute(format, args...);
ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
std::string result;
@@ -574,70 +573,70 @@
"contains one of $1-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1)
+ const substitute_internal::Arg& a1)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
"There were 2 substitution arguments given, but "
"this format std::string is either missing its $0/$1, or "
"contains one of $2-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
"There were 3 substitution arguments given, but "
"this format std::string is either missing its $0/$1/$2, or "
"contains one of $3-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2,
- const substitute_internal::Arg& a3)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
"There were 4 substitution arguments given, but "
"this format std::string is either missing its $0-$3, or "
"contains one of $4-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2,
- const substitute_internal::Arg& a3,
- const substitute_internal::Arg& a4)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
"There were 5 substitution arguments given, but "
"this format std::string is either missing its $0-$4, or "
"contains one of $5-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2,
- const substitute_internal::Arg& a3,
- const substitute_internal::Arg& a4,
- const substitute_internal::Arg& a5)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
"There were 6 substitution arguments given, but "
"this format std::string is either missing its $0-$5, or "
"contains one of $6-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2,
- const substitute_internal::Arg& a3,
- const substitute_internal::Arg& a4,
- const substitute_internal::Arg& a5,
- const substitute_internal::Arg& a6)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
"There were 7 substitution arguments given, but "
"this format std::string is either missing its $0-$6, or "
"contains one of $7-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2,
- const substitute_internal::Arg& a3,
- const substitute_internal::Arg& a4,
- const substitute_internal::Arg& a5,
- const substitute_internal::Arg& a6,
- const substitute_internal::Arg& a7)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
"There were 8 substitution arguments given, but "
"this format std::string is either missing its $0-$7, or "
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
index 144df01..f656890 100644
--- a/absl/strings/substitute_test.cc
+++ b/absl/strings/substitute_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index f52e9d4..5e69847 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
@@ -69,6 +69,10 @@
"notification.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }),
deps = [
":graphcycles_internal",
"//absl/base",
@@ -170,18 +174,31 @@
],
)
-cc_test(
- name = "mutex_benchmark",
+cc_library(
+ name = "mutex_benchmark_common",
+ testonly = 1,
srcs = ["mutex_benchmark.cc"],
copts = ABSL_TEST_COPTS,
- tags = ["benchmark"],
- visibility = ["//visibility:private"],
+ visibility = [
+ "//absl/synchronization:__pkg__",
+ ],
deps = [
":synchronization",
":thread_pool",
"//absl/base",
"@com_github_google_benchmark//:benchmark_main",
],
+ alwayslink = 1,
+)
+
+cc_binary(
+ name = "mutex_benchmark",
+ testonly = 1,
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":mutex_benchmark_common",
+ ],
)
cc_test(
@@ -232,10 +249,6 @@
"lifetime_test.cc",
],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
tags = ["no_test_ios_x86_64"],
deps = [
":synchronization",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index de0d7b7..68473b7 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,142 +14,182 @@
# limitations under the License.
#
-list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS
- "barrier.h"
- "blocking_counter.h"
- "mutex.h"
- "notification.h"
+absl_cc_library(
+ NAME
+ graphcycles_internal
+ HDRS
+ "internal/graphcycles.h"
+ SRCS
+ "internal/graphcycles.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::base_internal
+ absl::core_headers
+ absl::malloc_internal
)
-
-list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS
- "internal/create_thread_identity.h"
- "internal/graphcycles.h"
- "internal/kernel_timeout.h"
- "internal/per_thread_sem.h"
- "internal/thread_pool.h"
- "internal/waiter.h"
-)
-
-
-
-# synchronization library
-list(APPEND SYNCHRONIZATION_SRC
- "barrier.cc"
- "blocking_counter.cc"
- "internal/create_thread_identity.cc"
- "internal/per_thread_sem.cc"
- "internal/waiter.cc"
- "internal/graphcycles.cc"
- "notification.cc"
- "mutex.cc"
-)
-
-set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
-
-absl_library(
- TARGET
- absl_synchronization
- SOURCES
- ${SYNCHRONIZATION_SRC}
- PUBLIC_LIBRARIES
- ${SYNCHRONIZATION_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
synchronization
+ HDRS
+ "barrier.h"
+ "blocking_counter.h"
+ "internal/create_thread_identity.h"
+ "internal/kernel_timeout.h"
+ "internal/mutex_nonprod.inc"
+ "internal/per_thread_sem.h"
+ "internal/waiter.h"
+ "mutex.h"
+ "notification.h"
+ SRCS
+ "barrier.cc"
+ "blocking_counter.cc"
+ "internal/create_thread_identity.cc"
+ "internal/per_thread_sem.cc"
+ "internal/waiter.cc"
+ "notification.cc"
+ "mutex.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::graphcycles_internal
+ absl::base
+ absl::base_internal
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::malloc_internal
+ absl::stacktrace
+ absl::symbolize
+ absl::time
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-
-# test barrier_test
-set(BARRIER_TEST_SRC "barrier_test.cc")
-set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
barrier_test
- SOURCES
- ${BARRIER_TEST_SRC}
- PUBLIC_LIBRARIES
- ${BARRIER_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "barrier_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test blocking_counter_test
-set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc")
-set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
blocking_counter_test
- SOURCES
- ${BLOCKING_COUNTER_TEST_SRC}
- PUBLIC_LIBRARIES
- ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "blocking_counter_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test graphcycles_test
-set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc")
-set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
graphcycles_test
- SOURCES
- ${GRAPHCYCLES_TEST_SRC}
- PUBLIC_LIBRARIES
- ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/graphcycles_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::graphcycles_internal
+ absl::base
+ absl::core_headers
+ gmock_main
)
+absl_cc_library(
+ NAME
+ thread_pool
+ HDRS
+ "internal/thread_pool.h"
+ DEPS
+ absl::synchronization
+ absl::core_headers
+ TESTONLY
+)
-# test mutex_test
-set(MUTEX_TEST_SRC "mutex_test.cc")
-set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
mutex_test
- SOURCES
- ${MUTEX_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MUTEX_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "mutex_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::thread_pool
+ absl::base
+ absl::core_headers
+ absl::memory
+ absl::time
+ gmock_main
)
-
-# test notification_test
-set(NOTIFICATION_TEST_SRC "notification_test.cc")
-set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
notification_test
- SOURCES
- ${NOTIFICATION_TEST_SRC}
- PUBLIC_LIBRARIES
- ${NOTIFICATION_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "notification_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test per_thread_sem_test_common
-set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc")
-set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings)
-
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
per_thread_sem_test_common
- SOURCES
- ${PER_THREAD_SEM_TEST_COMMON_SRC}
- PUBLIC_LIBRARIES
- ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/per_thread_sem_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::base
+ absl::strings
+ absl::time
+ gmock
+ TESTONLY
)
+absl_cc_test(
+ NAME
+ per_thread_sem_test
+ SRCS
+ "internal/per_thread_sem_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::per_thread_sem_test_common
+ absl::synchronization
+ absl::base
+ absl::strings
+ absl::time
+ gmock_main
+)
-
-
-
-
-
+absl_cc_test(
+ NAME
+ lifetime_test
+ SRCS
+ "lifetime_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::base
+ absl::core_headers
+ Threads::Threads
+)
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc
index a1b3ad5..c2c539a 100644
--- a/absl/synchronization/barrier.cc
+++ b/absl/synchronization/barrier.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/barrier.h b/absl/synchronization/barrier.h
index f834fee..23bb2f5 100644
--- a/absl/synchronization/barrier.h
+++ b/absl/synchronization/barrier.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/barrier_test.cc b/absl/synchronization/barrier_test.cc
index d6cabab..bfc6cb1 100644
--- a/absl/synchronization/barrier_test.cc
+++ b/absl/synchronization/barrier_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
index 7e68e96..481a06b 100644
--- a/absl/synchronization/blocking_counter.cc
+++ b/absl/synchronization/blocking_counter.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
index 557ed02..4c66e0a 100644
--- a/absl/synchronization/blocking_counter.h
+++ b/absl/synchronization/blocking_counter.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
index e8223f8..c63e339 100644
--- a/absl/synchronization/blocking_counter_test.cc
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index e7a65cd..6e93605 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -67,6 +67,30 @@
return (addr + align - 1) & ~(align - 1);
}
+static void ResetThreadIdentity(base_internal::ThreadIdentity* identity) {
+ base_internal::PerThreadSynch* pts = &identity->per_thread_synch;
+ pts->next = nullptr;
+ pts->skip = nullptr;
+ pts->may_skip = false;
+ pts->waitp = nullptr;
+ pts->suppress_fatal_errors = false;
+ pts->readers = 0;
+ pts->priority = 0;
+ pts->next_priority_read_cycles = 0;
+ pts->state.store(base_internal::PerThreadSynch::State::kAvailable,
+ std::memory_order_relaxed);
+ pts->maybe_unlocking = false;
+ pts->wake = false;
+ pts->cond_waiter = false;
+ pts->all_locks = nullptr;
+ identity->waiter_state = {};
+ identity->blocked_count_ptr = nullptr;
+ identity->ticker.store(0, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+ identity->next = nullptr;
+}
+
static base_internal::ThreadIdentity* NewThreadIdentity() {
base_internal::ThreadIdentity* identity = nullptr;
@@ -90,7 +114,7 @@
RoundUp(reinterpret_cast<intptr_t>(allocation),
base_internal::PerThreadSynch::kAlignment));
}
- memset(identity, 0, sizeof(*identity));
+ ResetThreadIdentity(identity);
return identity;
}
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h
index 1bb87de..ebb16c5 100644
--- a/absl/synchronization/internal/create_thread_identity.h
+++ b/absl/synchronization/internal/create_thread_identity.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -50,4 +50,5 @@
} // namespace synchronization_internal
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index d3878de..0c8c756 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h
index 2e6686a..e5bde00 100644
--- a/absl/synchronization/internal/graphcycles.h
+++ b/absl/synchronization/internal/graphcycles.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc
index a239c25..54823e0 100644
--- a/absl/synchronization/internal/graphcycles_benchmark.cc
+++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
index 9a85b39..58e8477 100644
--- a/absl/synchronization/internal/graphcycles_test.cc
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index bb70800..61c72e7 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -53,6 +53,7 @@
// We explicitly do not support other custom formats: timespec, int64_t nanos.
// Unify on this and absl::Time, please.
+
bool has_timeout() const { return ns_ != 0; }
private:
@@ -76,7 +77,7 @@
if (x <= 0) x = 1;
// A time larger than what can be represented to the kernel is treated
// as no timeout.
- if (x == std::numeric_limits<int64_t>::max()) x = 0;
+ if (x == (std::numeric_limits<int64_t>::max)()) x = 0;
return x;
}
@@ -90,7 +91,7 @@
ERROR,
"Tried to create a timespec from a non-timeout; never do this.");
// But we'll try to continue sanely. no-timeout ~= saturated timeout.
- n = std::numeric_limits<int64_t>::max();
+ n = (std::numeric_limits<int64_t>::max)();
}
// Kernel APIs validate timespecs as being at or after the epoch,
@@ -100,8 +101,8 @@
if (n < 0) n = 0;
struct timespec abstime;
- int64_t seconds = std::min(n / kNanosPerSecond,
- int64_t{std::numeric_limits<time_t>::max()});
+ int64_t seconds = (std::min)(n / kNanosPerSecond,
+ int64_t{(std::numeric_limits<time_t>::max)()});
abstime.tv_sec = static_cast<time_t>(seconds);
abstime.tv_nsec =
static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
@@ -119,7 +120,7 @@
// <intsafe.h> and <WinBase.h>.
typedef unsigned long DWord; // NOLINT
DWord InMillisecondsFromNow() const {
- constexpr DWord kInfinite = std::numeric_limits<DWord>::max();
+ constexpr DWord kInfinite = (std::numeric_limits<DWord>::max)();
if (!has_timeout()) {
return kInfinite;
}
@@ -130,7 +131,7 @@
if (ns_ >= now) {
// Round up so that Now() + ms_from_now >= ns_.
constexpr uint64_t max_nanos =
- std::numeric_limits<int64_t>::max() - 999999u;
+ (std::numeric_limits<int64_t>::max)() - 999999u;
uint64_t ms_from_now =
(std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
if (ms_from_now > kInfinite) {
@@ -148,4 +149,5 @@
} // namespace synchronization_internal
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc
index 45c6032..267deaf 100644
--- a/absl/synchronization/internal/mutex_nonprod.cc
+++ b/absl/synchronization/internal/mutex_nonprod.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
index 0aab3d1..b8d5af7 100644
--- a/absl/synchronization/internal/mutex_nonprod.inc
+++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -214,6 +214,9 @@
// stack) should use this constructor.
explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
+ constexpr explicit SynchronizationStorage(absl::ConstInitType)
+ : is_dynamic_(false), once_(), space_{{0}} {}
+
SynchronizationStorage(SynchronizationStorage&) = delete;
SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc
index caa2baf..b7014fb 100644
--- a/absl/synchronization/internal/per_thread_sem.cc
+++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -89,6 +89,7 @@
if (identity->blocked_count_ptr != nullptr) {
identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
}
+
identity->is_idle.store(false, std::memory_order_relaxed);
identity->wait_start.store(0, std::memory_order_relaxed);
return !timeout;
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h
index 678b69e..e7da070 100644
--- a/absl/synchronization/internal/per_thread_sem.h
+++ b/absl/synchronization/internal/per_thread_sem.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -104,4 +104,5 @@
absl::synchronization_internal::KernelTimeout t) {
return AbslInternalPerThreadSemWait(t);
}
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc
index c29d840..dba7239 100644
--- a/absl/synchronization/internal/per_thread_sem_test.cc
+++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -114,10 +114,9 @@
min_cycles = std::min(min_cycles, cycles);
total_cycles += cycles;
}
- std::string out =
- StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=",
- absl::SixDigits(static_cast<double>(total_cycles) /
- kNumIterations));
+ std::string out = StrCat(
+ msg, "min cycle count=", min_cycles, " avg cycle count=",
+ absl::SixDigits(static_cast<double>(total_cycles) / kNumIterations));
printf("%s\n", out.c_str());
partner_thread.join();
@@ -152,12 +151,16 @@
}
TEST_F(PerThreadSemTest, Timeouts) {
- absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+ const absl::Duration delay = absl::Milliseconds(50);
+ const absl::Time start = absl::Now();
+ EXPECT_FALSE(Wait(start + delay));
+ const absl::Duration elapsed = absl::Now() - start;
// Allow for a slight early return, to account for quality of implementation
// issues on various platforms.
const absl::Duration slop = absl::Microseconds(200);
- EXPECT_FALSE(Wait(timeout));
- EXPECT_LE(timeout, absl::Now() + slop);
+ EXPECT_LE(delay - slop, elapsed)
+ << "Wait returned " << delay - elapsed
+ << " early (with " << slop << " slop), start time was " << start;
absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
EXPECT_FALSE(Wait(negative_timeout));
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h
index 8464042..7f458f5 100644
--- a/absl/synchronization/internal/thread_pool.h
+++ b/absl/synchronization/internal/thread_pool.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,6 +16,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
#include <cassert>
+#include <cstddef>
#include <functional>
#include <queue>
#include <thread> // NOLINT(build/c++11)
@@ -42,7 +43,7 @@
~ThreadPool() {
{
absl::MutexLock l(&mu_);
- for (int i = 0; i < threads_.size(); ++i) {
+ for (size_t i = 0; i < threads_.size(); i++) {
queue_.push(nullptr); // Shutdown signal.
}
}
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 768c520..74b0965 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -40,6 +40,7 @@
#include <atomic>
#include <cassert>
#include <cstdint>
+
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/base/optimization.h"
@@ -81,6 +82,7 @@
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
+
class Futex {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index 23166f4..66b4beb 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
index 90c9009..0279c8f 100644
--- a/absl/synchronization/lifetime_test.cc
+++ b/absl/synchronization/lifetime_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,6 +17,7 @@
#include <type_traits>
#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
@@ -72,23 +73,19 @@
// Launch thread 1 and thread 2, and block on their completion.
// If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally
// constructed instance instead.
-void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
- absl::Notification* notification) {
+void RunTests(absl::Mutex* mutex, absl::CondVar* condvar) {
absl::Mutex default_mutex;
absl::CondVar default_condvar;
- absl::Notification default_notification;
+ absl::Notification notification;
if (!mutex) {
mutex = &default_mutex;
}
if (!condvar) {
condvar = &default_condvar;
}
- if (!notification) {
- notification = &default_notification;
- }
bool state = false;
- std::thread thread_one(ThreadOne, mutex, condvar, notification, &state);
- std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state);
+ std::thread thread_one(ThreadOne, mutex, condvar, ¬ification, &state);
+ std::thread thread_two(ThreadTwo, mutex, condvar, ¬ification, &state);
thread_one.join();
thread_two.join();
}
@@ -96,10 +93,13 @@
void TestLocals() {
absl::Mutex mutex;
absl::CondVar condvar;
- absl::Notification notification;
- RunTests(&mutex, &condvar, ¬ification);
+ RunTests(&mutex, &condvar);
}
+// Normal kConstInit usage
+ABSL_CONST_INIT absl::Mutex const_init_mutex(absl::kConstInit);
+void TestConstInitGlobal() { RunTests(&const_init_mutex, nullptr); }
+
// Global variables during start and termination
//
// In a translation unit, static storage duration variables are initialized in
@@ -122,10 +122,53 @@
Function fn_;
};
+// kConstInit
+// Test early usage. (Declaration comes first; definitions must appear after
+// the test runner.)
+extern absl::Mutex early_const_init_mutex;
+// (Normally I'd write this +[], to make the cast-to-function-pointer explicit,
+// but in some MSVC setups we support, lambdas provide conversion operators to
+// different flavors of function pointers, making this trick ambiguous.)
+OnConstruction test_early_const_init([] {
+ RunTests(&early_const_init_mutex, nullptr);
+});
+// This definition appears before test_early_const_init, but it should be
+// initialized first (due to constant initialization). Test that the object
+// actually works when constructed this way.
+ABSL_CONST_INIT absl::Mutex early_const_init_mutex(absl::kConstInit);
+
+// Furthermore, test that the const-init c'tor doesn't stomp over the state of
+// a Mutex. Really, this is a test that the platform under test correctly
+// supports C++11 constant initialization. (The constant-initialization
+// constructors of globals "happen at link time"; memory is pre-initialized,
+// before the constructors of either grab_lock or check_still_locked are run.)
+extern absl::Mutex const_init_sanity_mutex;
+OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS {
+ const_init_sanity_mutex.Lock();
+});
+ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
+OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS {
+ const_init_sanity_mutex.AssertHeld();
+ const_init_sanity_mutex.Unlock();
+});
+
+// Test shutdown usage. (Declarations come first; definitions must appear after
+// the test runner.)
+extern absl::Mutex late_const_init_mutex;
+// OnDestruction is being used here as a global variable, even though it has a
+// non-trivial destructor. This is against the style guide. We're violating
+// that rule here to check that the exception we allow for kConstInit is safe.
+// NOLINTNEXTLINE
+OnDestruction test_late_const_init([] {
+ RunTests(&late_const_init_mutex, nullptr);
+});
+ABSL_CONST_INIT absl::Mutex late_const_init_mutex(absl::kConstInit);
+
} // namespace
int main() {
TestLocals();
+ TestConstInitGlobal();
// Explicitly call exit(0) here, to make it clear that we intend for the
// above global object destructors to run.
std::exit(0);
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 9d59a79..97c5919 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -118,6 +118,10 @@
} // namespace
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+ bool locking, bool trylock,
+ bool read_lock);
+
void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) {
submit_profile_data.Store(fn);
}
@@ -233,15 +237,14 @@
SYNCH_EV_SIGNALALL,
};
-enum { // Event flags
- SYNCH_F_R = 0x01, // reader event
- SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held
- SYNCH_F_ACQ = 0x04, // event is an acquire
+enum { // Event flags
+ SYNCH_F_R = 0x01, // reader event
+ SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held
+ SYNCH_F_TRY = 0x04, // TryLock or ReaderTryLock
+ SYNCH_F_UNLOCK = 0x08, // Unlock or ReaderUnlock
SYNCH_F_LCK_W = SYNCH_F_LCK,
SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R,
- SYNCH_F_ACQ_W = SYNCH_F_ACQ,
- SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R,
};
} // anonymous namespace
@@ -250,21 +253,22 @@
int flags;
const char *msg;
} event_properties[] = {
- { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " },
- { 0, "TryLock failed " },
- { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " },
- { 0, "ReaderTryLock failed " },
- { SYNCH_F_ACQ_W, "Lock blocking " },
- { SYNCH_F_LCK_W, "Lock returning " },
- { SYNCH_F_ACQ_R, "ReaderLock blocking " },
- { SYNCH_F_LCK_R, "ReaderLock returning " },
- { SYNCH_F_LCK_W, "Unlock " },
- { SYNCH_F_LCK_R, "ReaderUnlock " },
- { 0, "Wait on " },
- { 0, "Wait unblocked " },
- { 0, "Signal on " },
- { 0, "SignalAll on " },
+ {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "},
+ {0, "TryLock failed "},
+ {SYNCH_F_LCK_R | SYNCH_F_TRY, "ReaderTryLock succeeded "},
+ {0, "ReaderTryLock failed "},
+ {0, "Lock blocking "},
+ {SYNCH_F_LCK_W, "Lock returning "},
+ {0, "ReaderLock blocking "},
+ {SYNCH_F_LCK_R, "ReaderLock returning "},
+ {SYNCH_F_LCK_W | SYNCH_F_UNLOCK, "Unlock "},
+ {SYNCH_F_LCK_R | SYNCH_F_UNLOCK, "ReaderUnlock "},
+ {0, "Wait on "},
+ {0, "Wait unblocked "},
+ {0, "Signal on "},
+ {0, "SignalAll on "},
};
+
static absl::base_internal::SpinLock synch_event_mu(
absl::base_internal::kLinkerInitialized);
// protects synch_event
@@ -414,9 +418,26 @@
ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj,
(e == nullptr ? "" : e->name), buffer);
}
- if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr &&
- e->invariant != nullptr) {
- (*e->invariant)(e->arg);
+ const int flags = event_properties[ev].flags;
+ if ((flags & SYNCH_F_LCK) != 0 && e != nullptr && e->invariant != nullptr) {
+ // Calling the invariant as is causes problems under ThreadSanitizer.
+ // We are currently inside of Mutex Lock/Unlock and are ignoring all
+ // memory accesses and synchronization. If the invariant transitively
+ // synchronizes something else and we ignore the synchronization, we will
+ // get false positive race reports later.
+ // Reuse EvalConditionAnnotated to properly call into user code.
+ struct local {
+ static bool pred(SynchEvent *ev) {
+ (*ev->invariant)(ev->arg);
+ return false;
+ }
+ };
+ Condition cond(&local::pred, e);
+ Mutex *mu = static_cast<Mutex *>(obj);
+ const bool locking = (flags & SYNCH_F_UNLOCK) == 0;
+ const bool trylock = (flags & SYNCH_F_TRY) != 0;
+ const bool read_lock = (flags & SYNCH_F_R) != 0;
+ EvalConditionAnnotated(&cond, mu, locking, trylock, read_lock);
}
UnrefSynchEvent(e);
}
@@ -1079,7 +1100,7 @@
// if the wait extends past the absolute time specified, even if "s" is still
// on the mutex queue. In this case, remove "s" from the queue and return
// true, otherwise return false.
-void Mutex::Block(PerThreadSynch *s) {
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Block(PerThreadSynch *s) {
while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) {
if (!DecrementSynchSem(this, s, s->waitp->timeout)) {
// After a timeout, we go into a spin loop until we remove ourselves
@@ -1552,7 +1573,7 @@
ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how));
this->LockSlowLoop(&waitp, flags);
bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop
- cond.Eval();
+ EvalConditionAnnotated(&cond, this, true, false, how == kShared);
ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0);
return res;
}
@@ -1730,12 +1751,17 @@
// Compute cond->Eval() and tell race detectors that we do it under mutex mu.
static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
- bool locking, Mutex::MuHow how) {
+ bool locking, bool trylock,
+ bool read_lock) {
// Delicate annotation dance.
// We are currently inside of read/write lock/unlock operation.
// All memory accesses are ignored inside of mutex operations + for unlock
// operation tsan considers that we've already released the mutex.
bool res = false;
+#ifdef THREAD_SANITIZER
+ const int flags = read_lock ? __tsan_mutex_read_lock : 0;
+ const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
+#endif
if (locking) {
// For lock we pretend that we have finished the operation,
// evaluate the predicate, then unlock the mutex and start locking it again
@@ -1743,24 +1769,26 @@
// Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan
// will think the lock acquisition is recursive which will trigger
// deadlock detector.
- ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, tryflags, 0);
res = cond->Eval();
- ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+ // There is no "try" version of Unlock, so use flags instead of tryflags.
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, tryflags);
} else {
// Similarly, for unlock we pretend that we have unlocked the mutex,
// lock the mutex, evaluate the predicate, and start unlocking it again
// to match the annotation at the end of outer unlock operation.
- ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, flags);
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, flags, 0);
res = cond->Eval();
- ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
}
// Prevent unused param warnings in non-TSAN builds.
static_cast<void>(mu);
- static_cast<void>(how);
+ static_cast<void>(trylock);
+ static_cast<void>(read_lock);
return res;
}
@@ -1806,7 +1834,8 @@
v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) +
how->fast_add,
std::memory_order_acquire, std::memory_order_relaxed)) {
- if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) {
+ if (cond == nullptr ||
+ EvalConditionAnnotated(cond, this, true, false, how == kShared)) {
return true;
}
unlock = true;
@@ -1824,7 +1853,8 @@
}
this->LockSlowLoop(&waitp, flags);
return waitp.cond != nullptr || // => cond known true from LockSlowLoop
- cond == nullptr || EvalConditionAnnotated(cond, this, true, how);
+ cond == nullptr ||
+ EvalConditionAnnotated(cond, this, true, false, how == kShared);
}
// RAW_CHECK_FMT() takes a condition, a printf-style format string, and
@@ -1841,7 +1871,7 @@
// Test for either of two situations that should not occur in v:
// kMuWriter and kMuReader
// kMuWrWait and !kMuWait
- const intptr_t w = v ^ kMuWait;
+ const uintptr_t w = v ^ kMuWait;
// By flipping that bit, we can now test for:
// kMuWriter and kMuReader in w
// kMuWrWait and kMuWait in w
@@ -1880,7 +1910,8 @@
waitp->how->fast_add,
std::memory_order_acquire, std::memory_order_relaxed)) {
if (waitp->cond == nullptr ||
- EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ EvalConditionAnnotated(waitp->cond, this, true, false,
+ waitp->how == kShared)) {
break; // we timed out, or condition true, so return
}
this->UnlockSlow(waitp); // got lock but condition false
@@ -1923,7 +1954,8 @@
std::memory_order_release,
std::memory_order_relaxed));
if (waitp->cond == nullptr ||
- EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ EvalConditionAnnotated(waitp->cond, this, true, false,
+ waitp->how == kShared)) {
break; // we timed out, or condition true, so return
}
this->UnlockSlow(waitp); // got lock but condition false
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index a378190..c38e356 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -61,6 +61,7 @@
#include <cstdint>
#include <string>
+#include "absl/base/const_init.h"
#include "absl/base/internal/identity.h"
#include "absl/base/internal/low_level_alloc.h"
#include "absl/base/internal/thread_identity.h"
@@ -136,7 +137,27 @@
class LOCKABLE Mutex {
public:
+ // Creates a `Mutex` that is not held by anyone. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ //
+ // To create `Mutex` instances with static storage duration
+ // (e.g. a namespace-scoped or global variable), see
+ // `Mutex::Mutex(absl::kConstInit)` below instead.
Mutex();
+
+ // Creates a mutex with static storage duration. A global variable
+ // constructed this way avoids the lifetime issues that can occur on program
+ // startup and shutdown. (See absl/base/const_init.h.)
+ //
+ // For Mutexes allocated on the heap and stack, instead use the default
+ // constructor, which can interact more fully with the thread sanitizer.
+ //
+ // Example usage:
+ // namespace foo {
+ // ABSL_CONST_INIT Mutex mu(absl::kConstInit);
+ // }
+ explicit constexpr Mutex(absl::ConstInitType);
+
~Mutex();
// Mutex::Lock()
@@ -584,7 +605,7 @@
// -----------------------------------------------------------------------------
//
// As noted above, `Mutex` contains a number of member functions which take a
-// `Condition` as a argument; clients can wait for conditions to become `true`
+// `Condition` as an argument; clients can wait for conditions to become `true`
// before attempting to acquire the mutex. These sections are known as
// "condition critical" sections. To use a `Condition`, you simply need to
// construct it, and use within an appropriate `Mutex` member function;
@@ -879,11 +900,15 @@
};
#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
+
#else
inline Mutex::Mutex() : mu_(0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
+inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
+
inline CondVar::CondVar() : cv_(0) {}
#endif
@@ -1025,4 +1050,5 @@
extern "C" {
void AbslInternalMutexYield();
} // extern "C"
+
#endif // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
index 1e019e0..ab18800 100644
--- a/absl/synchronization/mutex_benchmark.cc
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,16 +12,154 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <cstdint>
+#include <mutex> // NOLINT(build/c++11)
#include <vector>
-#include "benchmark/benchmark.h"
-#include "absl/base/internal/sysinfo.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/spinlock.h"
#include "absl/synchronization/blocking_counter.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/synchronization/mutex.h"
+#include "benchmark/benchmark.h"
namespace {
+void BM_Mutex(benchmark::State& state) {
+ static absl::Mutex* mu = new absl::Mutex;
+ for (auto _ : state) {
+ absl::MutexLock lock(mu);
+ }
+}
+BENCHMARK(BM_Mutex)->UseRealTime()->Threads(1)->ThreadPerCpu();
+
+static void DelayNs(int64_t ns, int* data) {
+ int64_t end = absl::base_internal::CycleClock::Now() +
+ ns * absl::base_internal::CycleClock::Frequency() / 1e9;
+ while (absl::base_internal::CycleClock::Now() < end) {
+ ++(*data);
+ benchmark::DoNotOptimize(*data);
+ }
+}
+
+template <typename MutexType>
+class RaiiLocker {
+ public:
+ explicit RaiiLocker(MutexType* mu) : mu_(mu) { mu_->Lock(); }
+ ~RaiiLocker() { mu_->Unlock(); }
+ private:
+ MutexType* mu_;
+};
+
+template <>
+class RaiiLocker<std::mutex> {
+ public:
+ explicit RaiiLocker(std::mutex* mu) : mu_(mu) { mu_->lock(); }
+ ~RaiiLocker() { mu_->unlock(); }
+ private:
+ std::mutex* mu_;
+};
+
+template <typename MutexType>
+void BM_Contended(benchmark::State& state) {
+ struct Shared {
+ MutexType mu;
+ int data = 0;
+ };
+ static auto* shared = new Shared;
+ int local = 0;
+ for (auto _ : state) {
+ // Here we model both local work outside of the critical section as well as
+ // some work inside of the critical section. The idea is to capture some
+ // more or less realisitic contention levels.
+ // If contention is too low, the benchmark won't measure anything useful.
+ // If contention is unrealistically high, the benchmark will favor
+ // bad mutex implementations that block and otherwise distract threads
+ // from the mutex and shared state for as much as possible.
+ // To achieve this amount of local work is multiplied by number of threads
+ // to keep ratio between local work and critical section approximately
+ // equal regardless of number of threads.
+ DelayNs(100 * state.threads, &local);
+ RaiiLocker<MutexType> locker(&shared->mu);
+ DelayNs(state.range(0), &shared->data);
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
+BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
+BENCHMARK_TEMPLATE(BM_Contended, std::mutex)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
// Measure the overhead of conditions on mutex release (when they must be
// evaluated). Mutex has (some) support for equivalence classes allowing
// Conditions with the same function/argument to potentially not be multiply
@@ -82,13 +220,4 @@
#endif
BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters);
-void BM_ContendedMutex(benchmark::State& state) {
- static absl::Mutex* mu = new absl::Mutex;
- for (auto _ : state) {
- absl::MutexLock lock(mu);
- }
-}
-BENCHMARK(BM_ContendedMutex)->Threads(1);
-BENCHMARK(BM_ContendedMutex)->ThreadPerCpu();
-
} // namespace
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index b2820e2..1021122 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -610,9 +610,9 @@
waiter2.reset(); // "join" waiter2
}
-INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
- ::testing::Range(0, 8),
- ::testing::PrintToStringParamName());
+INSTANTIATE_TEST_SUITE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
+ ::testing::Range(0, 8),
+ ::testing::PrintToStringParamName());
// --------------------------------------------------------
// Test for fix of bug in DequeueAllWakeable()
@@ -1032,9 +1032,9 @@
ScopedDisableBazelTestWarnings() {
#ifdef WIN32
char file[MAX_PATH];
- if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) {
+ if (GetEnvironmentVariableA(kVarName, file, sizeof(file)) < sizeof(file)) {
warnings_output_file_ = file;
- SetEnvironmentVariable(kVarName, nullptr);
+ SetEnvironmentVariableA(kVarName, nullptr);
}
#else
const char *file = getenv(kVarName);
@@ -1048,7 +1048,7 @@
~ScopedDisableBazelTestWarnings() {
if (!warnings_output_file_.empty()) {
#ifdef WIN32
- SetEnvironmentVariable(kVarName, warnings_output_file_.c_str());
+ SetEnvironmentVariableA(kVarName, warnings_output_file_.c_str());
#else
setenv(kVarName, warnings_output_file_.c_str(), 0);
#endif
@@ -1367,8 +1367,8 @@
}
// Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`.
-INSTANTIATE_TEST_CASE_P(All, TimeoutTest,
- testing::ValuesIn(MakeTimeoutTestParamValues()));
+INSTANTIATE_TEST_SUITE_P(All, TimeoutTest,
+ testing::ValuesIn(MakeTimeoutTestParamValues()));
TEST_P(TimeoutTest, Await) {
const TimeoutTestParam params = GetParam();
@@ -1548,9 +1548,9 @@
class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};
// Instantiate the above with AllThreadCountOptions().
-INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest,
- ::testing::ValuesIn(AllThreadCountValues()),
- ::testing::PrintToStringParamName());
+INSTANTIATE_TEST_SUITE_P(ThreadCounts, MutexVariableThreadCountTest,
+ ::testing::ValuesIn(AllThreadCountValues()),
+ ::testing::PrintToStringParamName());
// Reduces iterations by some factor for slow platforms
// (determined empirically).
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index ed8cc90..53ace00 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,6 +22,7 @@
#include "absl/time/time.h"
namespace absl {
+
void Notification::Notify() {
MutexLock l(&this->mutex_);
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 107932f..82d111a 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -52,6 +52,7 @@
#include <atomic>
+#include "absl/base/macros.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
@@ -109,4 +110,5 @@
};
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
index d8708d5..059d4cd 100644
--- a/absl/synchronization/notification_test.cc
+++ b/absl/synchronization/notification_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -72,12 +72,16 @@
EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
const absl::Duration delay = absl::Milliseconds(50);
+ const absl::Time start = absl::Now();
+ EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
+ const absl::Duration elapsed = absl::Now() - start;
+
// Allow for a slight early return, to account for quality of implementation
// issues on various platforms.
const absl::Duration slop = absl::Microseconds(200);
- absl::Time start = absl::Now();
- EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
- EXPECT_LE(start + delay, absl::Now() + slop);
+ EXPECT_LE(delay - slop, elapsed)
+ << "WaitForNotificationWithTimeout returned " << delay - elapsed
+ << " early (with " << slop << " slop), start time was " << start;
ThreadSafeCounter ready_counter;
ThreadSafeCounter done_counter;
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index c7c16d4..a94be65 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
@@ -27,6 +27,7 @@
cc_library(
name = "time",
srcs = [
+ "civil_time.cc",
"clock.cc",
"duration.cc",
"format.cc",
@@ -35,6 +36,7 @@
"time.cc",
],
hdrs = [
+ "civil_time.h",
"clock.h",
"time.h",
],
@@ -72,10 +74,10 @@
cc_test(
name = "time_test",
srcs = [
+ "civil_time_test.cc",
"clock_test.cc",
"duration_test.cc",
"format_test.cc",
- "time_norm_test.cc",
"time_test.cc",
"time_zone_test.cc",
],
@@ -94,6 +96,7 @@
cc_test(
name = "time_benchmark",
srcs = [
+ "civil_time_benchmark.cc",
"clock_benchmark.cc",
"duration_benchmark.cc",
"format_benchmark.cc",
@@ -107,6 +110,8 @@
":test_util",
":time",
"//absl/base",
+ "//absl/base:core_headers",
+ "//absl/hash",
"@com_github_google_benchmark//:benchmark_main",
],
)
diff --git a/absl/time/BUILD.gn b/absl/time/BUILD.gn
index 5758e9d..e3f9e1a 100644
--- a/absl/time/BUILD.gn
+++ b/absl/time/BUILD.gn
@@ -22,6 +22,7 @@
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
+ "civil_time.cc",
"clock.cc",
"duration.cc",
"format.cc",
@@ -30,6 +31,7 @@
"time.cc",
]
public = [
+ "civil_time.h",
"clock.h",
"time.h",
]
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index 0627236..5909832 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,83 +14,114 @@
# limitations under the License.
#
-list(APPEND TIME_PUBLIC_HEADERS
- "clock.h"
- "time.h"
-)
-
-
-list(APPEND TIME_INTERNAL_HEADERS
- "internal/test_util.h"
- "internal/cctz/include/cctz/civil_time.h"
- "internal/cctz/include/cctz/civil_time_detail.h"
- "internal/cctz/include/cctz/time_zone.h"
- "internal/cctz/include/cctz/zone_info_source.h"
-)
-
-list(APPEND TIME_SRC
- "time.cc"
+absl_cc_library(
+ NAME
+ time
+ HDRS
+ "civil_time.h"
+ "clock.h"
+ "time.h"
+ SRCS
+ "civil_time.cc"
"clock.cc"
"duration.cc"
"format.cc"
+ "internal/get_current_time_chrono.inc"
+ "internal/get_current_time_posix.inc"
+ "time.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::int128
+ absl::strings
+ absl::civil_time
+ absl::time_zone
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ civil_time
+ HDRS
+ "internal/cctz/include/cctz/civil_time.h"
+ "internal/cctz/include/cctz/civil_time_detail.h"
+ SRCS
"internal/cctz/src/civil_time_detail.cc"
- "internal/cctz/src/time_zone_fixed.cc"
- "internal/cctz/src/time_zone_fixed.h"
- "internal/cctz/src/time_zone_format.cc"
- "internal/cctz/src/time_zone_if.cc"
- "internal/cctz/src/time_zone_if.h"
- "internal/cctz/src/time_zone_impl.cc"
- "internal/cctz/src/time_zone_impl.h"
- "internal/cctz/src/time_zone_info.cc"
- "internal/cctz/src/time_zone_info.h"
- "internal/cctz/src/time_zone_libc.cc"
- "internal/cctz/src/time_zone_libc.h"
- "internal/cctz/src/time_zone_lookup.cc"
- "internal/cctz/src/time_zone_posix.cc"
- "internal/cctz/src/time_zone_posix.h"
- "internal/cctz/src/tzfile.h"
- "internal/cctz/src/zone_info_source.cc"
- ${TIME_PUBLIC_HEADERS}
- ${TIME_INTERNAL_HEADERS}
-)
-set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings)
-
-absl_library(
- TARGET
- absl_time
- SOURCES
- ${TIME_SRC}
- PUBLIC_LIBRARIES
- ${TIME_PUBLIC_LIBRARIES}
- EXPORT_NAME
- time
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
)
+if(APPLE)
+ find_library(CoreFoundation CoreFoundation)
+endif()
-
-#
-## TESTS
-#
-
-# test time_test
-list(APPEND TIME_TEST_SRC
- "time_test.cc"
- "clock_test.cc"
- "duration_test.cc"
- "format_test.cc"
- "time_norm_test.cc"
- "time_test.cc"
- "time_zone_test.cc"
- "internal/test_util.cc"
+absl_cc_library(
+ NAME
+ time_zone
+ HDRS
+ "internal/cctz/include/cctz/time_zone.h"
+ "internal/cctz/include/cctz/zone_info_source.h"
+ SRCS
+ "internal/cctz/src/time_zone_fixed.cc"
+ "internal/cctz/src/time_zone_fixed.h"
+ "internal/cctz/src/time_zone_format.cc"
+ "internal/cctz/src/time_zone_if.cc"
+ "internal/cctz/src/time_zone_if.h"
+ "internal/cctz/src/time_zone_impl.cc"
+ "internal/cctz/src/time_zone_impl.h"
+ "internal/cctz/src/time_zone_info.cc"
+ "internal/cctz/src/time_zone_info.h"
+ "internal/cctz/src/time_zone_libc.cc"
+ "internal/cctz/src/time_zone_libc.h"
+ "internal/cctz/src/time_zone_lookup.cc"
+ "internal/cctz/src/time_zone_posix.cc"
+ "internal/cctz/src/time_zone_posix.h"
+ "internal/cctz/src/tzfile.h"
+ "internal/cctz/src/zone_info_source.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ $<$<PLATFORM_ID:Darwin>:${CoreFoundation}>
)
-set(TIME_TEST_PUBLIC_LIBRARIES absl::time)
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ test_util
+ HDRS
+ "internal/test_util.h"
+ SRCS
+ "internal/test_util.cc"
+ "internal/zoneinfo.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::time
+ absl::base
+ absl::time_zone
+ gmock
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
time_test
- SOURCES
- ${TIME_TEST_SRC}
- PUBLIC_LIBRARIES
- ${TIME_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "civil_time_test.cc"
+ "clock_test.cc"
+ "duration_test.cc"
+ "format_test.cc"
+ "time_test.cc"
+ "time_zone_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::test_util
+ absl::time
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::time_zone
+ gmock_main
)
-
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc
new file mode 100644
index 0000000..7527fc1
--- /dev/null
+++ b/absl/time/civil_time.cc
@@ -0,0 +1,83 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/time/civil_time.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "absl/strings/str_cat.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+namespace {
+
+// Since a civil time has a larger year range than absl::Time (64-bit years vs
+// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
+// around the year 2400, which will produce an equivalent year in a range that
+// absl::Time can handle.
+inline civil_year_t NormalizeYear(civil_year_t year) {
+ return 2400 + year % 400;
+}
+
+// Formats the given CivilSecond according to the given format.
+std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
+ const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
+ cs.hour(), cs.minute(), cs.second());
+ const TimeZone utc = UTCTimeZone();
+ // TODO(absl-team): Avoid conversion of fmt std::string.
+ return StrCat(cs.year(),
+ FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
+}
+
+} // namespace
+
+std::string FormatCivilTime(CivilSecond c) {
+ return FormatYearAnd("-%m-%dT%H:%M:%S", c);
+}
+std::string FormatCivilTime(CivilMinute c) {
+ return FormatYearAnd("-%m-%dT%H:%M", c);
+}
+std::string FormatCivilTime(CivilHour c) {
+ return FormatYearAnd("-%m-%dT%H", c);
+}
+std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
+std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
+std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
+
+namespace time_internal {
+
+std::ostream& operator<<(std::ostream& os, CivilYear y) {
+ return os << FormatCivilTime(y);
+}
+std::ostream& operator<<(std::ostream& os, CivilMonth m) {
+ return os << FormatCivilTime(m);
+}
+std::ostream& operator<<(std::ostream& os, CivilDay d) {
+ return os << FormatCivilTime(d);
+}
+std::ostream& operator<<(std::ostream& os, CivilHour h) {
+ return os << FormatCivilTime(h);
+}
+std::ostream& operator<<(std::ostream& os, CivilMinute m) {
+ return os << FormatCivilTime(m);
+}
+std::ostream& operator<<(std::ostream& os, CivilSecond s) {
+ return os << FormatCivilTime(s);
+}
+
+} // namespace time_internal
+
+} // namespace absl
diff --git a/absl/time/civil_time.h b/absl/time/civil_time.h
new file mode 100644
index 0000000..2dfcbd2
--- /dev/null
+++ b/absl/time/civil_time.h
@@ -0,0 +1,485 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: civil_time.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines abstractions for computing with "civil time".
+// The term "civil time" refers to the legally recognized human-scale time
+// that is represented by the six fields `YYYY-MM-DD hh:mm:ss`. A "date"
+// is perhaps the most common example of a civil time (represented here as
+// an `absl::CivilDay`).
+//
+// Modern-day civil time follows the Gregorian Calendar and is a
+// time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for
+// example, is not tied to a time zone. Put another way, a civil time does not
+// map to a unique point in time; a civil time must be mapped to an absolute
+// time *through* a time zone.
+//
+// Because a civil time is what most people think of as "time," it is common to
+// map absolute times to civil times to present to users.
+//
+// Time zones define the relationship between absolute and civil times. Given an
+// absolute or civil time and a time zone, you can compute the other time:
+//
+// Civil Time = F(Absolute Time, Time Zone)
+// Absolute Time = G(Civil Time, Time Zone)
+//
+// The Abseil time library allows you to construct such civil times from
+// absolute times; consult time.h for such functionality.
+//
+// This library provides six classes for constructing civil-time objects, and
+// provides several helper functions for rounding, iterating, and performing
+// arithmetic on civil-time objects, while avoiding complications like
+// daylight-saving time (DST):
+//
+// * `absl::CivilSecond`
+// * `absl::CivilMinute`
+// * `absl::CivilHour`
+// * `absl::CivilDay`
+// * `absl::CivilMonth`
+// * `absl::CivilYear`
+//
+// Example:
+//
+// // Construct a civil-time object for a specific day
+// const absl::CivilDay cd(1969, 07, 20);
+//
+// // Construct a civil-time object for a specific second
+// const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1);
+//
+// Note: In C++14 and later, this library is usable in a constexpr context.
+//
+// Example:
+//
+// // Valid in C++14
+// constexpr absl::CivilDay cd(1969, 07, 20);
+
+#ifndef ABSL_TIME_CIVIL_TIME_H_
+#define ABSL_TIME_CIVIL_TIME_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+namespace absl {
+
+namespace time_internal {
+struct second_tag : cctz::detail::second_tag {};
+struct minute_tag : second_tag, cctz::detail::minute_tag {};
+struct hour_tag : minute_tag, cctz::detail::hour_tag {};
+struct day_tag : hour_tag, cctz::detail::day_tag {};
+struct month_tag : day_tag, cctz::detail::month_tag {};
+struct year_tag : month_tag, cctz::detail::year_tag {};
+} // namespace time_internal
+
+// -----------------------------------------------------------------------------
+// CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear
+// -----------------------------------------------------------------------------
+//
+// Each of these civil-time types is a simple value type with the same
+// interface for construction and the same six accessors for each of the civil
+// time fields (year, month, day, hour, minute, and second, aka YMDHMS). These
+// classes differ only in their alignment, which is indicated by the type name
+// and specifies the field on which arithmetic operates.
+//
+// CONSTRUCTION
+//
+// Each of the civil-time types can be constructed in two ways: by directly
+// passing to the constructor up to six integers representing the YMDHMS fields,
+// or by copying the YMDHMS fields from a differently aligned civil-time type.
+// Omitted fields are assigned their minimum valid value. Hours, minutes, and
+// seconds will be set to 0, month and day will be set to 1. Since there is no
+// minimum year, the default is 1970.
+//
+// Examples:
+//
+// absl::CivilDay default_value; // 1970-01-01 00:00:00
+//
+// absl::CivilDay a(2015, 2, 3); // 2015-02-03 00:00:00
+// absl::CivilDay b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00
+// absl::CivilDay c(2015); // 2015-01-01 00:00:00
+//
+// absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06
+// absl::CivilMinute mm(ss); // 2015-02-03 04:05:00
+// absl::CivilHour hh(mm); // 2015-02-03 04:00:00
+// absl::CivilDay d(hh); // 2015-02-03 00:00:00
+// absl::CivilMonth m(d); // 2015-02-01 00:00:00
+// absl::CivilYear y(m); // 2015-01-01 00:00:00
+//
+// m = absl::CivilMonth(y); // 2015-01-01 00:00:00
+// d = absl::CivilDay(m); // 2015-01-01 00:00:00
+// hh = absl::CivilHour(d); // 2015-01-01 00:00:00
+// mm = absl::CivilMinute(hh); // 2015-01-01 00:00:00
+// ss = absl::CivilSecond(mm); // 2015-01-01 00:00:00
+//
+// Each civil-time class is aligned to the civil-time field indicated in the
+// class's name after normalization. Alignment is performed by setting all the
+// inferior fields to their minimum valid value (as described above). The
+// following are examples of how each of the six types would align the fields
+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
+// string format used here is not important; it's just a shorthand way of
+// showing the six YMDHMS fields.)
+//
+// absl::CivilSecond : 2015-11-22 12:34:56
+// absl::CivilMinute : 2015-11-22 12:34:00
+// absl::CivilHour : 2015-11-22 12:00:00
+// absl::CivilDay : 2015-11-22 00:00:00
+// absl::CivilMonth : 2015-11-01 00:00:00
+// absl::CivilYear : 2015-01-01 00:00:00
+//
+// Each civil-time type performs arithmetic on the field to which it is
+// aligned. This means that adding 1 to an absl::CivilDay increments the day
+// field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth
+// operates on the month field (normalizing as necessary). All arithmetic
+// produces a valid civil time. Difference requires two similarly aligned
+// civil-time objects and returns the scalar answer in units of the objects'
+// alignment. For example, the difference between two absl::CivilHour objects
+// will give an answer in units of civil hours.
+//
+// ALIGNMENT CONVERSION
+//
+// The alignment of a civil-time object cannot change, but the object may be
+// used to construct a new object with a different alignment. This is referred
+// to as "realigning". When realigning to a type with the same or more
+// precision (e.g., absl::CivilDay -> absl::CivilSecond), the conversion may be
+// performed implicitly since no information is lost. However, if information
+// could be discarded (e.g., CivilSecond -> CivilDay), the conversion must
+// be explicit at the call site.
+//
+// Examples:
+//
+// void UseDay(absl::CivilDay day);
+//
+// absl::CivilSecond cs;
+// UseDay(cs); // Won't compile because data may be discarded
+// UseDay(absl::CivilDay(cs)); // OK: explicit conversion
+//
+// absl::CivilDay cd;
+// UseDay(cd); // OK: no conversion needed
+//
+// absl::CivilMonth cm;
+// UseDay(cm); // OK: implicit conversion to absl::CivilDay
+//
+// NORMALIZATION
+//
+// Normalization takes invalid values and adjusts them to produce valid values.
+// Within the civil-time library, integer arguments passed to the Civil*
+// constructors may be out-of-range, in which case they are normalized by
+// carrying overflow into a field of courser granularity to produce valid
+// civil-time objects. This normalization enables natural arithmetic on
+// constructor arguments without worrying about the field's range.
+//
+// Examples:
+//
+// // Out-of-range; normalized to 2016-11-01
+// absl::CivilDay d(2016, 10, 32);
+// // Out-of-range, negative: normalized to 2016-10-30T23
+// absl::CivilHour h1(2016, 10, 31, -1);
+// // Normalization is cumulative: normalized to 2016-10-30T23
+// absl::CivilHour h2(2016, 10, 32, -25);
+//
+// Note: If normalization is undesired, you can signal an error by comparing
+// the constructor arguments to the normalized values returned by the YMDHMS
+// properties.
+//
+// COMPARISON
+//
+// Comparison between civil-time objects considers all six YMDHMS fields,
+// regardless of the type's alignment. Comparison between differently aligned
+// civil-time types is allowed.
+//
+// Examples:
+//
+// absl::CivilDay feb_3(2015, 2, 3); // 2015-02-03 00:00:00
+// absl::CivilDay mar_4(2015, 3, 4); // 2015-03-04 00:00:00
+// // feb_3 < mar_4
+// // absl::CivilYear(feb_3) == absl::CivilYear(mar_4)
+//
+// absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00
+// // feb_3 < feb_3_noon
+// // feb_3 == absl::CivilDay(feb_3_noon)
+//
+// // Iterates all the days of February 2015.
+// for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) {
+// // ...
+// }
+//
+// ARITHMETIC
+//
+// Civil-time types support natural arithmetic operators such as addition,
+// subtraction, and difference. Arithmetic operates on the civil-time field
+// indicated in the type's name. Difference operators require arguments with
+// the same alignment and return the answer in units of the alignment.
+//
+// Example:
+//
+// absl::CivilDay a(2015, 2, 3);
+// ++a; // 2015-02-04 00:00:00
+// --a; // 2015-02-03 00:00:00
+// absl::CivilDay b = a + 1; // 2015-02-04 00:00:00
+// absl::CivilDay c = 1 + b; // 2015-02-05 00:00:00
+// int n = c - a; // n = 2 (civil days)
+// int m = c - absl::CivilMonth(c); // Won't compile: different types.
+//
+// ACCESSORS
+//
+// Each civil-time type has accessors for all six of the civil-time fields:
+// year, month, day, hour, minute, and second.
+//
+// civil_year_t year()
+// int month()
+// int day()
+// int hour()
+// int minute()
+// int second()
+//
+// Recall that fields inferior to the type's aligment will be set to their
+// minimum valid value.
+//
+// Example:
+//
+// absl::CivilDay d(2015, 6, 28);
+// // d.year() == 2015
+// // d.month() == 6
+// // d.day() == 28
+// // d.hour() == 0
+// // d.minute() == 0
+// // d.second() == 0
+//
+// CASE STUDY: Adding a month to January 31.
+//
+// One of the classic questions that arises when considering a civil time
+// library (or a date library or a date/time library) is this:
+// "What is the result of adding a month to January 31?"
+// This is an interesting question because it is unclear what is meant by a
+// "month", and several different answers are possible, depending on context:
+//
+// 1. March 3 (or 2 if a leap year), if "add a month" means to add a month to
+// the current month, and adjust the date to overflow the extra days into
+// March. In this case the result of "February 31" would be normalized as
+// within the civil-time library.
+// 2. February 28 (or 29 if a leap year), if "add a month" means to add a
+// month, and adjust the date while holding the resulting month constant.
+// In this case, the result of "February 31" would be truncated to the last
+// day in February.
+// 3. An error. The caller may get some error, an exception, an invalid date
+// object, or perhaps return `false`. This may make sense because there is
+// no single unambiguously correct answer to the question.
+//
+// Practically speaking, any answer that is not what the programmer intended
+// is the wrong answer.
+//
+// The Abseil time library avoids this problem by making it impossible to
+// ask ambiguous questions. All civil-time objects are aligned to a particular
+// civil-field boundary (such as aligned to a year, month, day, hour, minute,
+// or second), and arithmetic operates on the field to which the object is
+// aligned. This means that in order to "add a month" the object must first be
+// aligned to a month boundary, which is equivalent to the first day of that
+// month.
+//
+// Of course, there are ways to compute an answer the question at hand using
+// this Abseil time library, but they require the programmer to be explicit
+// about the answer they expect. To illustrate, let's see how to compute all
+// three of the above possible answers to the question of "Jan 31 plus 1
+// month":
+//
+// Example:
+//
+// const absl::CivilDay d(2015, 1, 31);
+//
+// // Answer 1:
+// // Add 1 to the month field in the constructor, and rely on normalization.
+// const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day());
+// // normalized == 2015-03-03 (aka Feb 31)
+//
+// // Answer 2:
+// // Add 1 to month field, capping to the end of next month.
+// const auto next_month = absl::CivilMonth(d) + 1;
+// const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1;
+// const auto capped = std::min(normalized, last_day_of_next_month);
+// // capped == 2015-02-28
+//
+// // Answer 3:
+// // Signal an error if the normalized answer is not in next month.
+// if (absl::CivilMonth(normalized) != next_month) {
+// // error, month overflow
+// }
+//
+using CivilSecond =
+ time_internal::cctz::detail::civil_time<time_internal::second_tag>;
+using CivilMinute =
+ time_internal::cctz::detail::civil_time<time_internal::minute_tag>;
+using CivilHour =
+ time_internal::cctz::detail::civil_time<time_internal::hour_tag>;
+using CivilDay =
+ time_internal::cctz::detail::civil_time<time_internal::day_tag>;
+using CivilMonth =
+ time_internal::cctz::detail::civil_time<time_internal::month_tag>;
+using CivilYear =
+ time_internal::cctz::detail::civil_time<time_internal::year_tag>;
+
+// civil_year_t
+//
+// Type alias of a civil-time year value. This type is guaranteed to (at least)
+// support any year value supported by `time_t`.
+//
+// Example:
+//
+// absl::CivilSecond cs = ...;
+// absl::civil_year_t y = cs.year();
+// cs = absl::CivilSecond(y, 1, 1, 0, 0, 0); // CivilSecond(CivilYear(cs))
+//
+using civil_year_t = time_internal::cctz::year_t;
+
+// civil_diff_t
+//
+// Type alias of the difference between two civil-time values.
+// This type is used to indicate arguments that are not
+// normalized (such as parameters to the civil-time constructors), the results
+// of civil-time subtraction, or the operand to civil-time addition.
+//
+// Example:
+//
+// absl::civil_diff_t n_sec = cs1 - cs2; // cs1 == cs2 + n_sec;
+//
+using civil_diff_t = time_internal::cctz::diff_t;
+
+// Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday,
+// Weekday::friday, Weekday::saturday, Weekday::sunday
+//
+// The Weekday enum class represents the civil-time concept of a "weekday" with
+// members for all days of the week.
+//
+// absl::Weekday wd = absl::Weekday::thursday;
+//
+using Weekday = time_internal::cctz::weekday;
+
+// GetWeekday()
+//
+// Returns the absl::Weekday for the given absl::CivilDay.
+//
+// Example:
+//
+// absl::CivilDay a(2015, 8, 13);
+// absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday
+//
+inline Weekday GetWeekday(CivilDay cd) {
+ return time_internal::cctz::get_weekday(cd);
+}
+
+// NextWeekday()
+// PrevWeekday()
+//
+// Returns the absl::CivilDay that strictly follows or precedes a given
+// absl::CivilDay, and that falls on the given absl::Weekday.
+//
+// Example, given the following month:
+//
+// August 2015
+// Su Mo Tu We Th Fr Sa
+// 1
+// 2 3 4 5 6 7 8
+// 9 10 11 12 13 14 15
+// 16 17 18 19 20 21 22
+// 23 24 25 26 27 28 29
+// 30 31
+//
+// absl::CivilDay a(2015, 8, 13);
+// // absl::GetWeekday(a) == absl::Weekday::thursday
+// absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday);
+// // b = 2015-08-20
+// absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday);
+// // c = 2015-08-06
+//
+// absl::CivilDay d = ...
+// // Gets the following Thursday if d is not already Thursday
+// absl::CivilDay thurs1 = absl::PrevWeekday(d, absl::Weekday::thursday) + 7;
+// // Gets the previous Thursday if d is not already Thursday
+// absl::CivilDay thurs2 = absl::NextWeekday(d, absl::Weekday::thursday) - 7;
+//
+inline CivilDay NextWeekday(CivilDay cd, Weekday wd) {
+ return CivilDay(time_internal::cctz::next_weekday(cd, wd));
+}
+inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) {
+ return CivilDay(time_internal::cctz::prev_weekday(cd, wd));
+}
+
+// GetYearDay()
+//
+// Returns the day-of-year for the given absl::CivilDay.
+//
+// Example:
+//
+// absl::CivilDay a(2015, 1, 1);
+// int yd_jan_1 = absl::GetYearDay(a); // yd_jan_1 = 1
+// absl::CivilDay b(2015, 12, 31);
+// int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365
+//
+inline int GetYearDay(CivilDay cd) {
+ return time_internal::cctz::get_yearday(cd);
+}
+
+// FormatCivilTime()
+//
+// Formats the given civil-time value into a string value of the following
+// format:
+//
+// Type | Format
+// ---------------------------------
+// CivilSecond | YYYY-MM-DDTHH:MM:SS
+// CivilMinute | YYYY-MM-DDTHH:MM
+// CivilHour | YYYY-MM-DDTHH
+// CivilDay | YYYY-MM-DD
+// CivilMonth | YYYY-MM
+// CivilYear | YYYY
+//
+// Example:
+//
+// absl::CivilDay d = absl::CivilDay(1969, 7, 20);
+// std::string day_string = absl::FormatCivilTime(d); // "1969-07-20"
+//
+std::string FormatCivilTime(CivilSecond c);
+std::string FormatCivilTime(CivilMinute c);
+std::string FormatCivilTime(CivilHour c);
+std::string FormatCivilTime(CivilDay c);
+std::string FormatCivilTime(CivilMonth c);
+std::string FormatCivilTime(CivilYear c);
+
+namespace time_internal { // For functions found via ADL on civil-time tags.
+
+// Streaming Operators
+//
+// Each civil-time type may be sent to an output stream using operator<<().
+// The result matches the string produced by `FormatCivilTime()`.
+//
+// Example:
+//
+// absl::CivilDay d = absl::CivilDay("1969-07-20");
+// std::cout << "Date is: " << d << "\n";
+//
+std::ostream& operator<<(std::ostream& os, CivilYear y);
+std::ostream& operator<<(std::ostream& os, CivilMonth m);
+std::ostream& operator<<(std::ostream& os, CivilDay d);
+std::ostream& operator<<(std::ostream& os, CivilHour h);
+std::ostream& operator<<(std::ostream& os, CivilMinute m);
+std::ostream& operator<<(std::ostream& os, CivilSecond s);
+
+} // namespace time_internal
+
+} // namespace absl
+
+#endif // ABSL_TIME_CIVIL_TIME_H_
diff --git a/absl/time/civil_time_benchmark.cc b/absl/time/civil_time_benchmark.cc
new file mode 100644
index 0000000..4086983
--- /dev/null
+++ b/absl/time/civil_time_benchmark.cc
@@ -0,0 +1,107 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/time/civil_time.h"
+
+#include <numeric>
+#include <vector>
+
+#include "absl/hash/hash.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// Run on (12 X 3492 MHz CPUs); 2018-11-05T13:44:29.814239103-08:00
+// CPU: Intel Haswell with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:15MB
+// Benchmark Time(ns) CPU(ns) Iterations
+// ----------------------------------------------------------------
+// BM_Difference_Days 14.5 14.5 48531105
+// BM_Step_Days 12.6 12.6 54876006
+// BM_Format 587 587 1000000
+// BM_Parse 692 692 1000000
+// BM_RoundTripFormatParse 1309 1309 532075
+// BM_CivilYearAbslHash 0.710 0.710 976400000
+// BM_CivilMonthAbslHash 1.13 1.13 619500000
+// BM_CivilDayAbslHash 1.70 1.70 426000000
+// BM_CivilHourAbslHash 2.45 2.45 287600000
+// BM_CivilMinuteAbslHash 3.21 3.21 226200000
+// BM_CivilSecondAbslHash 4.10 4.10 171800000
+
+void BM_Difference_Days(benchmark::State& state) {
+ const absl::CivilDay c(2014, 8, 22);
+ const absl::CivilDay epoch(1970, 1, 1);
+ while (state.KeepRunning()) {
+ const absl::civil_diff_t n = c - epoch;
+ benchmark::DoNotOptimize(n);
+ }
+}
+BENCHMARK(BM_Difference_Days);
+
+void BM_Step_Days(benchmark::State& state) {
+ const absl::CivilDay kStart(2014, 8, 22);
+ absl::CivilDay c = kStart;
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(++c);
+ }
+}
+BENCHMARK(BM_Step_Days);
+
+void BM_Format(benchmark::State& state) {
+ const absl::CivilSecond c(2014, 1, 2, 3, 4, 5);
+ while (state.KeepRunning()) {
+ const std::string s = absl::FormatCivilTime(c);
+ benchmark::DoNotOptimize(s);
+ }
+}
+BENCHMARK(BM_Format);
+
+template <typename T>
+void BM_CivilTimeAbslHash(benchmark::State& state) {
+ const int kSize = 100000;
+ std::vector<T> civil_times(kSize);
+ std::iota(civil_times.begin(), civil_times.end(), T(2018));
+
+ absl::Hash<T> absl_hasher;
+ while (state.KeepRunningBatch(kSize)) {
+ for (const T civil_time : civil_times) {
+ benchmark::DoNotOptimize(absl_hasher(civil_time));
+ }
+ }
+}
+void BM_CivilYearAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilYear>(state);
+}
+void BM_CivilMonthAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilMonth>(state);
+}
+void BM_CivilDayAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilDay>(state);
+}
+void BM_CivilHourAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilHour>(state);
+}
+void BM_CivilMinuteAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilMinute>(state);
+}
+void BM_CivilSecondAbslHash(benchmark::State& state) {
+ BM_CivilTimeAbslHash<absl::CivilSecond>(state);
+}
+BENCHMARK(BM_CivilYearAbslHash);
+BENCHMARK(BM_CivilMonthAbslHash);
+BENCHMARK(BM_CivilDayAbslHash);
+BENCHMARK(BM_CivilHourAbslHash);
+BENCHMARK(BM_CivilMinuteAbslHash);
+BENCHMARK(BM_CivilSecondAbslHash);
+
+} // namespace
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
new file mode 100644
index 0000000..b8d5713
--- /dev/null
+++ b/absl/time/civil_time_test.cc
@@ -0,0 +1,1073 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/time/civil_time.h"
+
+#include <limits>
+#include <sstream>
+#include <type_traits>
+
+#include "absl/base/macros.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(CivilTime, DefaultConstruction) {
+ absl::CivilSecond ss;
+ EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss));
+
+ absl::CivilMinute mm;
+ EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm));
+
+ absl::CivilHour hh;
+ EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh));
+
+ absl::CivilDay d;
+ EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d));
+
+ absl::CivilMonth m;
+ EXPECT_EQ("1970-01", absl::FormatCivilTime(m));
+
+ absl::CivilYear y;
+ EXPECT_EQ("1970", absl::FormatCivilTime(y));
+}
+
+TEST(CivilTime, StructMember) {
+ struct S {
+ absl::CivilDay day;
+ };
+ S s = {};
+ EXPECT_EQ(absl::CivilDay{}, s.day);
+}
+
+TEST(CivilTime, FieldsConstruction) {
+ EXPECT_EQ("2015-01-02T03:04:05",
+ absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015-01-02T03:04:00",
+ absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015-01-02T03:00:00",
+ absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3)));
+ EXPECT_EQ("2015-01-02T00:00:00",
+ absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2)));
+ EXPECT_EQ("2015-01-01T00:00:00",
+ absl::FormatCivilTime(absl::CivilSecond(2015, 1)));
+ EXPECT_EQ("2015-01-01T00:00:00",
+ absl::FormatCivilTime(absl::CivilSecond(2015)));
+
+ EXPECT_EQ("2015-01-02T03:04",
+ absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015-01-02T03:04",
+ absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015-01-02T03:00",
+ absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3)));
+ EXPECT_EQ("2015-01-02T00:00",
+ absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2)));
+ EXPECT_EQ("2015-01-01T00:00",
+ absl::FormatCivilTime(absl::CivilMinute(2015, 1)));
+ EXPECT_EQ("2015-01-01T00:00",
+ absl::FormatCivilTime(absl::CivilMinute(2015)));
+
+ EXPECT_EQ("2015-01-02T03",
+ absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015-01-02T03",
+ absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015-01-02T03",
+ absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3)));
+ EXPECT_EQ("2015-01-02T00",
+ absl::FormatCivilTime(absl::CivilHour(2015, 1, 2)));
+ EXPECT_EQ("2015-01-01T00",
+ absl::FormatCivilTime(absl::CivilHour(2015, 1)));
+ EXPECT_EQ("2015-01-01T00",
+ absl::FormatCivilTime(absl::CivilHour(2015)));
+
+ EXPECT_EQ("2015-01-02",
+ absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015-01-02",
+ absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015-01-02",
+ absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3)));
+ EXPECT_EQ("2015-01-02",
+ absl::FormatCivilTime(absl::CivilDay(2015, 1, 2)));
+ EXPECT_EQ("2015-01-01",
+ absl::FormatCivilTime(absl::CivilDay(2015, 1)));
+ EXPECT_EQ("2015-01-01",
+ absl::FormatCivilTime(absl::CivilDay(2015)));
+
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3)));
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2)));
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015, 1)));
+ EXPECT_EQ("2015-01",
+ absl::FormatCivilTime(absl::CivilMonth(2015)));
+
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4, 5)));
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4)));
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3)));
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015, 1, 2)));
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015, 1)));
+ EXPECT_EQ("2015",
+ absl::FormatCivilTime(absl::CivilYear(2015)));
+}
+
+TEST(CivilTime, FieldsConstructionLimits) {
+ const int kIntMax = std::numeric_limits<int>::max();
+ EXPECT_EQ("2038-01-19T03:14:07",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, 0, 0, kIntMax)));
+ EXPECT_EQ("6121-02-11T05:21:07",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, 0, kIntMax, kIntMax)));
+ EXPECT_EQ("251104-11-20T12:21:07",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, kIntMax, kIntMax, kIntMax)));
+ EXPECT_EQ("6130715-05-30T12:21:07",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, kIntMax, kIntMax, kIntMax, kIntMax)));
+ EXPECT_EQ("185087685-11-26T12:21:07",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax)));
+
+ const int kIntMin = std::numeric_limits<int>::min();
+ EXPECT_EQ("1901-12-13T20:45:52",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, 0, 0, kIntMin)));
+ EXPECT_EQ("-2182-11-20T18:37:52",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, 0, kIntMin, kIntMin)));
+ EXPECT_EQ("-247165-02-11T10:37:52",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, 1, kIntMin, kIntMin, kIntMin)));
+ EXPECT_EQ("-6126776-08-01T10:37:52",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, 1, kIntMin, kIntMin, kIntMin, kIntMin)));
+ EXPECT_EQ("-185083747-10-31T10:37:52",
+ absl::FormatCivilTime(absl::CivilSecond(
+ 1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin)));
+}
+
+TEST(CivilTime, RangeLimits) {
+ const absl::civil_year_t kYearMax =
+ std::numeric_limits<absl::civil_year_t>::max();
+ EXPECT_EQ(absl::CivilYear(kYearMax),
+ absl::CivilYear::max());
+ EXPECT_EQ(absl::CivilMonth(kYearMax, 12),
+ absl::CivilMonth::max());
+ EXPECT_EQ(absl::CivilDay(kYearMax, 12, 31),
+ absl::CivilDay::max());
+ EXPECT_EQ(absl::CivilHour(kYearMax, 12, 31, 23),
+ absl::CivilHour::max());
+ EXPECT_EQ(absl::CivilMinute(kYearMax, 12, 31, 23, 59),
+ absl::CivilMinute::max());
+ EXPECT_EQ(absl::CivilSecond(kYearMax, 12, 31, 23, 59, 59),
+ absl::CivilSecond::max());
+
+ const absl::civil_year_t kYearMin =
+ std::numeric_limits<absl::civil_year_t>::min();
+ EXPECT_EQ(absl::CivilYear(kYearMin),
+ absl::CivilYear::min());
+ EXPECT_EQ(absl::CivilMonth(kYearMin, 1),
+ absl::CivilMonth::min());
+ EXPECT_EQ(absl::CivilDay(kYearMin, 1, 1),
+ absl::CivilDay::min());
+ EXPECT_EQ(absl::CivilHour(kYearMin, 1, 1, 0),
+ absl::CivilHour::min());
+ EXPECT_EQ(absl::CivilMinute(kYearMin, 1, 1, 0, 0),
+ absl::CivilMinute::min());
+ EXPECT_EQ(absl::CivilSecond(kYearMin, 1, 1, 0, 0, 0),
+ absl::CivilSecond::min());
+}
+
+TEST(CivilTime, ImplicitCrossAlignment) {
+ absl::CivilYear year(2015);
+ absl::CivilMonth month = year;
+ absl::CivilDay day = month;
+ absl::CivilHour hour = day;
+ absl::CivilMinute minute = hour;
+ absl::CivilSecond second = minute;
+
+ second = year;
+ EXPECT_EQ(second, year);
+ second = month;
+ EXPECT_EQ(second, month);
+ second = day;
+ EXPECT_EQ(second, day);
+ second = hour;
+ EXPECT_EQ(second, hour);
+ second = minute;
+ EXPECT_EQ(second, minute);
+
+ minute = year;
+ EXPECT_EQ(minute, year);
+ minute = month;
+ EXPECT_EQ(minute, month);
+ minute = day;
+ EXPECT_EQ(minute, day);
+ minute = hour;
+ EXPECT_EQ(minute, hour);
+
+ hour = year;
+ EXPECT_EQ(hour, year);
+ hour = month;
+ EXPECT_EQ(hour, month);
+ hour = day;
+ EXPECT_EQ(hour, day);
+
+ day = year;
+ EXPECT_EQ(day, year);
+ day = month;
+ EXPECT_EQ(day, month);
+
+ month = year;
+ EXPECT_EQ(month, year);
+
+ // Ensures unsafe conversions are not allowed.
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilSecond, absl::CivilMinute>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilSecond, absl::CivilHour>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilSecond, absl::CivilDay>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilSecond, absl::CivilMonth>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilSecond, absl::CivilYear>::value));
+
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilMinute, absl::CivilHour>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilMinute, absl::CivilDay>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilMinute, absl::CivilMonth>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilMinute, absl::CivilYear>::value));
+
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilHour, absl::CivilDay>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilHour, absl::CivilMonth>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilHour, absl::CivilYear>::value));
+
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilDay, absl::CivilMonth>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilDay, absl::CivilYear>::value));
+
+ EXPECT_FALSE(
+ (std::is_convertible<absl::CivilMonth, absl::CivilYear>::value));
+}
+
+TEST(CivilTime, ExplicitCrossAlignment) {
+ //
+ // Assign from smaller units -> larger units
+ //
+
+ absl::CivilSecond second(2015, 1, 2, 3, 4, 5);
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second));
+
+ absl::CivilMinute minute(second);
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute));
+
+ absl::CivilHour hour(minute);
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour));
+
+ absl::CivilDay day(hour);
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day));
+
+ absl::CivilMonth month(day);
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(month));
+
+ absl::CivilYear year(month);
+ EXPECT_EQ("2015", absl::FormatCivilTime(year));
+
+ //
+ // Now assign from larger units -> smaller units
+ //
+
+ month = absl::CivilMonth(year);
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(month));
+
+ day = absl::CivilDay(month);
+ EXPECT_EQ("2015-01-01", absl::FormatCivilTime(day));
+
+ hour = absl::CivilHour(day);
+ EXPECT_EQ("2015-01-01T00", absl::FormatCivilTime(hour));
+
+ minute = absl::CivilMinute(hour);
+ EXPECT_EQ("2015-01-01T00:00", absl::FormatCivilTime(minute));
+
+ second = absl::CivilSecond(minute);
+ EXPECT_EQ("2015-01-01T00:00:00", absl::FormatCivilTime(second));
+}
+
+// Metafunction to test whether difference is allowed between two types.
+template <typename T1, typename T2>
+struct HasDiff {
+ template <typename U1, typename U2>
+ static std::false_type test(...);
+ template <typename U1, typename U2>
+ static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>()));
+ static constexpr bool value = decltype(test<T1, T2>(0))::value;
+};
+
+TEST(CivilTime, DisallowCrossAlignedDifference) {
+ // Difference is allowed between types with the same alignment.
+ static_assert(HasDiff<absl::CivilSecond, absl::CivilSecond>::value, "");
+ static_assert(HasDiff<absl::CivilMinute, absl::CivilMinute>::value, "");
+ static_assert(HasDiff<absl::CivilHour, absl::CivilHour>::value, "");
+ static_assert(HasDiff<absl::CivilDay, absl::CivilDay>::value, "");
+ static_assert(HasDiff<absl::CivilMonth, absl::CivilMonth>::value, "");
+ static_assert(HasDiff<absl::CivilYear, absl::CivilYear>::value, "");
+
+ // Difference is disallowed between types with different alignments.
+ static_assert(!HasDiff<absl::CivilSecond, absl::CivilMinute>::value, "");
+ static_assert(!HasDiff<absl::CivilSecond, absl::CivilHour>::value, "");
+ static_assert(!HasDiff<absl::CivilSecond, absl::CivilDay>::value, "");
+ static_assert(!HasDiff<absl::CivilSecond, absl::CivilMonth>::value, "");
+ static_assert(!HasDiff<absl::CivilSecond, absl::CivilYear>::value, "");
+
+ static_assert(!HasDiff<absl::CivilMinute, absl::CivilHour>::value, "");
+ static_assert(!HasDiff<absl::CivilMinute, absl::CivilDay>::value, "");
+ static_assert(!HasDiff<absl::CivilMinute, absl::CivilMonth>::value, "");
+ static_assert(!HasDiff<absl::CivilMinute, absl::CivilYear>::value, "");
+
+ static_assert(!HasDiff<absl::CivilHour, absl::CivilDay>::value, "");
+ static_assert(!HasDiff<absl::CivilHour, absl::CivilMonth>::value, "");
+ static_assert(!HasDiff<absl::CivilHour, absl::CivilYear>::value, "");
+
+ static_assert(!HasDiff<absl::CivilDay, absl::CivilMonth>::value, "");
+ static_assert(!HasDiff<absl::CivilDay, absl::CivilYear>::value, "");
+
+ static_assert(!HasDiff<absl::CivilMonth, absl::CivilYear>::value, "");
+}
+
+TEST(CivilTime, ValueSemantics) {
+ const absl::CivilHour a(2015, 1, 2, 3);
+ const absl::CivilHour b = a;
+ const absl::CivilHour c(b);
+ absl::CivilHour d;
+ d = c;
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(d));
+}
+
+TEST(CivilTime, Relational) {
+ // Tests that the alignment unit is ignored in comparison.
+ const absl::CivilYear year(2014);
+ const absl::CivilMonth month(year);
+ EXPECT_EQ(year, month);
+
+#define TEST_RELATIONAL(OLDER, YOUNGER) \
+ do { \
+ EXPECT_FALSE(OLDER < OLDER); \
+ EXPECT_FALSE(OLDER > OLDER); \
+ EXPECT_TRUE(OLDER >= OLDER); \
+ EXPECT_TRUE(OLDER <= OLDER); \
+ EXPECT_FALSE(YOUNGER < YOUNGER); \
+ EXPECT_FALSE(YOUNGER > YOUNGER); \
+ EXPECT_TRUE(YOUNGER >= YOUNGER); \
+ EXPECT_TRUE(YOUNGER <= YOUNGER); \
+ EXPECT_EQ(OLDER, OLDER); \
+ EXPECT_NE(OLDER, YOUNGER); \
+ EXPECT_LT(OLDER, YOUNGER); \
+ EXPECT_LE(OLDER, YOUNGER); \
+ EXPECT_GT(YOUNGER, OLDER); \
+ EXPECT_GE(YOUNGER, OLDER); \
+ } while (0)
+
+ // Alignment is ignored in comparison (verified above), so CivilSecond is
+ // used to test comparison in all field positions.
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2015, 1, 1, 0, 0, 0));
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2014, 2, 1, 0, 0, 0));
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2014, 1, 2, 0, 0, 0));
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2014, 1, 1, 1, 0, 0));
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 0, 0),
+ absl::CivilSecond(2014, 1, 1, 1, 1, 0));
+ TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 1, 0),
+ absl::CivilSecond(2014, 1, 1, 1, 1, 1));
+
+ // Tests the relational operators of two different civil-time types.
+ TEST_RELATIONAL(absl::CivilDay(2014, 1, 1),
+ absl::CivilMinute(2014, 1, 1, 1, 1));
+ TEST_RELATIONAL(absl::CivilDay(2014, 1, 1),
+ absl::CivilMonth(2014, 2));
+
+#undef TEST_RELATIONAL
+}
+
+TEST(CivilTime, Arithmetic) {
+ absl::CivilSecond second(2015, 1, 2, 3, 4, 5);
+ EXPECT_EQ("2015-01-02T03:04:06", absl::FormatCivilTime(second += 1));
+ EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second + 1));
+ EXPECT_EQ("2015-01-02T03:04:08", absl::FormatCivilTime(2 + second));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second - 1));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second -= 1));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second++));
+ EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(++second));
+ EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second--));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(--second));
+
+ absl::CivilMinute minute(2015, 1, 2, 3, 4);
+ EXPECT_EQ("2015-01-02T03:05", absl::FormatCivilTime(minute += 1));
+ EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute + 1));
+ EXPECT_EQ("2015-01-02T03:07", absl::FormatCivilTime(2 + minute));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute - 1));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute -= 1));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute++));
+ EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(++minute));
+ EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute--));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(--minute));
+
+ absl::CivilHour hour(2015, 1, 2, 3);
+ EXPECT_EQ("2015-01-02T04", absl::FormatCivilTime(hour += 1));
+ EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour + 1));
+ EXPECT_EQ("2015-01-02T06", absl::FormatCivilTime(2 + hour));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour - 1));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour -= 1));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour++));
+ EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(++hour));
+ EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour--));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(--hour));
+
+ absl::CivilDay day(2015, 1, 2);
+ EXPECT_EQ("2015-01-03", absl::FormatCivilTime(day += 1));
+ EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day + 1));
+ EXPECT_EQ("2015-01-05", absl::FormatCivilTime(2 + day));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day - 1));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day -= 1));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day++));
+ EXPECT_EQ("2015-01-04", absl::FormatCivilTime(++day));
+ EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day--));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(--day));
+
+ absl::CivilMonth month(2015, 1);
+ EXPECT_EQ("2015-02", absl::FormatCivilTime(month += 1));
+ EXPECT_EQ("2015-03", absl::FormatCivilTime(month + 1));
+ EXPECT_EQ("2015-04", absl::FormatCivilTime(2 + month));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(month - 1));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(month -= 1));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(month++));
+ EXPECT_EQ("2015-03", absl::FormatCivilTime(++month));
+ EXPECT_EQ("2015-03", absl::FormatCivilTime(month--));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(--month));
+
+ absl::CivilYear year(2015);
+ EXPECT_EQ("2016", absl::FormatCivilTime(year += 1));
+ EXPECT_EQ("2017", absl::FormatCivilTime(year + 1));
+ EXPECT_EQ("2018", absl::FormatCivilTime(2 + year));
+ EXPECT_EQ("2015", absl::FormatCivilTime(year - 1));
+ EXPECT_EQ("2015", absl::FormatCivilTime(year -= 1));
+ EXPECT_EQ("2015", absl::FormatCivilTime(year++));
+ EXPECT_EQ("2017", absl::FormatCivilTime(++year));
+ EXPECT_EQ("2017", absl::FormatCivilTime(year--));
+ EXPECT_EQ("2015", absl::FormatCivilTime(--year));
+}
+
+TEST(CivilTime, ArithmeticLimits) {
+ const int kIntMax = std::numeric_limits<int>::max();
+ const int kIntMin = std::numeric_limits<int>::min();
+
+ absl::CivilSecond second(1970, 1, 1, 0, 0, 0);
+ second += kIntMax;
+ EXPECT_EQ("2038-01-19T03:14:07", absl::FormatCivilTime(second));
+ second -= kIntMax;
+ EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second));
+ second += kIntMin;
+ EXPECT_EQ("1901-12-13T20:45:52", absl::FormatCivilTime(second));
+ second -= kIntMin;
+ EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second));
+
+ absl::CivilMinute minute(1970, 1, 1, 0, 0);
+ minute += kIntMax;
+ EXPECT_EQ("6053-01-23T02:07", absl::FormatCivilTime(minute));
+ minute -= kIntMax;
+ EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute));
+ minute += kIntMin;
+ EXPECT_EQ("-2114-12-08T21:52", absl::FormatCivilTime(minute));
+ minute -= kIntMin;
+ EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute));
+
+ absl::CivilHour hour(1970, 1, 1, 0);
+ hour += kIntMax;
+ EXPECT_EQ("246953-10-09T07", absl::FormatCivilTime(hour));
+ hour -= kIntMax;
+ EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour));
+ hour += kIntMin;
+ EXPECT_EQ("-243014-03-24T16", absl::FormatCivilTime(hour));
+ hour -= kIntMin;
+ EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour));
+
+ absl::CivilDay day(1970, 1, 1);
+ day += kIntMax;
+ EXPECT_EQ("5881580-07-11", absl::FormatCivilTime(day));
+ day -= kIntMax;
+ EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day));
+ day += kIntMin;
+ EXPECT_EQ("-5877641-06-23", absl::FormatCivilTime(day));
+ day -= kIntMin;
+ EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day));
+
+ absl::CivilMonth month(1970, 1);
+ month += kIntMax;
+ EXPECT_EQ("178958940-08", absl::FormatCivilTime(month));
+ month -= kIntMax;
+ EXPECT_EQ("1970-01", absl::FormatCivilTime(month));
+ month += kIntMin;
+ EXPECT_EQ("-178955001-05", absl::FormatCivilTime(month));
+ month -= kIntMin;
+ EXPECT_EQ("1970-01", absl::FormatCivilTime(month));
+
+ absl::CivilYear year(0);
+ year += kIntMax;
+ EXPECT_EQ("2147483647", absl::FormatCivilTime(year));
+ year -= kIntMax;
+ EXPECT_EQ("0", absl::FormatCivilTime(year));
+ year += kIntMin;
+ EXPECT_EQ("-2147483648", absl::FormatCivilTime(year));
+ year -= kIntMin;
+ EXPECT_EQ("0", absl::FormatCivilTime(year));
+}
+
+TEST(CivilTime, Difference) {
+ absl::CivilSecond second(2015, 1, 2, 3, 4, 5);
+ EXPECT_EQ(0, second - second);
+ EXPECT_EQ(10, (second + 10) - second);
+ EXPECT_EQ(-10, (second - 10) - second);
+
+ absl::CivilMinute minute(2015, 1, 2, 3, 4);
+ EXPECT_EQ(0, minute - minute);
+ EXPECT_EQ(10, (minute + 10) - minute);
+ EXPECT_EQ(-10, (minute - 10) - minute);
+
+ absl::CivilHour hour(2015, 1, 2, 3);
+ EXPECT_EQ(0, hour - hour);
+ EXPECT_EQ(10, (hour + 10) - hour);
+ EXPECT_EQ(-10, (hour - 10) - hour);
+
+ absl::CivilDay day(2015, 1, 2);
+ EXPECT_EQ(0, day - day);
+ EXPECT_EQ(10, (day + 10) - day);
+ EXPECT_EQ(-10, (day - 10) - day);
+
+ absl::CivilMonth month(2015, 1);
+ EXPECT_EQ(0, month - month);
+ EXPECT_EQ(10, (month + 10) - month);
+ EXPECT_EQ(-10, (month - 10) - month);
+
+ absl::CivilYear year(2015);
+ EXPECT_EQ(0, year - year);
+ EXPECT_EQ(10, (year + 10) - year);
+ EXPECT_EQ(-10, (year - 10) - year);
+}
+
+TEST(CivilTime, DifferenceLimits) {
+ const absl::civil_diff_t kDiffMax =
+ std::numeric_limits<absl::civil_diff_t>::max();
+ const absl::civil_diff_t kDiffMin =
+ std::numeric_limits<absl::civil_diff_t>::min();
+
+ // Check day arithmetic at the end of the year range.
+ const absl::CivilDay max_day(kDiffMax, 12, 31);
+ EXPECT_EQ(1, max_day - (max_day - 1));
+ EXPECT_EQ(-1, (max_day - 1) - max_day);
+
+ // Check day arithmetic at the start of the year range.
+ const absl::CivilDay min_day(kDiffMin, 1, 1);
+ EXPECT_EQ(1, (min_day + 1) - min_day);
+ EXPECT_EQ(-1, min_day - (min_day + 1));
+
+ // Check the limits of the return value.
+ const absl::CivilDay d1(1970, 1, 1);
+ const absl::CivilDay d2(25252734927768524, 7, 27);
+ EXPECT_EQ(kDiffMax, d2 - d1);
+ EXPECT_EQ(kDiffMin, d1 - (d2 + 1));
+}
+
+TEST(CivilTime, Properties) {
+ absl::CivilSecond ss(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, ss.year());
+ EXPECT_EQ(2, ss.month());
+ EXPECT_EQ(3, ss.day());
+ EXPECT_EQ(4, ss.hour());
+ EXPECT_EQ(5, ss.minute());
+ EXPECT_EQ(6, ss.second());
+
+ absl::CivilMinute mm(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, mm.year());
+ EXPECT_EQ(2, mm.month());
+ EXPECT_EQ(3, mm.day());
+ EXPECT_EQ(4, mm.hour());
+ EXPECT_EQ(5, mm.minute());
+ EXPECT_EQ(0, mm.second());
+
+ absl::CivilHour hh(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, hh.year());
+ EXPECT_EQ(2, hh.month());
+ EXPECT_EQ(3, hh.day());
+ EXPECT_EQ(4, hh.hour());
+ EXPECT_EQ(0, hh.minute());
+ EXPECT_EQ(0, hh.second());
+
+ absl::CivilDay d(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, d.year());
+ EXPECT_EQ(2, d.month());
+ EXPECT_EQ(3, d.day());
+ EXPECT_EQ(0, d.hour());
+ EXPECT_EQ(0, d.minute());
+ EXPECT_EQ(0, d.second());
+
+ absl::CivilMonth m(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, m.year());
+ EXPECT_EQ(2, m.month());
+ EXPECT_EQ(1, m.day());
+ EXPECT_EQ(0, m.hour());
+ EXPECT_EQ(0, m.minute());
+ EXPECT_EQ(0, m.second());
+
+ absl::CivilYear y(2015, 2, 3, 4, 5, 6);
+ EXPECT_EQ(2015, y.year());
+ EXPECT_EQ(1, y.month());
+ EXPECT_EQ(1, y.day());
+ EXPECT_EQ(0, y.hour());
+ EXPECT_EQ(0, y.minute());
+ EXPECT_EQ(0, y.second());
+}
+
+TEST(CivilTime, Format) {
+ absl::CivilSecond ss;
+ EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss));
+
+ absl::CivilMinute mm;
+ EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm));
+
+ absl::CivilHour hh;
+ EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh));
+
+ absl::CivilDay d;
+ EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d));
+
+ absl::CivilMonth m;
+ EXPECT_EQ("1970-01", absl::FormatCivilTime(m));
+
+ absl::CivilYear y;
+ EXPECT_EQ("1970", absl::FormatCivilTime(y));
+}
+
+TEST(CivilTime, FormatAndParseLenient) {
+ absl::CivilSecond ss;
+ EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss));
+
+ absl::CivilMinute mm;
+ EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm));
+
+ absl::CivilHour hh;
+ EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh));
+
+ absl::CivilDay d;
+ EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d));
+
+ absl::CivilMonth m;
+ EXPECT_EQ("1970-01", absl::FormatCivilTime(m));
+
+ absl::CivilYear y;
+ EXPECT_EQ("1970", absl::FormatCivilTime(y));
+}
+
+TEST(CivilTime, OutputStream) {
+ absl::CivilSecond cs(2016, 2, 3, 4, 5, 6);
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilYear(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016.................X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilMonth(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016-02..............X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilDay(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016-02-03...........X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilHour(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016-02-03T04........X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilMinute(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::CivilSecond(cs);
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str());
+ }
+ {
+ std::stringstream ss;
+ ss << std::left << std::setfill('.');
+ ss << std::setw(3) << 'X';
+ ss << std::setw(21) << absl::Weekday::wednesday;
+ ss << std::setw(3) << 'X';
+ EXPECT_EQ("X..Wednesday............X..", ss.str());
+ }
+}
+
+TEST(CivilTime, Weekday) {
+ absl::CivilDay d(1970, 1, 1);
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(d)) << d;
+
+ // We used to get this wrong for years < -30.
+ d = absl::CivilDay(-31, 12, 24);
+ EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(d)) << d;
+}
+
+TEST(CivilTime, NextPrevWeekday) {
+ // Jan 1, 1970 was a Thursday.
+ const absl::CivilDay thursday(1970, 1, 1);
+
+ // Thursday -> Thursday
+ absl::CivilDay d = absl::NextWeekday(thursday, absl::Weekday::thursday);
+ EXPECT_EQ(7, d - thursday) << d;
+ EXPECT_EQ(d - 14, absl::PrevWeekday(thursday, absl::Weekday::thursday));
+
+ // Thursday -> Friday
+ d = absl::NextWeekday(thursday, absl::Weekday::friday);
+ EXPECT_EQ(1, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::friday));
+
+ // Thursday -> Saturday
+ d = absl::NextWeekday(thursday, absl::Weekday::saturday);
+ EXPECT_EQ(2, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::saturday));
+
+ // Thursday -> Sunday
+ d = absl::NextWeekday(thursday, absl::Weekday::sunday);
+ EXPECT_EQ(3, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::sunday));
+
+ // Thursday -> Monday
+ d = absl::NextWeekday(thursday, absl::Weekday::monday);
+ EXPECT_EQ(4, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::monday));
+
+ // Thursday -> Tuesday
+ d = absl::NextWeekday(thursday, absl::Weekday::tuesday);
+ EXPECT_EQ(5, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::tuesday));
+
+ // Thursday -> Wednesday
+ d = absl::NextWeekday(thursday, absl::Weekday::wednesday);
+ EXPECT_EQ(6, d - thursday) << d;
+ EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::wednesday));
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceWithHugeYear) {
+ absl::CivilDay d1(9223372036854775807, 1, 1);
+ absl::CivilDay d2(9223372036854775807, 12, 31);
+ EXPECT_EQ(364, d2 - d1);
+
+ d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1);
+ d2 = absl::CivilDay(-9223372036854775807 - 1, 12, 31);
+ EXPECT_EQ(365, d2 - d1);
+
+ // Check the limits of the return value at the end of the year range.
+ d1 = absl::CivilDay(9223372036854775807, 1, 1);
+ d2 = absl::CivilDay(9198119301927009252, 6, 6);
+ EXPECT_EQ(9223372036854775807, d1 - d2);
+ d2 = d2 - 1;
+ EXPECT_EQ(-9223372036854775807 - 1, d2 - d1);
+
+ // Check the limits of the return value at the start of the year range.
+ d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1);
+ d2 = absl::CivilDay(-9198119301927009254, 7, 28);
+ EXPECT_EQ(9223372036854775807, d2 - d1);
+ d2 = d2 + 1;
+ EXPECT_EQ(-9223372036854775807 - 1, d1 - d2);
+
+ // Check the limits of the return value from either side of year 0.
+ d1 = absl::CivilDay(-12626367463883278, 9, 3);
+ d2 = absl::CivilDay(12626367463883277, 3, 28);
+ EXPECT_EQ(9223372036854775807, d2 - d1);
+ d2 = d2 + 1;
+ EXPECT_EQ(-9223372036854775807 - 1, d1 - d2);
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceNoIntermediateOverflow) {
+ // The difference up to the minute field would be below the minimum
+ // int64_t, but the 52 extra seconds brings us back to the minimum.
+ absl::CivilSecond s1(-292277022657, 1, 27, 8, 29 - 1, 52);
+ absl::CivilSecond s2(1970, 1, 1, 0, 0 - 1, 0);
+ EXPECT_EQ(-9223372036854775807 - 1, s1 - s2);
+
+ // The difference up to the minute field would be above the maximum
+ // int64_t, but the -53 extra seconds brings us back to the maximum.
+ s1 = absl::CivilSecond(292277026596, 12, 4, 15, 30, 7 - 7);
+ s2 = absl::CivilSecond(1970, 1, 1, 0, 0, 0 - 7);
+ EXPECT_EQ(9223372036854775807, s1 - s2);
+}
+
+TEST(CivilTime, NormalizeSimpleOverflow) {
+ absl::CivilSecond cs;
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32, 59 + 1);
+ EXPECT_EQ("2013-11-15T16:33:00", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16, 59 + 1, 14);
+ EXPECT_EQ("2013-11-15T17:00:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 23 + 1, 32, 14);
+ EXPECT_EQ("2013-11-16T00:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 30 + 1, 16, 32, 14);
+ EXPECT_EQ("2013-12-01T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 12 + 1, 15, 16, 32, 14);
+ EXPECT_EQ("2014-01-15T16:32:14", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeSimpleUnderflow) {
+ absl::CivilSecond cs;
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32, 0 - 1);
+ EXPECT_EQ("2013-11-15T16:31:59", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16, 0 - 1, 14);
+ EXPECT_EQ("2013-11-15T15:59:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 0 - 1, 32, 14);
+ EXPECT_EQ("2013-11-14T23:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 1 - 1, 16, 32, 14);
+ EXPECT_EQ("2013-10-31T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 1 - 1, 15, 16, 32, 14);
+ EXPECT_EQ("2012-12-15T16:32:14", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeMultipleOverflow) {
+ absl::CivilSecond cs(2013, 12, 31, 23, 59, 59 + 1);
+ EXPECT_EQ("2014-01-01T00:00:00", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeMultipleUnderflow) {
+ absl::CivilSecond cs(2014, 1, 1, 0, 0, 0 - 1);
+ EXPECT_EQ("2013-12-31T23:59:59", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeOverflowLimits) {
+ absl::CivilSecond cs;
+
+ const int kintmax = std::numeric_limits<int>::max();
+ cs = absl::CivilSecond(0, kintmax, kintmax, kintmax, kintmax, kintmax);
+ EXPECT_EQ("185085715-11-27T12:21:07", absl::FormatCivilTime(cs));
+
+ const int kintmin = std::numeric_limits<int>::min();
+ cs = absl::CivilSecond(0, kintmin, kintmin, kintmin, kintmin, kintmin);
+ EXPECT_EQ("-185085717-10-31T10:37:52", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeComplexOverflow) {
+ absl::CivilSecond cs;
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 + 123456789);
+ EXPECT_EQ("2017-10-14T14:05:23", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32 + 1234567, 14);
+ EXPECT_EQ("2016-03-22T00:39:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16 + 123456, 32, 14);
+ EXPECT_EQ("2027-12-16T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15 + 1234, 16, 32, 14);
+ EXPECT_EQ("2017-04-02T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11 + 123, 15, 16, 32, 14);
+ EXPECT_EQ("2024-02-15T16:32:14", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeComplexUnderflow) {
+ absl::CivilSecond cs;
+ cs = absl::CivilSecond(1999, 3, 0, 0, 0, 0); // year 400
+ EXPECT_EQ("1999-02-28T00:00:00", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 - 123456789);
+ EXPECT_EQ("2009-12-17T18:59:05", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16, 32 - 1234567, 14);
+ EXPECT_EQ("2011-07-12T08:25:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15, 16 - 123456, 32, 14);
+ EXPECT_EQ("1999-10-16T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11, 15 - 1234, 16, 32, 14);
+ EXPECT_EQ("2010-06-30T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11 - 123, 15, 16, 32, 14);
+ EXPECT_EQ("2003-08-15T16:32:14", absl::FormatCivilTime(cs));
+}
+
+TEST(CivilTime, NormalizeMishmash) {
+ absl::CivilSecond cs;
+ cs = absl::CivilSecond(2013, 11 - 123, 15 + 1234, 16 - 123456, 32 + 1234567,
+ 14 - 123456789);
+ EXPECT_EQ("1991-05-09T03:06:05", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11 + 123, 15 - 1234, 16 + 123456, 32 - 1234567,
+ 14 + 123456789);
+ EXPECT_EQ("2036-05-24T05:58:23", absl::FormatCivilTime(cs));
+
+ cs = absl::CivilSecond(2013, 11, -146097 + 1, 16, 32, 14);
+ EXPECT_EQ("1613-11-01T16:32:14", absl::FormatCivilTime(cs));
+ cs = absl::CivilSecond(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14);
+ EXPECT_EQ("2013-11-01T16:32:14", absl::FormatCivilTime(cs));
+}
+
+// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
+// and check that they normalize to the expected time. 146097 days span
+// the 400-year Gregorian cycle used during normalization.
+TEST(CivilTime, NormalizeAllTheDays) {
+ absl::CivilDay expected(1970, 1, 1);
+ for (int day = 1; day <= 146097; ++day) {
+ absl::CivilSecond cs(1970, 1, day, 0, 0, 0);
+ EXPECT_EQ(expected, cs);
+ ++expected;
+ }
+}
+
+TEST(CivilTime, NormalizeWithHugeYear) {
+ absl::CivilMonth c(9223372036854775807, 1);
+ EXPECT_EQ("9223372036854775807-01", absl::FormatCivilTime(c));
+ c = c - 1; // Causes normalization
+ EXPECT_EQ("9223372036854775806-12", absl::FormatCivilTime(c));
+
+ c = absl::CivilMonth(-9223372036854775807 - 1, 1);
+ EXPECT_EQ("-9223372036854775808-01", absl::FormatCivilTime(c));
+ c = c + 12; // Causes normalization
+ EXPECT_EQ("-9223372036854775807-01", absl::FormatCivilTime(c));
+}
+
+TEST(CivilTime, LeapYears) {
+ const absl::CivilSecond s1(2013, 2, 28 + 1, 0, 0, 0);
+ EXPECT_EQ("2013-03-01T00:00:00", absl::FormatCivilTime(s1));
+
+ const absl::CivilSecond s2(2012, 2, 28 + 1, 0, 0, 0);
+ EXPECT_EQ("2012-02-29T00:00:00", absl::FormatCivilTime(s2));
+
+ const absl::CivilSecond s3(1900, 2, 28 + 1, 0, 0, 0);
+ EXPECT_EQ("1900-03-01T00:00:00", absl::FormatCivilTime(s3));
+
+ const struct {
+ int year;
+ int days;
+ struct {
+ int month;
+ int day;
+ } leap_day; // The date of the day after Feb 28.
+ } kLeapYearTable[]{
+ {1900, 365, {3, 1}},
+ {1999, 365, {3, 1}},
+ {2000, 366, {2, 29}}, // leap year
+ {2001, 365, {3, 1}},
+ {2002, 365, {3, 1}},
+ {2003, 365, {3, 1}},
+ {2004, 366, {2, 29}}, // leap year
+ {2005, 365, {3, 1}},
+ {2006, 365, {3, 1}},
+ {2007, 365, {3, 1}},
+ {2008, 366, {2, 29}}, // leap year
+ {2009, 365, {3, 1}},
+ {2100, 365, {3, 1}},
+ };
+
+ for (int i = 0; i < ABSL_ARRAYSIZE(kLeapYearTable); ++i) {
+ const int y = kLeapYearTable[i].year;
+ const int m = kLeapYearTable[i].leap_day.month;
+ const int d = kLeapYearTable[i].leap_day.day;
+ const int n = kLeapYearTable[i].days;
+
+ // Tests incrementing through the leap day.
+ const absl::CivilDay feb28(y, 2, 28);
+ const absl::CivilDay next_day = feb28 + 1;
+ EXPECT_EQ(m, next_day.month());
+ EXPECT_EQ(d, next_day.day());
+
+ // Tests difference in days of leap years.
+ const absl::CivilYear year(feb28);
+ const absl::CivilYear next_year = year + 1;
+ EXPECT_EQ(n, absl::CivilDay(next_year) - absl::CivilDay(year));
+ }
+}
+
+TEST(CivilTime, FirstThursdayInMonth) {
+ const absl::CivilDay nov1(2014, 11, 1);
+ const absl::CivilDay thursday =
+ absl::PrevWeekday(nov1, absl::Weekday::thursday) + 7;
+ EXPECT_EQ("2014-11-06", absl::FormatCivilTime(thursday));
+
+ // Bonus: Date of Thanksgiving in the United States
+ // Rule: Fourth Thursday of November
+ const absl::CivilDay thanksgiving = thursday + 7 * 3;
+ EXPECT_EQ("2014-11-27", absl::FormatCivilTime(thanksgiving));
+}
+
+TEST(CivilTime, DocumentationExample) {
+ absl::CivilSecond second(2015, 6, 28, 1, 2, 3); // 2015-06-28 01:02:03
+ absl::CivilMinute minute(second); // 2015-06-28 01:02:00
+ absl::CivilDay day(minute); // 2015-06-28 00:00:00
+
+ second -= 1; // 2015-06-28 01:02:02
+ --second; // 2015-06-28 01:02:01
+ EXPECT_EQ(minute, second - 1); // Comparison between types
+ EXPECT_LT(minute, second);
+
+ // int diff = second - minute; // ERROR: Mixed types, won't compile
+
+ absl::CivilDay june_1(2015, 6, 1); // Pass fields to c'tor.
+ int diff = day - june_1; // Num days between 'day' and June 1
+ EXPECT_EQ(27, diff);
+
+ // Fields smaller than alignment are floored to their minimum value.
+ absl::CivilDay day_floor(2015, 1, 2, 9, 9, 9);
+ EXPECT_EQ(0, day_floor.hour()); // 09:09:09 is floored
+ EXPECT_EQ(absl::CivilDay(2015, 1, 2), day_floor);
+
+ // Unspecified fields default to their minium value
+ absl::CivilDay day_default(2015); // Defaults to Jan 1
+ EXPECT_EQ(absl::CivilDay(2015, 1, 1), day_default);
+
+ // Iterates all the days of June.
+ absl::CivilMonth june(day); // CivilDay -> CivilMonth
+ absl::CivilMonth july = june + 1;
+ for (absl::CivilDay day = june_1; day < july; ++day) {
+ // ...
+ }
+}
+
+} // namespace
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index 74ee140..fa0ed34 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -379,7 +379,7 @@
//
// Manually mark this 'noinline' to minimize stack frame size of the fast
// path. Without this, sometimes a compiler may inline this big block of code
-// into the fast past. That causes lots of register spills and reloads that
+// into the fast path. That causes lots of register spills and reloads that
// are unnecessary unless the slow path is taken.
//
// TODO(absl-team): Remove this attribute when our compiler is smart enough
diff --git a/absl/time/clock.h b/absl/time/clock.h
index 3753d4e..bb52e4f 100644
--- a/absl/time/clock.h
+++ b/absl/time/clock.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/clock_benchmark.cc b/absl/time/clock_benchmark.cc
index 3d3cd9d..a69fe00 100644
--- a/absl/time/clock_benchmark.cc
+++ b/absl/time/clock_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
index 707166d..4bcfc6b 100644
--- a/absl/time/clock_test.cc
+++ b/absl/time/clock_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 2950c7c..67791fe 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -78,10 +78,16 @@
// Can't use std::isinfinite() because it doesn't exist on windows.
inline bool IsFinite(double d) {
+ if (std::isnan(d)) return false;
return d != std::numeric_limits<double>::infinity() &&
d != -std::numeric_limits<double>::infinity();
}
+inline bool IsValidDivisor(double d) {
+ if (std::isnan(d)) return false;
+ return d != 0.0;
+}
+
// Can't use std::round() because it is only available in C++11.
// Note that we ignore the possibility of floating-point over/underflow.
template <typename Double>
@@ -455,7 +461,7 @@
}
Duration& Duration::operator/=(double r) {
- if (time_internal::IsInfiniteDuration(*this) || r == 0.0) {
+ if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
@@ -743,9 +749,9 @@
} // namespace
-// From Go's doc at http://golang.org/pkg/time/#Duration.String
+// From Go's doc at https://golang.org/pkg/time/#Duration.String
// [FormatDuration] returns a string representing the duration in the
-// form "72h3m0.5s". Leading zero units are omitted. As a special
+// form "72h3m0.5s". Leading zero units are omitted. As a special
// case, durations less than one second format use a smaller unit
// (milli-, micro-, or nanoseconds) to ensure that the leading digit
// is non-zero. The zero duration formats as 0, with no unit.
@@ -849,8 +855,8 @@
} // namespace
-// From Go's doc at http://golang.org/pkg/time/#ParseDuration
-// [ParseDuration] parses a duration string. A duration string is
+// From Go's doc at https://golang.org/pkg/time/#ParseDuration
+// [ParseDuration] parses a duration string. A duration string is
// a possibly signed sequence of decimal numbers, each with optional
// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
// Valid time units are "ns", "us" "ms", "s", "m", "h".
@@ -895,6 +901,7 @@
*d = dur;
return true;
}
+
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
return ParseDuration(text, dst);
}
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
index d5657bd..83a836c 100644
--- a/absl/time/duration_benchmark.cc
+++ b/absl/time/duration_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,6 +17,7 @@
#include <ctime>
#include <string>
+#include "absl/base/attributes.h"
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 7ae25dc..e3cede6 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -56,6 +56,17 @@
return false;
}
+TEST(Duration, ConstExpr) {
+ constexpr absl::Duration d0 = absl::ZeroDuration();
+ static_assert(d0 == absl::ZeroDuration(), "ZeroDuration()");
+ constexpr absl::Duration d1 = absl::Seconds(1);
+ static_assert(d1 == absl::Seconds(1), "Seconds(1)");
+ static_assert(d1 != absl::ZeroDuration(), "Seconds(1)");
+ constexpr absl::Duration d2 = absl::InfiniteDuration();
+ static_assert(d2 == absl::InfiniteDuration(), "InfiniteDuration()");
+ static_assert(d2 != absl::ZeroDuration(), "InfiniteDuration()");
+}
+
TEST(Duration, ValueSemantics) {
// If this compiles, the test passes.
constexpr absl::Duration a; // Default construction
@@ -792,6 +803,40 @@
EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero));
}
+TEST(Duration, NaN) {
+ // Note that IEEE 754 does not define the behavior of a nan's sign when it is
+ // copied, so the code below allows for either + or - InfiniteDuration.
+#define TEST_NAN_HANDLING(NAME, NAN) \
+ do { \
+ const auto inf = absl::InfiniteDuration(); \
+ auto x = NAME(NAN); \
+ EXPECT_TRUE(x == inf || x == -inf); \
+ auto y = NAME(42); \
+ y *= NAN; \
+ EXPECT_TRUE(y == inf || y == -inf); \
+ auto z = NAME(42); \
+ z /= NAN; \
+ EXPECT_TRUE(z == inf || z == -inf); \
+ } while (0)
+
+ const double nan = std::numeric_limits<double>::quiet_NaN();
+ TEST_NAN_HANDLING(absl::Nanoseconds, nan);
+ TEST_NAN_HANDLING(absl::Microseconds, nan);
+ TEST_NAN_HANDLING(absl::Milliseconds, nan);
+ TEST_NAN_HANDLING(absl::Seconds, nan);
+ TEST_NAN_HANDLING(absl::Minutes, nan);
+ TEST_NAN_HANDLING(absl::Hours, nan);
+
+ TEST_NAN_HANDLING(absl::Nanoseconds, -nan);
+ TEST_NAN_HANDLING(absl::Microseconds, -nan);
+ TEST_NAN_HANDLING(absl::Milliseconds, -nan);
+ TEST_NAN_HANDLING(absl::Seconds, -nan);
+ TEST_NAN_HANDLING(absl::Minutes, -nan);
+ TEST_NAN_HANDLING(absl::Hours, -nan);
+
+#undef TEST_NAN_HANDLING
+}
+
TEST(Duration, Range) {
const absl::Duration range = ApproxYears(100 * 1e9);
const absl::Duration range_future = range;
@@ -1726,7 +1771,7 @@
TEST(Duration, FormatParseRoundTrip) {
#define TEST_PARSE_ROUNDTRIP(d) \
do { \
- std::string s = absl::FormatDuration(d); \
+ std::string s = absl::FormatDuration(d); \
absl::Duration dur; \
EXPECT_TRUE(absl::ParseDuration(s, &dur)); \
EXPECT_EQ(d, dur); \
diff --git a/absl/time/format.cc b/absl/time/format.cc
index ee597e4..d6ca860 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -67,7 +67,8 @@
} // namespace
-std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) {
+std::string FormatTime(const std::string& format, absl::Time t,
+ absl::TimeZone tz) {
if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
if (t == absl::InfinitePast()) return kInfinitePastStr;
const auto parts = Split(t);
@@ -83,15 +84,15 @@
return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
}
-bool ParseTime(const std::string& format, const std::string& input, absl::Time* time,
- std::string* err) {
+bool ParseTime(const std::string& format, const std::string& input,
+ absl::Time* time, std::string* err) {
return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
}
// If the input string does not contain an explicit UTC offset, interpret
// the fields with respect to the given TimeZone.
-bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz,
- absl::Time* time, std::string* err) {
+bool ParseTime(const std::string& format, const std::string& input,
+ absl::TimeZone tz, absl::Time* time, std::string* err) {
const char* data = input.c_str();
while (std::isspace(*data)) ++data;
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc
index ee53d71..249c51d 100644
--- a/absl/time/format_benchmark.cc
+++ b/absl/time/format_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -38,7 +38,8 @@
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
const absl::Time t =
- absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
+ absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) +
+ absl::Nanoseconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length());
}
@@ -50,8 +51,8 @@
state.SetLabel(fmt);
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
- absl::Time t =
- absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
+ absl::Time t = absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) +
+ absl::Nanoseconds(1);
const std::string when = absl::FormatTime(fmt, t, lax);
std::string err;
while (state.KeepRunning()) {
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc
index 7c84c33..4a1f1aa 100644
--- a/absl/time/format_test.cc
+++ b/absl/time/format_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,8 +27,8 @@
// A helper that tests the given format specifier by itself, and with leading
// and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu").
-void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt,
- const std::string& ans) {
+void TestFormatSpecifier(absl::Time t, absl::TimeZone tz,
+ const std::string& fmt, const std::string& ans) {
EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz));
EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz));
EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz));
@@ -118,7 +118,7 @@
absl::TimeZone tz = absl::UTCTimeZone();
// A year of 77 should be padded to 0077.
- absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz);
+ absl::Time t = absl::FromCivil(absl::CivilSecond(77, 6, 28, 9, 8, 7), tz);
EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000",
absl::FormatTime(absl::RFC1123_full, t, tz));
EXPECT_EQ("28 Jun 0077 09:08:07 +0000",
@@ -154,9 +154,9 @@
EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
"2013-06-28 19:08:09 -0800", &t, &err))
<< err;
- absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false);
- EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+ const auto ci = absl::FixedTimeZone(-8 * 60 * 60).At(t);
+ EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
+ EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
}
TEST(ParseTime, NullErrorString) {
@@ -177,17 +177,17 @@
EXPECT_TRUE(
absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
<< e;
- absl::Time::Breakdown bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true);
- EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+ auto ci = tz.At(t);
+ EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
+ EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
// But the timezone is ignored when a UTC offset is present.
EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
"2013-06-28 19:08:09 +0800", tz, &t, &e))
<< e;
- bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false);
- EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+ ci = absl::FixedTimeZone(8 * 60 * 60).At(t);
+ EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
+ EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
}
TEST(ParseTime, ErrorCases) {
@@ -332,15 +332,15 @@
EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
&t, &err));
EXPECT_NE(absl::InfiniteFuture(), t);
- EXPECT_EQ(3, t.In(tz).hour);
- EXPECT_EQ(4, t.In(tz).minute);
+ EXPECT_EQ(3, tz.At(t).cs.hour());
+ EXPECT_EQ(4, tz.At(t).cs.minute());
// "infinite-past" as literal std::string
EXPECT_TRUE(
absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
EXPECT_NE(absl::InfinitePast(), t);
- EXPECT_EQ(3, t.In(tz).hour);
- EXPECT_EQ(4, t.In(tz).minute);
+ EXPECT_EQ(3, tz.At(t).cs.hour());
+ EXPECT_EQ(4, tz.At(t).cs.minute());
// The input doesn't match the format.
EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err));
@@ -365,16 +365,18 @@
//
TEST(FormatParse, RoundTrip) {
- const absl::TimeZone gst =
+ const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
- const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst);
+ const absl::Time in =
+ absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax);
const absl::Duration subseconds = absl::Nanoseconds(654321);
std::string err;
// RFC3339, which renders subseconds.
{
absl::Time out;
- const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst);
+ const std::string s =
+ absl::FormatTime(absl::RFC3339_full, in + subseconds, lax);
EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
<< s << ": " << err;
EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
@@ -383,7 +385,7 @@
// RFC1123, which only does whole seconds.
{
absl::Time out;
- const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst);
+ const std::string s = absl::FormatTime(absl::RFC1123_full, in, lax);
EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err))
<< s << ": " << err;
EXPECT_EQ(in, out); // RFC1123_full includes %z
@@ -393,7 +395,12 @@
// work. On Windows, `absl::ParseTime()` falls back to std::get_time() which
// appears to fail on "%c" (or at least on the "%c" text produced by
// `strftime()`). This makes it fail the round-trip test.
-#ifndef _MSC_VER
+ //
+ // Under the emscripten compiler `absl::ParseTime() falls back to
+ // `strptime()`, but that ends up using a different definition for "%c"
+ // compared to `strftime()`, also causing the round-trip test to fail
+ // (see https://github.com/kripken/emscripten/pull/7491).
+#if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__)
// Even though we don't know what %c will produce, it should roundtrip,
// but only in the 0-offset timezone.
{
@@ -402,7 +409,7 @@
EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err;
EXPECT_EQ(in, out);
}
-#endif // _MSC_VER
+#endif // !_MSC_VER && !__EMSCRIPTEN__
}
TEST(FormatParse, RoundTripDistantFuture) {
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index 9f1ba21..903499b 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+package(features = ["-parse_headers"])
+
licenses(["notice"]) # Apache License
### libraries
@@ -85,6 +87,7 @@
"no_test_android_arm",
"no_test_android_arm64",
"no_test_android_x86",
+ "no_test_wasm",
],
deps = [
":civil_time",
@@ -96,12 +99,14 @@
cc_test(
name = "time_zone_lookup_test",
size = "small",
+ timeout = "moderate",
srcs = ["src/time_zone_lookup_test.cc"],
data = [":zoneinfo"],
tags = [
"no_test_android_arm",
"no_test_android_arm64",
"no_test_android_x86",
+ "no_test_wasm",
],
deps = [
":civil_time",
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h
index 0842fa4..f844182 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index d7f7271..a5923f1 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -326,6 +326,37 @@
////////////////////////////////////////////////////////////////////////
+namespace impl {
+
+template <typename H>
+H AbslHashValueImpl(second_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss);
+}
+template <typename H>
+H AbslHashValueImpl(minute_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm);
+}
+template <typename H>
+H AbslHashValueImpl(hour_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y, f.m, f.d, f.hh);
+}
+template <typename H>
+H AbslHashValueImpl(day_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y, f.m, f.d);
+}
+template <typename H>
+H AbslHashValueImpl(month_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y, f.m);
+}
+template <typename H>
+H AbslHashValueImpl(year_tag, H h, fields f) {
+ return H::combine(std::move(h), f.y);
+}
+
+} // namespace impl
+
+////////////////////////////////////////////////////////////////////////
+
template <typename T>
class civil_time {
public:
@@ -355,12 +386,12 @@
: civil_time(ct.f_) {}
// Factories for the maximum/minimum representable civil_time.
- static CONSTEXPR_F civil_time max() {
- const auto max_year = std::numeric_limits<std::int_least64_t>::max();
+ static CONSTEXPR_F civil_time (max)() {
+ const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
return civil_time(max_year, 12, 31, 23, 59, 59);
}
- static CONSTEXPR_F civil_time min() {
- const auto min_year = std::numeric_limits<std::int_least64_t>::min();
+ static CONSTEXPR_F civil_time (min)() {
+ const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
return civil_time(min_year, 1, 1, 0, 0, 0);
}
@@ -378,7 +409,7 @@
return *this;
}
CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
- if (n != std::numeric_limits<diff_t>::min()) {
+ if (n != (std::numeric_limits<diff_t>::min)()) {
f_ = step(T{}, f_, -n);
} else {
f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
@@ -418,8 +449,7 @@
template <typename H>
friend H AbslHashValue(H h, civil_time a) {
- return H::combine(std::move(h), a.f_.y, a.f_.m, a.f_.d,
- a.f_.hh, a.f_.mm, a.f_.ss);
+ return impl::AbslHashValueImpl(T{}, std::move(h), a.f_);
}
private:
@@ -506,9 +536,11 @@
};
CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
- CONSTEXPR_D weekday k_weekday_by_sun_off[7] = {
- weekday::sunday, weekday::monday, weekday::tuesday,
- weekday::wednesday, weekday::thursday, weekday::friday,
+ CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
+ weekday::monday, weekday::tuesday, weekday::wednesday,
+ weekday::thursday, weekday::friday, weekday::saturday,
+ weekday::sunday, weekday::monday, weekday::tuesday,
+ weekday::wednesday, weekday::thursday, weekday::friday,
weekday::saturday,
};
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
@@ -517,7 +549,7 @@
year_t wd = 2400 + (cd.year() % 400) - (cd.month() < 3);
wd += wd / 4 - wd / 100 + wd / 400;
wd += k_weekday_offsets[cd.month()] + cd.day();
- return k_weekday_by_sun_off[(wd % 7 + 7) % 7];
+ return k_weekday_by_mon_off[wd % 7 + 6];
}
////////////////////////////////////////////////////////////////////////
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h
index f28dad1..ef6c4ba 100644
--- a/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -72,7 +72,7 @@
//
// See also:
// - http://www.iana.org/time-zones
-// - http://en.wikipedia.org/wiki/Zoneinfo
+// - https://en.wikipedia.org/wiki/Zoneinfo
class time_zone {
public:
time_zone() : time_zone(nullptr) {} // Equivalent to UTC
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h
index 20a7697..2b898d1 100644
--- a/absl/time/internal/cctz/include/cctz/zone_info_source.h
+++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index 4498d7d..445366e 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -357,6 +357,7 @@
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
diff --git a/absl/time/internal/cctz/src/civil_time_detail.cc b/absl/time/internal/cctz/src/civil_time_detail.cc
index 780d5c9..cb40b6b 100644
--- a/absl/time/internal/cctz/src/civil_time_detail.cc
+++ b/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index faffde4..e590ee3 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index db9a475..81ece72 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.h b/absl/time/internal/cctz/src/time_zone_fixed.h
index 489b857..9c1f5e7 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.h
+++ b/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index a02b1e3..2585098 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,7 @@
// limitations under the License.
#if !defined(HAS_STRPTIME)
-# if !defined(_MSC_VER)
+# if !defined(_MSC_VER) && !defined(__MINGW32__)
# define HAS_STRPTIME 1 // assume everyone has strptime() except windows
# endif
#endif
@@ -149,15 +149,25 @@
offset = -offset; // bounded by 24h so no overflow
sign = '-';
}
- char sep = mode[0];
- if (sep != '\0' && mode[1] == '*') {
- ep = Format02d(ep, offset % 60);
+ const int seconds = offset % 60;
+ const int minutes = (offset /= 60) % 60;
+ const int hours = offset /= 60;
+ const char sep = mode[0];
+ const bool ext = (sep != '\0' && mode[1] == '*');
+ const bool ccc = (ext && mode[2] == ':');
+ if (ext && (!ccc || seconds != 0)) {
+ ep = Format02d(ep, seconds);
*--ep = sep;
+ } else {
+ // If we're not rendering seconds, sub-minute negative offsets
+ // should get a positive sign (e.g., offset=-10s => "+00:00").
+ if (hours == 0 && minutes == 0) sign = '+';
}
- int minutes = offset / 60;
- ep = Format02d(ep, minutes % 60);
- if (sep != '\0') *--ep = sep;
- ep = Format02d(ep, minutes / 60);
+ if (!ccc || minutes != 0 || seconds != 0) {
+ ep = Format02d(ep, minutes);
+ if (sep != '\0') *--ep = sep;
+ }
+ ep = Format02d(ep, hours);
*--ep = sign;
return ep;
}
@@ -384,6 +394,44 @@
continue;
}
+ // More complex specifiers that we handle ourselves.
+ if (*cur == ':' && cur + 1 != end) {
+ if (*(cur + 1) == 'z') {
+ // Formats %:z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 2;
+ continue;
+ }
+ if (*(cur + 1) == ':' && cur + 2 != end) {
+ if (*(cur + 2) == 'z') {
+ // Formats %::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 3;
+ continue;
+ }
+ if (*(cur + 2) == ':' && cur + 3 != end) {
+ if (*(cur + 3) == 'z') {
+ // Formats %:::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*:");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 4;
+ continue;
+ }
+ }
+ }
+ }
+
// Loop if there is no E modifier.
if (*cur != 'E' || ++cur == end) continue;
@@ -668,17 +716,27 @@
&percent_s);
if (data != nullptr) saw_percent_s = true;
continue;
+ case ':':
+ if (fmt[0] == 'z' ||
+ (fmt[0] == ':' &&
+ (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
+ data = ParseOffset(data, ":", &offset);
+ if (data != nullptr) saw_offset = true;
+ fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
+ continue;
+ }
+ break;
case '%':
data = (*data == '%' ? data + 1 : nullptr);
continue;
case 'E':
- if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) {
+ if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
data = ParseOffset(data, ":", &offset);
if (data != nullptr) saw_offset = true;
- fmt += (*fmt == 'z') ? 1 : 2;
+ fmt += (fmt[0] == 'z') ? 1 : 2;
continue;
}
- if (*fmt == '*' && *(fmt + 1) == 'S') {
+ if (fmt[0] == '*' && fmt[1] == 'S') {
data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
if (data != nullptr && *data == '.') {
data = ParseSubSeconds(data + 1, &subseconds);
@@ -686,14 +744,14 @@
fmt += 2;
continue;
}
- if (*fmt == '*' && *(fmt + 1) == 'f') {
+ if (fmt[0] == '*' && fmt[1] == 'f') {
if (data != nullptr && std::isdigit(*data)) {
data = ParseSubSeconds(data, &subseconds);
}
fmt += 2;
continue;
}
- if (*fmt == '4' && *(fmt + 1) == 'Y') {
+ if (fmt[0] == '4' && fmt[1] == 'Y') {
const char* bp = data;
data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
if (data != nullptr) {
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 6b9928e..705ccdc 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -64,17 +64,6 @@
EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
}
-// These tests sometimes run on platforms that have zoneinfo data so old
-// that the transition we are attempting to check does not exist, most
-// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
-// time_zone::version() so, in cases where we've learned that it matters,
-// we can make the check conditionally.
-int VersionCmp(time_zone tz, const std::string& target) {
- std::string version = tz.version();
- if (version.empty() && !target.empty()) return 1; // unknown > known
- return version.compare(target);
-}
-
} // namespace
//
@@ -174,7 +163,9 @@
TestFormatSpecifier(tp, tz, "%M", "00");
TestFormatSpecifier(tp, tz, "%S", "00");
TestFormatSpecifier(tp, tz, "%U", "00");
+#if !defined(__EMSCRIPTEN__)
TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday
+#endif
TestFormatSpecifier(tp, tz, "%W", "00");
TestFormatSpecifier(tp, tz, "%y", "70");
TestFormatSpecifier(tp, tz, "%Y", "1970");
@@ -436,51 +427,165 @@
}
TEST(Format, ExtendedOffset) {
- auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
- time_zone tz = utc_time_zone();
+ auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("America/New_York", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "-05:00");
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "-08:00");
+ tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "+10:00");
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
- EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz));
- // The true offset is -00:44:30 but %z only gives (truncated) minutes.
- TestFormatSpecifier(tp, tz, "%z", "-0044");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:44");
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
}
TEST(Format, ExtendedSecondOffset) {
- const time_zone utc = utc_time_zone();
- time_point<chrono::seconds> tp;
- time_zone tz;
+ const auto tp = chrono::system_clock::from_time_t(0);
- EXPECT_TRUE(load_time_zone("America/New_York", &tz));
- tp = convert(civil_second(1883, 11, 18, 16, 59, 59), utc);
- if (tz.lookup(tp).offset == -5 * 60 * 60) {
- // It looks like the tzdata is only 32 bit (probably macOS),
- // which bottoms out at 1901-12-13T20:45:52+00:00.
- } else {
- TestFormatSpecifier(tp, tz, "%E*z", "-04:56:02");
- TestFormatSpecifier(tp, tz, "%Ez", "-04:56");
- }
- tp += chrono::seconds(1);
- TestFormatSpecifier(tp, tz, "%E*z", "-05:00:00");
+ auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00");
- EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz));
- tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc);
- if (VersionCmp(tz, "2016g") >= 0) {
- TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
- TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
- }
- tp += chrono::seconds(1);
- TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00");
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
+
+ tz = fixed_time_zone(-chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
}
TEST(Format, ExtendedYears) {
@@ -1160,25 +1265,6 @@
const time_zone utc = utc_time_zone();
time_point<absl::time_internal::cctz::seconds> tp;
- // %z against +-HHMM.
- EXPECT_TRUE(parse("%z", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%z", "-123", utc, &tp));
-
- // %z against +-HH.
- EXPECT_TRUE(parse("%z", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%z", "-1", utc, &tp));
-
- // %Ez against +-HH:MM.
EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
@@ -1187,91 +1273,70 @@
EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
- // %Ez against +-HHMM.
- EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-123", utc, &tp));
+ for (auto fmt : {"%Ez", "%z"}) {
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
- // %Ez against +-HH.
- EXPECT_TRUE(parse("%Ez", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-1", utc, &tp));
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
}
TEST(Parse, ExtendedSecondOffset) {
const time_zone utc = utc_time_zone();
time_point<absl::time_internal::cctz::seconds> tp;
- // %Ez against +-HH:MM:SS.
- EXPECT_TRUE(parse("%Ez", "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12:34:5", utc, &tp));
+ for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
+ EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
- // %Ez against +-HHMMSS.
- EXPECT_TRUE(parse("%Ez", "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12345", utc, &tp));
+ EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
- // %E*z against +-HH:MM:SS.
- EXPECT_TRUE(parse("%E*z", "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12:34:5", utc, &tp));
+ EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
- // %E*z against +-HHMMSS.
- EXPECT_TRUE(parse("%E*z", "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12345", utc, &tp));
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
- // %E*z against +-HH:MM.
- EXPECT_TRUE(parse("%E*z", "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12:3", utc, &tp));
-
- // %E*z against +-HHMM.
- EXPECT_TRUE(parse("%E*z", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-123", utc, &tp));
-
- // %E*z against +-HH.
- EXPECT_TRUE(parse("%E*z", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-1", utc, &tp));
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
}
TEST(Parse, ExtendedYears) {
@@ -1390,6 +1455,10 @@
#if defined(_WIN32) || defined(_WIN64)
// Initial investigations indicate the %c does not roundtrip on Windows.
// TODO: Figure out what is going on here (perhaps a locale problem).
+#elif defined(__EMSCRIPTEN__)
+ // strftime() and strptime() use different defintions for "%c" under
+ // emscripten (see https://github.com/kripken/emscripten/pull/7491),
+ // causing its round-trip test to fail.
#else
// Even though we don't know what %c will produce, it should roundtrip,
// but only in the 0-offset timezone.
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
index 380834a..09aaee5 100644
--- a/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h
index e4bd386..d000b7a 100644
--- a/absl/time/internal/cctz/src/time_zone_if.h
+++ b/absl/time/internal/cctz/src/time_zone_if.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index 3062ccd..3cbc674 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h
index 14965ef..b73fad9 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.h
+++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index 2cb358d..50f7de5 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
// a grain of salt.
//
// For more information see tzfile(5), http://www.iana.org/time-zones, or
-// http://en.wikipedia.org/wiki/Zoneinfo.
+// https://en.wikipedia.org/wiki/Zoneinfo.
//
// Note that we assume the proleptic Gregorian calendar and 60-second
// minutes throughout.
@@ -921,7 +921,7 @@
++begin;
}
std::int_fast64_t unix_time = ToUnixSeconds(tp);
- const Transition target = { unix_time };
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::upper_bound(begin, end, target,
Transition::ByUnixTime());
for (; tr != end; ++tr) { // skip no-op transitions
@@ -956,7 +956,7 @@
}
unix_time += 1; // ceils
}
- const Transition target = { unix_time };
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::lower_bound(begin, end, target,
Transition::ByUnixTime());
for (; tr != begin; --tr) { // skip no-op transitions
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h
index 958e9b6..bff639f 100644
--- a/absl/time/internal/cctz/src/time_zone_info.h
+++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 074c8d0..3ab1623 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,6 +20,7 @@
#include <chrono>
#include <ctime>
+#include <limits>
#include <tuple>
#include <utility>
@@ -85,6 +86,76 @@
#endif // !defined(__tm_gmtoff) && !defined(__tm_zone)
#endif
+inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+ return gmtime_s(result, timep) ? nullptr : result;
+#else
+ return gmtime_r(timep, result);
+#endif
+}
+
+inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+ return localtime_s(result, timep) ? nullptr : result;
+#else
+ return localtime_r(timep, result);
+#endif
+}
+
+// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Returns false if time_t cannot represent the requested civil second.
+// Caller must have already checked that cs.year() will fit into a tm_year.
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
+ std::tm tm;
+ tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
+ tm.tm_mon = cs.month() - 1;
+ tm.tm_mday = cs.day();
+ tm.tm_hour = cs.hour();
+ tm.tm_min = cs.minute();
+ tm.tm_sec = cs.second();
+ tm.tm_isdst = is_dst;
+ *t = std::mktime(&tm);
+ if (*t == std::time_t{-1}) {
+ std::tm tm2;
+ const std::tm* tmp = local_time(t, &tm2);
+ if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
+ tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
+ tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
+ tmp->tm_sec != tm.tm_sec) {
+ // A true error (not just one second before the epoch).
+ return false;
+ }
+ }
+ *off = get_offset_abbr(tm).first;
+ return true;
+}
+
+// Find the least time_t in [lo:hi] where local time matches offset, given:
+// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
+std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
+ std::tm tm;
+ while (lo + 1 != hi) {
+ const std::time_t mid = lo + (hi - lo) / 2;
+ if (std::tm* tmp = local_time(&mid, &tm)) {
+ if (get_offset_abbr(*tmp).first == offset) {
+ hi = mid;
+ } else {
+ lo = mid;
+ }
+ } else {
+ // If std::tm cannot hold some result we resort to a linear search,
+ // ignoring all failed conversions. Slow, but never really happens.
+ while (++lo != hi) {
+ if (std::tm* tmp = local_time(&lo, &tm)) {
+ if (get_offset_abbr(*tmp).first == offset) break;
+ }
+ }
+ return lo;
+ }
+ }
+ return hi;
+}
+
} // namespace
TimeZoneLibC::TimeZoneLibC(const std::string& name)
@@ -93,59 +164,116 @@
time_zone::absolute_lookup TimeZoneLibC::BreakTime(
const time_point<seconds>& tp) const {
time_zone::absolute_lookup al;
- std::time_t t = ToUnixSeconds(tp);
- std::tm tm;
- if (local_) {
-#if defined(_WIN32) || defined(_WIN64)
- localtime_s(&tm, &t);
-#else
- localtime_r(&t, &tm);
-#endif
- std::tie(al.offset, al.abbr) = get_offset_abbr(tm);
- } else {
-#if defined(_WIN32) || defined(_WIN64)
- gmtime_s(&tm, &t);
-#else
- gmtime_r(&t, &tm);
-#endif
- al.offset = 0;
- al.abbr = "UTC";
+ al.offset = 0;
+ al.is_dst = false;
+ al.abbr = "-00";
+
+ const std::int_fast64_t s = ToUnixSeconds(tp);
+
+ // If std::time_t cannot hold the input we saturate the output.
+ if (s < std::numeric_limits<std::time_t>::min()) {
+ al.cs = civil_second::min();
+ return al;
}
- al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- al.is_dst = tm.tm_isdst > 0;
+ if (s > std::numeric_limits<std::time_t>::max()) {
+ al.cs = civil_second::max();
+ return al;
+ }
+
+ const std::time_t t = static_cast<std::time_t>(s);
+ std::tm tm;
+ std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
+
+ // If std::tm cannot hold the result we saturate the output.
+ if (tmp == nullptr) {
+ al.cs = (s < 0) ? civil_second::min() : civil_second::max();
+ return al;
+ }
+
+ const year_t year = tmp->tm_year + year_t{1900};
+ al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
+ if (!local_) al.abbr = "UTC"; // as expected by cctz
+ al.is_dst = tmp->tm_isdst > 0;
return al;
}
time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
- time_zone::civil_lookup cl;
- std::time_t t;
- if (local_) {
- // Does not handle SKIPPED/AMBIGUOUS or huge years.
- std::tm tm;
- tm.tm_year = static_cast<int>(cs.year() - 1900);
- tm.tm_mon = cs.month() - 1;
- tm.tm_mday = cs.day();
- tm.tm_hour = cs.hour();
- tm.tm_min = cs.minute();
- tm.tm_sec = cs.second();
- tm.tm_isdst = -1;
- t = std::mktime(&tm);
- } else {
- t = cs - civil_second();
+ if (!local_) {
+ // If time_point<seconds> cannot hold the result we saturate.
+ static const civil_second min_tp_cs =
+ civil_second() + ToUnixSeconds(time_point<seconds>::min());
+ static const civil_second max_tp_cs =
+ civil_second() + ToUnixSeconds(time_point<seconds>::max());
+ const time_point<seconds> tp =
+ (cs < min_tp_cs)
+ ? time_point<seconds>::min()
+ : (cs > max_tp_cs) ? time_point<seconds>::max()
+ : FromUnixSeconds(cs - civil_second());
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
- cl.kind = time_zone::civil_lookup::UNIQUE;
- cl.pre = cl.trans = cl.post = FromUnixSeconds(t);
- return cl;
+
+ // If tm_year cannot hold the requested year we saturate the result.
+ if (cs.year() < 0) {
+ if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
+ const time_point<seconds> tp = time_point<seconds>::min();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
+ } else {
+ if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
+ const time_point<seconds> tp = time_point<seconds>::max();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
+ }
+
+ // We probe with "is_dst" values of 0 and 1 to try to distinguish unique
+ // civil seconds from skipped or repeated ones. This is not always possible
+ // however, as the "dst" flag does not change over some offset transitions.
+ // We are also subject to the vagaries of mktime() implementations.
+ std::time_t t0, t1;
+ int offset0, offset1;
+ if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
+ if (t0 == t1) {
+ // The civil time was singular (pre == trans == post).
+ const time_point<seconds> tp = FromUnixSeconds(t0);
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
+
+ if (t0 > t1) {
+ std::swap(t0, t1);
+ std::swap(offset0, offset1);
+ }
+ const std::time_t tt = find_trans(t0, t1, offset1);
+ const time_point<seconds> trans = FromUnixSeconds(tt);
+
+ if (offset0 < offset1) {
+ // The civil time did not exist (pre >= trans > post).
+ const time_point<seconds> pre = FromUnixSeconds(t1);
+ const time_point<seconds> post = FromUnixSeconds(t0);
+ return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
+ }
+
+ // The civil time was ambiguous (pre < trans <= post).
+ const time_point<seconds> pre = FromUnixSeconds(t0);
+ const time_point<seconds> post = FromUnixSeconds(t1);
+ return {time_zone::civil_lookup::REPEATED, pre, trans, post};
+ }
+
+ // make_time() failed somehow so we saturate the result.
+ const time_point<seconds> tp = (cs < civil_second())
+ ? time_point<seconds>::min()
+ : time_point<seconds>::max();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
-bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
-bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h
index 4e40c61..0d18e9a 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.h
+++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index f2d151e..fd04e2d 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,6 +20,11 @@
#include <dlfcn.h>
#endif
#endif
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CFTimeZone.h>
+#endif
+
#include <cstdlib>
#include <cstring>
#include <string>
@@ -121,6 +126,11 @@
char* tz_env = nullptr;
#if defined(_MSC_VER)
_dupenv_s(&tz_env, nullptr, "TZ");
+#elif defined(__APPLE__)
+ CFTimeZoneRef system_time_zone = CFTimeZoneCopyDefault();
+ CFStringRef tz_name = CFTimeZoneGetName(system_time_zone);
+ tz_env = strdup(CFStringGetCStringPtr(tz_name, CFStringGetSystemEncoding()));
+ CFRelease(system_time_zone);
#else
tz_env = std::getenv("TZ");
#endif
@@ -153,6 +163,8 @@
#if defined(_MSC_VER)
free(localtime_env);
free(tz_env);
+#elif defined(__APPLE__)
+ free(tz_env);
#endif
time_zone tz;
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 551292f..8068e2f 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,7 +16,9 @@
#include <chrono>
#include <cstddef>
+#include <cstdlib>
#include <future>
+#include <limits>
#include <string>
#include <thread>
#include <vector>
@@ -335,6 +337,7 @@
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
@@ -664,6 +667,7 @@
} // namespace
+#if !defined(__EMSCRIPTEN__)
TEST(TimeZones, LoadZonesConcurrently) {
std::promise<void> ready_promise;
std::shared_future<void> ready_future(ready_promise.get_future());
@@ -711,6 +715,7 @@
}
EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
}
+#endif
TEST(TimeZone, NamedTimeZones) {
const time_zone utc = utc_time_zone();
@@ -925,7 +930,7 @@
EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second
}
-// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+// NOTE: Run this with -ftrapv to detect overflow problems.
TEST(MakeTime, SysSecondsLimits) {
const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez";
const time_zone utc = utc_time_zone();
@@ -990,6 +995,106 @@
EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), west);
EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+
+ // Some similar checks for the "libc" time-zone implementation.
+ if (sizeof(std::time_t) >= 8) {
+ // Checks that "tm_year + 1900", as used by the "libc" implementation,
+ // can produce year values beyond the range on an int without overflow.
+#if defined(_WIN32) || defined(_WIN64)
+ // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
+#else
+ const time_zone utc = LoadZone("libc:UTC");
+ const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
+ tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), utc);
+ EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, utc));
+ const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
+ tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, utc));
+#endif
+ }
+}
+
+TEST(MakeTime, LocalTimeLibC) {
+ // Checks that cctz and libc agree on transition points in [1970:2037].
+ //
+ // We limit this test case to environments where:
+ // 1) we know how to change the time zone used by localtime()/mktime(),
+ // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
+ // 3) we have some idea about how mktime() behaves during transitions.
+#if defined(__linux__) && !defined(__ANDROID__)
+ const char* const ep = getenv("TZ");
+ std::string tz_name = (ep != nullptr) ? ep : "";
+ for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
+ ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
+ const auto zi = local_time_zone();
+ const auto lc = LoadZone("libc:localtime");
+ time_zone::civil_transition trans;
+ for (auto tp = zi.lookup(civil_second()).trans;
+ zi.next_transition(tp, &trans);
+ tp = zi.lookup(trans.to).trans) {
+ const auto fcl = zi.lookup(trans.from);
+ const auto tcl = zi.lookup(trans.to);
+ civil_second cs; // compare cs in zi and lc
+ if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
+ if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
+ // Both unique; must be an is_dst or abbr change.
+ ASSERT_EQ(trans.from, trans.to);
+ const auto trans = fcl.trans;
+ const auto tal = zi.lookup(trans);
+ const auto tprev = trans - absl::time_internal::cctz::seconds(1);
+ const auto pal = zi.lookup(tprev);
+ if (pal.is_dst == tal.is_dst) {
+ ASSERT_STRNE(pal.abbr, tal.abbr);
+ }
+ continue;
+ }
+ ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
+ cs = trans.to;
+ } else {
+ ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
+ ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
+ cs = trans.from;
+ }
+ if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
+ const auto cl_zi = zi.lookup(cs);
+ if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
+ // The "libc" implementation cannot correctly classify transitions
+ // that don't change the "tm_isdst" flag. In Europe/Volgograd, for
+ // example, there is a SKIPPED transition from +03 to +04 with dst=F
+ // on both sides ...
+ // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
+ // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
+ // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
+ // say, the similar Europe/Chisinau transition from +02 to +03 ...
+ // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
+ // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
+ // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
+ // returns 1521936000.
+ continue;
+ }
+ if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
+ const std::string tzname = *np;
+ if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
+ // The "libc" implementation gets this transition wrong (at least
+ // until 2018g when it was removed), returning an offset of 3600
+ // instead of 0. TODO: Revert this when 2018g is ubiquitous.
+ continue;
+ }
+ }
+ const auto cl_lc = lc.lookup(cs);
+ SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
+ EXPECT_EQ(cl_zi.kind, cl_lc.kind);
+ EXPECT_EQ(cl_zi.pre, cl_lc.pre);
+ EXPECT_EQ(cl_zi.trans, cl_lc.trans);
+ EXPECT_EQ(cl_zi.post, cl_lc.post);
+ }
+ }
+ if (ep == nullptr) {
+ ASSERT_EQ(0, unsetenv("TZ"));
+ } else {
+ ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
+ }
+#endif
}
TEST(NextTransition, UTC) {
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
index 75ad8bc..993901a 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.cc
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h
index 9ccd4a8..6a60022 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.h
+++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -68,25 +68,35 @@
// it would take us to another day, and perhaps week, or even month.
struct PosixTransition {
enum DateFormat { J, N, M };
- struct {
- DateFormat fmt;
- union {
- struct {
- std::int_fast16_t day; // day of non-leap year [1:365]
- } j;
- struct {
- std::int_fast16_t day; // day of year [0:365]
- } n;
- struct {
- std::int_fast8_t month; // month of year [1:12]
- std::int_fast8_t week; // week of month [1:5] (5==last)
- std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
- } m;
+
+ struct Date {
+ struct NonLeapDay {
+ std::int_fast16_t day; // day of non-leap year [1:365]
};
- } date;
- struct {
+ struct Day {
+ std::int_fast16_t day; // day of year [0:365]
+ };
+ struct MonthWeekWeekday {
+ std::int_fast8_t month; // month of year [1:12]
+ std::int_fast8_t week; // week of month [1:5] (5==last)
+ std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
+ };
+
+ DateFormat fmt;
+
+ union {
+ NonLeapDay j;
+ Day n;
+ MonthWeekWeekday m;
+ };
+ };
+
+ struct Time {
std::int_fast32_t offset; // seconds before/after 00:00:00
- } time;
+ };
+
+ Date date;
+ Time time;
};
// The entirety of a POSIX-string specified time-zone rule. The standard
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h
index 90cfc0c..4485ba5 100644
--- a/absl/time/internal/cctz/src/tzfile.h
+++ b/absl/time/internal/cctz/src/tzfile.h
@@ -1,3 +1,5 @@
+/* Layout and location of TZif files. */
+
#ifndef TZFILE_H
#define TZFILE_H
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index bf2d2d2..1324846 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -54,7 +54,7 @@
#pragma comment( \
linker, \
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64)
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
#pragma comment( \
linker, \
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index fe86b5c..63f5800 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2018e-2-g99dd695
+2018i
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
index 8726e80..eaaa818 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
index 2a25f3a..a5867a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
index 8e32be3..82ea5aa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
index ba09750..0272fa1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index 65de344..4c57054 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
index aaa657f..dd75e3e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index f5f8ffb..0ea0253 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
index ddf3652..b8b9270 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
index 9fa7119..83eca03 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
index f2c9e30..549dae2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
index 5b871db..31cfad7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
index ddf3652..b8b9270 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
index ddf3652..b8b9270 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
index b434c67..2a154f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
index bbfe19d..8779590 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
index b1c97cc..cbdc045 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
index a4ece7f..59f3759 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
index b32e220..bd88531 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
index 4bd3885..0cd8ffb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
index f5d40ba..6766185 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
index 5696e0f..4323649 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
index 6c8bdf2..9bbb2fd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
index 8b295a9..bc9a522 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
index e4866ce..dfebfb9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
index 9fe9ad6..b798105 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
index 9fe9ad6..b798105 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
index 8c58f8c..5df3cf6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
index a74ba04..7d2ba91 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
index cb184d6..7654aeb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
index 5e8c44c..1032356 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
index 966a529..3c849fc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
index b19aa22..a4b71c1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
index 9e5ade6..948a390 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
index af8aa99..acfbbe4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
index bbb03a0..085fc9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
index 07e4e9f..1fc3256 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
index d308336..d3b318d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
index 3c61ddb..831bf84 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
index 5708b55..629ed42 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
index 5696e0f..4323649 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
index 6008a57..143eafc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
index 21e2b71..cd53107 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
index 6339936..7bb7ac4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
index b8e13b0..ab3c8a6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
index 7dcc4fc..fd69321 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
index abcde7d..f9f13a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
index f776904..69e17a0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
index d893446..b7ded8e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
index ada6d64..f8d54e2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
index e4866ce..dfebfb9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
index d322f01..f8db4b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
index de52bb6..495ef45 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
index 7e69f73..de6930c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
index c8cab1a..9abd028 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
index 9fe9ad6..b798105 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
index 6db6409..ff59657 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
index 5c1c063..55b0834 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
index 3dd8f0f..a5b1617 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
index e3adbdb..b268724 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
index 5708b55..629ed42 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
index 8c58f8c..5df3cf6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
index c247133..525a67e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
index 798f627..0fba741 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
index 145c89e..8a4ee7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
index d308336..d3b318d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
index ad68c72..9549adc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
index 61c9688..db9cead 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
index 78f9076..db9e339 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
index 7fc6691..5fbe26b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
index e3ea5c3..5e02260 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
index d02fbcd..3fa0579 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
index 41047f2..99b7d06 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
index 9b8bc7a..ac774e8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
index 29c83e7..ada6bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
index 5923cc6..5a0b7f1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
index 4a92c06..09511cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
index 22396bb..e637170 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
index f58522b..48412a4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
index ea293cc..0160308 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
index b4b945e..a3f2990 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
index 4c8ca6f..4597a62 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
index abf943b..6118b5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
index 92de38b..bf087a0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
index 7d29876..d1dd2fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
index f86ece4..756099a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
index 1a58fcd..8186060 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
index ec435c2..26c269d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
index 4a92c06..09511cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
index cc785da..fcd408d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
index a23d7b7..1abf75e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
index f16cb30..0133548 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
index 0250bf9..4ce95c1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
index e934de6..d236b7c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
index adbdbee..c818929 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
index b34f7b2..630935c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
index 4a92c06..09511cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
index 1388e8a..e107dc4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
index 0785ac5..c8138bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
index 7aedd26..162306f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
index a74ba04..7d2ba91 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
index d00668a..451f349 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
index fdf2e88..f4c4cf9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
index 60991aa..438e3ea 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
index cc785da..fcd408d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
index d308336..d3b318d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
index bc3df52..5e5fec5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
index 44280a5..d9fec37 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
index c0ce440..9dad4f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
index fdf2e88..f4c4cf9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
index d308336..d3b318d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
index 54442dc..fec8a8b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
index c543ffd..69256c6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
index 855cb02..b10241e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
index f9e2399..79716de 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
index 5671d25..5c59984 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
index afa94c2..43ee12d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
index 5e8c44c..1032356 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
index 55d6e32..3146138 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
index ecc1856..b46298e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
index c033597..85a7e16 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
index f11e3d2..1434ab0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
index 75bbcf2..06ceaad 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
index 51cb1ba..9df8d0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
index dcac92b..7dc5057 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
index f524fd2..0d1e565 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
index 7b4682a..6752c5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
index e5d0289..5091eb5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
index 7553fee..2f75480 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
index f8a0292..f6a856e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
index c886c9b..10998df 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
index 6d91f91..95ff8a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
index 8174c88..246345d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
index 8035b24..1fa0703 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
index 5b630ee..123f2ae 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
index 190c5c8..37d7830 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
index 5c1c063..55b0834 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
index df78b62..3e4e0db 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
index 1b608b3..b95c784 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
index adf2823..4d51271 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
index 7306cae..d959010 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
index b612ac2..16b7f92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
index 2423fc1..10cb02b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
index d4525a6..a662a57 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
index 4d84eed..a5a8af5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
index 70dcd2d..ea66099 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
index 9f50f36..61ff6fc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
index fe55739..c6d99b3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
index 5fe8d6b..20c9c84 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
index 884b1f6..4365a5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
index b612ac2..16b7f92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
index 8c58f8c..5df3cf6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
index 29c83e7..ada6bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
index d776a43..8080efa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
index ab766a4..816a042 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
index cc2cbf2..4e5eba5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
index 308a545..c417ba1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
index 8e1366c..e20e9e1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
index 7fc6691..5fbe26b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
index 662b8b6..31f7061 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
index a1d1485..65a5b0c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
index 4db1300..8e9ef25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
index 7aea8f9..477e939 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
index deefcc8..2969ebe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
index aa1d486..e504c9a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
index 29c83e7..ada6bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
index 7b4682a..6752c5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
index 9b5d924..0f9f832 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
index 447efbe..bdedd1b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
index 6b62e2d..fb3cd71 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
index 2ffe3d8..3718d47 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
index 523b0a1..da209f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
index d9d6eff..e6afa39 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
index d0bbacc..f100f47 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
index 40a9926..916f2c2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
index 0686353..bd6563e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
index aea2be7..83c308a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
index 5197dd9..e1f0b09 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
index a5f5b6d..60bcef6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
index 43a01d3..3dd85f8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
index 56913f8..7940e6e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
index a5f5b6d..60bcef6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
index 94a9d5a..4bb041a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
index 3757fac..5e565da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
index 9fa335c..5696abf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
index 239c017..c6842af 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
index e71bc4e..b2f9a25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
index 49a4b4d..d93201c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
index c3f0994..281b304 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
index 0e623cf..6a96601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
index 5803a3d..78cbcf0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
index 808a502..7504052 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
index 046c472..8d9e03c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
index 046c472..8d9e03c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
index 27072eb..317466d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
index 3aacd78..97fa6c7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
index a0c5f66..f514092 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
index a17d1ad..8a090d7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
index 8db5e8a..7249640 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
index 60efb41..82cc49c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
index 72f0896..efb24c2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
index e3f81ee..f7a7d54 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
index cad16b0..8624c7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
index b57972d..e1cfcb8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
index 95f5645..3baf752 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
index 15b358f..79b9d3c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
index dbd132f..ce9e00a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
index dbd132f..ce9e00a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
index 28fe430..4fc96c8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
index 98881f0..776f27d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
index ac45764..4b610b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
index 98881f0..776f27d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
index c94fa61..f6ce91a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
index c12f31a..7880d5d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
index 67c772b..694f6e6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
index 021f8a2..653b146 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
index 60d0de0..cf54deb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
index dbd132f..ce9e00a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
index a2e1b36..09c876a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
index 9264267..eab94fe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
index dc9058e..91eaff4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
index f367a55..8eb5f64 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
index 8413636..e8c53c0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
index 9a53b3a..833d4eb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
index 37b4edd..673d480 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
index 39ddc84..a4c0829 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
index df51199..2d14c99 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
index 80429ec..a22cf59 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
index fab27de..b9ed49c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
index b7dcaab..337e1d5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
index b44a1e1..0342b43 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
index 0cbd295..2f810b1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
index 0cbd295..2f810b1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
index 9183695..2b2f5bf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
index b57972d..e1cfcb8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
index faec35d..59efd24 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
index 5c95ebc..6d7d47b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
index 62b5389..4878622 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
index e71bc4e..b2f9a25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
index 2c20a32..d801000 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
index 2c20a32..d801000 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
index 2db0635..b20cc57 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
index 3a5dcb2..ed55442 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
index 06859a7..2c9220c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
index c12f31a..7880d5d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
index 3e663b2..f7f10ab 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
index ed4b248..2576a3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
index a5d39df..95e3c73 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
index 5e0d9b6..d805e4f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
index b8eb58d..e36aec4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
index 8db5e8a..7249640 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
index ec98c62..9377d03 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
index dc24926..dd54989 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
index a0c5f66..f514092 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
new file mode 100644
index 0000000..cb6e2d9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
index 0fc7fad..fc636b3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
index 3cc2aaf..a00282d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
index e71bc4e..b2f9a25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
index 9264267..eab94fe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
index 8d6b4df..9c94900 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
index 10c7af7..a5d1e97 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
index 312ec40..fa1cbd3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
index dbd132f..ce9e00a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
index 7858366..ebc4b0d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
index 16b1cd8..f8b7bb2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
index 748873b..f9cbe67 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
index 6f7dea4..e75bb36 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
index 4b2d2e2..09bb06e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
index 3157f80..0ae2f65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
index df51199..2d14c99 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
index a8bddb9..06d3324 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
index a8bddb9..06d3324 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
index 8ad44ba..26f4d34 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
index 919b003..28da9c9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
index 3a5dcb2..ed55442 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
index 94ddfea..82fd476 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
index 94ddfea..82fd476 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
index b44a1e1..0342b43 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
index 7431eb9..c0c3767 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
index 8db5e8a..7249640 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
index 80b170b..15731ab 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
index 220ad3d..1f86e77 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
index 3cc2aaf..a00282d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
index c1abb93..fff9f3b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
index 4c4e045..409c3b1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
index 1895e1b..56593db 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
index 548d979..3a5c6db 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
index 544f443..f319215 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
index 6bda6db..e2a49d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
index c486518..4dab7ef 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
index c486518..4dab7ef 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
index 239c017..c6842af 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
index e25f8a5..5213761 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
index dc49c32..ac6bd69 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
index 56b383b..b3311b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
index 6fd1af3..65d19ec 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
index 3649415..2fd42a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
index aaed12c..4ed4467 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
index 4f331a8..190b0e3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
index a327d83..26ffd9a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
index 768b167..874c865 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
index aaed12c..4ed4467 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
index a3f6f29..865801e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
index c6ae9a7..cf42d1d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
index 99f07a9..c49d499 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
index 07784ce..92d1215 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
index 57597b0..8c6c7dd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
index 71ca143..8ee1a6f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
index 57597b0..8c6c7dd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
index ec8dfe0..3f2d3d7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
index aaed12c..4ed4467 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
index c6ae9a7..cf42d1d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
index 85c26d5..d38b67e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
index a327d83..26ffd9a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
index 4f331a8..190b0e3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
index aaed12c..4ed4467 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
index 07784ce..92d1215 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
index ec8dfe0..3f2d3d7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
index 85c26d5..d38b67e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
index 768b167..874c865 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
index b612ac2..16b7f92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
index 6d91f91..95ff8a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
index 308a545..c417ba1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
index 855cb02..b10241e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET
index 4c4f8ef..d585656 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
index 5c8a1d9..41c4136 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
index f86ece4..756099a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
index 2ffe3d8..3718d47 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
index 7b4682a..6752c5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
index d02fbcd..3fa0579 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
index a1d1485..65a5b0c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
index 9b5d924..0f9f832 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
index 5fe8d6b..20c9c84 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
index 6b62e2d..fb3cd71 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
index ab766a4..816a042 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
index 060bef8..cae3744 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
index 1a58fcd..8186060 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Cuba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET
index beb273a..d2f54c9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST b/absl/time/internal/cctz/testdata/zoneinfo/EST
index ae34663..074a4fc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
index 54541fc..087b641 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
index ba09750..0272fa1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Egypt
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Eire b/absl/time/internal/cctz/testdata/zoneinfo/Eire
index 655daf3..5c5a7a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
index 082986e..087d1f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
index 23276cd..6437c68 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
index 28c579d..72a912e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
index c740603..6938a1a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
index 721cde2..a315577 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
index ae06bcb..ee77619 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
index 5a7f878..1ea7da2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
index 18cbf1f..dda1a9e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
index 1aa4be8..f4a0385 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
index cd8ed49..2d2ccd0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
index e0ba6b8..826c770 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
index eee1bcb..b125ad2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
index 4ff8701..dde682d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
index e12e461..352ec08 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
index 37f2739..dfa27fe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
index 09297f1..eef949d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
index 97ae1e1..f9363b2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
index 58d6d1b..35add05 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
index f0dc706..315cae4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
index a0790fe..7489a15 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
index a75a173..560243e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
index 85ebf22..b2bbe97 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
index 95def1f..b979dbb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
index c6a776e..365ab1f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
index f74a16f..742082f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
index 9b647c0..abc0b27 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
index 40147b9..a88c4b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
index 6dae5e4..ed064ed 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
index b06de7a..5962550 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
index 90d7c2a..5e069ea 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
index 0001602..9f3a067 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
index b4f2a2a..7ddd510 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
index ba82f31..85036de 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
index d8f19a6..d0d0a08 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
index e0eac4c..4eb7ed0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
index 3ddf6a5..dfdc6d2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
index 9c2b600..ad6cf59 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
index 2109b52..5bc1bfe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
index be87cf1..cb2ec06 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
index 655daf3..5c5a7a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
index a7105fa..117aadb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
index 29b3c81..b4f8f9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
index 9a53b3a..833d4eb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
index 37280d0..982d82a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
index b3e20a7..9337c9e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
index 40b558f..a3b5320 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
index a856530..355817b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
index 6fae86c..6c194a5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
index 9b51a73..ccc9d85 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
index c1208e2..bf2452d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
index 29b3c81..b4f8f9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
index 60041a4..801aead 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
index 0b40f1e..686ae88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
index 906bd05..ddb3f4e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
index 3e663b2..f7f10ab 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
index 239c017..c6842af 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
index cf6e2e2..ca85435 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
index ba82f31..85036de 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
index b729ee8..8495c50 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
index bdd3449..78a131b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
index 0539acf..97d5dd9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
index bdd3449..78a131b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
index e8cd6b1..8fd5f6d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
index f3b42b0..e82dbbc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
index 763e074..dcfdd08 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
index 43c7f2e..f3e0c7f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
index 18f903f..3a744cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
index 52c16a4..0b86017 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
index 2109b52..5bc1bfe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
index c280f43..7b61bdc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
index 8ddba90..677f088 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
index 9c2b600..ad6cf59 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
index bdd3449..78a131b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
index 9c0fac5..9e2d0c9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
index da380af..46ce484 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
index f4cb64f..8f170dd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
index 5cbba41..d6bb156 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
index 79c25d7..32a5722 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
index 6f14850..e42edfc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
index 9c2b600..ad6cf59 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Factory b/absl/time/internal/cctz/testdata/zoneinfo/Factory
index afeeb88..95bc3a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Factory
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Factory
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB b/absl/time/internal/cctz/testdata/zoneinfo/GB
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
index 4527515..a340326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT b/absl/time/internal/cctz/testdata/zoneinfo/GMT
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
index c05e45f..2ee1429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST
index 03e4db0..616c31b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/HST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/HST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
index dc9058e..91eaff4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
index dc49c32..ac6bd69 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iceland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
index 0e5e719..f609611 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
index 066c1e9..6babdee 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
index 34a2457..58f8051 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
index e7d4d3d..2cb6f3e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
index db8ac68..49e23e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
index 3f1a76e..ffa3365 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
index fd8d911..b23e2ce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
index 39631f2..6e19601 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
index d5f9aa4..11c6002 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran
index 3157f80..0ae2f65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel
index df51199..2d14c99 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Israel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
index 7aedd26..162306f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Japan b/absl/time/internal/cctz/testdata/zoneinfo/Japan
index 8ad44ba..26f4d34 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Japan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Japan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
index 1a27122..d641357 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Libya b/absl/time/internal/cctz/testdata/zoneinfo/Libya
index b32e220..bd88531 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Libya
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Libya
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET
index 71963d5..388dd74 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST b/absl/time/internal/cctz/testdata/zoneinfo/MST
index a1bee7c..da3e926 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
index 726a7e5..ddca8d1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
index 29c83e7..ada6bf7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
index afa94c2..43ee12d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
index f11e3d2..1434ab0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
index a5f5b6d..60bcef6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
index 957c80b..abe09cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
index 7fc6691..5fbe26b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Navajo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC
index dbd132f..ce9e00a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PRC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
index 6242ac0..d773e28 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
index 4091a85..fd03ff7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
index a5f5b6d..60bcef6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
index dc5a7d7..6a6c2da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
index 957c80b..abe09cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
index 289b795..8004d65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
index 060bef8..cae3744 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
index 5cee55d..d650a05 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
index a3f30e5..8087350 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
index 6e4b8af..4fa169f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
index 912db18..61a6695 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
index 3289094..e6a1544 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
index 76b2b3a..859b76d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
index 625016d..4e9e36c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
index 0c24095..908ccc1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
index 4286e6b..e224247 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
index bd85577..c7cd060 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
index bd85577..c7cd060 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
index 762275d..cf5b3bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
index f8222e6..11583b1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
index 1a27122..d641357 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
index b3a8c18..65990cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
index 10c5c9b..5fad0e1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
index 3e38e97..72707b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
index 6092119..86d3b7d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
index df6110d..1d58fe3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
index d0b9607..f630a65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
index d9c68f8..99f6bca 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
index 3e38e97..72707b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
index e1bbea5..05633b8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
index 54783cf..9092e48 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
index 9743bc3..090429c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
index 9743bc3..090429c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
index 3fa1f7f..f6fd51c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
index ace1ce4..9708b87 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
index 4286e6b..e224247 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
index 3e38e97..72707b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
index 7867d8b..37e4e88 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
index 3340413..e23c0cd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
index b3a5a89..35c9e2c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
index 289b795..8004d65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
index 2dc630c..837ce1f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
index b4f0f9b..8be9ac4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
index 289b795..8004d65 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Poland b/absl/time/internal/cctz/testdata/zoneinfo/Poland
index 5cbba41..d6bb156 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Poland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Poland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
index a856530..355817b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Portugal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROC b/absl/time/internal/cctz/testdata/zoneinfo/ROC
index 748873b..f9cbe67 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROK b/absl/time/internal/cctz/testdata/zoneinfo/ROK
index 312ec40..fa1cbd3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROK
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROK
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
index 7858366..ebc4b0d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
index 9a53b3a..833d4eb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Turkey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT
index 40147b9..a88c4b6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
index 6c8bdf2..9bbb2fd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
index 5696e0f..4323649 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
index adf2823..4d51271 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
index 3dd8f0f..a5b1617 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Central
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
index 4a92c06..09511cc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
index 7553fee..2f75480 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
index bd85577..c7cd060 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
index cc785da..fcd408d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
index e3ea5c3..5e02260 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
index 7fc6691..5fbe26b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
index c0ce440..9dad4f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
index 3e38e97..72707b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UTC b/absl/time/internal/cctz/testdata/zoneinfo/UTC
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Universal
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
index 906bd05..ddb3f4e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/W-SU
+++ b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET
index 444a193..9b03a17 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/WET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/WET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
index c3b97f1..5583f5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
index c2e0f8e..4e4a5c3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -10,7 +10,7 @@
#
# 1. ISO 3166-1 alpha-2 country code, current as of
# ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1
-# http://isotc.iso.org/livelink/livelink/Open/16944257
+# https://isotc.iso.org/livelink/livelink/Open/16944257
# 2. The usual English name for the coded region,
# chosen so that alphabetic sorting of subsets produces helpful lists.
# This is not the same as the English name in the ISO 3166 tables.
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 2d90ed7..9a8e424 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -1,35 +1,35 @@
-# tz zone descriptions
+# tzdb timezone descriptions
#
# This file is in the public domain.
#
-# From Paul Eggert (2017-10-01):
-# This file contains a table where each row stands for a zone where
-# civil time stamps have agreed since 1970. Columns are separated by
+# From Paul Eggert (2018-06-27):
+# This file contains a table where each row stands for a timezone where
+# civil timestamps have agreed since 1970. Columns are separated by
# a single tab. Lines beginning with '#' are comments. All text uses
# UTF-8 encoding. The columns of the table are as follows:
#
-# 1. The countries that overlap the zone, as a comma-separated list
+# 1. The countries that overlap the timezone, as a comma-separated list
# of ISO 3166 2-character country codes. See the file 'iso3166.tab'.
-# 2. Latitude and longitude of the zone's principal location
+# 2. Latitude and longitude of the timezone's principal location
# in ISO 6709 sign-degrees-minutes-seconds format,
# either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS,
# first latitude (+ is north), then longitude (+ is east).
-# 3. Zone name used in value of TZ environment variable.
-# Please see the theory.html file for how zone names are chosen.
-# If multiple zones overlap a country, each has a row in the
+# 3. Timezone name used in value of TZ environment variable.
+# Please see the theory.html file for how these names are chosen.
+# If multiple timezones overlap a country, each has a row in the
# table, with each column 1 containing the country code.
-# 4. Comments; present if and only if a country has multiple zones.
+# 4. Comments; present if and only if a country has multiple timezones.
#
-# If a zone covers multiple countries, the most-populous city is used,
+# If a timezone covers multiple countries, the most-populous city is used,
# and that country is listed first in column 1; any other countries
# are listed alphabetically by country code. The table is sorted
# first by country code, then (if possible) by an order within the
# country that (1) makes some geographical sense, and (2) puts the
-# most populous zones first, where that does not contradict (1).
+# most populous timezones first, where that does not contradict (1).
#
-# This table is intended as an aid for users, to help them select time
-# zone data entries appropriate for their practical needs. It is not
-# intended to take or endorse any position on legal or territorial claims.
+# This table is intended as an aid for users, to help them select timezones
+# appropriate for their practical needs. It is not intended to take or
+# endorse any position on legal or territorial claims.
#
#country-
#codes coordinates TZ comments
@@ -211,6 +211,7 @@
KR +3733+12658 Asia/Seoul
KZ +4315+07657 Asia/Almaty Kazakhstan (most areas)
KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda
+KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay
KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe
KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau
KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev
@@ -231,7 +232,7 @@
MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas)
MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan
MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar
-MO +2214+11335 Asia/Macau
+MO +221150+1133230 Asia/Macau
MQ +1436-06105 America/Martinique
MT +3554+01431 Europe/Malta
MU -2010+05730 Indian/Mauritius
@@ -289,9 +290,9 @@
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
RU +4457+03406 Europe/Simferopol MSK+00 - Crimea
-RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd
RU +5836+04939 Europe/Kirov MSK+00 - Kirov
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
+RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd
RU +5134+04602 Europe/Saratov MSK+01 - Saratov
RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
diff --git a/absl/time/internal/get_current_time_chrono.inc b/absl/time/internal/get_current_time_chrono.inc
index cf884a1..5180230 100644
--- a/absl/time/internal/get_current_time_chrono.inc
+++ b/absl/time/internal/get_current_time_chrono.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
index bbbef7d..59166a7 100644
--- a/absl/time/internal/test_util.cc
+++ b/absl/time/internal/test_util.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -26,12 +26,6 @@
namespace absl {
namespace time_internal {
-#if GTEST_USES_SIMPLE_RE
-extern const char kZoneAbbrRE[] = ".*"; // just punt
-#else
-extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
-#endif
-
TimeZone LoadTimeZone(const std::string& name) {
TimeZone tz;
ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
diff --git a/absl/time/internal/test_util.h b/absl/time/internal/test_util.h
index 8fd5fb9..d7319ea 100644
--- a/absl/time/internal/test_util.h
+++ b/absl/time/internal/test_util.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,35 +17,11 @@
#include <string>
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
#include "absl/time/time.h"
-// This helper is a macro so that failed expectations show up with the
-// correct line numbers.
-//
-// This is for internal testing of the Base Time library itself. This is not
-// part of a public API.
-#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \
- do { \
- EXPECT_EQ(y, bd.year); \
- EXPECT_EQ(m, bd.month); \
- EXPECT_EQ(d, bd.day); \
- EXPECT_EQ(h, bd.hour); \
- EXPECT_EQ(min, bd.minute); \
- EXPECT_EQ(s, bd.second); \
- EXPECT_EQ(off, bd.offset); \
- EXPECT_EQ(isdst, bd.is_dst); \
- EXPECT_THAT(bd.zone_abbr, \
- testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \
- } while (0)
-
namespace absl {
namespace time_internal {
-// A regular expression that matches all zone abbreviations (%Z).
-extern const char kZoneAbbrRE[];
-
// Loads the named timezone, but dies on any failure.
absl::TimeZone LoadTimeZone(const std::string& name);
diff --git a/absl/time/time.cc b/absl/time/time.cc
index 71fd8ee..977a951 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,13 +22,14 @@
// NOTE: To keep type verbosity to a minimum, the following variable naming
// conventions are used throughout this file.
//
-// cz: A cctz::time_zone
// tz: An absl::TimeZone
+// ci: An absl::TimeZone::CivilInfo
+// ti: An absl::TimeZone::TimeInfo
+// cd: An absl::CivilDay or a cctz::civil_day
+// cs: An absl::CivilSecond or a cctz::civil_second
+// bd: An absl::Time::Breakdown
// cl: A cctz::time_zone::civil_lookup
// al: A cctz::time_zone::absolute_lookup
-// cd: A cctz::civil_day
-// cs: A cctz::civil_second
-// bd: An absl::Time::Breakdown
#include "absl/time/time.h"
@@ -40,6 +41,7 @@
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace cctz = absl::time_internal::cctz;
+
namespace absl {
namespace {
@@ -75,7 +77,7 @@
return bd;
}
-inline Time::Breakdown InfinitePastBreakdown() {
+inline absl::Time::Breakdown InfinitePastBreakdown() {
Time::Breakdown bd;
bd.year = std::numeric_limits<int64_t>::min();
bd.month = 1;
@@ -92,6 +94,26 @@
return bd;
}
+inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
+ TimeZone::CivilInfo ci;
+ ci.cs = CivilSecond::max();
+ ci.subsecond = InfiniteDuration();
+ ci.offset = 0;
+ ci.is_dst = false;
+ ci.zone_abbr = "-00";
+ return ci;
+}
+
+inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
+ TimeZone::CivilInfo ci;
+ ci.cs = CivilSecond::min();
+ ci.subsecond = -InfiniteDuration();
+ ci.offset = 0;
+ ci.is_dst = false;
+ ci.zone_abbr = "-00";
+ return ci;
+}
+
inline absl::TimeConversion InfiniteFutureTimeConversion() {
absl::TimeConversion tc;
tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
@@ -134,19 +156,6 @@
return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
}
-inline absl::TimeConversion::Kind MapKind(
- const cctz::time_zone::civil_lookup::civil_kind& kind) {
- switch (kind) {
- case cctz::time_zone::civil_lookup::UNIQUE:
- return absl::TimeConversion::UNIQUE;
- case cctz::time_zone::civil_lookup::SKIPPED:
- return absl::TimeConversion::SKIPPED;
- case cctz::time_zone::civil_lookup::REPEATED:
- return absl::TimeConversion::REPEATED;
- }
- return absl::TimeConversion::UNIQUE;
-}
-
// Returns Mon=1..Sun=7.
inline int MapWeekday(const cctz::weekday& wd) {
switch (wd) {
@@ -168,11 +177,29 @@
return 1;
}
+bool FindTransition(const cctz::time_zone& tz,
+ bool (cctz::time_zone::*find_transition)(
+ const cctz::time_point<cctz::seconds>& tp,
+ cctz::time_zone::civil_transition* trans) const,
+ Time t, TimeZone::CivilTransition* trans) {
+ // Transitions are second-aligned, so we can discard any fractional part.
+ const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
+ cctz::time_zone::civil_transition tr;
+ if (!(tz.*find_transition)(tp, &tr)) return false;
+ trans->from = CivilSecond(tr.from);
+ trans->to = CivilSecond(tr.to);
+ return true;
+}
+
} // namespace
+//
+// Time
+//
+
absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
- if (*this == absl::InfiniteFuture()) return absl::InfiniteFutureBreakdown();
- if (*this == absl::InfinitePast()) return absl::InfinitePastBreakdown();
+ if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
+ if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
const auto al = cctz::time_zone(tz).lookup(tp);
@@ -187,92 +214,18 @@
bd.minute = cs.minute();
bd.second = cs.second();
bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
- bd.weekday = MapWeekday(get_weekday(cd));
- bd.yearday = get_yearday(cd);
+ bd.weekday = MapWeekday(cctz::get_weekday(cd));
+ bd.yearday = cctz::get_yearday(cd);
bd.offset = al.offset;
bd.is_dst = al.is_dst;
bd.zone_abbr = al.abbr;
return bd;
}
-absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
- const auto cz = cctz::time_zone(tz);
- const auto cs =
- cctz::civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- const auto cl = cz.lookup(cs);
- const auto tp = tm.tm_isdst == 0 ? cl.post : cl.pre;
- return MakeTimeWithOverflow(tp, cs, cz);
-}
-
-struct tm ToTM(absl::Time t, absl::TimeZone tz) {
- const absl::Time::Breakdown bd = t.In(tz);
- struct tm tm;
- std::memset(&tm, 0, sizeof(tm));
- tm.tm_sec = bd.second;
- tm.tm_min = bd.minute;
- tm.tm_hour = bd.hour;
- tm.tm_mday = bd.day;
- tm.tm_mon = bd.month - 1;
-
- // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
- // that tm.tm_year is years since 1900.
- if (bd.year < std::numeric_limits<int>::min() + 1900) {
- tm.tm_year = std::numeric_limits<int>::min();
- } else if (bd.year > std::numeric_limits<int>::max()) {
- tm.tm_year = std::numeric_limits<int>::max() - 1900;
- } else {
- tm.tm_year = static_cast<int>(bd.year - 1900);
- }
-
- tm.tm_wday = bd.weekday % 7;
- tm.tm_yday = bd.yearday - 1;
- tm.tm_isdst = bd.is_dst ? 1 : 0;
-
- return tm;
-}
-
//
-// Factory functions.
+// Conversions from/to other time types.
//
-absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
- int min, int sec, TimeZone tz) {
- // Avoids years that are too extreme for civil_second to normalize.
- if (year > 300000000000) return InfiniteFutureTimeConversion();
- if (year < -300000000000) return InfinitePastTimeConversion();
- const auto cz = cctz::time_zone(tz);
- const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
- absl::TimeConversion tc;
- tc.normalized = year != cs.year() || mon != cs.month() || day != cs.day() ||
- hour != cs.hour() || min != cs.minute() || sec != cs.second();
- const auto cl = cz.lookup(cs);
- // Converts the civil_lookup struct to a TimeConversion.
- tc.pre = MakeTimeWithOverflow(cl.pre, cs, cz, &tc.normalized);
- tc.trans = MakeTimeWithOverflow(cl.trans, cs, cz, &tc.normalized);
- tc.post = MakeTimeWithOverflow(cl.post, cs, cz, &tc.normalized);
- tc.kind = MapKind(cl.kind);
- return tc;
-}
-
-absl::Time FromDateTime(int64_t year, int mon, int day, int hour, int min,
- int sec, TimeZone tz) {
- if (year > 300000000000) return InfiniteFuture();
- if (year < -300000000000) return InfinitePast();
- const auto cz = cctz::time_zone(tz);
- const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
- const auto cl = cz.lookup(cs);
- return MakeTimeWithOverflow(cl.pre, cs, cz);
-}
-
-absl::Time TimeFromTimespec(timespec ts) {
- return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
-}
-
-absl::Time TimeFromTimeval(timeval tv) {
- return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
-}
-
absl::Time FromUDate(double udate) {
return time_internal::FromUnixDuration(absl::Milliseconds(udate));
}
@@ -281,10 +234,6 @@
return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
}
-//
-// Conversion to other time types.
-//
-
int64_t ToUnixNanos(Time t) {
if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
@@ -321,6 +270,23 @@
time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
+double ToUDate(Time t) {
+ return absl::FDivDuration(time_internal::ToUnixDuration(t),
+ absl::Milliseconds(1));
+}
+
+int64_t ToUniversal(absl::Time t) {
+ return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
+}
+
+absl::Time TimeFromTimespec(timespec ts) {
+ return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
+}
+
+absl::Time TimeFromTimeval(timeval tv) {
+ return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
+}
+
timespec ToTimespec(Time t) {
timespec ts;
absl::Duration d = time_internal::ToUnixDuration(t);
@@ -359,15 +325,6 @@
return tv;
}
-double ToUDate(Time t) {
- return absl::FDivDuration(time_internal::ToUnixDuration(t),
- absl::Milliseconds(1));
-}
-
-int64_t ToUniversal(absl::Time t) {
- return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
-}
-
Time FromChrono(const std::chrono::system_clock::time_point& tp) {
return time_internal::FromUnixDuration(time_internal::FromChrono(
tp - std::chrono::system_clock::from_time_t(0)));
@@ -381,4 +338,149 @@
time_internal::ToChronoDuration<D>(d);
}
+//
+// TimeZone
+//
+
+absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
+ if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
+ if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
+
+ const auto ud = time_internal::ToUnixDuration(t);
+ const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
+ const auto al = cz_.lookup(tp);
+
+ TimeZone::CivilInfo ci;
+ ci.cs = CivilSecond(al.cs);
+ ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
+ ci.offset = al.offset;
+ ci.is_dst = al.is_dst;
+ ci.zone_abbr = al.abbr;
+ return ci;
+}
+
+absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
+ const cctz::civil_second cs(ct);
+ const auto cl = cz_.lookup(cs);
+
+ TimeZone::TimeInfo ti;
+ switch (cl.kind) {
+ case cctz::time_zone::civil_lookup::UNIQUE:
+ ti.kind = TimeZone::TimeInfo::UNIQUE;
+ break;
+ case cctz::time_zone::civil_lookup::SKIPPED:
+ ti.kind = TimeZone::TimeInfo::SKIPPED;
+ break;
+ case cctz::time_zone::civil_lookup::REPEATED:
+ ti.kind = TimeZone::TimeInfo::REPEATED;
+ break;
+ }
+ ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
+ ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
+ ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
+ return ti;
+}
+
+bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
+ return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
+}
+
+bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
+ return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
+}
+
+//
+// Conversions involving time zones.
+//
+
+absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+ int min, int sec, TimeZone tz) {
+ // Avoids years that are too extreme for CivilSecond to normalize.
+ if (year > 300000000000) return InfiniteFutureTimeConversion();
+ if (year < -300000000000) return InfinitePastTimeConversion();
+
+ const CivilSecond cs(year, mon, day, hour, min, sec);
+ const auto ti = tz.At(cs);
+
+ TimeConversion tc;
+ tc.pre = ti.pre;
+ tc.trans = ti.trans;
+ tc.post = ti.post;
+ switch (ti.kind) {
+ case TimeZone::TimeInfo::UNIQUE:
+ tc.kind = TimeConversion::UNIQUE;
+ break;
+ case TimeZone::TimeInfo::SKIPPED:
+ tc.kind = TimeConversion::SKIPPED;
+ break;
+ case TimeZone::TimeInfo::REPEATED:
+ tc.kind = TimeConversion::REPEATED;
+ break;
+ }
+ tc.normalized = false;
+ if (year != cs.year() || mon != cs.month() || day != cs.day() ||
+ hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
+ tc.normalized = true;
+ }
+ return tc;
+}
+
+absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
+ const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ const auto ti = tz.At(cs);
+ return tm.tm_isdst == 0 ? ti.post : ti.pre;
+}
+
+struct tm ToTM(absl::Time t, absl::TimeZone tz) {
+ struct tm tm = {};
+
+ const auto ci = tz.At(t);
+ const auto& cs = ci.cs;
+ tm.tm_sec = cs.second();
+ tm.tm_min = cs.minute();
+ tm.tm_hour = cs.hour();
+ tm.tm_mday = cs.day();
+ tm.tm_mon = cs.month() - 1;
+
+ // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
+ // that tm.tm_year is years since 1900.
+ if (cs.year() < std::numeric_limits<int>::min() + 1900) {
+ tm.tm_year = std::numeric_limits<int>::min();
+ } else if (cs.year() > std::numeric_limits<int>::max()) {
+ tm.tm_year = std::numeric_limits<int>::max() - 1900;
+ } else {
+ tm.tm_year = static_cast<int>(cs.year() - 1900);
+ }
+
+ const CivilDay cd(cs);
+ switch (GetWeekday(cd)) {
+ case Weekday::sunday:
+ tm.tm_wday = 0;
+ break;
+ case Weekday::monday:
+ tm.tm_wday = 1;
+ break;
+ case Weekday::tuesday:
+ tm.tm_wday = 2;
+ break;
+ case Weekday::wednesday:
+ tm.tm_wday = 3;
+ break;
+ case Weekday::thursday:
+ tm.tm_wday = 4;
+ break;
+ case Weekday::friday:
+ tm.tm_wday = 5;
+ break;
+ case Weekday::saturday:
+ tm.tm_wday = 6;
+ break;
+ }
+ tm.tm_yday = GetYearDay(cd) - 1;
+ tm.tm_isdst = ci.is_dst ? 1 : 0;
+
+ return tm;
+}
+
} // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h
index 50bf971..594396c 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,18 +25,29 @@
// * `absl::TimeZone` defines geopolitical time zone regions (as collected
// within the IANA Time Zone database (https://www.iana.org/time-zones)).
//
+// Note: Absolute times are distinct from civil times, which refer to the
+// human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping
+// between absolute and civil times can be specified by use of time zones
+// (`absl::TimeZone` within this API). That is:
+//
+// Civil Time = F(Absolute Time, Time Zone)
+// Absolute Time = G(Civil Time, Time Zone)
+//
+// See civil_time.h for abstractions related to constructing and manipulating
+// civil time.
//
// Example:
//
// absl::TimeZone nyc;
-//
// // LoadTimeZone() may fail so it's always better to check for success.
// if (!absl::LoadTimeZone("America/New_York", &nyc)) {
// // handle error case
// }
//
// // My flight leaves NYC on Jan 2, 2017 at 03:04:05
-// absl::Time takeoff = absl::FromDateTime(2017, 1, 2, 3, 4, 5, nyc);
+// absl::CivilSecond cs(2017, 1, 2, 3, 4, 5);
+// absl::Time takeoff = absl::FromCivil(cs, nyc);
+//
// absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35);
// absl::Time landing = takeoff + flight_duration;
//
@@ -47,7 +58,7 @@
// std::string s = absl::FormatTime(
// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
// landing, syd);
-//
+
#ifndef ABSL_TIME_TIME_H_
#define ABSL_TIME_TIME_H_
@@ -57,6 +68,7 @@
#include <winsock2.h>
#endif
#include <chrono> // NOLINT(build/c++11)
+#include <cmath>
#include <cstdint>
#include <ctime>
#include <ostream>
@@ -64,8 +76,8 @@
#include <type_traits>
#include <utility>
-#include "absl/base/port.h" // Needed for string vs std::string
#include "absl/strings/string_view.h"
+#include "absl/time/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
@@ -140,6 +152,16 @@
// Value semantics.
constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration
+ // Copyable.
+#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1910
+ // Explicitly defining the constexpr copy constructor avoids an MSVC bug.
+ constexpr Duration(const Duration& d)
+ : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {}
+#else
+ constexpr Duration(const Duration& d) = default;
+#endif
+ Duration& operator=(const Duration& d) = default;
+
// Compound assignment operators.
Duration& operator+=(Duration d);
Duration& operator-=(Duration d);
@@ -348,11 +370,11 @@
// Factory functions for constructing `Duration` values from an integral number
// of the unit indicated by the factory function's name.
//
-// Note: no "Days()" factory function exists because "a day" is ambiguous. Civil
-// days are not always 24 hours long, and a 24-hour duration often does not
-// correspond with a civil day. If a 24-hour duration is needed, use
-// `absl::Hours(24)`.
-//
+// Note: no "Days()" factory function exists because "a day" is ambiguous.
+// Civil days are not always 24 hours long, and a 24-hour duration often does
+// not correspond with a civil day. If a 24-hour duration is needed, use
+// `absl::Hours(24)`. (If you actually want a civil day, use absl::CivilDay
+// from civil_time.h.)
//
// Example:
//
@@ -371,6 +393,7 @@
// factories, which should be preferred.
//
// Example:
+//
// auto a = absl::Seconds(1.5); // OK
// auto b = absl::Milliseconds(1500); // BETTER
template <typename T, time_internal::EnableIfFloat<T> = 0>
@@ -387,11 +410,13 @@
}
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Seconds(T n) {
- if (n >= 0) {
- if (n >= std::numeric_limits<int64_t>::max()) return InfiniteDuration();
+ if (n >= 0) { // Note: `NaN >= 0` is false.
+ if (n >= (std::numeric_limits<int64_t>::max)()) return InfiniteDuration();
return time_internal::MakePosDoubleDuration(n);
} else {
- if (n <= std::numeric_limits<int64_t>::min()) return -InfiniteDuration();
+ if (std::isnan(n))
+ return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration();
+ if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration();
return -time_internal::MakePosDoubleDuration(-n);
}
}
@@ -543,10 +568,9 @@
// The `absl::Time` class represents an instant in time as a count of clock
// ticks of some granularity (resolution) from some starting point (epoch).
//
-//
// `absl::Time` uses a resolution that is high enough to avoid loss in
// precision, and a range that is wide enough to avoid overflow, when
-// converting between tick counts in most Google time scales (i.e., precision
+// converting between tick counts in most Google time scales (i.e., resolution
// of at least one nanosecond, and range +/-100 billion years). Conversions
// between the time scales are performed by truncating (towards negative
// infinity) to the nearest representable point.
@@ -556,7 +580,6 @@
// absl::Time t1 = ...;
// absl::Time t2 = t1 + absl::Minutes(2);
// absl::Duration d = t2 - t1; // == absl::Minutes(2)
-// absl::Time::Breakdown bd = t1.In(absl::LocalTimeZone());
//
class Time {
public:
@@ -571,7 +594,11 @@
// absl::Time t = absl::Now();
// absl::Time t = absl::TimeFromTimeval(tv);
// absl::Time t = absl::InfinitePast();
- constexpr Time() {}
+ constexpr Time() = default;
+
+ // Copyable.
+ constexpr Time(const Time& t) = default;
+ Time& operator=(const Time& t) = default;
// Assignment operators.
Time& operator+=(Duration d) {
@@ -590,7 +617,10 @@
// intended to represent an instant in time. So, rather than passing
// a `Time::Breakdown` to a function, pass an `absl::Time` and an
// `absl::TimeZone`.
- struct Breakdown {
+ //
+ // Deprecated. Use `absl::TimeZone::CivilInfo`.
+ struct
+ Breakdown {
int64_t year; // year (e.g., 2013)
int month; // month of year [1:12]
int day; // day of month [1:31]
@@ -614,6 +644,8 @@
// Time::In()
//
// Returns the breakdown of this instant in the given TimeZone.
+ //
+ // Deprecated. Use `absl::TimeZone::At(Time)`.
Breakdown In(TimeZone tz) const;
template <typename H>
@@ -668,7 +700,7 @@
// Returns an `absl::Time` that is infinitely far in the future.
constexpr Time InfiniteFuture() {
return Time(
- time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U));
+ time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U));
}
// InfinitePast()
@@ -676,129 +708,9 @@
// Returns an `absl::Time` that is infinitely far in the past.
constexpr Time InfinitePast() {
return Time(
- time_internal::MakeDuration(std::numeric_limits<int64_t>::min(), ~0U));
+ time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U));
}
-// TimeConversion
-//
-// An `absl::TimeConversion` represents the conversion of year, month, day,
-// hour, minute, and second values (i.e., a civil time), in a particular
-// `absl::TimeZone`, to a time instant (an absolute time), as returned by
-// `absl::ConvertDateTime()`. (Subseconds must be handled separately.)
-//
-// It is possible, though, for a caller to try to convert values that
-// do not represent an actual or unique instant in time (due to a shift
-// in UTC offset in the `absl::TimeZone`, which results in a discontinuity in
-// the civil-time components). For example, a daylight-saving-time
-// transition skips or repeats civil times---in the United States, March
-// 13, 2011 02:15 never occurred, while November 6, 2011 01:15 occurred
-// twice---so requests for such times are not well-defined.
-//
-// To account for these possibilities, `absl::TimeConversion` is richer
-// than just a single `absl::Time`. When the civil time is skipped or
-// repeated, `absl::ConvertDateTime()` returns times calculated using the
-// pre-transition and post-transition UTC offsets, plus the transition
-// time itself.
-//
-// Examples:
-//
-// absl::TimeZone lax;
-// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) {
-// // handle error case
-// }
-//
-// // A unique civil time
-// absl::TimeConversion jan01 =
-// absl::ConvertDateTime(2011, 1, 1, 0, 0, 0, lax);
-// // jan01.kind == TimeConversion::UNIQUE
-// // jan01.pre is 2011/01/01 00:00:00 -0800
-// // jan01.trans is 2011/01/01 00:00:00 -0800
-// // jan01.post is 2011/01/01 00:00:00 -0800
-//
-// // A Spring DST transition, when there is a gap in civil time
-// absl::TimeConversion mar13 =
-// absl::ConvertDateTime(2011, 3, 13, 2, 15, 0, lax);
-// // mar13.kind == TimeConversion::SKIPPED
-// // mar13.pre is 2011/03/13 03:15:00 -0700
-// // mar13.trans is 2011/03/13 03:00:00 -0700
-// // mar13.post is 2011/03/13 01:15:00 -0800
-//
-// // A Fall DST transition, when civil times are repeated
-// absl::TimeConversion nov06 =
-// absl::ConvertDateTime(2011, 11, 6, 1, 15, 0, lax);
-// // nov06.kind == TimeConversion::REPEATED
-// // nov06.pre is 2011/11/06 01:15:00 -0700
-// // nov06.trans is 2011/11/06 01:00:00 -0800
-// // nov06.post is 2011/11/06 01:15:00 -0800
-//
-// The input month, day, hour, minute, and second values can also be
-// outside of their valid ranges, in which case they will be "normalized"
-// during the conversion.
-//
-// Example:
-//
-// // "October 32" normalizes to "November 1".
-// absl::TimeZone tz = absl::LocalTimeZone();
-// absl::TimeConversion tc =
-// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, tz);
-// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
-// // tc.pre.In(tz).month == 11 && tc.pre.In(tz).day == 1
-struct TimeConversion {
- Time pre; // time calculated using the pre-transition offset
- Time trans; // when the civil-time discontinuity occurred
- Time post; // time calculated using the post-transition offset
-
- enum Kind {
- UNIQUE, // the civil time was singular (pre == trans == post)
- SKIPPED, // the civil time did not exist
- REPEATED, // the civil time was ambiguous
- };
- Kind kind;
-
- bool normalized; // input values were outside their valid ranges
-};
-
-// ConvertDateTime()
-//
-// The full generality of a civil time to absl::Time conversion.
-TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
- int min, int sec, TimeZone tz);
-
-// FromDateTime()
-//
-// A convenience wrapper for `absl::ConvertDateTime()` that simply returns the
-// "pre" `absl::Time`. That is, the unique result, or the instant that
-// is correct using the pre-transition offset (as if the transition
-// never happened). This is typically the answer that humans expected when
-// faced with non-unique times, such as near daylight-saving time transitions.
-//
-// Example:
-//
-// absl::TimeZone seattle;
-// if (!absl::LoadTimeZone("America/Los_Angeles", &seattle)) {
-// // handle error case
-// }
-// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, seattle);
-Time FromDateTime(int64_t year, int mon, int day, int hour, int min, int sec,
- TimeZone tz);
-
-// FromTM()
-//
-// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
-// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
-// for a description of the expected values of the tm fields. IFF the indicated
-// time instant is not unique (see `absl::ConvertDateTime()` above), the
-// `tm_isdst` field is consulted to select the desired instant (`tm_isdst` > 0
-// means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 means use the default
-// like `absl::FromDateTime()`).
-Time FromTM(const struct tm& tm, TimeZone tz);
-
-// ToTM()
-//
-// Converts the given `absl::Time` to a struct tm using the given time zone.
-// See ctime(3) for a description of the values of the tm fields.
-struct tm ToTM(Time t, TimeZone tz);
-
// FromUnixNanos()
// FromUnixMicros()
// FromUnixMillis()
@@ -883,140 +795,6 @@
// // tp == std::chrono::system_clock::from_time_t(123);
std::chrono::system_clock::time_point ToChronoTime(Time);
-// RFC3339_full
-// RFC3339_sec
-//
-// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
-// with trailing zeros trimmed or with fractional seconds omitted altogether.
-//
-// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and
-// time with UTC offset. Also note the use of "%Y": RFC3339 mandates that
-// years have exactly four digits, but we allow them to take their natural
-// width.
-extern const char RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez
-extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez
-
-// RFC1123_full
-// RFC1123_no_wday
-//
-// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
-extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z
-extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
-
-// FormatTime()
-//
-// Formats the given `absl::Time` in the `absl::TimeZone` according to the
-// provided format string. Uses strftime()-like formatting options, with
-// the following extensions:
-//
-// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
-// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
-// - %E#S - Seconds with # digits of fractional precision
-// - %E*S - Seconds with full fractional precision (a literal '*')
-// - %E#f - Fractional seconds with # digits of precision
-// - %E*f - Fractional seconds with full precision (a literal '*')
-// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
-//
-// Note that %E0S behaves like %S, and %E0f produces no characters. In
-// contrast %E*f always produces at least one digit, which may be '0'.
-//
-// Note that %Y produces as many characters as it takes to fully render the
-// year. A year outside of [-999:9999] when formatted with %E4Y will produce
-// more than four characters, just like %Y.
-//
-// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
-// so that the result uniquely identifies a time instant.
-//
-// Example:
-//
-// absl::TimeZone lax;
-// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) {
-// // handle error case
-// }
-// absl::Time t = absl::FromDateTime(2013, 1, 2, 3, 4, 5, lax);
-//
-// string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
-// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000"
-//
-// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
-// string will be exactly "infinite-future". If the given `absl::Time` is
-// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
-// In both cases the given format string and `absl::TimeZone` are ignored.
-//
-std::string FormatTime(const std::string& format, Time t, TimeZone tz);
-
-// Convenience functions that format the given time using the RFC3339_full
-// format. The first overload uses the provided TimeZone, while the second
-// uses LocalTimeZone().
-std::string FormatTime(Time t, TimeZone tz);
-std::string FormatTime(Time t);
-
-// Output stream operator.
-inline std::ostream& operator<<(std::ostream& os, Time t) {
- return os << FormatTime(t);
-}
-
-// ParseTime()
-//
-// Parses an input string according to the provided format string and
-// returns the corresponding `absl::Time`. Uses strftime()-like formatting
-// options, with the same extensions as FormatTime(), but with the
-// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
-// and %E*z also accept the same inputs.
-//
-// %Y consumes as many numeric characters as it can, so the matching data
-// should always be terminated with a non-numeric. %E4Y always consumes
-// exactly four characters, including any sign.
-//
-// Unspecified fields are taken from the default date and time of ...
-//
-// "1970-01-01 00:00:00.0 +0000"
-//
-// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time
-// that represents "1970-01-01 15:45:00.0 +0000".
-//
-// Note that since ParseTime() returns time instants, it makes the most sense
-// to parse fully-specified date/time strings that include a UTC offset (%z,
-// %Ez, or %E*z).
-//
-// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
-// hour, minute, (fractional) second, and UTC offset. Other fields, like
-// weekday (%a or %A), while parsed for syntactic validity, are ignored
-// in the conversion.
-//
-// Date and time fields that are out-of-range will be treated as errors
-// rather than normalizing them like `absl::FromDateTime()` does. For example,
-// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
-//
-// A leap second of ":60" is normalized to ":00" of the following minute
-// with fractional seconds discarded. The following table shows how the
-// given seconds and subseconds will be parsed:
-//
-// "59.x" -> 59.x // exact
-// "60.x" -> 00.0 // normalized
-// "00.x" -> 00.x // exact
-//
-// Errors are indicated by returning false and assigning an error message
-// to the "err" out param if it is non-null.
-//
-// Note: If the input string is exactly "infinite-future", the returned
-// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
-// If the input string is "infinite-past", the returned `absl::Time` will be
-// `absl::InfinitePast()` and `true` will be returned.
-//
-bool ParseTime(const std::string& format, const std::string& input, Time* time,
- std::string* err);
-
-// Like ParseTime() above, but if the format string does not contain a UTC
-// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
-// given TimeZone. This means that the input, by itself, does not identify a
-// unique instant. Being time-zone dependent, it also admits the possibility
-// of ambiguity or non-existence, in which case the "pre" time (as defined
-// for ConvertDateTime()) is returned. For these reasons we recommend that
-// all date/time strings include a UTC offset so they're context independent.
-bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
- Time* time, std::string* err);
-
// Support for flag values of type Time. Time flags must be specified in a
// format that matches absl::RFC3339_full. For example:
//
@@ -1056,12 +834,14 @@
//
// See also:
// - https://github.com/google/cctz
-// - http://www.iana.org/time-zones
-// - http://en.wikipedia.org/wiki/Zoneinfo
+// - https://www.iana.org/time-zones
+// - https://en.wikipedia.org/wiki/Zoneinfo
class TimeZone {
public:
explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit.
+
+ // Copyable.
TimeZone(const TimeZone&) = default;
TimeZone& operator=(const TimeZone&) = default;
@@ -1069,6 +849,136 @@
std::string name() const { return cz_.name(); }
+ // TimeZone::CivilInfo
+ //
+ // Information about the civil time corresponding to an absolute time.
+ // This struct is not intended to represent an instant in time. So, rather
+ // than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time`
+ // and an `absl::TimeZone`.
+ struct CivilInfo {
+ CivilSecond cs;
+ Duration subsecond;
+
+ // Note: The following fields exist for backward compatibility
+ // with older APIs. Accessing these fields directly is a sign of
+ // imprudent logic in the calling code. Modern time-related code
+ // should only access this data indirectly by way of FormatTime().
+ // These fields are undefined for InfiniteFuture() and InfinitePast().
+ int offset; // seconds east of UTC
+ bool is_dst; // is offset non-standard?
+ const char* zone_abbr; // time-zone abbreviation (e.g., "PST")
+ };
+
+ // TimeZone::At(Time)
+ //
+ // Returns the civil time for this TimeZone at a certain `absl::Time`.
+ // If the input time is infinite, the output civil second will be set to
+ // CivilSecond::max() or min(), and the subsecond will be infinite.
+ //
+ // Example:
+ //
+ // const auto epoch = lax.At(absl::UnixEpoch());
+ // // epoch.cs == 1969-12-31 16:00:00
+ // // epoch.subsecond == absl::ZeroDuration()
+ // // epoch.offset == -28800
+ // // epoch.is_dst == false
+ // // epoch.abbr == "PST"
+ CivilInfo At(Time t) const;
+
+ // TimeZone::TimeInfo
+ //
+ // Information about the absolute times corresponding to a civil time.
+ // (Subseconds must be handled separately.)
+ //
+ // It is possible for a caller to pass a civil-time value that does
+ // not represent an actual or unique instant in time (due to a shift
+ // in UTC offset in the TimeZone, which results in a discontinuity in
+ // the civil-time components). For example, a daylight-saving-time
+ // transition skips or repeats civil times---in the United States,
+ // March 13, 2011 02:15 never occurred, while November 6, 2011 01:15
+ // occurred twice---so requests for such times are not well-defined.
+ // To account for these possibilities, `absl::TimeZone::TimeInfo` is
+ // richer than just a single `absl::Time`.
+ struct TimeInfo {
+ enum CivilKind {
+ UNIQUE, // the civil time was singular (pre == trans == post)
+ SKIPPED, // the civil time did not exist (pre >= trans > post)
+ REPEATED, // the civil time was ambiguous (pre < trans <= post)
+ } kind;
+ Time pre; // time calculated using the pre-transition offset
+ Time trans; // when the civil-time discontinuity occurred
+ Time post; // time calculated using the post-transition offset
+ };
+
+ // TimeZone::At(CivilSecond)
+ //
+ // Returns an `absl::TimeInfo` containing the absolute time(s) for this
+ // TimeZone at an `absl::CivilSecond`. When the civil time is skipped or
+ // repeated, returns times calculated using the pre-transition and post-
+ // transition UTC offsets, plus the transition time itself.
+ //
+ // Examples:
+ //
+ // // A unique civil time
+ // const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0));
+ // // jan01.kind == TimeZone::TimeInfo::UNIQUE
+ // // jan01.pre is 2011-01-01 00:00:00 -0800
+ // // jan01.trans is 2011-01-01 00:00:00 -0800
+ // // jan01.post is 2011-01-01 00:00:00 -0800
+ //
+ // // A Spring DST transition, when there is a gap in civil time
+ // const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0));
+ // // mar13.kind == TimeZone::TimeInfo::SKIPPED
+ // // mar13.pre is 2011-03-13 03:15:00 -0700
+ // // mar13.trans is 2011-03-13 03:00:00 -0700
+ // // mar13.post is 2011-03-13 01:15:00 -0800
+ //
+ // // A Fall DST transition, when civil times are repeated
+ // const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0));
+ // // nov06.kind == TimeZone::TimeInfo::REPEATED
+ // // nov06.pre is 2011-11-06 01:15:00 -0700
+ // // nov06.trans is 2011-11-06 01:00:00 -0800
+ // // nov06.post is 2011-11-06 01:15:00 -0800
+ TimeInfo At(CivilSecond ct) const;
+
+ // TimeZone::NextTransition()
+ // TimeZone::PrevTransition()
+ //
+ // Finds the time of the next/previous offset change in this time zone.
+ //
+ // By definition, `NextTransition(t, &trans)` returns false when `t` is
+ // `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false
+ // when `t` is `InfinitePast()`. If the zone has no transitions, the
+ // result will also be false no matter what the argument.
+ //
+ // Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)`
+ // returns true and sets `trans` to the first recorded transition. Chains
+ // of calls to `NextTransition()/PrevTransition()` will eventually return
+ // false, but it is unspecified exactly when `NextTransition(t, &trans)`
+ // jumps to false, or what time is set by `PrevTransition(t, &trans)` for
+ // a very distant `t`.
+ //
+ // Note: Enumeration of time-zone transitions is for informational purposes
+ // only. Modern time-related code should not care about when offset changes
+ // occur.
+ //
+ // Example:
+ // absl::TimeZone nyc;
+ // if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... }
+ // const auto now = absl::Now();
+ // auto t = absl::InfinitePast();
+ // absl::TimeZone::CivilTransition trans;
+ // while (t <= now && nyc.NextTransition(t, &trans)) {
+ // // transition: trans.from -> trans.to
+ // t = nyc.At(trans.to).trans;
+ // }
+ struct CivilTransition {
+ CivilSecond from; // the civil time we jump from
+ CivilSecond to; // the civil time we jump to
+ };
+ bool NextTransition(Time t, CivilTransition* trans) const;
+ bool PrevTransition(Time t, CivilTransition* trans) const;
+
template <typename H>
friend H AbslHashValue(H h, TimeZone tz) {
return H::combine(std::move(h), tz.cz_);
@@ -1127,6 +1037,270 @@
return TimeZone(time_internal::cctz::local_time_zone());
}
+// ToCivilSecond()
+// ToCivilMinute()
+// ToCivilHour()
+// ToCivilDay()
+// ToCivilMonth()
+// ToCivilYear()
+//
+// Helpers for TimeZone::At(Time) to return particularly aligned civil times.
+//
+// Example:
+//
+// absl::Time t = ...;
+// absl::TimeZone tz = ...;
+// const auto cd = absl::ToCivilDay(t, tz);
+inline CivilSecond ToCivilSecond(Time t, TimeZone tz) {
+ return tz.At(t).cs; // already a CivilSecond
+}
+inline CivilMinute ToCivilMinute(Time t, TimeZone tz) {
+ return CivilMinute(tz.At(t).cs);
+}
+inline CivilHour ToCivilHour(Time t, TimeZone tz) {
+ return CivilHour(tz.At(t).cs);
+}
+inline CivilDay ToCivilDay(Time t, TimeZone tz) {
+ return CivilDay(tz.At(t).cs);
+}
+inline CivilMonth ToCivilMonth(Time t, TimeZone tz) {
+ return CivilMonth(tz.At(t).cs);
+}
+inline CivilYear ToCivilYear(Time t, TimeZone tz) {
+ return CivilYear(tz.At(t).cs);
+}
+
+// FromCivil()
+//
+// Helper for TimeZone::At(CivilSecond) that provides "order-preserving
+// semantics." If the civil time maps to a unique time, that time is
+// returned. If the civil time is repeated in the given time zone, the
+// time using the pre-transition offset is returned. Otherwise, the
+// civil time is skipped in the given time zone, and the transition time
+// is returned. This means that for any two civil times, ct1 and ct2,
+// (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case
+// being when two non-existent civil times map to the same transition time.
+//
+// Note: Accepts civil times of any alignment.
+inline Time FromCivil(CivilSecond ct, TimeZone tz) {
+ const auto ti = tz.At(ct);
+ if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans;
+ return ti.pre;
+}
+
+// TimeConversion
+//
+// An `absl::TimeConversion` represents the conversion of year, month, day,
+// hour, minute, and second values (i.e., a civil time), in a particular
+// `absl::TimeZone`, to a time instant (an absolute time), as returned by
+// `absl::ConvertDateTime()`. Lecacy version of `absl::TimeZone::TimeInfo`.
+//
+// Deprecated. Use `absl::TimeZone::TimeInfo`.
+struct
+ TimeConversion {
+ Time pre; // time calculated using the pre-transition offset
+ Time trans; // when the civil-time discontinuity occurred
+ Time post; // time calculated using the post-transition offset
+
+ enum Kind {
+ UNIQUE, // the civil time was singular (pre == trans == post)
+ SKIPPED, // the civil time did not exist
+ REPEATED, // the civil time was ambiguous
+ };
+ Kind kind;
+
+ bool normalized; // input values were outside their valid ranges
+};
+
+// ConvertDateTime()
+//
+// Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes
+// the civil time as six, separate values (YMDHMS).
+//
+// The input month, day, hour, minute, and second values can be outside
+// of their valid ranges, in which case they will be "normalized" during
+// the conversion.
+//
+// Example:
+//
+// // "October 32" normalizes to "November 1".
+// absl::TimeConversion tc =
+// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax);
+// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
+// // absl::ToCivilDay(tc.pre, tz).month() == 11
+// // absl::ToCivilDay(tc.pre, tz).day() == 1
+//
+// Deprecated. Use `absl::TimeZone::At(CivilSecond)`.
+TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+ int min, int sec, TimeZone tz);
+
+// FromDateTime()
+//
+// A convenience wrapper for `absl::ConvertDateTime()` that simply returns
+// the "pre" `absl::Time`. That is, the unique result, or the instant that
+// is correct using the pre-transition offset (as if the transition never
+// happened).
+//
+// Example:
+//
+// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax);
+// // t = 2017-09-26 09:30:00 -0700
+//
+// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the
+// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil
+// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`.
+inline Time FromDateTime(int64_t year, int mon, int day, int hour,
+ int min, int sec, TimeZone tz) {
+ return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre;
+}
+
+// FromTM()
+//
+// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
+// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
+// for a description of the expected values of the tm fields. If the indicated
+// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)`
+// above), the `tm_isdst` field is consulted to select the desired instant
+// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0
+// means use the post-transition offset).
+Time FromTM(const struct tm& tm, TimeZone tz);
+
+// ToTM()
+//
+// Converts the given `absl::Time` to a struct tm using the given time zone.
+// See ctime(3) for a description of the values of the tm fields.
+struct tm ToTM(Time t, TimeZone tz);
+
+// RFC3339_full
+// RFC3339_sec
+//
+// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
+// with trailing zeros trimmed or with fractional seconds omitted altogether.
+//
+// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and
+// time with UTC offset. Also note the use of "%Y": RFC3339 mandates that
+// years have exactly four digits, but we allow them to take their natural
+// width.
+extern const char RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez
+extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez
+
+// RFC1123_full
+// RFC1123_no_wday
+//
+// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
+extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z
+extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
+
+// FormatTime()
+//
+// Formats the given `absl::Time` in the `absl::TimeZone` according to the
+// provided format string. Uses strftime()-like formatting options, with
+// the following extensions:
+//
+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+// - %E#S - Seconds with # digits of fractional precision
+// - %E*S - Seconds with full fractional precision (a literal '*')
+// - %E#f - Fractional seconds with # digits of precision
+// - %E*f - Fractional seconds with full precision (a literal '*')
+// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters. In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year. A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
+// so that the result uniquely identifies a time instant.
+//
+// Example:
+//
+// absl::CivilSecond cs(2013, 1, 2, 3, 4, 5);
+// absl::Time t = absl::FromCivil(cs, lax);
+// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
+// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000"
+//
+// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
+// string will be exactly "infinite-future". If the given `absl::Time` is
+// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
+// In both cases the given format string and `absl::TimeZone` are ignored.
+//
+std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+
+// Convenience functions that format the given time using the RFC3339_full
+// format. The first overload uses the provided TimeZone, while the second
+// uses LocalTimeZone().
+std::string FormatTime(Time t, TimeZone tz);
+std::string FormatTime(Time t);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Time t) {
+ return os << FormatTime(t);
+}
+
+// ParseTime()
+//
+// Parses an input string according to the provided format string and
+// returns the corresponding `absl::Time`. Uses strftime()-like formatting
+// options, with the same extensions as FormatTime(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
+// and %E*z also accept the same inputs.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric. %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+// "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that since ParseTime() returns time instants, it makes the most sense
+// to parse fully-specified date/time strings that include a UTC offset (%z,
+// %Ez, or %E*z).
+//
+// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
+// hour, minute, (fractional) second, and UTC offset. Other fields, like
+// weekday (%a or %A), while parsed for syntactic validity, are ignored
+// in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors
+// rather than normalizing them like `absl::CivilSecond` does. For example,
+// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A leap second of ":60" is normalized to ":00" of the following minute
+// with fractional seconds discarded. The following table shows how the
+// given seconds and subseconds will be parsed:
+//
+// "59.x" -> 59.x // exact
+// "60.x" -> 00.0 // normalized
+// "00.x" -> 00.x // exact
+//
+// Errors are indicated by returning false and assigning an error message
+// to the "err" out param if it is non-null.
+//
+// Note: If the input string is exactly "infinite-future", the returned
+// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
+// If the input string is "infinite-past", the returned `absl::Time` will be
+// `absl::InfinitePast()` and `true` will be returned.
+//
+bool ParseTime(const std::string& format, const std::string& input, Time* time,
+ std::string* err);
+
+// Like ParseTime() above, but if the format string does not contain a UTC
+// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
+// given TimeZone. This means that the input, by itself, does not identify a
+// unique instant. Being time-zone dependent, it also admits the possibility
+// of ambiguity or non-existence, in which case the "pre" time (as defined
+// by TimeZone::TimeInfo) is returned. For these reasons we recommend that
+// all date/time strings include a UTC offset so they're context independent.
+bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
+ Time* time, std::string* err);
+
// ============================================================================
// Implementation Details Follow
// ============================================================================
@@ -1164,17 +1338,20 @@
return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond)
: MakeDuration(sec, ticks);
}
+
// Provide access to the Duration representation.
constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; }
constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; }
+
+// Returns true iff d is positive or negative infinity.
constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; }
// Returns an infinite Duration with the opposite sign.
// REQUIRES: IsInfiniteDuration(d)
constexpr Duration OppositeInfinity(Duration d) {
return GetRepHi(d) < 0
- ? MakeDuration(std::numeric_limits<int64_t>::max(), ~0U)
- : MakeDuration(std::numeric_limits<int64_t>::min(), ~0U);
+ ? MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U)
+ : MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U);
}
// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow.
@@ -1199,14 +1376,14 @@
v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
}
constexpr Duration FromInt64(int64_t v, std::ratio<60>) {
- return (v <= std::numeric_limits<int64_t>::max() / 60 &&
- v >= std::numeric_limits<int64_t>::min() / 60)
+ return (v <= (std::numeric_limits<int64_t>::max)() / 60 &&
+ v >= (std::numeric_limits<int64_t>::min)() / 60)
? MakeDuration(v * 60)
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration FromInt64(int64_t v, std::ratio<3600>) {
- return (v <= std::numeric_limits<int64_t>::max() / 3600 &&
- v >= std::numeric_limits<int64_t>::min() / 3600)
+ return (v <= (std::numeric_limits<int64_t>::max)() / 3600 &&
+ v >= (std::numeric_limits<int64_t>::min)() / 3600)
? MakeDuration(v * 3600)
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
}
@@ -1263,14 +1440,15 @@
using Period = typename T::period;
static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
if (time_internal::IsInfiniteDuration(d))
- return d < ZeroDuration() ? T::min() : T::max();
+ return d < ZeroDuration() ? (T::min)() : (T::max)();
const auto v = ToInt64(d, Period{});
- if (v > std::numeric_limits<Rep>::max()) return T::max();
- if (v < std::numeric_limits<Rep>::min()) return T::min();
+ if (v > (std::numeric_limits<Rep>::max)()) return (T::max)();
+ if (v < (std::numeric_limits<Rep>::min)()) return (T::min)();
return T{v};
}
} // namespace time_internal
+
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::FromInt64(n, std::nano{});
}
@@ -1293,7 +1471,8 @@
constexpr bool operator<(Duration lhs, Duration rhs) {
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
- : time_internal::GetRepHi(lhs) == std::numeric_limits<int64_t>::min()
+ : time_internal::GetRepHi(lhs) ==
+ (std::numeric_limits<int64_t>::min)()
? time_internal::GetRepLo(lhs) + 1 <
time_internal::GetRepLo(rhs) + 1
: time_internal::GetRepLo(lhs) <
@@ -1318,7 +1497,8 @@
// a second's worth of ticks and avoid overflow (as negating int64_t-min + 1
// is safe).
return time_internal::GetRepLo(d) == 0
- ? time_internal::GetRepHi(d) == std::numeric_limits<int64_t>::min()
+ ? time_internal::GetRepHi(d) ==
+ (std::numeric_limits<int64_t>::min)()
? InfiniteDuration()
: time_internal::MakeDuration(-time_internal::GetRepHi(d))
: time_internal::IsInfiniteDuration(d)
@@ -1331,7 +1511,8 @@
}
constexpr Duration InfiniteDuration() {
- return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U);
+ return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(),
+ ~0U);
}
constexpr Duration FromChrono(const std::chrono::nanoseconds& d) {
diff --git a/absl/time/time_benchmark.cc b/absl/time/time_benchmark.cc
index e100994..99e6279 100644
--- a/absl/time/time_benchmark.cc
+++ b/absl/time/time_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -169,32 +169,32 @@
BENCHMARK(BM_Time_ToUnixSeconds);
//
-// FromDateTime
+// FromCivil
//
-// In each "FromDateTime" benchmark we switch between two YMDhms
-// values separated by at least one transition in order to defeat any
-// internal caching of previous results (e.g., see time_local_hint_).
+// In each "FromCivil" benchmark we switch between two YMDhms values
+// separated by at least one transition in order to defeat any internal
+// caching of previous results (e.g., see time_local_hint_).
//
// The "UTC" variants use UTC instead of the Google/local time zone.
// The "Day0" variants require normalization of the day of month.
//
-void BM_Time_FromDateTime_Absl(benchmark::State& state) {
+void BM_Time_FromCivil_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
- absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz);
+ absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
} else {
- absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz);
+ absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz);
}
++i;
}
}
-BENCHMARK(BM_Time_FromDateTime_Absl);
+BENCHMARK(BM_Time_FromCivil_Absl);
-void BM_Time_FromDateTime_Libc(benchmark::State& state) {
+void BM_Time_FromCivil_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
@@ -219,32 +219,32 @@
++i;
}
}
-BENCHMARK(BM_Time_FromDateTime_Libc);
+BENCHMARK(BM_Time_FromCivil_Libc);
-void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) {
+void BM_Time_FromCivilUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
while (state.KeepRunning()) {
- FromDateTime(2014, 12, 18, 20, 16, 18, tz);
+ absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
}
}
-BENCHMARK(BM_Time_FromDateTimeUTC_Absl);
+BENCHMARK(BM_Time_FromCivilUTC_Absl);
-void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) {
+void BM_Time_FromCivilDay0_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
- absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz);
+ absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz);
} else {
- absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz);
+ absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz);
}
++i;
}
}
-BENCHMARK(BM_Time_FromDateTimeDay0_Absl);
+BENCHMARK(BM_Time_FromCivilDay0_Absl);
-void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
+void BM_Time_FromCivilDay0_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
@@ -269,7 +269,7 @@
++i;
}
}
-BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
+BENCHMARK(BM_Time_FromCivilDay0_Libc);
//
// To/FromTimespec
diff --git a/absl/time/time_norm_test.cc b/absl/time/time_norm_test.cc
deleted file mode 100644
index 4436242..0000000
--- a/absl/time/time_norm_test.cc
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This file contains tests for FromDateTime() normalization, which is
-// time-zone independent so we just use UTC throughout.
-
-#include <cstdint>
-#include <limits>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/time/internal/test_util.h"
-#include "absl/time/time.h"
-
-namespace {
-
-TEST(TimeNormCase, SimpleOverflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc =
- absl::ConvertDateTime(2013, 11, 15, 16, 32, 59 + 1, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false);
-}
-
-TEST(TimeNormCase, SimpleUnderflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc = ConvertDateTime(2013, 11, 15, 16, 32, 0 - 1, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false);
-
- tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false);
-
- tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false);
-
- tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false);
-
- tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false);
-}
-
-TEST(TimeNormCase, MultipleOverflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
- absl::TimeConversion tc = ConvertDateTime(2013, 12, 31, 23, 59, 59 + 1, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false);
-}
-
-TEST(TimeNormCase, MultipleUnderflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
- absl::TimeConversion tc = absl::ConvertDateTime(2014, 1, 1, 0, 0, 0 - 1, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false);
-}
-
-TEST(TimeNormCase, OverflowLimits) {
- const absl::TimeZone utc = absl::UTCTimeZone();
- absl::TimeConversion tc;
- absl::Time::Breakdown bd;
-
- const int kintmax = std::numeric_limits<int>::max();
- tc = absl::ConvertDateTime(0, kintmax, kintmax, kintmax, kintmax, kintmax,
- utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false);
-
- const int kintmin = std::numeric_limits<int>::min();
- tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
- utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false);
-
- const int64_t max_year = std::numeric_limits<int64_t>::max();
- tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- EXPECT_EQ(absl::InfiniteFuture(), tc.pre);
-
- const int64_t min_year = std::numeric_limits<int64_t>::min();
- tc = absl::ConvertDateTime(min_year, 1, 1, 0, 0, 0, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- EXPECT_EQ(absl::InfinitePast(), tc.pre);
-}
-
-TEST(TimeNormCase, ComplexOverflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc =
- ConvertDateTime(2013, 11, 15, 16, 32, 14 + 123456789, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false);
-}
-
-TEST(TimeNormCase, ComplexUnderflow) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc =
- absl::ConvertDateTime(1999, 3, 0, 0, 0, 0, utc); // year 400
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false);
-}
-
-TEST(TimeNormCase, Mishmash) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc =
- absl::ConvertDateTime(2013, 11 - 123, 15 + 1234, 16 - 123456,
- 32 + 1234567, 14 - 123456789, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false);
-
- tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
- 32 - 1234567, 14 + 123456789, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false);
-
- // Here is a normalization case we got wrong for a while. Because the
- // day is converted to "1" within a 400-year (146097-day) period, we
- // didn't need to roll the month and so we didn't mark it as normalized.
- tc = absl::ConvertDateTime(2013, 11, -146097 + 1, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false);
-
- // Even though the month overflow compensates for the day underflow,
- // this should still be marked as normalized.
- tc = absl::ConvertDateTime(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false);
-}
-
-TEST(TimeNormCase, LeapYears) {
- const absl::TimeZone utc = absl::UTCTimeZone();
-
- absl::TimeConversion tc =
- absl::ConvertDateTime(2013, 2, 28 + 1, 0, 0, 0, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false);
-
- tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
- EXPECT_FALSE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false);
-
- tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
- EXPECT_FALSE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false);
-
- tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
- EXPECT_TRUE(tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false);
-}
-
-// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
-// and check that they normalize to the expected time. 146097 days span
-// the 400-year Gregorian cycle used during normalization.
-TEST(TimeNormCase, AllTheDays) {
- const absl::TimeZone utc = absl::UTCTimeZone();
- absl::Time exp_time = absl::UnixEpoch();
-
- for (int day = 1; day <= 146097; ++day) {
- absl::TimeConversion tc = absl::ConvertDateTime(1970, 1, day, 0, 0, 0, utc);
- EXPECT_EQ(day > 31, tc.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
- EXPECT_EQ(exp_time, tc.pre);
- exp_time += absl::Hours(24);
- }
-}
-
-} // namespace
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 4f8f58a..74148d5 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,6 +28,27 @@
namespace {
+#if GTEST_USES_SIMPLE_RE
+const char kZoneAbbrRE[] = ".*"; // just punt
+#else
+const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
+#endif
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+#define EXPECT_CIVIL_INFO(ci, y, m, d, h, min, s, off, isdst) \
+ do { \
+ EXPECT_EQ(y, ci.cs.year()); \
+ EXPECT_EQ(m, ci.cs.month()); \
+ EXPECT_EQ(d, ci.cs.day()); \
+ EXPECT_EQ(h, ci.cs.hour()); \
+ EXPECT_EQ(min, ci.cs.minute()); \
+ EXPECT_EQ(s, ci.cs.second()); \
+ EXPECT_EQ(off, ci.offset); \
+ EXPECT_EQ(isdst, ci.is_dst); \
+ EXPECT_THAT(ci.zone_abbr, testing::MatchesRegex(kZoneAbbrRE)); \
+ } while (0)
+
// A gMock matcher to match timespec values. Use this matcher like:
// timespec ts1, ts2;
// EXPECT_THAT(ts1, TimespecMatcher(ts2));
@@ -84,10 +105,10 @@
}
TEST(Time, UnixEpoch) {
- absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
- ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false);
- EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
- EXPECT_EQ(4, bd.weekday); // Thursday
+ const auto ci = absl::UTCTimeZone().At(absl::UnixEpoch());
+ EXPECT_EQ(absl::CivilSecond(1970, 1, 1, 0, 0, 0), ci.cs);
+ EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs)));
}
TEST(Time, Breakdown) {
@@ -95,26 +116,26 @@
absl::Time t = absl::UnixEpoch();
// The Unix epoch as seen in NYC.
- absl::Time::Breakdown bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false);
- EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
- EXPECT_EQ(3, bd.weekday); // Wednesday
+ auto ci = tz.At(t);
+ EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 19, 0, 0, -18000, false);
+ EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
+ EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
// Just before the epoch.
t -= absl::Nanoseconds(1);
- bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false);
- EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
- EXPECT_EQ(3, bd.weekday); // Wednesday
+ ci = tz.At(t);
+ EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 18, 59, 59, -18000, false);
+ EXPECT_EQ(absl::Nanoseconds(999999999), ci.subsecond);
+ EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
// Some time later.
t += absl::Hours(24) * 2735;
t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
absl::Nanoseconds(9);
- bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true);
- EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
- EXPECT_EQ(2, bd.weekday); // Tuesday
+ ci = tz.At(t);
+ EXPECT_CIVIL_INFO(ci, 1977, 6, 28, 14, 30, 15, -14400, true);
+ EXPECT_EQ(8, ci.subsecond / absl::Nanoseconds(1));
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
}
TEST(Time, AdditiveOperators) {
@@ -550,67 +571,63 @@
absl::ToChronoTime(absl::UnixEpoch() - tick));
}
-TEST(Time, ConvertDateTime) {
- const absl::TimeZone utc = absl::UTCTimeZone();
- const absl::TimeZone goog =
- absl::time_internal::LoadTimeZone("America/Los_Angeles");
+TEST(Time, TimeZoneAt) {
const absl::TimeZone nyc =
absl::time_internal::LoadTimeZone("America/New_York");
const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
- // A simple case of normalization.
- absl::TimeConversion oct32 = ConvertDateTime(2013, 10, 32, 8, 30, 0, goog);
- EXPECT_TRUE(oct32.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, oct32.kind);
- absl::TimeConversion nov01 = ConvertDateTime(2013, 11, 1, 8, 30, 0, goog);
- EXPECT_FALSE(nov01.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, nov01.kind);
- EXPECT_EQ(oct32.pre, nov01.pre);
- EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0700 (PDT)",
- absl::FormatTime(fmt, nov01.pre, goog));
+ // A non-transition where the civil time is unique.
+ absl::CivilSecond nov01(2013, 11, 1, 8, 30, 0);
+ const auto nov01_ci = nyc.At(nov01);
+ EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, nov01_ci.kind);
+ EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0400 (EDT)",
+ absl::FormatTime(fmt, nov01_ci.pre, nyc));
+ EXPECT_EQ(nov01_ci.pre, nov01_ci.trans);
+ EXPECT_EQ(nov01_ci.pre, nov01_ci.post);
+ EXPECT_EQ(nov01_ci.pre, absl::FromCivil(nov01, nyc));
// A Spring DST transition, when there is a gap in civil time
// and we prefer the later of the possible interpretations of a
// non-existent time.
- absl::TimeConversion mar13 = ConvertDateTime(2011, 3, 13, 2, 15, 0, nyc);
- EXPECT_FALSE(mar13.normalized);
- EXPECT_EQ(absl::TimeConversion::SKIPPED, mar13.kind);
+ absl::CivilSecond mar13(2011, 3, 13, 2, 15, 0);
+ const auto mar_ci = nyc.At(mar13);
+ EXPECT_EQ(absl::TimeZone::TimeInfo::SKIPPED, mar_ci.kind);
EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)",
- absl::FormatTime(fmt, mar13.pre, nyc));
+ absl::FormatTime(fmt, mar_ci.pre, nyc));
EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)",
- absl::FormatTime(fmt, mar13.trans, nyc));
+ absl::FormatTime(fmt, mar_ci.trans, nyc));
EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)",
- absl::FormatTime(fmt, mar13.post, nyc));
- EXPECT_EQ(mar13.pre, absl::FromDateTime(2011, 3, 13, 2, 15, 0, nyc));
+ absl::FormatTime(fmt, mar_ci.post, nyc));
+ EXPECT_EQ(mar_ci.trans, absl::FromCivil(mar13, nyc));
// A Fall DST transition, when civil times are repeated and
// we prefer the earlier of the possible interpretations of an
// ambiguous time.
- absl::TimeConversion nov06 = ConvertDateTime(2011, 11, 6, 1, 15, 0, nyc);
- EXPECT_FALSE(nov06.normalized);
- EXPECT_EQ(absl::TimeConversion::REPEATED, nov06.kind);
+ absl::CivilSecond nov06(2011, 11, 6, 1, 15, 0);
+ const auto nov06_ci = nyc.At(nov06);
+ EXPECT_EQ(absl::TimeZone::TimeInfo::REPEATED, nov06_ci.kind);
EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0400 (EDT)",
- absl::FormatTime(fmt, nov06.pre, nyc));
+ absl::FormatTime(fmt, nov06_ci.pre, nyc));
EXPECT_EQ("Sun, 6 Nov 2011 01:00:00 -0500 (EST)",
- absl::FormatTime(fmt, nov06.trans, nyc));
+ absl::FormatTime(fmt, nov06_ci.trans, nyc));
EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0500 (EST)",
- absl::FormatTime(fmt, nov06.post, nyc));
- EXPECT_EQ(nov06.pre, absl::FromDateTime(2011, 11, 6, 1, 15, 0, nyc));
+ absl::FormatTime(fmt, nov06_ci.post, nyc));
+ EXPECT_EQ(nov06_ci.pre, absl::FromCivil(nov06, nyc));
// Check that (time_t) -1 is handled correctly.
- absl::TimeConversion minus1 = ConvertDateTime(1969, 12, 31, 18, 59, 59, nyc);
- EXPECT_FALSE(minus1.normalized);
- EXPECT_EQ(absl::TimeConversion::UNIQUE, minus1.kind);
- EXPECT_EQ(-1, absl::ToTimeT(minus1.pre));
+ absl::CivilSecond minus1(1969, 12, 31, 18, 59, 59);
+ const auto minus1_cl = nyc.At(minus1);
+ EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, minus1_cl.kind);
+ EXPECT_EQ(-1, absl::ToTimeT(minus1_cl.pre));
EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)",
- absl::FormatTime(fmt, minus1.pre, nyc));
+ absl::FormatTime(fmt, minus1_cl.pre, nyc));
EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)",
- absl::FormatTime(fmt, minus1.pre, utc));
+ absl::FormatTime(fmt, minus1_cl.pre, absl::UTCTimeZone()));
}
-// FromDateTime(year, mon, day, hour, min, sec, UTCTimeZone()) has
-// a specialized fastpath implementation which we exercise here.
-TEST(Time, FromDateTimeUTC) {
+// FromCivil(CivilSecond(year, mon, day, hour, min, sec), UTCTimeZone())
+// has a specialized fastpath implementation, which we exercise here.
+TEST(Time, FromCivilUTC) {
const absl::TimeZone utc = absl::UTCTimeZone();
const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
const int kMax = std::numeric_limits<int>::max();
@@ -618,65 +635,36 @@
absl::Time t;
// 292091940881 is the last positive year to use the fastpath.
- t = absl::FromDateTime(292091940881, kMax, kMax, kMax, kMax, kMax, utc);
+ t = absl::FromCivil(
+ absl::CivilSecond(292091940881, kMax, kMax, kMax, kMax, kMax), utc);
EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
- t = absl::FromDateTime(292091940882, kMax, kMax, kMax, kMax, kMax, utc);
- EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow
- t = absl::FromDateTime(
- std::numeric_limits<int64_t>::max(), kMax, kMax, kMax, kMax, kMax, utc);
+ t = absl::FromCivil(
+ absl::CivilSecond(292091940882, kMax, kMax, kMax, kMax, kMax), utc);
EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow
// -292091936940 is the last negative year to use the fastpath.
- t = absl::FromDateTime(-292091936940, kMin, kMin, kMin, kMin, kMin, utc);
+ t = absl::FromCivil(
+ absl::CivilSecond(-292091936940, kMin, kMin, kMin, kMin, kMin), utc);
EXPECT_EQ("Fri, 1 Nov -292277022657 10:37:52 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
- t = absl::FromDateTime(-292091936941, kMin, kMin, kMin, kMin, kMin, utc);
+ t = absl::FromCivil(
+ absl::CivilSecond(-292091936941, kMin, kMin, kMin, kMin, kMin), utc);
EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no underflow
- t = absl::FromDateTime(
- std::numeric_limits<int64_t>::min(), kMin, kMin, kMin, kMin, kMin, utc);
- EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no overflow
// Check that we're counting leap years correctly.
- t = absl::FromDateTime(1900, 2, 28, 23, 59, 59, utc);
+ t = absl::FromCivil(absl::CivilSecond(1900, 2, 28, 23, 59, 59), utc);
EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
- t = absl::FromDateTime(1900, 3, 1, 0, 0, 0, utc);
+ t = absl::FromCivil(absl::CivilSecond(1900, 3, 1, 0, 0, 0), utc);
EXPECT_EQ("Thu, 1 Mar 1900 00:00:00 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
- t = absl::FromDateTime(2000, 2, 29, 23, 59, 59, utc);
+ t = absl::FromCivil(absl::CivilSecond(2000, 2, 29, 23, 59, 59), utc);
EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
- t = absl::FromDateTime(2000, 3, 1, 0, 0, 0, utc);
+ t = absl::FromCivil(absl::CivilSecond(2000, 3, 1, 0, 0, 0), utc);
EXPECT_EQ("Wed, 1 Mar 2000 00:00:00 +0000 (UTC)",
absl::FormatTime(fmt, t, utc));
-
- // Check normalization.
- const std::string ymdhms = "%Y-%m-%d %H:%M:%S";
- t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc);
- EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc);
- EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc);
- EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc);
- EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc);
- EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc);
- EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc);
- EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc);
- EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc);
- EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc);
- EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc);
- EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
- t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc);
- EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc));
}
TEST(Time, ToTM) {
@@ -684,8 +672,10 @@
// Compares the results of ToTM() to gmtime_r() for lots of times over the
// course of a few days.
- const absl::Time start = absl::FromDateTime(2014, 1, 2, 3, 4, 5, utc);
- const absl::Time end = absl::FromDateTime(2014, 1, 5, 3, 4, 5, utc);
+ const absl::Time start =
+ absl::FromCivil(absl::CivilSecond(2014, 1, 2, 3, 4, 5), utc);
+ const absl::Time end =
+ absl::FromCivil(absl::CivilSecond(2014, 1, 5, 3, 4, 5), utc);
for (absl::Time t = start; t < end; t += absl::Seconds(30)) {
const struct tm tm_bt = ToTM(t, utc);
const time_t tt = absl::ToTimeT(t);
@@ -711,12 +701,12 @@
// Checks that the tm_isdst field is correct when in standard time.
const absl::TimeZone nyc =
absl::time_internal::LoadTimeZone("America/New_York");
- absl::Time t = absl::FromDateTime(2014, 3, 1, 0, 0, 0, nyc);
+ absl::Time t = absl::FromCivil(absl::CivilSecond(2014, 3, 1, 0, 0, 0), nyc);
struct tm tm = ToTM(t, nyc);
EXPECT_FALSE(tm.tm_isdst);
// Checks that the tm_isdst field is correct when in daylight time.
- t = absl::FromDateTime(2014, 4, 1, 0, 0, 0, nyc);
+ t = absl::FromCivil(absl::CivilSecond(2014, 4, 1, 0, 0, 0), nyc);
tm = ToTM(t, nyc);
EXPECT_TRUE(tm.tm_isdst);
@@ -808,8 +798,8 @@
absl::time_internal::LoadTimeZone("America/New_York");
// Test round-tripping across a skipped transition
- absl::Time start = absl::FromDateTime(2014, 3, 9, 0, 0, 0, nyc);
- absl::Time end = absl::FromDateTime(2014, 3, 9, 4, 0, 0, nyc);
+ absl::Time start = absl::FromCivil(absl::CivilHour(2014, 3, 9, 0), nyc);
+ absl::Time end = absl::FromCivil(absl::CivilHour(2014, 3, 9, 4), nyc);
for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
struct tm tm = ToTM(t, nyc);
absl::Time rt = FromTM(tm, nyc);
@@ -817,8 +807,8 @@
}
// Test round-tripping across an ambiguous transition
- start = absl::FromDateTime(2014, 11, 2, 0, 0, 0, nyc);
- end = absl::FromDateTime(2014, 11, 2, 4, 0, 0, nyc);
+ start = absl::FromCivil(absl::CivilHour(2014, 11, 2, 0), nyc);
+ end = absl::FromCivil(absl::CivilHour(2014, 11, 2, 4), nyc);
for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
struct tm tm = ToTM(t, nyc);
absl::Time rt = FromTM(tm, nyc);
@@ -826,8 +816,8 @@
}
// Test round-tripping of unique instants crossing a day boundary
- start = absl::FromDateTime(2014, 6, 27, 22, 0, 0, nyc);
- end = absl::FromDateTime(2014, 6, 28, 4, 0, 0, nyc);
+ start = absl::FromCivil(absl::CivilHour(2014, 6, 27, 22), nyc);
+ end = absl::FromCivil(absl::CivilHour(2014, 6, 28, 4), nyc);
for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
struct tm tm = ToTM(t, nyc);
absl::Time rt = FromTM(tm, nyc);
@@ -980,27 +970,27 @@
EXPECT_EQ(min_timespec_sec, ts.tv_sec);
EXPECT_EQ(0, ts.tv_nsec);
- // Checks how Time::In() saturates on infinities.
- absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
+ // Checks how TimeZone::At() saturates on infinities.
+ auto ci = utc.At(absl::InfiniteFuture());
+ EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23,
59, 59, 0, false);
- EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
- EXPECT_EQ(4, bd.weekday); // Thursday
- EXPECT_EQ(365, bd.yearday);
- EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
- bd = absl::InfinitePast().In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
+ EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond);
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(365, absl::GetYearDay(absl::CivilDay(ci.cs)));
+ EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At()
+ ci = utc.At(absl::InfinitePast());
+ EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
0, 0, false);
- EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
- EXPECT_EQ(7, bd.weekday); // Sunday
- EXPECT_EQ(1, bd.yearday);
- EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
+ EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond);
+ EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(1, absl::GetYearDay(absl::CivilDay(ci.cs)));
+ EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At()
// Approach the maximal Time value from below.
- t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 6), utc);
EXPECT_EQ("292277026596-12-04T15:30:06+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc));
- t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 7, utc);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 7), utc);
EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ(
@@ -1008,21 +998,21 @@
// Checks that we can also get the maximal Time value for a far-east zone.
const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
- t = absl::FromDateTime(292277026596, 12, 5, 5, 30, 7, plus14);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 5, 30, 7), plus14);
EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
absl::FormatTime(absl::RFC3339_full, t, plus14));
EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
// One second later should push us to infinity.
- t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 8, utc);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc));
// Approach the minimal Time value from above.
- t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 53, utc);
+ t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 53), utc);
EXPECT_EQ("-292277022657-01-27T08:29:53+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc));
- t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 52, utc);
+ t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 52), utc);
EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ(
@@ -1030,14 +1020,15 @@
// Checks that we can also get the minimal Time value for a far-west zone.
const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
- t = absl::FromDateTime(-292277022657, 1, 26, 20, 29, 52, minus12);
+ t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 26, 20, 29, 52),
+ minus12);
EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
absl::FormatTime(absl::RFC3339_full, t, minus12));
EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
// One second before should push us to -infinity.
- t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 51, utc);
+ t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc));
}
@@ -1051,38 +1042,160 @@
absl::time_internal::LoadTimeZone("America/New_York");
const absl::Time max =
absl::FromUnixSeconds(std::numeric_limits<int64_t>::max());
- absl::Time::Breakdown bd;
+ absl::TimeZone::CivilInfo ci;
absl::Time t;
// The maximal time converted in each zone.
- bd = max.In(syd);
- ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true);
- t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
+ ci = syd.At(max);
+ EXPECT_CIVIL_INFO(ci, 292277026596, 12, 5, 2, 30, 7, 39600, true);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 7), syd);
EXPECT_EQ(max, t);
- bd = max.In(nyc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false);
- t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
+ ci = nyc.At(max);
+ EXPECT_CIVIL_INFO(ci, 292277026596, 12, 4, 10, 30, 7, -18000, false);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 7), nyc);
EXPECT_EQ(max, t);
// One second later should push us to infinity.
- t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 8, syd);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 8), syd);
EXPECT_EQ(absl::InfiniteFuture(), t);
- t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 8, nyc);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 8), nyc);
EXPECT_EQ(absl::InfiniteFuture(), t);
// And we should stick there.
- t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 9, syd);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 9), syd);
EXPECT_EQ(absl::InfiniteFuture(), t);
- t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 9, nyc);
+ t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 9), nyc);
EXPECT_EQ(absl::InfiniteFuture(), t);
// All the way up to a saturated date/time, without overflow.
- t = absl::FromDateTime(
- std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, syd);
+ t = absl::FromCivil(absl::CivilSecond::max(), syd);
EXPECT_EQ(absl::InfiniteFuture(), t);
- t = absl::FromDateTime(
- std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, nyc);
+ t = absl::FromCivil(absl::CivilSecond::max(), nyc);
EXPECT_EQ(absl::InfiniteFuture(), t);
}
+TEST(Time, FromCivilAlignment) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ const absl::CivilSecond cs(2015, 2, 3, 4, 5, 6);
+ absl::Time t = absl::FromCivil(cs, utc);
+ EXPECT_EQ("2015-02-03T04:05:06+00:00", absl::FormatTime(t, utc));
+ t = absl::FromCivil(absl::CivilMinute(cs), utc);
+ EXPECT_EQ("2015-02-03T04:05:00+00:00", absl::FormatTime(t, utc));
+ t = absl::FromCivil(absl::CivilHour(cs), utc);
+ EXPECT_EQ("2015-02-03T04:00:00+00:00", absl::FormatTime(t, utc));
+ t = absl::FromCivil(absl::CivilDay(cs), utc);
+ EXPECT_EQ("2015-02-03T00:00:00+00:00", absl::FormatTime(t, utc));
+ t = absl::FromCivil(absl::CivilMonth(cs), utc);
+ EXPECT_EQ("2015-02-01T00:00:00+00:00", absl::FormatTime(t, utc));
+ t = absl::FromCivil(absl::CivilYear(cs), utc);
+ EXPECT_EQ("2015-01-01T00:00:00+00:00", absl::FormatTime(t, utc));
+}
+
+TEST(Time, LegacyDateTime) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ const std::string ymdhms = "%Y-%m-%d %H:%M:%S";
+ const int kMax = std::numeric_limits<int>::max();
+ const int kMin = std::numeric_limits<int>::min();
+ absl::Time t;
+
+ t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(),
+ kMax, kMax, kMax, kMax, kMax, utc);
+ EXPECT_EQ("infinite-future",
+ absl::FormatTime(ymdhms, t, utc)); // no overflow
+ t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(),
+ kMin, kMin, kMin, kMin, kMin, utc);
+ EXPECT_EQ("infinite-past",
+ absl::FormatTime(ymdhms, t, utc)); // no overflow
+
+ // Check normalization.
+ EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized);
+ t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc);
+ EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc);
+ EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc);
+ EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc);
+ EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc);
+ EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc);
+ EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc);
+ EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc);
+ EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc);
+ EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc);
+ EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc);
+ EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc);
+ EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc));
+}
+
+TEST(Time, NextTransitionUTC) {
+ const auto tz = absl::UTCTimeZone();
+ absl::TimeZone::CivilTransition trans;
+
+ auto t = absl::InfinitePast();
+ EXPECT_FALSE(tz.NextTransition(t, &trans));
+
+ t = absl::InfiniteFuture();
+ EXPECT_FALSE(tz.NextTransition(t, &trans));
+}
+
+TEST(Time, PrevTransitionUTC) {
+ const auto tz = absl::UTCTimeZone();
+ absl::TimeZone::CivilTransition trans;
+
+ auto t = absl::InfiniteFuture();
+ EXPECT_FALSE(tz.PrevTransition(t, &trans));
+
+ t = absl::InfinitePast();
+ EXPECT_FALSE(tz.PrevTransition(t, &trans));
+}
+
+TEST(Time, NextTransitionNYC) {
+ const auto tz = absl::time_internal::LoadTimeZone("America/New_York");
+ absl::TimeZone::CivilTransition trans;
+
+ auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.NextTransition(t, &trans));
+ EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 2, 0, 0), trans.from);
+ EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 1, 0, 0), trans.to);
+
+ t = absl::InfiniteFuture();
+ EXPECT_FALSE(tz.NextTransition(t, &trans));
+
+ t = absl::InfinitePast();
+ EXPECT_TRUE(tz.NextTransition(t, &trans));
+ if (trans.from == absl::CivilSecond(1918, 03, 31, 2, 0, 0)) {
+ // It looks like the tzdata is only 32 bit (probably macOS),
+ // which bottoms out at 1901-12-13T20:45:52+00:00.
+ EXPECT_EQ(absl::CivilSecond(1918, 3, 31, 3, 0, 0), trans.to);
+ } else {
+ EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 3, 58), trans.from);
+ EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 0, 0), trans.to);
+ }
+}
+
+TEST(Time, PrevTransitionNYC) {
+ const auto tz = absl::time_internal::LoadTimeZone("America/New_York");
+ absl::TimeZone::CivilTransition trans;
+
+ auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.PrevTransition(t, &trans));
+ EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 2, 0, 0), trans.from);
+ EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 3, 0, 0), trans.to);
+
+ t = absl::InfinitePast();
+ EXPECT_FALSE(tz.PrevTransition(t, &trans));
+
+ t = absl::InfiniteFuture();
+ EXPECT_TRUE(tz.PrevTransition(t, &trans));
+ // We have a transition but we don't know which one.
+}
+
} // namespace
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc
index 43d9190..8f1e74a 100644
--- a/absl/time/time_zone_test.cc
+++ b/absl/time/time_zone_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 32f690c..7da0003 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
@@ -168,6 +168,7 @@
deps = [
":bad_optional_access",
"//absl/base:config",
+ "//absl/base:core_headers",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/utility",
@@ -286,6 +287,7 @@
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
deps = [
":variant",
+ "//absl/base:config",
"//absl/base:exception_safety_testing",
"//absl/memory",
"@com_google_googletest//:gtest_main",
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 2f2e3a7..8afde46 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,216 +13,306 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-list(APPEND TYPES_PUBLIC_HEADERS
- "any.h"
- "bad_any_cast.h"
- "bad_optional_access.h"
- "optional.h"
- "span.h"
- "variant.h"
-)
-
-
-# any library
-absl_header_library(
- TARGET
- absl_any
- PUBLIC_LIBRARIES
- absl::bad_any_cast
- absl::base
- absl::meta
- absl::utility
- PRIVATE_COMPILE_FLAGS
- ${ABSL_EXCEPTIONS_FLAG}
- EXPORT_NAME
+absl_cc_library(
+ NAME
any
-)
-
-# span library
-absl_header_library(
- TARGET
- absl_span
- PUBLIC_LIBRARIES
+ HDRS
+ "any.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bad_any_cast
+ absl::config
+ absl::core_headers
+ absl::type_traits
absl::utility
- EXPORT_NAME
- span
+ PUBLIC
)
-
-# bad_any_cast library
-list(APPEND BAD_ANY_CAST_SRC
- "bad_any_cast.cc"
- ${TYPES_PUBLIC_HEADERS}
-)
-
-absl_library(
- TARGET
- absl_bad_any_cast
- SOURCES
- ${BAD_ANY_CAST_SRC}
- PUBLIC_LIBRARIES
- EXPORT_NAME
+absl_cc_library(
+ NAME
bad_any_cast
+ HDRS
+ "bad_any_cast.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bad_any_cast_impl
+ absl::config
+ PUBLIC
)
-
-# optional library
-list(APPEND OPTIONAL_SRC
- "optional.cc"
-)
-
-absl_library(
- TARGET
- absl_optional
- SOURCES
- ${OPTIONAL_SRC}
- PUBLIC_LIBRARIES
- absl::bad_optional_access
+absl_cc_library(
+ NAME
+ bad_any_cast_impl
+ SRCS
+ "bad_any_cast.h"
+ "bad_any_cast.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
absl::base
- absl::memory
- absl::meta
- absl::utility
- EXPORT_NAME
- optional
+ absl::config
)
-
-set(BAD_OPTIONAL_ACCESS_SRC "bad_optional_access.cc")
-set(BAD_OPTIONAL_ACCESS_LIBRARIES absl::base)
-
-absl_library(
- TARGET
- absl_bad_optional_access
- SOURCES
- ${BAD_OPTIONAL_ACCESS_SRC}
- PUBLIC_LIBRARIES
- ${BAD_OPTIONAL_ACCESS_PUBLIC_LIBRARIES}
- EXPORT_NAME
- bad_optional_access
-)
-
-# variant library
-absl_library(
- TARGET
- absl_variant
- SOURCES
- "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h"
- PUBLIC_LIBRARIES
- absl::base absl::meta absl::utility
- PRIVATE_COMPILE_FLAGS
- ${ABSL_EXCEPTIONS_FLAG}
- EXPORT_NAME
- variant
-)
-
-#
-## TESTS
-#
-
-
-# test any_test
-set(ANY_TEST_SRC "any_test.cc")
-set(ANY_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::any absl::bad_any_cast test_instance_tracker_lib)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
any_test
- SOURCES
- ${ANY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "any_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::any
+ absl::base
+ absl::config
+ absl::exception_testing
+ absl::test_instance_tracker
+ gmock_main
)
-
-# test any_test_noexceptions
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
any_test_noexceptions
- SOURCES
- ${ANY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "any_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::any
+ absl::base
+ absl::config
+ absl::exception_testing
+ absl::test_instance_tracker
+ gmock_main
)
-# test any_exception_safety_test
-set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
-set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::any
- absl::base
- absl_base_internal_exception_safety_testing
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
any_exception_safety_test
- SOURCES
- ${ANY_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "any_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::any
+ absl::exception_safety_testing
+ gmock_main
)
+absl_cc_library(
+ NAME
+ span
+ HDRS
+ "span.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::algorithm
+ absl::core_headers
+ absl::throw_delegate
+ absl::type_traits
+ PUBLIC
+)
-# test span_test
-set(SPAN_TEST_SRC "span_test.cc")
-set(SPAN_TEST_PUBLIC_LIBRARIES absl::base absl::strings absl::throw_delegate absl::span test_instance_tracker_lib)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
span_test
- SOURCES
- ${SPAN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPAN_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "span_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::span
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::exception_testing
+ absl::fixed_array
+ absl::inlined_vector
+ absl::hash_testing
+ absl::strings
+ gmock_main
)
-
-# test span_test_noexceptions
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
span_test_noexceptions
- SOURCES
- ${SPAN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPAN_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "span_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::span
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::exception_testing
+ absl::fixed_array
+ absl::inlined_vector
+ absl::hash_testing
+ absl::strings
+ gmock_main
)
-
-
-# test optional_test
-set(OPTIONAL_TEST_SRC "optional_test.cc")
-set(OPTIONAL_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::optional absl_bad_optional_access)
-
-absl_test(
- TARGET
- optional_test
- SOURCES
- ${OPTIONAL_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OPTIONAL_TEST_PUBLIC_LIBRARIES}
+absl_cc_library(
+ NAME
+ optional
+ HDRS
+ "optional.h"
+ SRCS
+ "optional.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bad_optional_access
+ absl::config
+ absl::core_headers
+ absl::memory
+ absl::type_traits
+ absl::utility
+ PUBLIC
)
-
-# test optional_exception_safety_test
-set(OPTIONAL_EXCEPTION_SAFETY_TEST_SRC "optional_exception_safety_test.cc")
-set(OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::optional
- absl_base_internal_exception_safety_testing
-)
-
-absl_test(
- TARGET
- optional_exception_safety_test
- SOURCES
- ${OPTIONAL_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+absl_cc_library(
+ NAME
+ bad_optional_access
+ HDRS
+ "bad_optional_access.h"
+ SRCS
+ "bad_optional_access.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ PUBLIC
)
+
+absl_cc_library(
+ NAME
+ bad_variant_access
+ HDRS
+ "bad_variant_access.h"
+ SRCS
+ "bad_variant_access.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ optional_test
+ SRCS
+ "optional_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::optional
+ absl::base
+ absl::config
+ absl::type_traits
+ absl::strings
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ optional_exception_safety_test
+ SRCS
+ "optional_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::optional
+ absl::exception_safety_testing
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ variant
+ HDRS
+ "variant.h"
+ SRCS
+ "internal/variant.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bad_variant_access
+ absl::base_internal
+ absl::config
+ absl::core_headers
+ absl::type_traits
+ absl::utility
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ variant_test
+ SRCS
+ "variant_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::variant
+ absl::config
+ absl::core_headers
+ absl::memory
+ absl::type_traits
+ absl::strings
+ gmock_main
+)
+
+# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8
+if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9)
+absl_cc_test(
+ NAME
+ variant_exception_safety_test
+ SRCS
+ "variant_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::variant
+ absl::config
+ absl::exception_safety_testing
+ absl::memory
+ gmock_main
+)
+endif()
diff --git a/absl/types/any.h b/absl/types/any.h
index a973c6d..f3a3281 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -58,7 +58,7 @@
#ifdef ABSL_HAVE_STD_ANY
-#include <any>
+#include <any> // IWYU pragma: export
namespace absl {
using std::any;
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc
index f9dd8c4..5d7d8a5 100644
--- a/absl/types/any_exception_safety_test.cc
+++ b/absl/types/any_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -135,6 +135,7 @@
EXPECT_TRUE(strong_empty_any_tester.Test(assign_val));
EXPECT_TRUE(strong_empty_any_tester.Test(move));
}
+
// libstdc++ std::any fails this test
#if !defined(ABSL_HAVE_STD_ANY)
TEST(AnyExceptionSafety, Emplace) {
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc
index 115e78d..a6351bf 100644
--- a/absl/types/any_test.cc
+++ b/absl/types/any_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc
index 2e2fd29..505919a 100644
--- a/absl/types/bad_any_cast.cc
+++ b/absl/types/bad_any_cast.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
index 6039013..8d020ed 100644
--- a/absl/types/bad_any_cast.h
+++ b/absl/types/bad_any_cast.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc
index 5587077..a791c7c 100644
--- a/absl/types/bad_optional_access.cc
+++ b/absl/types/bad_optional_access.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
index c6c2746..add5c45 100644
--- a/absl/types/bad_optional_access.h
+++ b/absl/types/bad_optional_access.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc
index d27d775..a4325c8 100644
--- a/absl/types/bad_variant_access.cc
+++ b/absl/types/bad_variant_access.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h
index e7355a5..637db43 100644
--- a/absl/types/bad_variant_access.h
+++ b/absl/types/bad_variant_access.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index eff4fef..5ca66e2 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -1234,23 +1234,29 @@
// Base that is dependent on whether or not the move-assign can be trivial.
template <class... T>
using VariantMoveAssignBase = absl::conditional_t<
- absl::disjunction<absl::conjunction<absl::is_move_assignable<Union<T...>>,
- std::is_move_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<
- std::is_move_constructible<T>...,
- absl::is_move_assignable<T>...>>>::value,
+ absl::disjunction<
+ absl::conjunction<absl::is_move_assignable<Union<T...>>,
+ std::is_move_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<std::is_move_constructible<T>...,
+ // Note: We're not qualifying this with
+ // absl:: because it doesn't compile
+ // under MSVC.
+ is_move_assignable<T>...>>>::value,
VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
// Base that is dependent on whether or not the copy-assign can be trivial.
template <class... T>
using VariantCopyAssignBase = absl::conditional_t<
- absl::disjunction<absl::conjunction<absl::is_copy_assignable<Union<T...>>,
- std::is_copy_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<
- std::is_copy_constructible<T>...,
- absl::is_copy_assignable<T>...>>>::value,
+ absl::disjunction<
+ absl::conjunction<absl::is_copy_assignable<Union<T...>>,
+ std::is_copy_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<std::is_copy_constructible<T>...,
+ // Note: We're not qualifying this with
+ // absl:: because it doesn't compile
+ // under MSVC.
+ is_copy_assignable<T>...>>>::value,
VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
template <class... T>
@@ -1542,8 +1548,8 @@
variant<Types...>* w;
template <std::size_t I>
void operator()(SizeT<I>) const {
- using std::swap;
- swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w));
+ type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v),
+ VariantCoreAccess::Access<I>(*w));
}
void operator()(SizeT<variant_npos>) const {}
@@ -1598,11 +1604,12 @@
template <typename Variant, typename... Ts>
struct VariantHashBase<Variant,
absl::enable_if_t<absl::conjunction<
- type_traits_internal::IsHashEnabled<Ts>...>::value>,
+ type_traits_internal::IsHashable<Ts>...>::value>,
Ts...> {
using argument_type = Variant;
using result_type = size_t;
size_t operator()(const Variant& var) const {
+ type_traits_internal::AssertHashEnabled<Ts...>();
if (var.valueless_by_exception()) {
return 239799884;
}
diff --git a/absl/types/optional.cc b/absl/types/optional.cc
index ef27290..44ff829 100644
--- a/absl/types/optional.cc
+++ b/absl/types/optional.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 1421001..f0ae9a1 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,11 +36,12 @@
#define ABSL_TYPES_OPTIONAL_H_
#include "absl/base/config.h"
+#include "absl/memory/memory.h"
#include "absl/utility/utility.h"
#ifdef ABSL_HAVE_STD_OPTIONAL
-#include <optional>
+#include <optional> // IWYU pragma: export
namespace absl {
using std::bad_optional_access;
@@ -60,7 +61,6 @@
#include <utility>
#include "absl/base/attributes.h"
-#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
#include "absl/types/bad_optional_access.h"
@@ -114,10 +114,6 @@
// need the inline variable support in C++17 for external linkage.
// * Throws `absl::bad_optional_access` instead of
// `std::bad_optional_access`.
-// * `optional::swap()` and `absl::swap()` relies on
-// `std::is_(nothrow_)swappable()`, which has been introduced in C++17.
-// As a workaround, we assume `is_swappable()` is always `true`
-// and `is_nothrow_swappable()` is the same as `std::is_trivial()`.
// * `make_optional()` cannot be declared `constexpr` due to the absence of
// guaranteed copy elision.
// * The move constructor's `noexcept` specification is stronger, i.e. if the
@@ -163,7 +159,7 @@
// This class stores the data in optional<T>.
// It is specialized based on whether T is trivially destructible.
// This is the specialization for non trivially destructible type.
-template <typename T, bool = std::is_trivially_destructible<T>::value>
+template <typename T, bool unused = std::is_trivially_destructible<T>::value>
class optional_data_dtor_base {
struct dummy_type {
static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
@@ -261,10 +257,10 @@
// have trivial move but nontrivial copy.
// Also, we should be checking is_trivially_copyable here, which is not
// supported now, so we use is_trivially_* traits instead.
-template <typename T, bool = absl::is_trivially_copy_constructible<T>::value&&
- absl::is_trivially_copy_assignable<
- typename std::remove_cv<T>::type>::value&&
- std::is_trivially_destructible<T>::value>
+template <typename T,
+ bool unused = absl::is_trivially_copy_constructible<T>::value&&
+ absl::is_trivially_copy_assignable<typename std::remove_cv<
+ T>::type>::value&& std::is_trivially_destructible<T>::value>
class optional_data;
// Trivially copyable types
@@ -295,7 +291,7 @@
optional_data() = default;
- optional_data(const optional_data& rhs) {
+ optional_data(const optional_data& rhs) : optional_data_base<T>() {
if (rhs.engaged_) {
this->construct(rhs.data_);
}
@@ -303,7 +299,8 @@
optional_data(optional_data&& rhs) noexcept(
absl::default_allocator_is_nothrow::value ||
- std::is_nothrow_move_constructible<T>::value) {
+ std::is_nothrow_move_constructible<T>::value)
+ : optional_data_base<T>() {
if (rhs.engaged_) {
this->construct(std::move(rhs.data_));
}
@@ -403,23 +400,24 @@
};
template <typename T>
-constexpr copy_traits get_ctor_copy_traits() {
- return std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : std::is_move_constructible<T>::value ? copy_traits::movable
- : copy_traits::non_movable;
-}
+struct ctor_copy_traits {
+ static constexpr copy_traits traits =
+ std::is_copy_constructible<T>::value
+ ? copy_traits::copyable
+ : std::is_move_constructible<T>::value ? copy_traits::movable
+ : copy_traits::non_movable;
+};
template <typename T>
-constexpr copy_traits get_assign_copy_traits() {
- return absl::is_copy_assignable<T>::value &&
- std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : absl::is_move_assignable<T>::value &&
- std::is_move_constructible<T>::value
- ? copy_traits::movable
- : copy_traits::non_movable;
-}
+struct assign_copy_traits {
+ static constexpr copy_traits traits =
+ absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
+ ? copy_traits::copyable
+ : absl::is_move_assignable<T>::value &&
+ std::is_move_constructible<T>::value
+ ? copy_traits::movable
+ : copy_traits::non_movable;
+};
// Whether T is constructible or convertible from optional<U>.
template <typename T, typename U>
@@ -467,6 +465,7 @@
using argument_type = absl::optional<T>;
using result_type = size_t;
size_t operator()(const absl::optional<T>& opt) const {
+ absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
if (opt) {
return std::hash<absl::remove_const_t<T> >()(*opt);
} else {
@@ -484,9 +483,9 @@
template <typename T>
class optional : private optional_internal::optional_data<T>,
private optional_internal::optional_ctor_base<
- optional_internal::get_ctor_copy_traits<T>()>,
+ optional_internal::ctor_copy_traits<T>::traits>,
private optional_internal::optional_assign_base<
- optional_internal::get_assign_copy_traits<T>()> {
+ optional_internal::assign_copy_traits<T>::traits> {
using data_base = optional_internal::optional_data<T>;
public:
@@ -511,10 +510,11 @@
// the arguments `std::forward<Args>(args)...` within the `optional`.
// (The `in_place_t` is a tag used to indicate that the contained object
// should be constructed in-place.)
- //
- // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE.
- template <typename... Args>
- constexpr explicit optional(in_place_t, Args&&... args)
+ template <typename InPlaceT, typename... Args,
+ absl::enable_if_t<absl::conjunction<
+ std::is_same<InPlaceT, in_place_t>,
+ std::is_constructible<T, Args&&...> >::value>* = nullptr>
+ constexpr explicit optional(InPlaceT, Args&&... args)
: data_base(in_place_t(), absl::forward<Args>(args)...) {}
// Constructs a non-empty `optional` direct-initialized value of type `T` from
@@ -750,11 +750,10 @@
// Swap, standard semantics
void swap(optional& rhs) noexcept(
std::is_nothrow_move_constructible<T>::value&&
- std::is_trivial<T>::value) {
+ type_traits_internal::IsNothrowSwappable<T>::value) {
if (*this) {
if (rhs) {
- using std::swap;
- swap(**this, *rhs);
+ type_traits_internal::Swap(**this, *rhs);
} else {
rhs.construct(std::move(**this));
this->destruct();
@@ -906,12 +905,10 @@
//
// Performs a swap between two `absl::optional` objects, using standard
// semantics.
-//
-// NOTE: we assume `is_swappable()` is always `true`. A compile error will
-// result if this is not the case.
-template <typename T,
- typename std::enable_if<std::is_move_constructible<T>::value,
- bool>::type = false>
+template <typename T, typename std::enable_if<
+ std::is_move_constructible<T>::value &&
+ type_traits_internal::IsSwappable<T>::value,
+ bool>::type = false>
void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc
index d117ee5..aaf8ebc 100644
--- a/absl/types/optional_exception_safety_test.cc
+++ b/absl/types/optional_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
index d90db9f..0665488 100644
--- a/absl/types/optional_test.cc
+++ b/absl/types/optional_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -157,6 +157,16 @@
NonMovable& operator=(NonMovable&&) = delete;
};
+struct NoDefault {
+ NoDefault() = delete;
+ NoDefault(const NoDefault&) {}
+ NoDefault& operator=(const NoDefault&) { return *this; }
+};
+
+struct ConvertsFromInPlaceT {
+ ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT
+};
+
TEST(optionalTest, DefaultConstructor) {
absl::optional<int> empty;
EXPECT_FALSE(empty);
@@ -337,16 +347,18 @@
static_assert((*opt2).x == ConstexprType::kCtorInitializerList, "");
#endif
- // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...>
- // SFINAE is added to optional::optional(absl::in_place_t, Args&&...).
- // struct I {
- // I(absl::in_place_t);
- // };
+ EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
+ absl::in_place_t>::value));
+ EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
+ const absl::in_place_t&>::value));
+ EXPECT_TRUE(
+ (std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
+ absl::in_place_t, absl::in_place_t>::value));
- // EXPECT_FALSE((std::is_constructible<absl::optional<I>,
- // absl::in_place_t>::value));
- // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const
- // absl::in_place_t&>::value));
+ EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>,
+ absl::in_place_t>::value));
+ EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>,
+ absl::in_place_t&&>::value));
}
// template<U=T> optional(U&&);
@@ -1042,9 +1054,9 @@
// test exception throw on value()
absl::optional<int> empty;
#ifdef ABSL_HAVE_EXCEPTIONS
- EXPECT_THROW(empty.value(), absl::bad_optional_access);
+ EXPECT_THROW((void)empty.value(), absl::bad_optional_access);
#else
- EXPECT_DEATH(empty.value(), "Bad optional access");
+ EXPECT_DEATH((void)empty.value(), "Bad optional access");
#endif
// test constexpr value()
@@ -1476,8 +1488,8 @@
TEST(optionalTest, ValueType) {
EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value));
- EXPECT_TRUE(
- (std::is_same<absl::optional<std::string>::value_type, std::string>::value));
+ EXPECT_TRUE((std::is_same<absl::optional<std::string>::value_type,
+ std::string>::value));
EXPECT_FALSE(
(std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value));
}
@@ -1504,18 +1516,19 @@
static_assert(is_hash_enabled_for<absl::optional<int>>::value, "");
static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
+ static_assert(
+ absl::type_traits_internal::IsHashable<absl::optional<int>>::value, "");
+ static_assert(
+ absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value,
+ "");
+ absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>();
+ absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>();
-#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
- _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
- // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
- // static_assert to catch any user-defined type that doesn't provide a hash
- // specialization. So instantiating std::hash<absl::optional<T>> will result
- // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, "");
+ static_assert(!absl::type_traits_internal::IsHashable<
+ absl::optional<NonHashable>>::value,
+ "");
#endif
// libstdc++ std::optional is missing remove_const_t, i.e. it's using
@@ -1623,4 +1636,29 @@
EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value);
}
+#if !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION)
+struct NestedClassBug {
+ struct Inner {
+ bool dummy = false;
+ };
+ absl::optional<Inner> value;
+};
+
+TEST(optionalTest, InPlaceTSFINAEBug) {
+ NestedClassBug b;
+ ((void)b);
+ using Inner = NestedClassBug::Inner;
+
+ EXPECT_TRUE((std::is_default_constructible<Inner>::value));
+ EXPECT_TRUE((std::is_constructible<Inner>::value));
+ EXPECT_TRUE(
+ (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value));
+
+ absl::optional<Inner> o(absl::in_place);
+ EXPECT_TRUE(o.has_value());
+ o.emplace();
+ EXPECT_TRUE(o.has_value());
+}
+#endif // !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION)
+
} // namespace
diff --git a/absl/types/span.h b/absl/types/span.h
index 911af0c..d7f48d9 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -87,7 +87,7 @@
return c.data();
}
-// Before C++17, string::data returns a const char* in all cases.
+// Before C++17, std::string::data returns a const char* in all cases.
inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
int) noexcept {
return &s[0];
@@ -485,6 +485,40 @@
: (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
}
+ // Span::first()
+ //
+ // Returns a `Span` containing first `len` elements. Parameter `len` is of
+ // type `size_type` and thus non-negative. `len` value must be <= size().
+ //
+ // Examples:
+ //
+ // std::vector<int> vec = {10, 11, 12, 13};
+ // absl::MakeSpan(vec).first(1); // {10}
+ // absl::MakeSpan(vec).first(3); // {10, 11, 12}
+ // absl::MakeSpan(vec).first(5); // throws std::out_of_range
+ constexpr Span first(size_type len) const {
+ return (len <= size())
+ ? Span(data(), len)
+ : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+ }
+
+ // Span::last()
+ //
+ // Returns a `Span` containing last `len` elements. Parameter `len` is of
+ // type `size_type` and thus non-negative. `len` value must be <= size().
+ //
+ // Examples:
+ //
+ // std::vector<int> vec = {10, 11, 12, 13};
+ // absl::MakeSpan(vec).last(1); // {13}
+ // absl::MakeSpan(vec).last(3); // {11, 12, 13}
+ // absl::MakeSpan(vec).last(5); // throws std::out_of_range
+ constexpr Span last(size_type len) const {
+ return (len <= size())
+ ? Span(size() - len + data(), len)
+ : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+ }
+
// Support for absl::Hash.
template <typename H>
friend H AbslHashValue(H h, Span v) {
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index bd739ff..9269f91 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -139,8 +139,10 @@
EXPECT_THAT(s_const_abc, SpanIs(abc));
EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value));
- EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value));
- EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value));
+ EXPECT_FALSE(
+ (std::is_constructible<absl::Span<const int>, std::string>::value));
+ EXPECT_TRUE(
+ (std::is_convertible<std::string, absl::Span<const char>>::value));
}
TEST(IntSpan, FromConstPointer) {
@@ -293,6 +295,38 @@
#endif
}
+TEST(IntSpan, First) {
+ std::vector<int> empty;
+ EXPECT_THAT(absl::MakeSpan(empty).first(0), SpanIs(empty));
+
+ auto ramp = MakeRamp(10);
+ EXPECT_THAT(absl::MakeSpan(ramp).first(0), SpanIs(ramp.data(), 0));
+ EXPECT_THAT(absl::MakeSpan(ramp).first(10), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).first(3), SpanIs(ramp.data(), 3));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(absl::MakeSpan(ramp).first(11), std::out_of_range);
+#else
+ EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).first(11), "");
+#endif
+}
+
+TEST(IntSpan, Last) {
+ std::vector<int> empty;
+ EXPECT_THAT(absl::MakeSpan(empty).last(0), SpanIs(empty));
+
+ auto ramp = MakeRamp(10);
+ EXPECT_THAT(absl::MakeSpan(ramp).last(0), SpanIs(ramp.data() + 10, 0));
+ EXPECT_THAT(absl::MakeSpan(ramp).last(10), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).last(3), SpanIs(ramp.data() + 7, 3));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(absl::MakeSpan(ramp).last(11), std::out_of_range);
+#else
+ EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).last(11), "");
+#endif
+}
+
TEST(IntSpan, MakeSpanPtrLength) {
std::vector<int> empty;
auto s_empty = absl::MakeSpan(empty.data(), empty.size());
@@ -767,6 +801,8 @@
ABSL_TEST_CONSTEXPR(span.begin());
ABSL_TEST_CONSTEXPR(span.cbegin());
ABSL_TEST_CONSTEXPR(span.subspan(0, 0));
+ ABSL_TEST_CONSTEXPR(span.first(1));
+ ABSL_TEST_CONSTEXPR(span.last(1));
ABSL_TEST_CONSTEXPR(span[0]);
}
@@ -779,4 +815,19 @@
EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
}
+TEST(Span, Hash) {
+ int array[] = {1, 2, 3, 4};
+ int array2[] = {1, 2, 3};
+ using T = absl::Span<const int>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {// Empties
+ T(), T(nullptr, 0), T(array, 0), T(array2, 0),
+ // Different array with same value
+ T(array, 3), T(array2), T({1, 2, 3}),
+ // Same array, but different length
+ T(array, 1), T(array, 2),
+ // Same length, but different array
+ T(array + 1, 2), T(array + 2, 2)}));
+}
+
} // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 2f78722..ebd52d2 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -47,7 +47,7 @@
#ifdef ABSL_HAVE_STD_VARIANT
-#include <variant>
+#include <variant> // IWYU pragma: export
namespace absl {
using std::bad_variant_access;
@@ -82,7 +82,7 @@
// absl::variant
// -----------------------------------------------------------------------------
//
-// An 'absl::variant` type is a form of type-safe union. An `absl::variant` --
+// An `absl::variant` type is a form of type-safe union. An `absl::variant` --
// except in exceptional cases -- always holds a value of one of its alternative
// types.
//
@@ -129,14 +129,19 @@
// type (in which case, they will be swapped) or to two different types (in
// which case the values will need to be moved).
//
-template <typename... Ts>
+template <
+ typename... Ts,
+ absl::enable_if_t<
+ absl::conjunction<std::is_move_constructible<Ts>...,
+ type_traits_internal::IsSwappable<Ts>...>::value,
+ int> = 0>
void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
v.swap(w);
}
// variant_size
//
-// Returns the number of alterative types available for a given `absl::variant`
+// Returns the number of alternative types available for a given `absl::variant`
// type as a compile-time constant expression. As this is a class template, it
// is not generally useful for accessing the number of alternative types of
// any given `absl::variant` instance.
@@ -399,9 +404,9 @@
// Calls a provided functor on a given set of variants. `absl::visit()` is
// commonly used to conditionally inspect the state of a given variant (or set
// of variants).
-// Requires: The expression in the Effects: element shall be a valid expression
-// of the same type and value category, for all combinations of alternative
-// types of all variants. Otherwise, the program is ill-formed.
+//
+// The functor must return the same type when called with any of the variants'
+// alternatives.
//
// Example:
//
@@ -414,6 +419,7 @@
// };
//
// // Declare our variant, and call `absl::visit()` on it.
+// // Note that `GetVariant()` returns void in either case.
// absl::variant<int, std::string> foo = std::string("foo");
// GetVariant visitor;
// absl::visit(visitor, foo); // Prints `The variant's value is: foo'
@@ -453,7 +459,7 @@
std::is_object<Tn>...>::value,
"Attempted to instantiate a variant containing a non-object "
"type.");
- // Intentionally not qualifing `negation` with `absl::` to work around a bug
+ // Intentionally not qualifying `negation` with `absl::` to work around a bug
// in MSVC 2015 with inline namespace and variadic template.
static_assert(absl::conjunction<negation<std::is_array<T0> >,
negation<std::is_array<Tn> >...>::value,
@@ -561,7 +567,7 @@
// Assignment Operators
- // Copy assignement operator
+ // Copy assignment operator
variant& operator=(const variant& other) = default;
// Move assignment operator
@@ -687,12 +693,12 @@
//
// Swaps the values of two variant objects.
//
- // TODO(calabrese)
- // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()`
- // which is introduced in C++17. So we assume `is_swappable()` is always
- // true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
void swap(variant& rhs) noexcept(
- absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) {
+ absl::conjunction<
+ std::is_nothrow_move_constructible<T0>,
+ std::is_nothrow_move_constructible<Tn>...,
+ type_traits_internal::IsNothrowSwappable<T0>,
+ type_traits_internal::IsNothrowSwappable<Tn>...>::value) {
return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
}
diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc
index 99658ac..a5f5216 100644
--- a/absl/types/variant_benchmark.cc
+++ b/absl/types/variant_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
index 58436f0..76beb59 100644
--- a/absl/types/variant_exception_safety_test.cc
+++ b/absl/types/variant_exception_safety_test.cc
@@ -4,13 +4,14 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+
#include "absl/types/variant.h"
#include <iostream>
@@ -20,9 +21,13 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/exception_safety_testing.h"
#include "absl/memory/memory.h"
+// See comment in absl/base/config.h
+#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
+
namespace absl {
namespace {
@@ -311,6 +316,12 @@
EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
}
{
+ // libstdc++ introduced a regression between 2018-09-25 and 2019-01-06.
+ // The fix is targeted for gcc-9.
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7
+ // https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=267614
+#if !(defined(ABSL_HAVE_STD_VARIANT) && \
+ defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
// - otherwise (index() != j), equivalent to
// emplace<j>(get<j>(std::move(rhs)))
// - If an exception is thrown during the call to Tj's move construction
@@ -326,6 +337,8 @@
auto copy = rhs;
*lhs = std::move(copy);
}));
+#endif // !(defined(ABSL_HAVE_STD_VARIANT) &&
+ // defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
}
}
@@ -506,3 +519,5 @@
} // namespace
} // namespace absl
+
+#endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index bfb8bd7..ab40ed2 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -52,7 +52,7 @@
#endif // ABSL_HAVE_EXCEPTIONS
#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \
- ABSL_VARIANT_TEST_EXPECT_FAIL((__VA_ARGS__), absl::bad_variant_access, \
+ ABSL_VARIANT_TEST_EXPECT_FAIL((void)(__VA_ARGS__), absl::bad_variant_access, \
"Bad variant access")
struct Hashable {};
@@ -257,7 +257,7 @@
// each type.
template <typename T>
class VariantTypesTest : public ::testing::Test {};
-TYPED_TEST_CASE(VariantTypesTest, VariantTypes);
+TYPED_TEST_SUITE(VariantTypesTest, VariantTypes);
////////////////////
// [variant.ctor] //
@@ -484,7 +484,8 @@
}
TEST(VariantTest, InPlaceTypeInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6);
ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
@@ -519,7 +520,8 @@
}
TEST(VariantTest, InPlaceIndexInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6);
ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
@@ -560,8 +562,14 @@
#ifdef ABSL_HAVE_EXCEPTIONS
+// See comment in absl/base/config.h
+#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
+TEST(VariantTest, DISABLED_TestDtorValuelessByException)
+#else
// Test destruction when in the valueless_by_exception state.
-TEST(VariantTest, TestDtorValuelessByException) {
+TEST(VariantTest, TestDtorValuelessByException)
+#endif
+{
int counter = 0;
IncrementInDtor counter_adjuster(&counter);
@@ -826,7 +834,8 @@
}
TEST(VariantTest, TestEmplaceInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
Var v1(absl::in_place_index_t<0>{}, 555);
MoveOnlyWithListConstructor& emplace_result =
@@ -863,7 +872,8 @@
}
TEST(VariantTest, TestEmplaceIndexInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
Var v1(absl::in_place_index_t<0>{}, 555);
MoveOnlyWithListConstructor& emplace_result =
@@ -1301,7 +1311,8 @@
absl::get<std::string>(std::move(v)));
const Var& const_v = v;
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(const_v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<std::string>(const_v));
ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
absl::get<std::string>(std::move(const_v))); // NOLINT
}
@@ -1358,7 +1369,8 @@
EXPECT_EQ(*elem, 0);
{
auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1467,7 +1479,8 @@
}
{
auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1520,7 +1533,8 @@
}
{
auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1723,9 +1737,13 @@
bool operator()(std::string&&) const { return true; } // NOLINT
int operator()(const std::string&, const std::string&) const { return 0; }
- int operator()(const std::string&, std::string&&) const { return 1; } // NOLINT
- int operator()(std::string&&, const std::string&) const { return 2; } // NOLINT
- int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT
+ int operator()(const std::string&, std::string&&) const {
+ return 1;
+ } // NOLINT
+ int operator()(std::string&&, const std::string&) const {
+ return 2;
+ } // NOLINT
+ int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT
};
EXPECT_FALSE(absl::visit(Visitor{}, v));
EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v)));
@@ -1801,9 +1819,9 @@
EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
B(std::unique_ptr<int>(new int(7)))),
::testing::Pair(5, 7));
- EXPECT_THAT(
- absl::visit(Visitor(), A(std::string("BBBBB")), B(absl::string_view("ABC"))),
- ::testing::Pair(5, 3));
+ EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
+ B(absl::string_view("ABC"))),
+ ::testing::Pair(5, 3));
}
TEST(VariantTest, VisitNoArgs) {
@@ -1972,29 +1990,17 @@
}
TEST(VariantTest, Hash) {
- static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, "");
- static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value,
+ static_assert(type_traits_internal::IsHashable<variant<int>>::value, "");
+ static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, "");
+ static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value,
+ "");
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+ static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value,
"");
static_assert(
- type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
-
-#if defined(_MSC_VER) || \
- (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
- _LIBCPP_STD_VER > 11) || \
- defined(__APPLE__)
- // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
- // static_assert to catch any user-defined type T that doesn't provide a hash
- // specialization. So instantiating std::hash<variant<T>> will result
- // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
- static_assert(
- !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
- static_assert(!type_traits_internal::IsHashEnabled<
- variant<Hashable, NonHashable>>::value,
- "");
+ !type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value,
+ "");
#endif
// MSVC std::hash<std::variant> does not use the index, thus produce the same
@@ -2018,11 +2024,10 @@
EXPECT_GT(hashcodes.size(), 90);
// test const-qualified
+ static_assert(type_traits_internal::IsHashable<variant<const int>>::value,
+ "");
static_assert(
- type_traits_internal::IsHashEnabled<variant<const int>>::value, "");
- static_assert(
- type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
- "");
+ type_traits_internal::IsHashable<variant<const Hashable>>::value, "");
std::hash<absl::variant<const int>> c_hash;
for (int i = 0; i < 100; ++i) {
EXPECT_EQ(hash(i), c_hash(i));
@@ -2171,7 +2176,8 @@
// We still need the explicit cast for std::string, because C++ won't apply
// two user-defined implicit conversions in a row.
- EXPECT_TRUE(absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
+ EXPECT_TRUE(
+ absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
}
struct Convertible2;
@@ -2195,7 +2201,8 @@
TEST(VariantTest, TestRvalueConversion) {
variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0)));
+ ConvertVariantTo<variant<double, std::string>>(
+ variant<std::string, int>(0)));
ASSERT_TRUE(absl::holds_alternative<double>(var));
EXPECT_EQ(0.0, absl::get<double>(var));
@@ -2287,7 +2294,8 @@
TEST(VariantTest, TestMoveConversion) {
using Variant =
variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
- using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)}));
@@ -2295,8 +2303,8 @@
ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr);
EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var));
- var =
- ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+ var = ConvertVariantTo<Variant>(
+ OtherVariant(absl::make_unique<std::string>("foo")));
ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var));
EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var));
}
@@ -2307,7 +2315,8 @@
// whether moving or copying has occurred.
using Variant =
variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>;
- using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
Variant v1(std::make_shared<const int>(0));
@@ -2336,7 +2345,8 @@
TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3)));
+ ConvertVariantTo<variant<double, std::string>>(
+ variant<std::string, int>(3)));
EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0));
var = ConvertVariantTo<variant<double, std::string>>(
@@ -2378,7 +2388,8 @@
variant<const char*, float> source2 = "foo";
destination = ConvertVariantTo<variant<double, std::string>>(source2);
- EXPECT_THAT(absl::get_if<std::string>(&destination), Pointee(std::string("foo")));
+ EXPECT_THAT(absl::get_if<std::string>(&destination),
+ Pointee(std::string("foo")));
variant<int, float> source3(42);
variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
@@ -2415,15 +2426,16 @@
TEST(VariantTest, TestMoveConversionViaConvertVariantTo) {
using Variant =
variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
- using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)}));
EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var),
Pointee(Pointee(3)));
- var =
- ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+ var = ConvertVariantTo<Variant>(
+ OtherVariant(absl::make_unique<std::string>("foo")));
EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var),
Pointee(Pointee(std::string("foo"))));
}
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
index c01b49b..5185ccd 100644
--- a/absl/utility/BUILD.bazel
+++ b/absl/utility/BUILD.bazel
@@ -1,5 +1,5 @@
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt
index dc3a631..e1edd19 100644
--- a/absl/utility/CMakeLists.txt
+++ b/absl/utility/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,39 +14,31 @@
# limitations under the License.
#
-
-list(APPEND UTILITY_PUBLIC_HEADERS
- "utility.h"
-)
-
-absl_header_library(
- TARGET
- absl_utility
- PUBLIC_LIBRARIES
- absl::base
- EXPORT_NAME
+absl_cc_library(
+ NAME
utility
+ HDRS
+ "utility.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base_internal
+ absl::config
+ absl::type_traits
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-# test utility_test
-set(UTILITY_TEST_SRC "utility_test.cc")
-set(UTILITY_TEST_PUBLIC_LIBRARIES
- absl::base
- absl::memory
- absl::strings
- absl::utility
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
utility_test
- SOURCES
- ${UTILITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${UTILITY_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "utility_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::utility
+ absl::core_headers
+ absl::memory
+ absl::strings
+ gmock_main
)
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index aef4baa..853c1fb 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,10 +32,9 @@
//
// References:
//
-// http://en.cppreference.com/w/cpp/utility/integer_sequence
-// http://en.cppreference.com/w/cpp/utility/apply
+// https://en.cppreference.com/w/cpp/utility/integer_sequence
+// https://en.cppreference.com/w/cpp/utility/apply
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html
-//
#ifndef ABSL_UTILITY_UTILITY_H_
#define ABSL_UTILITY_UTILITY_H_
@@ -234,25 +233,33 @@
//
// Example:
//
-// class Foo{void Bar(int);};
-// void user_function(int, string);
-// void user_function(std::unique_ptr<Foo>);
+// class Foo {
+// public:
+// void Bar(int);
+// };
+// void user_function1(int, std::string);
+// void user_function2(std::unique_ptr<Foo>);
+// auto user_lambda = [](int, int) {};
//
// int main()
// {
-// std::tuple<int, string> tuple1(42, "bar");
-// // Invokes the user function overload on int, string.
-// absl::apply(&user_function, tuple1);
+// std::tuple<int, std::string> tuple1(42, "bar");
+// // Invokes the first user function on int, std::string.
+// absl::apply(&user_function1, tuple1);
//
-// auto foo = absl::make_unique<Foo>();
-// std::tuple<Foo*, int> tuple2(foo.get(), 42);
-// // Invokes the method Bar on foo with one argument 42.
-// absl::apply(&Foo::Bar, foo.get(), 42);
-//
-// std::tuple<std::unique_ptr<Foo>> tuple3(absl::make_unique<Foo>());
+// std::tuple<std::unique_ptr<Foo>> tuple2(absl::make_unique<Foo>());
// // Invokes the user function that takes ownership of the unique
// // pointer.
-// absl::apply(&user_function, std::move(tuple));
+// absl::apply(&user_function2, std::move(tuple2));
+//
+// auto foo = absl::make_unique<Foo>();
+// std::tuple<Foo*, int> tuple3(foo.get(), 42);
+// // Invokes the method Bar on foo with one argument, 42.
+// absl::apply(&Foo::Bar, tuple3);
+//
+// std::tuple<int, int> tuple4(8, 9);
+// // Invokes a lambda.
+// absl::apply(user_lambda, tuple4);
// }
template <typename Functor, typename Tuple>
auto apply(Functor&& functor, Tuple&& t)
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc
index 3c447b2..5a4972b 100644
--- a/absl/utility/utility_test.cc
+++ b/absl/utility/utility_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -135,7 +135,7 @@
template <typename Tup, size_t... Is>
std::vector<std::string> TupStringVecImpl(const Tup& tup,
- absl::index_sequence<Is...>) {
+ absl::index_sequence<Is...>) {
return {Fmt(std::get<Is>(tup))...};
}
diff --git a/api/array_view.h b/api/array_view.h
index efc642d..bf91484 100644
--- a/api/array_view.h
+++ b/api/array_view.h
@@ -231,6 +231,12 @@
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {}
+ template <
+ typename U,
+ typename std::enable_if<Size == impl::kArrayViewVarSize &&
+ HasDataAndSize<U, T>::value>::type* = nullptr>
+ ArrayView(const U& u) // NOLINT(runtime/explicit)
+ : ArrayView(u.data(), u.size()) {}
// Indexing and iteration. These allow mutation even if the ArrayView is
// const, because the ArrayView doesn't own the array. (To prevent mutation,
diff --git a/api/array_view_unittest.cc b/api/array_view_unittest.cc
index 694ed0b..62b51c0 100644
--- a/api/array_view_unittest.cc
+++ b/api/array_view_unittest.cc
@@ -28,16 +28,21 @@
using ::testing::IsEmpty;
template <typename T>
-void Call(ArrayView<T>) {}
+size_t Call(ArrayView<T> av) {
+ return av.size();
+}
+
+template <typename T, size_t N>
+void CallFixed(ArrayView<T, N> av) {}
} // namespace
TEST(ArrayViewTest, TestConstructFromPtrAndArray) {
char arr[] = "Arrr!";
const char carr[] = "Carrr!";
- Call<const char>(arr);
- Call<const char>(carr);
- Call<char>(arr);
+ EXPECT_EQ(6u, Call<const char>(arr));
+ EXPECT_EQ(7u, Call<const char>(carr));
+ EXPECT_EQ(6u, Call<char>(arr));
// Call<char>(carr); // Compile error, because can't drop const.
// Call<int>(arr); // Compile error, because incompatible types.
ArrayView<int*> x;
@@ -182,6 +187,8 @@
}
TEST(ArrayViewTest, TestStdArray) {
+ EXPECT_EQ(4u, Call<const int>(std::array<int, 4>{1, 2, 3, 4}));
+ CallFixed<const int, 3>(std::array<int, 3>{2, 3, 4});
constexpr size_t size = 5;
std::array<float, size> arr{};
// Fixed size view.
@@ -214,11 +221,12 @@
}
TEST(ArrayViewTest, TestStdVector) {
+ EXPECT_EQ(3u, Call<const int>(std::vector<int>{4, 5, 6}));
std::vector<int> v;
v.push_back(3);
v.push_back(11);
- Call<const int>(v);
- Call<int>(v);
+ EXPECT_EQ(2u, Call<const int>(v));
+ EXPECT_EQ(2u, Call<int>(v));
// Call<unsigned int>(v); // Compile error, because incompatible types.
ArrayView<int> x = v;
EXPECT_EQ(2u, x.size());
@@ -229,7 +237,7 @@
EXPECT_EQ(v.data(), y.data());
// ArrayView<double> d = v; // Compile error, because incompatible types.
const std::vector<int> cv;
- Call<const int>(cv);
+ EXPECT_EQ(0u, Call<const int>(cv));
// Call<int>(cv); // Compile error, because can't drop const.
ArrayView<const int> z = cv;
EXPECT_EQ(0u, z.size());
@@ -239,8 +247,8 @@
TEST(ArrayViewTest, TestRtcBuffer) {
rtc::Buffer b = "so buffer";
- Call<const uint8_t>(b);
- Call<uint8_t>(b);
+ EXPECT_EQ(10u, Call<const uint8_t>(b));
+ EXPECT_EQ(10u, Call<uint8_t>(b));
// Call<int8_t>(b); // Compile error, because incompatible types.
ArrayView<uint8_t> x = b;
EXPECT_EQ(10u, x.size());
@@ -251,7 +259,7 @@
EXPECT_EQ(b.data(), y.data());
// ArrayView<char> d = b; // Compile error, because incompatible types.
const rtc::Buffer cb = "very const";
- Call<const uint8_t>(cb);
+ EXPECT_EQ(11u, Call<const uint8_t>(cb));
// Call<uint8_t>(cb); // Compile error, because can't drop const.
ArrayView<const uint8_t> z = cb;
EXPECT_EQ(11u, z.size());
diff --git a/api/async_resolver_factory.h b/api/async_resolver_factory.h
new file mode 100644
index 0000000..93d3f79
--- /dev/null
+++ b/api/async_resolver_factory.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef API_ASYNC_RESOLVER_FACTORY_H_
+#define API_ASYNC_RESOLVER_FACTORY_H_
+
+#include "rtc_base/async_resolver_interface.h"
+
+namespace webrtc {
+
+// An abstract factory for creating AsyncResolverInterfaces. This allows
+// client applications to provide WebRTC with their own mechanism for
+// performing DNS resolution.
+class AsyncResolverFactory {
+ public:
+ AsyncResolverFactory() = default;
+ virtual ~AsyncResolverFactory() = default;
+
+ // The caller should call Destroy on the returned object to delete it.
+ virtual rtc::AsyncResolverInterface* Create() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_ASYNC_RESOLVER_FACTORY_H_
diff --git a/api/audio/audio_frame.cc b/api/audio/audio_frame.cc
index 75d30b0..1e706b9 100644
--- a/api/audio/audio_frame.cc
+++ b/api/audio/audio_frame.cc
@@ -13,7 +13,7 @@
#include <string.h>
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
diff --git a/api/audio/audio_frame.h b/api/audio/audio_frame.h
index dd6ac02..8f1dc62 100644
--- a/api/audio/audio_frame.h
+++ b/api/audio/audio_frame.h
@@ -14,7 +14,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/api/audio/audio_mixer.h b/api/audio/audio_mixer.h
index 14eefc1..b290cfa 100644
--- a/api/audio/audio_mixer.h
+++ b/api/audio/audio_mixer.h
@@ -14,7 +14,7 @@
#include <memory>
#include "api/audio/audio_frame.h"
-#include "rtc_base/refcount.h"
+#include "rtc_base/ref_count.h"
namespace webrtc {
diff --git a/api/audio/echo_canceller3_config.cc b/api/audio/echo_canceller3_config.cc
index 3eb2a8d..a560c9e 100644
--- a/api/audio/echo_canceller3_config.cc
+++ b/api/audio/echo_canceller3_config.cc
@@ -87,19 +87,11 @@
c->delay.down_sampling_factor = 4;
res = false;
}
- if (c->delay.delay_headroom_blocks <= 1 &&
- c->delay.hysteresis_limit_1_blocks == 1) {
- c->delay.hysteresis_limit_1_blocks = 0;
- res = false;
- }
+
res = res & Limit(&c->delay.default_delay, 0, 5000);
res = res & Limit(&c->delay.num_filters, 0, 5000);
- res = res & Limit(&c->delay.api_call_jitter_blocks, 1, 5000);
- res = res & Limit(&c->delay.min_echo_path_delay_blocks, 0, 5000);
- res = res & Limit(&c->delay.delay_headroom_blocks, 0, 5000);
- res = res & Limit(&c->delay.hysteresis_limit_1_blocks, 0, 5000);
- res = res & Limit(&c->delay.hysteresis_limit_2_blocks, 0, 5000);
- res = res & Limit(&c->delay.skew_hysteresis_blocks, 0, 5000);
+ res = res & Limit(&c->delay.delay_headroom_samples, 0, 5000);
+ res = res & Limit(&c->delay.hysteresis_limit_blocks, 0, 5000);
res = res & Limit(&c->delay.fixed_capture_delay_samples, 0, 5000);
res = res & Limit(&c->delay.delay_estimate_smoothing, 0.f, 1.f);
res = res & Limit(&c->delay.delay_candidate_detection_threshold, 0.f, 1.f);
@@ -150,9 +142,7 @@
}
res = res & Limit(&c->erle.num_sections, 1, c->filter.main.length_blocks);
- res = res & Limit(&c->ep_strength.lf, 0.f, 1000000.f);
- res = res & Limit(&c->ep_strength.mf, 0.f, 1000000.f);
- res = res & Limit(&c->ep_strength.hf, 0.f, 1000000.f);
+ res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
res =
@@ -174,15 +164,6 @@
res = res & Limit(&c->render_levels.poor_excitation_render_limit_ds8, 0.f,
32768.f * 32768.f);
- res =
- res & Limit(&c->echo_removal_control.gain_rampup.initial_gain, 0.f, 1.f);
- res = res & Limit(&c->echo_removal_control.gain_rampup.first_non_zero_gain,
- 0.f, 1.f);
- res = res & Limit(&c->echo_removal_control.gain_rampup.non_zero_gain_blocks,
- 0, 100000);
- res = res &
- Limit(&c->echo_removal_control.gain_rampup.full_gain_blocks, 0, 100000);
-
res = res & Limit(&c->echo_model.noise_floor_hold, 0, 1000);
res = res & Limit(&c->echo_model.min_noise_floor_power, 0, 2000000.f);
res = res & Limit(&c->echo_model.stationary_gate_slope, 0, 1000000.f);
@@ -244,12 +225,6 @@
res = res & Limit(&c->suppressor.floor_first_increase, 0.f, 1000000.f);
- if (c->delay.delay_headroom_blocks >
- c->filter.main_initial.length_blocks - 1) {
- c->delay.delay_headroom_blocks = c->filter.main_initial.length_blocks - 1;
- res = false;
- }
-
return res;
}
} // namespace webrtc
diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h
index ffe17f2..7dcc7dd 100644
--- a/api/audio/echo_canceller3_config.h
+++ b/api/audio/echo_canceller3_config.h
@@ -27,7 +27,6 @@
EchoCanceller3Config(const EchoCanceller3Config& e);
struct Buffering {
- bool use_new_render_buffering = true;
size_t excess_render_detection_interval_blocks = 250;
size_t max_allowed_excess_render_blocks = 8;
} buffering;
@@ -38,12 +37,8 @@
size_t default_delay = 5;
size_t down_sampling_factor = 4;
size_t num_filters = 5;
- size_t api_call_jitter_blocks = 26;
- size_t min_echo_path_delay_blocks = 0;
- size_t delay_headroom_blocks = 2;
- size_t hysteresis_limit_1_blocks = 1;
- size_t hysteresis_limit_2_blocks = 1;
- size_t skew_hysteresis_blocks = 3;
+ size_t delay_headroom_samples = 32;
+ size_t hysteresis_limit_blocks = 1;
size_t fixed_capture_delay_samples = 0;
float delay_estimate_smoothing = 0.7f;
float delay_candidate_detection_threshold = 0.2f;
@@ -91,9 +86,7 @@
} erle;
struct EpStrength {
- float lf = 1.f;
- float mf = 1.f;
- float hf = 1.f;
+ float default_gain = 1.f;
float default_len = 0.83f;
bool reverb_based_on_render = true;
bool echo_can_saturate = true;
@@ -118,12 +111,6 @@
} render_levels;
struct EchoRemovalControl {
- struct GainRampup {
- float initial_gain = 0.0f;
- float first_non_zero_gain = 0.001f;
- int non_zero_gain_blocks = 187;
- int full_gain_blocks = 312;
- } gain_rampup;
bool has_clock_drift = false;
bool linear_and_stable_echo_path = false;
} echo_removal_control;
diff --git a/api/audio/echo_canceller3_config_json.cc b/api/audio/echo_canceller3_config_json.cc
index 01a831c..4c8c8ab 100644
--- a/api/audio/echo_canceller3_config_json.cc
+++ b/api/audio/echo_canceller3_config_json.cc
@@ -9,9 +9,11 @@
*/
#include "api/audio/echo_canceller3_config_json.h"
+#include <stddef.h>
#include <string>
#include <vector>
+#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/json.h"
#include "rtc_base/strings/string_builder.h"
@@ -136,8 +138,6 @@
Json::Value section;
if (rtc::GetValueFromJsonObject(root, "buffering", §ion)) {
- ReadParam(section, "use_new_render_buffering",
- &cfg.buffering.use_new_render_buffering);
ReadParam(section, "excess_render_detection_interval_blocks",
&cfg.buffering.excess_render_detection_interval_blocks);
ReadParam(section, "max_allowed_excess_render_blocks",
@@ -148,18 +148,10 @@
ReadParam(section, "default_delay", &cfg.delay.default_delay);
ReadParam(section, "down_sampling_factor", &cfg.delay.down_sampling_factor);
ReadParam(section, "num_filters", &cfg.delay.num_filters);
- ReadParam(section, "api_call_jitter_blocks",
- &cfg.delay.api_call_jitter_blocks);
- ReadParam(section, "min_echo_path_delay_blocks",
- &cfg.delay.min_echo_path_delay_blocks);
- ReadParam(section, "delay_headroom_blocks",
- &cfg.delay.delay_headroom_blocks);
- ReadParam(section, "hysteresis_limit_1_blocks",
- &cfg.delay.hysteresis_limit_1_blocks);
- ReadParam(section, "hysteresis_limit_2_blocks",
- &cfg.delay.hysteresis_limit_2_blocks);
- ReadParam(section, "skew_hysteresis_blocks",
- &cfg.delay.skew_hysteresis_blocks);
+ ReadParam(section, "delay_headroom_samples",
+ &cfg.delay.delay_headroom_samples);
+ ReadParam(section, "hysteresis_limit_blocks",
+ &cfg.delay.hysteresis_limit_blocks);
ReadParam(section, "fixed_capture_delay_samples",
&cfg.delay.fixed_capture_delay_samples);
ReadParam(section, "delay_estimate_smoothing",
@@ -201,9 +193,7 @@
}
if (rtc::GetValueFromJsonObject(aec3_root, "ep_strength", §ion)) {
- ReadParam(section, "lf", &cfg.ep_strength.lf);
- ReadParam(section, "mf", &cfg.ep_strength.mf);
- ReadParam(section, "hf", &cfg.ep_strength.hf);
+ ReadParam(section, "default_gain", &cfg.ep_strength.default_gain);
ReadParam(section, "default_len", &cfg.ep_strength.default_len);
ReadParam(section, "reverb_based_on_render",
&cfg.ep_strength.reverb_based_on_render);
@@ -241,17 +231,6 @@
if (rtc::GetValueFromJsonObject(aec3_root, "echo_removal_control",
§ion)) {
- Json::Value subsection;
- if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) {
- ReadParam(subsection, "initial_gain",
- &cfg.echo_removal_control.gain_rampup.initial_gain);
- ReadParam(subsection, "first_non_zero_gain",
- &cfg.echo_removal_control.gain_rampup.first_non_zero_gain);
- ReadParam(subsection, "non_zero_gain_blocks",
- &cfg.echo_removal_control.gain_rampup.non_zero_gain_blocks);
- ReadParam(subsection, "full_gain_blocks",
- &cfg.echo_removal_control.gain_rampup.full_gain_blocks);
- }
ReadParam(section, "has_clock_drift",
&cfg.echo_removal_control.has_clock_drift);
ReadParam(section, "linear_and_stable_echo_path",
@@ -352,17 +331,9 @@
ost << "\"down_sampling_factor\": " << config.delay.down_sampling_factor
<< ",";
ost << "\"num_filters\": " << config.delay.num_filters << ",";
- ost << "\"api_call_jitter_blocks\": " << config.delay.api_call_jitter_blocks
+ ost << "\"delay_headroom_samples\": " << config.delay.delay_headroom_samples
<< ",";
- ost << "\"min_echo_path_delay_blocks\": "
- << config.delay.min_echo_path_delay_blocks << ",";
- ost << "\"delay_headroom_blocks\": " << config.delay.delay_headroom_blocks
- << ",";
- ost << "\"hysteresis_limit_1_blocks\": "
- << config.delay.hysteresis_limit_1_blocks << ",";
- ost << "\"hysteresis_limit_2_blocks\": "
- << config.delay.hysteresis_limit_2_blocks << ",";
- ost << "\"skew_hysteresis_blocks\": " << config.delay.skew_hysteresis_blocks
+ ost << "\"hysteresis_limit_blocks\": " << config.delay.hysteresis_limit_blocks
<< ",";
ost << "\"fixed_capture_delay_samples\": "
<< config.delay.fixed_capture_delay_samples << ",";
@@ -431,9 +402,7 @@
ost << "},";
ost << "\"ep_strength\": {";
- ost << "\"lf\": " << config.ep_strength.lf << ",";
- ost << "\"mf\": " << config.ep_strength.mf << ",";
- ost << "\"hf\": " << config.ep_strength.hf << ",";
+ ost << "\"default_gain\": " << config.ep_strength.default_gain << ",";
ost << "\"default_len\": " << config.ep_strength.default_len << ",";
ost << "\"reverb_based_on_render\": "
<< (config.ep_strength.reverb_based_on_render ? "true" : "false") << ",";
@@ -474,16 +443,6 @@
ost << "},";
ost << "\"echo_removal_control\": {";
- ost << "\"gain_rampup\": {";
- ost << "\"initial_gain\": "
- << config.echo_removal_control.gain_rampup.initial_gain << ",";
- ost << "\"first_non_zero_gain\": "
- << config.echo_removal_control.gain_rampup.first_non_zero_gain << ",";
- ost << "\"non_zero_gain_blocks\": "
- << config.echo_removal_control.gain_rampup.non_zero_gain_blocks << ",";
- ost << "\"full_gain_blocks\": "
- << config.echo_removal_control.gain_rampup.full_gain_blocks;
- ost << "},";
ost << "\"has_clock_drift\": "
<< (config.echo_removal_control.has_clock_drift ? "true" : "false")
<< ",";
diff --git a/api/audio_options.cc b/api/audio_options.cc
index e33214b..16c0430 100644
--- a/api/audio_options.cc
+++ b/api/audio_options.cc
@@ -10,6 +10,7 @@
#include "api/audio_options.h"
+#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace cricket {
@@ -51,6 +52,8 @@
change.audio_jitter_buffer_fast_accelerate);
SetFrom(&audio_jitter_buffer_min_delay_ms,
change.audio_jitter_buffer_min_delay_ms);
+ SetFrom(&audio_jitter_buffer_enable_rtx_handling,
+ change.audio_jitter_buffer_enable_rtx_handling);
SetFrom(&typing_detection, change.typing_detection);
SetFrom(&experimental_agc, change.experimental_agc);
SetFrom(&extended_filter_aec, change.extended_filter_aec);
@@ -80,6 +83,8 @@
o.audio_jitter_buffer_fast_accelerate &&
audio_jitter_buffer_min_delay_ms ==
o.audio_jitter_buffer_min_delay_ms &&
+ audio_jitter_buffer_enable_rtx_handling ==
+ o.audio_jitter_buffer_enable_rtx_handling &&
typing_detection == o.typing_detection &&
experimental_agc == o.experimental_agc &&
extended_filter_aec == o.extended_filter_aec &&
@@ -113,6 +118,8 @@
audio_jitter_buffer_fast_accelerate);
ToStringIfSet(&result, "audio_jitter_buffer_min_delay_ms",
audio_jitter_buffer_min_delay_ms);
+ ToStringIfSet(&result, "audio_jitter_buffer_enable_rtx_handling",
+ audio_jitter_buffer_enable_rtx_handling);
ToStringIfSet(&result, "typing", typing_detection);
ToStringIfSet(&result, "experimental_agc", experimental_agc);
ToStringIfSet(&result, "extended_filter_aec", extended_filter_aec);
diff --git a/api/audio_options.h b/api/audio_options.h
index c2d1f44..478bff6 100644
--- a/api/audio_options.h
+++ b/api/audio_options.h
@@ -56,6 +56,8 @@
absl::optional<bool> audio_jitter_buffer_fast_accelerate;
// Audio receiver jitter buffer (NetEq) minimum target delay in milliseconds.
absl::optional<int> audio_jitter_buffer_min_delay_ms;
+ // Audio receiver jitter buffer (NetEq) should handle retransmitted packets.
+ absl::optional<bool> audio_jitter_buffer_enable_rtx_handling;
// Audio processing to detect typing.
absl::optional<bool> typing_detection;
absl::optional<bool> experimental_agc;
diff --git a/api/candidate.cc b/api/candidate.cc
index 275b173..c857f89 100644
--- a/api/candidate.cc
+++ b/api/candidate.cc
@@ -11,7 +11,7 @@
#include "api/candidate.h"
#include "rtc_base/helpers.h"
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
#include "rtc_base/strings/string_builder.h"
namespace cricket {
@@ -125,4 +125,19 @@
return !(*this == o);
}
+Candidate Candidate::ToSanitizedCopy(bool use_hostname_address,
+ bool filter_related_address) const {
+ Candidate copy(*this);
+ if (use_hostname_address) {
+ rtc::SocketAddress hostname_only_addr(address().hostname(),
+ address().port());
+ copy.set_address(hostname_only_addr);
+ }
+ if (filter_related_address) {
+ copy.set_related_address(
+ rtc::EmptySocketAddressWithFamily(copy.address().family()));
+ }
+ return copy;
+}
+
} // namespace cricket
diff --git a/api/candidate.h b/api/candidate.h
index 4c650d9..7452055 100644
--- a/api/candidate.h
+++ b/api/candidate.h
@@ -19,7 +19,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/network_constants.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/system/rtc_export.h"
namespace cricket {
@@ -166,6 +166,16 @@
bool operator==(const Candidate& o) const;
bool operator!=(const Candidate& o) const;
+ // Returns a sanitized copy configured by the given booleans. If
+ // |use_host_address| is true, the returned copy has its IP removed from
+ // |address()|, which leads |address()| to be a hostname address. If
+ // |filter_related_address|, the returned copy has its related address reset
+ // to the wildcard address (i.e. 0.0.0.0 for IPv4 and :: for IPv6). Note that
+ // setting both booleans to false returns an identical copy to the original
+ // candidate.
+ Candidate ToSanitizedCopy(bool use_hostname_address,
+ bool filter_related_address) const;
+
private:
std::string ToStringInternal(bool sensitive) const;
diff --git a/api/create_peerconnection_factory.cc b/api/create_peerconnection_factory.cc
index 1a6d086..0d15e8c 100644
--- a/api/create_peerconnection_factory.cc
+++ b/api/create_peerconnection_factory.cc
@@ -13,104 +13,26 @@
#include <memory>
#include <utility>
-#include "api/call/callfactoryinterface.h"
-#include "api/peerconnectioninterface.h"
+#include "api/audio/audio_mixer.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "api/call/call_factory_interface.h"
+#include "api/fec_controller.h"
+#include "api/peer_connection_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/transport/network_control.h"
#include "api/video_codecs/video_decoder_factory.h"
#include "api/video_codecs/video_encoder_factory.h"
#include "logging/rtc_event_log/rtc_event_log_factory.h"
#include "logging/rtc_event_log/rtc_event_log_factory_interface.h"
-#include "media/engine/webrtcmediaengine.h"
+#include "media/base/media_engine.h"
+#include "media/engine/webrtc_media_engine.h"
#include "modules/audio_device/include/audio_device.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/bind.h"
-#include "rtc_base/scoped_ref_ptr.h"
#include "rtc_base/thread.h"
namespace webrtc {
-#if defined(USE_BUILTIN_SW_CODECS)
-rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory) {
- return CreatePeerConnectionFactoryWithAudioMixer(
- nullptr /*network_thread*/, nullptr /*worker_thread*/,
- nullptr /*signaling_thread*/, nullptr /*default_adm*/,
- audio_encoder_factory, audio_decoder_factory,
- nullptr /*video_encoder_factory*/, nullptr /*video_decoder_factory*/,
- nullptr /*audio_mixer*/);
-}
-
-// Note: all the other CreatePeerConnectionFactory variants just end up calling
-// this, ultimately.
-rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer,
- rtc::scoped_refptr<AudioProcessing> audio_processing) {
- rtc::scoped_refptr<AudioProcessing> audio_processing_use = audio_processing;
- if (!audio_processing_use) {
- audio_processing_use = AudioProcessingBuilder().Create();
- }
-
- std::unique_ptr<cricket::MediaEngineInterface> media_engine(
- cricket::WebRtcMediaEngineFactory::Create(
- default_adm, audio_encoder_factory, audio_decoder_factory,
- video_encoder_factory, video_decoder_factory, audio_mixer,
- audio_processing_use));
-
- std::unique_ptr<CallFactoryInterface> call_factory = CreateCallFactory();
-
- std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory =
- CreateRtcEventLogFactory();
-
- return CreateModularPeerConnectionFactory(
- network_thread, worker_thread, signaling_thread, std::move(media_engine),
- std::move(call_factory), std::move(event_log_factory));
-}
-
-rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer,
- rtc::scoped_refptr<AudioProcessing> audio_processing,
- std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory,
- std::unique_ptr<NetworkControllerFactoryInterface>
- network_controller_factory) {
- rtc::scoped_refptr<AudioProcessing> audio_processing_use = audio_processing;
- if (!audio_processing_use) {
- audio_processing_use = AudioProcessingBuilder().Create();
- }
-
- std::unique_ptr<cricket::MediaEngineInterface> media_engine(
- cricket::WebRtcMediaEngineFactory::Create(
- default_adm, audio_encoder_factory, audio_decoder_factory,
- video_encoder_factory, video_decoder_factory, audio_mixer,
- audio_processing_use));
-
- std::unique_ptr<CallFactoryInterface> call_factory = CreateCallFactory();
-
- std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory =
- CreateRtcEventLogFactory();
-
- return CreateModularPeerConnectionFactory(
- network_thread, worker_thread, signaling_thread, std::move(media_engine),
- std::move(call_factory), std::move(event_log_factory),
- std::move(fec_controller_factory), std::move(network_controller_factory));
-}
-#endif
-
rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
rtc::Thread* network_thread,
rtc::Thread* worker_thread,
@@ -145,38 +67,4 @@
return CreateModularPeerConnectionFactory(std::move(dependencies));
}
-#if defined(USE_BUILTIN_SW_CODECS)
-rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactoryWithAudioMixer(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer) {
- return CreatePeerConnectionFactory(
- network_thread, worker_thread, signaling_thread, default_adm,
- audio_encoder_factory, audio_decoder_factory, video_encoder_factory,
- video_decoder_factory, audio_mixer, nullptr);
-}
-
-rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory) {
- return CreatePeerConnectionFactoryWithAudioMixer(
- network_thread, worker_thread, signaling_thread, default_adm,
- audio_encoder_factory, audio_decoder_factory, video_encoder_factory,
- video_decoder_factory, nullptr);
-}
-#endif
-
} // namespace webrtc
diff --git a/api/create_peerconnection_factory.h b/api/create_peerconnection_factory.h
index baa50c7..40f1276 100644
--- a/api/create_peerconnection_factory.h
+++ b/api/create_peerconnection_factory.h
@@ -17,9 +17,10 @@
#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/audio_codecs/audio_encoder_factory.h"
#include "api/fec_controller.h"
-#include "api/peerconnectioninterface.h"
+#include "api/peer_connection_interface.h"
+#include "api/scoped_refptr.h"
#include "api/transport/network_control.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/deprecation.h"
namespace rtc {
// TODO(bugs.webrtc.org/9987): Move rtc::Thread to api/ or expose a better
@@ -28,104 +29,14 @@
class Thread;
} // namespace rtc
-namespace cricket {
-class WebRtcVideoDecoderFactory;
-class WebRtcVideoEncoderFactory;
-} // namespace cricket
-
namespace webrtc {
class AudioDeviceModule;
class AudioProcessing;
-#if defined(USE_BUILTIN_SW_CODECS)
-// Create a new instance of PeerConnectionFactoryInterface.
-//
-// This method relies on the thread it's called on as the "signaling thread"
-// for the PeerConnectionFactory it creates.
-//
-// As such, if the current thread is not already running an rtc::Thread message
-// loop, an application using this method must eventually either call
-// rtc::Thread::Current()->Run(), or call
-// rtc::Thread::Current()->ProcessMessages() within the application's own
-// message loop.
-RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactory(
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory);
-
-// Create a new instance of PeerConnectionFactoryInterface.
-//
-// |network_thread|, |worker_thread| and |signaling_thread| are
-// the only mandatory parameters.
-//
-// If non-null, a reference is added to |default_adm|, and ownership of
-// |video_encoder_factory| and |video_decoder_factory| is transferred to the
-// returned factory.
-// TODO(deadbeef): Use rtc::scoped_refptr<> and std::unique_ptr<> to make this
-// ownership transfer and ref counting more obvious.
-RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory);
-
-// Create a new instance of PeerConnectionFactoryInterface with optional
-// external audio mixed and audio processing modules.
-//
-// If |audio_mixer| is null, an internal audio mixer will be created and used.
-// If |audio_processing| is null, an internal audio processing module will be
-// created and used.
-RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer,
- rtc::scoped_refptr<AudioProcessing> audio_processing);
-
-// Create a new instance of PeerConnectionFactoryInterface with optional
-// external audio mixer, audio processing, and fec controller modules.
-//
-// If |audio_mixer| is null, an internal audio mixer will be created and used.
-// If |audio_processing| is null, an internal audio processing module will be
-// created and used.
-// If |fec_controller_factory| is null, an internal fec controller module will
-// be created and used.
-// If |network_controller_factory| is provided, it will be used if enabled via
-// field trial.
-RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactory(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer,
- rtc::scoped_refptr<AudioProcessing> audio_processing,
- std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory,
- std::unique_ptr<NetworkControllerFactoryInterface>
- network_controller_factory = nullptr);
-#endif // defined(USE_BUILTIN_SW_CODECS)
-
// Create a new instance of PeerConnectionFactoryInterface with optional video
// codec factories. These video factories represents all video codecs, i.e. no
// extra internal video codecs will be added.
-// When building WebRTC with rtc_use_builtin_sw_codecs = false, this is the
-// only available CreatePeerConnectionFactory overload.
RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(
rtc::Thread* network_thread,
@@ -139,41 +50,6 @@
rtc::scoped_refptr<AudioMixer> audio_mixer,
rtc::scoped_refptr<AudioProcessing> audio_processing);
-#if defined(USE_BUILTIN_SW_CODECS)
-// Create a new instance of PeerConnectionFactoryInterface with external audio
-// mixer.
-//
-// If |audio_mixer| is null, an internal audio mixer will be created and used.
-RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactoryWithAudioMixer(
- rtc::Thread* network_thread,
- rtc::Thread* worker_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
- rtc::scoped_refptr<AudioMixer> audio_mixer);
-
-// Create a new instance of PeerConnectionFactoryInterface.
-// Same thread is used as worker and network thread.
-RTC_EXPORT inline rtc::scoped_refptr<PeerConnectionFactoryInterface>
-CreatePeerConnectionFactory(
- rtc::Thread* worker_and_network_thread,
- rtc::Thread* signaling_thread,
- AudioDeviceModule* default_adm,
- rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
- rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
- cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
- cricket::WebRtcVideoDecoderFactory* video_decoder_factory) {
- return CreatePeerConnectionFactory(
- worker_and_network_thread, worker_and_network_thread, signaling_thread,
- default_adm, audio_encoder_factory, audio_decoder_factory,
- video_encoder_factory, video_decoder_factory);
-}
-#endif // defined(USE_BUILTIN_SW_CODECS)
-
} // namespace webrtc
#endif // API_CREATE_PEERCONNECTION_FACTORY_H_
diff --git a/api/crypto_params.h b/api/crypto_params.h
new file mode 100644
index 0000000..5da352c
--- /dev/null
+++ b/api/crypto_params.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 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.
+ */
+
+#ifndef API_CRYPTO_PARAMS_H_
+#define API_CRYPTO_PARAMS_H_
+
+#include <string>
+
+namespace cricket {
+
+// Parameters for SRTP negotiation, as described in RFC 4568.
+// TODO(benwright) - Rename to SrtpCryptoParams as these only apply to SRTP and
+// not generic crypto parameters for WebRTC.
+struct CryptoParams {
+ CryptoParams() : tag(0) {}
+ CryptoParams(int t,
+ const std::string& cs,
+ const std::string& kp,
+ const std::string& sp)
+ : tag(t), cipher_suite(cs), key_params(kp), session_params(sp) {}
+
+ bool Matches(const CryptoParams& params) const {
+ return (tag == params.tag && cipher_suite == params.cipher_suite);
+ }
+
+ int tag;
+ std::string cipher_suite;
+ std::string key_params;
+ std::string session_params;
+};
+
+} // namespace cricket
+
+#endif // API_CRYPTO_PARAMS_H_
diff --git a/api/data_channel_interface.cc b/api/data_channel_interface.cc
new file mode 100644
index 0000000..240ccbe
--- /dev/null
+++ b/api/data_channel_interface.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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 "api/data_channel_interface.h"
+
+namespace webrtc {
+
+bool DataChannelInterface::ordered() const {
+ return false;
+}
+
+uint16_t DataChannelInterface::maxRetransmitTime() const {
+ return 0;
+}
+
+uint16_t DataChannelInterface::maxRetransmits() const {
+ return 0;
+}
+
+std::string DataChannelInterface::protocol() const {
+ return std::string();
+}
+
+bool DataChannelInterface::negotiated() const {
+ return false;
+}
+
+} // namespace webrtc
diff --git a/api/data_channel_interface.h b/api/data_channel_interface.h
new file mode 100644
index 0000000..91a9804
--- /dev/null
+++ b/api/data_channel_interface.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// This file contains interfaces for DataChannels
+// http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcdatachannel
+
+#ifndef API_DATA_CHANNEL_INTERFACE_H_
+#define API_DATA_CHANNEL_INTERFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/copy_on_write_buffer.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelinit
+// TODO(deadbeef): Use absl::optional for the "-1 if unset" things.
+struct DataChannelInit {
+ // Deprecated. Reliability is assumed, and channel will be unreliable if
+ // maxRetransmitTime or MaxRetransmits is set.
+ bool reliable = false;
+
+ // True if ordered delivery is required.
+ bool ordered = true;
+
+ // The max period of time in milliseconds in which retransmissions will be
+ // sent. After this time, no more retransmissions will be sent. -1 if unset.
+ //
+ // Cannot be set along with |maxRetransmits|.
+ int maxRetransmitTime = -1;
+
+ // The max number of retransmissions. -1 if unset.
+ //
+ // Cannot be set along with |maxRetransmitTime|.
+ int maxRetransmits = -1;
+
+ // This is set by the application and opaque to the WebRTC implementation.
+ std::string protocol;
+
+ // True if the channel has been externally negotiated and we do not send an
+ // in-band signalling in the form of an "open" message. If this is true, |id|
+ // below must be set; otherwise it should be unset and will be negotiated
+ // in-band.
+ bool negotiated = false;
+
+ // The stream id, or SID, for SCTP data channels. -1 if unset (see above).
+ int id = -1;
+};
+
+// At the JavaScript level, data can be passed in as a string or a blob, so
+// this structure's |binary| flag tells whether the data should be interpreted
+// as binary or text.
+struct DataBuffer {
+ DataBuffer(const rtc::CopyOnWriteBuffer& data, bool binary)
+ : data(data), binary(binary) {}
+ // For convenience for unit tests.
+ explicit DataBuffer(const std::string& text)
+ : data(text.data(), text.length()), binary(false) {}
+ size_t size() const { return data.size(); }
+
+ rtc::CopyOnWriteBuffer data;
+ // Indicates if the received data contains UTF-8 or binary data.
+ // Note that the upper layers are left to verify the UTF-8 encoding.
+ // TODO(jiayl): prefer to use an enum instead of a bool.
+ bool binary;
+};
+
+// Used to implement RTCDataChannel events.
+//
+// The code responding to these callbacks should unwind the stack before
+// using any other webrtc APIs; re-entrancy is not supported.
+class DataChannelObserver {
+ public:
+ // The data channel state have changed.
+ virtual void OnStateChange() = 0;
+ // A data buffer was successfully received.
+ virtual void OnMessage(const DataBuffer& buffer) = 0;
+ // The data channel's buffered_amount has changed.
+ virtual void OnBufferedAmountChange(uint64_t previous_amount) {}
+
+ protected:
+ virtual ~DataChannelObserver() = default;
+};
+
+class DataChannelInterface : public rtc::RefCountInterface {
+ public:
+ // C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelstate
+ // Unlikely to change, but keep in sync with DataChannel.java:State and
+ // RTCDataChannel.h:RTCDataChannelState.
+ enum DataState {
+ kConnecting,
+ kOpen, // The DataChannel is ready to send data.
+ kClosing,
+ kClosed
+ };
+
+ static const char* DataStateString(DataState state) {
+ switch (state) {
+ case kConnecting:
+ return "connecting";
+ case kOpen:
+ return "open";
+ case kClosing:
+ return "closing";
+ case kClosed:
+ return "closed";
+ }
+ RTC_CHECK(false) << "Unknown DataChannel state: " << state;
+ return "";
+ }
+
+ // Used to receive events from the data channel. Only one observer can be
+ // registered at a time. UnregisterObserver should be called before the
+ // observer object is destroyed.
+ virtual void RegisterObserver(DataChannelObserver* observer) = 0;
+ virtual void UnregisterObserver() = 0;
+
+ // The label attribute represents a label that can be used to distinguish this
+ // DataChannel object from other DataChannel objects.
+ virtual std::string label() const = 0;
+
+ // The accessors below simply return the properties from the DataChannelInit
+ // the data channel was constructed with.
+ virtual bool reliable() const = 0;
+ // TODO(deadbeef): Remove these dummy implementations when all classes have
+ // implemented these APIs. They should all just return the values the
+ // DataChannel was created with.
+ virtual bool ordered() const;
+ virtual uint16_t maxRetransmitTime() const;
+ virtual uint16_t maxRetransmits() const;
+ virtual std::string protocol() const;
+ virtual bool negotiated() const;
+
+ // Returns the ID from the DataChannelInit, if it was negotiated out-of-band.
+ // If negotiated in-band, this ID will be populated once the DTLS role is
+ // determined, and until then this will return -1.
+ virtual int id() const = 0;
+ virtual DataState state() const = 0;
+ virtual uint32_t messages_sent() const = 0;
+ virtual uint64_t bytes_sent() const = 0;
+ virtual uint32_t messages_received() const = 0;
+ virtual uint64_t bytes_received() const = 0;
+
+ // Returns the number of bytes of application data (UTF-8 text and binary
+ // data) that have been queued using Send but have not yet been processed at
+ // the SCTP level. See comment above Send below.
+ virtual uint64_t buffered_amount() const = 0;
+
+ // Begins the graceful data channel closing procedure. See:
+ // https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.7
+ virtual void Close() = 0;
+
+ // Sends |data| to the remote peer. If the data can't be sent at the SCTP
+ // level (due to congestion control), it's buffered at the data channel level,
+ // up to a maximum of 16MB. If Send is called while this buffer is full, the
+ // data channel will be closed abruptly.
+ //
+ // So, it's important to use buffered_amount() and OnBufferedAmountChange to
+ // ensure the data channel is used efficiently but without filling this
+ // buffer.
+ virtual bool Send(const DataBuffer& buffer) = 0;
+
+ protected:
+ ~DataChannelInterface() override = default;
+};
+
+} // namespace webrtc
+
+#endif // API_DATA_CHANNEL_INTERFACE_H_
diff --git a/api/dtls_transport_interface.h b/api/dtls_transport_interface.h
new file mode 100644
index 0000000..7f35a23
--- /dev/null
+++ b/api/dtls_transport_interface.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef API_DTLS_TRANSPORT_INTERFACE_H_
+#define API_DTLS_TRANSPORT_INTERFACE_H_
+
+#include "api/ice_transport_interface.h"
+#include "api/rtc_error.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// States of a DTLS transport, corresponding to the JS API specification.
+// http://w3c.github.io/webrtc-pc/#dom-rtcdtlstransportstate
+enum class DtlsTransportState {
+ kNew, // Has not started negotiating yet.
+ kConnecting, // In the process of negotiating a secure connection.
+ kConnected, // Completed negotiation and verified fingerprints.
+ kClosed, // Intentionally closed.
+ kFailed, // Failure due to an error or failing to verify a remote
+ // fingerprint.
+ kNumValues
+};
+
+// This object gives snapshot information about the changeable state of a
+// DTLSTransport.
+class DtlsTransportInformation {
+ public:
+ explicit DtlsTransportInformation(DtlsTransportState state) : state_(state) {}
+ DtlsTransportState state() const { return state_; }
+ // TODO(hta): Add remote certificate access
+ private:
+ DtlsTransportState state_;
+};
+
+class DtlsTransportObserverInterface {
+ public:
+ // This callback carries information about the state of the transport.
+ // The argument is a pass-by-value snapshot of the state.
+ virtual void OnStateChange(DtlsTransportInformation info) = 0;
+ // This callback is called when an error occurs, causing the transport
+ // to go to the kFailed state.
+ virtual void OnError(RTCError error) = 0;
+
+ protected:
+ virtual ~DtlsTransportObserverInterface() = default;
+};
+
+// A DTLS transport, as represented to the outside world.
+// This object is created on the network thread, and can only be
+// accessed on that thread, except for functions explicitly marked otherwise.
+// References can be held by other threads, and destruction can therefore
+// be initiated by other threads.
+class DtlsTransportInterface : public rtc::RefCountInterface {
+ public:
+ // Returns a pointer to the ICE transport that is owned by the DTLS transport.
+ virtual rtc::scoped_refptr<IceTransportInterface> ice_transport() = 0;
+ // Returns information on the state of the DtlsTransport.
+ // This function can be called from other threads.
+ virtual DtlsTransportInformation Information() = 0;
+ // Observer management.
+ virtual void RegisterObserver(DtlsTransportObserverInterface* observer) = 0;
+ virtual void UnregisterObserver() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_DTLS_TRANSPORT_INTERFACE_H_
diff --git a/api/dtmf_sender_interface.h b/api/dtmf_sender_interface.h
new file mode 100644
index 0000000..9cdfba1
--- /dev/null
+++ b/api/dtmf_sender_interface.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 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.
+ */
+
+#ifndef API_DTMF_SENDER_INTERFACE_H_
+#define API_DTMF_SENDER_INTERFACE_H_
+
+#include <string>
+
+#include "api/media_stream_interface.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// DtmfSender callback interface, used to implement RTCDtmfSender events.
+// Applications should implement this interface to get notifications from the
+// DtmfSender.
+class DtmfSenderObserverInterface {
+ public:
+ // Triggered when DTMF |tone| is sent.
+ // If |tone| is empty that means the DtmfSender has sent out all the given
+ // tones.
+ // The callback includes the state of the tone buffer at the time when
+ // the tone finished playing.
+ virtual void OnToneChange(const std::string& tone,
+ const std::string& tone_buffer) {}
+ // DEPRECATED: Older API without tone buffer.
+ // TODO(bugs.webrtc.org/9725): Remove old API and default implementation
+ // when old callers are gone.
+ virtual void OnToneChange(const std::string& tone) {}
+
+ protected:
+ virtual ~DtmfSenderObserverInterface() = default;
+};
+
+// The interface of native implementation of the RTCDTMFSender defined by the
+// WebRTC W3C Editor's Draft.
+// See: https://www.w3.org/TR/webrtc/#peer-to-peer-dtmf
+class DtmfSenderInterface : public rtc::RefCountInterface {
+ public:
+ // Used to receive events from the DTMF sender. Only one observer can be
+ // registered at a time. UnregisterObserver should be called before the
+ // observer object is destroyed.
+ virtual void RegisterObserver(DtmfSenderObserverInterface* observer) = 0;
+ virtual void UnregisterObserver() = 0;
+
+ // Returns true if this DtmfSender is capable of sending DTMF. Otherwise
+ // returns false. To be able to send DTMF, the associated RtpSender must be
+ // able to send packets, and a "telephone-event" codec must be negotiated.
+ virtual bool CanInsertDtmf() = 0;
+
+ // Queues a task that sends the DTMF |tones|. The |tones| parameter is treated
+ // as a series of characters. The characters 0 through 9, A through D, #, and
+ // * generate the associated DTMF tones. The characters a to d are equivalent
+ // to A to D. The character ',' indicates a delay of 2 seconds before
+ // processing the next character in the tones parameter.
+ //
+ // Unrecognized characters are ignored.
+ //
+ // The |duration| parameter indicates the duration in ms to use for each
+ // character passed in the |tones| parameter. The duration cannot be more
+ // than 6000 or less than 70.
+ //
+ // The |inter_tone_gap| parameter indicates the gap between tones in ms. The
+ // |inter_tone_gap| must be at least 50 ms but should be as short as
+ // possible.
+ //
+ // If InsertDtmf is called on the same object while an existing task for this
+ // object to generate DTMF is still running, the previous task is canceled.
+ // Returns true on success and false on failure.
+ virtual bool InsertDtmf(const std::string& tones,
+ int duration,
+ int inter_tone_gap) = 0;
+
+ // Returns the tones remaining to be played out.
+ virtual std::string tones() const = 0;
+
+ // Returns the current tone duration value in ms.
+ // This value will be the value last set via the InsertDtmf() method, or the
+ // default value of 100 ms if InsertDtmf() was never called.
+ virtual int duration() const = 0;
+
+ // Returns the current value of the between-tone gap in ms.
+ // This value will be the value last set via the InsertDtmf() method, or the
+ // default value of 50 ms if InsertDtmf() was never called.
+ virtual int inter_tone_gap() const = 0;
+
+ protected:
+ ~DtmfSenderInterface() override = default;
+};
+
+} // namespace webrtc
+
+#endif // API_DTMF_SENDER_INTERFACE_H_
diff --git a/api/ice_transport_factory.cc b/api/ice_transport_factory.cc
new file mode 100644
index 0000000..6cc399a
--- /dev/null
+++ b/api/ice_transport_factory.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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 "api/ice_transport_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "p2p/base/ice_transport_internal.h"
+#include "p2p/base/p2p_transport_channel.h"
+#include "p2p/base/port_allocator.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+
+namespace {
+
+// This implementation of IceTransportInterface is used in cases where
+// the only reference to the P2PTransport will be through this class.
+// It must be constructed, accessed and destroyed on the signaling thread.
+class IceTransportWithTransportChannel : public IceTransportInterface {
+ public:
+ IceTransportWithTransportChannel(
+ std::unique_ptr<cricket::IceTransportInternal> internal)
+ : internal_(std::move(internal)) {}
+
+ ~IceTransportWithTransportChannel() override {
+ RTC_DCHECK_RUN_ON(&thread_checker_);
+ }
+
+ cricket::IceTransportInternal* internal() override {
+ RTC_DCHECK_RUN_ON(&thread_checker_);
+ return internal_.get();
+ }
+
+ private:
+ const rtc::ThreadChecker thread_checker_{};
+ const std::unique_ptr<cricket::IceTransportInternal> internal_
+ RTC_GUARDED_BY(thread_checker_);
+};
+
+} // namespace
+
+rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
+ cricket::PortAllocator* port_allocator) {
+ return new rtc::RefCountedObject<IceTransportWithTransportChannel>(
+ absl::make_unique<cricket::P2PTransportChannel>("", 0, port_allocator));
+}
+
+} // namespace webrtc
diff --git a/api/ice_transport_factory.h b/api/ice_transport_factory.h
new file mode 100644
index 0000000..a8330df
--- /dev/null
+++ b/api/ice_transport_factory.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef API_ICE_TRANSPORT_FACTORY_H_
+#define API_ICE_TRANSPORT_FACTORY_H_
+
+#include "api/ice_transport_interface.h"
+#include "api/scoped_refptr.h"
+
+namespace cricket {
+class PortAllocator;
+}
+
+namespace webrtc {
+
+// Static factory for an IceTransport object that can be created
+// without using a webrtc::PeerConnection.
+// The returned object must be accessed and destroyed on the thread that
+// created it.
+// The PortAllocator must outlive the created IceTransportInterface object.
+rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
+ cricket::PortAllocator* port_allocator);
+
+} // namespace webrtc
+
+#endif // API_ICE_TRANSPORT_FACTORY_H_
diff --git a/api/ice_transport_interface.h b/api/ice_transport_interface.h
new file mode 100644
index 0000000..6e63045
--- /dev/null
+++ b/api/ice_transport_interface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef API_ICE_TRANSPORT_INTERFACE_H_
+#define API_ICE_TRANSPORT_INTERFACE_H_
+
+#include "api/rtc_error.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace cricket {
+class IceTransportInternal;
+} // namespace cricket
+
+namespace webrtc {
+
+// An ICE transport, as represented to the outside world.
+// This object is refcounted, and is therefore alive until the
+// last holder has released it.
+class IceTransportInterface : public rtc::RefCountInterface {
+ public:
+ // Accessor for the internal representation of an ICE transport.
+ // The returned object can only be safely used on the signalling thread.
+ // TODO(crbug.com/907849): Add API calls for the functions that have to
+ // be exposed to clients, and stop allowing access to the
+ // cricket::IceTransportInternal API.
+ virtual cricket::IceTransportInternal* internal() = 0;
+};
+
+} // namespace webrtc
+#endif // API_ICE_TRANSPORT_INTERFACE_H_
diff --git a/api/jsep.h b/api/jsep.h
index 1c50455..6da7827 100644
--- a/api/jsep.h
+++ b/api/jsep.h
@@ -27,8 +27,8 @@
#include <vector>
#include "absl/types/optional.h"
-#include "api/rtcerror.h"
-#include "rtc_base/refcount.h"
+#include "api/rtc_error.h"
+#include "rtc_base/ref_count.h"
#include "rtc_base/system/rtc_export.h"
namespace cricket {
diff --git a/api/jsep_ice_candidate.cc b/api/jsep_ice_candidate.cc
new file mode 100644
index 0000000..59da4e4
--- /dev/null
+++ b/api/jsep_ice_candidate.cc
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018 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 "api/jsep_ice_candidate.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace webrtc {
+
+std::string JsepIceCandidate::sdp_mid() const {
+ return sdp_mid_;
+}
+
+int JsepIceCandidate::sdp_mline_index() const {
+ return sdp_mline_index_;
+}
+
+const cricket::Candidate& JsepIceCandidate::candidate() const {
+ return candidate_;
+}
+
+std::string JsepIceCandidate::server_url() const {
+ return candidate_.url();
+}
+
+JsepCandidateCollection::JsepCandidateCollection() = default;
+
+JsepCandidateCollection::JsepCandidateCollection(JsepCandidateCollection&& o)
+ : candidates_(std::move(o.candidates_)) {}
+
+size_t JsepCandidateCollection::count() const {
+ return candidates_.size();
+}
+
+void JsepCandidateCollection::add(JsepIceCandidate* candidate) {
+ candidates_.push_back(candidate);
+}
+
+const IceCandidateInterface* JsepCandidateCollection::at(size_t index) const {
+ return candidates_[index];
+}
+
+JsepCandidateCollection::~JsepCandidateCollection() {
+ for (std::vector<JsepIceCandidate*>::iterator it = candidates_.begin();
+ it != candidates_.end(); ++it) {
+ delete *it;
+ }
+}
+
+bool JsepCandidateCollection::HasCandidate(
+ const IceCandidateInterface* candidate) const {
+ bool ret = false;
+ for (std::vector<JsepIceCandidate*>::const_iterator it = candidates_.begin();
+ it != candidates_.end(); ++it) {
+ if ((*it)->sdp_mid() == candidate->sdp_mid() &&
+ (*it)->sdp_mline_index() == candidate->sdp_mline_index() &&
+ (*it)->candidate().IsEquivalent(candidate->candidate())) {
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+size_t JsepCandidateCollection::remove(const cricket::Candidate& candidate) {
+ auto iter = std::find_if(candidates_.begin(), candidates_.end(),
+ [candidate](JsepIceCandidate* c) {
+ return candidate.MatchesForRemoval(c->candidate());
+ });
+ if (iter != candidates_.end()) {
+ delete *iter;
+ candidates_.erase(iter);
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/api/jsep_ice_candidate.h b/api/jsep_ice_candidate.h
new file mode 100644
index 0000000..5b22454
--- /dev/null
+++ b/api/jsep_ice_candidate.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// TODO(deadbeef): Move this out of api/; it's an implementation detail and
+// shouldn't be used externally.
+
+#ifndef API_JSEP_ICE_CANDIDATE_H_
+#define API_JSEP_ICE_CANDIDATE_H_
+
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "api/candidate.h"
+#include "api/jsep.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Implementation of IceCandidateInterface.
+class JsepIceCandidate : public IceCandidateInterface {
+ public:
+ JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index);
+ JsepIceCandidate(const std::string& sdp_mid,
+ int sdp_mline_index,
+ const cricket::Candidate& candidate);
+ ~JsepIceCandidate() override;
+ // |err| may be null.
+ bool Initialize(const std::string& sdp, SdpParseError* err);
+ void SetCandidate(const cricket::Candidate& candidate) {
+ candidate_ = candidate;
+ }
+
+ std::string sdp_mid() const override;
+ int sdp_mline_index() const override;
+ const cricket::Candidate& candidate() const override;
+
+ std::string server_url() const override;
+
+ bool ToString(std::string* out) const override;
+
+ private:
+ std::string sdp_mid_;
+ int sdp_mline_index_;
+ cricket::Candidate candidate_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(JsepIceCandidate);
+};
+
+// Implementation of IceCandidateCollection which stores JsepIceCandidates.
+class JsepCandidateCollection : public IceCandidateCollection {
+ public:
+ JsepCandidateCollection();
+ // Move constructor is defined so that a vector of JsepCandidateCollections
+ // can be resized.
+ JsepCandidateCollection(JsepCandidateCollection&& o);
+ ~JsepCandidateCollection() override;
+ size_t count() const override;
+ bool HasCandidate(const IceCandidateInterface* candidate) const override;
+ // Adds and takes ownership of the JsepIceCandidate.
+ // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is
+ // more clear.
+ virtual void add(JsepIceCandidate* candidate);
+ const IceCandidateInterface* at(size_t index) const override;
+ // Removes the candidate that has a matching address and protocol.
+ //
+ // Returns the number of candidates that were removed.
+ size_t remove(const cricket::Candidate& candidate);
+
+ private:
+ std::vector<JsepIceCandidate*> candidates_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(JsepCandidateCollection);
+};
+
+} // namespace webrtc
+
+#endif // API_JSEP_ICE_CANDIDATE_H_
diff --git a/api/jsep_session_description.h b/api/jsep_session_description.h
new file mode 100644
index 0000000..75ae0cd
--- /dev/null
+++ b/api/jsep_session_description.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// TODO(deadbeef): Move this out of api/; it's an implementation detail and
+// shouldn't be used externally.
+
+#ifndef API_JSEP_SESSION_DESCRIPTION_H_
+#define API_JSEP_SESSION_DESCRIPTION_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/candidate.h"
+#include "api/jsep.h"
+#include "api/jsep_ice_candidate.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace cricket {
+class SessionDescription;
+}
+
+namespace webrtc {
+
+// Implementation of SessionDescriptionInterface.
+class JsepSessionDescription : public SessionDescriptionInterface {
+ public:
+ explicit JsepSessionDescription(SdpType type);
+ // TODO(steveanton): Remove this once callers have switched to SdpType.
+ explicit JsepSessionDescription(const std::string& type);
+ JsepSessionDescription(
+ SdpType type,
+ std::unique_ptr<cricket::SessionDescription> description,
+ absl::string_view session_id,
+ absl::string_view session_version);
+ virtual ~JsepSessionDescription();
+
+ // Takes ownership of |description|.
+ // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is
+ // more clear.
+ bool Initialize(cricket::SessionDescription* description,
+ const std::string& session_id,
+ const std::string& session_version);
+
+ virtual cricket::SessionDescription* description() {
+ return description_.get();
+ }
+ virtual const cricket::SessionDescription* description() const {
+ return description_.get();
+ }
+ virtual std::string session_id() const { return session_id_; }
+ virtual std::string session_version() const { return session_version_; }
+ virtual SdpType GetType() const { return type_; }
+ virtual std::string type() const { return SdpTypeToString(type_); }
+ // Allows changing the type. Used for testing.
+ virtual bool AddCandidate(const IceCandidateInterface* candidate);
+ virtual size_t RemoveCandidates(
+ const std::vector<cricket::Candidate>& candidates);
+ virtual size_t number_of_mediasections() const;
+ virtual const IceCandidateCollection* candidates(
+ size_t mediasection_index) const;
+ virtual bool ToString(std::string* out) const;
+
+ static const int kDefaultVideoCodecId;
+ static const char kDefaultVideoCodecName[];
+
+ private:
+ std::unique_ptr<cricket::SessionDescription> description_;
+ std::string session_id_;
+ std::string session_version_;
+ SdpType type_;
+ std::vector<JsepCandidateCollection> candidate_collection_;
+
+ bool GetMediasectionIndex(const IceCandidateInterface* candidate,
+ size_t* index);
+ int GetMediasectionIndex(const cricket::Candidate& candidate);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(JsepSessionDescription);
+};
+
+} // namespace webrtc
+
+#endif // API_JSEP_SESSION_DESCRIPTION_H_
diff --git a/api/media_stream_interface.cc b/api/media_stream_interface.cc
new file mode 100644
index 0000000..cf994cb
--- /dev/null
+++ b/api/media_stream_interface.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 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 "api/media_stream_interface.h"
+
+namespace webrtc {
+
+const char MediaStreamTrackInterface::kVideoKind[] = "video";
+const char MediaStreamTrackInterface::kAudioKind[] = "audio";
+
+VideoTrackInterface::ContentHint VideoTrackInterface::content_hint() const {
+ return ContentHint::kNone;
+}
+
+bool AudioTrackInterface::GetSignalLevel(int* level) {
+ return false;
+}
+
+rtc::scoped_refptr<AudioProcessorInterface>
+AudioTrackInterface::GetAudioProcessor() {
+ return nullptr;
+}
+
+const cricket::AudioOptions AudioSourceInterface::options() const {
+ return {};
+}
+
+double MediaSourceInterface::GetLatency() const {
+ return 0.0;
+}
+
+} // namespace webrtc
diff --git a/api/media_stream_interface.h b/api/media_stream_interface.h
new file mode 100644
index 0000000..1249b85
--- /dev/null
+++ b/api/media_stream_interface.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// This file contains interfaces for MediaStream, MediaTrack and MediaSource.
+// These interfaces are used for implementing MediaStream and MediaTrack as
+// defined in http://dev.w3.org/2011/webrtc/editor/webrtc.html#stream-api. These
+// interfaces must be used only with PeerConnection. PeerConnectionManager
+// interface provides the factory methods to create MediaStream and MediaTracks.
+
+#ifndef API_MEDIA_STREAM_INTERFACE_H_
+#define API_MEDIA_STREAM_INTERFACE_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/audio_options.h"
+#include "api/scoped_refptr.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
+#include "modules/audio_processing/include/audio_processing_statistics.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// Generic observer interface.
+class ObserverInterface {
+ public:
+ virtual void OnChanged() = 0;
+
+ protected:
+ virtual ~ObserverInterface() {}
+};
+
+class NotifierInterface {
+ public:
+ virtual void RegisterObserver(ObserverInterface* observer) = 0;
+ virtual void UnregisterObserver(ObserverInterface* observer) = 0;
+
+ virtual ~NotifierInterface() {}
+};
+
+// Base class for sources. A MediaStreamTrack has an underlying source that
+// provides media. A source can be shared by multiple tracks.
+class MediaSourceInterface : public rtc::RefCountInterface,
+ public NotifierInterface {
+ public:
+ enum SourceState { kInitializing, kLive, kEnded, kMuted };
+
+ virtual SourceState state() const = 0;
+
+ virtual bool remote() const = 0;
+
+ // Sets the minimum latency of the remote source until audio playout. Actual
+ // observered latency may differ depending on the source. |latency| is in the
+ // range of [0.0, 10.0] seconds.
+ // TODO(kuddai) make pure virtual once not only remote tracks support latency.
+ virtual void SetLatency(double latency) {}
+ virtual double GetLatency() const;
+
+ protected:
+ ~MediaSourceInterface() override = default;
+};
+
+// C++ version of MediaStreamTrack.
+// See: https://www.w3.org/TR/mediacapture-streams/#mediastreamtrack
+class MediaStreamTrackInterface : public rtc::RefCountInterface,
+ public NotifierInterface {
+ public:
+ enum TrackState {
+ kLive,
+ kEnded,
+ };
+
+ static const char kAudioKind[];
+ static const char kVideoKind[];
+
+ // The kind() method must return kAudioKind only if the object is a
+ // subclass of AudioTrackInterface, and kVideoKind only if the
+ // object is a subclass of VideoTrackInterface. It is typically used
+ // to protect a static_cast<> to the corresponding subclass.
+ virtual std::string kind() const = 0;
+
+ // Track identifier.
+ virtual std::string id() const = 0;
+
+ // A disabled track will produce silence (if audio) or black frames (if
+ // video). Can be disabled and re-enabled.
+ virtual bool enabled() const = 0;
+ virtual bool set_enabled(bool enable) = 0;
+
+ // Live or ended. A track will never be live again after becoming ended.
+ virtual TrackState state() const = 0;
+
+ protected:
+ ~MediaStreamTrackInterface() override = default;
+};
+
+// VideoTrackSourceInterface is a reference counted source used for
+// VideoTracks. The same source can be used by multiple VideoTracks.
+// VideoTrackSourceInterface is designed to be invoked on the signaling thread
+// except for rtc::VideoSourceInterface<VideoFrame> methods that will be invoked
+// on the worker thread via a VideoTrack. A custom implementation of a source
+// can inherit AdaptedVideoTrackSource instead of directly implementing this
+// interface.
+class VideoTrackSourceInterface : public MediaSourceInterface,
+ public rtc::VideoSourceInterface<VideoFrame> {
+ public:
+ struct Stats {
+ // Original size of captured frame, before video adaptation.
+ int input_width;
+ int input_height;
+ };
+
+ // Indicates that parameters suitable for screencasts should be automatically
+ // applied to RtpSenders.
+ // TODO(perkj): Remove these once all known applications have moved to
+ // explicitly setting suitable parameters for screencasts and don't need this
+ // implicit behavior.
+ virtual bool is_screencast() const = 0;
+
+ // Indicates that the encoder should denoise video before encoding it.
+ // If it is not set, the default configuration is used which is different
+ // depending on video codec.
+ // TODO(perkj): Remove this once denoising is done by the source, and not by
+ // the encoder.
+ virtual absl::optional<bool> needs_denoising() const = 0;
+
+ // Returns false if no stats are available, e.g, for a remote source, or a
+ // source which has not seen its first frame yet.
+ //
+ // Implementation should avoid blocking.
+ virtual bool GetStats(Stats* stats) = 0;
+
+ protected:
+ ~VideoTrackSourceInterface() override = default;
+};
+
+// VideoTrackInterface is designed to be invoked on the signaling thread except
+// for rtc::VideoSourceInterface<VideoFrame> methods that must be invoked
+// on the worker thread.
+// PeerConnectionFactory::CreateVideoTrack can be used for creating a VideoTrack
+// that ensures thread safety and that all methods are called on the right
+// thread.
+class VideoTrackInterface : public MediaStreamTrackInterface,
+ public rtc::VideoSourceInterface<VideoFrame> {
+ public:
+ // Video track content hint, used to override the source is_screencast
+ // property.
+ // See https://crbug.com/653531 and https://w3c.github.io/mst-content-hint.
+ enum class ContentHint { kNone, kFluid, kDetailed, kText };
+
+ // Register a video sink for this track. Used to connect the track to the
+ // underlying video engine.
+ void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
+ const rtc::VideoSinkWants& wants) override {}
+ void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
+
+ virtual VideoTrackSourceInterface* GetSource() const = 0;
+
+ virtual ContentHint content_hint() const;
+ virtual void set_content_hint(ContentHint hint) {}
+
+ protected:
+ ~VideoTrackInterface() override = default;
+};
+
+// Interface for receiving audio data from a AudioTrack.
+class AudioTrackSinkInterface {
+ public:
+ virtual void OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ size_t number_of_channels,
+ size_t number_of_frames) = 0;
+
+ protected:
+ virtual ~AudioTrackSinkInterface() {}
+};
+
+// AudioSourceInterface is a reference counted source used for AudioTracks.
+// The same source can be used by multiple AudioTracks.
+class AudioSourceInterface : public MediaSourceInterface {
+ public:
+ class AudioObserver {
+ public:
+ virtual void OnSetVolume(double volume) = 0;
+
+ protected:
+ virtual ~AudioObserver() {}
+ };
+
+ // TODO(deadbeef): Makes all the interfaces pure virtual after they're
+ // implemented in chromium.
+
+ // Sets the volume of the source. |volume| is in the range of [0, 10].
+ // TODO(tommi): This method should be on the track and ideally volume should
+ // be applied in the track in a way that does not affect clones of the track.
+ virtual void SetVolume(double volume) {}
+
+ // Registers/unregisters observers to the audio source.
+ virtual void RegisterAudioObserver(AudioObserver* observer) {}
+ virtual void UnregisterAudioObserver(AudioObserver* observer) {}
+
+ // TODO(tommi): Make pure virtual.
+ virtual void AddSink(AudioTrackSinkInterface* sink) {}
+ virtual void RemoveSink(AudioTrackSinkInterface* sink) {}
+
+ // Returns options for the AudioSource.
+ // (for some of the settings this approach is broken, e.g. setting
+ // audio network adaptation on the source is the wrong layer of abstraction).
+ virtual const cricket::AudioOptions options() const;
+};
+
+// Interface of the audio processor used by the audio track to collect
+// statistics.
+class AudioProcessorInterface : public rtc::RefCountInterface {
+ public:
+ struct AudioProcessorStatistics {
+ bool typing_noise_detected = false;
+ AudioProcessingStats apm_statistics;
+ };
+
+ // Get audio processor statistics. The |has_remote_tracks| argument should be
+ // set if there are active remote tracks (this would usually be true during
+ // a call). If there are no remote tracks some of the stats will not be set by
+ // the AudioProcessor, because they only make sense if there is at least one
+ // remote track.
+ virtual AudioProcessorStatistics GetStats(bool has_remote_tracks) = 0;
+
+ protected:
+ ~AudioProcessorInterface() override = default;
+};
+
+class AudioTrackInterface : public MediaStreamTrackInterface {
+ public:
+ // TODO(deadbeef): Figure out if the following interface should be const or
+ // not.
+ virtual AudioSourceInterface* GetSource() const = 0;
+
+ // Add/Remove a sink that will receive the audio data from the track.
+ virtual void AddSink(AudioTrackSinkInterface* sink) = 0;
+ virtual void RemoveSink(AudioTrackSinkInterface* sink) = 0;
+
+ // Get the signal level from the audio track.
+ // Return true on success, otherwise false.
+ // TODO(deadbeef): Change the interface to int GetSignalLevel() and pure
+ // virtual after it's implemented in chromium.
+ virtual bool GetSignalLevel(int* level);
+
+ // Get the audio processor used by the audio track. Return null if the track
+ // does not have any processor.
+ // TODO(deadbeef): Make the interface pure virtual.
+ virtual rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor();
+
+ protected:
+ ~AudioTrackInterface() override = default;
+};
+
+typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> > AudioTrackVector;
+typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > VideoTrackVector;
+
+// C++ version of https://www.w3.org/TR/mediacapture-streams/#mediastream.
+//
+// A major difference is that remote audio/video tracks (received by a
+// PeerConnection/RtpReceiver) are not synchronized simply by adding them to
+// the same stream; a session description with the correct "a=msid" attributes
+// must be pushed down.
+//
+// Thus, this interface acts as simply a container for tracks.
+class MediaStreamInterface : public rtc::RefCountInterface,
+ public NotifierInterface {
+ public:
+ virtual std::string id() const = 0;
+
+ virtual AudioTrackVector GetAudioTracks() = 0;
+ virtual VideoTrackVector GetVideoTracks() = 0;
+ virtual rtc::scoped_refptr<AudioTrackInterface> FindAudioTrack(
+ const std::string& track_id) = 0;
+ virtual rtc::scoped_refptr<VideoTrackInterface> FindVideoTrack(
+ const std::string& track_id) = 0;
+
+ virtual bool AddTrack(AudioTrackInterface* track) = 0;
+ virtual bool AddTrack(VideoTrackInterface* track) = 0;
+ virtual bool RemoveTrack(AudioTrackInterface* track) = 0;
+ virtual bool RemoveTrack(VideoTrackInterface* track) = 0;
+
+ protected:
+ ~MediaStreamInterface() override = default;
+};
+
+} // namespace webrtc
+
+#endif // API_MEDIA_STREAM_INTERFACE_H_
diff --git a/api/media_stream_proxy.h b/api/media_stream_proxy.h
new file mode 100644
index 0000000..5169679
--- /dev/null
+++ b/api/media_stream_proxy.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 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.
+ */
+
+#ifndef API_MEDIA_STREAM_PROXY_H_
+#define API_MEDIA_STREAM_PROXY_H_
+
+#include <string>
+
+#include "api/media_stream_interface.h"
+#include "api/proxy.h"
+
+namespace webrtc {
+
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_SIGNALING_PROXY_MAP(MediaStream)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_METHOD0(AudioTrackVector, GetAudioTracks)
+PROXY_METHOD0(VideoTrackVector, GetVideoTracks)
+PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>,
+ FindAudioTrack,
+ const std::string&)
+PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>,
+ FindVideoTrack,
+ const std::string&)
+PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*)
+PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*)
+PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*)
+PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_MEDIA_STREAM_PROXY_H_
diff --git a/api/media_stream_track_proxy.h b/api/media_stream_track_proxy.h
new file mode 100644
index 0000000..d3dc255
--- /dev/null
+++ b/api/media_stream_track_proxy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011 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.
+ */
+
+// This file includes proxy classes for tracks. The purpose is
+// to make sure tracks are only accessed from the signaling thread.
+
+#ifndef API_MEDIA_STREAM_TRACK_PROXY_H_
+#define API_MEDIA_STREAM_TRACK_PROXY_H_
+
+#include <string>
+
+#include "api/media_stream_interface.h"
+#include "api/proxy.h"
+
+namespace webrtc {
+
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+
+BEGIN_SIGNALING_PROXY_MAP(AudioTrack)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, kind)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(TrackState, state)
+PROXY_CONSTMETHOD0(bool, enabled)
+PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource)
+PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*)
+PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*)
+PROXY_METHOD1(bool, GetSignalLevel, int*)
+PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor)
+PROXY_METHOD1(bool, set_enabled, bool)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+END_PROXY_MAP()
+
+BEGIN_PROXY_MAP(VideoTrack)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, kind)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(TrackState, state)
+PROXY_CONSTMETHOD0(bool, enabled)
+PROXY_METHOD1(bool, set_enabled, bool)
+PROXY_CONSTMETHOD0(ContentHint, content_hint)
+PROXY_METHOD1(void, set_content_hint, ContentHint)
+PROXY_WORKER_METHOD2(void,
+ AddOrUpdateSink,
+ rtc::VideoSinkInterface<VideoFrame>*,
+ const rtc::VideoSinkWants&)
+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
+PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource)
+
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_MEDIA_STREAM_TRACK_PROXY_H_
diff --git a/api/media_transport_interface.cc b/api/media_transport_interface.cc
index ef223aa..20bbe26 100644
--- a/api/media_transport_interface.cc
+++ b/api/media_transport_interface.cc
@@ -29,71 +29,9 @@
const MediaTransportSettings&) = default;
MediaTransportSettings::~MediaTransportSettings() = default;
-MediaTransportEncodedAudioFrame::~MediaTransportEncodedAudioFrame() {}
-
-MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame(
- int sampling_rate_hz,
- int starting_sample_index,
- int samples_per_channel,
- int sequence_number,
- FrameType frame_type,
- uint8_t payload_type,
- std::vector<uint8_t> encoded_data)
- : sampling_rate_hz_(sampling_rate_hz),
- starting_sample_index_(starting_sample_index),
- samples_per_channel_(samples_per_channel),
- sequence_number_(sequence_number),
- frame_type_(frame_type),
- payload_type_(payload_type),
- encoded_data_(std::move(encoded_data)) {}
-
-MediaTransportEncodedAudioFrame& MediaTransportEncodedAudioFrame::operator=(
- const MediaTransportEncodedAudioFrame&) = default;
-
-MediaTransportEncodedAudioFrame& MediaTransportEncodedAudioFrame::operator=(
- MediaTransportEncodedAudioFrame&&) = default;
-
-MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame(
- const MediaTransportEncodedAudioFrame&) = default;
-
-MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame(
- MediaTransportEncodedAudioFrame&&) = default;
-
-MediaTransportEncodedVideoFrame::~MediaTransportEncodedVideoFrame() {}
-
-MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame(
- int64_t frame_id,
- std::vector<int64_t> referenced_frame_ids,
- VideoCodecType codec_type,
- const webrtc::EncodedImage& encoded_image)
- : codec_type_(codec_type),
- encoded_image_(encoded_image),
- frame_id_(frame_id),
- referenced_frame_ids_(std::move(referenced_frame_ids)) {}
-
-MediaTransportEncodedVideoFrame& MediaTransportEncodedVideoFrame::operator=(
- const MediaTransportEncodedVideoFrame&) = default;
-
-MediaTransportEncodedVideoFrame& MediaTransportEncodedVideoFrame::operator=(
- MediaTransportEncodedVideoFrame&&) = default;
-
-MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame(
- const MediaTransportEncodedVideoFrame&) = default;
-
-MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame(
- MediaTransportEncodedVideoFrame&&) = default;
SendDataParams::SendDataParams() = default;
-
-RTCErrorOr<std::unique_ptr<MediaTransportInterface>>
-MediaTransportFactory::CreateMediaTransport(
- rtc::PacketTransportInternal* packet_transport,
- rtc::Thread* network_thread,
- bool is_caller) {
- MediaTransportSettings settings;
- settings.is_caller = is_caller;
- return CreateMediaTransport(packet_transport, network_thread, settings);
-}
+SendDataParams::SendDataParams(const SendDataParams&) = default;
RTCErrorOr<std::unique_ptr<MediaTransportInterface>>
MediaTransportFactory::CreateMediaTransport(
@@ -103,22 +41,60 @@
return std::unique_ptr<MediaTransportInterface>(nullptr);
}
+RTCErrorOr<std::unique_ptr<MediaTransportInterface>>
+MediaTransportFactory::CreateMediaTransport(
+ rtc::Thread* network_thread,
+ const MediaTransportSettings& settings) {
+ return std::unique_ptr<MediaTransportInterface>(nullptr);
+}
+
+std::string MediaTransportFactory::GetTransportName() const {
+ return "";
+}
+
+MediaTransportInterface::MediaTransportInterface() = default;
+MediaTransportInterface::~MediaTransportInterface() = default;
+
+absl::optional<std::string>
+MediaTransportInterface::GetTransportParametersOffer() const {
+ return absl::nullopt;
+}
+
+void MediaTransportInterface::Connect(
+ rtc::PacketTransportInternal* packet_transport) {}
+
+void MediaTransportInterface::SetKeyFrameRequestCallback(
+ MediaTransportKeyFrameRequestCallback* callback) {}
+
absl::optional<TargetTransferRate>
MediaTransportInterface::GetLatestTargetTransferRate() {
return absl::nullopt;
}
-void MediaTransportInterface::SetNetworkChangeCallback(
+void MediaTransportInterface::AddNetworkChangeCallback(
MediaTransportNetworkChangeCallback* callback) {}
-void MediaTransportInterface::RemoveTargetTransferRateObserver(
- webrtc::TargetTransferRateObserver* observer) {}
+void MediaTransportInterface::RemoveNetworkChangeCallback(
+ MediaTransportNetworkChangeCallback* callback) {}
+
+void MediaTransportInterface::SetFirstAudioPacketReceivedObserver(
+ AudioPacketReceivedObserver* observer) {}
void MediaTransportInterface::AddTargetTransferRateObserver(
- webrtc::TargetTransferRateObserver* observer) {}
+ TargetTransferRateObserver* observer) {}
+void MediaTransportInterface::RemoveTargetTransferRateObserver(
+ TargetTransferRateObserver* observer) {}
+
+void MediaTransportInterface::AddRttObserver(
+ MediaTransportRttObserver* observer) {}
+void MediaTransportInterface::RemoveRttObserver(
+ MediaTransportRttObserver* observer) {}
size_t MediaTransportInterface::GetAudioPacketOverhead() const {
return 0;
}
+void MediaTransportInterface::SetAllocatedBitrateLimits(
+ const MediaTransportAllocatedBitrateLimits& limits) {}
+
} // namespace webrtc
diff --git a/api/media_transport_interface.h b/api/media_transport_interface.h
index b10dd63..d333bec 100644
--- a/api/media_transport_interface.h
+++ b/api/media_transport_interface.h
@@ -21,14 +21,15 @@
#include <memory>
#include <string>
#include <utility>
-#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
-#include "api/rtcerror.h"
-#include "api/video/encoded_image.h"
-#include "rtc_base/copyonwritebuffer.h"
-#include "rtc_base/networkroute.h"
+#include "api/rtc_error.h"
+#include "api/transport/media/audio_transport.h"
+#include "api/transport/media/video_transport.h"
+#include "api/units/data_rate.h"
+#include "rtc_base/copy_on_write_buffer.h"
+#include "rtc_base/network_route.h"
namespace rtc {
class PacketTransportInternal;
@@ -37,6 +38,23 @@
namespace webrtc {
+class RtcEventLog;
+
+class AudioPacketReceivedObserver {
+ public:
+ virtual ~AudioPacketReceivedObserver() = default;
+
+ // Invoked for the first received audio packet on a given channel id.
+ // It will be invoked once for each channel id.
+ virtual void OnFirstAudioPacketReceived(int64_t channel_id) = 0;
+};
+
+struct MediaTransportAllocatedBitrateLimits {
+ DataRate min_pacing_rate = DataRate::Zero();
+ DataRate max_padding_bitrate = DataRate::Zero();
+ DataRate max_total_allocated_bitrate = DataRate::Zero();
+};
+
// A collection of settings for creation of media transport.
struct MediaTransportSettings final {
MediaTransportSettings();
@@ -52,91 +70,15 @@
// TODO(bugs.webrtc.org/9944): This should become zero buffer in the distant
// future.
absl::optional<std::string> pre_shared_key;
-};
-// Represents encoded audio frame in any encoding (type of encoding is opaque).
-// To avoid copying of encoded data use move semantics when passing by value.
-class MediaTransportEncodedAudioFrame final {
- public:
- enum class FrameType {
- // Normal audio frame (equivalent to webrtc::kAudioFrameSpeech).
- kSpeech,
+ // If present, this is a config passed from the caller to the answerer in the
+ // offer. Each media transport knows how to understand its own parameters.
+ absl::optional<std::string> remote_transport_parameters;
- // DTX frame (equivalent to webrtc::kAudioFrameCN).
- // DTX frame (equivalent to webrtc::kAudioFrameCN).
- kDiscontinuousTransmission,
- // TODO(nisse): Mis-spelled version, update users, then delete.
- kDiscountinuousTransmission = kDiscontinuousTransmission,
- };
-
- MediaTransportEncodedAudioFrame(
- // Audio sampling rate, for example 48000.
- int sampling_rate_hz,
-
- // Starting sample index of the frame, i.e. how many audio samples were
- // before this frame since the beginning of the call or beginning of time
- // in one channel (the starting point should not matter for NetEq). In
- // WebRTC it is used as a timestamp of the frame.
- // TODO(sukhanov): Starting_sample_index is currently adjusted on the
- // receiver side in RTP path. Non-RTP implementations should preserve it.
- // For NetEq initial offset should not matter so we should consider fixing
- // RTP path.
- int starting_sample_index,
-
- // Number of audio samples in audio frame in 1 channel.
- int samples_per_channel,
-
- // Sequence number of the frame in the order sent, it is currently
- // required by NetEq, but we can fix NetEq, because starting_sample_index
- // should be enough.
- int sequence_number,
-
- // If audio frame is a speech or discontinued transmission.
- FrameType frame_type,
-
- // Opaque payload type. In RTP codepath payload type is stored in RTP
- // header. In other implementations it should be simply passed through the
- // wire -- it's needed for decoder.
- uint8_t payload_type,
-
- // Vector with opaque encoded data.
- std::vector<uint8_t> encoded_data);
-
- ~MediaTransportEncodedAudioFrame();
- MediaTransportEncodedAudioFrame(const MediaTransportEncodedAudioFrame&);
- MediaTransportEncodedAudioFrame& operator=(
- const MediaTransportEncodedAudioFrame& other);
- MediaTransportEncodedAudioFrame& operator=(
- MediaTransportEncodedAudioFrame&& other);
- MediaTransportEncodedAudioFrame(MediaTransportEncodedAudioFrame&&);
-
- // Getters.
- int sampling_rate_hz() const { return sampling_rate_hz_; }
- int starting_sample_index() const { return starting_sample_index_; }
- int samples_per_channel() const { return samples_per_channel_; }
- int sequence_number() const { return sequence_number_; }
-
- uint8_t payload_type() const { return payload_type_; }
- FrameType frame_type() const { return frame_type_; }
-
- rtc::ArrayView<const uint8_t> encoded_data() const { return encoded_data_; }
-
- private:
- int sampling_rate_hz_;
- int starting_sample_index_;
- int samples_per_channel_;
-
- // TODO(sukhanov): Refactor NetEq so we don't need sequence number.
- // Having sample_index and samples_per_channel should be enough.
- int sequence_number_;
-
- FrameType frame_type_;
-
- // TODO(sukhanov): Consider enumerating allowed encodings and store enum
- // instead of uint payload_type.
- uint8_t payload_type_;
-
- std::vector<uint8_t> encoded_data_;
+ // If present, provides the event log that media transport should use.
+ // Media transport does not own it. The lifetime of |event_log| will exceed
+ // the lifetime of the instance of MediaTransportInterface instance.
+ RtcEventLog* event_log = nullptr;
};
// Callback to notify about network route changes.
@@ -149,79 +91,6 @@
const rtc::NetworkRoute& new_network_route) = 0;
};
-// Interface for receiving encoded audio frames from MediaTransportInterface
-// implementations.
-class MediaTransportAudioSinkInterface {
- public:
- virtual ~MediaTransportAudioSinkInterface() = default;
-
- // Called when new encoded audio frame is received.
- virtual void OnData(uint64_t channel_id,
- MediaTransportEncodedAudioFrame frame) = 0;
-};
-
-// Represents encoded video frame, along with the codec information.
-class MediaTransportEncodedVideoFrame final {
- public:
- MediaTransportEncodedVideoFrame(int64_t frame_id,
- std::vector<int64_t> referenced_frame_ids,
- VideoCodecType codec_type,
- const webrtc::EncodedImage& encoded_image);
- ~MediaTransportEncodedVideoFrame();
- MediaTransportEncodedVideoFrame(const MediaTransportEncodedVideoFrame&);
- MediaTransportEncodedVideoFrame& operator=(
- const MediaTransportEncodedVideoFrame& other);
- MediaTransportEncodedVideoFrame& operator=(
- MediaTransportEncodedVideoFrame&& other);
- MediaTransportEncodedVideoFrame(MediaTransportEncodedVideoFrame&&);
-
- VideoCodecType codec_type() const { return codec_type_; }
- const webrtc::EncodedImage& encoded_image() const { return encoded_image_; }
-
- int64_t frame_id() const { return frame_id_; }
- const std::vector<int64_t>& referenced_frame_ids() const {
- return referenced_frame_ids_;
- }
-
- private:
- VideoCodecType codec_type_;
-
- // The buffer is not owned by the encoded image by default. On the sender it
- // means that it will need to make a copy of it if it wants to deliver it
- // asynchronously.
- webrtc::EncodedImage encoded_image_;
-
- // Frame id uniquely identifies a frame in a stream. It needs to be unique in
- // a given time window (i.e. technically unique identifier for the lifetime of
- // the connection is not needed, but you need to guarantee that remote side
- // got rid of the previous frame_id if you plan to reuse it).
- //
- // It is required by a remote jitter buffer, and is the same as
- // EncodedFrame::id::picture_id.
- //
- // This data must be opaque to the media transport, and media transport should
- // itself not make any assumptions about what it is and its uniqueness.
- int64_t frame_id_;
-
- // A single frame might depend on other frames. This is set of identifiers on
- // which the current frame depends.
- std::vector<int64_t> referenced_frame_ids_;
-};
-
-// Interface for receiving encoded video frames from MediaTransportInterface
-// implementations.
-class MediaTransportVideoSinkInterface {
- public:
- virtual ~MediaTransportVideoSinkInterface() = default;
-
- // Called when new encoded video frame is received.
- virtual void OnData(uint64_t channel_id,
- MediaTransportEncodedVideoFrame frame) = 0;
-
- // Called when the request for keyframe is received.
- virtual void OnKeyFrameRequested(uint64_t channel_id) = 0;
-};
-
// State of the media transport. Media transport begins in the pending state.
// It transitions to writable when it is ready to send media. It may transition
// back to pending if the connection is blocked. It may transition to closed at
@@ -241,6 +110,19 @@
virtual void OnStateChanged(MediaTransportState state) = 0;
};
+// Callback for RTT measurements on the receive side.
+// TODO(nisse): Related interfaces: CallStatsObserver and RtcpRttStats. It's
+// somewhat unclear what type of measurement is needed. It's used to configure
+// NACK generation and playout buffer. Either raw measurement values or recent
+// maximum would make sense for this use. Need consolidation of RTT signalling.
+class MediaTransportRttObserver {
+ public:
+ virtual ~MediaTransportRttObserver() = default;
+
+ // Invoked when a new RTT measurement is available, typically once per ACK.
+ virtual void OnRttUpdated(int64_t rtt_ms) = 0;
+};
+
// Supported types of application data messages.
enum class DataMessageType {
// Application data buffer with the binary bit unset.
@@ -259,6 +141,7 @@
// unreliable delivery.
struct SendDataParams {
SendDataParams();
+ SendDataParams(const SendDataParams&);
DataMessageType type = DataMessageType::kText;
@@ -305,7 +188,29 @@
// and receiving bandwidth estimate update from congestion control.
class MediaTransportInterface {
public:
- virtual ~MediaTransportInterface() = default;
+ MediaTransportInterface();
+ virtual ~MediaTransportInterface();
+
+ // Retrieves callers config (i.e. media transport offer) that should be passed
+ // to the callee, before the call is connected. Such config is opaque to SDP
+ // (sdp just passes it through). The config is a binary blob, so SDP may
+ // choose to use base64 to serialize it (or any other approach that guarantees
+ // that the binary blob goes through). This should only be called for the
+ // caller's perspective.
+ //
+ // This may return an unset optional, which means that the given media
+ // transport is not supported / disabled and shouldn't be reported in SDP.
+ //
+ // It may also return an empty string, in which case the media transport is
+ // supported, but without any extra settings.
+ // TODO(psla): Make abstract.
+ virtual absl::optional<std::string> GetTransportParametersOffer() const;
+
+ // Connect the media transport to the ICE transport.
+ // The implementation must be able to ignore incoming packets that don't
+ // belong to it.
+ // TODO(psla): Make abstract.
+ virtual void Connect(rtc::PacketTransportInternal* packet_transport);
// Start asynchronous send of audio frame. The status returned by this method
// only pertains to the synchronous operations (e.g.
@@ -321,6 +226,10 @@
uint64_t channel_id,
const MediaTransportEncodedVideoFrame& frame) = 0;
+ // Used by video sender to be notified on key frame requests.
+ virtual void SetKeyFrameRequestCallback(
+ MediaTransportKeyFrameRequestCallback* callback);
+
// Requests a keyframe for the particular channel (stream). The caller should
// check that the keyframe is not present in a jitter buffer already (i.e.
// don't request a keyframe if there is one that you will get from the jitter
@@ -341,12 +250,27 @@
// A newly registered observer will be called back with the latest recorded
// target rate, if available.
virtual void AddTargetTransferRateObserver(
- webrtc::TargetTransferRateObserver* observer);
+ TargetTransferRateObserver* observer);
// Removes an existing |observer| from observers. If observer was never
// registered, an error is logged and method does nothing.
virtual void RemoveTargetTransferRateObserver(
- webrtc::TargetTransferRateObserver* observer);
+ TargetTransferRateObserver* observer);
+
+ // Sets audio packets observer, which gets informed about incoming audio
+ // packets. Before destruction, the observer must be unregistered by setting
+ // nullptr.
+ //
+ // This method may be temporary, when the multiplexer is implemented (or
+ // multiplexer may use it to demultiplex channel ids).
+ virtual void SetFirstAudioPacketReceivedObserver(
+ AudioPacketReceivedObserver* observer);
+
+ // Intended for receive side. AddRttObserver registers an observer to be
+ // called for each RTT measurement, typically once per ACK. Before media
+ // transport is destructed the observer must be unregistered.
+ virtual void AddRttObserver(MediaTransportRttObserver* observer);
+ virtual void RemoveRttObserver(MediaTransportRttObserver* observer);
// Returns the last known target transfer rate as reported to the above
// observers.
@@ -358,12 +282,13 @@
// might not be a very accurate number.
virtual size_t GetAudioPacketOverhead() const;
- // Sets an observer for network change events. If the network route is already
- // established when the callback is set, |callback| will be called immediately
- // with the current network route.
- // Before media transport is destroyed, the callback must be unregistered by
- // setting it to nullptr.
- virtual void SetNetworkChangeCallback(
+ // Registers an observer for network change events. If the network route is
+ // already established when the callback is added, |callback| will be called
+ // immediately with the current network route. Before media transport is
+ // destroyed, the callback must be removed.
+ virtual void AddNetworkChangeCallback(
+ MediaTransportNetworkChangeCallback* callback);
+ virtual void RemoveNetworkChangeCallback(
MediaTransportNetworkChangeCallback* callback);
// Sets a state observer callback. Before media transport is destroyed, the
@@ -373,6 +298,15 @@
virtual void SetMediaTransportStateCallback(
MediaTransportStateCallback* callback) = 0;
+ // Updates allocation limits.
+ // TODO(psla): Make abstract when downstream implementation implement it.
+ virtual void SetAllocatedBitrateLimits(
+ const MediaTransportAllocatedBitrateLimits& limits);
+
+ // Opens a data |channel_id| for sending. May return an error if the
+ // specified |channel_id| is unusable. Must be called before |SendData|.
+ virtual RTCError OpenChannel(int channel_id) = 0;
+
// Sends a data buffer to the remote endpoint using the given send parameters.
// |buffer| may not be larger than 256 KiB. Returns an error if the send
// fails.
@@ -408,21 +342,28 @@
// - Does not take ownership of packet_transport or network_thread.
// - Does not support group calls, in 1:1 call one side must set
// is_caller = true and another is_caller = false.
- // TODO(bugs.webrtc.org/9938) This constructor will be removed and replaced
- // with the one below.
- virtual RTCErrorOr<std::unique_ptr<MediaTransportInterface>>
- CreateMediaTransport(rtc::PacketTransportInternal* packet_transport,
- rtc::Thread* network_thread,
- bool is_caller);
-
- // Creates media transport.
- // - Does not take ownership of packet_transport or network_thread.
- // TODO(bugs.webrtc.org/9938): remove default implementation once all children
- // override it.
virtual RTCErrorOr<std::unique_ptr<MediaTransportInterface>>
CreateMediaTransport(rtc::PacketTransportInternal* packet_transport,
rtc::Thread* network_thread,
const MediaTransportSettings& settings);
+
+ // Creates a new Media Transport in a disconnected state. If the media
+ // transport for the caller is created, one can then call
+ // MediaTransportInterface::GetTransportParametersOffer on that new instance.
+ // TODO(psla): Make abstract.
+ virtual RTCErrorOr<std::unique_ptr<webrtc::MediaTransportInterface>>
+ CreateMediaTransport(rtc::Thread* network_thread,
+ const MediaTransportSettings& settings);
+
+ // Gets a transport name which is supported by the implementation.
+ // Different factories should return different transport names, and at runtime
+ // it will be checked that different names were used.
+ // For example, "rtp" or "generic" may be returned by two different
+ // implementations.
+ // The value returned by this method must never change in the lifetime of the
+ // factory.
+ // TODO(psla): Make abstract.
+ virtual std::string GetTransportName() const;
};
} // namespace webrtc
diff --git a/api/media_types.cc b/api/media_types.cc
new file mode 100644
index 0000000..3359f1d
--- /dev/null
+++ b/api/media_types.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 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 "api/media_types.h"
+
+#include "api/media_stream_interface.h"
+#include "rtc_base/checks.h"
+
+namespace {
+static const char* kMediaTypeData = "data";
+} // namespace
+
+namespace cricket {
+
+std::string MediaTypeToString(MediaType type) {
+ switch (type) {
+ case MEDIA_TYPE_AUDIO:
+ return webrtc::MediaStreamTrackInterface::kAudioKind;
+ case MEDIA_TYPE_VIDEO:
+ return webrtc::MediaStreamTrackInterface::kVideoKind;
+ case MEDIA_TYPE_DATA:
+ return kMediaTypeData;
+ }
+ FATAL();
+ // Not reachable; avoids compile warning.
+ return "";
+}
+
+MediaType MediaTypeFromString(const std::string& type_str) {
+ if (type_str == webrtc::MediaStreamTrackInterface::kAudioKind) {
+ return MEDIA_TYPE_AUDIO;
+ } else if (type_str == webrtc::MediaStreamTrackInterface::kVideoKind) {
+ return MEDIA_TYPE_VIDEO;
+ } else if (type_str == kMediaTypeData) {
+ return MEDIA_TYPE_DATA;
+ }
+ FATAL();
+ // Not reachable; avoids compile warning.
+ return static_cast<MediaType>(-1);
+}
+
+} // namespace cricket
diff --git a/api/media_types.h b/api/media_types.h
new file mode 100644
index 0000000..64e2ebc
--- /dev/null
+++ b/api/media_types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef API_MEDIA_TYPES_H_
+#define API_MEDIA_TYPES_H_
+
+#include <string>
+
+// The cricket and webrtc have separate definitions for what a media type is.
+// They're not compatible. Watch out for this.
+
+namespace cricket {
+
+enum MediaType { MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO, MEDIA_TYPE_DATA };
+
+std::string MediaTypeToString(MediaType type);
+// Aborts on invalid string. Only expected to be used on strings that are
+// guaranteed to be valid, such as MediaStreamTrackInterface::kind().
+MediaType MediaTypeFromString(const std::string& type_str);
+
+} // namespace cricket
+
+namespace webrtc {
+
+enum class MediaType { ANY, AUDIO, VIDEO, DATA };
+
+} // namespace webrtc
+
+#endif // API_MEDIA_TYPES_H_
diff --git a/api/notifier.h b/api/notifier.h
index e5c61c9..c03b104 100644
--- a/api/notifier.h
+++ b/api/notifier.h
@@ -13,7 +13,7 @@
#include <list>
-#include "api/mediastreaminterface.h"
+#include "api/media_stream_interface.h"
#include "rtc_base/checks.h"
namespace webrtc {
diff --git a/api/peer_connection_factory_proxy.h b/api/peer_connection_factory_proxy.h
new file mode 100644
index 0000000..620f1ca
--- /dev/null
+++ b/api/peer_connection_factory_proxy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef API_PEER_CONNECTION_FACTORY_PROXY_H_
+#define API_PEER_CONNECTION_FACTORY_PROXY_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "api/peer_connection_interface.h"
+#include "api/proxy.h"
+#include "rtc_base/bind.h"
+
+namespace webrtc {
+
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_SIGNALING_PROXY_MAP(PeerConnectionFactory)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_METHOD1(void, SetOptions, const Options&)
+PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>,
+ CreatePeerConnection,
+ const PeerConnectionInterface::RTCConfiguration&,
+ std::unique_ptr<cricket::PortAllocator>,
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
+ PeerConnectionObserver*)
+PROXY_METHOD2(rtc::scoped_refptr<PeerConnectionInterface>,
+ CreatePeerConnection,
+ const PeerConnectionInterface::RTCConfiguration&,
+ PeerConnectionDependencies)
+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
+ GetRtpSenderCapabilities,
+ cricket::MediaType)
+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
+ GetRtpReceiverCapabilities,
+ cricket::MediaType)
+PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>,
+ CreateLocalMediaStream,
+ const std::string&)
+PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
+ CreateAudioSource,
+ const cricket::AudioOptions&)
+PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>,
+ CreateVideoTrack,
+ const std::string&,
+ VideoTrackSourceInterface*)
+PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>,
+ CreateAudioTrack,
+ const std::string&,
+ AudioSourceInterface*)
+PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t)
+PROXY_METHOD0(void, StopAecDump)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_PEER_CONNECTION_FACTORY_PROXY_H_
diff --git a/api/peer_connection_interface.cc b/api/peer_connection_interface.cc
new file mode 100644
index 0000000..244ee73
--- /dev/null
+++ b/api/peer_connection_interface.cc
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2018 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 "api/peer_connection_interface.h"
+#include "api/dtls_transport_interface.h"
+#include "api/sctp_transport_interface.h"
+
+namespace webrtc {
+
+PeerConnectionInterface::IceServer::IceServer() = default;
+PeerConnectionInterface::IceServer::IceServer(const IceServer& rhs) = default;
+PeerConnectionInterface::IceServer::~IceServer() = default;
+
+PeerConnectionInterface::RTCConfiguration::RTCConfiguration() = default;
+
+PeerConnectionInterface::RTCConfiguration::RTCConfiguration(
+ const RTCConfiguration& rhs) = default;
+
+PeerConnectionInterface::RTCConfiguration::RTCConfiguration(
+ RTCConfigurationType type) {
+ if (type == RTCConfigurationType::kAggressive) {
+ // These parameters are also defined in Java and IOS configurations,
+ // so their values may be overwritten by the Java or IOS configuration.
+ bundle_policy = kBundlePolicyMaxBundle;
+ rtcp_mux_policy = kRtcpMuxPolicyRequire;
+ ice_connection_receiving_timeout = kAggressiveIceConnectionReceivingTimeout;
+
+ // These parameters are not defined in Java or IOS configuration,
+ // so their values will not be overwritten.
+ enable_ice_renomination = true;
+ redetermine_role_on_ice_restart = false;
+ }
+}
+
+PeerConnectionInterface::RTCConfiguration::~RTCConfiguration() = default;
+
+RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
+PeerConnectionInterface::AddTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids) {
+ return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
+}
+
+bool PeerConnectionInterface::RemoveTrack(RtpSenderInterface* sender) {
+ return RemoveTrackNew(sender).ok();
+}
+
+RTCError PeerConnectionInterface::RemoveTrackNew(
+ rtc::scoped_refptr<RtpSenderInterface> sender) {
+ return RTCError(RemoveTrack(sender) ? RTCErrorType::NONE
+ : RTCErrorType::INTERNAL_ERROR);
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnectionInterface::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnectionInterface::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type,
+ const RtpTransceiverInit& init) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+}
+
+rtc::scoped_refptr<RtpSenderInterface> PeerConnectionInterface::CreateSender(
+ const std::string& kind,
+ const std::string& stream_id) {
+ return rtc::scoped_refptr<RtpSenderInterface>();
+}
+
+std::vector<rtc::scoped_refptr<RtpSenderInterface>>
+PeerConnectionInterface::GetSenders() const {
+ return std::vector<rtc::scoped_refptr<RtpSenderInterface>>();
+}
+
+std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
+PeerConnectionInterface::GetReceivers() const {
+ return std::vector<rtc::scoped_refptr<RtpReceiverInterface>>();
+}
+
+std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnectionInterface::GetTransceivers() const {
+ return std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>();
+}
+
+const SessionDescriptionInterface*
+PeerConnectionInterface::current_local_description() const {
+ return nullptr;
+}
+
+const SessionDescriptionInterface*
+PeerConnectionInterface::current_remote_description() const {
+ return nullptr;
+}
+
+const SessionDescriptionInterface*
+PeerConnectionInterface::pending_local_description() const {
+ return nullptr;
+}
+
+const SessionDescriptionInterface*
+PeerConnectionInterface::pending_remote_description() const {
+ return nullptr;
+}
+
+PeerConnectionInterface::RTCConfiguration
+PeerConnectionInterface::GetConfiguration() {
+ return PeerConnectionInterface::RTCConfiguration();
+}
+
+bool PeerConnectionInterface::SetConfiguration(
+ const PeerConnectionInterface::RTCConfiguration& config,
+ RTCError* error) {
+ return false;
+}
+
+bool PeerConnectionInterface::SetConfiguration(
+ const PeerConnectionInterface::RTCConfiguration& config) {
+ return false;
+}
+
+bool PeerConnectionInterface::RemoveIceCandidates(
+ const std::vector<cricket::Candidate>& candidates) {
+ return false;
+}
+
+RTCError PeerConnectionInterface::SetBitrate(const BitrateSettings& bitrate) {
+ BitrateParameters bitrate_parameters;
+ bitrate_parameters.min_bitrate_bps = bitrate.min_bitrate_bps;
+ bitrate_parameters.current_bitrate_bps = bitrate.start_bitrate_bps;
+ bitrate_parameters.max_bitrate_bps = bitrate.max_bitrate_bps;
+ return SetBitrate(bitrate_parameters);
+}
+
+RTCError PeerConnectionInterface::SetBitrate(
+ const BitrateParameters& bitrate_parameters) {
+ BitrateSettings bitrate;
+ bitrate.min_bitrate_bps = bitrate_parameters.min_bitrate_bps;
+ bitrate.start_bitrate_bps = bitrate_parameters.current_bitrate_bps;
+ bitrate.max_bitrate_bps = bitrate_parameters.max_bitrate_bps;
+ return SetBitrate(bitrate);
+}
+
+PeerConnectionInterface::IceConnectionState
+PeerConnectionInterface::standardized_ice_connection_state() {
+ return PeerConnectionInterface::IceConnectionState::kIceConnectionFailed;
+}
+
+PeerConnectionInterface::PeerConnectionState
+PeerConnectionInterface::peer_connection_state() {
+ return PeerConnectionInterface::PeerConnectionState::kFailed;
+}
+
+bool PeerConnectionInterface::StartRtcEventLog(rtc::PlatformFile file,
+ int64_t max_size_bytes) {
+ return false;
+}
+
+bool PeerConnectionInterface::StartRtcEventLog(
+ std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms) {
+ return false;
+}
+
+rtc::scoped_refptr<DtlsTransportInterface>
+PeerConnectionInterface::LookupDtlsTransportByMid(const std::string& mid) {
+ RTC_NOTREACHED();
+ return nullptr;
+}
+
+rtc::scoped_refptr<SctpTransportInterface>
+PeerConnectionInterface::GetSctpTransport() const {
+ RTC_NOTREACHED();
+ return nullptr;
+}
+
+PeerConnectionInterface::BitrateParameters::BitrateParameters() = default;
+
+PeerConnectionInterface::BitrateParameters::~BitrateParameters() = default;
+
+PeerConnectionDependencies::PeerConnectionDependencies(
+ PeerConnectionObserver* observer_in)
+ : observer(observer_in) {}
+
+PeerConnectionDependencies::PeerConnectionDependencies(
+ PeerConnectionDependencies&&) = default;
+
+PeerConnectionDependencies::~PeerConnectionDependencies() = default;
+
+PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies() =
+ default;
+
+PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies(
+ PeerConnectionFactoryDependencies&&) = default;
+
+PeerConnectionFactoryDependencies::~PeerConnectionFactoryDependencies() =
+ default;
+
+rtc::scoped_refptr<PeerConnectionInterface>
+PeerConnectionFactoryInterface::CreatePeerConnection(
+ const PeerConnectionInterface::RTCConfiguration& configuration,
+ std::unique_ptr<cricket::PortAllocator> allocator,
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
+ PeerConnectionObserver* observer) {
+ return nullptr;
+}
+
+rtc::scoped_refptr<PeerConnectionInterface>
+PeerConnectionFactoryInterface::CreatePeerConnection(
+ const PeerConnectionInterface::RTCConfiguration& configuration,
+ PeerConnectionDependencies dependencies) {
+ return nullptr;
+}
+
+RtpCapabilities PeerConnectionFactoryInterface::GetRtpSenderCapabilities(
+ cricket::MediaType kind) const {
+ return {};
+}
+
+RtpCapabilities PeerConnectionFactoryInterface::GetRtpReceiverCapabilities(
+ cricket::MediaType kind) const {
+ return {};
+}
+
+} // namespace webrtc
diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h
new file mode 100644
index 0000000..1d7f96f
--- /dev/null
+++ b/api/peer_connection_interface.h
@@ -0,0 +1,1437 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// This file contains the PeerConnection interface as defined in
+// https://w3c.github.io/webrtc-pc/#peer-to-peer-connections
+//
+// The PeerConnectionFactory class provides factory methods to create
+// PeerConnection, MediaStream and MediaStreamTrack objects.
+//
+// The following steps are needed to setup a typical call using WebRTC:
+//
+// 1. Create a PeerConnectionFactoryInterface. Check constructors for more
+// information about input parameters.
+//
+// 2. Create a PeerConnection object. Provide a configuration struct which
+// points to STUN and/or TURN servers used to generate ICE candidates, and
+// provide an object that implements the PeerConnectionObserver interface,
+// which is used to receive callbacks from the PeerConnection.
+//
+// 3. Create local MediaStreamTracks using the PeerConnectionFactory and add
+// them to PeerConnection by calling AddTrack (or legacy method, AddStream).
+//
+// 4. Create an offer, call SetLocalDescription with it, serialize it, and send
+// it to the remote peer
+//
+// 5. Once an ICE candidate has been gathered, the PeerConnection will call the
+// observer function OnIceCandidate. The candidates must also be serialized and
+// sent to the remote peer.
+//
+// 6. Once an answer is received from the remote peer, call
+// SetRemoteDescription with the remote answer.
+//
+// 7. Once a remote candidate is received from the remote peer, provide it to
+// the PeerConnection by calling AddIceCandidate.
+//
+// The receiver of a call (assuming the application is "call"-based) can decide
+// to accept or reject the call; this decision will be taken by the application,
+// not the PeerConnection.
+//
+// If the application decides to accept the call, it should:
+//
+// 1. Create PeerConnectionFactoryInterface if it doesn't exist.
+//
+// 2. Create a new PeerConnection.
+//
+// 3. Provide the remote offer to the new PeerConnection object by calling
+// SetRemoteDescription.
+//
+// 4. Generate an answer to the remote offer by calling CreateAnswer and send it
+// back to the remote peer.
+//
+// 5. Provide the local answer to the new PeerConnection by calling
+// SetLocalDescription with the answer.
+//
+// 6. Provide the remote ICE candidates by calling AddIceCandidate.
+//
+// 7. Once a candidate has been gathered, the PeerConnection will call the
+// observer function OnIceCandidate. Send these candidates to the remote peer.
+
+#ifndef API_PEER_CONNECTION_INTERFACE_H_
+#define API_PEER_CONNECTION_INTERFACE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/async_resolver_factory.h"
+#include "api/audio/audio_mixer.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "api/audio_options.h"
+#include "api/call/call_factory_interface.h"
+#include "api/crypto/crypto_options.h"
+#include "api/data_channel_interface.h"
+#include "api/fec_controller.h"
+#include "api/jsep.h"
+#include "api/media_stream_interface.h"
+#include "api/media_transport_interface.h"
+#include "api/rtc_error.h"
+#include "api/rtc_event_log_output.h"
+#include "api/rtp_receiver_interface.h"
+#include "api/rtp_sender_interface.h"
+#include "api/rtp_transceiver_interface.h"
+#include "api/set_remote_description_observer_interface.h"
+#include "api/stats/rtc_stats_collector_callback.h"
+#include "api/stats_types.h"
+#include "api/transport/bitrate_settings.h"
+#include "api/transport/network_control.h"
+#include "api/turn_customizer.h"
+#include "logging/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "media/base/media_config.h"
+// TODO(bugs.webrtc.org/7447): We plan to provide a way to let applications
+// inject a PacketSocketFactory and/or NetworkManager, and not expose
+// PortAllocator in the PeerConnection api.
+#include "media/base/media_engine.h" // nogncheck
+#include "p2p/base/port_allocator.h" // nogncheck
+// TODO(nisse): The interface for bitrate allocation strategy belongs in api/.
+#include "rtc_base/bitrate_allocation_strategy.h"
+#include "rtc_base/network.h"
+#include "rtc_base/platform_file.h"
+#include "rtc_base/rtc_certificate.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_stream_adapter.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace rtc {
+class SSLIdentity;
+class Thread;
+} // namespace rtc
+
+namespace webrtc {
+class AudioDeviceModule;
+class AudioMixer;
+class AudioProcessing;
+class DtlsTransportInterface;
+class SctpTransportInterface;
+class VideoDecoderFactory;
+class VideoEncoderFactory;
+
+// MediaStream container interface.
+class StreamCollectionInterface : public rtc::RefCountInterface {
+ public:
+ // TODO(ronghuawu): Update the function names to c++ style, e.g. find -> Find.
+ virtual size_t count() = 0;
+ virtual MediaStreamInterface* at(size_t index) = 0;
+ virtual MediaStreamInterface* find(const std::string& label) = 0;
+ virtual MediaStreamTrackInterface* FindAudioTrack(const std::string& id) = 0;
+ virtual MediaStreamTrackInterface* FindVideoTrack(const std::string& id) = 0;
+
+ protected:
+ // Dtor protected as objects shouldn't be deleted via this interface.
+ ~StreamCollectionInterface() override = default;
+};
+
+class StatsObserver : public rtc::RefCountInterface {
+ public:
+ virtual void OnComplete(const StatsReports& reports) = 0;
+
+ protected:
+ ~StatsObserver() override = default;
+};
+
+enum class SdpSemantics { kPlanB, kUnifiedPlan };
+
+class PeerConnectionInterface : public rtc::RefCountInterface {
+ public:
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcsignalingstate
+ enum SignalingState {
+ kStable,
+ kHaveLocalOffer,
+ kHaveLocalPrAnswer,
+ kHaveRemoteOffer,
+ kHaveRemotePrAnswer,
+ kClosed,
+ };
+
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcicegatheringstate
+ enum IceGatheringState {
+ kIceGatheringNew,
+ kIceGatheringGathering,
+ kIceGatheringComplete
+ };
+
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectionstate
+ enum class PeerConnectionState {
+ kNew,
+ kConnecting,
+ kConnected,
+ kDisconnected,
+ kFailed,
+ kClosed,
+ };
+
+ // See https://w3c.github.io/webrtc-pc/#dom-rtciceconnectionstate
+ enum IceConnectionState {
+ kIceConnectionNew,
+ kIceConnectionChecking,
+ kIceConnectionConnected,
+ kIceConnectionCompleted,
+ kIceConnectionFailed,
+ kIceConnectionDisconnected,
+ kIceConnectionClosed,
+ kIceConnectionMax,
+ };
+
+ // TLS certificate policy.
+ enum TlsCertPolicy {
+ // For TLS based protocols, ensure the connection is secure by not
+ // circumventing certificate validation.
+ kTlsCertPolicySecure,
+ // For TLS based protocols, disregard security completely by skipping
+ // certificate validation. This is insecure and should never be used unless
+ // security is irrelevant in that particular context.
+ kTlsCertPolicyInsecureNoCheck,
+ };
+
+ struct IceServer {
+ IceServer();
+ IceServer(const IceServer&);
+ ~IceServer();
+
+ // TODO(jbauch): Remove uri when all code using it has switched to urls.
+ // List of URIs associated with this server. Valid formats are described
+ // in RFC7064 and RFC7065, and more may be added in the future. The "host"
+ // part of the URI may contain either an IP address or a hostname.
+ std::string uri;
+ std::vector<std::string> urls;
+ std::string username;
+ std::string password;
+ TlsCertPolicy tls_cert_policy = kTlsCertPolicySecure;
+ // If the URIs in |urls| only contain IP addresses, this field can be used
+ // to indicate the hostname, which may be necessary for TLS (using the SNI
+ // extension). If |urls| itself contains the hostname, this isn't
+ // necessary.
+ std::string hostname;
+ // List of protocols to be used in the TLS ALPN extension.
+ std::vector<std::string> tls_alpn_protocols;
+ // List of elliptic curves to be used in the TLS elliptic curves extension.
+ std::vector<std::string> tls_elliptic_curves;
+
+ bool operator==(const IceServer& o) const {
+ return uri == o.uri && urls == o.urls && username == o.username &&
+ password == o.password && tls_cert_policy == o.tls_cert_policy &&
+ hostname == o.hostname &&
+ tls_alpn_protocols == o.tls_alpn_protocols &&
+ tls_elliptic_curves == o.tls_elliptic_curves;
+ }
+ bool operator!=(const IceServer& o) const { return !(*this == o); }
+ };
+ typedef std::vector<IceServer> IceServers;
+
+ enum IceTransportsType {
+ // TODO(pthatcher): Rename these kTransporTypeXXX, but update
+ // Chromium at the same time.
+ kNone,
+ kRelay,
+ kNoHost,
+ kAll
+ };
+
+ // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1
+ enum BundlePolicy {
+ kBundlePolicyBalanced,
+ kBundlePolicyMaxBundle,
+ kBundlePolicyMaxCompat
+ };
+
+ // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1
+ enum RtcpMuxPolicy {
+ kRtcpMuxPolicyNegotiate,
+ kRtcpMuxPolicyRequire,
+ };
+
+ enum TcpCandidatePolicy {
+ kTcpCandidatePolicyEnabled,
+ kTcpCandidatePolicyDisabled
+ };
+
+ enum CandidateNetworkPolicy {
+ kCandidateNetworkPolicyAll,
+ kCandidateNetworkPolicyLowCost
+ };
+
+ enum ContinualGatheringPolicy { GATHER_ONCE, GATHER_CONTINUALLY };
+
+ enum class RTCConfigurationType {
+ // A configuration that is safer to use, despite not having the best
+ // performance. Currently this is the default configuration.
+ kSafe,
+ // An aggressive configuration that has better performance, although it
+ // may be riskier and may need extra support in the application.
+ kAggressive
+ };
+
+ // TODO(hbos): Change into class with private data and public getters.
+ // TODO(nisse): In particular, accessing fields directly from an
+ // application is brittle, since the organization mirrors the
+ // organization of the implementation, which isn't stable. So we
+ // need getters and setters at least for fields which applications
+ // are interested in.
+ struct RTC_EXPORT RTCConfiguration {
+ // This struct is subject to reorganization, both for naming
+ // consistency, and to group settings to match where they are used
+ // in the implementation. To do that, we need getter and setter
+ // methods for all settings which are of interest to applications,
+ // Chrome in particular.
+
+ RTCConfiguration();
+ RTCConfiguration(const RTCConfiguration&);
+ explicit RTCConfiguration(RTCConfigurationType type);
+ ~RTCConfiguration();
+
+ bool operator==(const RTCConfiguration& o) const;
+ bool operator!=(const RTCConfiguration& o) const;
+
+ bool dscp() const { return media_config.enable_dscp; }
+ void set_dscp(bool enable) { media_config.enable_dscp = enable; }
+
+ bool cpu_adaptation() const {
+ return media_config.video.enable_cpu_adaptation;
+ }
+ void set_cpu_adaptation(bool enable) {
+ media_config.video.enable_cpu_adaptation = enable;
+ }
+
+ bool suspend_below_min_bitrate() const {
+ return media_config.video.suspend_below_min_bitrate;
+ }
+ void set_suspend_below_min_bitrate(bool enable) {
+ media_config.video.suspend_below_min_bitrate = enable;
+ }
+
+ bool prerenderer_smoothing() const {
+ return media_config.video.enable_prerenderer_smoothing;
+ }
+ void set_prerenderer_smoothing(bool enable) {
+ media_config.video.enable_prerenderer_smoothing = enable;
+ }
+
+ bool experiment_cpu_load_estimator() const {
+ return media_config.video.experiment_cpu_load_estimator;
+ }
+ void set_experiment_cpu_load_estimator(bool enable) {
+ media_config.video.experiment_cpu_load_estimator = enable;
+ }
+
+ int audio_rtcp_report_interval_ms() const {
+ return media_config.audio.rtcp_report_interval_ms;
+ }
+ void set_audio_rtcp_report_interval_ms(int audio_rtcp_report_interval_ms) {
+ media_config.audio.rtcp_report_interval_ms =
+ audio_rtcp_report_interval_ms;
+ }
+
+ int video_rtcp_report_interval_ms() const {
+ return media_config.video.rtcp_report_interval_ms;
+ }
+ void set_video_rtcp_report_interval_ms(int video_rtcp_report_interval_ms) {
+ media_config.video.rtcp_report_interval_ms =
+ video_rtcp_report_interval_ms;
+ }
+
+ static const int kUndefined = -1;
+ // Default maximum number of packets in the audio jitter buffer.
+ static const int kAudioJitterBufferMaxPackets = 200;
+ // ICE connection receiving timeout for aggressive configuration.
+ static const int kAggressiveIceConnectionReceivingTimeout = 1000;
+
+ ////////////////////////////////////////////////////////////////////////
+ // The below few fields mirror the standard RTCConfiguration dictionary:
+ // https://w3c.github.io/webrtc-pc/#rtcconfiguration-dictionary
+ ////////////////////////////////////////////////////////////////////////
+
+ // TODO(pthatcher): Rename this ice_servers, but update Chromium
+ // at the same time.
+ IceServers servers;
+ // TODO(pthatcher): Rename this ice_transport_type, but update
+ // Chromium at the same time.
+ IceTransportsType type = kAll;
+ BundlePolicy bundle_policy = kBundlePolicyBalanced;
+ RtcpMuxPolicy rtcp_mux_policy = kRtcpMuxPolicyRequire;
+ std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates;
+ int ice_candidate_pool_size = 0;
+
+ //////////////////////////////////////////////////////////////////////////
+ // The below fields correspond to constraints from the deprecated
+ // constraints interface for constructing a PeerConnection.
+ //
+ // absl::optional fields can be "missing", in which case the implementation
+ // default will be used.
+ //////////////////////////////////////////////////////////////////////////
+
+ // If set to true, don't gather IPv6 ICE candidates.
+ // TODO(deadbeef): Remove this? IPv6 support has long stopped being
+ // experimental
+ bool disable_ipv6 = false;
+
+ // If set to true, don't gather IPv6 ICE candidates on Wi-Fi.
+ // Only intended to be used on specific devices. Certain phones disable IPv6
+ // when the screen is turned off and it would be better to just disable the
+ // IPv6 ICE candidates on Wi-Fi in those cases.
+ bool disable_ipv6_on_wifi = false;
+
+ // By default, the PeerConnection will use a limited number of IPv6 network
+ // interfaces, in order to avoid too many ICE candidate pairs being created
+ // and delaying ICE completion.
+ //
+ // Can be set to INT_MAX to effectively disable the limit.
+ int max_ipv6_networks = cricket::kDefaultMaxIPv6Networks;
+
+ // Exclude link-local network interfaces
+ // from considertaion for gathering ICE candidates.
+ bool disable_link_local_networks = false;
+
+ // If set to true, use RTP data channels instead of SCTP.
+ // TODO(deadbeef): Remove this. We no longer commit to supporting RTP data
+ // channels, though some applications are still working on moving off of
+ // them.
+ bool enable_rtp_data_channel = false;
+
+ // Minimum bitrate at which screencast video tracks will be encoded at.
+ // This means adding padding bits up to this bitrate, which can help
+ // when switching from a static scene to one with motion.
+ absl::optional<int> screencast_min_bitrate;
+
+ // Use new combined audio/video bandwidth estimation?
+ absl::optional<bool> combined_audio_video_bwe;
+
+ // TODO(bugs.webrtc.org/9891) - Move to crypto_options
+ // Can be used to disable DTLS-SRTP. This should never be done, but can be
+ // useful for testing purposes, for example in setting up a loopback call
+ // with a single PeerConnection.
+ absl::optional<bool> enable_dtls_srtp;
+
+ /////////////////////////////////////////////////
+ // The below fields are not part of the standard.
+ /////////////////////////////////////////////////
+
+ // Can be used to disable TCP candidate generation.
+ TcpCandidatePolicy tcp_candidate_policy = kTcpCandidatePolicyEnabled;
+
+ // Can be used to avoid gathering candidates for a "higher cost" network,
+ // if a lower cost one exists. For example, if both Wi-Fi and cellular
+ // interfaces are available, this could be used to avoid using the cellular
+ // interface.
+ CandidateNetworkPolicy candidate_network_policy =
+ kCandidateNetworkPolicyAll;
+
+ // The maximum number of packets that can be stored in the NetEq audio
+ // jitter buffer. Can be reduced to lower tolerated audio latency.
+ int audio_jitter_buffer_max_packets = kAudioJitterBufferMaxPackets;
+
+ // Whether to use the NetEq "fast mode" which will accelerate audio quicker
+ // if it falls behind.
+ bool audio_jitter_buffer_fast_accelerate = false;
+
+ // The minimum delay in milliseconds for the audio jitter buffer.
+ int audio_jitter_buffer_min_delay_ms = 0;
+
+ // Whether the audio jitter buffer adapts the delay to retransmitted
+ // packets.
+ bool audio_jitter_buffer_enable_rtx_handling = false;
+
+ // Timeout in milliseconds before an ICE candidate pair is considered to be
+ // "not receiving", after which a lower priority candidate pair may be
+ // selected.
+ int ice_connection_receiving_timeout = kUndefined;
+
+ // Interval in milliseconds at which an ICE "backup" candidate pair will be
+ // pinged. This is a candidate pair which is not actively in use, but may
+ // be switched to if the active candidate pair becomes unusable.
+ //
+ // This is relevant mainly to Wi-Fi/cell handoff; the application may not
+ // want this backup cellular candidate pair pinged frequently, since it
+ // consumes data/battery.
+ int ice_backup_candidate_pair_ping_interval = kUndefined;
+
+ // Can be used to enable continual gathering, which means new candidates
+ // will be gathered as network interfaces change. Note that if continual
+ // gathering is used, the candidate removal API should also be used, to
+ // avoid an ever-growing list of candidates.
+ ContinualGatheringPolicy continual_gathering_policy = GATHER_ONCE;
+
+ // If set to true, candidate pairs will be pinged in order of most likely
+ // to work (which means using a TURN server, generally), rather than in
+ // standard priority order.
+ bool prioritize_most_likely_ice_candidate_pairs = false;
+
+ // Implementation defined settings. A public member only for the benefit of
+ // the implementation. Applications must not access it directly, and should
+ // instead use provided accessor methods, e.g., set_cpu_adaptation.
+ struct cricket::MediaConfig media_config;
+
+ // If set to true, only one preferred TURN allocation will be used per
+ // network interface. UDP is preferred over TCP and IPv6 over IPv4. This
+ // can be used to cut down on the number of candidate pairings.
+ bool prune_turn_ports = false;
+
+ // If set to true, this means the ICE transport should presume TURN-to-TURN
+ // candidate pairs will succeed, even before a binding response is received.
+ // This can be used to optimize the initial connection time, since the DTLS
+ // handshake can begin immediately.
+ bool presume_writable_when_fully_relayed = false;
+
+ // If true, "renomination" will be added to the ice options in the transport
+ // description.
+ // See: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00
+ bool enable_ice_renomination = false;
+
+ // If true, the ICE role is re-determined when the PeerConnection sets a
+ // local transport description that indicates an ICE restart.
+ //
+ // This is standard RFC5245 ICE behavior, but causes unnecessary role
+ // thrashing, so an application may wish to avoid it. This role
+ // re-determining was removed in ICEbis (ICE v2).
+ bool redetermine_role_on_ice_restart = true;
+
+ // The following fields define intervals in milliseconds at which ICE
+ // connectivity checks are sent.
+ //
+ // We consider ICE is "strongly connected" for an agent when there is at
+ // least one candidate pair that currently succeeds in connectivity check
+ // from its direction i.e. sending a STUN ping and receives a STUN ping
+ // response, AND all candidate pairs have sent a minimum number of pings for
+ // connectivity (this number is implementation-specific). Otherwise, ICE is
+ // considered in "weak connectivity".
+ //
+ // Note that the above notion of strong and weak connectivity is not defined
+ // in RFC 5245, and they apply to our current ICE implementation only.
+ //
+ // 1) ice_check_interval_strong_connectivity defines the interval applied to
+ // ALL candidate pairs when ICE is strongly connected, and it overrides the
+ // default value of this interval in the ICE implementation;
+ // 2) ice_check_interval_weak_connectivity defines the counterpart for ALL
+ // pairs when ICE is weakly connected, and it overrides the default value of
+ // this interval in the ICE implementation;
+ // 3) ice_check_min_interval defines the minimal interval (equivalently the
+ // maximum rate) that overrides the above two intervals when either of them
+ // is less.
+ absl::optional<int> ice_check_interval_strong_connectivity;
+ absl::optional<int> ice_check_interval_weak_connectivity;
+ absl::optional<int> ice_check_min_interval;
+
+ // The min time period for which a candidate pair must wait for response to
+ // connectivity checks before it becomes unwritable. This parameter
+ // overrides the default value in the ICE implementation if set.
+ absl::optional<int> ice_unwritable_timeout;
+
+ // The min number of connectivity checks that a candidate pair must sent
+ // without receiving response before it becomes unwritable. This parameter
+ // overrides the default value in the ICE implementation if set.
+ absl::optional<int> ice_unwritable_min_checks;
+
+ // The min time period for which a candidate pair must wait for response to
+ // connectivity checks it becomes inactive. This parameter overrides the
+ // default value in the ICE implementation if set.
+ absl::optional<int> ice_inactive_timeout;
+
+ // The interval in milliseconds at which STUN candidates will resend STUN
+ // binding requests to keep NAT bindings open.
+ absl::optional<int> stun_candidate_keepalive_interval;
+
+ // ICE Periodic Regathering
+ // If set, WebRTC will periodically create and propose candidates without
+ // starting a new ICE generation. The regathering happens continuously with
+ // interval specified in milliseconds by the uniform distribution [a, b].
+ absl::optional<rtc::IntervalRange> ice_regather_interval_range;
+
+ // Optional TurnCustomizer.
+ // With this class one can modify outgoing TURN messages.
+ // The object passed in must remain valid until PeerConnection::Close() is
+ // called.
+ webrtc::TurnCustomizer* turn_customizer = nullptr;
+
+ // Preferred network interface.
+ // A candidate pair on a preferred network has a higher precedence in ICE
+ // than one on an un-preferred network, regardless of priority or network
+ // cost.
+ absl::optional<rtc::AdapterType> network_preference;
+
+ // Configure the SDP semantics used by this PeerConnection. Note that the
+ // WebRTC 1.0 specification requires kUnifiedPlan semantics. The
+ // RtpTransceiver API is only available with kUnifiedPlan semantics.
+ //
+ // kPlanB will cause PeerConnection to create offers and answers with at
+ // most one audio and one video m= section with multiple RtpSenders and
+ // RtpReceivers specified as multiple a=ssrc lines within the section. This
+ // will also cause PeerConnection to ignore all but the first m= section of
+ // the same media type.
+ //
+ // kUnifiedPlan will cause PeerConnection to create offers and answers with
+ // multiple m= sections where each m= section maps to one RtpSender and one
+ // RtpReceiver (an RtpTransceiver), either both audio or both video. This
+ // will also cause PeerConnection to ignore all but the first a=ssrc lines
+ // that form a Plan B stream.
+ //
+ // For users who wish to send multiple audio/video streams and need to stay
+ // interoperable with legacy WebRTC implementations or use legacy APIs,
+ // specify kPlanB.
+ //
+ // For all other users, specify kUnifiedPlan.
+ SdpSemantics sdp_semantics = SdpSemantics::kPlanB;
+
+ // TODO(bugs.webrtc.org/9891) - Move to crypto_options or remove.
+ // Actively reset the SRTP parameters whenever the DTLS transports
+ // underneath are reset for every offer/answer negotiation.
+ // This is only intended to be a workaround for crbug.com/835958
+ // WARNING: This would cause RTP/RTCP packets decryption failure if not used
+ // correctly. This flag will be deprecated soon. Do not rely on it.
+ bool active_reset_srtp_params = false;
+
+ // If MediaTransportFactory is provided in PeerConnectionFactory, this flag
+ // informs PeerConnection that it should use the MediaTransportInterface for
+ // media (audio/video). It's invalid to set it to |true| if the
+ // MediaTransportFactory wasn't provided.
+ bool use_media_transport = false;
+
+ // If MediaTransportFactory is provided in PeerConnectionFactory, this flag
+ // informs PeerConnection that it should use the MediaTransportInterface for
+ // data channels. It's invalid to set it to |true| if the
+ // MediaTransportFactory wasn't provided. Data channels over media
+ // transport are not compatible with RTP or SCTP data channels. Setting
+ // both |use_media_transport_for_data_channels| and
+ // |enable_rtp_data_channel| is invalid.
+ bool use_media_transport_for_data_channels = false;
+
+ // Defines advanced optional cryptographic settings related to SRTP and
+ // frame encryption for native WebRTC. Setting this will overwrite any
+ // settings set in PeerConnectionFactory (which is deprecated).
+ absl::optional<CryptoOptions> crypto_options;
+
+ // Configure if we should include the SDP attribute extmap-allow-mixed in
+ // our offer. Although we currently do support this, it's not included in
+ // our offer by default due to a previous bug that caused the SDP parser to
+ // abort parsing if this attribute was present. This is fixed in Chrome 71.
+ // TODO(webrtc:9985): Change default to true once sufficient time has
+ // passed.
+ bool offer_extmap_allow_mixed = false;
+
+ //
+ // Don't forget to update operator== if adding something.
+ //
+ };
+
+ // See: https://www.w3.org/TR/webrtc/#idl-def-rtcofferansweroptions
+ struct RTCOfferAnswerOptions {
+ static const int kUndefined = -1;
+ static const int kMaxOfferToReceiveMedia = 1;
+
+ // The default value for constraint offerToReceiveX:true.
+ static const int kOfferToReceiveMediaTrue = 1;
+
+ // These options are left as backwards compatibility for clients who need
+ // "Plan B" semantics. Clients who have switched to "Unified Plan" semantics
+ // should use the RtpTransceiver API (AddTransceiver) instead.
+ //
+ // offer_to_receive_X set to 1 will cause a media description to be
+ // generated in the offer, even if no tracks of that type have been added.
+ // Values greater than 1 are treated the same.
+ //
+ // If set to 0, the generated directional attribute will not include the
+ // "recv" direction (meaning it will be "sendonly" or "inactive".
+ int offer_to_receive_video = kUndefined;
+ int offer_to_receive_audio = kUndefined;
+
+ bool voice_activity_detection = true;
+ bool ice_restart = false;
+
+ // If true, will offer to BUNDLE audio/video/data together. Not to be
+ // confused with RTCP mux (multiplexing RTP and RTCP together).
+ bool use_rtp_mux = true;
+
+ // This will apply to all video tracks with a Plan B SDP offer/answer.
+ int num_simulcast_layers = 1;
+
+ RTCOfferAnswerOptions() = default;
+
+ RTCOfferAnswerOptions(int offer_to_receive_video,
+ int offer_to_receive_audio,
+ bool voice_activity_detection,
+ bool ice_restart,
+ bool use_rtp_mux)
+ : offer_to_receive_video(offer_to_receive_video),
+ offer_to_receive_audio(offer_to_receive_audio),
+ voice_activity_detection(voice_activity_detection),
+ ice_restart(ice_restart),
+ use_rtp_mux(use_rtp_mux) {}
+ };
+
+ // Used by GetStats to decide which stats to include in the stats reports.
+ // |kStatsOutputLevelStandard| includes the standard stats for Javascript API;
+ // |kStatsOutputLevelDebug| includes both the standard stats and additional
+ // stats for debugging purposes.
+ enum StatsOutputLevel {
+ kStatsOutputLevelStandard,
+ kStatsOutputLevelDebug,
+ };
+
+ // Accessor methods to active local streams.
+ // This method is not supported with kUnifiedPlan semantics. Please use
+ // GetSenders() instead.
+ virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams() = 0;
+
+ // Accessor methods to remote streams.
+ // This method is not supported with kUnifiedPlan semantics. Please use
+ // GetReceivers() instead.
+ virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams() = 0;
+
+ // Add a new MediaStream to be sent on this PeerConnection.
+ // Note that a SessionDescription negotiation is needed before the
+ // remote peer can receive the stream.
+ //
+ // This has been removed from the standard in favor of a track-based API. So,
+ // this is equivalent to simply calling AddTrack for each track within the
+ // stream, with the one difference that if "stream->AddTrack(...)" is called
+ // later, the PeerConnection will automatically pick up the new track. Though
+ // this functionality will be deprecated in the future.
+ //
+ // This method is not supported with kUnifiedPlan semantics. Please use
+ // AddTrack instead.
+ virtual bool AddStream(MediaStreamInterface* stream) = 0;
+
+ // Remove a MediaStream from this PeerConnection.
+ // Note that a SessionDescription negotiation is needed before the
+ // remote peer is notified.
+ //
+ // This method is not supported with kUnifiedPlan semantics. Please use
+ // RemoveTrack instead.
+ virtual void RemoveStream(MediaStreamInterface* stream) = 0;
+
+ // Add a new MediaStreamTrack to be sent on this PeerConnection, and return
+ // the newly created RtpSender. The RtpSender will be associated with the
+ // streams specified in the |stream_ids| list.
+ //
+ // Errors:
+ // - INVALID_PARAMETER: |track| is null, has a kind other than audio or video,
+ // or a sender already exists for the track.
+ // - INVALID_STATE: The PeerConnection is closed.
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids);
+
+ // Remove an RtpSender from this PeerConnection.
+ // Returns true on success.
+ // TODO(steveanton): Replace with signature that returns RTCError.
+ virtual bool RemoveTrack(RtpSenderInterface* sender);
+
+ // Plan B semantics: Removes the RtpSender from this PeerConnection.
+ // Unified Plan semantics: Stop sending on the RtpSender and mark the
+ // corresponding RtpTransceiver direction as no longer sending.
+ //
+ // Errors:
+ // - INVALID_PARAMETER: |sender| is null or (Plan B only) the sender is not
+ // associated with this PeerConnection.
+ // - INVALID_STATE: PeerConnection is closed.
+ // TODO(bugs.webrtc.org/9534): Rename to RemoveTrack once the other signature
+ // is removed.
+ virtual RTCError RemoveTrackNew(
+ rtc::scoped_refptr<RtpSenderInterface> sender);
+
+ // AddTransceiver creates a new RtpTransceiver and adds it to the set of
+ // transceivers. Adding a transceiver will cause future calls to CreateOffer
+ // to add a media description for the corresponding transceiver.
+ //
+ // The initial value of |mid| in the returned transceiver is null. Setting a
+ // new session description may change it to a non-null value.
+ //
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
+ //
+ // Optionally, an RtpTransceiverInit structure can be specified to configure
+ // the transceiver from construction. If not specified, the transceiver will
+ // default to having a direction of kSendRecv and not be part of any streams.
+ //
+ // These methods are only available when Unified Plan is enabled (see
+ // RTCConfiguration).
+ //
+ // Common errors:
+ // - INTERNAL_ERROR: The configuration does not have Unified Plan enabled.
+ // TODO(steveanton): Make these pure virtual once downstream projects have
+ // updated.
+
+ // Adds a transceiver with a sender set to transmit the given track. The kind
+ // of the transceiver (and sender/receiver) will be derived from the kind of
+ // the track.
+ // Errors:
+ // - INVALID_PARAMETER: |track| is null.
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track);
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init);
+
+ // Adds a transceiver with the given kind. Can either be MEDIA_TYPE_AUDIO or
+ // MEDIA_TYPE_VIDEO.
+ // Errors:
+ // - INVALID_PARAMETER: |media_type| is not MEDIA_TYPE_AUDIO or
+ // MEDIA_TYPE_VIDEO.
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(cricket::MediaType media_type);
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(cricket::MediaType media_type, const RtpTransceiverInit& init);
+
+ // TODO(deadbeef): Make these pure virtual once all subclasses implement them.
+
+ // Creates a sender without a track. Can be used for "early media"/"warmup"
+ // use cases, where the application may want to negotiate video attributes
+ // before a track is available to send.
+ //
+ // The standard way to do this would be through "addTransceiver", but we
+ // don't support that API yet.
+ //
+ // |kind| must be "audio" or "video".
+ //
+ // |stream_id| is used to populate the msid attribute; if empty, one will
+ // be generated automatically.
+ //
+ // This method is not supported with kUnifiedPlan semantics. Please use
+ // AddTransceiver instead.
+ virtual rtc::scoped_refptr<RtpSenderInterface> CreateSender(
+ const std::string& kind,
+ const std::string& stream_id);
+
+ // If Plan B semantics are specified, gets all RtpSenders, created either
+ // through AddStream, AddTrack, or CreateSender. All senders of a specific
+ // media type share the same media description.
+ //
+ // If Unified Plan semantics are specified, gets the RtpSender for each
+ // RtpTransceiver.
+ virtual std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders()
+ const;
+
+ // If Plan B semantics are specified, gets all RtpReceivers created when a
+ // remote description is applied. All receivers of a specific media type share
+ // the same media description. It is also possible to have a media description
+ // with no associated RtpReceivers, if the directional attribute does not
+ // indicate that the remote peer is sending any media.
+ //
+ // If Unified Plan semantics are specified, gets the RtpReceiver for each
+ // RtpTransceiver.
+ virtual std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers()
+ const;
+
+ // Get all RtpTransceivers, created either through AddTransceiver, AddTrack or
+ // by a remote description applied with SetRemoteDescription.
+ //
+ // Note: This method is only available when Unified Plan is enabled (see
+ // RTCConfiguration).
+ virtual std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
+ GetTransceivers() const;
+
+ // The legacy non-compliant GetStats() API. This correspond to the
+ // callback-based version of getStats() in JavaScript. The returned metrics
+ // are UNDOCUMENTED and many of them rely on implementation-specific details.
+ // The goal is to DELETE THIS VERSION but we can't today because it is heavily
+ // relied upon by third parties. See https://crbug.com/822696.
+ //
+ // This version is wired up into Chrome. Any stats implemented are
+ // automatically exposed to the Web Platform. This has BYPASSED the Chrome
+ // release processes for years and lead to cross-browser incompatibility
+ // issues and web application reliance on Chrome-only behavior.
+ //
+ // This API is in "maintenance mode", serious regressions should be fixed but
+ // adding new stats is highly discouraged.
+ //
+ // TODO(hbos): Deprecate and remove this when third parties have migrated to
+ // the spec-compliant GetStats() API. https://crbug.com/822696
+ virtual bool GetStats(StatsObserver* observer,
+ MediaStreamTrackInterface* track, // Optional
+ StatsOutputLevel level) = 0;
+ // The spec-compliant GetStats() API. This correspond to the promise-based
+ // version of getStats() in JavaScript. Implementation status is described in
+ // api/stats/rtcstats_objects.h. For more details on stats, see spec:
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getstats
+ // TODO(hbos): Takes shared ownership, use rtc::scoped_refptr<> instead. This
+ // requires stop overriding the current version in third party or making third
+ // party calls explicit to avoid ambiguity during switch. Make the future
+ // version abstract as soon as third party projects implement it.
+ virtual void GetStats(RTCStatsCollectorCallback* callback) {}
+ // Spec-compliant getStats() performing the stats selection algorithm with the
+ // sender. https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-getstats
+ // TODO(hbos): Make abstract as soon as third party projects implement it.
+ virtual void GetStats(
+ rtc::scoped_refptr<RtpSenderInterface> selector,
+ rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {}
+ // Spec-compliant getStats() performing the stats selection algorithm with the
+ // receiver. https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getstats
+ // TODO(hbos): Make abstract as soon as third party projects implement it.
+ virtual void GetStats(
+ rtc::scoped_refptr<RtpReceiverInterface> selector,
+ rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {}
+ // Clear cached stats in the RTCStatsCollector.
+ // Exposed for testing while waiting for automatic cache clear to work.
+ // https://bugs.webrtc.org/8693
+ virtual void ClearStatsCache() {}
+
+ // Create a data channel with the provided config, or default config if none
+ // is provided. Note that an offer/answer negotiation is still necessary
+ // before the data channel can be used.
+ //
+ // Also, calling CreateDataChannel is the only way to get a data "m=" section
+ // in SDP, so it should be done before CreateOffer is called, if the
+ // application plans to use data channels.
+ virtual rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
+ const std::string& label,
+ const DataChannelInit* config) = 0;
+
+ // Returns the more recently applied description; "pending" if it exists, and
+ // otherwise "current". See below.
+ virtual const SessionDescriptionInterface* local_description() const = 0;
+ virtual const SessionDescriptionInterface* remote_description() const = 0;
+
+ // A "current" description the one currently negotiated from a complete
+ // offer/answer exchange.
+ virtual const SessionDescriptionInterface* current_local_description() const;
+ virtual const SessionDescriptionInterface* current_remote_description() const;
+
+ // A "pending" description is one that's part of an incomplete offer/answer
+ // exchange (thus, either an offer or a pranswer). Once the offer/answer
+ // exchange is finished, the "pending" description will become "current".
+ virtual const SessionDescriptionInterface* pending_local_description() const;
+ virtual const SessionDescriptionInterface* pending_remote_description() const;
+
+ // Create a new offer.
+ // The CreateSessionDescriptionObserver callback will be called when done.
+ virtual void CreateOffer(CreateSessionDescriptionObserver* observer,
+ const RTCOfferAnswerOptions& options) = 0;
+
+ // Create an answer to an offer.
+ // The CreateSessionDescriptionObserver callback will be called when done.
+ virtual void CreateAnswer(CreateSessionDescriptionObserver* observer,
+ const RTCOfferAnswerOptions& options) = 0;
+
+ // Sets the local session description.
+ // The PeerConnection takes the ownership of |desc| even if it fails.
+ // The |observer| callback will be called when done.
+ // TODO(deadbeef): Change |desc| to be a unique_ptr, to make it clear
+ // that this method always takes ownership of it.
+ virtual void SetLocalDescription(SetSessionDescriptionObserver* observer,
+ SessionDescriptionInterface* desc) = 0;
+ // Sets the remote session description.
+ // The PeerConnection takes the ownership of |desc| even if it fails.
+ // The |observer| callback will be called when done.
+ // TODO(hbos): Remove when Chrome implements the new signature.
+ virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer,
+ SessionDescriptionInterface* desc) {}
+ // TODO(hbos): Make pure virtual when Chrome has updated its signature.
+ virtual void SetRemoteDescription(
+ std::unique_ptr<SessionDescriptionInterface> desc,
+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) {}
+
+ // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of
+ // PeerConnectionInterface implement it.
+ virtual PeerConnectionInterface::RTCConfiguration GetConfiguration();
+
+ // Sets the PeerConnection's global configuration to |config|.
+ //
+ // The members of |config| that may be changed are |type|, |servers|,
+ // |ice_candidate_pool_size| and |prune_turn_ports| (though the candidate
+ // pool size can't be changed after the first call to SetLocalDescription).
+ // Note that this means the BUNDLE and RTCP-multiplexing policies cannot be
+ // changed with this method.
+ //
+ // Any changes to STUN/TURN servers or ICE candidate policy will affect the
+ // next gathering phase, and cause the next call to createOffer to generate
+ // new ICE credentials, as described in JSEP. This also occurs when
+ // |prune_turn_ports| changes, for the same reasoning.
+ //
+ // If an error occurs, returns false and populates |error| if non-null:
+ // - INVALID_MODIFICATION if |config| contains a modified parameter other
+ // than one of the parameters listed above.
+ // - INVALID_RANGE if |ice_candidate_pool_size| is out of range.
+ // - SYNTAX_ERROR if parsing an ICE server URL failed.
+ // - INVALID_PARAMETER if a TURN server is missing |username| or |password|.
+ // - INTERNAL_ERROR if an unexpected error occurred.
+ //
+ // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of
+ // PeerConnectionInterface implement it.
+ virtual bool SetConfiguration(
+ const PeerConnectionInterface::RTCConfiguration& config,
+ RTCError* error);
+
+ // Version without error output param for backwards compatibility.
+ // TODO(deadbeef): Remove once chromium is updated.
+ virtual bool SetConfiguration(
+ const PeerConnectionInterface::RTCConfiguration& config);
+
+ // Provides a remote candidate to the ICE Agent.
+ // A copy of the |candidate| will be created and added to the remote
+ // description. So the caller of this method still has the ownership of the
+ // |candidate|.
+ virtual bool AddIceCandidate(const IceCandidateInterface* candidate) = 0;
+
+ // Removes a group of remote candidates from the ICE agent. Needed mainly for
+ // continual gathering, to avoid an ever-growing list of candidates as
+ // networks come and go.
+ virtual bool RemoveIceCandidates(
+ const std::vector<cricket::Candidate>& candidates);
+
+ // 0 <= min <= current <= max should hold for set parameters.
+ struct BitrateParameters {
+ BitrateParameters();
+ ~BitrateParameters();
+
+ absl::optional<int> min_bitrate_bps;
+ absl::optional<int> current_bitrate_bps;
+ absl::optional<int> max_bitrate_bps;
+ };
+
+ // SetBitrate limits the bandwidth allocated for all RTP streams sent by
+ // this PeerConnection. Other limitations might affect these limits and
+ // are respected (for example "b=AS" in SDP).
+ //
+ // Setting |current_bitrate_bps| will reset the current bitrate estimate
+ // to the provided value.
+ virtual RTCError SetBitrate(const BitrateSettings& bitrate);
+
+ // TODO(nisse): Deprecated - use version above. These two default
+ // implementations require subclasses to implement one or the other
+ // of the methods.
+ virtual RTCError SetBitrate(const BitrateParameters& bitrate_parameters);
+
+ // Sets current strategy. If not set default WebRTC allocator will be used.
+ // May be changed during an active session. The strategy
+ // ownership is passed with std::unique_ptr
+ // TODO(alexnarest): Make this pure virtual when tests will be updated
+ virtual void SetBitrateAllocationStrategy(
+ std::unique_ptr<rtc::BitrateAllocationStrategy>
+ bitrate_allocation_strategy) {}
+
+ // Enable/disable playout of received audio streams. Enabled by default. Note
+ // that even if playout is enabled, streams will only be played out if the
+ // appropriate SDP is also applied. Setting |playout| to false will stop
+ // playout of the underlying audio device but starts a task which will poll
+ // for audio data every 10ms to ensure that audio processing happens and the
+ // audio statistics are updated.
+ // TODO(henrika): deprecate and remove this.
+ virtual void SetAudioPlayout(bool playout) {}
+
+ // Enable/disable recording of transmitted audio streams. Enabled by default.
+ // Note that even if recording is enabled, streams will only be recorded if
+ // the appropriate SDP is also applied.
+ // TODO(henrika): deprecate and remove this.
+ virtual void SetAudioRecording(bool recording) {}
+
+ // Looks up the DtlsTransport associated with a MID value.
+ // In the Javascript API, DtlsTransport is a property of a sender, but
+ // because the PeerConnection owns the DtlsTransport in this implementation,
+ // it is better to look them up on the PeerConnection.
+ // TODO(hta): Remove default implementation after updating Chrome.
+ virtual rtc::scoped_refptr<DtlsTransportInterface> LookupDtlsTransportByMid(
+ const std::string& mid);
+
+ // Returns the SCTP transport, if any.
+ // TODO(hta): Remove default implementation after updating Chrome.
+ virtual rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const;
+
+ // Returns the current SignalingState.
+ virtual SignalingState signaling_state() = 0;
+
+ // Returns an aggregate state of all ICE *and* DTLS transports.
+ // This is left in place to avoid breaking native clients who expect our old,
+ // nonstandard behavior.
+ // TODO(jonasolsson): deprecate and remove this.
+ virtual IceConnectionState ice_connection_state() = 0;
+
+ // Returns an aggregated state of all ICE transports.
+ virtual IceConnectionState standardized_ice_connection_state();
+
+ // Returns an aggregated state of all ICE and DTLS transports.
+ virtual PeerConnectionState peer_connection_state();
+
+ virtual IceGatheringState ice_gathering_state() = 0;
+
+ // Starts RtcEventLog using existing file. Takes ownership of |file| and
+ // passes it on to Call, which will take the ownership. If the
+ // operation fails the file will be closed.
+ // The logging will stop when |max_size_bytes| is reached or when the
+ // StopRtcEventLog function is called.
+ // TODO(eladalon): Deprecate and remove this.
+ virtual bool StartRtcEventLog(rtc::PlatformFile file, int64_t max_size_bytes);
+
+ // Start RtcEventLog using an existing output-sink. Takes ownership of
+ // |output| and passes it on to Call, which will take the ownership. If the
+ // operation fails the output will be closed and deallocated. The event log
+ // will send serialized events to the output object every |output_period_ms|.
+ virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output,
+ int64_t output_period_ms);
+
+ // Stops logging the RtcEventLog.
+ // TODO(ivoc): Make this pure virtual when Chrome is updated.
+ virtual void StopRtcEventLog() {}
+
+ // Terminates all media, closes the transports, and in general releases any
+ // resources used by the PeerConnection. This is an irreversible operation.
+ //
+ // Note that after this method completes, the PeerConnection will no longer
+ // use the PeerConnectionObserver interface passed in on construction, and
+ // thus the observer object can be safely destroyed.
+ virtual void Close() = 0;
+
+ protected:
+ // Dtor protected as objects shouldn't be deleted via this interface.
+ ~PeerConnectionInterface() override = default;
+};
+
+// PeerConnection callback interface, used for RTCPeerConnection events.
+// Application should implement these methods.
+class PeerConnectionObserver {
+ public:
+ virtual ~PeerConnectionObserver() = default;
+
+ // Triggered when the SignalingState changed.
+ virtual void OnSignalingChange(
+ PeerConnectionInterface::SignalingState new_state) = 0;
+
+ // Triggered when media is received on a new stream from remote peer.
+ virtual void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) {}
+
+ // Triggered when a remote peer closes a stream.
+ virtual void OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) {
+ }
+
+ // Triggered when a remote peer opens a data channel.
+ virtual void OnDataChannel(
+ rtc::scoped_refptr<DataChannelInterface> data_channel) = 0;
+
+ // Triggered when renegotiation is needed. For example, an ICE restart
+ // has begun.
+ virtual void OnRenegotiationNeeded() = 0;
+
+ // Called any time the legacy IceConnectionState changes.
+ //
+ // Note that our ICE states lag behind the standard slightly. The most
+ // notable differences include the fact that "failed" occurs after 15
+ // seconds, not 30, and this actually represents a combination ICE + DTLS
+ // state, so it may be "failed" if DTLS fails while ICE succeeds.
+ //
+ // TODO(jonasolsson): deprecate and remove this.
+ virtual void OnIceConnectionChange(
+ PeerConnectionInterface::IceConnectionState new_state) = 0;
+
+ // Called any time the standards-compliant IceConnectionState changes.
+ virtual void OnStandardizedIceConnectionChange(
+ PeerConnectionInterface::IceConnectionState new_state) {}
+
+ // Called any time the PeerConnectionState changes.
+ virtual void OnConnectionChange(
+ PeerConnectionInterface::PeerConnectionState new_state) {}
+
+ // Called any time the IceGatheringState changes.
+ virtual void OnIceGatheringChange(
+ PeerConnectionInterface::IceGatheringState new_state) = 0;
+
+ // A new ICE candidate has been gathered.
+ virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0;
+
+ // Ice candidates have been removed.
+ // TODO(honghaiz): Make this a pure virtual method when all its subclasses
+ // implement it.
+ virtual void OnIceCandidatesRemoved(
+ const std::vector<cricket::Candidate>& candidates) {}
+
+ // Called when the ICE connection receiving status changes.
+ virtual void OnIceConnectionReceivingChange(bool receiving) {}
+
+ // This is called when a receiver and its track are created.
+ // TODO(zhihuang): Make this pure virtual when all subclasses implement it.
+ // Note: This is called with both Plan B and Unified Plan semantics. Unified
+ // Plan users should prefer OnTrack, OnAddTrack is only called as backwards
+ // compatibility (and is called in the exact same situations as OnTrack).
+ virtual void OnAddTrack(
+ rtc::scoped_refptr<RtpReceiverInterface> receiver,
+ const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {}
+
+ // This is called when signaling indicates a transceiver will be receiving
+ // media from the remote endpoint. This is fired during a call to
+ // SetRemoteDescription. The receiving track can be accessed by:
+ // |transceiver->receiver()->track()| and its associated streams by
+ // |transceiver->receiver()->streams()|.
+ // Note: This will only be called if Unified Plan semantics are specified.
+ // This behavior is specified in section 2.2.8.2.5 of the "Set the
+ // RTCSessionDescription" algorithm:
+ // https://w3c.github.io/webrtc-pc/#set-description
+ virtual void OnTrack(
+ rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {}
+
+ // Called when signaling indicates that media will no longer be received on a
+ // track.
+ // With Plan B semantics, the given receiver will have been removed from the
+ // PeerConnection and the track muted.
+ // With Unified Plan semantics, the receiver will remain but the transceiver
+ // will have changed direction to either sendonly or inactive.
+ // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
+ // TODO(hbos,deadbeef): Make pure virtual when all subclasses implement it.
+ virtual void OnRemoveTrack(
+ rtc::scoped_refptr<RtpReceiverInterface> receiver) {}
+
+ // Called when an interesting usage is detected by WebRTC.
+ // An appropriate action is to add information about the context of the
+ // PeerConnection and write the event to some kind of "interesting events"
+ // log function.
+ // The heuristics for defining what constitutes "interesting" are
+ // implementation-defined.
+ virtual void OnInterestingUsage(int usage_pattern) {}
+};
+
+// PeerConnectionDependencies holds all of PeerConnections dependencies.
+// A dependency is distinct from a configuration as it defines significant
+// executable code that can be provided by a user of the API.
+//
+// All new dependencies should be added as a unique_ptr to allow the
+// PeerConnection object to be the definitive owner of the dependencies
+// lifetime making injection safer.
+struct PeerConnectionDependencies final {
+ explicit PeerConnectionDependencies(PeerConnectionObserver* observer_in);
+ // This object is not copyable or assignable.
+ PeerConnectionDependencies(const PeerConnectionDependencies&) = delete;
+ PeerConnectionDependencies& operator=(const PeerConnectionDependencies&) =
+ delete;
+ // This object is only moveable.
+ PeerConnectionDependencies(PeerConnectionDependencies&&);
+ PeerConnectionDependencies& operator=(PeerConnectionDependencies&&) = default;
+ ~PeerConnectionDependencies();
+ // Mandatory dependencies
+ PeerConnectionObserver* observer = nullptr;
+ // Optional dependencies
+ std::unique_ptr<cricket::PortAllocator> allocator;
+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory;
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator;
+ std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier;
+};
+
+// PeerConnectionFactoryDependencies holds all of the PeerConnectionFactory
+// dependencies. All new dependencies should be added here instead of
+// overloading the function. This simplifies dependency injection and makes it
+// clear which are mandatory and optional. If possible please allow the peer
+// connection factory to take ownership of the dependency by adding a unique_ptr
+// to this structure.
+struct PeerConnectionFactoryDependencies final {
+ PeerConnectionFactoryDependencies();
+ // This object is not copyable or assignable.
+ PeerConnectionFactoryDependencies(const PeerConnectionFactoryDependencies&) =
+ delete;
+ PeerConnectionFactoryDependencies& operator=(
+ const PeerConnectionFactoryDependencies&) = delete;
+ // This object is only moveable.
+ PeerConnectionFactoryDependencies(PeerConnectionFactoryDependencies&&);
+ PeerConnectionFactoryDependencies& operator=(
+ PeerConnectionFactoryDependencies&&) = default;
+ ~PeerConnectionFactoryDependencies();
+
+ // Optional dependencies
+ rtc::Thread* network_thread = nullptr;
+ rtc::Thread* worker_thread = nullptr;
+ rtc::Thread* signaling_thread = nullptr;
+ std::unique_ptr<cricket::MediaEngineInterface> media_engine;
+ std::unique_ptr<CallFactoryInterface> call_factory;
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory;
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory;
+ std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory;
+ std::unique_ptr<MediaTransportFactory> media_transport_factory;
+};
+
+// PeerConnectionFactoryInterface is the factory interface used for creating
+// PeerConnection, MediaStream and MediaStreamTrack objects.
+//
+// The simplest method for obtaiing one, CreatePeerConnectionFactory will
+// create the required libjingle threads, socket and network manager factory
+// classes for networking if none are provided, though it requires that the
+// application runs a message loop on the thread that called the method (see
+// explanation below)
+//
+// If an application decides to provide its own threads and/or implementation
+// of networking classes, it should use the alternate
+// CreatePeerConnectionFactory method which accepts threads as input, and use
+// the CreatePeerConnection version that takes a PortAllocator as an argument.
+class PeerConnectionFactoryInterface : public rtc::RefCountInterface {
+ public:
+ class Options {
+ public:
+ Options() {}
+
+ // If set to true, created PeerConnections won't enforce any SRTP
+ // requirement, allowing unsecured media. Should only be used for
+ // testing/debugging.
+ bool disable_encryption = false;
+
+ // Deprecated. The only effect of setting this to true is that
+ // CreateDataChannel will fail, which is not that useful.
+ bool disable_sctp_data_channels = false;
+
+ // If set to true, any platform-supported network monitoring capability
+ // won't be used, and instead networks will only be updated via polling.
+ //
+ // This only has an effect if a PeerConnection is created with the default
+ // PortAllocator implementation.
+ bool disable_network_monitor = false;
+
+ // Sets the network types to ignore. For instance, calling this with
+ // ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK will ignore Ethernet and
+ // loopback interfaces.
+ int network_ignore_mask = rtc::kDefaultNetworkIgnoreMask;
+
+ // Sets the maximum supported protocol version. The highest version
+ // supported by both ends will be used for the connection, i.e. if one
+ // party supports DTLS 1.0 and the other DTLS 1.2, DTLS 1.0 will be used.
+ rtc::SSLProtocolVersion ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
+
+ // Sets crypto related options, e.g. enabled cipher suites.
+ CryptoOptions crypto_options = CryptoOptions::NoGcm();
+ };
+
+ // Set the options to be used for subsequently created PeerConnections.
+ virtual void SetOptions(const Options& options) = 0;
+
+ // The preferred way to create a new peer connection. Simply provide the
+ // configuration and a PeerConnectionDependencies structure.
+ // TODO(benwright): Make pure virtual once downstream mock PC factory classes
+ // are updated.
+ virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
+ const PeerConnectionInterface::RTCConfiguration& configuration,
+ PeerConnectionDependencies dependencies);
+
+ // Deprecated; |allocator| and |cert_generator| may be null, in which case
+ // default implementations will be used.
+ //
+ // |observer| must not be null.
+ //
+ // Note that this method does not take ownership of |observer|; it's the
+ // responsibility of the caller to delete it. It can be safely deleted after
+ // Close has been called on the returned PeerConnection, which ensures no
+ // more observer callbacks will be invoked.
+ virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
+ const PeerConnectionInterface::RTCConfiguration& configuration,
+ std::unique_ptr<cricket::PortAllocator> allocator,
+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
+ PeerConnectionObserver* observer);
+
+ // Returns the capabilities of an RTP sender of type |kind|.
+ // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
+ // TODO(orphis): Make pure virtual when all subclasses implement it.
+ virtual RtpCapabilities GetRtpSenderCapabilities(
+ cricket::MediaType kind) const;
+
+ // Returns the capabilities of an RTP receiver of type |kind|.
+ // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
+ // TODO(orphis): Make pure virtual when all subclasses implement it.
+ virtual RtpCapabilities GetRtpReceiverCapabilities(
+ cricket::MediaType kind) const;
+
+ virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(
+ const std::string& stream_id) = 0;
+
+ // Creates an AudioSourceInterface.
+ // |options| decides audio processing settings.
+ virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(
+ const cricket::AudioOptions& options) = 0;
+
+ // Creates a new local VideoTrack. The same |source| can be used in several
+ // tracks.
+ virtual rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack(
+ const std::string& label,
+ VideoTrackSourceInterface* source) = 0;
+
+ // Creates an new AudioTrack. At the moment |source| can be null.
+ virtual rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
+ const std::string& label,
+ AudioSourceInterface* source) = 0;
+
+ // Starts AEC dump using existing file. Takes ownership of |file| and passes
+ // it on to VoiceEngine (via other objects) immediately, which will take
+ // the ownerhip. If the operation fails, the file will be closed.
+ // A maximum file size in bytes can be specified. When the file size limit is
+ // reached, logging is stopped automatically. If max_size_bytes is set to a
+ // value <= 0, no limit will be used, and logging will continue until the
+ // StopAecDump function is called.
+ virtual bool StartAecDump(rtc::PlatformFile file, int64_t max_size_bytes) = 0;
+
+ // Stops logging the AEC dump.
+ virtual void StopAecDump() = 0;
+
+ protected:
+ // Dtor and ctor protected as objects shouldn't be created or deleted via
+ // this interface.
+ PeerConnectionFactoryInterface() {}
+ ~PeerConnectionFactoryInterface() override = default;
+};
+
+// This is a lower-level version of the CreatePeerConnectionFactory functions
+// above. It's implemented in the "peerconnection" build target, whereas the
+// above methods are only implemented in the broader "libjingle_peerconnection"
+// build target, which pulls in the implementations of every module webrtc may
+// use.
+//
+// If an application knows it will only require certain modules, it can reduce
+// webrtc's impact on its binary size by depending only on the "peerconnection"
+// target and the modules the application requires, using
+// CreateModularPeerConnectionFactory instead of one of the
+// CreatePeerConnectionFactory methods above. For example, if an application
+// only uses WebRTC for audio, it can pass in null pointers for the
+// video-specific interfaces, and omit the corresponding modules from its
+// build.
+//
+// If |network_thread| or |worker_thread| are null, the PeerConnectionFactory
+// will create the necessary thread internally. If |signaling_thread| is null,
+// the PeerConnectionFactory will use the thread on which this method is called
+// as the signaling thread, wrapping it in an rtc::Thread object if needed.
+//
+// If non-null, a reference is added to |default_adm|, and ownership of
+// |video_encoder_factory| and |video_decoder_factory| is transferred to the
+// returned factory.
+//
+// If |audio_mixer| is null, an internal audio mixer will be created and used.
+//
+// TODO(deadbeef): Use rtc::scoped_refptr<> and std::unique_ptr<> to make this
+// ownership transfer and ref counting more obvious.
+//
+// TODO(deadbeef): Encapsulate these modules in a struct, so that when a new
+// module is inevitably exposed, we can just add a field to the struct instead
+// of adding a whole new CreateModularPeerConnectionFactory overload.
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+ rtc::Thread* network_thread,
+ rtc::Thread* worker_thread,
+ rtc::Thread* signaling_thread,
+ std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+ std::unique_ptr<CallFactoryInterface> call_factory,
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory);
+
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+ rtc::Thread* network_thread,
+ rtc::Thread* worker_thread,
+ rtc::Thread* signaling_thread,
+ std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+ std::unique_ptr<CallFactoryInterface> call_factory,
+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory,
+ std::unique_ptr<NetworkControllerFactoryInterface>
+ network_controller_factory = nullptr);
+
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+ PeerConnectionFactoryDependencies dependencies);
+
+} // namespace webrtc
+
+#endif // API_PEER_CONNECTION_INTERFACE_H_
diff --git a/api/peer_connection_proxy.h b/api/peer_connection_proxy.h
new file mode 100644
index 0000000..61058b5
--- /dev/null
+++ b/api/peer_connection_proxy.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 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.
+ */
+
+#ifndef API_PEER_CONNECTION_PROXY_H_
+#define API_PEER_CONNECTION_PROXY_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/peer_connection_interface.h"
+#include "api/proxy.h"
+
+namespace webrtc {
+
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_SIGNALING_PROXY_MAP(PeerConnection)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams)
+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams)
+PROXY_METHOD1(bool, AddStream, MediaStreamInterface*)
+PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
+ AddTrack,
+ rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const std::vector<std::string>&)
+PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*)
+PROXY_METHOD1(RTCError, RemoveTrackNew, rtc::scoped_refptr<RtpSenderInterface>)
+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ rtc::scoped_refptr<MediaStreamTrackInterface>)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const RtpTransceiverInit&)
+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ cricket::MediaType)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ cricket::MediaType,
+ const RtpTransceiverInit&)
+PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>,
+ CreateSender,
+ const std::string&,
+ const std::string&)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
+ GetSenders)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
+ GetReceivers)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ GetTransceivers)
+PROXY_METHOD3(bool,
+ GetStats,
+ StatsObserver*,
+ MediaStreamTrackInterface*,
+ StatsOutputLevel)
+PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*)
+PROXY_METHOD2(void,
+ GetStats,
+ rtc::scoped_refptr<RtpSenderInterface>,
+ rtc::scoped_refptr<RTCStatsCollectorCallback>)
+PROXY_METHOD2(void,
+ GetStats,
+ rtc::scoped_refptr<RtpReceiverInterface>,
+ rtc::scoped_refptr<RTCStatsCollectorCallback>)
+PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>,
+ CreateDataChannel,
+ const std::string&,
+ const DataChannelInit*)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+ current_local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+ current_remote_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+ pending_local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+ pending_remote_description)
+PROXY_METHOD2(void,
+ CreateOffer,
+ CreateSessionDescriptionObserver*,
+ const RTCOfferAnswerOptions&)
+PROXY_METHOD2(void,
+ CreateAnswer,
+ CreateSessionDescriptionObserver*,
+ const RTCOfferAnswerOptions&)
+PROXY_METHOD2(void,
+ SetLocalDescription,
+ SetSessionDescriptionObserver*,
+ SessionDescriptionInterface*)
+PROXY_METHOD2(void,
+ SetRemoteDescription,
+ SetSessionDescriptionObserver*,
+ SessionDescriptionInterface*)
+PROXY_METHOD2(void,
+ SetRemoteDescription,
+ std::unique_ptr<SessionDescriptionInterface>,
+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>)
+PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration)
+PROXY_METHOD2(bool,
+ SetConfiguration,
+ const PeerConnectionInterface::RTCConfiguration&,
+ RTCError*)
+PROXY_METHOD1(bool,
+ SetConfiguration,
+ const PeerConnectionInterface::RTCConfiguration&)
+PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*)
+PROXY_METHOD1(bool, RemoveIceCandidates, const std::vector<cricket::Candidate>&)
+PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&)
+PROXY_METHOD1(void,
+ SetBitrateAllocationStrategy,
+ std::unique_ptr<rtc::BitrateAllocationStrategy>)
+PROXY_METHOD1(void, SetAudioPlayout, bool)
+PROXY_METHOD1(void, SetAudioRecording, bool)
+PROXY_METHOD1(rtc::scoped_refptr<DtlsTransportInterface>,
+ LookupDtlsTransportByMid,
+ const std::string&)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<SctpTransportInterface>, GetSctpTransport)
+PROXY_METHOD0(SignalingState, signaling_state)
+PROXY_METHOD0(IceConnectionState, ice_connection_state)
+PROXY_METHOD0(IceConnectionState, standardized_ice_connection_state)
+PROXY_METHOD0(PeerConnectionState, peer_connection_state)
+PROXY_METHOD0(IceGatheringState, ice_gathering_state)
+PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t)
+PROXY_METHOD2(bool,
+ StartRtcEventLog,
+ std::unique_ptr<RtcEventLogOutput>,
+ int64_t)
+PROXY_METHOD0(void, StopRtcEventLog)
+PROXY_METHOD0(void, Close)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_PEER_CONNECTION_PROXY_H_
diff --git a/api/proxy.h b/api/proxy.h
index 9916051..6627aac 100644
--- a/api/proxy.h
+++ b/api/proxy.h
@@ -53,12 +53,20 @@
#define API_PROXY_H_
#include <memory>
+#include <string>
#include <utility>
+#include "api/scoped_refptr.h"
#include "rtc_base/event.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/thread.h"
+namespace rtc {
+class Location;
+}
+
namespace webrtc {
template <typename R>
diff --git a/api/ref_counted_base.h b/api/ref_counted_base.h
new file mode 100644
index 0000000..a1761db
--- /dev/null
+++ b/api/ref_counted_base.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 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.
+ */
+#ifndef API_REF_COUNTED_BASE_H_
+#define API_REF_COUNTED_BASE_H_
+
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counter.h"
+
+namespace rtc {
+
+class RefCountedBase {
+ public:
+ RefCountedBase() = default;
+
+ void AddRef() const { ref_count_.IncRef(); }
+ RefCountReleaseStatus Release() const {
+ const auto status = ref_count_.DecRef();
+ if (status == RefCountReleaseStatus::kDroppedLastRef) {
+ delete this;
+ }
+ return status;
+ }
+
+ protected:
+ virtual ~RefCountedBase() = default;
+
+ private:
+ mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+} // namespace rtc
+
+#endif // API_REF_COUNTED_BASE_H_
diff --git a/api/rtc_error.cc b/api/rtc_error.cc
new file mode 100644
index 0000000..51fd07f
--- /dev/null
+++ b/api/rtc_error.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 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 "api/rtc_error.h"
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/arraysize.h"
+
+namespace {
+
+const absl::string_view kRTCErrorTypeNames[] = {
+ "NONE",
+ "UNSUPPORTED_OPERATION",
+ "UNSUPPORTED_PARAMETER",
+ "INVALID_PARAMETER",
+ "INVALID_RANGE",
+ "SYNTAX_ERROR",
+ "INVALID_STATE",
+ "INVALID_MODIFICATION",
+ "NETWORK_ERROR",
+ "RESOURCE_EXHAUSTED",
+ "INTERNAL_ERROR",
+};
+static_assert(static_cast<int>(webrtc::RTCErrorType::INTERNAL_ERROR) ==
+ (arraysize(kRTCErrorTypeNames) - 1),
+ "kRTCErrorTypeNames must have as many strings as RTCErrorType "
+ "has values.");
+
+} // namespace
+
+namespace webrtc {
+
+RTCError::RTCError(RTCError&& other) = default;
+RTCError& RTCError::operator=(RTCError&& other) = default;
+
+// static
+RTCError RTCError::OK() {
+ return RTCError();
+}
+
+const char* RTCError::message() const {
+ return message_.c_str();
+}
+
+void RTCError::set_message(std::string message) {
+ message_ = std::move(message);
+}
+
+absl::string_view ToString(RTCErrorType error) {
+ int index = static_cast<int>(error);
+ return kRTCErrorTypeNames[index];
+}
+
+} // namespace webrtc
diff --git a/api/rtc_error.h b/api/rtc_error.h
new file mode 100644
index 0000000..904a619
--- /dev/null
+++ b/api/rtc_error.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef API_RTC_ERROR_H_
+#define API_RTC_ERROR_H_
+
+#ifdef UNIT_TEST
+#include <ostream>
+#endif // UNIT_TEST
+#include <string>
+#include <utility> // For std::move.
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+// Enumeration to represent distinct classes of errors that an application
+// may wish to act upon differently. These roughly map to DOMExceptions or
+// RTCError "errorDetailEnum" values in the web API, as described in the
+// comments below.
+enum class RTCErrorType {
+ // No error.
+ NONE,
+
+ // An operation is valid, but currently unsupported.
+ // Maps to OperationError DOMException.
+ UNSUPPORTED_OPERATION,
+
+ // A supplied parameter is valid, but currently unsupported.
+ // Maps to OperationError DOMException.
+ UNSUPPORTED_PARAMETER,
+
+ // General error indicating that a supplied parameter is invalid.
+ // Maps to InvalidAccessError or TypeError DOMException depending on context.
+ INVALID_PARAMETER,
+
+ // Slightly more specific than INVALID_PARAMETER; a parameter's value was
+ // outside the allowed range.
+ // Maps to RangeError DOMException.
+ INVALID_RANGE,
+
+ // Slightly more specific than INVALID_PARAMETER; an error occurred while
+ // parsing string input.
+ // Maps to SyntaxError DOMException.
+ SYNTAX_ERROR,
+
+ // The object does not support this operation in its current state.
+ // Maps to InvalidStateError DOMException.
+ INVALID_STATE,
+
+ // An attempt was made to modify the object in an invalid way.
+ // Maps to InvalidModificationError DOMException.
+ INVALID_MODIFICATION,
+
+ // An error occurred within an underlying network protocol.
+ // Maps to NetworkError DOMException.
+ NETWORK_ERROR,
+
+ // Some resource has been exhausted; file handles, hardware resources, ports,
+ // etc.
+ // Maps to OperationError DOMException.
+ RESOURCE_EXHAUSTED,
+
+ // The operation failed due to an internal error.
+ // Maps to OperationError DOMException.
+ INTERNAL_ERROR,
+};
+
+// Roughly corresponds to RTCError in the web api. Holds an error type, a
+// message, and possibly additional information specific to that error.
+//
+// Doesn't contain anything beyond a type and message now, but will in the
+// future as more errors are implemented.
+class RTCError {
+ public:
+ // Constructors.
+
+ // Creates a "no error" error.
+ RTCError() {}
+ explicit RTCError(RTCErrorType type) : type_(type) {}
+
+ RTCError(RTCErrorType type, std::string message)
+ : type_(type), message_(std::move(message)) {}
+
+ // Delete the copy constructor and assignment operator; there aren't any use
+ // cases where you should need to copy an RTCError, as opposed to moving it.
+ // Can revisit this decision if use cases arise in the future.
+ RTCError(const RTCError& other) = delete;
+ RTCError& operator=(const RTCError& other) = delete;
+
+ // Move constructor and move-assignment operator.
+ RTCError(RTCError&& other);
+ RTCError& operator=(RTCError&& other);
+
+ // Identical to default constructed error.
+ //
+ // Preferred over the default constructor for code readability.
+ static RTCError OK();
+
+ // Error type.
+ RTCErrorType type() const { return type_; }
+ void set_type(RTCErrorType type) { type_ = type; }
+
+ // Human-readable message describing the error. Shouldn't be used for
+ // anything but logging/diagnostics, since messages are not guaranteed to be
+ // stable.
+ const char* message() const;
+
+ void set_message(std::string message);
+
+ // Convenience method for situations where you only care whether or not an
+ // error occurred.
+ bool ok() const { return type_ == RTCErrorType::NONE; }
+
+ private:
+ RTCErrorType type_ = RTCErrorType::NONE;
+ std::string message_;
+};
+
+// Outputs the error as a friendly string. Update this method when adding a new
+// error type.
+//
+// Only intended to be used for logging/diagnostics. The string_view points
+// to literal string that lives for the whole duration of the program.
+absl::string_view ToString(RTCErrorType error);
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ RTCErrorType error) {
+ return stream << ToString(error);
+}
+#endif // UNIT_TEST
+
+// Helper macro that can be used by implementations to create an error with a
+// message and log it. |message| should be a string literal or movable
+// std::string.
+#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \
+ { \
+ RTC_DCHECK(type != RTCErrorType::NONE); \
+ RTC_LOG(severity) << message << " (" << ToString(type) << ")"; \
+ return webrtc::RTCError(type, message); \
+ }
+
+#define LOG_AND_RETURN_ERROR(type, message) \
+ LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR)
+
+// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr
+// models the concept of an object that is either a usable value, or an error
+// Status explaining why such a value is not present. To this end RTCErrorOr<T>
+// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is
+// enforced by a debug check in most cases.
+//
+// The primary use-case for RTCErrorOr<T> is as the return value of a function
+// which may fail. For example, CreateRtpSender will fail if the parameters
+// could not be successfully applied at the media engine level, but if
+// successful will return a unique_ptr to an RtpSender.
+//
+// Example client usage for a RTCErrorOr<std::unique_ptr<T>>:
+//
+// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo = result.ConsumeValue();
+// foo->DoSomethingCool();
+// } else {
+// RTC_LOG(LS_ERROR) << result.error();
+// }
+//
+// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>:
+//
+// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) {
+// if (arg <= 0) {
+// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive");
+// } else {
+// return std::unique_ptr<Foo>(new Foo(arg));
+// }
+// }
+//
+template <typename T>
+class RTCErrorOr {
+ // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit
+ // conversion from Foo to Bar exists.
+ template <typename U>
+ friend class RTCErrorOr;
+
+ public:
+ typedef T element_type;
+
+ // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This
+ // is marked 'explicit' to try to catch cases like 'return {};', where people
+ // think RTCErrorOr<std::vector<int>> will be initialized with an empty
+ // vector, instead of a RTCErrorType::INTERNAL_ERROR error.
+ RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {}
+
+ // Constructs a new RTCErrorOr with the given non-ok error. After calling
+ // this constructor, calls to value() will DCHECK-fail.
+ //
+ // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return
+ // value, so it is convenient and sensible to be able to do 'return
+ // RTCError(...)' when the return type is RTCErrorOr<T>.
+ //
+ // REQUIRES: !error.ok(). This requirement is DCHECKed.
+ RTCErrorOr(RTCError&& error) : error_(std::move(error)) { // NOLINT
+ RTC_DCHECK(!error.ok());
+ }
+
+ // Constructs a new RTCErrorOr with the given value. After calling this
+ // constructor, calls to value() will succeed, and calls to error() will
+ // return a default-constructed RTCError.
+ //
+ // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type
+ // so it is convenient and sensible to be able to do 'return T()'
+ // when the return type is RTCErrorOr<T>.
+ RTCErrorOr(const T& value) : value_(value) {} // NOLINT
+ RTCErrorOr(T&& value) : value_(std::move(value)) {} // NOLINT
+
+ // Delete the copy constructor and assignment operator; there aren't any use
+ // cases where you should need to copy an RTCErrorOr, as opposed to moving
+ // it. Can revisit this decision if use cases arise in the future.
+ RTCErrorOr(const RTCErrorOr& other) = delete;
+ RTCErrorOr& operator=(const RTCErrorOr& other) = delete;
+
+ // Move constructor and move-assignment operator.
+ //
+ // Visual Studio doesn't support "= default" with move constructors or
+ // assignment operators (even though they compile, they segfault), so define
+ // them explicitly.
+ RTCErrorOr(RTCErrorOr&& other)
+ : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
+ RTCErrorOr& operator=(RTCErrorOr&& other) {
+ error_ = std::move(other.error_);
+ value_ = std::move(other.value_);
+ return *this;
+ }
+
+ // Conversion constructor and assignment operator; T must be copy or move
+ // constructible from U.
+ template <typename U>
+ RTCErrorOr(RTCErrorOr<U> other) // NOLINT
+ : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
+ template <typename U>
+ RTCErrorOr& operator=(RTCErrorOr<U> other) {
+ error_ = std::move(other.error_);
+ value_ = std::move(other.value_);
+ return *this;
+ }
+
+ // Returns a reference to our error. If this contains a T, then returns
+ // default-constructed RTCError.
+ const RTCError& error() const { return error_; }
+
+ // Moves the error. Can be useful if, say "CreateFoo" returns an
+ // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an
+ // RTCErrorOr<Bar>, and wants to forward the error up the stack.
+ RTCError MoveError() { return std::move(error_); }
+
+ // Returns this->error().ok()
+ bool ok() const { return error_.ok(); }
+
+ // Returns a reference to our current value, or DCHECK-fails if !this->ok().
+ //
+ // Can be convenient for the implementation; for example, a method may want
+ // to access the value in some way before returning it to the next method on
+ // the stack.
+ const T& value() const {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+ T& value() {
+ RTC_DCHECK(ok());
+ return value_;
+ }
+
+ // Moves our current value out of this object and returns it, or DCHECK-fails
+ // if !this->ok().
+ T MoveValue() {
+ RTC_DCHECK(ok());
+ return std::move(value_);
+ }
+
+ private:
+ RTCError error_;
+ T value_;
+};
+
+} // namespace webrtc
+
+#endif // API_RTC_ERROR_H_
diff --git a/api/rtc_error_unittest.cc b/api/rtc_error_unittest.cc
new file mode 100644
index 0000000..e9beb00
--- /dev/null
+++ b/api/rtc_error_unittest.cc
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2017 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 <utility>
+
+#include "api/rtc_error.h"
+#include "test/gtest.h"
+
+namespace {
+
+const int kDefaultMoveOnlyIntValue = 0xbadf00d;
+
+// Class that has no copy constructor, ensuring that RTCErrorOr can
+struct MoveOnlyInt {
+ MoveOnlyInt() {}
+ explicit MoveOnlyInt(int value) : value(value) {}
+ MoveOnlyInt(const MoveOnlyInt& other) = delete;
+ MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete;
+ MoveOnlyInt(MoveOnlyInt&& other) : value(other.value) {}
+ MoveOnlyInt& operator=(MoveOnlyInt&& other) {
+ value = other.value;
+ return *this;
+ }
+
+ int value = kDefaultMoveOnlyIntValue;
+};
+
+// Same as above. Used to test conversion from RTCErrorOr<A> to RTCErrorOr<B>
+// when A can be converted to B.
+struct MoveOnlyInt2 {
+ MoveOnlyInt2() {}
+ explicit MoveOnlyInt2(int value) : value(value) {}
+ MoveOnlyInt2(const MoveOnlyInt2& other) = delete;
+ MoveOnlyInt2& operator=(const MoveOnlyInt2& other) = delete;
+ MoveOnlyInt2(MoveOnlyInt2&& other) : value(other.value) {}
+ MoveOnlyInt2& operator=(MoveOnlyInt2&& other) {
+ value = other.value;
+ return *this;
+ }
+
+ explicit MoveOnlyInt2(MoveOnlyInt&& other) : value(other.value) {}
+ MoveOnlyInt2& operator=(MoveOnlyInt&& other) {
+ value = other.value;
+ return *this;
+ }
+
+ int value = kDefaultMoveOnlyIntValue;
+};
+
+} // namespace
+
+namespace webrtc {
+
+// Test that the default constructor creates a "no error" error.
+TEST(RTCErrorTest, DefaultConstructor) {
+ RTCError e;
+ EXPECT_EQ(RTCErrorType::NONE, e.type());
+ EXPECT_EQ(std::string(), e.message());
+ EXPECT_TRUE(e.ok());
+}
+
+TEST(RTCErrorTest, NormalConstructors) {
+ RTCError a(RTCErrorType::INVALID_PARAMETER);
+ EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, a.type());
+ EXPECT_EQ(std::string(), a.message());
+
+ // Constructor that takes const char* message.
+ RTCError b(RTCErrorType::UNSUPPORTED_PARAMETER, "foobar");
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, b.type());
+ EXPECT_EQ(std::string("foobar"), b.message());
+
+ // Constructor that takes std::string message.
+ RTCError c(RTCErrorType::INVALID_RANGE, std::string("new"));
+ EXPECT_EQ(RTCErrorType::INVALID_RANGE, c.type());
+ EXPECT_EQ(std::string("new"), c.message());
+}
+
+TEST(RTCErrorTest, MoveConstructor) {
+ // Static string.
+ RTCError a(RTCErrorType::INVALID_PARAMETER, "foo");
+ RTCError b(std::move(a));
+ EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, b.type());
+ EXPECT_EQ(std::string("foo"), b.message());
+
+ // Non-static string.
+ RTCError c(RTCErrorType::UNSUPPORTED_PARAMETER, std::string("bar"));
+ RTCError d(std::move(c));
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, d.type());
+ EXPECT_EQ(std::string("bar"), d.message());
+}
+
+TEST(RTCErrorTest, MoveAssignment) {
+ // Try all combinations of "is static string"/"is non-static string" moves.
+ RTCError e(RTCErrorType::INVALID_PARAMETER, "foo");
+
+ e = RTCError(RTCErrorType::UNSUPPORTED_PARAMETER, "bar");
+ EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, e.type());
+ EXPECT_EQ(std::string("bar"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("baz"));
+ EXPECT_EQ(std::string("baz"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("another"));
+ EXPECT_EQ(std::string("another"), e.message());
+
+ e = RTCError(RTCErrorType::SYNTAX_ERROR, "last");
+ EXPECT_EQ(std::string("last"), e.message());
+}
+
+// Test that the error returned by RTCError::OK() is a "no error" error.
+TEST(RTCErrorTest, OKConstant) {
+ RTCError ok = RTCError::OK();
+ EXPECT_EQ(RTCErrorType::NONE, ok.type());
+ EXPECT_EQ(std::string(), ok.message());
+ EXPECT_TRUE(ok.ok());
+}
+
+// Test that "error.ok()" behaves as expected.
+TEST(RTCErrorTest, OkMethod) {
+ RTCError success;
+ RTCError failure(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_TRUE(success.ok());
+ EXPECT_FALSE(failure.ok());
+}
+
+// Test that a message can be set using either static const strings or
+// std::strings.
+TEST(RTCErrorTest, SetMessage) {
+ RTCError e;
+ // Try all combinations of "is static string"/"is non-static string" calls.
+ e.set_message("foo");
+ EXPECT_EQ(std::string("foo"), e.message());
+
+ e.set_message("bar");
+ EXPECT_EQ(std::string("bar"), e.message());
+
+ e.set_message(std::string("string"));
+ EXPECT_EQ(std::string("string"), e.message());
+
+ e.set_message(std::string("more"));
+ EXPECT_EQ(std::string("more"), e.message());
+
+ e.set_message("love to test");
+ EXPECT_EQ(std::string("love to test"), e.message());
+}
+
+// Test that the default constructor creates an "INTERNAL_ERROR".
+TEST(RTCErrorOrTest, DefaultConstructor) {
+ RTCErrorOr<MoveOnlyInt> e;
+ EXPECT_EQ(RTCErrorType::INTERNAL_ERROR, e.error().type());
+}
+
+// Test that an RTCErrorOr can be implicitly constructed from a value.
+TEST(RTCErrorOrTest, ImplicitValueConstructor) {
+ RTCErrorOr<MoveOnlyInt> e = [] { return MoveOnlyInt(100); }();
+ EXPECT_EQ(100, e.value().value);
+}
+
+// Test that an RTCErrorOr can be implicitly constructed from an RTCError.
+TEST(RTCErrorOrTest, ImplicitErrorConstructor) {
+ RTCErrorOr<MoveOnlyInt> e = [] {
+ return RTCError(RTCErrorType::SYNTAX_ERROR);
+ }();
+ EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, e.error().type());
+}
+
+TEST(RTCErrorOrTest, MoveConstructor) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt> b(std::move(a));
+ EXPECT_EQ(5, b.value().value);
+}
+
+TEST(RTCErrorOrTest, MoveAssignment) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt> b(MoveOnlyInt(10));
+ a = std::move(b);
+ EXPECT_EQ(10, a.value().value);
+}
+
+TEST(RTCErrorOrTest, ConversionConstructor) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(1));
+ RTCErrorOr<MoveOnlyInt2> b(std::move(a));
+}
+
+TEST(RTCErrorOrTest, ConversionAssignment) {
+ RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5));
+ RTCErrorOr<MoveOnlyInt2> b(MoveOnlyInt2(10));
+ b = std::move(a);
+ EXPECT_EQ(5, b.value().value);
+}
+
+TEST(RTCErrorOrTest, OkMethod) {
+ RTCErrorOr<int> success(1337);
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_TRUE(success.ok());
+ EXPECT_FALSE(error.ok());
+}
+
+TEST(RTCErrorOrTest, MoveError) {
+ RTCErrorOr<int> e({RTCErrorType::SYNTAX_ERROR, "message"});
+ RTCError err = e.MoveError();
+ EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, err.type());
+ EXPECT_EQ(std::string("message"), err.message());
+}
+
+TEST(RTCErrorOrTest, MoveValue) {
+ RTCErrorOr<MoveOnlyInt> e(MoveOnlyInt(88));
+ MoveOnlyInt value = e.MoveValue();
+ EXPECT_EQ(88, value.value);
+}
+
+// Death tests.
+// Disabled on Android because death tests misbehave on Android, see
+// base/test/gtest_util.h.
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+TEST(RTCErrorOrDeathTest, ConstructWithOkError) {
+ RTCErrorOr<int> err;
+ EXPECT_DEATH(err = RTCError::OK(), "");
+}
+
+TEST(RTCErrorOrDeathTest, DereferenceErrorValue) {
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_DEATH(error.value(), "");
+}
+
+TEST(RTCErrorOrDeathTest, MoveErrorValue) {
+ RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR);
+ EXPECT_DEATH(error.MoveValue(), "");
+}
+
+#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+} // namespace webrtc
diff --git a/api/rtc_event_log_output.h b/api/rtc_event_log_output.h
new file mode 100644
index 0000000..92fb9e8
--- /dev/null
+++ b/api/rtc_event_log_output.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+#ifndef API_RTC_EVENT_LOG_OUTPUT_H_
+#define API_RTC_EVENT_LOG_OUTPUT_H_
+
+#include <string>
+
+namespace webrtc {
+
+// NOTE: This class is still under development and may change without notice.
+class RtcEventLogOutput {
+ public:
+ virtual ~RtcEventLogOutput() = default;
+
+ // An output normally starts out active, though that might not always be
+ // the case (e.g. failed to open a file for writing).
+ // Once an output has become inactive (e.g. maximum file size reached), it can
+ // never become active again.
+ virtual bool IsActive() const = 0;
+
+ // Write encoded events to an output. Returns true if the output was
+ // successfully written in its entirety. Otherwise, no guarantee is given
+ // about how much data was written, if any. The output sink becomes inactive
+ // after the first time |false| is returned. Write() may not be called on
+ // an inactive output sink.
+ virtual bool Write(const std::string& output) = 0;
+
+ // Indicates that buffers should be written to disk if applicable.
+ virtual void Flush() {}
+};
+
+} // namespace webrtc
+
+#endif // API_RTC_EVENT_LOG_OUTPUT_H_
diff --git a/api/rtp_headers.h b/api/rtp_headers.h
index c766899..8ab560c 100644
--- a/api/rtp_headers.h
+++ b/api/rtp_headers.h
@@ -82,6 +82,17 @@
// Mid represents RtpMid which is a string.
typedef StringRtpHeaderExtension Mid;
+struct FeedbackRequest {
+ // Determines whether the recv delta as specified in
+ // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
+ // should be included.
+ bool include_timestamps;
+ // Include feedback of received packets in the range [sequence_number -
+ // sequence_count + 1, sequence_number]. That is, no feedback will be sent if
+ // sequence_count is zero.
+ int sequence_count;
+};
+
struct RTPHeaderExtension {
RTPHeaderExtension();
RTPHeaderExtension(const RTPHeaderExtension& other);
@@ -93,6 +104,7 @@
uint32_t absoluteSendTime;
bool hasTransportSequenceNumber;
uint16_t transportSequenceNumber;
+ absl::optional<FeedbackRequest> feedback_request;
// Audio Level includes both level in dBov and voiced/unvoiced bit. See:
// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc
new file mode 100644
index 0000000..9ba2423
--- /dev/null
+++ b/api/rtp_parameters.cc
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017 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 "api/rtp_parameters.h"
+
+#include <algorithm>
+#include <string>
+
+#include "api/array_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+const double kDefaultBitratePriority = 1.0;
+
+RtcpFeedback::RtcpFeedback() = default;
+RtcpFeedback::RtcpFeedback(RtcpFeedbackType type) : type(type) {}
+RtcpFeedback::RtcpFeedback(RtcpFeedbackType type,
+ RtcpFeedbackMessageType message_type)
+ : type(type), message_type(message_type) {}
+RtcpFeedback::RtcpFeedback(const RtcpFeedback& rhs) = default;
+RtcpFeedback::~RtcpFeedback() = default;
+
+RtpCodecCapability::RtpCodecCapability() = default;
+RtpCodecCapability::~RtpCodecCapability() = default;
+
+RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() = default;
+RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
+ const std::string& uri)
+ : uri(uri) {}
+RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
+ const std::string& uri,
+ int preferred_id)
+ : uri(uri), preferred_id(preferred_id) {}
+RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default;
+
+RtpExtension::RtpExtension() = default;
+RtpExtension::RtpExtension(const std::string& uri, int id) : uri(uri), id(id) {}
+RtpExtension::RtpExtension(const std::string& uri, int id, bool encrypt)
+ : uri(uri), id(id), encrypt(encrypt) {}
+RtpExtension::~RtpExtension() = default;
+
+RtpFecParameters::RtpFecParameters() = default;
+RtpFecParameters::RtpFecParameters(FecMechanism mechanism)
+ : mechanism(mechanism) {}
+RtpFecParameters::RtpFecParameters(FecMechanism mechanism, uint32_t ssrc)
+ : ssrc(ssrc), mechanism(mechanism) {}
+RtpFecParameters::RtpFecParameters(const RtpFecParameters& rhs) = default;
+RtpFecParameters::~RtpFecParameters() = default;
+
+RtpRtxParameters::RtpRtxParameters() = default;
+RtpRtxParameters::RtpRtxParameters(uint32_t ssrc) : ssrc(ssrc) {}
+RtpRtxParameters::RtpRtxParameters(const RtpRtxParameters& rhs) = default;
+RtpRtxParameters::~RtpRtxParameters() = default;
+
+RtpEncodingParameters::RtpEncodingParameters() = default;
+RtpEncodingParameters::RtpEncodingParameters(const RtpEncodingParameters& rhs) =
+ default;
+RtpEncodingParameters::~RtpEncodingParameters() = default;
+
+RtpCodecParameters::RtpCodecParameters() = default;
+RtpCodecParameters::RtpCodecParameters(const RtpCodecParameters& rhs) = default;
+RtpCodecParameters::~RtpCodecParameters() = default;
+
+RtpCapabilities::RtpCapabilities() = default;
+RtpCapabilities::~RtpCapabilities() = default;
+
+RtcpParameters::RtcpParameters() = default;
+RtcpParameters::RtcpParameters(const RtcpParameters& rhs) = default;
+RtcpParameters::~RtcpParameters() = default;
+
+RtpParameters::RtpParameters() = default;
+RtpParameters::RtpParameters(const RtpParameters& rhs) = default;
+RtpParameters::~RtpParameters() = default;
+
+std::string RtpExtension::ToString() const {
+ char buf[256];
+ rtc::SimpleStringBuilder sb(buf);
+ sb << "{uri: " << uri;
+ sb << ", id: " << id;
+ if (encrypt) {
+ sb << ", encrypt";
+ }
+ sb << '}';
+ return sb.str();
+}
+
+const char RtpExtension::kAudioLevelUri[] =
+ "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+
+const char RtpExtension::kTimestampOffsetUri[] =
+ "urn:ietf:params:rtp-hdrext:toffset";
+
+const char RtpExtension::kAbsSendTimeUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+
+const char RtpExtension::kVideoRotationUri[] = "urn:3gpp:video-orientation";
+
+const char RtpExtension::kTransportSequenceNumberUri[] =
+ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
+const char RtpExtension::kTransportSequenceNumberV2Uri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02";
+
+// This extension allows applications to adaptively limit the playout delay
+// on frames as per the current needs. For example, a gaming application
+// has very different needs on end-to-end delay compared to a video-conference
+// application.
+const char RtpExtension::kPlayoutDelayUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
+
+const char RtpExtension::kVideoContentTypeUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type";
+
+const char RtpExtension::kVideoTimingUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/video-timing";
+
+const char RtpExtension::kMidUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid";
+
+const char RtpExtension::kFrameMarkingUri[] =
+ "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07";
+
+const char RtpExtension::kGenericFrameDescriptorUri00[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00";
+const char RtpExtension::kGenericFrameDescriptorUri01[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-01";
+const char RtpExtension::kGenericFrameDescriptorUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00";
+
+const char RtpExtension::kEncryptHeaderExtensionsUri[] =
+ "urn:ietf:params:rtp-hdrext:encrypt";
+
+const char RtpExtension::kColorSpaceUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/color-space";
+
+const char RtpExtension::kRidUri[] =
+ "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+
+const char RtpExtension::kRepairedRidUri[] =
+ "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
+
+constexpr int RtpExtension::kMinId;
+constexpr int RtpExtension::kMaxId;
+constexpr int RtpExtension::kMaxValueSize;
+constexpr int RtpExtension::kOneByteHeaderExtensionMaxId;
+constexpr int RtpExtension::kOneByteHeaderExtensionMaxValueSize;
+
+bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
+ return uri == webrtc::RtpExtension::kAudioLevelUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri ||
+ uri == webrtc::RtpExtension::kMidUri ||
+ uri == webrtc::RtpExtension::kRidUri ||
+ uri == webrtc::RtpExtension::kRepairedRidUri;
+}
+
+bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
+ return uri == webrtc::RtpExtension::kTimestampOffsetUri ||
+ uri == webrtc::RtpExtension::kAbsSendTimeUri ||
+ uri == webrtc::RtpExtension::kVideoRotationUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri ||
+ uri == webrtc::RtpExtension::kPlayoutDelayUri ||
+ uri == webrtc::RtpExtension::kVideoContentTypeUri ||
+ uri == webrtc::RtpExtension::kVideoTimingUri ||
+ uri == webrtc::RtpExtension::kMidUri ||
+ uri == webrtc::RtpExtension::kFrameMarkingUri ||
+ uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00 ||
+ uri == webrtc::RtpExtension::kGenericFrameDescriptorUri01 ||
+ uri == webrtc::RtpExtension::kColorSpaceUri ||
+ uri == webrtc::RtpExtension::kRidUri ||
+ uri == webrtc::RtpExtension::kRepairedRidUri;
+}
+
+bool RtpExtension::IsEncryptionSupported(const std::string& uri) {
+ return uri == webrtc::RtpExtension::kAudioLevelUri ||
+ uri == webrtc::RtpExtension::kTimestampOffsetUri ||
+#if !defined(ENABLE_EXTERNAL_AUTH)
+ // TODO(jbauch): Figure out a way to always allow "kAbsSendTimeUri"
+ // here and filter out later if external auth is really used in
+ // srtpfilter. External auth is used by Chromium and replaces the
+ // extension header value of "kAbsSendTimeUri", so it must not be
+ // encrypted (which can't be done by Chromium).
+ uri == webrtc::RtpExtension::kAbsSendTimeUri ||
+#endif
+ uri == webrtc::RtpExtension::kVideoRotationUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
+ uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri ||
+ uri == webrtc::RtpExtension::kPlayoutDelayUri ||
+ uri == webrtc::RtpExtension::kVideoContentTypeUri ||
+ uri == webrtc::RtpExtension::kMidUri ||
+ uri == webrtc::RtpExtension::kRidUri ||
+ uri == webrtc::RtpExtension::kRepairedRidUri;
+}
+
+const RtpExtension* RtpExtension::FindHeaderExtensionByUri(
+ const std::vector<RtpExtension>& extensions,
+ const std::string& uri) {
+ for (const auto& extension : extensions) {
+ if (extension.uri == uri) {
+ return &extension;
+ }
+ }
+ return nullptr;
+}
+
+std::vector<RtpExtension> RtpExtension::FilterDuplicateNonEncrypted(
+ const std::vector<RtpExtension>& extensions) {
+ std::vector<RtpExtension> filtered;
+ for (auto extension = extensions.begin(); extension != extensions.end();
+ ++extension) {
+ if (extension->encrypt) {
+ filtered.push_back(*extension);
+ continue;
+ }
+
+ // Only add non-encrypted extension if no encrypted with the same URI
+ // is also present...
+ if (std::find_if(extension + 1, extensions.end(),
+ [extension](const RtpExtension& check) {
+ return extension->uri == check.uri;
+ }) != extensions.end()) {
+ continue;
+ }
+
+ // ...and has not been added before.
+ if (!FindHeaderExtensionByUri(filtered, extension->uri)) {
+ filtered.push_back(*extension);
+ }
+ }
+ return filtered;
+}
+} // namespace webrtc
diff --git a/api/rtp_parameters.h b/api/rtp_parameters.h
new file mode 100644
index 0000000..b7d7702
--- /dev/null
+++ b/api/rtp_parameters.h
@@ -0,0 +1,664 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef API_RTP_PARAMETERS_H_
+#define API_RTP_PARAMETERS_H_
+
+#include <stdint.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/media_types.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// These structures are intended to mirror those defined by:
+// http://draft.ortc.org/#rtcrtpdictionaries*
+// Contains everything specified as of 2017 Jan 24.
+//
+// They are used when retrieving or modifying the parameters of an
+// RtpSender/RtpReceiver, or retrieving capabilities.
+//
+// Note on conventions: Where ORTC may use "octet", "short" and "unsigned"
+// types, we typically use "int", in keeping with our style guidelines. The
+// parameter's actual valid range will be enforced when the parameters are set,
+// rather than when the parameters struct is built. An exception is made for
+// SSRCs, since they use the full unsigned 32-bit range, and aren't expected to
+// be used for any numeric comparisons/operations.
+//
+// Additionally, where ORTC uses strings, we may use enums for things that have
+// a fixed number of supported values. However, for things that can be extended
+// (such as codecs, by providing an external encoder factory), a string
+// identifier is used.
+
+enum class FecMechanism {
+ RED,
+ RED_AND_ULPFEC,
+ FLEXFEC,
+};
+
+// Used in RtcpFeedback struct.
+enum class RtcpFeedbackType {
+ CCM,
+ NACK,
+ REMB, // "goog-remb"
+ TRANSPORT_CC,
+};
+
+// Used in RtcpFeedback struct when type is NACK or CCM.
+enum class RtcpFeedbackMessageType {
+ // Equivalent to {type: "nack", parameter: undefined} in ORTC.
+ GENERIC_NACK,
+ PLI, // Usable with NACK.
+ FIR, // Usable with CCM.
+};
+
+enum class DtxStatus {
+ DISABLED,
+ ENABLED,
+};
+
+// Based on the spec in
+// https://w3c.github.io/webrtc-pc/#idl-def-rtcdegradationpreference.
+// These options are enforced on a best-effort basis. For instance, all of
+// these options may suffer some frame drops in order to avoid queuing.
+// TODO(sprang): Look into possibility of more strictly enforcing the
+// maintain-framerate option.
+// TODO(deadbeef): Default to "balanced", as the spec indicates?
+enum class DegradationPreference {
+ // Don't take any actions based on over-utilization signals. Not part of the
+ // web API.
+ DISABLED,
+ // On over-use, request lower frame rate, possibly causing frame drops.
+ MAINTAIN_FRAMERATE,
+ // On over-use, request lower resolution, possibly causing down-scaling.
+ MAINTAIN_RESOLUTION,
+ // Try to strike a "pleasing" balance between frame rate or resolution.
+ BALANCED,
+};
+
+extern const double kDefaultBitratePriority;
+
+struct RtcpFeedback {
+ RtcpFeedbackType type = RtcpFeedbackType::CCM;
+
+ // Equivalent to ORTC "parameter" field with slight differences:
+ // 1. It's an enum instead of a string.
+ // 2. Generic NACK feedback is represented by a GENERIC_NACK message type,
+ // rather than an unset "parameter" value.
+ absl::optional<RtcpFeedbackMessageType> message_type;
+
+ // Constructors for convenience.
+ RtcpFeedback();
+ explicit RtcpFeedback(RtcpFeedbackType type);
+ RtcpFeedback(RtcpFeedbackType type, RtcpFeedbackMessageType message_type);
+ RtcpFeedback(const RtcpFeedback&);
+ ~RtcpFeedback();
+
+ bool operator==(const RtcpFeedback& o) const {
+ return type == o.type && message_type == o.message_type;
+ }
+ bool operator!=(const RtcpFeedback& o) const { return !(*this == o); }
+};
+
+// RtpCodecCapability is to RtpCodecParameters as RtpCapabilities is to
+// RtpParameters. This represents the static capabilities of an endpoint's
+// implementation of a codec.
+struct RtpCodecCapability {
+ RtpCodecCapability();
+ ~RtpCodecCapability();
+
+ // Build MIME "type/subtype" string from |name| and |kind|.
+ std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; }
+
+ // Used to identify the codec. Equivalent to MIME subtype.
+ std::string name;
+
+ // The media type of this codec. Equivalent to MIME top-level type.
+ cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO;
+
+ // Clock rate in Hertz. If unset, the codec is applicable to any clock rate.
+ absl::optional<int> clock_rate;
+
+ // Default payload type for this codec. Mainly needed for codecs that use
+ // that have statically assigned payload types.
+ absl::optional<int> preferred_payload_type;
+
+ // Maximum packetization time supported by an RtpReceiver for this codec.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<int> max_ptime;
+
+ // Preferred packetization time for an RtpReceiver or RtpSender of this
+ // codec.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<int> ptime;
+
+ // The number of audio channels supported. Unused for video codecs.
+ absl::optional<int> num_channels;
+
+ // Feedback mechanisms supported for this codec.
+ std::vector<RtcpFeedback> rtcp_feedback;
+
+ // Codec-specific parameters that must be signaled to the remote party.
+ //
+ // Corresponds to "a=fmtp" parameters in SDP.
+ //
+ // Contrary to ORTC, these parameters are named using all lowercase strings.
+ // This helps make the mapping to SDP simpler, if an application is using
+ // SDP. Boolean values are represented by the string "1".
+ std::unordered_map<std::string, std::string> parameters;
+
+ // Codec-specific parameters that may optionally be signaled to the remote
+ // party.
+ // TODO(deadbeef): Not implemented.
+ std::unordered_map<std::string, std::string> options;
+
+ // Maximum number of temporal layer extensions supported by this codec.
+ // For example, a value of 1 indicates that 2 total layers are supported.
+ // TODO(deadbeef): Not implemented.
+ int max_temporal_layer_extensions = 0;
+
+ // Maximum number of spatial layer extensions supported by this codec.
+ // For example, a value of 1 indicates that 2 total layers are supported.
+ // TODO(deadbeef): Not implemented.
+ int max_spatial_layer_extensions = 0;
+
+ // Whether the implementation can send/receive SVC layers with distinct
+ // SSRCs. Always false for audio codecs. True for video codecs that support
+ // scalable video coding with MRST.
+ // TODO(deadbeef): Not implemented.
+ bool svc_multi_stream_support = false;
+
+ bool operator==(const RtpCodecCapability& o) const {
+ return name == o.name && kind == o.kind && clock_rate == o.clock_rate &&
+ preferred_payload_type == o.preferred_payload_type &&
+ max_ptime == o.max_ptime && ptime == o.ptime &&
+ num_channels == o.num_channels && rtcp_feedback == o.rtcp_feedback &&
+ parameters == o.parameters && options == o.options &&
+ max_temporal_layer_extensions == o.max_temporal_layer_extensions &&
+ max_spatial_layer_extensions == o.max_spatial_layer_extensions &&
+ svc_multi_stream_support == o.svc_multi_stream_support;
+ }
+ bool operator!=(const RtpCodecCapability& o) const { return !(*this == o); }
+};
+
+// Used in RtpCapabilities; represents the capabilities/preferences of an
+// implementation for a header extension.
+//
+// Just called "RtpHeaderExtension" in ORTC, but the "Capability" suffix was
+// added here for consistency and to avoid confusion with
+// RtpHeaderExtensionParameters.
+//
+// Note that ORTC includes a "kind" field, but we omit this because it's
+// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)",
+// you know you're getting audio capabilities.
+struct RtpHeaderExtensionCapability {
+ // URI of this extension, as defined in RFC8285.
+ std::string uri;
+
+ // Preferred value of ID that goes in the packet.
+ absl::optional<int> preferred_id;
+
+ // If true, it's preferred that the value in the header is encrypted.
+ // TODO(deadbeef): Not implemented.
+ bool preferred_encrypt = false;
+
+ // Constructors for convenience.
+ RtpHeaderExtensionCapability();
+ explicit RtpHeaderExtensionCapability(const std::string& uri);
+ RtpHeaderExtensionCapability(const std::string& uri, int preferred_id);
+ ~RtpHeaderExtensionCapability();
+
+ bool operator==(const RtpHeaderExtensionCapability& o) const {
+ return uri == o.uri && preferred_id == o.preferred_id &&
+ preferred_encrypt == o.preferred_encrypt;
+ }
+ bool operator!=(const RtpHeaderExtensionCapability& o) const {
+ return !(*this == o);
+ }
+};
+
+// RTP header extension, see RFC8285.
+struct RtpExtension {
+ RtpExtension();
+ RtpExtension(const std::string& uri, int id);
+ RtpExtension(const std::string& uri, int id, bool encrypt);
+ ~RtpExtension();
+ std::string ToString() const;
+ bool operator==(const RtpExtension& rhs) const {
+ return uri == rhs.uri && id == rhs.id && encrypt == rhs.encrypt;
+ }
+ static bool IsSupportedForAudio(const std::string& uri);
+ static bool IsSupportedForVideo(const std::string& uri);
+ // Return "true" if the given RTP header extension URI may be encrypted.
+ static bool IsEncryptionSupported(const std::string& uri);
+
+ // Returns the named header extension if found among all extensions,
+ // nullptr otherwise.
+ static const RtpExtension* FindHeaderExtensionByUri(
+ const std::vector<RtpExtension>& extensions,
+ const std::string& uri);
+
+ // Return a list of RTP header extensions with the non-encrypted extensions
+ // removed if both the encrypted and non-encrypted extension is present for
+ // the same URI.
+ static std::vector<RtpExtension> FilterDuplicateNonEncrypted(
+ const std::vector<RtpExtension>& extensions);
+
+ // Header extension for audio levels, as defined in:
+ // http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03
+ static const char kAudioLevelUri[];
+
+ // Header extension for RTP timestamp offset, see RFC 5450 for details:
+ // http://tools.ietf.org/html/rfc5450
+ static const char kTimestampOffsetUri[];
+
+ // Header extension for absolute send time, see url for details:
+ // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
+ static const char kAbsSendTimeUri[];
+
+ // Header extension for coordination of video orientation, see url for
+ // details:
+ // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ts_126114v120700p.pdf
+ static const char kVideoRotationUri[];
+
+ // Header extension for video content type. E.g. default or screenshare.
+ static const char kVideoContentTypeUri[];
+
+ // Header extension for video timing.
+ static const char kVideoTimingUri[];
+
+ // Header extension for video frame marking.
+ static const char kFrameMarkingUri[];
+
+ // Experimental codec agnostic frame descriptor.
+ static const char kGenericFrameDescriptorUri00[];
+ static const char kGenericFrameDescriptorUri01[];
+ // TODO(bugs.webrtc.org/10243): Remove once dependencies have been updated.
+ static const char kGenericFrameDescriptorUri[];
+
+ // Header extension for transport sequence number, see url for details:
+ // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions
+ static const char kTransportSequenceNumberUri[];
+ static const char kTransportSequenceNumberV2Uri[];
+
+ static const char kPlayoutDelayUri[];
+
+ // Header extension for identifying media section within a transport.
+ // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-49#section-15
+ static const char kMidUri[];
+
+ // Encryption of Header Extensions, see RFC 6904 for details:
+ // https://tools.ietf.org/html/rfc6904
+ static const char kEncryptHeaderExtensionsUri[];
+
+ // Header extension for color space information.
+ static const char kColorSpaceUri[];
+
+ // Header extension for RIDs and Repaired RIDs
+ // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
+ // https://tools.ietf.org/html/draft-ietf-mmusic-rid-15
+ static const char kRidUri[];
+ static const char kRepairedRidUri[];
+
+ // Inclusive min and max IDs for two-byte header extensions and one-byte
+ // header extensions, per RFC8285 Section 4.2-4.3.
+ static constexpr int kMinId = 1;
+ static constexpr int kMaxId = 255;
+ static constexpr int kMaxValueSize = 255;
+ static constexpr int kOneByteHeaderExtensionMaxId = 14;
+ static constexpr int kOneByteHeaderExtensionMaxValueSize = 16;
+
+ std::string uri;
+ int id = 0;
+ bool encrypt = false;
+};
+
+// TODO(deadbeef): This is missing the "encrypt" flag, which is unimplemented.
+typedef RtpExtension RtpHeaderExtensionParameters;
+
+struct RtpFecParameters {
+ // If unset, a value is chosen by the implementation.
+ // Works just like RtpEncodingParameters::ssrc.
+ absl::optional<uint32_t> ssrc;
+
+ FecMechanism mechanism = FecMechanism::RED;
+
+ // Constructors for convenience.
+ RtpFecParameters();
+ explicit RtpFecParameters(FecMechanism mechanism);
+ RtpFecParameters(FecMechanism mechanism, uint32_t ssrc);
+ RtpFecParameters(const RtpFecParameters&);
+ ~RtpFecParameters();
+
+ bool operator==(const RtpFecParameters& o) const {
+ return ssrc == o.ssrc && mechanism == o.mechanism;
+ }
+ bool operator!=(const RtpFecParameters& o) const { return !(*this == o); }
+};
+
+struct RtpRtxParameters {
+ // If unset, a value is chosen by the implementation.
+ // Works just like RtpEncodingParameters::ssrc.
+ absl::optional<uint32_t> ssrc;
+
+ // Constructors for convenience.
+ RtpRtxParameters();
+ explicit RtpRtxParameters(uint32_t ssrc);
+ RtpRtxParameters(const RtpRtxParameters&);
+ ~RtpRtxParameters();
+
+ bool operator==(const RtpRtxParameters& o) const { return ssrc == o.ssrc; }
+ bool operator!=(const RtpRtxParameters& o) const { return !(*this == o); }
+};
+
+struct RtpEncodingParameters {
+ RtpEncodingParameters();
+ RtpEncodingParameters(const RtpEncodingParameters&);
+ ~RtpEncodingParameters();
+
+ // If unset, a value is chosen by the implementation.
+ //
+ // Note that the chosen value is NOT returned by GetParameters, because it
+ // may change due to an SSRC conflict, in which case the conflict is handled
+ // internally without any event. Another way of looking at this is that an
+ // unset SSRC acts as a "wildcard" SSRC.
+ absl::optional<uint32_t> ssrc;
+
+ // Can be used to reference a codec in the |codecs| member of the
+ // RtpParameters that contains this RtpEncodingParameters. If unset, the
+ // implementation will choose the first possible codec (if a sender), or
+ // prepare to receive any codec (for a receiver).
+ // TODO(deadbeef): Not implemented. Implementation of RtpSender will always
+ // choose the first codec from the list.
+ absl::optional<int> codec_payload_type;
+
+ // Specifies the FEC mechanism, if set.
+ // TODO(deadbeef): Not implemented. Current implementation will use whatever
+ // FEC codecs are available, including red+ulpfec.
+ absl::optional<RtpFecParameters> fec;
+
+ // Specifies the RTX parameters, if set.
+ // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
+ absl::optional<RtpRtxParameters> rtx;
+
+ // Only used for audio. If set, determines whether or not discontinuous
+ // transmission will be used, if an available codec supports it. If not
+ // set, the implementation default setting will be used.
+ // TODO(deadbeef): Not implemented. Current implementation will use a CN
+ // codec as long as it's present.
+ absl::optional<DtxStatus> dtx;
+
+ // The relative bitrate priority of this encoding. Currently this is
+ // implemented for the entire rtp sender by using the value of the first
+ // encoding parameter.
+ // TODO(webrtc.bugs.org/8630): Implement this per encoding parameter.
+ // Currently there is logic for how bitrate is distributed per simulcast layer
+ // in the VideoBitrateAllocator. This must be updated to incorporate relative
+ // bitrate priority.
+ double bitrate_priority = kDefaultBitratePriority;
+
+ // The relative DiffServ Code Point priority for this encoding, allowing
+ // packets to be marked relatively higher or lower without affecting
+ // bandwidth allocations. See https://w3c.github.io/webrtc-dscp-exp/ . NB
+ // we follow chromium's translation of the allowed string enum values for
+ // this field to 1.0, 0.5, et cetera, similar to bitrate_priority above.
+ // TODO(http://crbug.com/webrtc/8630): Implement this per encoding parameter.
+ double network_priority = kDefaultBitratePriority;
+
+ // Indicates the preferred duration of media represented by a packet in
+ // milliseconds for this encoding. If set, this will take precedence over the
+ // ptime set in the RtpCodecParameters. This could happen if SDP negotiation
+ // creates a ptime for a specific codec, which is later changed in the
+ // RtpEncodingParameters by the application.
+ // TODO(bugs.webrtc.org/8819): Not implemented.
+ absl::optional<int> ptime;
+
+ // If set, this represents the Transport Independent Application Specific
+ // maximum bandwidth defined in RFC3890. If unset, there is no maximum
+ // bitrate. Currently this is implemented for the entire rtp sender by using
+ // the value of the first encoding parameter.
+ //
+ // Just called "maxBitrate" in ORTC spec.
+ //
+ // TODO(deadbeef): With ORTC RtpSenders, this currently sets the total
+ // bandwidth for the entire bandwidth estimator (audio and video). This is
+ // just always how "b=AS" was handled, but it's not correct and should be
+ // fixed.
+ absl::optional<int> max_bitrate_bps;
+
+ // Specifies the minimum bitrate in bps for video.
+ // TODO(asapersson): Not implemented for ORTC API.
+ absl::optional<int> min_bitrate_bps;
+
+ // Specifies the maximum framerate in fps for video.
+ // TODO(asapersson): Different framerates are not supported per simulcast
+ // layer. If set, the maximum |max_framerate| is currently used.
+ // Not supported for screencast.
+ absl::optional<int> max_framerate;
+
+ // Specifies the number of temporal layers for video (if the feature is
+ // supported by the codec implementation).
+ // TODO(asapersson): Different number of temporal layers are not supported
+ // per simulcast layer.
+ // Screencast support is experimental.
+ absl::optional<int> num_temporal_layers;
+
+ // For video, scale the resolution down by this factor.
+ absl::optional<double> scale_resolution_down_by;
+
+ // Scale the framerate down by this factor.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<double> scale_framerate_down_by;
+
+ // For an RtpSender, set to true to cause this encoding to be encoded and
+ // sent, and false for it not to be encoded and sent. This allows control
+ // across multiple encodings of a sender for turning simulcast layers on and
+ // off.
+ // TODO(webrtc.bugs.org/8807): Updating this parameter will trigger an encoder
+ // reset, but this isn't necessarily required.
+ bool active = true;
+
+ // Value to use for RID RTP header extension.
+ // Called "encodingId" in ORTC.
+ std::string rid;
+
+ // RIDs of encodings on which this layer depends.
+ // Called "dependencyEncodingIds" in ORTC spec.
+ // TODO(deadbeef): Not implemented.
+ std::vector<std::string> dependency_rids;
+
+ bool operator==(const RtpEncodingParameters& o) const {
+ return ssrc == o.ssrc && codec_payload_type == o.codec_payload_type &&
+ fec == o.fec && rtx == o.rtx && dtx == o.dtx &&
+ bitrate_priority == o.bitrate_priority &&
+ network_priority == o.network_priority && ptime == o.ptime &&
+ max_bitrate_bps == o.max_bitrate_bps &&
+ min_bitrate_bps == o.min_bitrate_bps &&
+ max_framerate == o.max_framerate &&
+ num_temporal_layers == o.num_temporal_layers &&
+ scale_resolution_down_by == o.scale_resolution_down_by &&
+ scale_framerate_down_by == o.scale_framerate_down_by &&
+ active == o.active && rid == o.rid &&
+ dependency_rids == o.dependency_rids;
+ }
+ bool operator!=(const RtpEncodingParameters& o) const {
+ return !(*this == o);
+ }
+};
+
+struct RtpCodecParameters {
+ RtpCodecParameters();
+ RtpCodecParameters(const RtpCodecParameters&);
+ ~RtpCodecParameters();
+
+ // Build MIME "type/subtype" string from |name| and |kind|.
+ std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; }
+
+ // Used to identify the codec. Equivalent to MIME subtype.
+ std::string name;
+
+ // The media type of this codec. Equivalent to MIME top-level type.
+ cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO;
+
+ // Payload type used to identify this codec in RTP packets.
+ // This must always be present, and must be unique across all codecs using
+ // the same transport.
+ int payload_type = 0;
+
+ // If unset, the implementation default is used.
+ absl::optional<int> clock_rate;
+
+ // The number of audio channels used. Unset for video codecs. If unset for
+ // audio, the implementation default is used.
+ // TODO(deadbeef): The "implementation default" part isn't fully implemented.
+ // Only defaults to 1, even though some codecs (such as opus) should really
+ // default to 2.
+ absl::optional<int> num_channels;
+
+ // The maximum packetization time to be used by an RtpSender.
+ // If |ptime| is also set, this will be ignored.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<int> max_ptime;
+
+ // The packetization time to be used by an RtpSender.
+ // If unset, will use any time up to max_ptime.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<int> ptime;
+
+ // Feedback mechanisms to be used for this codec.
+ // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
+ std::vector<RtcpFeedback> rtcp_feedback;
+
+ // Codec-specific parameters that must be signaled to the remote party.
+ //
+ // Corresponds to "a=fmtp" parameters in SDP.
+ //
+ // Contrary to ORTC, these parameters are named using all lowercase strings.
+ // This helps make the mapping to SDP simpler, if an application is using
+ // SDP. Boolean values are represented by the string "1".
+ std::unordered_map<std::string, std::string> parameters;
+
+ bool operator==(const RtpCodecParameters& o) const {
+ return name == o.name && kind == o.kind && payload_type == o.payload_type &&
+ clock_rate == o.clock_rate && num_channels == o.num_channels &&
+ max_ptime == o.max_ptime && ptime == o.ptime &&
+ rtcp_feedback == o.rtcp_feedback && parameters == o.parameters;
+ }
+ bool operator!=(const RtpCodecParameters& o) const { return !(*this == o); }
+};
+
+// RtpCapabilities is used to represent the static capabilities of an
+// endpoint. An application can use these capabilities to construct an
+// RtpParameters.
+struct RtpCapabilities {
+ RtpCapabilities();
+ ~RtpCapabilities();
+
+ // Supported codecs.
+ std::vector<RtpCodecCapability> codecs;
+
+ // Supported RTP header extensions.
+ std::vector<RtpHeaderExtensionCapability> header_extensions;
+
+ // Supported Forward Error Correction (FEC) mechanisms. Note that the RED,
+ // ulpfec and flexfec codecs used by these mechanisms will still appear in
+ // |codecs|.
+ std::vector<FecMechanism> fec;
+
+ bool operator==(const RtpCapabilities& o) const {
+ return codecs == o.codecs && header_extensions == o.header_extensions &&
+ fec == o.fec;
+ }
+ bool operator!=(const RtpCapabilities& o) const { return !(*this == o); }
+};
+
+struct RtcpParameters final {
+ RtcpParameters();
+ RtcpParameters(const RtcpParameters&);
+ ~RtcpParameters();
+
+ // The SSRC to be used in the "SSRC of packet sender" field. If not set, one
+ // will be chosen by the implementation.
+ // TODO(deadbeef): Not implemented.
+ absl::optional<uint32_t> ssrc;
+
+ // The Canonical Name (CNAME) used by RTCP (e.g. in SDES messages).
+ //
+ // If empty in the construction of the RtpTransport, one will be generated by
+ // the implementation, and returned in GetRtcpParameters. Multiple
+ // RtpTransports created by the same OrtcFactory will use the same generated
+ // CNAME.
+ //
+ // If empty when passed into SetParameters, the CNAME simply won't be
+ // modified.
+ std::string cname;
+
+ // Send reduced-size RTCP?
+ bool reduced_size = false;
+
+ // Send RTCP multiplexed on the RTP transport?
+ // Not used with PeerConnection senders/receivers
+ bool mux = true;
+
+ bool operator==(const RtcpParameters& o) const {
+ return ssrc == o.ssrc && cname == o.cname &&
+ reduced_size == o.reduced_size && mux == o.mux;
+ }
+ bool operator!=(const RtcpParameters& o) const { return !(*this == o); }
+};
+
+struct RTC_EXPORT RtpParameters {
+ RtpParameters();
+ RtpParameters(const RtpParameters&);
+ ~RtpParameters();
+
+ // Used when calling getParameters/setParameters with a PeerConnection
+ // RtpSender, to ensure that outdated parameters are not unintentionally
+ // applied successfully.
+ std::string transaction_id;
+
+ // Value to use for MID RTP header extension.
+ // Called "muxId" in ORTC.
+ // TODO(deadbeef): Not implemented.
+ std::string mid;
+
+ std::vector<RtpCodecParameters> codecs;
+
+ std::vector<RtpHeaderExtensionParameters> header_extensions;
+
+ std::vector<RtpEncodingParameters> encodings;
+
+ // Only available with a Peerconnection RtpSender.
+ // In ORTC, our API includes an additional "RtpTransport"
+ // abstraction on which RTCP parameters are set.
+ RtcpParameters rtcp;
+
+ // When bandwidth is constrained and the RtpSender needs to choose between
+ // degrading resolution or degrading framerate, degradationPreference
+ // indicates which is preferred. Only for video tracks.
+ DegradationPreference degradation_preference =
+ DegradationPreference::BALANCED;
+
+ bool operator==(const RtpParameters& o) const {
+ return mid == o.mid && codecs == o.codecs &&
+ header_extensions == o.header_extensions &&
+ encodings == o.encodings && rtcp == o.rtcp &&
+ degradation_preference == o.degradation_preference;
+ }
+ bool operator!=(const RtpParameters& o) const { return !(*this == o); }
+};
+
+} // namespace webrtc
+
+#endif // API_RTP_PARAMETERS_H_
diff --git a/api/rtp_parameters_unittest.cc b/api/rtp_parameters_unittest.cc
new file mode 100644
index 0000000..b6f2482
--- /dev/null
+++ b/api/rtp_parameters_unittest.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 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 "api/rtp_parameters.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+using webrtc::RtpExtension;
+
+static const char kExtensionUri1[] = "extension-uri1";
+static const char kExtensionUri2[] = "extension-uri2";
+
+static const RtpExtension kExtension1(kExtensionUri1, 1);
+static const RtpExtension kExtension1Encrypted(kExtensionUri1, 10, true);
+static const RtpExtension kExtension2(kExtensionUri2, 2);
+
+TEST(RtpExtensionTest, FilterDuplicateNonEncrypted) {
+ std::vector<RtpExtension> extensions;
+ std::vector<RtpExtension> filtered;
+
+ extensions.push_back(kExtension1);
+ extensions.push_back(kExtension1Encrypted);
+ filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions);
+ EXPECT_EQ(1u, filtered.size());
+ EXPECT_EQ(std::vector<RtpExtension>{kExtension1Encrypted}, filtered);
+
+ extensions.clear();
+ extensions.push_back(kExtension1Encrypted);
+ extensions.push_back(kExtension1);
+ filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions);
+ EXPECT_EQ(1u, filtered.size());
+ EXPECT_EQ(std::vector<RtpExtension>{kExtension1Encrypted}, filtered);
+
+ extensions.clear();
+ extensions.push_back(kExtension1);
+ extensions.push_back(kExtension2);
+ filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions);
+ EXPECT_EQ(2u, filtered.size());
+ EXPECT_EQ(extensions, filtered);
+}
+} // namespace webrtc
diff --git a/api/rtp_receiver_interface.cc b/api/rtp_receiver_interface.cc
new file mode 100644
index 0000000..52f72df
--- /dev/null
+++ b/api/rtp_receiver_interface.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 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 "api/rtp_receiver_interface.h"
+
+namespace webrtc {
+
+RtpSource::RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type)
+ : timestamp_ms_(timestamp_ms),
+ source_id_(source_id),
+ source_type_(source_type) {}
+
+RtpSource::RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type,
+ uint8_t audio_level)
+ : timestamp_ms_(timestamp_ms),
+ source_id_(source_id),
+ source_type_(source_type),
+ audio_level_(audio_level) {}
+
+RtpSource::RtpSource(const RtpSource&) = default;
+RtpSource& RtpSource::operator=(const RtpSource&) = default;
+RtpSource::~RtpSource() = default;
+
+std::vector<std::string> RtpReceiverInterface::stream_ids() const {
+ return {};
+}
+
+std::vector<rtc::scoped_refptr<MediaStreamInterface>>
+RtpReceiverInterface::streams() const {
+ return {};
+}
+
+std::vector<RtpSource> RtpReceiverInterface::GetSources() const {
+ return {};
+}
+
+void RtpReceiverInterface::SetFrameDecryptor(
+ rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) {}
+
+rtc::scoped_refptr<FrameDecryptorInterface>
+RtpReceiverInterface::GetFrameDecryptor() const {
+ return nullptr;
+}
+
+rtc::scoped_refptr<DtlsTransportInterface>
+RtpReceiverInterface::dtls_transport() const {
+ return nullptr;
+}
+
+} // namespace webrtc
diff --git a/api/rtp_receiver_interface.h b/api/rtp_receiver_interface.h
new file mode 100644
index 0000000..7d9870b
--- /dev/null
+++ b/api/rtp_receiver_interface.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2015 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.
+ */
+
+// This file contains interfaces for RtpReceivers
+// http://w3c.github.io/webrtc-pc/#rtcrtpreceiver-interface
+
+#ifndef API_RTP_RECEIVER_INTERFACE_H_
+#define API_RTP_RECEIVER_INTERFACE_H_
+
+#include <string>
+#include <vector>
+
+#include "api/crypto/frame_decryptor_interface.h"
+#include "api/dtls_transport_interface.h"
+#include "api/media_stream_interface.h"
+#include "api/media_types.h"
+#include "api/proxy.h"
+#include "api/rtp_parameters.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+enum class RtpSourceType {
+ SSRC,
+ CSRC,
+};
+
+class RtpSource {
+ public:
+ RtpSource() = delete;
+ RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type);
+ RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type,
+ uint8_t audio_level);
+ RtpSource(const RtpSource&);
+ RtpSource& operator=(const RtpSource&);
+ ~RtpSource();
+
+ int64_t timestamp_ms() const { return timestamp_ms_; }
+ void update_timestamp_ms(int64_t timestamp_ms) {
+ RTC_DCHECK_LE(timestamp_ms_, timestamp_ms);
+ timestamp_ms_ = timestamp_ms;
+ }
+
+ // The identifier of the source can be the CSRC or the SSRC.
+ uint32_t source_id() const { return source_id_; }
+
+ // The source can be either a contributing source or a synchronization source.
+ RtpSourceType source_type() const { return source_type_; }
+
+ absl::optional<uint8_t> audio_level() const { return audio_level_; }
+ void set_audio_level(const absl::optional<uint8_t>& level) {
+ audio_level_ = level;
+ }
+
+ bool operator==(const RtpSource& o) const {
+ return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() &&
+ source_type_ == o.source_type() && audio_level_ == o.audio_level_;
+ }
+
+ private:
+ int64_t timestamp_ms_;
+ uint32_t source_id_;
+ RtpSourceType source_type_;
+ absl::optional<uint8_t> audio_level_;
+};
+
+class RtpReceiverObserverInterface {
+ public:
+ // Note: Currently if there are multiple RtpReceivers of the same media type,
+ // they will all call OnFirstPacketReceived at once.
+ //
+ // In the future, it's likely that an RtpReceiver will only call
+ // OnFirstPacketReceived when a packet is received specifically for its
+ // SSRC/mid.
+ virtual void OnFirstPacketReceived(cricket::MediaType media_type) = 0;
+
+ protected:
+ virtual ~RtpReceiverObserverInterface() {}
+};
+
+class RtpReceiverInterface : public rtc::RefCountInterface {
+ public:
+ virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0;
+
+ // The dtlsTransport attribute exposes the DTLS transport on which the
+ // media is received. It may be null.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-transport
+ // TODO(https://bugs.webrtc.org/907849) remove default implementation
+ virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const;
+
+ // The list of streams that |track| is associated with. This is the same as
+ // the [[AssociatedRemoteMediaStreams]] internal slot in the spec.
+ // https://w3c.github.io/webrtc-pc/#dfn-associatedremotemediastreams
+ // TODO(hbos): Make pure virtual as soon as Chromium's mock implements this.
+ // TODO(https://crbug.com/webrtc/9480): Remove streams() in favor of
+ // stream_ids() as soon as downstream projects are no longer dependent on
+ // stream objects.
+ virtual std::vector<std::string> stream_ids() const;
+ virtual std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams() const;
+
+ // Audio or video receiver?
+ virtual cricket::MediaType media_type() const = 0;
+
+ // Not to be confused with "mid", this is a field we can temporarily use
+ // to uniquely identify a receiver until we implement Unified Plan SDP.
+ virtual std::string id() const = 0;
+
+ // The WebRTC specification only defines RTCRtpParameters in terms of senders,
+ // but this API also applies them to receivers, similar to ORTC:
+ // http://ortc.org/wp-content/uploads/2016/03/ortc.html#rtcrtpparameters*.
+ virtual RtpParameters GetParameters() const = 0;
+ // Currently, doesn't support changing any parameters, but may in the future.
+ virtual bool SetParameters(const RtpParameters& parameters) = 0;
+
+ // Does not take ownership of observer.
+ // Must call SetObserver(nullptr) before the observer is destroyed.
+ virtual void SetObserver(RtpReceiverObserverInterface* observer) = 0;
+
+ // TODO(zhihuang): Remove the default implementation once the subclasses
+ // implement this. Currently, the only relevant subclass is the
+ // content::FakeRtpReceiver in Chromium.
+ virtual std::vector<RtpSource> GetSources() const;
+
+ // Sets a user defined frame decryptor that will decrypt the entire frame
+ // before it is sent across the network. This will decrypt the entire frame
+ // using the user provided decryption mechanism regardless of whether SRTP is
+ // enabled or not.
+ virtual void SetFrameDecryptor(
+ rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor);
+
+ // Returns a pointer to the frame decryptor set previously by the
+ // user. This can be used to update the state of the object.
+ virtual rtc::scoped_refptr<FrameDecryptorInterface> GetFrameDecryptor() const;
+
+ protected:
+ ~RtpReceiverInterface() override = default;
+};
+
+// Define proxy for RtpReceiverInterface.
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_SIGNALING_PROXY_MAP(RtpReceiver)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtlsTransportInterface>, dtls_transport)
+PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>,
+ streams)
+PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(RtpParameters, GetParameters)
+PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
+PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*)
+PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources)
+PROXY_METHOD1(void,
+ SetFrameDecryptor,
+ rtc::scoped_refptr<FrameDecryptorInterface>)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameDecryptorInterface>,
+ GetFrameDecryptor)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_RTP_RECEIVER_INTERFACE_H_
diff --git a/api/rtp_sender_interface.cc b/api/rtp_sender_interface.cc
new file mode 100644
index 0000000..d23fd18
--- /dev/null
+++ b/api/rtp_sender_interface.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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 "api/rtp_sender_interface.h"
+
+namespace webrtc {
+
+void RtpSenderInterface::SetFrameEncryptor(
+ rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {}
+
+rtc::scoped_refptr<FrameEncryptorInterface>
+RtpSenderInterface::GetFrameEncryptor() const {
+ return nullptr;
+}
+
+std::vector<RtpEncodingParameters> RtpSenderInterface::init_send_encodings()
+ const {
+ return {};
+}
+
+rtc::scoped_refptr<DtlsTransportInterface> RtpSenderInterface::dtls_transport()
+ const {
+ return nullptr;
+}
+
+} // namespace webrtc
diff --git a/api/rtp_sender_interface.h b/api/rtp_sender_interface.h
new file mode 100644
index 0000000..e0a29a3
--- /dev/null
+++ b/api/rtp_sender_interface.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2015 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.
+ */
+
+// This file contains interfaces for RtpSenders
+// http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
+
+#ifndef API_RTP_SENDER_INTERFACE_H_
+#define API_RTP_SENDER_INTERFACE_H_
+
+#include <string>
+#include <vector>
+
+#include "api/crypto/frame_encryptor_interface.h"
+#include "api/dtls_transport_interface.h"
+#include "api/dtmf_sender_interface.h"
+#include "api/media_stream_interface.h"
+#include "api/media_types.h"
+#include "api/proxy.h"
+#include "api/rtc_error.h"
+#include "api/rtp_parameters.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+class RtpSenderInterface : public rtc::RefCountInterface {
+ public:
+ // Returns true if successful in setting the track.
+ // Fails if an audio track is set on a video RtpSender, or vice-versa.
+ virtual bool SetTrack(MediaStreamTrackInterface* track) = 0;
+ virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0;
+
+ // The dtlsTransport attribute exposes the DTLS transport on which the
+ // media is sent. It may be null.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-transport
+ // TODO(https://bugs.webrtc.org/907849) remove default implementation
+ virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const;
+
+ // Returns primary SSRC used by this sender for sending media.
+ // Returns 0 if not yet determined.
+ // TODO(deadbeef): Change to absl::optional.
+ // TODO(deadbeef): Remove? With GetParameters this should be redundant.
+ virtual uint32_t ssrc() const = 0;
+
+ // Audio or video sender?
+ virtual cricket::MediaType media_type() const = 0;
+
+ // Not to be confused with "mid", this is a field we can temporarily use
+ // to uniquely identify a receiver until we implement Unified Plan SDP.
+ virtual std::string id() const = 0;
+
+ // Returns a list of media stream ids associated with this sender's track.
+ // These are signalled in the SDP so that the remote side can associate
+ // tracks.
+ virtual std::vector<std::string> stream_ids() const = 0;
+
+ // Returns the list of encoding parameters that will be applied when the SDP
+ // local description is set. These initial encoding parameters can be set by
+ // PeerConnection::AddTransceiver, and later updated with Get/SetParameters.
+ // TODO(orphis): Make it pure virtual once Chrome has updated
+ virtual std::vector<RtpEncodingParameters> init_send_encodings() const;
+
+ virtual RtpParameters GetParameters() const = 0;
+ // Note that only a subset of the parameters can currently be changed. See
+ // rtpparameters.h
+ // The encodings are in increasing quality order for simulcast.
+ virtual RTCError SetParameters(const RtpParameters& parameters) = 0;
+
+ // Returns null for a video sender.
+ virtual rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const = 0;
+
+ // Sets a user defined frame encryptor that will encrypt the entire frame
+ // before it is sent across the network. This will encrypt the entire frame
+ // using the user provided encryption mechanism regardless of whether SRTP is
+ // enabled or not.
+ virtual void SetFrameEncryptor(
+ rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor);
+
+ // Returns a pointer to the frame encryptor set previously by the
+ // user. This can be used to update the state of the object.
+ virtual rtc::scoped_refptr<FrameEncryptorInterface> GetFrameEncryptor() const;
+
+ protected:
+ ~RtpSenderInterface() override = default;
+};
+
+// Define proxy for RtpSenderInterface.
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_SIGNALING_PROXY_MAP(RtpSender)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtlsTransportInterface>, dtls_transport)
+PROXY_CONSTMETHOD0(uint32_t, ssrc)
+PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
+PROXY_CONSTMETHOD0(std::vector<RtpEncodingParameters>, init_send_encodings)
+PROXY_CONSTMETHOD0(RtpParameters, GetParameters)
+PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender)
+PROXY_METHOD1(void,
+ SetFrameEncryptor,
+ rtc::scoped_refptr<FrameEncryptorInterface>)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameEncryptorInterface>,
+ GetFrameEncryptor)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_RTP_SENDER_INTERFACE_H_
diff --git a/api/rtp_transceiver_interface.cc b/api/rtp_transceiver_interface.cc
new file mode 100644
index 0000000..0504331
--- /dev/null
+++ b/api/rtp_transceiver_interface.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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 "api/rtp_transceiver_interface.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RtpTransceiverInit::RtpTransceiverInit() = default;
+
+RtpTransceiverInit::RtpTransceiverInit(const RtpTransceiverInit& rhs) = default;
+
+RtpTransceiverInit::~RtpTransceiverInit() = default;
+
+absl::optional<RtpTransceiverDirection>
+RtpTransceiverInterface::fired_direction() const {
+ return absl::nullopt;
+}
+
+void RtpTransceiverInterface::SetCodecPreferences(
+ rtc::ArrayView<RtpCodecCapability>) {
+ RTC_NOTREACHED() << "Not implemented";
+}
+
+} // namespace webrtc
diff --git a/api/rtp_transceiver_interface.h b/api/rtp_transceiver_interface.h
new file mode 100644
index 0000000..aec0d15
--- /dev/null
+++ b/api/rtp_transceiver_interface.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef API_RTP_TRANSCEIVER_INTERFACE_H_
+#define API_RTP_TRANSCEIVER_INTERFACE_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/media_types.h"
+#include "api/rtp_parameters.h"
+#include "api/rtp_receiver_interface.h"
+#include "api/rtp_sender_interface.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection
+enum class RtpTransceiverDirection {
+ kSendRecv,
+ kSendOnly,
+ kRecvOnly,
+ kInactive
+};
+
+// Structure for initializing an RtpTransceiver in a call to
+// PeerConnectionInterface::AddTransceiver.
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
+struct RtpTransceiverInit final {
+ RtpTransceiverInit();
+ RtpTransceiverInit(const RtpTransceiverInit&);
+ ~RtpTransceiverInit();
+ // Direction of the RtpTransceiver. See RtpTransceiverInterface::direction().
+ RtpTransceiverDirection direction = RtpTransceiverDirection::kSendRecv;
+
+ // The added RtpTransceiver will be added to these streams.
+ std::vector<std::string> stream_ids;
+
+ // TODO(bugs.webrtc.org/7600): Not implemented.
+ std::vector<RtpEncodingParameters> send_encodings;
+};
+
+// The RtpTransceiverInterface maps to the RTCRtpTransceiver defined by the
+// WebRTC specification. A transceiver represents a combination of an RtpSender
+// and an RtpReceiver than share a common mid. As defined in JSEP, an
+// RtpTransceiver is said to be associated with a media description if its mid
+// property is non-null; otherwise, it is said to be disassociated.
+// JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24
+//
+// Note that RtpTransceivers are only supported when using PeerConnection with
+// Unified Plan SDP.
+//
+// This class is thread-safe.
+//
+// WebRTC specification for RTCRtpTransceiver, the JavaScript analog:
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver
+class RtpTransceiverInterface : public rtc::RefCountInterface {
+ public:
+ // Media type of the transceiver. Any sender(s)/receiver(s) will have this
+ // type as well.
+ virtual cricket::MediaType media_type() const = 0;
+
+ // The mid attribute is the mid negotiated and present in the local and
+ // remote descriptions. Before negotiation is complete, the mid value may be
+ // null. After rollbacks, the value may change from a non-null value to null.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
+ virtual absl::optional<std::string> mid() const = 0;
+
+ // The sender attribute exposes the RtpSender corresponding to the RTP media
+ // that may be sent with the transceiver's mid. The sender is always present,
+ // regardless of the direction of media.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender
+ virtual rtc::scoped_refptr<RtpSenderInterface> sender() const = 0;
+
+ // The receiver attribute exposes the RtpReceiver corresponding to the RTP
+ // media that may be received with the transceiver's mid. The receiver is
+ // always present, regardless of the direction of media.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver
+ virtual rtc::scoped_refptr<RtpReceiverInterface> receiver() const = 0;
+
+ // The stopped attribute indicates that the sender of this transceiver will no
+ // longer send, and that the receiver will no longer receive. It is true if
+ // either stop has been called or if setting the local or remote description
+ // has caused the RtpTransceiver to be stopped.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped
+ virtual bool stopped() const = 0;
+
+ // The direction attribute indicates the preferred direction of this
+ // transceiver, which will be used in calls to CreateOffer and CreateAnswer.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
+ virtual RtpTransceiverDirection direction() const = 0;
+
+ // Sets the preferred direction of this transceiver. An update of
+ // directionality does not take effect immediately. Instead, future calls to
+ // CreateOffer and CreateAnswer mark the corresponding media descriptions as
+ // sendrecv, sendonly, recvonly, or inactive.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
+ virtual void SetDirection(RtpTransceiverDirection new_direction) = 0;
+
+ // The current_direction attribute indicates the current direction negotiated
+ // for this transceiver. If this transceiver has never been represented in an
+ // offer/answer exchange, or if the transceiver is stopped, the value is null.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
+ virtual absl::optional<RtpTransceiverDirection> current_direction() const = 0;
+
+ // An internal slot designating for which direction the relevant
+ // PeerConnection events have been fired. This is to ensure that events like
+ // OnAddTrack only get fired once even if the same session description is
+ // applied again.
+ // Exposed in the public interface for use by Chromium.
+ virtual absl::optional<RtpTransceiverDirection> fired_direction() const;
+
+ // The Stop method irreversibly stops the RtpTransceiver. The sender of this
+ // transceiver will no longer send, the receiver will no longer receive.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop
+ virtual void Stop() = 0;
+
+ // The SetCodecPreferences method overrides the default codec preferences used
+ // by WebRTC for this transceiver.
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences
+ // TODO(steveanton): Not implemented.
+ virtual void SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codecs);
+
+ protected:
+ ~RtpTransceiverInterface() override = default;
+};
+
+} // namespace webrtc
+
+#endif // API_RTP_TRANSCEIVER_INTERFACE_H_
diff --git a/api/scoped_refptr.h b/api/scoped_refptr.h
index 0993e03..67d179f 100644
--- a/api/scoped_refptr.h
+++ b/api/scoped_refptr.h
@@ -71,6 +71,8 @@
template <class T>
class scoped_refptr {
public:
+ typedef T element_type;
+
scoped_refptr() : ptr_(nullptr) {}
scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit)
diff --git a/api/sctp_transport_interface.cc b/api/sctp_transport_interface.cc
new file mode 100644
index 0000000..c6c1fbe
--- /dev/null
+++ b/api/sctp_transport_interface.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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 <utility>
+
+#include "api/sctp_transport_interface.h"
+
+namespace webrtc {
+
+SctpTransportInformation::SctpTransportInformation(SctpTransportState state)
+ : state_(state) {}
+
+SctpTransportInformation::SctpTransportInformation(
+ SctpTransportState state,
+ rtc::scoped_refptr<DtlsTransportInterface> dtls_transport,
+ absl::optional<double> max_message_size,
+ absl::optional<int> max_channels)
+ : state_(state),
+ dtls_transport_(std::move(dtls_transport)),
+ max_message_size_(max_message_size),
+ max_channels_(max_channels) {}
+
+SctpTransportInformation::~SctpTransportInformation() {}
+
+} // namespace webrtc
diff --git a/api/sctp_transport_interface.h b/api/sctp_transport_interface.h
new file mode 100644
index 0000000..3698fc2
--- /dev/null
+++ b/api/sctp_transport_interface.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef API_SCTP_TRANSPORT_INTERFACE_H_
+#define API_SCTP_TRANSPORT_INTERFACE_H_
+
+#include "absl/types/optional.h"
+#include "api/dtls_transport_interface.h"
+#include "api/rtc_error.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// States of a SCTP transport, corresponding to the JS API specification.
+// http://w3c.github.io/webrtc-pc/#dom-rtcsctptransportstate
+enum class SctpTransportState {
+ kNew, // Has not started negotiating yet. Non-standard state.
+ kConnecting, // In the process of negotiating an association.
+ kConnected, // Completed negotiation of an association.
+ kClosed, // Closed by local or remote party.
+ kNumValues
+};
+
+// This object gives snapshot information about the changeable state of a
+// SctpTransport.
+// It reflects the readonly attributes of the object in the specification.
+// http://w3c.github.io/webrtc-pc/#rtcsctptransport-interface
+class SctpTransportInformation {
+ public:
+ explicit SctpTransportInformation(SctpTransportState state);
+ SctpTransportInformation(
+ SctpTransportState state,
+ rtc::scoped_refptr<DtlsTransportInterface> dtls_transport,
+ absl::optional<double> max_message_size,
+ absl::optional<int> max_channels);
+ ~SctpTransportInformation();
+ // The DTLS transport that supports this SCTP transport.
+ rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const {
+ return dtls_transport_;
+ }
+ SctpTransportState state() const { return state_; }
+ absl::optional<double> MaxMessageSize() const { return max_message_size_; }
+ absl::optional<int> MaxChannels() const { return max_channels_; }
+
+ private:
+ SctpTransportState state_;
+ rtc::scoped_refptr<DtlsTransportInterface> dtls_transport_;
+ absl::optional<double> max_message_size_;
+ absl::optional<int> max_channels_;
+};
+
+class SctpTransportObserverInterface {
+ public:
+ // This callback carries information about the state of the transport.
+ // The argument is a pass-by-value snapshot of the state.
+ // The callback will be called on the network thread.
+ virtual void OnStateChange(SctpTransportInformation info) = 0;
+
+ protected:
+ virtual ~SctpTransportObserverInterface() = default;
+};
+
+// A SCTP transport, as represented to the outside world.
+// This object is created on the network thread, and can only be
+// accessed on that thread, except for functions explicitly marked otherwise.
+// References can be held by other threads, and destruction can therefore
+// be initiated by other threads.
+class SctpTransportInterface : public rtc::RefCountInterface {
+ public:
+ // This function can be called from other threads.
+ virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const = 0;
+ // Returns information on the state of the SctpTransport.
+ // This function can be called from other threads.
+ virtual SctpTransportInformation Information() const = 0;
+ // Observer management.
+ virtual void RegisterObserver(SctpTransportObserverInterface* observer) = 0;
+ virtual void UnregisterObserver() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_SCTP_TRANSPORT_INTERFACE_H_
diff --git a/api/set_remote_description_observer_interface.h b/api/set_remote_description_observer_interface.h
new file mode 100644
index 0000000..1782555
--- /dev/null
+++ b/api/set_remote_description_observer_interface.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_
+#define API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_
+
+#include "api/rtc_error.h"
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// An observer for PeerConnectionInterface::SetRemoteDescription(). The
+// callback is invoked such that the state of the peer connection can be
+// examined to accurately reflect the effects of the SetRemoteDescription
+// operation.
+class SetRemoteDescriptionObserverInterface : public rtc::RefCountInterface {
+ public:
+ // On success, |error.ok()| is true.
+ virtual void OnSetRemoteDescriptionComplete(RTCError error) = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_
diff --git a/api/stats_types.cc b/api/stats_types.cc
new file mode 100644
index 0000000..71b1f86
--- /dev/null
+++ b/api/stats_types.cc
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2014 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 "api/stats_types.h"
+
+#include <string.h>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/ref_counted_object.h"
+
+// TODO(tommi): Could we have a static map of value name -> expected type
+// and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)?
+// Alternatively, we could define the names+type in a separate document and
+// generate strongly typed inline C++ code that forces the correct type to be
+// used for a given name at compile time.
+
+using rtc::RefCountedObject;
+
+namespace webrtc {
+namespace {
+
+// The id of StatsReport of type kStatsReportTypeBwe.
+const char kStatsReportVideoBweId[] = "bweforvideo";
+
+// NOTE: These names need to be consistent with an external
+// specification (W3C Stats Identifiers).
+const char* InternalTypeToString(StatsReport::StatsType type) {
+ switch (type) {
+ case StatsReport::kStatsReportTypeSession:
+ return "googLibjingleSession";
+ case StatsReport::kStatsReportTypeBwe:
+ return "VideoBwe";
+ case StatsReport::kStatsReportTypeRemoteSsrc:
+ return "remoteSsrc";
+ case StatsReport::kStatsReportTypeSsrc:
+ return "ssrc";
+ case StatsReport::kStatsReportTypeTrack:
+ return "googTrack";
+ case StatsReport::kStatsReportTypeIceLocalCandidate:
+ return "localcandidate";
+ case StatsReport::kStatsReportTypeIceRemoteCandidate:
+ return "remotecandidate";
+ case StatsReport::kStatsReportTypeTransport:
+ return "transport";
+ case StatsReport::kStatsReportTypeComponent:
+ return "googComponent";
+ case StatsReport::kStatsReportTypeCandidatePair:
+ return "googCandidatePair";
+ case StatsReport::kStatsReportTypeCertificate:
+ return "googCertificate";
+ case StatsReport::kStatsReportTypeDataChannel:
+ return "datachannel";
+ }
+ RTC_NOTREACHED();
+ return nullptr;
+}
+
+class BandwidthEstimationId : public StatsReport::IdBase {
+ public:
+ BandwidthEstimationId()
+ : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {}
+ std::string ToString() const override { return kStatsReportVideoBweId; }
+};
+
+class TypedId : public StatsReport::IdBase {
+ public:
+ TypedId(StatsReport::StatsType type, const std::string& id)
+ : StatsReport::IdBase(type), id_(id) {}
+
+ bool Equals(const IdBase& other) const override {
+ return IdBase::Equals(other) &&
+ static_cast<const TypedId&>(other).id_ == id_;
+ }
+
+ std::string ToString() const override {
+ return std::string(InternalTypeToString(type_)) + kSeparator + id_;
+ }
+
+ protected:
+ const std::string id_;
+};
+
+class TypedIntId : public StatsReport::IdBase {
+ public:
+ TypedIntId(StatsReport::StatsType type, int id)
+ : StatsReport::IdBase(type), id_(id) {}
+
+ bool Equals(const IdBase& other) const override {
+ return IdBase::Equals(other) &&
+ static_cast<const TypedIntId&>(other).id_ == id_;
+ }
+
+ std::string ToString() const override {
+ return std::string(InternalTypeToString(type_)) + kSeparator +
+ rtc::ToString(id_);
+ }
+
+ protected:
+ const int id_;
+};
+
+class IdWithDirection : public TypedId {
+ public:
+ IdWithDirection(StatsReport::StatsType type,
+ const std::string& id,
+ StatsReport::Direction direction)
+ : TypedId(type, id), direction_(direction) {}
+
+ bool Equals(const IdBase& other) const override {
+ return TypedId::Equals(other) &&
+ static_cast<const IdWithDirection&>(other).direction_ == direction_;
+ }
+
+ std::string ToString() const override {
+ std::string ret(TypedId::ToString());
+ ret += kSeparator;
+ ret += direction_ == StatsReport::kSend ? "send" : "recv";
+ return ret;
+ }
+
+ private:
+ const StatsReport::Direction direction_;
+};
+
+class CandidateId : public TypedId {
+ public:
+ CandidateId(bool local, const std::string& id)
+ : TypedId(local ? StatsReport::kStatsReportTypeIceLocalCandidate
+ : StatsReport::kStatsReportTypeIceRemoteCandidate,
+ id) {}
+
+ std::string ToString() const override { return "Cand-" + id_; }
+};
+
+class ComponentId : public StatsReport::IdBase {
+ public:
+ ComponentId(const std::string& content_name, int component)
+ : ComponentId(StatsReport::kStatsReportTypeComponent,
+ content_name,
+ component) {}
+
+ bool Equals(const IdBase& other) const override {
+ return IdBase::Equals(other) &&
+ static_cast<const ComponentId&>(other).component_ == component_ &&
+ static_cast<const ComponentId&>(other).content_name_ ==
+ content_name_;
+ }
+
+ std::string ToString() const override { return ToString("Channel-"); }
+
+ protected:
+ ComponentId(StatsReport::StatsType type,
+ const std::string& content_name,
+ int component)
+ : IdBase(type), content_name_(content_name), component_(component) {}
+
+ std::string ToString(const char* prefix) const {
+ std::string ret(prefix);
+ ret += content_name_;
+ ret += '-';
+ ret += rtc::ToString(component_);
+ return ret;
+ }
+
+ private:
+ const std::string content_name_;
+ const int component_;
+};
+
+class CandidatePairId : public ComponentId {
+ public:
+ CandidatePairId(const std::string& content_name, int component, int index)
+ : ComponentId(StatsReport::kStatsReportTypeCandidatePair,
+ content_name,
+ component),
+ index_(index) {}
+
+ bool Equals(const IdBase& other) const override {
+ return ComponentId::Equals(other) &&
+ static_cast<const CandidatePairId&>(other).index_ == index_;
+ }
+
+ std::string ToString() const override {
+ std::string ret(ComponentId::ToString("Conn-"));
+ ret += '-';
+ ret += rtc::ToString(index_);
+ return ret;
+ }
+
+ private:
+ const int index_;
+};
+
+} // namespace
+
+StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
+StatsReport::IdBase::~IdBase() {}
+
+StatsReport::StatsType StatsReport::IdBase::type() const {
+ return type_;
+}
+
+bool StatsReport::IdBase::Equals(const IdBase& other) const {
+ return other.type_ == type_;
+}
+
+StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type)
+ : name(name), type_(int_type) {
+ RTC_DCHECK(type_ == kInt || type_ == kInt64);
+ type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value;
+}
+
+StatsReport::Value::Value(StatsValueName name, float f)
+ : name(name), type_(kFloat) {
+ value_.float_ = f;
+}
+
+StatsReport::Value::Value(StatsValueName name, const std::string& value)
+ : name(name), type_(kString) {
+ value_.string_ = new std::string(value);
+}
+
+StatsReport::Value::Value(StatsValueName name, const char* value)
+ : name(name), type_(kStaticString) {
+ value_.static_string_ = value;
+}
+
+StatsReport::Value::Value(StatsValueName name, bool b)
+ : name(name), type_(kBool) {
+ value_.bool_ = b;
+}
+
+StatsReport::Value::Value(StatsValueName name, const Id& value)
+ : name(name), type_(kId) {
+ value_.id_ = new Id(value);
+}
+
+StatsReport::Value::~Value() {
+ switch (type_) {
+ case kInt:
+ case kInt64:
+ case kFloat:
+ case kBool:
+ case kStaticString:
+ break;
+ case kString:
+ delete value_.string_;
+ break;
+ case kId:
+ delete value_.id_;
+ break;
+ }
+}
+
+bool StatsReport::Value::Equals(const Value& other) const {
+ if (name != other.name)
+ return false;
+
+ // There's a 1:1 relation between a name and a type, so we don't have to
+ // check that.
+ RTC_DCHECK_EQ(type_, other.type_);
+
+ switch (type_) {
+ case kInt:
+ return value_.int_ == other.value_.int_;
+ case kInt64:
+ return value_.int64_ == other.value_.int64_;
+ case kFloat:
+ return value_.float_ == other.value_.float_;
+ case kStaticString: {
+#if RTC_DCHECK_IS_ON
+ if (value_.static_string_ != other.value_.static_string_) {
+ RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) !=
+ 0)
+ << "Duplicate global?";
+ }
+#endif
+ return value_.static_string_ == other.value_.static_string_;
+ }
+ case kString:
+ return *value_.string_ == *other.value_.string_;
+ case kBool:
+ return value_.bool_ == other.value_.bool_;
+ case kId:
+ return (*value_.id_)->Equals(*other.value_.id_);
+ }
+ RTC_NOTREACHED();
+ return false;
+}
+
+bool StatsReport::Value::operator==(const std::string& value) const {
+ return (type_ == kString && value_.string_->compare(value) == 0) ||
+ (type_ == kStaticString && value.compare(value_.static_string_) == 0);
+}
+
+bool StatsReport::Value::operator==(const char* value) const {
+ if (type_ == kString)
+ return value_.string_->compare(value) == 0;
+ if (type_ != kStaticString)
+ return false;
+#if RTC_DCHECK_IS_ON
+ if (value_.static_string_ != value)
+ RTC_DCHECK(strcmp(value_.static_string_, value) != 0)
+ << "Duplicate global?";
+#endif
+ return value == value_.static_string_;
+}
+
+bool StatsReport::Value::operator==(int64_t value) const {
+ return type_ == kInt ? value_.int_ == static_cast<int>(value)
+ : (type_ == kInt64 ? value_.int64_ == value : false);
+}
+
+bool StatsReport::Value::operator==(bool value) const {
+ return type_ == kBool && value_.bool_ == value;
+}
+
+bool StatsReport::Value::operator==(float value) const {
+ return type_ == kFloat && value_.float_ == value;
+}
+
+bool StatsReport::Value::operator==(const Id& value) const {
+ return type_ == kId && (*value_.id_)->Equals(value);
+}
+
+int StatsReport::Value::int_val() const {
+ RTC_DCHECK(type_ == kInt);
+ return value_.int_;
+}
+
+int64_t StatsReport::Value::int64_val() const {
+ RTC_DCHECK(type_ == kInt64);
+ return value_.int64_;
+}
+
+float StatsReport::Value::float_val() const {
+ RTC_DCHECK(type_ == kFloat);
+ return value_.float_;
+}
+
+const char* StatsReport::Value::static_string_val() const {
+ RTC_DCHECK(type_ == kStaticString);
+ return value_.static_string_;
+}
+
+const std::string& StatsReport::Value::string_val() const {
+ RTC_DCHECK(type_ == kString);
+ return *value_.string_;
+}
+
+bool StatsReport::Value::bool_val() const {
+ RTC_DCHECK(type_ == kBool);
+ return value_.bool_;
+}
+
+const char* StatsReport::Value::display_name() const {
+ switch (name) {
+ case kStatsValueNameAecDivergentFilterFraction:
+ return "aecDivergentFilterFraction";
+ case kStatsValueNameAudioOutputLevel:
+ return "audioOutputLevel";
+ case kStatsValueNameAudioInputLevel:
+ return "audioInputLevel";
+ case kStatsValueNameBytesSent:
+ return "bytesSent";
+ case kStatsValueNameConcealedSamples:
+ return "concealedSamples";
+ case kStatsValueNameConcealmentEvents:
+ return "concealmentEvents";
+ case kStatsValueNamePacketsSent:
+ return "packetsSent";
+ case kStatsValueNameBytesReceived:
+ return "bytesReceived";
+ case kStatsValueNameLabel:
+ return "label";
+ case kStatsValueNamePacketsReceived:
+ return "packetsReceived";
+ case kStatsValueNamePacketsLost:
+ return "packetsLost";
+ case kStatsValueNameProtocol:
+ return "protocol";
+ case kStatsValueNameTotalSamplesReceived:
+ return "totalSamplesReceived";
+ case kStatsValueNameTransportId:
+ return "transportId";
+ case kStatsValueNameSelectedCandidatePairId:
+ return "selectedCandidatePairId";
+ case kStatsValueNameSsrc:
+ return "ssrc";
+ case kStatsValueNameState:
+ return "state";
+ case kStatsValueNameDataChannelId:
+ return "datachannelid";
+ case kStatsValueNameFramesDecoded:
+ return "framesDecoded";
+ case kStatsValueNameFramesEncoded:
+ return "framesEncoded";
+ case kStatsValueNameJitterBufferDelay:
+ return "jitterBufferDelay";
+ case kStatsValueNameCodecImplementationName:
+ return "codecImplementationName";
+ case kStatsValueNameMediaType:
+ return "mediaType";
+ case kStatsValueNameQpSum:
+ return "qpSum";
+ // 'goog' prefixed constants.
+ case kStatsValueNameAccelerateRate:
+ return "googAccelerateRate";
+ case kStatsValueNameActiveConnection:
+ return "googActiveConnection";
+ case kStatsValueNameActualEncBitrate:
+ return "googActualEncBitrate";
+ case kStatsValueNameAvailableReceiveBandwidth:
+ return "googAvailableReceiveBandwidth";
+ case kStatsValueNameAvailableSendBandwidth:
+ return "googAvailableSendBandwidth";
+ case kStatsValueNameAvgEncodeMs:
+ return "googAvgEncodeMs";
+ case kStatsValueNameBucketDelay:
+ return "googBucketDelay";
+ case kStatsValueNameBandwidthLimitedResolution:
+ return "googBandwidthLimitedResolution";
+ // STUN ping related attributes.
+ //
+ // TODO(zhihuang) Rename these stats to follow the standards.
+ // Connectivity checks.
+ case kStatsValueNameSentPingRequestsTotal:
+ return "requestsSent";
+ case kStatsValueNameSentPingRequestsBeforeFirstResponse:
+ return "consentRequestsSent";
+ case kStatsValueNameSentPingResponses:
+ return "responsesSent";
+ case kStatsValueNameRecvPingRequests:
+ return "requestsReceived";
+ case kStatsValueNameRecvPingResponses:
+ return "responsesReceived";
+ // STUN Keepalive pings.
+ case kStatsValueNameSentStunKeepaliveRequests:
+ return "stunKeepaliveRequestsSent";
+ case kStatsValueNameRecvStunKeepaliveResponses:
+ return "stunKeepaliveResponsesReceived";
+ case kStatsValueNameStunKeepaliveRttTotal:
+ return "stunKeepaliveRttTotal";
+ case kStatsValueNameStunKeepaliveRttSquaredTotal:
+ return "stunKeepaliveRttSquaredTotal";
+
+ // Candidate related attributes. Values are taken from
+ // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
+ case kStatsValueNameCandidateIPAddress:
+ return "ipAddress";
+ case kStatsValueNameCandidateNetworkType:
+ return "networkType";
+ case kStatsValueNameCandidatePortNumber:
+ return "portNumber";
+ case kStatsValueNameCandidatePriority:
+ return "priority";
+ case kStatsValueNameCandidateTransportType:
+ return "transport";
+ case kStatsValueNameCandidateType:
+ return "candidateType";
+
+ case kStatsValueNameChannelId:
+ return "googChannelId";
+ case kStatsValueNameCodecName:
+ return "googCodecName";
+ case kStatsValueNameComponent:
+ return "googComponent";
+ case kStatsValueNameContentName:
+ return "googContentName";
+ case kStatsValueNameContentType:
+ return "googContentType";
+ case kStatsValueNameCpuLimitedResolution:
+ return "googCpuLimitedResolution";
+ case kStatsValueNameDecodingCTSG:
+ return "googDecodingCTSG";
+ case kStatsValueNameDecodingCTN:
+ return "googDecodingCTN";
+ case kStatsValueNameDecodingMutedOutput:
+ return "googDecodingMuted";
+ case kStatsValueNameDecodingNormal:
+ return "googDecodingNormal";
+ case kStatsValueNameDecodingPLC:
+ return "googDecodingPLC";
+ case kStatsValueNameDecodingCNG:
+ return "googDecodingCNG";
+ case kStatsValueNameDecodingPLCCNG:
+ return "googDecodingPLCCNG";
+ case kStatsValueNameDer:
+ return "googDerBase64";
+ case kStatsValueNameDtlsCipher:
+ return "dtlsCipher";
+ case kStatsValueNameEchoDelayMedian:
+ return "googEchoCancellationEchoDelayMedian";
+ case kStatsValueNameEchoDelayStdDev:
+ return "googEchoCancellationEchoDelayStdDev";
+ case kStatsValueNameEchoReturnLoss:
+ return "googEchoCancellationReturnLoss";
+ case kStatsValueNameEchoReturnLossEnhancement:
+ return "googEchoCancellationReturnLossEnhancement";
+ case kStatsValueNameEncodeUsagePercent:
+ return "googEncodeUsagePercent";
+ case kStatsValueNameExpandRate:
+ return "googExpandRate";
+ case kStatsValueNameFingerprint:
+ return "googFingerprint";
+ case kStatsValueNameFingerprintAlgorithm:
+ return "googFingerprintAlgorithm";
+ case kStatsValueNameFirsReceived:
+ return "googFirsReceived";
+ case kStatsValueNameFirsSent:
+ return "googFirsSent";
+ case kStatsValueNameFirstFrameReceivedToDecodedMs:
+ return "googFirstFrameReceivedToDecodedMs";
+ case kStatsValueNameFrameHeightInput:
+ return "googFrameHeightInput";
+ case kStatsValueNameFrameHeightReceived:
+ return "googFrameHeightReceived";
+ case kStatsValueNameFrameHeightSent:
+ return "googFrameHeightSent";
+ case kStatsValueNameFrameRateReceived:
+ return "googFrameRateReceived";
+ case kStatsValueNameFrameRateDecoded:
+ return "googFrameRateDecoded";
+ case kStatsValueNameFrameRateOutput:
+ return "googFrameRateOutput";
+ case kStatsValueNameDecodeMs:
+ return "googDecodeMs";
+ case kStatsValueNameMaxDecodeMs:
+ return "googMaxDecodeMs";
+ case kStatsValueNameCurrentDelayMs:
+ return "googCurrentDelayMs";
+ case kStatsValueNameTargetDelayMs:
+ return "googTargetDelayMs";
+ case kStatsValueNameJitterBufferMs:
+ return "googJitterBufferMs";
+ case kStatsValueNameMinPlayoutDelayMs:
+ return "googMinPlayoutDelayMs";
+ case kStatsValueNameRenderDelayMs:
+ return "googRenderDelayMs";
+ case kStatsValueNameCaptureStartNtpTimeMs:
+ return "googCaptureStartNtpTimeMs";
+ case kStatsValueNameFrameRateInput:
+ return "googFrameRateInput";
+ case kStatsValueNameFrameRateSent:
+ return "googFrameRateSent";
+ case kStatsValueNameFrameWidthInput:
+ return "googFrameWidthInput";
+ case kStatsValueNameFrameWidthReceived:
+ return "googFrameWidthReceived";
+ case kStatsValueNameFrameWidthSent:
+ return "googFrameWidthSent";
+ case kStatsValueNameHasEnteredLowResolution:
+ return "googHasEnteredLowResolution";
+ case kStatsValueNameHugeFramesSent:
+ return "hugeFramesSent";
+ case kStatsValueNameInitiator:
+ return "googInitiator";
+ case kStatsValueNameInterframeDelayMaxMs:
+ return "googInterframeDelayMax";
+ case kStatsValueNameIssuerId:
+ return "googIssuerId";
+ case kStatsValueNameJitterReceived:
+ return "googJitterReceived";
+ case kStatsValueNameLocalAddress:
+ return "googLocalAddress";
+ case kStatsValueNameLocalCandidateId:
+ return "localCandidateId";
+ case kStatsValueNameLocalCandidateType:
+ return "googLocalCandidateType";
+ case kStatsValueNameLocalCertificateId:
+ return "localCertificateId";
+ case kStatsValueNameAdaptationChanges:
+ return "googAdaptationChanges";
+ case kStatsValueNameNacksReceived:
+ return "googNacksReceived";
+ case kStatsValueNameNacksSent:
+ return "googNacksSent";
+ case kStatsValueNamePreemptiveExpandRate:
+ return "googPreemptiveExpandRate";
+ case kStatsValueNamePlisReceived:
+ return "googPlisReceived";
+ case kStatsValueNamePlisSent:
+ return "googPlisSent";
+ case kStatsValueNamePreferredJitterBufferMs:
+ return "googPreferredJitterBufferMs";
+ case kStatsValueNameReceiving:
+ return "googReadable";
+ case kStatsValueNameRemoteAddress:
+ return "googRemoteAddress";
+ case kStatsValueNameRemoteCandidateId:
+ return "remoteCandidateId";
+ case kStatsValueNameRemoteCandidateType:
+ return "googRemoteCandidateType";
+ case kStatsValueNameRemoteCertificateId:
+ return "remoteCertificateId";
+ case kStatsValueNameResidualEchoLikelihood:
+ return "googResidualEchoLikelihood";
+ case kStatsValueNameResidualEchoLikelihoodRecentMax:
+ return "googResidualEchoLikelihoodRecentMax";
+ case kStatsValueNameAnaBitrateActionCounter:
+ return "googAnaBitrateActionCounter";
+ case kStatsValueNameAnaChannelActionCounter:
+ return "googAnaChannelActionCounter";
+ case kStatsValueNameAnaDtxActionCounter:
+ return "googAnaDtxActionCounter";
+ case kStatsValueNameAnaFecActionCounter:
+ return "googAnaFecActionCounter";
+ case kStatsValueNameAnaFrameLengthIncreaseCounter:
+ return "googAnaFrameLengthIncreaseCounter";
+ case kStatsValueNameAnaFrameLengthDecreaseCounter:
+ return "googAnaFrameLengthDecreaseCounter";
+ case kStatsValueNameAnaUplinkPacketLossFraction:
+ return "googAnaUplinkPacketLossFraction";
+ case kStatsValueNameRetransmitBitrate:
+ return "googRetransmitBitrate";
+ case kStatsValueNameRtt:
+ return "googRtt";
+ case kStatsValueNameSecondaryDecodedRate:
+ return "googSecondaryDecodedRate";
+ case kStatsValueNameSecondaryDiscardedRate:
+ return "googSecondaryDiscardedRate";
+ case kStatsValueNameSendPacketsDiscarded:
+ return "packetsDiscardedOnSend";
+ case kStatsValueNameSpeechExpandRate:
+ return "googSpeechExpandRate";
+ case kStatsValueNameSrtpCipher:
+ return "srtpCipher";
+ case kStatsValueNameTargetEncBitrate:
+ return "googTargetEncBitrate";
+ case kStatsValueNameTotalAudioEnergy:
+ return "totalAudioEnergy";
+ case kStatsValueNameTotalSamplesDuration:
+ return "totalSamplesDuration";
+ case kStatsValueNameTransmitBitrate:
+ return "googTransmitBitrate";
+ case kStatsValueNameTransportType:
+ return "googTransportType";
+ case kStatsValueNameTrackId:
+ return "googTrackId";
+ case kStatsValueNameTimingFrameInfo:
+ return "googTimingFrameInfo";
+ case kStatsValueNameTypingNoiseState:
+ return "googTypingNoiseState";
+ case kStatsValueNameWritable:
+ return "googWritable";
+ }
+
+ return nullptr;
+}
+
+std::string StatsReport::Value::ToString() const {
+ switch (type_) {
+ case kInt:
+ return rtc::ToString(value_.int_);
+ case kInt64:
+ return rtc::ToString(value_.int64_);
+ case kFloat:
+ return rtc::ToString(value_.float_);
+ case kStaticString:
+ return std::string(value_.static_string_);
+ case kString:
+ return *value_.string_;
+ case kBool:
+ return value_.bool_ ? "true" : "false";
+ case kId:
+ return (*value_.id_)->ToString();
+ }
+ RTC_NOTREACHED();
+ return std::string();
+}
+
+StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) {
+ RTC_DCHECK(id_.get());
+}
+
+StatsReport::~StatsReport() = default;
+
+// static
+StatsReport::Id StatsReport::NewBandwidthEstimationId() {
+ return Id(new RefCountedObject<BandwidthEstimationId>());
+}
+
+// static
+StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) {
+ return Id(new RefCountedObject<TypedId>(type, id));
+}
+
+// static
+StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) {
+ return Id(new RefCountedObject<TypedIntId>(type, id));
+}
+
+// static
+StatsReport::Id StatsReport::NewIdWithDirection(
+ StatsType type,
+ const std::string& id,
+ StatsReport::Direction direction) {
+ return Id(new RefCountedObject<IdWithDirection>(type, id, direction));
+}
+
+// static
+StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) {
+ return Id(new RefCountedObject<CandidateId>(local, id));
+}
+
+// static
+StatsReport::Id StatsReport::NewComponentId(const std::string& content_name,
+ int component) {
+ return Id(new RefCountedObject<ComponentId>(content_name, component));
+}
+
+// static
+StatsReport::Id StatsReport::NewCandidatePairId(const std::string& content_name,
+ int component,
+ int index) {
+ return Id(
+ new RefCountedObject<CandidatePairId>(content_name, component, index));
+}
+
+const char* StatsReport::TypeToString() const {
+ return InternalTypeToString(id_->type());
+}
+
+void StatsReport::AddString(StatsReport::StatsValueName name,
+ const std::string& value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value));
+}
+
+void StatsReport::AddString(StatsReport::StatsValueName name,
+ const char* value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value));
+}
+
+void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value, Value::kInt64));
+}
+
+void StatsReport::AddInt(StatsReport::StatsValueName name, int value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == static_cast<int64_t>(value)))
+ values_[name] = ValuePtr(new Value(name, value, Value::kInt));
+}
+
+void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value));
+}
+
+void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value));
+}
+
+void StatsReport::AddId(StatsReport::StatsValueName name, const Id& value) {
+ const Value* found = FindValue(name);
+ if (!found || !(*found == value))
+ values_[name] = ValuePtr(new Value(name, value));
+}
+
+const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const {
+ Values::const_iterator it = values_.find(name);
+ return it == values_.end() ? nullptr : it->second.get();
+}
+
+StatsCollection::StatsCollection() {}
+
+StatsCollection::~StatsCollection() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ for (auto* r : list_)
+ delete r;
+}
+
+StatsCollection::const_iterator StatsCollection::begin() const {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return list_.begin();
+}
+
+StatsCollection::const_iterator StatsCollection::end() const {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return list_.end();
+}
+
+size_t StatsCollection::size() const {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return list_.size();
+}
+
+StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(Find(id) == nullptr);
+ StatsReport* report = new StatsReport(id);
+ list_.push_back(report);
+ return report;
+}
+
+StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ StatsReport* ret = Find(id);
+ return ret ? ret : InsertNew(id);
+}
+
+StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(id.get());
+ Container::iterator it = std::find_if(
+ list_.begin(), list_.end(),
+ [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
+ if (it != end()) {
+ StatsReport* report = new StatsReport((*it)->id());
+ delete *it;
+ *it = report;
+ return report;
+ }
+ return InsertNew(id);
+}
+
+// Looks for a report with the given |id|. If one is not found, null
+// will be returned.
+StatsReport* StatsCollection::Find(const StatsReport::Id& id) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ Container::iterator it = std::find_if(
+ list_.begin(), list_.end(),
+ [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
+ return it == list_.end() ? nullptr : *it;
+}
+
+} // namespace webrtc
diff --git a/api/stats_types.h b/api/stats_types.h
new file mode 100644
index 0000000..0e97eaf
--- /dev/null
+++ b/api/stats_types.h
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2012 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.
+ */
+
+// This file contains structures used for retrieving statistics from an ongoing
+// libjingle session.
+
+#ifndef API_STATS_TYPES_H_
+#define API_STATS_TYPES_H_
+
+#include <algorithm>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "api/scoped_refptr.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/thread_checker.h"
+
+namespace webrtc {
+
+class StatsReport {
+ public:
+ // Indicates whether a track is for sending or receiving.
+ // Used in reports for audio/video tracks.
+ enum Direction {
+ kSend = 0,
+ kReceive,
+ };
+
+ enum StatsType {
+ // StatsReport types.
+ // A StatsReport of |type| = "googSession" contains overall information
+ // about the thing libjingle calls a session (which may contain one
+ // or more RTP sessions.
+ kStatsReportTypeSession,
+
+ // A StatsReport of |type| = "googTransport" contains information
+ // about a libjingle "transport".
+ kStatsReportTypeTransport,
+
+ // A StatsReport of |type| = "googComponent" contains information
+ // about a libjingle "channel" (typically, RTP or RTCP for a transport).
+ // This is intended to be the same thing as an ICE "Component".
+ kStatsReportTypeComponent,
+
+ // A StatsReport of |type| = "googCandidatePair" contains information
+ // about a libjingle "connection" - a single source/destination port pair.
+ // This is intended to be the same thing as an ICE "candidate pair".
+ kStatsReportTypeCandidatePair,
+
+ // A StatsReport of |type| = "VideoBWE" is statistics for video Bandwidth
+ // Estimation, which is global per-session. The |id| field is "bweforvideo"
+ // (will probably change in the future).
+ kStatsReportTypeBwe,
+
+ // A StatsReport of |type| = "ssrc" is statistics for a specific rtp stream.
+ // The |id| field is the SSRC in decimal form of the rtp stream.
+ kStatsReportTypeSsrc,
+
+ // A StatsReport of |type| = "remoteSsrc" is statistics for a specific
+ // rtp stream, generated by the remote end of the connection.
+ kStatsReportTypeRemoteSsrc,
+
+ // A StatsReport of |type| = "googTrack" is statistics for a specific media
+ // track. The |id| field is the track id.
+ kStatsReportTypeTrack,
+
+ // A StatsReport of |type| = "localcandidate" or "remotecandidate" is
+ // attributes on a specific ICE Candidate. It links to its connection pair
+ // by candidate id. The string value is taken from
+ // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
+ kStatsReportTypeIceLocalCandidate,
+ kStatsReportTypeIceRemoteCandidate,
+
+ // A StatsReport of |type| = "googCertificate" contains an SSL certificate
+ // transmitted by one of the endpoints of this connection. The |id| is
+ // controlled by the fingerprint, and is used to identify the certificate in
+ // the Channel stats (as "googLocalCertificateId" or
+ // "googRemoteCertificateId") and in any child certificates (as
+ // "googIssuerId").
+ kStatsReportTypeCertificate,
+
+ // A StatsReport of |type| = "datachannel" with statistics for a
+ // particular DataChannel.
+ kStatsReportTypeDataChannel,
+ };
+
+ enum StatsValueName {
+ kStatsValueNameActiveConnection,
+ kStatsValueNameAecDivergentFilterFraction,
+ kStatsValueNameAudioInputLevel,
+ kStatsValueNameAudioOutputLevel,
+ kStatsValueNameBytesReceived,
+ kStatsValueNameBytesSent,
+ kStatsValueNameCodecImplementationName,
+ kStatsValueNameConcealedSamples,
+ kStatsValueNameConcealmentEvents,
+ kStatsValueNameDataChannelId,
+ kStatsValueNameFramesDecoded,
+ kStatsValueNameFramesEncoded,
+ kStatsValueNameJitterBufferDelay,
+ kStatsValueNameMediaType,
+ kStatsValueNamePacketsLost,
+ kStatsValueNamePacketsReceived,
+ kStatsValueNamePacketsSent,
+ kStatsValueNameProtocol,
+ kStatsValueNameQpSum,
+ kStatsValueNameReceiving,
+ kStatsValueNameSelectedCandidatePairId,
+ kStatsValueNameSsrc,
+ kStatsValueNameState,
+ kStatsValueNameTotalAudioEnergy,
+ kStatsValueNameTotalSamplesDuration,
+ kStatsValueNameTotalSamplesReceived,
+ kStatsValueNameTransportId,
+ kStatsValueNameSentPingRequestsTotal,
+ kStatsValueNameSentPingRequestsBeforeFirstResponse,
+ kStatsValueNameSentPingResponses,
+ kStatsValueNameRecvPingRequests,
+ kStatsValueNameRecvPingResponses,
+ kStatsValueNameSentStunKeepaliveRequests,
+ kStatsValueNameRecvStunKeepaliveResponses,
+ kStatsValueNameStunKeepaliveRttTotal,
+ kStatsValueNameStunKeepaliveRttSquaredTotal,
+
+ // Internal StatsValue names.
+ kStatsValueNameAccelerateRate,
+ kStatsValueNameActualEncBitrate,
+ kStatsValueNameAdaptationChanges,
+ kStatsValueNameAvailableReceiveBandwidth,
+ kStatsValueNameAvailableSendBandwidth,
+ kStatsValueNameAvgEncodeMs,
+ kStatsValueNameBandwidthLimitedResolution,
+ kStatsValueNameBucketDelay,
+ kStatsValueNameCaptureStartNtpTimeMs,
+ kStatsValueNameCandidateIPAddress,
+ kStatsValueNameCandidateNetworkType,
+ kStatsValueNameCandidatePortNumber,
+ kStatsValueNameCandidatePriority,
+ kStatsValueNameCandidateTransportType,
+ kStatsValueNameCandidateType,
+ kStatsValueNameChannelId,
+ kStatsValueNameCodecName,
+ kStatsValueNameComponent,
+ kStatsValueNameContentName,
+ kStatsValueNameContentType,
+ kStatsValueNameCpuLimitedResolution,
+ kStatsValueNameCurrentDelayMs,
+ kStatsValueNameDecodeMs,
+ kStatsValueNameDecodingCNG,
+ kStatsValueNameDecodingCTN,
+ kStatsValueNameDecodingCTSG,
+ kStatsValueNameDecodingMutedOutput,
+ kStatsValueNameDecodingNormal,
+ kStatsValueNameDecodingPLC,
+ kStatsValueNameDecodingPLCCNG,
+ kStatsValueNameDer,
+ kStatsValueNameDtlsCipher,
+ kStatsValueNameEchoDelayMedian,
+ kStatsValueNameEchoDelayStdDev,
+ kStatsValueNameEchoReturnLoss,
+ kStatsValueNameEchoReturnLossEnhancement,
+ kStatsValueNameEncodeUsagePercent,
+ kStatsValueNameExpandRate,
+ kStatsValueNameFingerprint,
+ kStatsValueNameFingerprintAlgorithm,
+ kStatsValueNameFirsReceived,
+ kStatsValueNameFirsSent,
+ kStatsValueNameFirstFrameReceivedToDecodedMs,
+ kStatsValueNameFrameHeightInput,
+ kStatsValueNameFrameHeightReceived,
+ kStatsValueNameFrameHeightSent,
+ kStatsValueNameFrameRateDecoded,
+ kStatsValueNameFrameRateInput,
+ kStatsValueNameFrameRateOutput,
+ kStatsValueNameFrameRateReceived,
+ kStatsValueNameFrameRateSent,
+ kStatsValueNameFrameWidthInput,
+ kStatsValueNameFrameWidthReceived,
+ kStatsValueNameFrameWidthSent,
+ kStatsValueNameHasEnteredLowResolution,
+ kStatsValueNameHugeFramesSent,
+ kStatsValueNameInitiator,
+ kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds.
+ kStatsValueNameIssuerId,
+ kStatsValueNameJitterBufferMs,
+ kStatsValueNameJitterReceived,
+ kStatsValueNameLabel,
+ kStatsValueNameLocalAddress,
+ kStatsValueNameLocalCandidateId,
+ kStatsValueNameLocalCandidateType,
+ kStatsValueNameLocalCertificateId,
+ kStatsValueNameMaxDecodeMs,
+ kStatsValueNameMinPlayoutDelayMs,
+ kStatsValueNameNacksReceived,
+ kStatsValueNameNacksSent,
+ kStatsValueNamePlisReceived,
+ kStatsValueNamePlisSent,
+ kStatsValueNamePreemptiveExpandRate,
+ kStatsValueNamePreferredJitterBufferMs,
+ kStatsValueNameRemoteAddress,
+ kStatsValueNameRemoteCandidateId,
+ kStatsValueNameRemoteCandidateType,
+ kStatsValueNameRemoteCertificateId,
+ kStatsValueNameRenderDelayMs,
+ kStatsValueNameResidualEchoLikelihood,
+ kStatsValueNameResidualEchoLikelihoodRecentMax,
+ kStatsValueNameAnaBitrateActionCounter,
+ kStatsValueNameAnaChannelActionCounter,
+ kStatsValueNameAnaDtxActionCounter,
+ kStatsValueNameAnaFecActionCounter,
+ kStatsValueNameAnaFrameLengthIncreaseCounter,
+ kStatsValueNameAnaFrameLengthDecreaseCounter,
+ kStatsValueNameAnaUplinkPacketLossFraction,
+ kStatsValueNameRetransmitBitrate,
+ kStatsValueNameRtt,
+ kStatsValueNameSecondaryDecodedRate,
+ kStatsValueNameSecondaryDiscardedRate,
+ kStatsValueNameSendPacketsDiscarded,
+ kStatsValueNameSpeechExpandRate,
+ kStatsValueNameSrtpCipher,
+ kStatsValueNameTargetDelayMs,
+ kStatsValueNameTargetEncBitrate,
+ kStatsValueNameTimingFrameInfo, // Result of |TimingFrameInfo::ToString|
+ kStatsValueNameTrackId,
+ kStatsValueNameTransmitBitrate,
+ kStatsValueNameTransportType,
+ kStatsValueNameTypingNoiseState,
+ kStatsValueNameWritable,
+ };
+
+ class IdBase : public rtc::RefCountInterface {
+ public:
+ ~IdBase() override;
+ StatsType type() const;
+
+ // Users of IdBase will be using the Id typedef, which is compatible with
+ // this Equals() function. It simply calls the protected (and overridden)
+ // Equals() method.
+ bool Equals(const rtc::scoped_refptr<IdBase>& other) const {
+ return Equals(*other.get());
+ }
+
+ virtual std::string ToString() const = 0;
+
+ protected:
+ // Protected since users of the IdBase type will be using the Id typedef.
+ virtual bool Equals(const IdBase& other) const;
+
+ explicit IdBase(StatsType type); // Only meant for derived classes.
+ const StatsType type_;
+
+ static const char kSeparator = '_';
+ };
+
+ typedef rtc::scoped_refptr<IdBase> Id;
+
+ struct Value {
+ enum Type {
+ kInt, // int.
+ kInt64, // int64_t.
+ kFloat, // float.
+ kString, // std::string
+ kStaticString, // const char*.
+ kBool, // bool.
+ kId, // Id.
+ };
+
+ Value(StatsValueName name, int64_t value, Type int_type);
+ Value(StatsValueName name, float f);
+ Value(StatsValueName name, const std::string& value);
+ Value(StatsValueName name, const char* value);
+ Value(StatsValueName name, bool b);
+ Value(StatsValueName name, const Id& value);
+
+ ~Value();
+
+ // Support ref counting. Note that for performance reasons, we
+ // don't use thread safe operations. Therefore, all operations
+ // affecting the ref count (in practice, creation and copying of
+ // the Values mapping) must occur on webrtc's signalling thread.
+ int AddRef() const {
+ RTC_DCHECK_RUN_ON(&thread_checker_);
+ return ++ref_count_;
+ }
+ int Release() const {
+ RTC_DCHECK_RUN_ON(&thread_checker_);
+ int count = --ref_count_;
+ if (!count)
+ delete this;
+ return count;
+ }
+
+ // TODO(tommi): This compares name as well as value...
+ // I think we should only need to compare the value part and
+ // move the name part into a hash map.
+ bool Equals(const Value& other) const;
+
+ // Comparison operators. Return true iff the current instance is of the
+ // correct type and holds the same value. No conversion is performed so
+ // a string value of "123" is not equal to an int value of 123 and an int
+ // value of 123 is not equal to a float value of 123.0f.
+ // One exception to this is that types kInt and kInt64 can be compared and
+ // kString and kStaticString too.
+ bool operator==(const std::string& value) const;
+ bool operator==(const char* value) const;
+ bool operator==(int64_t value) const;
+ bool operator==(bool value) const;
+ bool operator==(float value) const;
+ bool operator==(const Id& value) const;
+
+ // Getters that allow getting the native value directly.
+ // The caller must know the type beforehand or else hit a check.
+ int int_val() const;
+ int64_t int64_val() const;
+ float float_val() const;
+ const char* static_string_val() const;
+ const std::string& string_val() const;
+ bool bool_val() const;
+ const Id& id_val() const;
+
+ // Returns the string representation of |name|.
+ const char* display_name() const;
+
+ // Converts the native value to a string representation of the value.
+ std::string ToString() const;
+
+ Type type() const { return type_; }
+
+ // TODO(tommi): Move |name| and |display_name| out of the Value struct.
+ const StatsValueName name;
+
+ private:
+ rtc::ThreadChecker thread_checker_;
+ mutable int ref_count_ RTC_GUARDED_BY(thread_checker_) = 0;
+
+ const Type type_;
+ // TODO(tommi): Use C++ 11 union and make value_ const.
+ union InternalType {
+ int int_;
+ int64_t int64_;
+ float float_;
+ bool bool_;
+ std::string* string_;
+ const char* static_string_;
+ Id* id_;
+ } value_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Value);
+ };
+
+ typedef rtc::scoped_refptr<Value> ValuePtr;
+ typedef std::map<StatsValueName, ValuePtr> Values;
+
+ // Ownership of |id| is passed to |this|.
+ explicit StatsReport(const Id& id);
+ ~StatsReport();
+
+ // Factory functions for various types of stats IDs.
+ static Id NewBandwidthEstimationId();
+ static Id NewTypedId(StatsType type, const std::string& id);
+ static Id NewTypedIntId(StatsType type, int id);
+ static Id NewIdWithDirection(StatsType type,
+ const std::string& id,
+ Direction direction);
+ static Id NewCandidateId(bool local, const std::string& id);
+ static Id NewComponentId(const std::string& content_name, int component);
+ static Id NewCandidatePairId(const std::string& content_name,
+ int component,
+ int index);
+
+ const Id& id() const { return id_; }
+ StatsType type() const { return id_->type(); }
+ double timestamp() const { return timestamp_; }
+ void set_timestamp(double t) { timestamp_ = t; }
+ bool empty() const { return values_.empty(); }
+ const Values& values() const { return values_; }
+
+ const char* TypeToString() const;
+
+ void AddString(StatsValueName name, const std::string& value);
+ void AddString(StatsValueName name, const char* value);
+ void AddInt64(StatsValueName name, int64_t value);
+ void AddInt(StatsValueName name, int value);
+ void AddFloat(StatsValueName name, float value);
+ void AddBoolean(StatsValueName name, bool value);
+ void AddId(StatsValueName name, const Id& value);
+
+ const Value* FindValue(StatsValueName name) const;
+
+ private:
+ // The unique identifier for this object.
+ // This is used as a key for this report in ordered containers,
+ // so it must never be changed.
+ const Id id_;
+ double timestamp_; // Time since 1970-01-01T00:00:00Z in milliseconds.
+ Values values_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(StatsReport);
+};
+
+// Typedef for an array of const StatsReport pointers.
+// Ownership of the pointers held by this implementation is assumed to lie
+// elsewhere and lifetime guarantees are made by the implementation that uses
+// this type. In the StatsCollector, object ownership lies with the
+// StatsCollection class.
+typedef std::vector<const StatsReport*> StatsReports;
+
+// A map from the report id to the report.
+// This class wraps an STL container and provides a limited set of
+// functionality in order to keep things simple.
+class StatsCollection {
+ public:
+ StatsCollection();
+ ~StatsCollection();
+
+ typedef std::list<StatsReport*> Container;
+ typedef Container::iterator iterator;
+ typedef Container::const_iterator const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+ size_t size() const;
+
+ // Creates a new report object with |id| that does not already
+ // exist in the list of reports.
+ StatsReport* InsertNew(const StatsReport::Id& id);
+ StatsReport* FindOrAddNew(const StatsReport::Id& id);
+ StatsReport* ReplaceOrAddNew(const StatsReport::Id& id);
+
+ // Looks for a report with the given |id|. If one is not found, null
+ // will be returned.
+ StatsReport* Find(const StatsReport::Id& id);
+
+ private:
+ Container list_;
+ rtc::ThreadChecker thread_checker_;
+};
+
+} // namespace webrtc
+
+#endif // API_STATS_TYPES_H_
diff --git a/api/task_queue/default_task_queue_factory.h b/api/task_queue/default_task_queue_factory.h
new file mode 100644
index 0000000..ccdd1eb
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
+#define API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory();
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/default_task_queue_factory_gcd.cc b/api/task_queue/default_task_queue_factory_gcd.cc
new file mode 100644
index 0000000..7e17b48
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory_gcd.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright 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 <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/task_queue_gcd.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() {
+ return CreateTaskQueueGcdFactory();
+}
+
+} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_libevent.cc b/api/task_queue/default_task_queue_factory_libevent.cc
new file mode 100644
index 0000000..f2fb418
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory_libevent.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright 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 <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/task_queue_libevent.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() {
+ return CreateTaskQueueLibeventFactory();
+}
+
+} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_stdlib.cc b/api/task_queue/default_task_queue_factory_stdlib.cc
new file mode 100644
index 0000000..ca7d720
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory_stdlib.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright 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 <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/task_queue_stdlib.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() {
+ return CreateTaskQueueStdlibFactory();
+}
+
+} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_unittest.cc b/api/task_queue/default_task_queue_factory_unittest.cc
new file mode 100644
index 0000000..92c17d8
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory_unittest.cc
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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 "api/task_queue/default_task_queue_factory.h"
+
+#include "api/task_queue/task_queue_test.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+INSTANTIATE_TEST_SUITE_P(Default,
+ TaskQueueTest,
+ ::testing::Values(CreateDefaultTaskQueueFactory));
+
+} // namespace
+} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_win.cc b/api/task_queue/default_task_queue_factory_win.cc
new file mode 100644
index 0000000..493ea66
--- /dev/null
+++ b/api/task_queue/default_task_queue_factory_win.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright 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 <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/task_queue_win.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() {
+ return CreateTaskQueueWinFactory();
+}
+
+} // namespace webrtc
diff --git a/api/task_queue/global_task_queue_factory.cc b/api/task_queue/global_task_queue_factory.cc
new file mode 100644
index 0000000..528d14d
--- /dev/null
+++ b/api/task_queue/global_task_queue_factory.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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 "api/task_queue/global_task_queue_factory.h"
+
+#include "api/task_queue/default_task_queue_factory.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+TaskQueueFactory* GlobalOrDefault(TaskQueueFactory* global) {
+ static TaskQueueFactory* const factory =
+ global ? global : CreateDefaultTaskQueueFactory().release();
+ return factory;
+}
+
+} // namespace
+
+void SetGlobalTaskQueueFactory(std::unique_ptr<TaskQueueFactory> factory) {
+ RTC_CHECK(factory) << "Can't set nullptr TaskQueueFactory";
+ // Own, but never delete the global factory.
+ TaskQueueFactory* global = factory.release();
+ RTC_CHECK(GlobalOrDefault(global) == global)
+ << "Task queue factory set after another SetFactory or after a task "
+ "queue was created";
+}
+
+TaskQueueFactory& GlobalTaskQueueFactory() {
+ return *GlobalOrDefault(nullptr);
+}
+
+} // namespace webrtc
diff --git a/api/task_queue/global_task_queue_factory.h b/api/task_queue/global_task_queue_factory.h
new file mode 100644
index 0000000..a580833
--- /dev/null
+++ b/api/task_queue/global_task_queue_factory.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_
+#define API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+// May be called at most once, and before any TaskQueue is created.
+void SetGlobalTaskQueueFactory(std::unique_ptr<TaskQueueFactory> factory);
+
+// Returns TaskQueue factory. Always returns the same factory.
+TaskQueueFactory& GlobalTaskQueueFactory();
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/module.mk b/api/task_queue/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/api/task_queue/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/api/task_queue/queued_task.h b/api/task_queue/queued_task.h
new file mode 100644
index 0000000..5748628
--- /dev/null
+++ b/api/task_queue/queued_task.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+#ifndef API_TASK_QUEUE_QUEUED_TASK_H_
+#define API_TASK_QUEUE_QUEUED_TASK_H_
+
+namespace webrtc {
+
+// Base interface for asynchronously executed tasks.
+// The interface basically consists of a single function, Run(), that executes
+// on the target queue. For more details see the Run() method and TaskQueue.
+class QueuedTask {
+ public:
+ virtual ~QueuedTask() = default;
+
+ // Main routine that will run when the task is executed on the desired queue.
+ // The task should return |true| to indicate that it should be deleted or
+ // |false| to indicate that the queue should consider ownership of the task
+ // having been transferred. Returning |false| can be useful if a task has
+ // re-posted itself to a different queue or is otherwise being re-used.
+ virtual bool Run() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_QUEUED_TASK_H_
diff --git a/api/task_queue/task_queue_base.cc b/api/task_queue/task_queue_base.cc
new file mode 100644
index 0000000..7d3539a
--- /dev/null
+++ b/api/task_queue/task_queue_base.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright 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 "api/task_queue/task_queue_base.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "rtc_base/checks.h"
+
+#if defined(ABSL_HAVE_THREAD_LOCAL)
+
+namespace webrtc {
+namespace {
+
+ABSL_CONST_INIT thread_local TaskQueueBase* current = nullptr;
+
+} // namespace
+
+TaskQueueBase* TaskQueueBase::Current() {
+ return current;
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
+ TaskQueueBase* task_queue)
+ : previous_(current) {
+ current = task_queue;
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
+ current = previous_;
+}
+} // namespace webrtc
+
+#elif defined(WEBRTC_POSIX)
+
+#include <pthread.h>
+
+namespace webrtc {
+namespace {
+
+ABSL_CONST_INIT pthread_key_t g_queue_ptr_tls = 0;
+
+void InitializeTls() {
+ RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0);
+}
+
+pthread_key_t GetQueuePtrTls() {
+ static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+ RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0);
+ return g_queue_ptr_tls;
+}
+
+} // namespace
+
+TaskQueueBase* TaskQueueBase::Current() {
+ return static_cast<TaskQueueBase*>(pthread_getspecific(GetQueuePtrTls()));
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
+ TaskQueueBase* task_queue)
+ : previous_(TaskQueueBase::Current()) {
+ pthread_setspecific(GetQueuePtrTls(), task_queue);
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
+ pthread_setspecific(GetQueuePtrTls(), previous_);
+}
+
+} // namespace webrtc
+
+#else
+#error Unsupported platform
+#endif
diff --git a/api/task_queue/task_queue_base.h b/api/task_queue/task_queue_base.h
new file mode 100644
index 0000000..b1b5cc7
--- /dev/null
+++ b/api/task_queue/task_queue_base.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+
+#include <memory>
+
+#include "api/task_queue/queued_task.h"
+
+// TODO(bugs.webrtc.org/10191): Remove when
+// rtc::TaskQueue* rtc::TaskQueue::Current() is unused.
+namespace rtc {
+class TaskQueue;
+} // namespace rtc
+
+namespace webrtc {
+
+// Asynchronously executes tasks in a way that guarantees that they're executed
+// in FIFO order and that tasks never overlap. Tasks may always execute on the
+// same worker thread and they may not. To DCHECK that tasks are executing on a
+// known task queue, use IsCurrent().
+class TaskQueueBase {
+ public:
+ // Starts destruction of the task queue.
+ // On return ensures no task are running and no new tasks are able to start
+ // on the task queue.
+ // Responsible for deallocation. Deallocation may happen syncrhoniously during
+ // Delete or asynchronously after Delete returns.
+ // Code not running on the TaskQueue should not make any assumption when
+ // TaskQueue is deallocated and thus should not call any methods after Delete.
+ // Code running on the TaskQueue should not call Delete, but can assume
+ // TaskQueue still exists and may call other methods, e.g. PostTask.
+ virtual void Delete() = 0;
+
+ // Schedules a task to execute. Tasks are executed in FIFO order.
+ // If |task->Run()| returns true, task is deleted on the task queue
+ // before next QueuedTask starts executing.
+ // When a TaskQueue is deleted, pending tasks will not be executed but they
+ // will be deleted. The deletion of tasks may happen synchronously on the
+ // TaskQueue or it may happen asynchronously after TaskQueue is deleted.
+ // This may vary from one implementation to the next so assumptions about
+ // lifetimes of pending tasks should not be made.
+ virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0;
+
+ // Schedules a task to execute a specified number of milliseconds from when
+ // the call is made. The precision should be considered as "best effort"
+ // and in some cases, such as on Windows when all high precision timers have
+ // been used up, can be off by as much as 15 millseconds.
+ virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) = 0;
+
+ // Returns the task queue that is running the current thread.
+ // Returns nullptr if this thread is not associated with any task queue.
+ static TaskQueueBase* Current();
+ bool IsCurrent() const { return Current() == this; }
+
+ protected:
+ class CurrentTaskQueueSetter {
+ public:
+ explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
+ CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
+ CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete;
+ ~CurrentTaskQueueSetter();
+
+ private:
+ TaskQueueBase* const previous_;
+ };
+
+ // Users of the TaskQueue should call Delete instead of directly deleting
+ // this object.
+ virtual ~TaskQueueBase() = default;
+
+ private:
+ friend class rtc::TaskQueue;
+ rtc::TaskQueue* task_queue_ = nullptr;
+};
+
+struct TaskQueueDeleter {
+ void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); }
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_TASK_QUEUE_BASE_H_
diff --git a/api/task_queue/task_queue_factory.h b/api/task_queue/task_queue_factory.h
new file mode 100644
index 0000000..b68ab33
--- /dev/null
+++ b/api/task_queue/task_queue_factory.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
+#define API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "api/task_queue/task_queue_base.h"
+
+namespace webrtc {
+
+// The implementation of this interface must be thread-safe.
+class TaskQueueFactory {
+ public:
+ // TaskQueue priority levels. On some platforms these will map to thread
+ // priorities, on others such as Mac and iOS, GCD queue priorities.
+ enum class Priority { NORMAL = 0, HIGH, LOW };
+
+ virtual ~TaskQueueFactory() = default;
+ virtual std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/task_queue_test.cc b/api/task_queue/task_queue_test.cc
new file mode 100644
index 0000000..e78dbd2
--- /dev/null
+++ b/api/task_queue/task_queue_test.cc
@@ -0,0 +1,254 @@
+/*
+ * Copyright 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 "api/task_queue/task_queue_test.h"
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/event.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+namespace {
+
+std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ const std::unique_ptr<webrtc::TaskQueueFactory>& factory,
+ absl::string_view task_queue_name,
+ TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL) {
+ return factory->CreateTaskQueue(task_queue_name, priority);
+}
+
+TEST_P(TaskQueueTest, Construct) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ auto queue = CreateTaskQueue(factory, "Construct");
+ EXPECT_FALSE(queue->IsCurrent());
+}
+
+TEST_P(TaskQueueTest, PostAndCheckCurrent) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event event;
+ auto queue = CreateTaskQueue(factory, "PostAndCheckCurrent");
+
+ // We're not running a task, so there shouldn't be a current queue.
+ EXPECT_FALSE(queue->IsCurrent());
+ EXPECT_FALSE(TaskQueueBase::Current());
+
+ queue->PostTask(ToQueuedTask([&event, &queue] {
+ EXPECT_TRUE(queue->IsCurrent());
+ event.Set();
+ }));
+ EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostCustomTask) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event ran;
+ auto queue = CreateTaskQueue(factory, "PostCustomImplementation");
+
+ class CustomTask : public QueuedTask {
+ public:
+ explicit CustomTask(rtc::Event* ran) : ran_(ran) {}
+
+ private:
+ bool Run() override {
+ ran_->Set();
+ return false; // Do not allow the task to be deleted by the queue.
+ }
+
+ rtc::Event* const ran_;
+ } my_task(&ran);
+
+ queue->PostTask(absl::WrapUnique(&my_task));
+ EXPECT_TRUE(ran.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayedZero) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event event;
+ auto queue = CreateTaskQueue(factory, "PostDelayedZero");
+
+ queue->PostDelayedTask(ToQueuedTask([&event] { event.Set(); }), 0);
+ EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostFromQueue) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event event;
+ auto queue = CreateTaskQueue(factory, "PostFromQueue");
+
+ queue->PostTask(ToQueuedTask([&event, &queue] {
+ queue->PostTask(ToQueuedTask([&event] { event.Set(); }));
+ }));
+ EXPECT_TRUE(event.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayed) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event event;
+ auto queue =
+ CreateTaskQueue(factory, "PostDelayed", TaskQueueFactory::Priority::HIGH);
+
+ int64_t start = rtc::TimeMillis();
+ queue->PostDelayedTask(ToQueuedTask([&event, &queue] {
+ EXPECT_TRUE(queue->IsCurrent());
+ event.Set();
+ }),
+ 100);
+ EXPECT_TRUE(event.Wait(1000));
+ int64_t end = rtc::TimeMillis();
+ // These tests are a little relaxed due to how "powerful" our test bots can
+ // be. Most recently we've seen windows bots fire the callback after 94-99ms,
+ // which is why we have a little bit of leeway backwards as well.
+ EXPECT_GE(end - start, 90u);
+ EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290.
+}
+
+TEST_P(TaskQueueTest, PostMultipleDelayed) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ auto queue = CreateTaskQueue(factory, "PostMultipleDelayed");
+
+ std::vector<rtc::Event> events(100);
+ for (int i = 0; i < 100; ++i) {
+ rtc::Event* event = &events[i];
+ queue->PostDelayedTask(ToQueuedTask([event, &queue] {
+ EXPECT_TRUE(queue->IsCurrent());
+ event->Set();
+ }),
+ i);
+ }
+
+ for (rtc::Event& e : events)
+ EXPECT_TRUE(e.Wait(1000));
+}
+
+TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event run;
+ rtc::Event deleted;
+ auto queue = CreateTaskQueue(factory, "PostDelayedAfterDestruct");
+ queue->PostDelayedTask(
+ ToQueuedTask([&run] { run.Set(); }, [&deleted] { deleted.Set(); }), 100);
+ // Destroy the queue.
+ queue = nullptr;
+ // Task might outlive the TaskQueue, but still should be deleted.
+ EXPECT_TRUE(deleted.Wait(200));
+ EXPECT_FALSE(run.Wait(0)); // and should not run.
+}
+
+TEST_P(TaskQueueTest, PostAndReuse) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ rtc::Event event;
+ auto post_queue = CreateTaskQueue(factory, "PostQueue");
+ auto reply_queue = CreateTaskQueue(factory, "ReplyQueue");
+
+ int call_count = 0;
+
+ class ReusedTask : public QueuedTask {
+ public:
+ ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event)
+ : counter_(*counter), reply_queue_(reply_queue), event_(*event) {
+ EXPECT_EQ(counter_, 0);
+ }
+
+ private:
+ bool Run() override {
+ if (++counter_ == 1) {
+ reply_queue_->PostTask(absl::WrapUnique(this));
+ // At this point, the object is owned by reply_queue_ and it's
+ // theoratically possible that the object has been deleted (e.g. if
+ // posting wasn't possible). So, don't touch any member variables here.
+
+ // Indicate to the current queue that ownership has been transferred.
+ return false;
+ } else {
+ EXPECT_EQ(counter_, 2);
+ EXPECT_TRUE(reply_queue_->IsCurrent());
+ event_.Set();
+ return true; // Indicate that the object should be deleted.
+ }
+ }
+
+ int& counter_;
+ TaskQueueBase* const reply_queue_;
+ rtc::Event& event_;
+ };
+
+ auto task =
+ absl::make_unique<ReusedTask>(&call_count, reply_queue.get(), &event);
+ post_queue->PostTask(std::move(task));
+ EXPECT_TRUE(event.Wait(1000));
+}
+
+// Tests posting more messages than a queue can queue up.
+// In situations like that, tasks will get dropped.
+TEST_P(TaskQueueTest, PostALot) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ // To destruct the event after the queue has gone out of scope.
+ rtc::Event event;
+
+ int tasks_executed = 0;
+ int tasks_cleaned_up = 0;
+ static const int kTaskCount = 0xffff;
+
+ {
+ auto queue = CreateTaskQueue(factory, "PostALot");
+
+ // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
+ // So here we post a total of 0xffff+1 messages, which triggers a failure
+ // case inside of the libevent queue implementation.
+
+ queue->PostTask(
+ ToQueuedTask([&event] { event.Wait(rtc::Event::kForever); }));
+ for (int i = 0; i < kTaskCount; ++i)
+ queue->PostTask(
+ ToQueuedTask([&tasks_executed] { ++tasks_executed; },
+ [&tasks_cleaned_up] { ++tasks_cleaned_up; }));
+ event.Set(); // Unblock the first task.
+ }
+
+ EXPECT_GE(tasks_cleaned_up, tasks_executed);
+ EXPECT_EQ(tasks_cleaned_up, kTaskCount);
+}
+
+// Test posting two tasks that have shared state not protected by a
+// lock. The TaskQueue should guarantee memory read-write order and
+// FIFO task execution order, so the second task should always see the
+// changes that were made by the first task.
+//
+// If the TaskQueue doesn't properly synchronize the execution of
+// tasks, there will be a data race, which is undefined behavior. The
+// EXPECT calls may randomly catch this, but to make the most of this
+// unit test, run it under TSan or some other tool that is able to
+// directly detect data races.
+TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
+ std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()();
+ struct SharedState {
+ // First task will set this value to 1 and second will assert it.
+ int state = 0;
+ } state;
+
+ auto queue = CreateTaskQueue(factory, "PostTwoWithSharedUnprotectedState");
+ rtc::Event done;
+ queue->PostTask(ToQueuedTask([&state, &queue, &done] {
+ // Post tasks from queue to guarantee, that 1st task won't be
+ // executed before the second one will be posted.
+ queue->PostTask(ToQueuedTask([&state] { state.state = 1; }));
+ queue->PostTask(ToQueuedTask([&state, &done] {
+ EXPECT_EQ(state.state, 1);
+ done.Set();
+ }));
+ // Check, that state changing tasks didn't start yet.
+ EXPECT_EQ(state.state, 0);
+ }));
+ EXPECT_TRUE(done.Wait(1000));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/api/task_queue/task_queue_test.h b/api/task_queue/task_queue_test.h
new file mode 100644
index 0000000..e2e4730
--- /dev/null
+++ b/api/task_queue/task_queue_test.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TASK_QUEUE_TASK_QUEUE_TEST_H_
+#define API_TASK_QUEUE_TASK_QUEUE_TEST_H_
+
+#include <functional>
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+// Suite of tests to verify TaskQueue implementation with.
+// Example usage:
+//
+// namespace {
+//
+// using ::testing::Values;
+// using ::webrtc::TaskQueueTest;
+//
+// std::unique_ptr<webrtc::TaskQueueFactory> CreateMyFactory();
+//
+// INSTANTIATE_TEST_SUITE_P(My, TaskQueueTest, Values(CreateMyFactory));
+//
+// } // namespace
+class TaskQueueTest : public ::testing::TestWithParam<
+ std::function<std::unique_ptr<TaskQueueFactory>()>> {
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_TASK_QUEUE_TEST_H_
diff --git a/api/transport/field_trial_based_config.cc b/api/transport/field_trial_based_config.cc
new file mode 100644
index 0000000..7e6764f
--- /dev/null
+++ b/api/transport/field_trial_based_config.cc
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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 "api/transport/field_trial_based_config.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+std::string FieldTrialBasedConfig::Lookup(absl::string_view key) const {
+ return webrtc::field_trial::FindFullName(std::string(key));
+}
+} // namespace webrtc
diff --git a/api/transport/field_trial_based_config.h b/api/transport/field_trial_based_config.h
new file mode 100644
index 0000000..e0989db
--- /dev/null
+++ b/api/transport/field_trial_based_config.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
+#define API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
+
+#include <string>
+#include "absl/strings/string_view.h"
+#include "api/transport/webrtc_key_value_config.h"
+
+namespace webrtc {
+// Implementation using the field trial API fo the key value lookup.
+class FieldTrialBasedConfig : public WebRtcKeyValueConfig {
+ public:
+ std::string Lookup(absl::string_view key) const override;
+};
+} // namespace webrtc
+
+#endif // API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
diff --git a/api/transport/goog_cc_factory.cc b/api/transport/goog_cc_factory.cc
index 119e2dc..92fd4d1 100644
--- a/api/transport/goog_cc_factory.cc
+++ b/api/transport/goog_cc_factory.cc
@@ -10,8 +10,11 @@
#include "api/transport/goog_cc_factory.h"
+#include <stdint.h>
+
#include "absl/memory/memory.h"
#include "modules/congestion_controller/goog_cc/goog_cc_network_control.h"
+
namespace webrtc {
GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
RtcEventLog* event_log)
diff --git a/api/transport/network_control.h b/api/transport/network_control.h
index 9086260..53ac10e 100644
--- a/api/transport/network_control.h
+++ b/api/transport/network_control.h
@@ -14,6 +14,7 @@
#include <memory>
#include "api/transport/network_types.h"
+#include "api/transport/webrtc_key_value_config.h"
namespace webrtc {
@@ -23,6 +24,9 @@
// Called to indicate target transfer rate as well as giving information about
// the current estimate of network parameters.
virtual void OnTargetTransferRate(TargetTransferRate) = 0;
+ // Called to provide updates to the expected target rate in case it changes
+ // before the first call to OnTargetTransferRate.
+ virtual void OnStartRateUpdate(DataRate) {}
};
// Configuration sent to factory create function. The parameters here are
@@ -36,6 +40,10 @@
// Initial stream specific configuration, these are changed at any later time
// by calls to OnStreamsConfig.
StreamsConfig stream_based_config;
+
+ // Optional override of configuration of WebRTC internals. Using nullptr here
+ // indicates that the field trial API will be used.
+ const WebRtcKeyValueConfig* key_value_config = nullptr;
};
// NetworkControllerInterface is implemented by network controllers. A network
diff --git a/api/transport/network_types.cc b/api/transport/network_types.cc
index 80214de..acc9c2b 100644
--- a/api/transport/network_types.cc
+++ b/api/transport/network_types.cc
@@ -81,4 +81,8 @@
probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
}
+ProcessInterval::ProcessInterval() = default;
+ProcessInterval::ProcessInterval(const ProcessInterval&) = default;
+ProcessInterval::~ProcessInterval() = default;
+
} // namespace webrtc
diff --git a/api/transport/network_types.h b/api/transport/network_types.h
index 0f1d7ab..e26561a 100644
--- a/api/transport/network_types.h
+++ b/api/transport/network_types.h
@@ -31,13 +31,11 @@
StreamsConfig(const StreamsConfig&);
~StreamsConfig();
Timestamp at_time = Timestamp::PlusInfinity();
- bool requests_alr_probing = false;
+ absl::optional<bool> requests_alr_probing;
absl::optional<double> pacing_factor;
absl::optional<DataRate> min_pacing_rate;
absl::optional<DataRate> max_padding_rate;
absl::optional<DataRate> max_total_allocated_bitrate;
- // The send rate of traffic for which feedback is not received.
- DataRate unacknowledged_rate_allocation = DataRate::Zero();
};
struct TargetRateConstraints {
@@ -136,6 +134,7 @@
~TransportPacketsFeedback();
Timestamp feedback_time = Timestamp::PlusInfinity();
+ Timestamp first_unacked_send_time = Timestamp::PlusInfinity();
DataSize data_in_flight = DataSize::Zero();
DataSize prior_in_flight = DataSize::Zero();
std::vector<PacketResult> packet_feedbacks;
@@ -177,6 +176,7 @@
DataRate target_data_rate = DataRate::Zero();
TimeDelta target_duration = TimeDelta::Zero();
int32_t target_probe_count = 0;
+ int32_t id = 0;
};
struct TargetTransferRate {
@@ -201,7 +201,11 @@
// Process control
struct ProcessInterval {
+ ProcessInterval();
+ ProcessInterval(const ProcessInterval&);
+ ~ProcessInterval();
Timestamp at_time = Timestamp::PlusInfinity();
+ absl::optional<DataSize> pacer_queue;
};
} // namespace webrtc
diff --git a/api/transport/webrtc_key_value_config.h b/api/transport/webrtc_key_value_config.h
new file mode 100644
index 0000000..c6376a9
--- /dev/null
+++ b/api/transport/webrtc_key_value_config.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 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.
+ */
+#ifndef API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_
+#define API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_
+
+#include <string>
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+
+// An interface that provides a key-value mapping for configuring internal
+// details of WebRTC. Note that there's no guarantess that the meaning of a
+// particular key value mapping will be preserved over time and no announcements
+// will be made if they are changed. It's up to the library user to ensure that
+// the behavior does not break.
+class WebRtcKeyValueConfig {
+ public:
+ virtual ~WebRtcKeyValueConfig() = default;
+ // The configured value for the given key. Defaults to an empty string.
+ virtual std::string Lookup(absl::string_view key) const = 0;
+};
+} // namespace webrtc
+
+#endif // API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_
diff --git a/api/turn_customizer.h b/api/turn_customizer.h
new file mode 100644
index 0000000..f0bf0d9
--- /dev/null
+++ b/api/turn_customizer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef API_TURN_CUSTOMIZER_H_
+#define API_TURN_CUSTOMIZER_H_
+
+#include <stdlib.h>
+
+namespace cricket {
+class PortInterface;
+class StunMessage;
+} // namespace cricket
+
+namespace webrtc {
+
+class TurnCustomizer {
+ public:
+ // This is called before a TURN message is sent.
+ // This could be used to add implementation specific attributes to a request.
+ virtual void MaybeModifyOutgoingStunMessage(
+ cricket::PortInterface* port,
+ cricket::StunMessage* message) = 0;
+
+ // TURN can send data using channel data messages or Send indication.
+ // This method should return false if |data| should be sent using
+ // a Send indication instead of a ChannelData message, even if a
+ // channel is bound.
+ virtual bool AllowChannelData(cricket::PortInterface* port,
+ const void* data,
+ size_t size,
+ bool payload) = 0;
+
+ virtual ~TurnCustomizer() {}
+};
+
+} // namespace webrtc
+
+#endif // API_TURN_CUSTOMIZER_H_
diff --git a/api/uma_metrics.h b/api/uma_metrics.h
new file mode 100644
index 0000000..51b0ff0
--- /dev/null
+++ b/api/uma_metrics.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 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.
+ */
+
+// This file contains enums related to IPv4/IPv6 metrics.
+
+#ifndef API_UMA_METRICS_H_
+#define API_UMA_METRICS_H_
+
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+
+// Currently this contains information related to WebRTC network/transport
+// information.
+
+// The difference between PeerConnectionEnumCounter and
+// PeerConnectionMetricsName is that the "EnumCounter" is only counting the
+// occurrences of events, while "Name" has a value associated with it which is
+// used to form a histogram.
+
+// This enum is backed by Chromium's histograms.xml,
+// chromium/src/tools/metrics/histograms/histograms.xml
+// Existing values cannot be re-ordered and new enums must be added
+// before kBoundary.
+enum PeerConnectionAddressFamilyCounter {
+ kPeerConnection_IPv4,
+ kPeerConnection_IPv6,
+ kBestConnections_IPv4,
+ kBestConnections_IPv6,
+ kPeerConnectionAddressFamilyCounter_Max,
+};
+
+// TODO(guoweis): Keep previous name here until all references are renamed.
+#define kBoundary kPeerConnectionAddressFamilyCounter_Max
+
+// TODO(guoweis): Keep previous name here until all references are renamed.
+typedef PeerConnectionAddressFamilyCounter PeerConnectionUMAMetricsCounter;
+
+// This enum defines types for UMA samples, which will have a range.
+enum PeerConnectionMetricsName {
+ kNetworkInterfaces_IPv4, // Number of IPv4 interfaces.
+ kNetworkInterfaces_IPv6, // Number of IPv6 interfaces.
+ kTimeToConnect, // In milliseconds.
+ kLocalCandidates_IPv4, // Number of IPv4 local candidates.
+ kLocalCandidates_IPv6, // Number of IPv6 local candidates.
+ kPeerConnectionMetricsName_Max
+};
+
+// TODO(guoweis): Keep previous name here until all references are renamed.
+typedef PeerConnectionMetricsName PeerConnectionUMAMetricsName;
+
+// The IceCandidatePairType has the format of
+// <local_candidate_type>_<remote_candidate_type>. It is recorded based on the
+// type of candidate pair used when the PeerConnection first goes to a completed
+// state. When BUNDLE is enabled, only the first transport gets recorded.
+enum IceCandidatePairType {
+ // HostHost is deprecated. It was replaced with the set of types at the bottom
+ // to report private or public host IP address.
+ kIceCandidatePairHostHost,
+ kIceCandidatePairHostSrflx,
+ kIceCandidatePairHostRelay,
+ kIceCandidatePairHostPrflx,
+ kIceCandidatePairSrflxHost,
+ kIceCandidatePairSrflxSrflx,
+ kIceCandidatePairSrflxRelay,
+ kIceCandidatePairSrflxPrflx,
+ kIceCandidatePairRelayHost,
+ kIceCandidatePairRelaySrflx,
+ kIceCandidatePairRelayRelay,
+ kIceCandidatePairRelayPrflx,
+ kIceCandidatePairPrflxHost,
+ kIceCandidatePairPrflxSrflx,
+ kIceCandidatePairPrflxRelay,
+
+ // The following 9 types tell whether local and remote hosts have hostname,
+ // private or public IP addresses.
+ kIceCandidatePairHostPrivateHostPrivate,
+ kIceCandidatePairHostPrivateHostPublic,
+ kIceCandidatePairHostPublicHostPrivate,
+ kIceCandidatePairHostPublicHostPublic,
+ kIceCandidatePairHostNameHostName,
+ kIceCandidatePairHostNameHostPrivate,
+ kIceCandidatePairHostNameHostPublic,
+ kIceCandidatePairHostPrivateHostName,
+ kIceCandidatePairHostPublicHostName,
+ kIceCandidatePairMax
+};
+
+enum KeyExchangeProtocolType {
+ kEnumCounterKeyProtocolDtls,
+ kEnumCounterKeyProtocolSdes,
+ kEnumCounterKeyProtocolMax
+};
+
+enum KeyExchangeProtocolMedia {
+ kEnumCounterKeyProtocolMediaTypeDtlsAudio,
+ kEnumCounterKeyProtocolMediaTypeDtlsVideo,
+ kEnumCounterKeyProtocolMediaTypeDtlsData,
+ kEnumCounterKeyProtocolMediaTypeSdesAudio,
+ kEnumCounterKeyProtocolMediaTypeSdesVideo,
+ kEnumCounterKeyProtocolMediaTypeSdesData,
+ kEnumCounterKeyProtocolMediaTypeMax
+};
+
+enum SdpSemanticRequested {
+ kSdpSemanticRequestDefault,
+ kSdpSemanticRequestPlanB,
+ kSdpSemanticRequestUnifiedPlan,
+ kSdpSemanticRequestMax
+};
+
+enum SdpSemanticNegotiated {
+ kSdpSemanticNegotiatedNone,
+ kSdpSemanticNegotiatedPlanB,
+ kSdpSemanticNegotiatedUnifiedPlan,
+ kSdpSemanticNegotiatedMixed,
+ kSdpSemanticNegotiatedMax
+};
+
+// Metric which records the format of the received SDP for tracking how much the
+// difference between Plan B and Unified Plan affect users.
+enum SdpFormatReceived {
+ // No audio or video tracks. This is worth special casing since it seems to be
+ // the most common scenario (data-channel only).
+ kSdpFormatReceivedNoTracks,
+ // No more than one audio and one video track. Should be compatible with both
+ // Plan B and Unified Plan endpoints.
+ kSdpFormatReceivedSimple,
+ // More than one audio track or more than one video track in the Plan B format
+ // (e.g., one audio media section with multiple streams).
+ kSdpFormatReceivedComplexPlanB,
+ // More than one audio track or more than one video track in the Unified Plan
+ // format (e.g., two audio media sections).
+ kSdpFormatReceivedComplexUnifiedPlan,
+ kSdpFormatReceivedMax
+};
+
+// Metric for counting the outcome of adding an ICE candidate
+enum AddIceCandidateResult {
+ kAddIceCandidateSuccess,
+ kAddIceCandidateFailClosed,
+ kAddIceCandidateFailNoRemoteDescription,
+ kAddIceCandidateFailNullCandidate,
+ kAddIceCandidateFailNotValid,
+ kAddIceCandidateFailNotReady,
+ kAddIceCandidateFailInAddition,
+ kAddIceCandidateFailNotUsable,
+ kAddIceCandidateMax
+};
+
+// Metric for recording which api surface was used to enable simulcast.
+enum SimulcastApiVersion {
+ kSimulcastApiVersionNone,
+ kSimulcastApiVersionLegacy,
+ kSimulcastApiVersionSpecCompliant,
+ kSimulcastApiVersionMax,
+};
+
+} // namespace webrtc
+
+#endif // API_UMA_METRICS_H_
diff --git a/api/units/data_rate.cc b/api/units/data_rate.cc
index d72d958..f9586c5 100644
--- a/api/units/data_rate.cc
+++ b/api/units/data_rate.cc
@@ -10,6 +10,7 @@
#include "api/units/data_rate.h"
+#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
@@ -17,8 +18,10 @@
std::string ToString(DataRate value) {
char buf[64];
rtc::SimpleStringBuilder sb(buf);
- if (value.IsInfinite()) {
- sb << "inf bps";
+ if (value.IsPlusInfinity()) {
+ sb << "+inf bps";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf bps";
} else {
if (value.bps() == 0 || value.bps() % 1000 != 0) {
sb << value.bps() << " bps";
diff --git a/api/units/data_rate.h b/api/units/data_rate.h
index 7119284..9b09aa9 100644
--- a/api/units/data_rate.h
+++ b/api/units/data_rate.h
@@ -52,10 +52,17 @@
}
template <typename T>
static constexpr DataRate bps(T bits_per_second) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromValue(bits_per_second);
}
template <typename T>
+ static constexpr DataRate bytes_per_sec(T bytes_per_second) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction<8>(bytes_per_second);
+ }
+ template <typename T>
static constexpr DataRate kbps(T kilobits_per_sec) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromFraction<1000>(kilobits_per_sec);
}
template <typename T = int64_t>
@@ -63,6 +70,10 @@
return ToValue<T>();
}
template <typename T = int64_t>
+ constexpr T bytes_per_sec() const {
+ return ToFraction<8, T>();
+ }
+ template <typename T = int64_t>
T kbps() const {
return ToFraction<1000, T>();
}
diff --git a/api/units/data_size.cc b/api/units/data_size.cc
index 8a87786..45487df 100644
--- a/api/units/data_size.cc
+++ b/api/units/data_size.cc
@@ -10,6 +10,7 @@
#include "api/units/data_size.h"
+#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
@@ -17,8 +18,10 @@
std::string ToString(DataSize value) {
char buf[64];
rtc::SimpleStringBuilder sb(buf);
- if (value.IsInfinite()) {
- sb << "inf bytes";
+ if (value.IsPlusInfinity()) {
+ sb << "+inf bytes";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf bytes";
} else {
sb << value.bytes() << " bytes";
}
diff --git a/api/units/data_size.h b/api/units/data_size.h
index b4cbb65..90ef00d 100644
--- a/api/units/data_size.h
+++ b/api/units/data_size.h
@@ -31,14 +31,13 @@
return FromStaticValue<bytes>();
}
- template <
- typename T,
- typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
+ template <typename T>
static DataSize bytes(T bytes) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromValue(bytes);
}
template <typename T = int64_t>
- typename std::enable_if<std::is_arithmetic<T>::value, T>::type bytes() const {
+ T bytes() const {
return ToValue<T>();
}
diff --git a/api/units/time_delta.cc b/api/units/time_delta.cc
index f90451b..9fe1308 100644
--- a/api/units/time_delta.cc
+++ b/api/units/time_delta.cc
@@ -10,6 +10,7 @@
#include "api/units/time_delta.h"
+#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
index 6458369..e5172f4 100644
--- a/api/units/time_delta.h
+++ b/api/units/time_delta.h
@@ -46,14 +46,17 @@
}
template <typename T>
static TimeDelta seconds(T seconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromFraction<1000000>(seconds);
}
template <typename T>
static TimeDelta ms(T milliseconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromFraction<1000>(milliseconds);
}
template <typename T>
static TimeDelta us(T microseconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromValue(microseconds);
}
template <typename T = int64_t>
diff --git a/api/units/timestamp.cc b/api/units/timestamp.cc
index d3417cf..0b9cdd9 100644
--- a/api/units/timestamp.cc
+++ b/api/units/timestamp.cc
@@ -10,14 +10,17 @@
#include "api/units/timestamp.h"
+#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
std::string ToString(Timestamp value) {
char buf[64];
rtc::SimpleStringBuilder sb(buf);
- if (value.IsInfinite()) {
- sb << "inf ms";
+ if (value.IsPlusInfinity()) {
+ sb << "+inf ms";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf ms";
} else {
if (value.ms() % 1000 == 0)
sb << value.seconds() << " s";
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
index a6e450f..370a091 100644
--- a/api/units/timestamp.h
+++ b/api/units/timestamp.h
@@ -45,14 +45,17 @@
template <typename T>
static Timestamp seconds(T seconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromFraction<1000000>(seconds);
}
template <typename T>
static Timestamp ms(T milliseconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromFraction<1000>(milliseconds);
}
template <typename T>
static Timestamp us(T microseconds) {
+ static_assert(std::is_arithmetic<T>::value, "");
return FromValue(microseconds);
}
template <typename T = int64_t>
diff --git a/api/video/builtin_video_bitrate_allocator_factory.cc b/api/video/builtin_video_bitrate_allocator_factory.cc
index 70f6ad0..b01e5c2 100644
--- a/api/video/builtin_video_bitrate_allocator_factory.cc
+++ b/api/video/builtin_video_bitrate_allocator_factory.cc
@@ -11,7 +11,9 @@
#include "api/video/builtin_video_bitrate_allocator_factory.h"
#include "absl/memory/memory.h"
-#include "media/base/codec.h"
+#include "api/video/video_bitrate_allocator.h"
+#include "api/video_codecs/video_codec.h"
+#include "common_types.h" // NOLINT(build/include)
#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
diff --git a/api/video/color_space.cc b/api/video/color_space.cc
index ad138ab..710bb43 100644
--- a/api/video/color_space.cc
+++ b/api/video/color_space.cc
@@ -10,6 +10,7 @@
#include "api/video/color_space.h"
+namespace webrtc {
namespace {
// Try to convert |enum_value| into the enum class T. |enum_bitmask| is created
// by the funciton below. Returns true if conversion was successful, false
@@ -50,9 +51,17 @@
return MakeMask(0, N, values);
}
-} // namespace
+bool SetChromaSitingFromUint8(uint8_t enum_value,
+ ColorSpace::ChromaSiting* chroma_siting) {
+ constexpr ColorSpace::ChromaSiting kChromaSitings[] = {
+ ColorSpace::ChromaSiting::kUnspecified,
+ ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings);
-namespace webrtc {
+ return SetFromUint8(enum_value, enum_bitmask, chroma_siting);
+}
+
+} // namespace
ColorSpace::ColorSpace() = default;
ColorSpace::ColorSpace(const ColorSpace& other) = default;
@@ -63,17 +72,27 @@
TransferID transfer,
MatrixID matrix,
RangeID range)
- : ColorSpace(primaries, transfer, matrix, range, nullptr) {}
+ : ColorSpace(primaries,
+ transfer,
+ matrix,
+ range,
+ ChromaSiting::kUnspecified,
+ ChromaSiting::kUnspecified,
+ nullptr) {}
ColorSpace::ColorSpace(PrimaryID primaries,
TransferID transfer,
MatrixID matrix,
RangeID range,
+ ChromaSiting chroma_siting_horz,
+ ChromaSiting chroma_siting_vert,
const HdrMetadata* hdr_metadata)
: primaries_(primaries),
transfer_(transfer),
matrix_(matrix),
range_(range),
+ chroma_siting_horizontal_(chroma_siting_horz),
+ chroma_siting_vertical_(chroma_siting_vert),
hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata)
: absl::nullopt) {}
@@ -93,17 +112,24 @@
return range_;
}
+ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const {
+ return chroma_siting_horizontal_;
+}
+
+ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const {
+ return chroma_siting_vertical_;
+}
+
const HdrMetadata* ColorSpace::hdr_metadata() const {
return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
}
bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
constexpr PrimaryID kPrimaryIds[] = {
- PrimaryID::kInvalid, PrimaryID::kBT709, PrimaryID::kUNSPECIFIED,
- PrimaryID::kBT470M, PrimaryID::kBT470BG, PrimaryID::kSMPTE170M,
- PrimaryID::kSMPTE240M, PrimaryID::kFILM, PrimaryID::kBT2020,
- PrimaryID::kSMPTEST428, PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432,
- PrimaryID::kJEDECP22};
+ PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M,
+ PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, PrimaryID::kSMPTE240M,
+ PrimaryID::kFILM, PrimaryID::kBT2020, PrimaryID::kSMPTEST428,
+ PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, PrimaryID::kJEDECP22};
constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds);
return SetFromUint8(enum_value, enum_bitmask, &primaries_);
@@ -111,15 +137,15 @@
bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
constexpr TransferID kTransferIds[] = {
- TransferID::kInvalid, TransferID::kBT709,
- TransferID::kUNSPECIFIED, TransferID::kGAMMA22,
- TransferID::kGAMMA28, TransferID::kSMPTE170M,
- TransferID::kSMPTE240M, TransferID::kLINEAR,
- TransferID::kLOG, TransferID::kLOG_SQRT,
- TransferID::kIEC61966_2_4, TransferID::kBT1361_ECG,
- TransferID::kIEC61966_2_1, TransferID::kBT2020_10,
- TransferID::kBT2020_12, TransferID::kSMPTEST2084,
- TransferID::kSMPTEST428, TransferID::kARIB_STD_B67};
+ TransferID::kBT709, TransferID::kUnspecified,
+ TransferID::kGAMMA22, TransferID::kGAMMA28,
+ TransferID::kSMPTE170M, TransferID::kSMPTE240M,
+ TransferID::kLINEAR, TransferID::kLOG,
+ TransferID::kLOG_SQRT, TransferID::kIEC61966_2_4,
+ TransferID::kBT1361_ECG, TransferID::kIEC61966_2_1,
+ TransferID::kBT2020_10, TransferID::kBT2020_12,
+ TransferID::kSMPTEST2084, TransferID::kSMPTEST428,
+ TransferID::kARIB_STD_B67};
constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds);
return SetFromUint8(enum_value, enum_bitmask, &transfer_);
@@ -127,11 +153,11 @@
bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) {
constexpr MatrixID kMatrixIds[] = {
- MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUNSPECIFIED,
- MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M,
- MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL,
- MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS,
- MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP, MatrixID::kInvalid};
+ MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUnspecified,
+ MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M,
+ MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL,
+ MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS,
+ MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP};
constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds);
return SetFromUint8(enum_value, enum_bitmask, &matrix_);
@@ -145,6 +171,14 @@
return SetFromUint8(enum_value, enum_bitmask, &range_);
}
+bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) {
+ return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_);
+}
+
+bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) {
+ return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_);
+}
+
void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) {
hdr_metadata_ =
hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt;
diff --git a/api/video/color_space.h b/api/video/color_space.h
index 79a15f5..91b4e17 100644
--- a/api/video/color_space.h
+++ b/api/video/color_space.h
@@ -35,9 +35,8 @@
public:
enum class PrimaryID : uint8_t {
// The indices are equal to the values specified in T-REC H.273 Table 2.
- kInvalid = 0,
kBT709 = 1,
- kUNSPECIFIED = 2,
+ kUnspecified = 2,
kBT470M = 4,
kBT470BG = 5,
kSMPTE170M = 6, // Identical to BT601
@@ -54,9 +53,8 @@
enum class TransferID : uint8_t {
// The indices are equal to the values specified in T-REC H.273 Table 3.
- kInvalid = 0,
kBT709 = 1,
- kUNSPECIFIED = 2,
+ kUnspecified = 2,
kGAMMA22 = 4,
kGAMMA28 = 5,
kSMPTE170M = 6,
@@ -80,7 +78,7 @@
// The indices are equal to the values specified in T-REC H.273 Table 4.
kRGB = 0,
kBT709 = 1,
- kUNSPECIFIED = 2,
+ kUnspecified = 2,
kFCC = 4,
kBT470BG = 5,
kSMPTE170M = 6,
@@ -92,7 +90,6 @@
kCDNCLS = 12,
kCDCLS = 13,
kBT2100_ICTCP = 14,
- kInvalid = 63,
// When adding/removing entries here, please make sure to do the
// corresponding change to kMatrixIds.
};
@@ -111,6 +108,19 @@
// corresponding change to kRangeIds.
};
+ enum class ChromaSiting {
+ // Chroma siting specifies how chroma is subsampled relative to the luma
+ // samples in a YUV video frame.
+ // The indices are equal to the values specified at
+ // https://www.webmproject.org/docs/container/#colour for the element
+ // ChromaSitingVert and ChromaSitingHorz.
+ kUnspecified = 0,
+ kCollocated = 1,
+ kHalf = 2,
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kChromaSitings.
+ };
+
ColorSpace();
ColorSpace(const ColorSpace& other);
ColorSpace(ColorSpace&& other);
@@ -118,40 +128,50 @@
ColorSpace(PrimaryID primaries,
TransferID transfer,
MatrixID matrix,
- RangeID full_range);
+ RangeID range);
ColorSpace(PrimaryID primaries,
TransferID transfer,
MatrixID matrix,
RangeID range,
+ ChromaSiting chroma_siting_horizontal,
+ ChromaSiting chroma_siting_vertical,
const HdrMetadata* hdr_metadata);
- bool operator==(const ColorSpace& other) const {
- return primaries_ == other.primaries() && transfer_ == other.transfer() &&
- matrix_ == other.matrix() && range_ == other.range() &&
- ((hdr_metadata_.has_value() && other.hdr_metadata() &&
- *hdr_metadata_ == *other.hdr_metadata()) ||
- (!hdr_metadata_.has_value() && other.hdr_metadata() == nullptr));
+ friend bool operator==(const ColorSpace& lhs, const ColorSpace& rhs) {
+ return lhs.primaries_ == rhs.primaries_ && lhs.transfer_ == rhs.transfer_ &&
+ lhs.matrix_ == rhs.matrix_ && lhs.range_ == rhs.range_ &&
+ lhs.chroma_siting_horizontal_ == rhs.chroma_siting_horizontal_ &&
+ lhs.chroma_siting_vertical_ == rhs.chroma_siting_vertical_ &&
+ lhs.hdr_metadata_ == rhs.hdr_metadata_;
+ }
+ friend bool operator!=(const ColorSpace& lhs, const ColorSpace& rhs) {
+ return !(lhs == rhs);
}
PrimaryID primaries() const;
TransferID transfer() const;
MatrixID matrix() const;
RangeID range() const;
+ ChromaSiting chroma_siting_horizontal() const;
+ ChromaSiting chroma_siting_vertical() const;
const HdrMetadata* hdr_metadata() const;
bool set_primaries_from_uint8(uint8_t enum_value);
bool set_transfer_from_uint8(uint8_t enum_value);
bool set_matrix_from_uint8(uint8_t enum_value);
bool set_range_from_uint8(uint8_t enum_value);
+ bool set_chroma_siting_horizontal_from_uint8(uint8_t enum_value);
+ bool set_chroma_siting_vertical_from_uint8(uint8_t enum_value);
void set_hdr_metadata(const HdrMetadata* hdr_metadata);
private:
- PrimaryID primaries_ = PrimaryID::kInvalid;
- TransferID transfer_ = TransferID::kInvalid;
- MatrixID matrix_ = MatrixID::kInvalid;
+ PrimaryID primaries_ = PrimaryID::kUnspecified;
+ TransferID transfer_ = TransferID::kUnspecified;
+ MatrixID matrix_ = MatrixID::kUnspecified;
RangeID range_ = RangeID::kInvalid;
+ ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified;
+ ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified;
absl::optional<HdrMetadata> hdr_metadata_;
};
} // namespace webrtc
-
#endif // API_VIDEO_COLOR_SPACE_H_
diff --git a/api/video/encoded_frame.h b/api/video/encoded_frame.h
index b8462c6..fa06568 100644
--- a/api/video/encoded_frame.h
+++ b/api/video/encoded_frame.h
@@ -13,6 +13,9 @@
#include "modules/video_coding/encoded_frame.h"
+#include <stddef.h>
+#include <stdint.h>
+
namespace webrtc {
namespace video_coding {
@@ -56,8 +59,6 @@
EncodedFrame() = default;
virtual ~EncodedFrame() {}
- virtual bool GetBitstream(uint8_t* destination) const = 0;
-
// When this frame was received.
virtual int64_t ReceivedTime() const = 0;
@@ -69,8 +70,6 @@
// been implemented.
virtual bool delayed_by_retransmission() const;
- size_t size() const { return _length; }
-
bool is_keyframe() const { return num_references == 0; }
VideoLayerFrameId id;
@@ -80,6 +79,9 @@
size_t num_references = 0;
int64_t references[kMaxFrameReferences];
bool inter_layer_predicted = false;
+ // Is this subframe the last one in the superframe (In RTP stream that would
+ // mean that the last packet has a marker bit set).
+ bool is_last_spatial_layer = true;
};
} // namespace video_coding
diff --git a/api/video/encoded_image.cc b/api/video/encoded_image.cc
index e7c6fad..d1fa046 100644
--- a/api/video/encoded_image.cc
+++ b/api/video/encoded_image.cc
@@ -29,10 +29,23 @@
EncodedImage::EncodedImage() : EncodedImage(nullptr, 0, 0) {}
+EncodedImage::EncodedImage(EncodedImage&&) = default;
EncodedImage::EncodedImage(const EncodedImage&) = default;
-EncodedImage::EncodedImage(uint8_t* buffer, size_t length, size_t size)
- : _buffer(buffer), _length(length), _size(size) {}
+EncodedImage::EncodedImage(uint8_t* buffer, size_t size, size_t capacity)
+ : size_(size), buffer_(buffer), capacity_(capacity) {}
+
+EncodedImage::~EncodedImage() = default;
+
+EncodedImage& EncodedImage::operator=(EncodedImage&&) = default;
+EncodedImage& EncodedImage::operator=(const EncodedImage&) = default;
+
+void EncodedImage::Retain() {
+ if (buffer_) {
+ encoded_data_.SetData(buffer_, size_);
+ buffer_ = nullptr;
+ }
+}
void EncodedImage::SetEncodeTime(int64_t encode_start_ms,
int64_t encode_finish_ms) {
diff --git a/api/video/encoded_image.h b/api/video/encoded_image.h
index a7c719c..1d3bd46 100644
--- a/api/video/encoded_image.h
+++ b/api/video/encoded_image.h
@@ -15,13 +15,14 @@
#include "absl/types/optional.h"
#include "api/video/color_space.h"
-#include "api/video/video_bitrate_allocation.h"
+#include "api/video/video_codec_constants.h"
#include "api/video/video_codec_type.h"
#include "api/video/video_content_type.h"
#include "api/video/video_rotation.h"
#include "api/video/video_timing.h"
#include "common_types.h" // NOLINT(build/include)
#include "rtc_base/checks.h"
+#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@@ -37,8 +38,16 @@
static size_t GetBufferPaddingBytes(VideoCodecType codec_type);
EncodedImage();
+ EncodedImage(EncodedImage&&);
+ // Discouraged: potentially expensive.
EncodedImage(const EncodedImage&);
- EncodedImage(uint8_t* buffer, size_t length, size_t size);
+ EncodedImage(uint8_t* buffer, size_t length, size_t capacity);
+
+ ~EncodedImage();
+
+ EncodedImage& operator=(EncodedImage&&);
+ // Discouraged: potentially expensive.
+ EncodedImage& operator=(const EncodedImage&);
// TODO(nisse): Change style to timestamp(), set_timestamp(), for consistency
// with the VideoFrame class.
@@ -62,20 +71,51 @@
const webrtc::ColorSpace* ColorSpace() const {
return color_space_ ? &*color_space_ : nullptr;
}
- void SetColorSpace(const webrtc::ColorSpace* color_space) {
- color_space_ =
- color_space ? absl::make_optional(*color_space) : absl::nullopt;
+ void SetColorSpace(const absl::optional<webrtc::ColorSpace>& color_space) {
+ color_space_ = color_space;
}
+ size_t size() const { return size_; }
+ void set_size(size_t new_size) {
+ RTC_DCHECK_LE(new_size, capacity());
+ size_ = new_size;
+ }
+ size_t capacity() const { return buffer_ ? capacity_ : encoded_data_.size(); }
+
+ void set_buffer(uint8_t* buffer, size_t capacity) {
+ buffer_ = buffer;
+ capacity_ = capacity;
+ }
+
+ void Allocate(size_t capacity) {
+ encoded_data_.SetSize(capacity);
+ buffer_ = nullptr;
+ }
+
+ uint8_t* data() { return buffer_ ? buffer_ : encoded_data_.data(); }
+ const uint8_t* data() const {
+ return buffer_ ? buffer_ : encoded_data_.cdata();
+ }
+ // TODO(nisse): At some places, code accepts a const ref EncodedImage, but
+ // still writes to it, to clear padding at the end of the encoded data.
+ // Padding is required by ffmpeg; the best way to deal with that is likely to
+ // make this class ensure that buffers always have a few zero padding bytes.
+ uint8_t* mutable_data() const { return const_cast<uint8_t*>(data()); }
+
+ // TODO(bugs.webrtc.org/9378): Delete. Used by code that wants to modify a
+ // buffer corresponding to a const EncodedImage. Requires an un-owned buffer.
+ uint8_t* buffer() const { return buffer_; }
+
+ // Hack to workaround lack of ownership of the encoded data. If we don't
+ // already own the underlying data, make an owned copy.
+ void Retain();
+
uint32_t _encodedWidth = 0;
uint32_t _encodedHeight = 0;
// NTP time of the capture time in local timebase in milliseconds.
int64_t ntp_time_ms_ = 0;
int64_t capture_time_ms_ = 0;
FrameType _frameType = kVideoFrameDelta;
- uint8_t* _buffer;
- size_t _length;
- size_t _size;
VideoRotation rotation_ = kVideoRotation_0;
VideoContentType content_type_ = VideoContentType::UNSPECIFIED;
bool _completeFrame = false;
@@ -99,6 +139,14 @@
} timing_;
private:
+ // TODO(bugs.webrtc.org/9378): We're transitioning to always owning the
+ // encoded data.
+ rtc::CopyOnWriteBuffer encoded_data_;
+ size_t size_; // Size of encoded frame data.
+ // Non-null when used with an un-owned buffer.
+ uint8_t* buffer_;
+ // Allocated size of _buffer; relevant only if it's non-null.
+ size_t capacity_;
uint32_t timestamp_rtp_ = 0;
absl::optional<int> spatial_index_;
absl::optional<webrtc::ColorSpace> color_space_;
diff --git a/api/video/hdr_metadata.h b/api/video/hdr_metadata.h
index 676a900..e9001a2 100644
--- a/api/video/hdr_metadata.h
+++ b/api/video/hdr_metadata.h
@@ -11,27 +11,47 @@
#ifndef API_VIDEO_HDR_METADATA_H_
#define API_VIDEO_HDR_METADATA_H_
-#include <stdint.h>
-
namespace webrtc {
// SMPTE ST 2086 mastering metadata,
// see https://ieeexplore.ieee.org/document/8353899.
struct HdrMasteringMetadata {
struct Chromaticity {
- // xy chromaticity coordinates must be calculated as specified in ISO
- // 11664-3:2012 Section 7, and must be specified with four decimal places.
- // The x coordinate must be in the range [0.0001, 0.7400] and the y
- // coordinate must be in the range [0.0001, 0.8400].
- float x = 0.0f;
- float y = 0.0f;
+ Chromaticity();
+
bool operator==(const Chromaticity& rhs) const {
return x == rhs.x && y == rhs.y;
}
- Chromaticity();
+ bool Validate() const {
+ return x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0;
+ }
+
+ // xy chromaticity coordinates must be calculated as specified in ISO
+ // 11664-3:2012 Section 7, and must be specified with four decimal places.
+ // The x coordinate should be in the range [0.0001, 0.7400] and the y
+ // coordinate should be in the range [0.0001, 0.8400]. Valid range [0.0000,
+ // 1.0000].
+ float x = 0.0f;
+ float y = 0.0f;
};
+ HdrMasteringMetadata();
+
+ bool operator==(const HdrMasteringMetadata& rhs) const {
+ return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) &&
+ (primary_b == rhs.primary_b) && (white_point == rhs.white_point) &&
+ (luminance_max == rhs.luminance_max) &&
+ (luminance_min == rhs.luminance_min));
+ }
+
+ bool Validate() const {
+ return luminance_max >= 0.0 && luminance_max <= 20000.0 &&
+ luminance_min >= 0.0 && luminance_min <= 5.0 &&
+ primary_r.Validate() && primary_g.Validate() &&
+ primary_b.Validate() && white_point.Validate();
+ }
+
// The nominal primaries of the mastering display.
Chromaticity primary_r;
Chromaticity primary_g;
@@ -41,37 +61,20 @@
Chromaticity white_point;
// The nominal maximum display luminance of the mastering display. Specified
- // in the unit candela/m2. The value must be in the range [5, 10000] with zero
- // decimal places.
+ // in the unit candela/m2. The value should be in the range [5, 10000] with
+ // zero decimal places. Valid range [0, 20000].
float luminance_max = 0.0f;
// The nominal minimum display luminance of the mastering display. Specified
- // in the unit candela/m2. The value must be in the range [0.0001, 5.0000]
- // with four decimal places.
+ // in the unit candela/m2. The value should be in the range [0.0001, 5.0000]
+ // with four decimal places. Valid range [0.0000, 5.0000].
float luminance_min = 0.0f;
-
- HdrMasteringMetadata();
-
- bool operator==(const HdrMasteringMetadata& rhs) const {
- return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) &&
- (primary_b == rhs.primary_b) && (white_point == rhs.white_point) &&
- (luminance_max == rhs.luminance_max) &&
- (luminance_min == rhs.luminance_min));
- }
};
// High dynamic range (HDR) metadata common for HDR10 and WebM/VP9-based HDR
// formats. This struct replicates the HDRMetadata struct defined in
// https://cs.chromium.org/chromium/src/media/base/hdr_metadata.h
struct HdrMetadata {
- HdrMasteringMetadata mastering_metadata;
- // Max content light level (CLL), i.e. maximum brightness level present in the
- // stream, in nits. 1 nit = 1 candela/m2.
- uint32_t max_content_light_level = 0;
- // Max frame-average light level (FALL), i.e. maximum average brightness of
- // the brightest frame in the stream, in nits.
- uint32_t max_frame_average_light_level = 0;
-
HdrMetadata();
bool operator==(const HdrMetadata& rhs) const {
@@ -80,6 +83,21 @@
(max_frame_average_light_level == rhs.max_frame_average_light_level) &&
(mastering_metadata == rhs.mastering_metadata));
}
+
+ bool Validate() const {
+ return max_content_light_level >= 0 && max_content_light_level <= 20000 &&
+ max_frame_average_light_level >= 0 &&
+ max_frame_average_light_level <= 20000 &&
+ mastering_metadata.Validate();
+ }
+
+ HdrMasteringMetadata mastering_metadata;
+ // Max content light level (CLL), i.e. maximum brightness level present in the
+ // stream, in nits. 1 nit = 1 candela/m2. Valid range [0, 20000].
+ int max_content_light_level = 0;
+ // Max frame-average light level (FALL), i.e. maximum average brightness of
+ // the brightest frame in the stream, in nits. Valid range [0, 20000].
+ int max_frame_average_light_level = 0;
};
} // namespace webrtc
diff --git a/api/video/i010_buffer.cc b/api/video/i010_buffer.cc
index adb5a5e..7286676 100644
--- a/api/video/i010_buffer.cc
+++ b/api/video/i010_buffer.cc
@@ -9,14 +9,12 @@
*/
#include "api/video/i010_buffer.h"
-#include <algorithm>
#include <utility>
#include "api/video/i420_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "third_party/libyuv/include/libyuv/convert.h"
-#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/libyuv/include/libyuv/scale.h"
// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
@@ -234,4 +232,35 @@
CropAndScaleFrom(src, 0, 0, src.width(), src.height());
}
+void I010Buffer::PasteFrom(const I010BufferInterface& picture,
+ int offset_col,
+ int offset_row) {
+ RTC_CHECK_LE(picture.width() + offset_col, width());
+ RTC_CHECK_LE(picture.height() + offset_row, height());
+ RTC_CHECK_GE(offset_col, 0);
+ RTC_CHECK_GE(offset_row, 0);
+
+ // Pasted picture has to be aligned so subsumpled UV plane isn't corrupted.
+ RTC_CHECK(offset_col % 2 == 0);
+ RTC_CHECK(offset_row % 2 == 0);
+ RTC_CHECK(picture.width() % 2 == 0 ||
+ picture.width() + offset_col == width());
+ RTC_CHECK(picture.height() % 2 == 0 ||
+ picture.height() + offset_row == height());
+
+ libyuv::CopyPlane_16(picture.DataY(), picture.StrideY(),
+ MutableDataY() + StrideY() * offset_row + offset_col,
+ StrideY(), picture.width(), picture.height());
+
+ libyuv::CopyPlane_16(
+ picture.DataU(), picture.StrideU(),
+ MutableDataU() + StrideU() * offset_row / 2 + offset_col / 2, StrideU(),
+ picture.width() / 2, picture.height() / 2);
+
+ libyuv::CopyPlane_16(
+ picture.DataV(), picture.StrideV(),
+ MutableDataV() + StrideV() * offset_row / 2 + offset_col / 2, StrideV(),
+ picture.width() / 2, picture.height() / 2);
+}
+
} // namespace webrtc
diff --git a/api/video/i010_buffer.h b/api/video/i010_buffer.h
index 1208b31..4b35ca3 100644
--- a/api/video/i010_buffer.h
+++ b/api/video/i010_buffer.h
@@ -11,8 +11,10 @@
#ifndef API_VIDEO_I010_BUFFER_H_
#define API_VIDEO_I010_BUFFER_H_
+#include <stdint.h>
#include <memory>
+#include "api/scoped_refptr.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "rtc_base/memory/aligned_malloc.h"
@@ -63,6 +65,12 @@
// Scale all of |src| to the size of |this| buffer, with no cropping.
void ScaleFrom(const I010BufferInterface& src);
+ // Pastes whole picture to canvas at (offset_row, offset_col).
+ // Offsets and picture dimensions must be even.
+ void PasteFrom(const I010BufferInterface& picture,
+ int offset_col,
+ int offset_row);
+
protected:
I010Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
~I010Buffer() override;
diff --git a/api/video/i420_buffer.cc b/api/video/i420_buffer.cc
index 8d239f3..46de581 100644
--- a/api/video/i420_buffer.cc
+++ b/api/video/i420_buffer.cc
@@ -10,12 +10,11 @@
#include "api/video/i420_buffer.h"
#include <string.h>
-
#include <algorithm>
#include <utility>
#include "rtc_base/checks.h"
-#include "rtc_base/keep_ref_until_done.h"
+#include "rtc_base/ref_counted_object.h"
#include "third_party/libyuv/include/libyuv/convert.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/libyuv/include/libyuv/scale.h"
@@ -227,4 +226,35 @@
CropAndScaleFrom(src, 0, 0, src.width(), src.height());
}
+void I420Buffer::PasteFrom(const I420BufferInterface& picture,
+ int offset_col,
+ int offset_row) {
+ RTC_CHECK_LE(picture.width() + offset_col, width());
+ RTC_CHECK_LE(picture.height() + offset_row, height());
+ RTC_CHECK_GE(offset_col, 0);
+ RTC_CHECK_GE(offset_row, 0);
+
+ // Pasted picture has to be aligned so subsumpled UV plane isn't corrupted.
+ RTC_CHECK(offset_col % 2 == 0);
+ RTC_CHECK(offset_row % 2 == 0);
+ RTC_CHECK(picture.width() % 2 == 0 ||
+ picture.width() + offset_col == width());
+ RTC_CHECK(picture.height() % 2 == 0 ||
+ picture.height() + offset_row == height());
+
+ libyuv::CopyPlane(picture.DataY(), picture.StrideY(),
+ MutableDataY() + StrideY() * offset_row + offset_col,
+ StrideY(), picture.width(), picture.height());
+
+ libyuv::CopyPlane(
+ picture.DataU(), picture.StrideU(),
+ MutableDataU() + StrideU() * offset_row / 2 + offset_col / 2, StrideU(),
+ picture.width() / 2, picture.height() / 2);
+
+ libyuv::CopyPlane(
+ picture.DataV(), picture.StrideV(),
+ MutableDataV() + StrideV() * offset_row / 2 + offset_col / 2, StrideV(),
+ picture.width() / 2, picture.height() / 2);
+}
+
} // namespace webrtc
diff --git a/api/video/i420_buffer.h b/api/video/i420_buffer.h
index 631e394..b76a507 100644
--- a/api/video/i420_buffer.h
+++ b/api/video/i420_buffer.h
@@ -14,10 +14,10 @@
#include <stdint.h>
#include <memory>
+#include "api/scoped_refptr.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "rtc_base/memory/aligned_malloc.h"
-#include "rtc_base/scoped_ref_ptr.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@@ -97,6 +97,12 @@
// Scale all of |src| to the size of |this| buffer, with no cropping.
void ScaleFrom(const I420BufferInterface& src);
+ // Pastes whole picture to canvas at (offset_row, offset_col).
+ // Offsets and picture dimensions must be even.
+ void PasteFrom(const I420BufferInterface& picture,
+ int offset_col,
+ int offset_row);
+
protected:
I420Buffer(int width, int height);
I420Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
diff --git a/api/video/video_bitrate_allocation.h b/api/video/video_bitrate_allocation.h
index d1771b4..ef64226 100644
--- a/api/video/video_bitrate_allocation.h
+++ b/api/video/video_bitrate_allocation.h
@@ -18,14 +18,10 @@
#include <vector>
#include "absl/types/optional.h"
+#include "api/video/video_codec_constants.h"
namespace webrtc {
-// TODO(sprang): Move back to common_types when include of this is removed.
-enum : int { kMaxSimulcastStreams = 4 };
-enum : int { kMaxSpatialLayers = 5 };
-enum : int { kMaxTemporalStreams = 4 };
-
// Class that describes how video bitrate, in bps, is allocated across temporal
// and spatial layers. Not that bitrates are NOT cumulative. Depending on if
// layers are dependent or not, it is up to the user to aggregate.
diff --git a/api/video/video_codec_constants.h b/api/video/video_codec_constants.h
new file mode 100644
index 0000000..a3f7cd2
--- /dev/null
+++ b/api/video/video_codec_constants.h
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+#ifndef API_VIDEO_VIDEO_CODEC_CONSTANTS_H_
+#define API_VIDEO_VIDEO_CODEC_CONSTANTS_H_
+
+namespace webrtc {
+
+enum : int { kMaxSimulcastStreams = 4 };
+enum : int { kMaxSpatialLayers = 5 };
+enum : int { kMaxTemporalStreams = 4 };
+
+} // namespace webrtc
+
+#endif // API_VIDEO_VIDEO_CODEC_CONSTANTS_H_
diff --git a/api/video/video_codec_type.h b/api/video/video_codec_type.h
index 447723c..2e406c0 100644
--- a/api/video/video_codec_type.h
+++ b/api/video/video_codec_type.h
@@ -21,7 +21,6 @@
kVideoCodecVP8,
kVideoCodecVP9,
kVideoCodecH264,
- kVideoCodecI420,
kVideoCodecMultiplex,
};
diff --git a/api/video/video_frame.cc b/api/video/video_frame.cc
index eaae33b..7a71f43 100644
--- a/api/video/video_frame.cc
+++ b/api/video/video_frame.cc
@@ -10,18 +10,63 @@
#include "api/video/video_frame.h"
+#include <algorithm>
+
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
+void VideoFrame::UpdateRect::Union(const UpdateRect& other) {
+ if (other.IsEmpty())
+ return;
+ if (IsEmpty()) {
+ *this = other;
+ return;
+ }
+ int right = std::max(offset_x + width, other.offset_x + other.width);
+ int bottom = std::max(offset_y + height, other.offset_y + other.height);
+ offset_x = std::min(offset_x, other.offset_x);
+ offset_y = std::min(offset_y, other.offset_y);
+ width = right - offset_x;
+ height = bottom - offset_y;
+ RTC_DCHECK_GT(width, 0);
+ RTC_DCHECK_GT(height, 0);
+}
+
+void VideoFrame::UpdateRect::Intersect(const UpdateRect& other) {
+ if (other.IsEmpty() || IsEmpty()) {
+ MakeEmptyUpdate();
+ return;
+ }
+
+ int right = std::min(offset_x + width, other.offset_x + other.width);
+ int bottom = std::min(offset_y + height, other.offset_y + other.height);
+ offset_x = std::max(offset_x, other.offset_x);
+ offset_y = std::max(offset_y, other.offset_y);
+ width = right - offset_x;
+ height = bottom - offset_y;
+ if (width <= 0 || height <= 0) {
+ MakeEmptyUpdate();
+ }
+}
+
+void VideoFrame::UpdateRect::MakeEmptyUpdate() {
+ width = height = offset_x = offset_y = 0;
+}
+
+bool VideoFrame::UpdateRect::IsEmpty() const {
+ return width == 0 && height == 0;
+}
+
VideoFrame::Builder::Builder() = default;
VideoFrame::Builder::~Builder() = default;
VideoFrame VideoFrame::Builder::build() {
- return VideoFrame(video_frame_buffer_, timestamp_us_, timestamp_rtp_,
- ntp_time_ms_, rotation_, color_space_);
+ RTC_CHECK(video_frame_buffer_ != nullptr);
+ return VideoFrame(id_, video_frame_buffer_, timestamp_us_, timestamp_rtp_,
+ ntp_time_ms_, rotation_, color_space_, update_rect_);
}
VideoFrame::Builder& VideoFrame::Builder::set_video_frame_buffer(
@@ -59,7 +104,7 @@
}
VideoFrame::Builder& VideoFrame::Builder::set_color_space(
- const ColorSpace& color_space) {
+ const absl::optional<ColorSpace>& color_space) {
color_space_ = color_space;
return *this;
}
@@ -71,6 +116,17 @@
return *this;
}
+VideoFrame::Builder& VideoFrame::Builder::set_id(uint16_t id) {
+ id_ = id;
+ return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_update_rect(
+ const VideoFrame::UpdateRect& update_rect) {
+ update_rect_ = update_rect;
+ return *this;
+}
+
VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
webrtc::VideoRotation rotation,
int64_t timestamp_us)
@@ -78,7 +134,8 @@
timestamp_rtp_(0),
ntp_time_ms_(0),
timestamp_us_(timestamp_us),
- rotation_(rotation) {}
+ rotation_(rotation),
+ update_rect_{0, 0, buffer->width(), buffer->height()} {}
VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
uint32_t timestamp_rtp,
@@ -88,22 +145,33 @@
timestamp_rtp_(timestamp_rtp),
ntp_time_ms_(0),
timestamp_us_(render_time_ms * rtc::kNumMicrosecsPerMillisec),
- rotation_(rotation) {
+ rotation_(rotation),
+ update_rect_{0, 0, buffer->width(), buffer->height()} {
RTC_DCHECK(buffer);
}
-VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
+VideoFrame::VideoFrame(uint16_t id,
+ const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
int64_t timestamp_us,
uint32_t timestamp_rtp,
int64_t ntp_time_ms,
VideoRotation rotation,
- const absl::optional<ColorSpace>& color_space)
- : video_frame_buffer_(buffer),
+ const absl::optional<ColorSpace>& color_space,
+ const absl::optional<UpdateRect>& update_rect)
+ : id_(id),
+ video_frame_buffer_(buffer),
timestamp_rtp_(timestamp_rtp),
ntp_time_ms_(ntp_time_ms),
timestamp_us_(timestamp_us),
rotation_(rotation),
- color_space_(color_space) {}
+ color_space_(color_space),
+ update_rect_(update_rect.value_or(UpdateRect{
+ 0, 0, video_frame_buffer_->width(), video_frame_buffer_->height()})) {
+ RTC_DCHECK_GE(update_rect_.offset_x, 0);
+ RTC_DCHECK_GE(update_rect_.offset_y, 0);
+ RTC_DCHECK_LE(update_rect_.offset_x + update_rect_.width, width());
+ RTC_DCHECK_LE(update_rect_.offset_y + update_rect_.height, height());
+}
VideoFrame::~VideoFrame() = default;
diff --git a/api/video/video_frame.h b/api/video/video_frame.h
index 2c5d081..c7dd02a 100644
--- a/api/video/video_frame.h
+++ b/api/video/video_frame.h
@@ -14,17 +14,36 @@
#include <stdint.h>
#include "absl/types/optional.h"
+#include "api/scoped_refptr.h"
#include "api/video/color_space.h"
#include "api/video/hdr_metadata.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
class RTC_EXPORT VideoFrame {
public:
+ struct UpdateRect {
+ int offset_x;
+ int offset_y;
+ int width;
+ int height;
+
+ // Makes this UpdateRect a bounding box of this and other rect.
+ void Union(const UpdateRect& other);
+
+ // Makes this UpdateRect an intersection of this and other rect.
+ void Intersect(const UpdateRect& other);
+
+ // Sets everything to 0, making this UpdateRect a zero-size (empty) update.
+ void MakeEmptyUpdate();
+
+ bool IsEmpty() const;
+ };
+
// Preferred way of building VideoFrame objects.
class Builder {
public:
@@ -39,16 +58,20 @@
Builder& set_timestamp_rtp(uint32_t timestamp_rtp);
Builder& set_ntp_time_ms(int64_t ntp_time_ms);
Builder& set_rotation(VideoRotation rotation);
- Builder& set_color_space(const ColorSpace& color_space);
+ Builder& set_color_space(const absl::optional<ColorSpace>& color_space);
Builder& set_color_space(const ColorSpace* color_space);
+ Builder& set_id(uint16_t id);
+ Builder& set_update_rect(const UpdateRect& update_rect);
private:
+ uint16_t id_ = 0;
rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
int64_t timestamp_us_ = 0;
uint32_t timestamp_rtp_ = 0;
int64_t ntp_time_ms_ = 0;
VideoRotation rotation_ = kVideoRotation_0;
absl::optional<ColorSpace> color_space_;
+ absl::optional<UpdateRect> update_rect_;
};
// To be deprecated. Migrate all use to Builder.
@@ -75,6 +98,15 @@
// Get frame size in pixels.
uint32_t size() const;
+ // Get frame ID. Returns 0 if ID is not set. Not guarantee to be transferred
+ // from the sender to the receiver, but preserved on single side. The id
+ // should be propagated between all frame modifications during its lifetime
+ // from capturing to sending as encoded image. It is intended to be unique
+ // over a time window of a few minutes for peer connection, to which
+ // corresponding video stream belongs to.
+ uint16_t id() const { return id_; }
+ void set_id(uint16_t id) { id_ = id; }
+
// System monotonic clock, same timebase as rtc::TimeMicros().
int64_t timestamp_us() const { return timestamp_us_; }
void set_timestamp_us(int64_t timestamp_us) { timestamp_us_ = timestamp_us; }
@@ -115,8 +147,9 @@
void set_rotation(VideoRotation rotation) { rotation_ = rotation; }
// Get color space when available.
- const ColorSpace* color_space() const {
- return color_space_ ? &*color_space_ : nullptr;
+ const absl::optional<ColorSpace>& color_space() const { return color_space_; }
+ void set_color_space(const absl::optional<ColorSpace>& color_space) {
+ color_space_ = color_space;
}
// Get render time in milliseconds.
@@ -133,14 +166,29 @@
return video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative;
}
+ // Always initialized to whole frame update, can be set by Builder or manually
+ // by |set_update_rect|.
+ UpdateRect update_rect() const { return update_rect_; }
+ // Rectangle must be within the frame dimensions.
+ void set_update_rect(const VideoFrame::UpdateRect& update_rect) {
+ RTC_DCHECK_GE(update_rect.offset_x, 0);
+ RTC_DCHECK_GE(update_rect.offset_y, 0);
+ RTC_DCHECK_LE(update_rect.offset_x + update_rect.width, width());
+ RTC_DCHECK_LE(update_rect.offset_y + update_rect.height, height());
+ update_rect_ = update_rect;
+ }
+
private:
- VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
+ VideoFrame(uint16_t id,
+ const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
int64_t timestamp_us,
uint32_t timestamp_rtp,
int64_t ntp_time_ms,
VideoRotation rotation,
- const absl::optional<ColorSpace>& color_space);
+ const absl::optional<ColorSpace>& color_space,
+ const absl::optional<UpdateRect>& update_rect);
+ uint16_t id_;
// An opaque reference counted handle that stores the pixel data.
rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
uint32_t timestamp_rtp_;
@@ -148,6 +196,9 @@
int64_t timestamp_us_;
VideoRotation rotation_;
absl::optional<ColorSpace> color_space_;
+ // Updated since the last frame area. Unless set explicitly, will always be
+ // a full frame rectangle.
+ UpdateRect update_rect_;
};
} // namespace webrtc
diff --git a/api/video/video_frame_buffer.h b/api/video/video_frame_buffer.h
index 1e8169a..7fb603e 100644
--- a/api/video/video_frame_buffer.h
+++ b/api/video/video_frame_buffer.h
@@ -13,8 +13,8 @@
#include <stdint.h>
-#include "rtc_base/refcount.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
namespace webrtc {
diff --git a/api/video/video_source_interface.h b/api/video/video_source_interface.h
index 2bf7370..9d1641c 100644
--- a/api/video/video_source_interface.h
+++ b/api/video/video_source_interface.h
@@ -47,15 +47,13 @@
template <typename VideoFrameT>
class VideoSourceInterface {
public:
+ virtual ~VideoSourceInterface() = default;
+
virtual void AddOrUpdateSink(VideoSinkInterface<VideoFrameT>* sink,
const VideoSinkWants& wants) = 0;
// RemoveSink must guarantee that at the time the method returns,
// there is no current and no future calls to VideoSinkInterface::OnFrame.
virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0;
-
- protected:
- // Non-public, since one shouldn't own sources via this interface.
- virtual ~VideoSourceInterface() {}
};
} // namespace rtc
diff --git a/api/video/video_stream_encoder_create.cc b/api/video/video_stream_encoder_create.cc
index 3147d34..875edd9 100644
--- a/api/video/video_stream_encoder_create.cc
+++ b/api/video/video_stream_encoder_create.cc
@@ -11,17 +11,30 @@
#include "api/video/video_stream_encoder_create.h"
#include "absl/memory/memory.h"
+#include "api/task_queue/global_task_queue_factory.h"
+#include "video/overuse_frame_detector.h"
#include "video/video_stream_encoder.h"
namespace webrtc {
std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
- const VideoStreamEncoderSettings& settings,
- // Deprecated, used for tests only.
- rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback) {
- return absl::make_unique<VideoStreamEncoder>(
- number_of_cores, encoder_stats_observer, settings, pre_encode_callback,
- absl::make_unique<OveruseFrameDetector>(encoder_stats_observer));
+ const VideoStreamEncoderSettings& settings) {
+ return CreateVideoStreamEncoder(Clock::GetRealTimeClock(),
+ &GlobalTaskQueueFactory(), number_of_cores,
+ encoder_stats_observer, settings);
}
+
+std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
+ Clock* clock,
+ TaskQueueFactory* task_queue_factory,
+ uint32_t number_of_cores,
+ VideoStreamEncoderObserver* encoder_stats_observer,
+ const VideoStreamEncoderSettings& settings) {
+ return absl::make_unique<VideoStreamEncoder>(
+ clock, number_of_cores, encoder_stats_observer, settings,
+ absl::make_unique<OveruseFrameDetector>(encoder_stats_observer),
+ task_queue_factory);
+}
+
} // namespace webrtc
diff --git a/api/video/video_stream_encoder_create.h b/api/video/video_stream_encoder_create.h
index 9117273..4241626 100644
--- a/api/video/video_stream_encoder_create.h
+++ b/api/video/video_stream_encoder_create.h
@@ -11,31 +11,31 @@
#ifndef API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
#define API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
-#include <map>
+#include <stdint.h>
#include <memory>
-#include <utility>
+#include "api/task_queue/task_queue_factory.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_sink_interface.h"
#include "api/video/video_stream_encoder_interface.h"
#include "api/video/video_stream_encoder_observer.h"
#include "api/video/video_stream_encoder_settings.h"
namespace webrtc {
+// TODO(srte): Find a way to avoid this forward declaration.
+class Clock;
std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
- const VideoStreamEncoderSettings& settings,
- // Deprecated, used for tests only.
- rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback);
+ const VideoStreamEncoderSettings& settings);
-inline std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
+std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder(
+ Clock* clock,
+ TaskQueueFactory* task_queue_factory,
uint32_t number_of_cores,
VideoStreamEncoderObserver* encoder_stats_observer,
- const VideoStreamEncoderSettings& settings) {
- return CreateVideoStreamEncoder(number_of_cores, encoder_stats_observer,
- settings, nullptr);
-}
-
+ const VideoStreamEncoderSettings& settings);
} // namespace webrtc
#endif // API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
diff --git a/api/video/video_stream_encoder_interface.h b/api/video/video_stream_encoder_interface.h
index 2f95e58..7181143 100644
--- a/api/video/video_stream_encoder_interface.h
+++ b/api/video/video_stream_encoder_interface.h
@@ -13,7 +13,8 @@
#include <vector>
-#include "api/rtpparameters.h" // For DegradationPreference.
+#include "api/rtp_parameters.h" // For DegradationPreference.
+#include "api/video/video_bitrate_allocator.h"
#include "api/video/video_sink_interface.h"
#include "api/video/video_source_interface.h"
#include "api/video_codecs/video_encoder.h"
@@ -21,9 +22,6 @@
namespace webrtc {
-// TODO(nisse): Move full declaration to api/.
-class VideoBitrateAllocationObserver;
-
// This interface represents a class responsible for creating and driving the
// encoder(s) for a single video stream. It is also responsible for adaptation
// decisions related to video quality, requesting reduced frame rate or
@@ -44,6 +42,7 @@
public:
virtual void OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
+ VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps) = 0;
};
diff --git a/api/video/video_timing.cc b/api/video/video_timing.cc
index 40de011..df1bc48 100644
--- a/api/video/video_timing.cc
+++ b/api/video/video_timing.cc
@@ -10,10 +10,21 @@
#include "api/video/video_timing.h"
+#include "api/array_view.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
+uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
+ if (time_ms < base_ms) {
+ RTC_DLOG(LS_ERROR) << "Delta " << (time_ms - base_ms)
+ << "ms expected to be positive";
+ }
+ return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
+}
+
TimingFrameInfo::TimingFrameInfo()
: rtp_timestamp(0),
capture_time_ms(-1),
diff --git a/api/video/video_timing.h b/api/video/video_timing.h
index e787a45..745afbc 100644
--- a/api/video/video_timing.h
+++ b/api/video/video_timing.h
@@ -16,9 +16,6 @@
#include <limits>
#include <string>
-#include "rtc_base/checks.h"
-#include "rtc_base/numerics/safe_conversions.h"
-
namespace webrtc {
// Video timing timestamps in ms counted from capture_time_ms of a frame.
@@ -46,10 +43,7 @@
// Used to fill this data structure as per
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
// 16-bit deltas of timestamps from packet capture time.
- static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
- RTC_DCHECK_GE(time_ms, base_ms);
- return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
- }
+ static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
uint16_t encode_start_delta_ms;
uint16_t encode_finish_delta_ms;
diff --git a/api/video_track_source_proxy.h b/api/video_track_source_proxy.h
new file mode 100644
index 0000000..eb11bef
--- /dev/null
+++ b/api/video_track_source_proxy.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 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.
+ */
+
+#ifndef API_VIDEO_TRACK_SOURCE_PROXY_H_
+#define API_VIDEO_TRACK_SOURCE_PROXY_H_
+
+#include "api/media_stream_interface.h"
+#include "api/proxy.h"
+
+namespace webrtc {
+
+// Makes sure the real VideoTrackSourceInterface implementation is destroyed on
+// the signaling thread and marshals all method calls to the signaling thread.
+// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
+// are called on is an implementation detail.
+BEGIN_PROXY_MAP(VideoTrackSource)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(SourceState, state)
+PROXY_CONSTMETHOD0(bool, remote)
+PROXY_CONSTMETHOD0(bool, is_screencast)
+PROXY_CONSTMETHOD0(absl::optional<bool>, needs_denoising)
+PROXY_METHOD1(bool, GetStats, Stats*)
+PROXY_WORKER_METHOD2(void,
+ AddOrUpdateSink,
+ rtc::VideoSinkInterface<VideoFrame>*,
+ const rtc::VideoSinkWants&)
+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
+PROXY_WORKER_METHOD1(void, SetLatency, double)
+PROXY_WORKER_CONSTMETHOD0(double, GetLatency)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+END_PROXY_MAP()
+
+} // namespace webrtc
+
+#endif // API_VIDEO_TRACK_SOURCE_PROXY_H_
diff --git a/audio/BUILD.gn b/audio/BUILD.gn
index c045af6..3a1d123 100644
--- a/audio/BUILD.gn
+++ b/audio/BUILD.gn
@@ -37,15 +37,11 @@
"transport_feedback_packet_loss_tracker.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
"../api:array_view",
"../api:call_api",
"../api:libjingle_peerconnection_api",
+ "../api:scoped_refptr",
"../api:transport_api",
"../api/audio:aec3_factory",
"../api/audio:audio_frame_api",
@@ -61,7 +57,6 @@
"../logging:rtc_stream_config",
"../modules/audio_coding",
"../modules/audio_coding:audio_encoder_cng",
- "../modules/audio_coding:audio_format_conversion",
"../modules/audio_coding:audio_network_adaptor_config",
"../modules/audio_device",
"../modules/audio_processing",
@@ -79,7 +74,7 @@
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_task_queue",
"../rtc_base:safe_minmax",
- "../rtc_base:stringutils",
+ "../rtc_base/experiments:audio_allocation_settings",
"../system_wrappers",
"../system_wrappers:field_trial",
"../system_wrappers:metrics",
@@ -104,12 +99,8 @@
"../system_wrappers:system_wrappers",
"../test:test_common",
"../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
]
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
rtc_source_set("audio_tests") {
@@ -148,6 +139,7 @@
"../logging:rtc_event_log_api",
"../modules/audio_device:mock_audio_device",
"../rtc_base:rtc_base_tests_utils",
+ "../test:field_trial",
# For TestAudioDeviceModule
"../modules/audio_device:audio_device_impl",
@@ -163,6 +155,7 @@
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_task_queue",
"../rtc_base:safe_compare",
+ "../rtc_base:timeutils",
"../system_wrappers:system_wrappers",
"../test:audio_codec_mocks",
"../test:rtp_test_utils",
@@ -172,11 +165,6 @@
"//testing/gtest",
"//third_party/abseil-cpp/absl/memory",
]
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
if (rtc_enable_protobuf) {
@@ -206,11 +194,6 @@
"../resources/voice_engine/audio_tiny16.wav",
"../resources/voice_engine/audio_tiny48.wav",
]
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163)
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
group("low_bandwidth_audio_perf_test") {
@@ -280,10 +263,5 @@
data = [
"//resources/voice_engine/audio_dtx16.wav",
]
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
}
diff --git a/audio/audio_level.h b/audio/audio_level.h
index 3bbe5fd..bb04cc0 100644
--- a/audio/audio_level.h
+++ b/audio/audio_level.h
@@ -11,7 +11,7 @@
#ifndef AUDIO_AUDIO_LEVEL_H_
#define AUDIO_AUDIO_LEVEL_H_
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 8d4afe0..b7b68d0 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -17,7 +17,7 @@
#include "api/array_view.h"
#include "api/audio_codecs/audio_format.h"
#include "api/call/audio_sink.h"
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "audio/audio_send_stream.h"
#include "audio/audio_state.h"
#include "audio/channel_receive.h"
@@ -27,7 +27,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
@@ -67,6 +67,7 @@
namespace internal {
namespace {
std::unique_ptr<voe::ChannelReceiveInterface> CreateChannelReceive(
+ Clock* clock,
webrtc::AudioState* audio_state,
ProcessThread* module_process_thread,
const webrtc::AudioReceiveStream::Config& config,
@@ -75,33 +76,37 @@
internal::AudioState* internal_audio_state =
static_cast<internal::AudioState*>(audio_state);
return voe::CreateChannelReceive(
- module_process_thread, internal_audio_state->audio_device_module(),
+ clock, module_process_thread, internal_audio_state->audio_device_module(),
config.media_transport, config.rtcp_send_transport, event_log,
config.rtp.remote_ssrc, config.jitter_buffer_max_packets,
config.jitter_buffer_fast_accelerate, config.jitter_buffer_min_delay_ms,
- config.decoder_factory, config.codec_pair_id, config.frame_decryptor,
- config.crypto_options);
+ config.jitter_buffer_enable_rtx_handling, config.decoder_factory,
+ config.codec_pair_id, config.frame_decryptor, config.crypto_options);
}
} // namespace
AudioReceiveStream::AudioReceiveStream(
+ Clock* clock,
RtpStreamReceiverControllerInterface* receiver_controller,
PacketRouter* packet_router,
ProcessThread* module_process_thread,
const webrtc::AudioReceiveStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
webrtc::RtcEventLog* event_log)
- : AudioReceiveStream(receiver_controller,
+ : AudioReceiveStream(clock,
+ receiver_controller,
packet_router,
config,
audio_state,
event_log,
- CreateChannelReceive(audio_state.get(),
+ CreateChannelReceive(clock,
+ audio_state.get(),
module_process_thread,
config,
event_log)) {}
AudioReceiveStream::AudioReceiveStream(
+ Clock* clock,
RtpStreamReceiverControllerInterface* receiver_controller,
PacketRouter* packet_router,
const webrtc::AudioReceiveStream::Config& config,
@@ -175,8 +180,8 @@
channel_receive_->GetRTCPStatistics();
// TODO(solenberg): Don't return here if we can't get the codec - return the
// stats we *can* get.
- webrtc::CodecInst codec_inst = {0};
- if (!channel_receive_->GetRecCodec(&codec_inst)) {
+ auto receive_codec = channel_receive_->GetReceiveCodec();
+ if (!receive_codec) {
return stats;
}
@@ -185,13 +190,12 @@
stats.packets_lost = call_stats.cumulativeLost;
stats.fraction_lost = Q8ToFloat(call_stats.fractionLost);
stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_;
- if (codec_inst.pltype != -1) {
- stats.codec_name = codec_inst.plname;
- stats.codec_payload_type = codec_inst.pltype;
- }
+ stats.codec_name = receive_codec->second.name;
+ stats.codec_payload_type = receive_codec->first;
stats.ext_seqnum = call_stats.extendedMax;
- if (codec_inst.plfreq / 1000 > 0) {
- stats.jitter_ms = call_stats.jitterSamples / (codec_inst.plfreq / 1000);
+ int clockrate_khz = receive_codec->second.clockrate_hz / 1000;
+ if (clockrate_khz > 0) {
+ stats.jitter_ms = call_stats.jitterSamples / clockrate_khz;
}
stats.delay_estimate_ms = channel_receive_->GetDelayEstimate();
stats.audio_level = channel_receive_->GetSpeechOutputLevelFullRange();
@@ -208,6 +212,7 @@
stats.jitter_buffer_delay_seconds =
static_cast<double>(ns.jitterBufferDelayMs) /
static_cast<double>(rtc::kNumMillisecsPerSec);
+ stats.jitter_buffer_emitted_count = ns.jitterBufferEmittedCount;
stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
@@ -216,6 +221,9 @@
stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate);
stats.jitter_buffer_flushes = ns.packetBufferFlushes;
stats.delayed_packet_outage_samples = ns.delayedPacketOutageSamples;
+ stats.relative_packet_arrival_delay_seconds =
+ static_cast<double>(ns.relativePacketArrivalDelayMs) /
+ static_cast<double>(rtc::kNumMillisecsPerSec);
auto ds = channel_receive_->GetDecodingCallStatistics();
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
@@ -239,6 +247,16 @@
channel_receive_->SetChannelOutputVolumeScaling(gain);
}
+bool AudioReceiveStream::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
+ RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+ return channel_receive_->SetBaseMinimumPlayoutDelayMs(delay_ms);
+}
+
+int AudioReceiveStream::GetBaseMinimumPlayoutDelayMs() const {
+ RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+ return channel_receive_->GetBaseMinimumPlayoutDelayMs();
+}
+
std::vector<RtpSource> AudioReceiveStream::GetSources() const {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
return channel_receive_->GetSources();
diff --git a/audio/audio_receive_stream.h b/audio/audio_receive_stream.h
index 86bcb1c..1745c0f 100644
--- a/audio/audio_receive_stream.h
+++ b/audio/audio_receive_stream.h
@@ -19,8 +19,9 @@
#include "audio/audio_state.h"
#include "call/audio_receive_stream.h"
#include "call/syncable.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/thread_checker.h"
+#include "system_wrappers/include/clock.h"
namespace webrtc {
class PacketRouter;
@@ -41,7 +42,8 @@
public AudioMixer::Source,
public Syncable {
public:
- AudioReceiveStream(RtpStreamReceiverControllerInterface* receiver_controller,
+ AudioReceiveStream(Clock* clock,
+ RtpStreamReceiverControllerInterface* receiver_controller,
PacketRouter* packet_router,
ProcessThread* module_process_thread,
const webrtc::AudioReceiveStream::Config& config,
@@ -49,6 +51,7 @@
webrtc::RtcEventLog* event_log);
// For unit tests, which need to supply a mock channel receive.
AudioReceiveStream(
+ Clock* clock,
RtpStreamReceiverControllerInterface* receiver_controller,
PacketRouter* packet_router,
const webrtc::AudioReceiveStream::Config& config,
@@ -64,6 +67,8 @@
webrtc::AudioReceiveStream::Stats GetStats() const override;
void SetSink(AudioSinkInterface* sink) override;
void SetGain(float gain) override;
+ bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override;
+ int GetBaseMinimumPlayoutDelayMs() const override;
std::vector<webrtc::RtpSource> GetSources() const override;
// TODO(nisse): We don't formally implement RtpPacketSinkInterface, and this
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc
index 7422810..4594e56 100644
--- a/audio/audio_receive_stream_unittest.cc
+++ b/audio/audio_receive_stream_unittest.cc
@@ -10,6 +10,7 @@
#include <map>
#include <string>
+#include <utility>
#include <vector>
#include "api/test/mock_audio_mixer.h"
@@ -24,6 +25,7 @@
#include "modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/time_utils.h"
#include "test/gtest.h"
#include "test/mock_audio_decoder_factory.h"
#include "test/mock_transport.h"
@@ -63,10 +65,11 @@
const CallReceiveStatistics kCallStats = {345, 678, 901, 234,
-12, 567, 890, 123};
-const CodecInst kCodecInst = {123, "codec_name_recv", 96000, -187, 0, -103};
+const std::pair<int, SdpAudioFormat> kReceiveCodec =
+ {123, {"codec_name_recv", 96000, 0}};
const NetworkStatistics kNetworkStats = {
- 123, 456, false, 789012, 3456, 123, 456, 0, {}, 789, 12,
- 345, 678, 901, 0, -1, -1, -1, -1, -1, 0};
+ 123, 456, false, 789012, 3456, 123, 456, 789, 0, {}, 789,
+ 12, 345, 678, 901, 0, -1, -1, -1, -1, -1, 0};
const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
struct ConfigHelper {
@@ -112,8 +115,8 @@
std::unique_ptr<internal::AudioReceiveStream> CreateAudioReceiveStream() {
return std::unique_ptr<internal::AudioReceiveStream>(
new internal::AudioReceiveStream(
- &rtp_stream_receiver_controller_, &packet_router_, stream_config_,
- audio_state_, &event_log_,
+ Clock::GetRealTimeClock(), &rtp_stream_receiver_controller_,
+ &packet_router_, stream_config_, audio_state_, &event_log_,
std::unique_ptr<voe::ChannelReceiveInterface>(channel_receive_)));
}
@@ -140,8 +143,8 @@
.WillOnce(Return(kNetworkStats));
EXPECT_CALL(*channel_receive_, GetDecodingCallStatistics())
.WillOnce(Return(kAudioDecodeStats));
- EXPECT_CALL(*channel_receive_, GetRecCodec(_))
- .WillOnce(DoAll(SetArgPointee<0>(kCodecInst), Return(true)));
+ EXPECT_CALL(*channel_receive_, GetReceiveCodec())
+ .WillOnce(Return(kReceiveCodec));
}
private:
@@ -267,10 +270,11 @@
stats.packets_rcvd);
EXPECT_EQ(kCallStats.cumulativeLost, stats.packets_lost);
EXPECT_EQ(Q8ToFloat(kCallStats.fractionLost), stats.fraction_lost);
- EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name);
+ EXPECT_EQ(kReceiveCodec.second.name, stats.codec_name);
EXPECT_EQ(kCallStats.extendedMax, stats.ext_seqnum);
- EXPECT_EQ(kCallStats.jitterSamples / (kCodecInst.plfreq / 1000),
- stats.jitter_ms);
+ EXPECT_EQ(
+ kCallStats.jitterSamples / (kReceiveCodec.second.clockrate_hz / 1000),
+ stats.jitter_ms);
EXPECT_EQ(kNetworkStats.currentBufferSize, stats.jitter_buffer_ms);
EXPECT_EQ(kNetworkStats.preferredBufferSize,
stats.jitter_buffer_preferred_ms);
@@ -285,6 +289,8 @@
EXPECT_EQ(static_cast<double>(kNetworkStats.jitterBufferDelayMs) /
static_cast<double>(rtc::kNumMillisecsPerSec),
stats.jitter_buffer_delay_seconds);
+ EXPECT_EQ(kNetworkStats.jitterBufferEmittedCount,
+ stats.jitter_buffer_emitted_count);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
stats.speech_expand_rate);
diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc
index 75e6efb..bb79149 100644
--- a/audio/audio_send_stream.cc
+++ b/audio/audio_send_stream.cc
@@ -19,7 +19,7 @@
#include "api/audio_codecs/audio_encoder_factory.h"
#include "api/audio_codecs/audio_format.h"
#include "api/call/transport.h"
-#include "api/crypto/frameencryptorinterface.h"
+#include "api/crypto/frame_encryptor_interface.h"
#include "audio/audio_state.h"
#include "audio/channel_send.h"
#include "audio/conversion.h"
@@ -37,7 +37,6 @@
#include "rtc_base/logging.h"
#include "rtc_base/strings/audio_format_to_string.h"
#include "rtc_base/task_queue.h"
-#include "rtc_base/timeutils.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -48,14 +47,6 @@
constexpr size_t kPacketLossRateMinNumAckedPackets = 50;
constexpr size_t kRecoverablePacketLossRateMinNumAckedPairs = 40;
-void CallEncoder(const std::unique_ptr<voe::ChannelSendInterface>& channel_send,
- rtc::FunctionView<void(AudioEncoder*)> lambda) {
- channel_send->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder_ptr) {
- RTC_DCHECK(encoder_ptr);
- lambda(encoder_ptr->get());
- });
-}
-
void UpdateEventLogStreamConfig(RtcEventLog* event_log,
const AudioSendStream::Config& config,
const AudioSendStream::Config* old_config) {
@@ -91,6 +82,7 @@
} // namespace
AudioSendStream::AudioSendStream(
+ Clock* clock,
const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
rtc::TaskQueue* worker_queue,
@@ -100,7 +92,8 @@
RtcEventLog* event_log,
RtcpRttStats* rtcp_rtt_stats,
const absl::optional<RtpState>& suspended_rtp_state)
- : AudioSendStream(config,
+ : AudioSendStream(clock,
+ config,
audio_state,
worker_queue,
rtp_transport,
@@ -108,9 +101,11 @@
event_log,
rtcp_rtt_stats,
suspended_rtp_state,
- voe::CreateChannelSend(worker_queue,
+ voe::CreateChannelSend(clock,
+ worker_queue,
module_process_thread,
config.media_transport,
+ /*overhead_observer=*/this,
config.send_transport,
rtcp_rtt_stats,
event_log,
@@ -120,6 +115,7 @@
config.rtcp_report_interval_ms)) {}
AudioSendStream::AudioSendStream(
+ Clock* clock,
const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
rtc::TaskQueue* worker_queue,
@@ -129,7 +125,8 @@
RtcpRttStats* rtcp_rtt_stats,
const absl::optional<RtpState>& suspended_rtp_state,
std::unique_ptr<voe::ChannelSendInterface> channel_send)
- : worker_queue_(worker_queue),
+ : clock_(clock),
+ worker_queue_(worker_queue),
config_(Config(/*send_transport=*/nullptr,
/*media_transport=*/nullptr)),
audio_state_(audio_state),
@@ -152,7 +149,15 @@
// should be no rtp_transport, and below check should be strengthened to XOR
// (either rtp_transport or media_transport but not both).
RTC_DCHECK(rtp_transport || config.media_transport);
-
+ if (config.media_transport) {
+ // TODO(sukhanov): Currently media transport audio overhead is considered
+ // constant, we will not get overhead_observer calls when using
+ // media_transport. In the future when we introduce RTP media transport we
+ // should make audio overhead interface consistent and work for both RTP and
+ // non-RTP implementations.
+ audio_overhead_per_packet_bytes_ =
+ config.media_transport->GetAudioPacketOverhead();
+ }
rtp_rtcp_module_ = channel_send_->GetRtpRtcp();
RTC_DCHECK(rtp_rtcp_module_);
@@ -197,11 +202,19 @@
ids.transport_sequence_number = extension.id;
} else if (extension.uri == RtpExtension::kMidUri) {
ids.mid = extension.id;
+ } else if (extension.uri == RtpExtension::kRidUri) {
+ ids.rid = extension.id;
+ } else if (extension.uri == RtpExtension::kRepairedRidUri) {
+ ids.repaired_rid = extension.id;
}
}
return ids;
}
+int AudioSendStream::TransportSeqNumId(const AudioSendStream::Config& config) {
+ return FindExtensionIds(config.rtp.extensions).transport_sequence_number;
+}
+
void AudioSendStream::ConfigureStream(
webrtc::internal::AudioSendStream* stream,
const webrtc::AudioSendStream::Config& new_config,
@@ -247,18 +260,16 @@
}
bool transport_seq_num_id_changed =
new_ids.transport_sequence_number != old_ids.transport_sequence_number;
- if (first_time ||
- (transport_seq_num_id_changed &&
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"))) {
+ if (first_time || (transport_seq_num_id_changed &&
+ !stream->allocation_settings_.ForceNoAudioFeedback())) {
if (!first_time) {
channel_send->ResetSenderCongestionControlObjects();
}
RtcpBandwidthObserver* bandwidth_observer = nullptr;
- bool has_transport_sequence_number =
- new_ids.transport_sequence_number != 0 &&
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC");
- if (has_transport_sequence_number) {
+
+ if (stream->allocation_settings_.ShouldSendTransportSequenceNumber(
+ new_ids.transport_sequence_number)) {
channel_send->EnableSendTransportSequenceNumber(
new_ids.transport_sequence_number);
// Probing in application limited region is only used in combination with
@@ -281,6 +292,13 @@
channel_send->SetMid(new_config.rtp.mid, new_ids.mid);
}
+ // RID RTP header extension
+ if ((first_time || new_ids.rid != old_ids.rid ||
+ new_ids.repaired_rid != old_ids.repaired_rid ||
+ new_config.rtp.rid != old_config.rtp.rid)) {
+ channel_send->SetRid(new_config.rtp.rid, new_ids.rid, new_ids.repaired_rid);
+ }
+
if (!ReconfigureSendCodec(stream, new_config)) {
RTC_LOG(LS_ERROR) << "Failed to set up send codec state.";
}
@@ -297,20 +315,13 @@
return;
}
- bool has_transport_sequence_number =
- FindExtensionIds(config_.rtp.extensions).transport_sequence_number != 0 &&
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC");
- if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1 &&
- !config_.has_dscp &&
- (has_transport_sequence_number ||
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe") ||
- webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC"))) {
- // Audio BWE is enabled.
+ if (allocation_settings_.IncludeAudioInAllocationOnStart(
+ config_.min_bitrate_bps, config_.max_bitrate_bps, config_.has_dscp,
+ TransportSeqNumId(config_))) {
rtp_transport_->packet_sender()->SetAccountForAudioPackets(true);
rtp_rtcp_module_->SetAsPartOfAllocation(true);
ConfigureBitrateObserver(config_.min_bitrate_bps, config_.max_bitrate_bps,
- config_.bitrate_priority,
- has_transport_sequence_number);
+ config_.bitrate_priority);
} else {
rtp_rtcp_module_->SetAsPartOfAllocation(false);
}
@@ -448,7 +459,7 @@
// TODO(eladalon): This function call could potentially reset the window,
// setting both PLR and RPLR to unknown. Consider (during upcoming
// refactoring) passing an indication of such an event.
- packet_loss_tracker_.OnPacketAdded(seq_num, rtc::TimeMillis());
+ packet_loss_tracker_.OnPacketAdded(seq_num, clock_->TimeInMilliseconds());
}
}
@@ -474,9 +485,36 @@
}
}
-void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) {
+void AudioSendStream::SetTransportOverhead(
+ int transport_overhead_per_packet_bytes) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- channel_send_->SetTransportOverhead(transport_overhead_per_packet);
+ rtc::CritScope cs(&overhead_per_packet_lock_);
+ transport_overhead_per_packet_bytes_ = transport_overhead_per_packet_bytes;
+ UpdateOverheadForEncoder();
+}
+
+void AudioSendStream::OnOverheadChanged(
+ size_t overhead_bytes_per_packet_bytes) {
+ rtc::CritScope cs(&overhead_per_packet_lock_);
+ audio_overhead_per_packet_bytes_ = overhead_bytes_per_packet_bytes;
+ UpdateOverheadForEncoder();
+}
+
+void AudioSendStream::UpdateOverheadForEncoder() {
+ const size_t overhead_per_packet_bytes = GetPerPacketOverheadBytes();
+ channel_send_->CallEncoder([&](AudioEncoder* encoder) {
+ encoder->OnReceivedOverhead(overhead_per_packet_bytes);
+ });
+}
+
+size_t AudioSendStream::TestOnlyGetPerPacketOverheadBytes() const {
+ rtc::CritScope cs(&overhead_per_packet_lock_);
+ return GetPerPacketOverheadBytes();
+}
+
+size_t AudioSendStream::GetPerPacketOverheadBytes() const {
+ return transport_overhead_per_packet_bytes_ +
+ audio_overhead_per_packet_bytes_;
}
RtpState AudioSendStream::GetRtpState() const {
@@ -529,16 +567,11 @@
return false;
}
- // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is
- // not enabled, do not update target audio bitrate if we are in
- // WebRTC-Audio-SendSideBwe-For-Video experiment
- const bool do_not_update_target_bitrate =
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") &&
- webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") &&
- !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number;
// If a bitrate has been specified for the codec, use it over the
// codec's default.
- if (!do_not_update_target_bitrate && spec.target_bitrate_bps) {
+ if (stream->allocation_settings_.UpdateAudioTargetBitrate(
+ TransportSeqNumId(new_config)) &&
+ spec.target_bitrate_bps) {
encoder->OnReceivedTargetAudioBitrate(*spec.target_bitrate_bps);
}
@@ -567,10 +600,18 @@
new_config.send_codec_spec->format.clockrate_hz);
}
+ // Set currently known overhead (used in ANA, opus only).
+ // If overhead changes later, it will be updated in UpdateOverheadForEncoder.
+ {
+ rtc::CritScope cs(&stream->overhead_per_packet_lock_);
+ encoder->OnReceivedOverhead(stream->GetPerPacketOverheadBytes());
+ }
+
stream->StoreEncoderProperties(encoder->SampleRateHz(),
encoder->NumChannels());
stream->channel_send_->SetEncoder(new_config.send_codec_spec->payload_type,
std::move(encoder));
+
return true;
}
@@ -601,22 +642,16 @@
return SetupSendCodec(stream, new_config);
}
- // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is
- // not enabled, do not update target audio bitrate if we are in
- // WebRTC-Audio-SendSideBwe-For-Video experiment
- const bool do_not_update_target_bitrate =
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") &&
- webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") &&
- !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number;
-
const absl::optional<int>& new_target_bitrate_bps =
new_config.send_codec_spec->target_bitrate_bps;
// If a bitrate has been specified for the codec, use it over the
// codec's default.
- if (!do_not_update_target_bitrate && new_target_bitrate_bps &&
+ if (stream->allocation_settings_.UpdateAudioTargetBitrate(
+ TransportSeqNumId(new_config)) &&
+ new_target_bitrate_bps &&
new_target_bitrate_bps !=
old_config.send_codec_spec->target_bitrate_bps) {
- CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) {
+ stream->channel_send_->CallEncoder([&](AudioEncoder* encoder) {
encoder->OnReceivedTargetAudioBitrate(*new_target_bitrate_bps);
});
}
@@ -624,6 +659,12 @@
ReconfigureANA(stream, new_config);
ReconfigureCNG(stream, new_config);
+ // Set currently known overhead (used in ANA, opus only).
+ {
+ rtc::CritScope cs(&stream->overhead_per_packet_lock_);
+ stream->UpdateOverheadForEncoder();
+ }
+
return true;
}
@@ -634,7 +675,7 @@
return;
}
if (new_config.audio_network_adaptor_config) {
- CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) {
+ stream->channel_send_->CallEncoder([&](AudioEncoder* encoder) {
if (encoder->EnableAudioNetworkAdaptor(
*new_config.audio_network_adaptor_config, stream->event_log_)) {
RTC_DLOG(LS_INFO) << "Audio network adaptor enabled on SSRC "
@@ -644,9 +685,8 @@
}
});
} else {
- CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) {
- encoder->DisableAudioNetworkAdaptor();
- });
+ stream->channel_send_->CallEncoder(
+ [&](AudioEncoder* encoder) { encoder->DisableAudioNetworkAdaptor(); });
RTC_DLOG(LS_INFO) << "Audio network adaptor disabled on SSRC "
<< new_config.rtp.ssrc;
}
@@ -701,26 +741,21 @@
// allow us to configure the bitrate observer if the new config has bitrate
// limits set, but would only have us call RemoveBitrateObserver if we were
// previously configured with bitrate limits.
- int new_transport_seq_num_id =
- FindExtensionIds(new_config.rtp.extensions).transport_sequence_number;
if (stream->config_.min_bitrate_bps == new_config.min_bitrate_bps &&
stream->config_.max_bitrate_bps == new_config.max_bitrate_bps &&
stream->config_.bitrate_priority == new_config.bitrate_priority &&
- (FindExtensionIds(stream->config_.rtp.extensions)
- .transport_sequence_number == new_transport_seq_num_id ||
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) {
+ (TransportSeqNumId(stream->config_) == TransportSeqNumId(new_config) ||
+ stream->allocation_settings_.IgnoreSeqNumIdChange())) {
return;
}
- bool has_transport_sequence_number = new_transport_seq_num_id != 0;
- if (new_config.min_bitrate_bps != -1 && new_config.max_bitrate_bps != -1 &&
- !new_config.has_dscp &&
- (has_transport_sequence_number ||
- !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) {
+ if (stream->allocation_settings_.IncludeAudioInAllocationOnReconfigure(
+ new_config.min_bitrate_bps, new_config.max_bitrate_bps,
+ new_config.has_dscp, TransportSeqNumId(new_config))) {
stream->rtp_transport_->packet_sender()->SetAccountForAudioPackets(true);
- stream->ConfigureBitrateObserver(
- new_config.min_bitrate_bps, new_config.max_bitrate_bps,
- new_config.bitrate_priority, has_transport_sequence_number);
+ stream->ConfigureBitrateObserver(new_config.min_bitrate_bps,
+ new_config.max_bitrate_bps,
+ new_config.bitrate_priority);
stream->rtp_rtcp_module_->SetAsPartOfAllocation(true);
} else {
stream->rtp_transport_->packet_sender()->SetAccountForAudioPackets(false);
@@ -731,8 +766,7 @@
void AudioSendStream::ConfigureBitrateObserver(int min_bitrate_bps,
int max_bitrate_bps,
- double bitrate_priority,
- bool has_packet_feedback) {
+ double bitrate_priority) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RTC_DCHECK_GE(max_bitrate_bps, min_bitrate_bps);
rtc::Event thread_sync_event;
@@ -746,8 +780,9 @@
bitrate_allocator_->AddObserver(
this, MediaStreamAllocationConfig{
static_cast<uint32_t>(min_bitrate_bps),
- static_cast<uint32_t>(max_bitrate_bps), 0, true,
- config_.track_id, bitrate_priority, has_packet_feedback});
+ static_cast<uint32_t>(max_bitrate_bps), 0,
+ allocation_settings_.DefaultPriorityBitrate().bps(), true,
+ config_.track_id, bitrate_priority});
thread_sync_event.Set();
});
thread_sync_event.Wait(rtc::Event::kForever);
@@ -765,14 +800,8 @@
void AudioSendStream::RegisterCngPayloadType(int payload_type,
int clockrate_hz) {
- const CodecInst codec = {payload_type, "CN", clockrate_hz, 0, 1, 0};
- if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) {
- rtp_rtcp_module_->DeRegisterSendPayload(codec.pltype);
- if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) {
- RTC_DLOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to "
- "RTP/RTCP module";
- }
- }
+ rtp_rtcp_module_->RegisterAudioSendPayload(payload_type, "CN", clockrate_hz,
+ 1, 0);
}
} // namespace internal
} // namespace webrtc
diff --git a/audio/audio_send_stream.h b/audio/audio_send_stream.h
index bf94901..c227e61 100644
--- a/audio/audio_send_stream.h
+++ b/audio/audio_send_stream.h
@@ -20,7 +20,8 @@
#include "call/audio_state.h"
#include "call/bitrate_allocator.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/experiments/audio_allocation_settings.h"
#include "rtc_base/race_checker.h"
#include "rtc_base/thread_checker.h"
@@ -35,9 +36,11 @@
class AudioSendStream final : public webrtc::AudioSendStream,
public webrtc::BitrateAllocatorObserver,
- public webrtc::PacketFeedbackObserver {
+ public webrtc::PacketFeedbackObserver,
+ public webrtc::OverheadObserver {
public:
- AudioSendStream(const webrtc::AudioSendStream::Config& config,
+ AudioSendStream(Clock* clock,
+ const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
rtc::TaskQueue* worker_queue,
ProcessThread* module_process_thread,
@@ -47,7 +50,8 @@
RtcpRttStats* rtcp_rtt_stats,
const absl::optional<RtpState>& suspended_rtp_state);
// For unit tests, which need to supply a mock ChannelSend.
- AudioSendStream(const webrtc::AudioSendStream::Config& config,
+ AudioSendStream(Clock* clock,
+ const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
rtc::TaskQueue* worker_queue,
RtpTransportControllerSendInterface* rtp_transport,
@@ -84,11 +88,19 @@
void OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector) override;
- void SetTransportOverhead(int transport_overhead_per_packet);
+ void SetTransportOverhead(int transport_overhead_per_packet_bytes);
+
+ // OverheadObserver override reports audio packetization overhead from
+ // RTP/RTCP module or Media Transport.
+ void OnOverheadChanged(size_t overhead_bytes_per_packet_bytes) override;
RtpState GetRtpState() const;
const voe::ChannelSendInterface* GetChannel() const;
+ // Returns combined per-packet overhead.
+ size_t TestOnlyGetPerPacketOverheadBytes() const
+ RTC_LOCKS_EXCLUDED(overhead_per_packet_lock_);
+
private:
class TimedTransport;
@@ -112,16 +124,26 @@
void ConfigureBitrateObserver(int min_bitrate_bps,
int max_bitrate_bps,
- double bitrate_priority,
- bool has_packet_feedback);
+ double bitrate_priority);
void RemoveBitrateObserver();
+ // Sets per-packet overhead on encoded (for ANA) based on current known values
+ // of transport and packetization overheads.
+ void UpdateOverheadForEncoder()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_);
+
+ // Returns combined per-packet overhead.
+ size_t GetPerPacketOverheadBytes() const
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_);
+
void RegisterCngPayloadType(int payload_type, int clockrate_hz);
+ Clock* clock_;
rtc::ThreadChecker worker_thread_checker_;
rtc::ThreadChecker pacer_thread_checker_;
rtc::RaceChecker audio_capture_race_checker_;
rtc::TaskQueue* worker_queue_;
+ const AudioAllocationSettings allocation_settings_;
webrtc::AudioSendStream::Config config_;
rtc::scoped_refptr<webrtc::AudioState> audio_state_;
const std::unique_ptr<voe::ChannelSendInterface> channel_send_;
@@ -148,9 +170,22 @@
int audio_level = 0;
int transport_sequence_number = 0;
int mid = 0;
+ int rid = 0;
+ int repaired_rid = 0;
};
static ExtensionIds FindExtensionIds(
const std::vector<RtpExtension>& extensions);
+ static int TransportSeqNumId(const Config& config);
+
+ rtc::CriticalSection overhead_per_packet_lock_;
+
+ // Current transport overhead (ICE, TURN, etc.)
+ size_t transport_overhead_per_packet_bytes_
+ RTC_GUARDED_BY(overhead_per_packet_lock_) = 0;
+
+ // Current audio packetization overhead (RTP or Media Transport).
+ size_t audio_overhead_per_packet_bytes_
+ RTC_GUARDED_BY(overhead_per_packet_lock_) = 0;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
};
diff --git a/audio/audio_send_stream_tests.cc b/audio/audio_send_stream_tests.cc
index 7deeff3..8a83554 100644
--- a/audio/audio_send_stream_tests.cc
+++ b/audio/audio_send_stream_tests.cc
@@ -8,7 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string>
+#include <utility>
+#include <vector>
+
#include "test/call_test.h"
+#include "test/field_trial.h"
#include "test/gtest.h"
#include "test/rtcp_packet_parser.h"
@@ -16,6 +21,11 @@
namespace test {
namespace {
+enum : int { // The first valid value is 1.
+ kAudioLevelExtensionId = 1,
+ kTransportSequenceNumberExtensionId,
+};
+
class AudioSendTest : public SendTest {
public:
AudioSendTest() : SendTest(CallTest::kDefaultTimeoutMs) {}
@@ -101,8 +111,8 @@
class AudioLevelObserver : public AudioSendTest {
public:
AudioLevelObserver() : AudioSendTest() {
- EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
- kRtpExtensionAudioLevel, test::kAudioLevelExtensionId));
+ EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
+ kAudioLevelExtensionId));
}
Action OnSendRtp(const uint8_t* packet, size_t length) override {
@@ -125,8 +135,8 @@
AudioSendStream::Config* send_config,
std::vector<AudioReceiveStream::Config>* receive_configs) override {
send_config->rtp.extensions.clear();
- send_config->rtp.extensions.push_back(RtpExtension(
- RtpExtension::kAudioLevelUri, test::kAudioLevelExtensionId));
+ send_config->rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelExtensionId));
}
void PerformTest() override {
@@ -137,42 +147,54 @@
RunBaseTest(&test);
}
-TEST_F(AudioSendStreamCallTest, SupportsTransportWideSequenceNumbers) {
- static const uint8_t kExtensionId = test::kTransportSequenceNumberExtensionId;
- class TransportWideSequenceNumberObserver : public AudioSendTest {
- public:
- TransportWideSequenceNumberObserver() : AudioSendTest() {
- EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
- kRtpExtensionTransportSequenceNumber, kExtensionId));
- }
+class TransportWideSequenceNumberObserver : public AudioSendTest {
+ public:
+ explicit TransportWideSequenceNumberObserver(bool expect_sequence_number)
+ : AudioSendTest(), expect_sequence_number_(expect_sequence_number) {
+ EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber,
+ kTransportSequenceNumberExtensionId));
+ }
- private:
- Action OnSendRtp(const uint8_t* packet, size_t length) override {
- RTPHeader header;
- EXPECT_TRUE(parser_->Parse(packet, length, &header));
+ private:
+ Action OnSendRtp(const uint8_t* packet, size_t length) override {
+ RTPHeader header;
+ EXPECT_TRUE(parser_->Parse(packet, length, &header));
- EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
- EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
- EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
+ EXPECT_EQ(header.extension.hasTransportSequenceNumber,
+ expect_sequence_number_);
+ EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
+ EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
- observation_complete_.Set();
+ observation_complete_.Set();
- return SEND_PACKET;
- }
+ return SEND_PACKET;
+ }
- void ModifyAudioConfigs(
- AudioSendStream::Config* send_config,
- std::vector<AudioReceiveStream::Config>* receive_configs) override {
- send_config->rtp.extensions.clear();
- send_config->rtp.extensions.push_back(RtpExtension(
- RtpExtension::kTransportSequenceNumberUri, kExtensionId));
- }
+ void ModifyAudioConfigs(
+ AudioSendStream::Config* send_config,
+ std::vector<AudioReceiveStream::Config>* receive_configs) override {
+ send_config->rtp.extensions.clear();
+ send_config->rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kTransportSequenceNumberUri,
+ kTransportSequenceNumberExtensionId));
+ }
- void PerformTest() override {
- EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet.";
- }
- } test;
+ void PerformTest() override {
+ EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet.";
+ }
+ const bool expect_sequence_number_;
+};
+TEST_F(AudioSendStreamCallTest, SendsTransportWideSequenceNumbersInFieldTrial) {
+ ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/");
+ TransportWideSequenceNumberObserver test(/*expect_sequence_number=*/true);
+ RunBaseTest(&test);
+}
+
+TEST_F(AudioSendStreamCallTest,
+ DoesNotSendTransportWideSequenceNumbersPerDefault) {
+ TransportWideSequenceNumberObserver test(/*expect_sequence_number=*/false);
RunBaseTest(&test);
}
diff --git a/audio/audio_send_stream_unittest.cc b/audio/audio_send_stream_unittest.cc
index e400ada..ddd8137 100644
--- a/audio/audio_send_stream_unittest.cc
+++ b/audio/audio_send_stream_unittest.cc
@@ -28,6 +28,8 @@
#include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h"
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "rtc_base/task_queue.h"
+#include "system_wrappers/include/clock.h"
+#include "test/field_trial.h"
#include "test/gtest.h"
#include "test/mock_audio_encoder.h"
#include "test/mock_audio_encoder_factory.h"
@@ -61,7 +63,6 @@
const int kTelephoneEventPayloadFrequency = 65432;
const int kTelephoneEventCode = 45;
const int kTelephoneEventDuration = 6789;
-const CodecInst kIsacCodec = {103, "isac", 16000, 320, 1, 32000};
constexpr int kIsacPayloadType = 103;
const SdpAudioFormat kIsacFormat = {"isac", 16000, 1};
const SdpAudioFormat kOpusFormat = {"opus", 48000, 2};
@@ -73,12 +74,10 @@
class MockLimitObserver : public BitrateAllocator::LimitObserver {
public:
- MOCK_METHOD5(OnAllocationLimitsChanged,
+ MOCK_METHOD3(OnAllocationLimitsChanged,
void(uint32_t min_send_bitrate_bps,
uint32_t max_padding_bitrate_bps,
- uint32_t total_bitrate_bps,
- uint32_t allocated_without_feedback_bps,
- bool has_packet_feedback));
+ uint32_t total_bitrate_bps));
};
std::unique_ptr<MockAudioEncoder> SetupAudioEncoderMock(
@@ -127,9 +126,10 @@
struct ConfigHelper {
ConfigHelper(bool audio_bwe_enabled, bool expect_set_encoder_call)
- : stream_config_(/*send_transport=*/nullptr, /*media_transport=*/nullptr),
+ : clock_(1000000),
+ stream_config_(/*send_transport=*/nullptr, /*media_transport=*/nullptr),
audio_processing_(new rtc::RefCountedObject<MockAudioProcessing>()),
- bitrate_allocator_(&limit_observer_),
+ bitrate_allocator_(&clock_, &limit_observer_),
worker_queue_("ConfigHelper_worker_queue"),
audio_encoder_(nullptr) {
using testing::Invoke;
@@ -163,8 +163,9 @@
std::unique_ptr<internal::AudioSendStream> CreateAudioSendStream() {
return std::unique_ptr<internal::AudioSendStream>(
new internal::AudioSendStream(
- stream_config_, audio_state_, &worker_queue_, &rtp_transport_,
- &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, absl::nullopt,
+ Clock::GetRealTimeClock(), stream_config_, audio_state_,
+ &worker_queue_, &rtp_transport_, &bitrate_allocator_, &event_log_,
+ &rtcp_rtt_stats_, absl::nullopt,
std::unique_ptr<voe::ChannelSendInterface>(channel_send_)));
}
@@ -211,6 +212,7 @@
.Times(1);
}
EXPECT_CALL(*channel_send_, ResetSenderCongestionControlObjects()).Times(1);
+ EXPECT_CALL(*channel_send_, SetRid(std::string(), 0, 0)).Times(1);
}
void SetupMockForSetupSendCodec(bool expect_set_encoder_call) {
@@ -224,15 +226,14 @@
}
}
- void SetupMockForModifyEncoder() {
+ void SetupMockForCallEncoder() {
// Let ModifyEncoder to invoke mock audio encoder.
- EXPECT_CALL(*channel_send_, ModifyEncoder(_))
- .WillRepeatedly(Invoke(
- [this](rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)>
- modifier) {
+ EXPECT_CALL(*channel_send_, CallEncoder(_))
+ .WillRepeatedly(
+ [this](rtc::FunctionView<void(AudioEncoder*)> modifier) {
if (this->audio_encoder_)
- modifier(&this->audio_encoder_);
- }));
+ modifier(this->audio_encoder_.get());
+ });
}
void SetupMockForSendTelephoneEvent() {
@@ -285,6 +286,7 @@
}
private:
+ SimulatedClock clock_;
rtc::scoped_refptr<AudioState> audio_state_;
AudioSendStream::Config stream_config_;
testing::StrictMock<MockChannelSend>* channel_send_ = nullptr;
@@ -356,6 +358,7 @@
}
TEST(AudioSendStreamTest, AudioBweCorrectObjectsOnChannelProxy) {
+ ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/");
ConfigHelper helper(true, true);
auto send_stream = helper.CreateAudioSendStream();
}
@@ -375,11 +378,11 @@
EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent);
EXPECT_EQ(kReportBlock.cumulative_num_packets_lost, stats.packets_lost);
EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost);
- EXPECT_EQ(std::string(kIsacCodec.plname), stats.codec_name);
+ EXPECT_EQ(kIsacFormat.name, stats.codec_name);
EXPECT_EQ(static_cast<int32_t>(kReportBlock.extended_highest_sequence_number),
stats.ext_seqnum);
EXPECT_EQ(static_cast<int32_t>(kReportBlock.interarrival_jitter /
- (kIsacCodec.plfreq / 1000)),
+ (kIsacFormat.clockrate_hz / 1000)),
stats.jitter_ms);
EXPECT_EQ(kCallStats.rttMs, stats.rtt_ms);
EXPECT_EQ(0, stats.audio_level);
@@ -428,7 +431,7 @@
auto stream_config = helper.config();
stream_config.audio_network_adaptor_config = kAnaReconfigString;
- helper.SetupMockForModifyEncoder();
+ helper.SetupMockForCallEncoder();
send_stream->Reconfigure(stream_config);
}
@@ -507,6 +510,7 @@
}
TEST(AudioSendStreamTest, ReconfigureTransportCcResetsFirst) {
+ ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/");
ConfigHelper helper(false, true);
auto send_stream = helper.CreateAudioSendStream();
auto new_config = helper.config();
@@ -522,9 +526,61 @@
helper.transport(), Ne(nullptr)))
.Times(1);
}
+
+ // CallEncoder will be called to re-set overhead.
+ EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1);
+
send_stream->Reconfigure(new_config);
}
+TEST(AudioSendStreamTest, OnTransportOverheadChanged) {
+ ConfigHelper helper(false, true);
+ auto send_stream = helper.CreateAudioSendStream();
+ auto new_config = helper.config();
+
+ // CallEncoder will be called on overhead change.
+ EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1);
+
+ const size_t transport_overhead_per_packet_bytes = 333;
+ send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
+
+ EXPECT_EQ(transport_overhead_per_packet_bytes,
+ send_stream->TestOnlyGetPerPacketOverheadBytes());
+}
+
+TEST(AudioSendStreamTest, OnAudioOverheadChanged) {
+ ConfigHelper helper(false, true);
+ auto send_stream = helper.CreateAudioSendStream();
+ auto new_config = helper.config();
+
+ // CallEncoder will be called on overhead change.
+ EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1);
+
+ const size_t audio_overhead_per_packet_bytes = 555;
+ send_stream->OnOverheadChanged(audio_overhead_per_packet_bytes);
+ EXPECT_EQ(audio_overhead_per_packet_bytes,
+ send_stream->TestOnlyGetPerPacketOverheadBytes());
+}
+
+TEST(AudioSendStreamTest, OnAudioAndTransportOverheadChanged) {
+ ConfigHelper helper(false, true);
+ auto send_stream = helper.CreateAudioSendStream();
+ auto new_config = helper.config();
+
+ // CallEncoder will be called when each of overhead changes.
+ EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(2);
+
+ const size_t transport_overhead_per_packet_bytes = 333;
+ send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
+
+ const size_t audio_overhead_per_packet_bytes = 555;
+ send_stream->OnOverheadChanged(audio_overhead_per_packet_bytes);
+
+ EXPECT_EQ(
+ transport_overhead_per_packet_bytes + audio_overhead_per_packet_bytes,
+ send_stream->TestOnlyGetPerPacketOverheadBytes());
+}
+
// Validates that reconfiguring the AudioSendStream with a Frame encryptor
// correctly reconfigures on the object without crashing.
TEST(AudioSendStreamTest, ReconfigureWithFrameEncryptor) {
diff --git a/audio/audio_state.cc b/audio/audio_state.cc
index 7d473ae..334eaed 100644
--- a/audio/audio_state.cc
+++ b/audio/audio_state.cc
@@ -17,9 +17,9 @@
#include "absl/memory/memory.h"
#include "audio/audio_receive_stream.h"
#include "modules/audio_device/include/audio_device.h"
-#include "rtc_base/atomicops.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/thread.h"
namespace webrtc {
@@ -168,20 +168,6 @@
audio_transport_.SetStereoChannelSwapping(enable);
}
-// Reference count; implementation copied from rtc::RefCountedObject.
-void AudioState::AddRef() const {
- rtc::AtomicOps::Increment(&ref_count_);
-}
-
-// Reference count; implementation copied from rtc::RefCountedObject.
-rtc::RefCountReleaseStatus AudioState::Release() const {
- if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
- delete this;
- return rtc::RefCountReleaseStatus::kDroppedLastRef;
- }
- return rtc::RefCountReleaseStatus::kOtherRefsRemained;
-}
-
void AudioState::UpdateAudioTransportWithSendingStreams() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
std::vector<webrtc::AudioSendStream*> sending_streams;
@@ -199,6 +185,6 @@
rtc::scoped_refptr<AudioState> AudioState::Create(
const AudioState::Config& config) {
- return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
+ return new rtc::RefCountedObject<internal::AudioState>(config);
}
} // namespace webrtc
diff --git a/audio/audio_state.h b/audio/audio_state.h
index 9e302c4..60250da 100644
--- a/audio/audio_state.h
+++ b/audio/audio_state.h
@@ -18,9 +18,9 @@
#include "audio/audio_transport_impl.h"
#include "audio/null_audio_poller.h"
#include "call/audio_state.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/refcount.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/ref_count.h"
#include "rtc_base/thread_checker.h"
namespace webrtc {
@@ -30,7 +30,7 @@
namespace internal {
-class AudioState final : public webrtc::AudioState {
+class AudioState : public webrtc::AudioState {
public:
explicit AudioState(const AudioState::Config& config);
~AudioState() override;
@@ -60,10 +60,6 @@
void RemoveSendingStream(webrtc::AudioSendStream* stream);
private:
- // rtc::RefCountInterface implementation.
- void AddRef() const override;
- rtc::RefCountReleaseStatus Release() const override;
-
void UpdateAudioTransportWithSendingStreams();
rtc::ThreadChecker thread_checker_;
@@ -72,10 +68,6 @@
bool recording_enabled_ = true;
bool playout_enabled_ = true;
- // Reference count; implementation copied from rtc::RefCountedObject.
- // TODO(nisse): Use RefCountedObject or RefCountedBase instead.
- mutable volatile int ref_count_ = 0;
-
// Transports mixed audio from the mixer to the audio device and
// recorded audio to the sending streams.
AudioTransportImpl audio_transport_;
diff --git a/audio/audio_state_unittest.cc b/audio/audio_state_unittest.cc
index dc622df..75bf4e1 100644
--- a/audio/audio_state_unittest.cc
+++ b/audio/audio_state_unittest.cc
@@ -16,7 +16,7 @@
#include "modules/audio_device/include/mock_audio_device.h"
#include "modules/audio_mixer/audio_mixer_impl.h"
#include "modules/audio_processing/include/mock_audio_processing.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "test/gtest.h"
namespace webrtc {
@@ -98,14 +98,14 @@
TEST(AudioStateTest, ConstructDestruct) {
ConfigHelper helper;
- std::unique_ptr<internal::AudioState> audio_state(
- new internal::AudioState(helper.config()));
+ rtc::scoped_refptr<internal::AudioState> audio_state(
+ new rtc::RefCountedObject<internal::AudioState>(helper.config()));
}
TEST(AudioStateTest, RecordedAudioArrivesAtSingleStream) {
ConfigHelper helper;
- std::unique_ptr<internal::AudioState> audio_state(
- new internal::AudioState(helper.config()));
+ rtc::scoped_refptr<internal::AudioState> audio_state(
+ new rtc::RefCountedObject<internal::AudioState>(helper.config()));
MockAudioSendStream stream;
audio_state->AddSendingStream(&stream, 8000, 2);
@@ -142,8 +142,8 @@
TEST(AudioStateTest, RecordedAudioArrivesAtMultipleStreams) {
ConfigHelper helper;
- std::unique_ptr<internal::AudioState> audio_state(
- new internal::AudioState(helper.config()));
+ rtc::scoped_refptr<internal::AudioState> audio_state(
+ new rtc::RefCountedObject<internal::AudioState>(helper.config()));
MockAudioSendStream stream_1;
MockAudioSendStream stream_2;
@@ -196,8 +196,9 @@
constexpr size_t kNumChannels = 2;
ConfigHelper helper;
- std::unique_ptr<internal::AudioState> audio_state(
- new internal::AudioState(helper.config()));
+ rtc::scoped_refptr<internal::AudioState> audio_state(
+ new rtc::RefCountedObject<internal::AudioState>(helper.config()));
+
audio_state->SetStereoChannelSwapping(true);
MockAudioSendStream stream;
@@ -227,8 +228,8 @@
constexpr size_t kNumChannels = 1;
ConfigHelper helper;
- std::unique_ptr<internal::AudioState> audio_state(
- new internal::AudioState(helper.config()));
+ rtc::scoped_refptr<internal::AudioState> audio_state(
+ new rtc::RefCountedObject<internal::AudioState>(helper.config()));
// Push a silent buffer -> Level stats should be zeros except for duration.
{
diff --git a/audio/audio_transport_impl.cc b/audio/audio_transport_impl.cc
index 539456e..cdbdacd 100644
--- a/audio/audio_transport_impl.cc
+++ b/audio/audio_transport_impl.cc
@@ -133,9 +133,9 @@
// Typing detection (utilizes the APM/VAD decision). We let the VAD determine
// if we're using this feature or not.
- // TODO(solenberg): is_enabled() takes a lock. Work around that.
+ // TODO(solenberg): GetConfig() takes a lock. Work around that.
bool typing_detected = false;
- if (audio_processing_->voice_detection()->is_enabled()) {
+ if (audio_processing_->GetConfig().voice_detection.enabled) {
if (audio_frame->vad_activity_ != AudioFrame::kVadUnknown) {
bool vad_active = audio_frame->vad_activity_ == AudioFrame::kVadActive;
typing_detected = typing_detection_.Process(key_pressed, vad_active);
@@ -214,7 +214,6 @@
int64_t* ntp_time_ms) {
RTC_DCHECK_EQ(bits_per_sample, 16);
RTC_DCHECK_GE(number_of_channels, 1);
- RTC_DCHECK_LE(number_of_channels, 2);
RTC_DCHECK_GE(sample_rate, AudioProcessing::NativeRate::kSampleRate8kHz);
// 100 = 1 second / data duration (10 ms).
diff --git a/audio/audio_transport_impl.h b/audio/audio_transport_impl.h
index 3a3155c..4c244a1 100644
--- a/audio/audio_transport_impl.h
+++ b/audio/audio_transport_impl.h
@@ -14,14 +14,14 @@
#include <vector>
#include "api/audio/audio_mixer.h"
+#include "api/scoped_refptr.h"
#include "audio/audio_level.h"
#include "common_audio/resampler/include/push_resampler.h"
#include "modules/audio_device/include/audio_device.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/typing_detection.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc
index 483147f..79523c8 100644
--- a/audio/channel_receive.cc
+++ b/audio/channel_receive.cc
@@ -33,16 +33,17 @@
#include "modules/rtp_rtcp/source/contributing_sources.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_minmax.h"
#include "rtc_base/race_checker.h"
#include "rtc_base/thread_checker.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/metrics.h"
namespace webrtc {
@@ -51,50 +52,32 @@
namespace {
constexpr double kAudioSampleDurationSeconds = 0.01;
-constexpr int64_t kMaxRetransmissionWindowMs = 1000;
-constexpr int64_t kMinRetransmissionWindowMs = 30;
// Video Sync.
constexpr int kVoiceEngineMinMinPlayoutDelayMs = 0;
constexpr int kVoiceEngineMaxMinPlayoutDelayMs = 10000;
-webrtc::FrameType WebrtcFrameTypeForMediaTransportFrameType(
- MediaTransportEncodedAudioFrame::FrameType frame_type) {
- switch (frame_type) {
- case MediaTransportEncodedAudioFrame::FrameType::kSpeech:
- return kAudioFrameSpeech;
- break;
-
- case MediaTransportEncodedAudioFrame::FrameType::
- kDiscountinuousTransmission:
- return kAudioFrameCN;
- break;
- }
-}
-
-WebRtcRTPHeader CreateWebrtcRTPHeaderForMediaTransportFrame(
+RTPHeader CreateRTPHeaderForMediaTransportFrame(
const MediaTransportEncodedAudioFrame& frame,
uint64_t channel_id) {
- webrtc::WebRtcRTPHeader webrtc_header = {};
- webrtc_header.header.payloadType = frame.payload_type();
- webrtc_header.header.payload_type_frequency = frame.sampling_rate_hz();
- webrtc_header.header.timestamp = frame.starting_sample_index();
- webrtc_header.header.sequenceNumber = frame.sequence_number();
+ webrtc::RTPHeader rtp_header;
+ rtp_header.payloadType = frame.payload_type();
+ rtp_header.payload_type_frequency = frame.sampling_rate_hz();
+ rtp_header.timestamp = frame.starting_sample_index();
+ rtp_header.sequenceNumber = frame.sequence_number();
- webrtc_header.frameType =
- WebrtcFrameTypeForMediaTransportFrameType(frame.frame_type());
-
- webrtc_header.header.ssrc = static_cast<uint32_t>(channel_id);
+ rtp_header.ssrc = static_cast<uint32_t>(channel_id);
// The rest are initialized by the RTPHeader constructor.
- return webrtc_header;
+ return rtp_header;
}
class ChannelReceive : public ChannelReceiveInterface,
public MediaTransportAudioSinkInterface {
public:
// Used for receive streams.
- ChannelReceive(ProcessThread* module_process_thread,
+ ChannelReceive(Clock* clock,
+ ProcessThread* module_process_thread,
AudioDeviceModule* audio_device_module,
MediaTransportInterface* media_transport,
Transport* rtcp_send_transport,
@@ -103,6 +86,7 @@
size_t jitter_buffer_max_packets,
bool jitter_buffer_fast_playout,
int jitter_buffer_min_delay_ms,
+ bool jitter_buffer_enable_rtx_handling,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
absl::optional<AudioCodecPairId> codec_pair_id,
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor,
@@ -119,7 +103,8 @@
void StopPlayout() override;
// Codecs
- bool GetRecCodec(CodecInst* codec) const override;
+ absl::optional<std::pair<int, SdpAudioFormat>>
+ GetReceiveCodec() const override;
bool ReceivedRTCPPacket(const uint8_t* data, size_t length) override;
@@ -143,6 +128,10 @@
void SetMinimumPlayoutDelay(int delayMs) override;
uint32_t GetPlayoutTimestamp() const override;
+ // Audio quality.
+ bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override;
+ int GetBaseMinimumPlayoutDelayMs() const override;
+
// Produces the transport-related timestamps; current_delay_ms is left unset.
absl::optional<Syncable::Info> GetSyncInfo() const override;
@@ -184,7 +173,7 @@
int32_t OnReceivedPayloadData(const uint8_t* payloadData,
size_t payloadSize,
- const WebRtcRTPHeader* rtpHeader);
+ const RTPHeader& rtpHeader);
bool Playing() const {
rtc::CritScope lock(&playing_lock_);
@@ -272,10 +261,9 @@
webrtc::CryptoOptions crypto_options_;
};
-int32_t ChannelReceive::OnReceivedPayloadData(
- const uint8_t* payloadData,
- size_t payloadSize,
- const WebRtcRTPHeader* rtpHeader) {
+int32_t ChannelReceive::OnReceivedPayloadData(const uint8_t* payloadData,
+ size_t payloadSize,
+ const RTPHeader& rtp_header) {
// We should not be receiving any RTP packets if media_transport is set.
RTC_CHECK(!media_transport_);
@@ -286,7 +274,7 @@
}
// Push the incoming payload (parsed and ready for decoding) into the ACM
- if (audio_coding_->IncomingPacket(payloadData, payloadSize, *rtpHeader) !=
+ if (audio_coding_->IncomingPacket(payloadData, payloadSize, rtp_header) !=
0) {
RTC_DLOG(LS_ERROR) << "ChannelReceive::OnReceivedPayloadData() unable to "
"push data to the ACM";
@@ -319,8 +307,7 @@
// Send encoded audio frame to Decoder / NetEq.
if (audio_coding_->IncomingPacket(
frame.encoded_data().data(), frame.encoded_data().size(),
- CreateWebrtcRTPHeaderForMediaTransportFrame(frame, channel_id)) !=
- 0) {
+ CreateRTPHeaderForMediaTransportFrame(frame, channel_id)) != 0) {
RTC_DLOG(LS_ERROR) << "ChannelReceive::OnData: unable to "
"push data to the ACM";
}
@@ -442,6 +429,7 @@
}
ChannelReceive::ChannelReceive(
+ Clock* clock,
ProcessThread* module_process_thread,
AudioDeviceModule* audio_device_module,
MediaTransportInterface* media_transport,
@@ -451,16 +439,16 @@
size_t jitter_buffer_max_packets,
bool jitter_buffer_fast_playout,
int jitter_buffer_min_delay_ms,
+ bool jitter_buffer_enable_rtx_handling,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
absl::optional<AudioCodecPairId> codec_pair_id,
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor,
const webrtc::CryptoOptions& crypto_options)
: event_log_(rtc_event_log),
- rtp_receive_statistics_(
- ReceiveStatistics::Create(Clock::GetRealTimeClock())),
+ rtp_receive_statistics_(ReceiveStatistics::Create(clock)),
remote_ssrc_(remote_ssrc),
_outputAudioLevel(),
- ntp_estimator_(Clock::GetRealTimeClock()),
+ ntp_estimator_(clock),
playout_timestamp_rtp_(0),
playout_delay_ms_(0),
rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
@@ -485,12 +473,15 @@
acm_config.neteq_config.enable_fast_accelerate = jitter_buffer_fast_playout;
acm_config.neteq_config.min_delay_ms = jitter_buffer_min_delay_ms;
acm_config.neteq_config.enable_muted_state = true;
+ acm_config.neteq_config.enable_rtx_handling =
+ jitter_buffer_enable_rtx_handling;
audio_coding_.reset(AudioCodingModule::Create(acm_config));
_outputAudioLevel.Clear();
rtp_receive_statistics_->EnableRetransmitDetection(remote_ssrc_, true);
RtpRtcp::Configuration configuration;
+ configuration.clock = clock;
configuration.audio = true;
configuration.receiver_only = true;
configuration.outgoing_transport = rtcp_send_transport;
@@ -552,9 +543,10 @@
_outputAudioLevel.Clear();
}
-bool ChannelReceive::GetRecCodec(CodecInst* codec) const {
+absl::optional<std::pair<int, SdpAudioFormat>>
+ ChannelReceive::GetReceiveCodec() const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- return (audio_coding_->ReceiveCodec(codec) == 0);
+ return audio_coding_->ReceiveCodec();
}
std::vector<webrtc::RtpSource> ChannelReceive::GetSources() const {
@@ -628,8 +620,6 @@
const uint8_t* payload = packet + header.headerLength;
assert(packet_length >= header.headerLength);
size_t payload_length = packet_length - header.headerLength;
- WebRtcRTPHeader webrtc_rtp_header = {};
- webrtc_rtp_header.header = header;
size_t payload_data_length = payload_length - header.paddingLength;
@@ -668,11 +658,9 @@
}
if (payload_data_length == 0) {
- webrtc_rtp_header.frameType = kEmptyFrame;
- return OnReceivedPayloadData(nullptr, 0, &webrtc_rtp_header);
+ return OnReceivedPayloadData(nullptr, 0, header);
}
- return OnReceivedPayloadData(payload, payload_data_length,
- &webrtc_rtp_header);
+ return OnReceivedPayloadData(payload, payload_data_length, header);
}
// May be called on either worker thread or network thread.
@@ -690,13 +678,6 @@
return true;
}
- int64_t nack_window_ms = rtt;
- if (nack_window_ms < kMinRetransmissionWindowMs) {
- nack_window_ms = kMinRetransmissionWindowMs;
- } else if (nack_window_ms > kMaxRetransmissionWindowMs) {
- nack_window_ms = kMaxRetransmissionWindowMs;
- }
-
uint32_t ntp_secs = 0;
uint32_t ntp_frac = 0;
uint32_t rtp_timestamp = 0;
@@ -802,11 +783,14 @@
void ChannelReceive::SetNACKStatus(bool enable, int max_packets) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
// None of these functions can fail.
- rtp_receive_statistics_->SetMaxReorderingThreshold(max_packets);
- if (enable)
+ if (enable) {
+ rtp_receive_statistics_->SetMaxReorderingThreshold(max_packets);
audio_coding_->EnableNack(max_packets);
- else
+ } else {
+ rtp_receive_statistics_->SetMaxReorderingThreshold(
+ kDefaultMaxReorderingThreshold);
audio_coding_->DisableNack();
+ }
}
// Called when we are missing one or more packets.
@@ -848,12 +832,8 @@
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 = rtc::SafeClamp(delay_ms, 0, 10000);
- if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
- (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs)) {
- RTC_DLOG(LS_ERROR) << "SetMinimumPlayoutDelay() invalid min delay";
- return;
- }
+ delay_ms = rtc::SafeClamp(delay_ms, kVoiceEngineMinMinPlayoutDelayMs,
+ kVoiceEngineMaxMinPlayoutDelayMs);
if (audio_coding_->SetMinimumPlayoutDelay(delay_ms) != 0) {
RTC_DLOG(LS_ERROR)
<< "SetMinimumPlayoutDelay() failed to set min playout delay";
@@ -868,6 +848,14 @@
}
}
+bool ChannelReceive::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
+ return audio_coding_->SetBaseMinimumPlayoutDelayMs(delay_ms);
+}
+
+int ChannelReceive::GetBaseMinimumPlayoutDelayMs() const {
+ return audio_coding_->GetBaseMinimumPlayoutDelayMs();
+}
+
absl::optional<Syncable::Info> ChannelReceive::GetSyncInfo() const {
RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread());
Syncable::Info info;
@@ -920,13 +908,13 @@
}
int ChannelReceive::GetRtpTimestampRateHz() const {
- const auto format = audio_coding_->ReceiveFormat();
+ const auto decoder = audio_coding_->ReceiveCodec();
// Default to the playout frequency if we've not gotten any packets yet.
// TODO(ossu): Zero clockrate can only happen if we've added an external
// decoder for a format we don't support internally. Remove once that way of
// adding decoders is gone!
- return (format && format->clockrate_hz != 0)
- ? format->clockrate_hz
+ return (decoder && decoder->second.clockrate_hz != 0)
+ ? decoder->second.clockrate_hz
: audio_coding_->PlayoutFrequency();
}
@@ -973,6 +961,7 @@
} // namespace
std::unique_ptr<ChannelReceiveInterface> CreateChannelReceive(
+ Clock* clock,
ProcessThread* module_process_thread,
AudioDeviceModule* audio_device_module,
MediaTransportInterface* media_transport,
@@ -982,16 +971,17 @@
size_t jitter_buffer_max_packets,
bool jitter_buffer_fast_playout,
int jitter_buffer_min_delay_ms,
+ bool jitter_buffer_enable_rtx_handling,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
absl::optional<AudioCodecPairId> codec_pair_id,
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor,
const webrtc::CryptoOptions& crypto_options) {
return absl::make_unique<ChannelReceive>(
- module_process_thread, audio_device_module, media_transport,
+ clock, module_process_thread, audio_device_module, media_transport,
rtcp_send_transport, rtc_event_log, remote_ssrc,
jitter_buffer_max_packets, jitter_buffer_fast_playout,
- jitter_buffer_min_delay_ms, decoder_factory, codec_pair_id,
- frame_decryptor, crypto_options);
+ jitter_buffer_min_delay_ms, jitter_buffer_enable_rtx_handling,
+ decoder_factory, codec_pair_id, frame_decryptor, crypto_options);
}
} // namespace voe
diff --git a/audio/channel_receive.h b/audio/channel_receive.h
index 9027623..b3e4f9c 100644
--- a/audio/channel_receive.h
+++ b/audio/channel_receive.h
@@ -13,6 +13,7 @@
#include <map>
#include <memory>
+#include <utility>
#include <vector>
#include "absl/types/optional.h"
@@ -20,9 +21,9 @@
#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/call/audio_sink.h"
#include "api/call/transport.h"
-#include "api/crypto/cryptooptions.h"
+#include "api/crypto/crypto_options.h"
#include "api/media_transport_interface.h"
-#include "api/rtpreceiverinterface.h"
+#include "api/rtp_receiver_interface.h"
#include "call/rtp_packet_sink_interface.h"
#include "call/syncable.h"
#include "modules/audio_coding/include/audio_coding_module.h"
@@ -79,7 +80,9 @@
virtual void StartPlayout() = 0;
virtual void StopPlayout() = 0;
- virtual bool GetRecCodec(CodecInst* codec) const = 0;
+ // Payload type and format of last received RTP packet, if any.
+ virtual absl::optional<std::pair<int, SdpAudioFormat>>
+ GetReceiveCodec() const = 0;
virtual bool ReceivedRTCPPacket(const uint8_t* data, size_t length) = 0;
@@ -99,6 +102,12 @@
virtual void SetMinimumPlayoutDelay(int delay_ms) = 0;
virtual uint32_t GetPlayoutTimestamp() const = 0;
+ // Audio quality.
+ // Base minimum delay sets lower bound on minimum delay value which
+ // determines minimum delay until audio playout.
+ virtual bool SetBaseMinimumPlayoutDelayMs(int delay_ms) = 0;
+ virtual int GetBaseMinimumPlayoutDelayMs() const = 0;
+
// Produces the transport-related timestamps; current_delay_ms is left unset.
virtual absl::optional<Syncable::Info> GetSyncInfo() const = 0;
@@ -127,6 +136,7 @@
};
std::unique_ptr<ChannelReceiveInterface> CreateChannelReceive(
+ Clock* clock,
ProcessThread* module_process_thread,
AudioDeviceModule* audio_device_module,
MediaTransportInterface* media_transport,
@@ -136,6 +146,7 @@
size_t jitter_buffer_max_packets,
bool jitter_buffer_fast_playout,
int jitter_buffer_min_delay_ms,
+ bool jitter_buffer_enable_rtx_handling,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
absl::optional<AudioCodecPairId> codec_pair_id,
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor,
diff --git a/audio/channel_send.cc b/audio/channel_send.cc
index c458fe4..0c8be1f 100644
--- a/audio/channel_send.cc
+++ b/audio/channel_send.cc
@@ -20,7 +20,7 @@
#include "absl/memory/memory.h"
#include "api/array_view.h"
#include "api/call/transport.h"
-#include "api/crypto/frameencryptorinterface.h"
+#include "api/crypto/frame_encryptor_interface.h"
#include "audio/utility/audio_frame_operations.h"
#include "call/rtp_transport_controller_send_interface.h"
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
@@ -31,7 +31,7 @@
#include "modules/pacing/packet_router.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/location.h"
@@ -41,7 +41,8 @@
#include "rtc_base/rate_limiter.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread_checker.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
+#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/field_trial.h"
#include "system_wrappers/include/metrics.h"
@@ -78,8 +79,6 @@
class ChannelSend
: public ChannelSendInterface,
- public Transport,
- public OverheadObserver,
public AudioPacketizationCallback, // receive encoded packets from the
// ACM
public TargetTransferRateObserver {
@@ -88,9 +87,11 @@
// declaration.
friend class VoERtcpObserver;
- ChannelSend(rtc::TaskQueue* encoder_queue,
+ ChannelSend(Clock* clock,
+ rtc::TaskQueue* encoder_queue,
ProcessThread* module_process_thread,
MediaTransportInterface* media_transport,
+ OverheadObserver* overhead_observer,
Transport* rtp_transport,
RtcpRttStats* rtcp_rtt_stats,
RtcEventLog* rtc_event_log,
@@ -106,6 +107,7 @@
std::unique_ptr<AudioEncoder> encoder) override;
void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)>
modifier) override;
+ void CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) override;
// API methods
void StartSend() override;
@@ -134,6 +136,9 @@
// RTP+RTCP
void SetLocalSSRC(uint32_t ssrc) override;
+ void SetRid(const std::string& rid,
+ int extension_id,
+ int repaired_extension_id) override;
void SetMid(const std::string& mid, int extension_id) override;
void SetExtmapAllowMixed(bool extmap_allow_mixed) override;
void SetSendAudioLevelIndicationStatus(bool enable, int id) override;
@@ -158,8 +163,6 @@
// packet.
void ProcessAndEncodeAudio(std::unique_ptr<AudioFrame> audio_frame) override;
- void SetTransportOverhead(size_t transport_overhead_per_packet) override;
-
// The existence of this function alongside OnUplinkPacketLossRate is
// a compromise. We want the encoder to be agnostic of the PLR source, but
// we also don't want it to receive conflicting information from TWCC and
@@ -186,23 +189,11 @@
size_t payloadSize,
const RTPFragmentationHeader* fragmentation) override;
- // From Transport (called by the RTP/RTCP module)
- bool SendRtp(const uint8_t* data,
- size_t len,
- const PacketOptions& packet_options) override;
- bool SendRtcp(const uint8_t* data, size_t len) override;
-
- // From OverheadObserver in the RTP/RTCP module
- void OnOverheadChanged(size_t overhead_bytes_per_packet) override;
-
void OnUplinkPacketLossRate(float packet_loss_rate);
bool InputMute() const;
int SetSendRtpHeaderExtension(bool enable, RTPExtensionType type, int id);
- void UpdateOverheadForEncoder()
- RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_);
-
int32_t SendRtpAudio(FrameType frameType,
uint8_t payloadType,
uint32_t timeStamp,
@@ -238,7 +229,6 @@
// audio thread to another, but access is still sequential.
rtc::RaceChecker audio_thread_race_checker_;
- rtc::CriticalSection _callbackCritSect;
rtc::CriticalSection volume_settings_critsect_;
bool sending_ RTC_GUARDED_BY(&worker_thread_checker_) = false;
@@ -250,11 +240,8 @@
std::unique_ptr<AudioCodingModule> audio_coding_;
uint32_t _timeStamp RTC_GUARDED_BY(encoder_queue_);
- uint16_t send_sequence_number_;
-
// uses
ProcessThread* const _moduleProcessThreadPtr;
- Transport* const _transportPtr; // WebRtc socket or external transport
RmsLevel rms_level_ RTC_GUARDED_BY(encoder_queue_);
bool input_mute_ RTC_GUARDED_BY(volume_settings_critsect_);
bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_);
@@ -262,10 +249,7 @@
// TODO(henrika): can today be accessed on the main thread and on the
// task queue; hence potential race.
bool _includeAudioLevelIndication;
- size_t transport_overhead_per_packet_
- RTC_GUARDED_BY(overhead_per_packet_lock_);
- size_t rtp_overhead_per_packet_ RTC_GUARDED_BY(overhead_per_packet_lock_);
- rtc::CriticalSection overhead_per_packet_lock_;
+
// RtcpBandwidthObserver
const std::unique_ptr<VoERtcpObserver> rtcp_observer_;
@@ -416,7 +400,7 @@
public:
explicit VoERtcpObserver(ChannelSend* owner)
: owner_(owner), bandwidth_observer_(nullptr) {}
- virtual ~VoERtcpObserver() {}
+ ~VoERtcpObserver() override {}
void SetBandwidthObserver(RtcpBandwidthObserver* bandwidth_observer) {
rtc::CritScope lock(&crit_);
@@ -515,6 +499,12 @@
rtc::ArrayView<const uint8_t> payload(payloadData, payloadSize);
if (media_transport() != nullptr) {
+ if (frameType == kEmptyFrame) {
+ // TODO(bugs.webrtc.org/9719): Media transport Send doesn't support
+ // sending empty frames.
+ return 0;
+ }
+
return SendMediaTransportAudio(frameType, payloadType, timeStamp, payload,
fragmentation);
} else {
@@ -606,7 +596,7 @@
sampling_rate_hz = media_transport_sampling_frequency_;
channel_id = media_transport_channel_id_;
}
- const MediaTransportEncodedAudioFrame frame(
+ MediaTransportEncodedAudioFrame frame(
/*sampling_rate_hz=*/sampling_rate_hz,
// TODO(nisse): Timestamp and sample index are the same for all supported
@@ -641,48 +631,11 @@
return 0;
}
-bool ChannelSend::SendRtp(const uint8_t* data,
- size_t len,
- const PacketOptions& options) {
- // We should not be sending RTP packets if media transport is available.
- RTC_CHECK(!media_transport());
-
- rtc::CritScope cs(&_callbackCritSect);
-
- if (_transportPtr == NULL) {
- RTC_DLOG(LS_ERROR)
- << "ChannelSend::SendPacket() failed to send RTP packet due to"
- << " invalid transport object";
- return false;
- }
-
- if (!_transportPtr->SendRtp(data, len, options)) {
- RTC_DLOG(LS_ERROR) << "ChannelSend::SendPacket() RTP transmission failed";
- return false;
- }
- return true;
-}
-
-bool ChannelSend::SendRtcp(const uint8_t* data, size_t len) {
- rtc::CritScope cs(&_callbackCritSect);
- if (_transportPtr == NULL) {
- RTC_DLOG(LS_ERROR)
- << "ChannelSend::SendRtcp() failed to send RTCP packet due to"
- << " invalid transport object";
- return false;
- }
-
- int n = _transportPtr->SendRtcp(data, len);
- if (n < 0) {
- RTC_DLOG(LS_ERROR) << "ChannelSend::SendRtcp() transmission failed";
- return false;
- }
- return true;
-}
-
-ChannelSend::ChannelSend(rtc::TaskQueue* encoder_queue,
+ChannelSend::ChannelSend(Clock* clock,
+ rtc::TaskQueue* encoder_queue,
ProcessThread* module_process_thread,
MediaTransportInterface* media_transport,
+ OverheadObserver* overhead_observer,
Transport* rtp_transport,
RtcpRttStats* rtcp_rtt_stats,
RtcEventLog* rtc_event_log,
@@ -693,20 +646,16 @@
: event_log_(rtc_event_log),
_timeStamp(0), // This is just an offset, RTP module will add it's own
// random offset
- send_sequence_number_(0),
_moduleProcessThreadPtr(module_process_thread),
- _transportPtr(rtp_transport),
input_mute_(false),
previous_frame_muted_(false),
_includeAudioLevelIndication(false),
- transport_overhead_per_packet_(0),
- rtp_overhead_per_packet_(0),
rtcp_observer_(new VoERtcpObserver(this)),
feedback_observer_proxy_(new TransportFeedbackProxy()),
seq_num_allocator_proxy_(new TransportSequenceNumberProxy()),
rtp_packet_sender_proxy_(new RtpPacketSenderProxy()),
- retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(),
- kMaxRetransmissionWindowMs)),
+ retransmission_rate_limiter_(
+ new RateLimiter(clock, kMaxRetransmissionWindowMs)),
use_twcc_plr_for_ana_(
webrtc::field_trial::FindFullName("UseTwccPlrForAna") == "Enabled"),
encoder_queue_(encoder_queue),
@@ -726,13 +675,19 @@
// RTPMediaTransport. In this case it means that overhead and bandwidth
// observers should not be called when using media transport.
if (!media_transport_) {
- configuration.overhead_observer = this;
+ // TODO(sukhanov): Overhead observer is only needed for RTP path, because in
+ // media transport audio overhead is currently considered constant (see
+ // getter MediaTransportInterface::GetAudioPacketOverhead). In the future
+ // when we introduce RTP media transport we should make audio overhead
+ // interface consistent and work for both RTP and non-RTP implementations.
+ configuration.overhead_observer = overhead_observer;
configuration.bandwidth_callback = rtcp_observer_.get();
configuration.transport_feedback_callback = feedback_observer_proxy_.get();
}
+ configuration.clock = clock;
configuration.audio = true;
- configuration.outgoing_transport = this;
+ configuration.outgoing_transport = rtp_transport;
configuration.paced_sender = rtp_packet_sender_proxy_.get();
configuration.transport_sequence_number_allocator =
@@ -753,7 +708,6 @@
if (media_transport_) {
RTC_DLOG(LS_INFO) << "Setting media_transport_ rate observers.";
media_transport_->AddTargetTransferRateObserver(this);
- OnOverheadChanged(media_transport_->GetAudioPacketOverhead());
} else {
RTC_DLOG(LS_INFO) << "Not setting media_transport_ rate observers.";
}
@@ -780,7 +734,6 @@
}
StopSend();
-
int error = audio_coding_->RegisterTransportCallback(NULL);
RTC_DCHECK_EQ(0, error);
@@ -793,11 +746,6 @@
RTC_DCHECK(!sending_);
sending_ = true;
- // Resume the previous sequence number which was reset by StopSend(). This
- // needs to be done before |sending| is set to true on the RTP/RTCP module.
- if (send_sequence_number_) {
- _rtpRtcpModule->SetSequenceNumber(send_sequence_number_);
- }
_rtpRtcpModule->SetSendingMediaStatus(true);
int ret = _rtpRtcpModule->SetSendingStatus(true);
RTC_DCHECK_EQ(0, ret);
@@ -833,14 +781,6 @@
}
flush.Wait(rtc::Event::kForever);
- // Store the sequence number to be able to pick up the same sequence for
- // the next StartSend(). This is needed for restarting device, otherwise
- // it might cause libSRTP to complain about packets being replayed.
- // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
- // CL is landed. See issue
- // https://code.google.com/p/webrtc/issues/detail?id=2111 .
- send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
-
// Reset sending SSRC and sequence number and triggers direct transmission
// of RTCP BYE
if (_rtpRtcpModule->SetSendingStatus(false) == -1) {
@@ -854,33 +794,14 @@
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RTC_DCHECK_GE(payload_type, 0);
RTC_DCHECK_LE(payload_type, 127);
- // TODO(ossu): Make CodecInsts up, for now: one for the RTP/RTCP module and
- // one for for us to keep track of sample rate and number of channels, etc.
// The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate)
// as well as some other things, so we collect this info and send it along.
- CodecInst rtp_codec;
- rtp_codec.pltype = payload_type;
- strncpy(rtp_codec.plname, "audio", sizeof(rtp_codec.plname));
- rtp_codec.plname[sizeof(rtp_codec.plname) - 1] = 0;
- // Seems unclear if it should be clock rate or sample rate. CodecInst
- // supposedly carries the sample rate, but only clock rate seems sensible to
- // send to the RTP/RTCP module.
- rtp_codec.plfreq = encoder->RtpTimestampRateHz();
- rtp_codec.pacsize = rtc::CheckedDivExact(
- static_cast<int>(encoder->Max10MsFramesInAPacket() * rtp_codec.plfreq),
- 100);
- rtp_codec.channels = encoder->NumChannels();
- rtp_codec.rate = 0;
-
- if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) {
- _rtpRtcpModule->DeRegisterSendPayload(payload_type);
- if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) {
- RTC_DLOG(LS_ERROR)
- << "SetEncoder() failed to register codec to RTP/RTCP module";
- return false;
- }
- }
+ _rtpRtcpModule->RegisterAudioSendPayload(payload_type,
+ "audio",
+ encoder->RtpTimestampRateHz(),
+ encoder->NumChannels(),
+ 0);
if (media_transport_) {
rtc::CritScope cs(&media_transport_lock_);
@@ -895,10 +816,22 @@
void ChannelSend::ModifyEncoder(
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) {
- RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+ // This method can be called on the worker thread, module process thread
+ // or network thread. Audio coding is thread safe, so we do not need to
+ // enforce the calling thread.
audio_coding_->ModifyEncoder(modifier);
}
+void ChannelSend::CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) {
+ ModifyEncoder([modifier](std::unique_ptr<AudioEncoder>* encoder_ptr) {
+ if (*encoder_ptr) {
+ modifier(encoder_ptr->get());
+ } else {
+ RTC_DLOG(LS_WARNING) << "Trying to call unset encoder.";
+ }
+ });
+}
+
void ChannelSend::OnBitrateAllocation(BitrateAllocationUpdate update) {
// This method can be called on the worker thread, module process thread
// or on a TaskQueue via VideoSendStreamImpl::OnEncoderConfigurationChanged.
@@ -908,10 +841,8 @@
// module_process_thread_checker_.CalledOnValidThread());
rtc::CritScope lock(&bitrate_crit_section_);
- audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedUplinkAllocation(update);
- }
+ CallEncoder([&](AudioEncoder* encoder) {
+ encoder->OnReceivedUplinkAllocation(update);
});
retransmission_rate_limiter_->SetMaxRate(update.target_bitrate.bps());
configured_bitrate_bps_ = update.target_bitrate.bps();
@@ -926,31 +857,25 @@
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
if (!use_twcc_plr_for_ana_)
return;
- audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
- }
+ CallEncoder([&](AudioEncoder* encoder) {
+ encoder->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
});
}
void ChannelSend::OnRecoverableUplinkPacketLossRate(
float recoverable_packet_loss_rate) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
- audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedUplinkRecoverablePacketLossFraction(
- recoverable_packet_loss_rate);
- }
+ CallEncoder([&](AudioEncoder* encoder) {
+ encoder->OnReceivedUplinkRecoverablePacketLossFraction(
+ recoverable_packet_loss_rate);
});
}
void ChannelSend::OnUplinkPacketLossRate(float packet_loss_rate) {
if (use_twcc_plr_for_ana_)
return;
- audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
- }
+ CallEncoder([&](AudioEncoder* encoder) {
+ encoder->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
});
}
@@ -1017,19 +942,8 @@
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RTC_DCHECK_LE(0, payload_type);
RTC_DCHECK_GE(127, payload_type);
- CodecInst codec = {0};
- codec.pltype = payload_type;
- codec.plfreq = payload_frequency;
- memcpy(codec.plname, "telephone-event", 16);
- if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
- _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
- if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
- RTC_DLOG(LS_ERROR)
- << "SetSendTelephoneEventPayloadType() failed to register "
- "send payload type";
- return false;
- }
- }
+ _rtpRtcpModule->RegisterAudioSendPayload(payload_type, "telephone-event",
+ payload_frequency, 0, 0);
return true;
}
@@ -1044,6 +958,23 @@
_rtpRtcpModule->SetSSRC(ssrc);
}
+void ChannelSend::SetRid(const std::string& rid,
+ int extension_id,
+ int repaired_extension_id) {
+ RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+ if (extension_id != 0) {
+ int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId,
+ extension_id);
+ RTC_DCHECK_EQ(0, ret);
+ }
+ if (repaired_extension_id != 0) {
+ int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId,
+ repaired_extension_id);
+ RTC_DCHECK_EQ(0, ret);
+ }
+ _rtpRtcpModule->SetRid(rid);
+}
+
void ChannelSend::SetMid(const std::string& mid, int extension_id) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id);
@@ -1220,30 +1151,6 @@
_timeStamp += static_cast<uint32_t>(audio_input->samples_per_channel_);
}
-void ChannelSend::UpdateOverheadForEncoder() {
- size_t overhead_per_packet =
- transport_overhead_per_packet_ + rtp_overhead_per_packet_;
- audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedOverhead(overhead_per_packet);
- }
- });
-}
-
-void ChannelSend::SetTransportOverhead(size_t transport_overhead_per_packet) {
- RTC_DCHECK_RUN_ON(&worker_thread_checker_);
- rtc::CritScope cs(&overhead_per_packet_lock_);
- transport_overhead_per_packet_ = transport_overhead_per_packet;
- UpdateOverheadForEncoder();
-}
-
-// TODO(solenberg): Make AudioSendStream an OverheadObserver instead.
-void ChannelSend::OnOverheadChanged(size_t overhead_bytes_per_packet) {
- rtc::CritScope cs(&overhead_per_packet_lock_);
- rtp_overhead_per_packet_ = overhead_bytes_per_packet;
- UpdateOverheadForEncoder();
-}
-
ANAStats ChannelSend::GetANAStatistics() const {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
return audio_coding_->GetANAStats();
@@ -1310,7 +1217,7 @@
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
rtc::CritScope cs(&encoder_queue_lock_);
if (encoder_queue_is_active_) {
- encoder_queue_->PostTask([this, frame_encryptor]() {
+ encoder_queue_->PostTask([this, frame_encryptor]() mutable {
this->frame_encryptor_ = std::move(frame_encryptor);
});
} else {
@@ -1318,6 +1225,9 @@
}
}
+// TODO(sukhanov): Consider moving TargetTransferRate observer to
+// AudioSendStream. Since AudioSendStream owns encoder and configures ANA, it
+// makes sense to consolidate all rate (and overhead) calculation there.
void ChannelSend::OnTargetTransferRate(TargetTransferRate rate) {
RTC_DCHECK(media_transport_);
OnReceivedRtt(rate.network_estimate.round_trip_time.ms());
@@ -1325,20 +1235,18 @@
void ChannelSend::OnReceivedRtt(int64_t rtt_ms) {
// Invoke audio encoders OnReceivedRtt().
- audio_coding_->ModifyEncoder(
- [rtt_ms](std::unique_ptr<AudioEncoder>* encoder) {
- if (*encoder) {
- (*encoder)->OnReceivedRtt(rtt_ms);
- }
- });
+ CallEncoder(
+ [rtt_ms](AudioEncoder* encoder) { encoder->OnReceivedRtt(rtt_ms); });
}
} // namespace
std::unique_ptr<ChannelSendInterface> CreateChannelSend(
+ Clock* clock,
rtc::TaskQueue* encoder_queue,
ProcessThread* module_process_thread,
MediaTransportInterface* media_transport,
+ OverheadObserver* overhead_observer,
Transport* rtp_transport,
RtcpRttStats* rtcp_rtt_stats,
RtcEventLog* rtc_event_log,
@@ -1347,9 +1255,10 @@
bool extmap_allow_mixed,
int rtcp_report_interval_ms) {
return absl::make_unique<ChannelSend>(
- encoder_queue, module_process_thread, media_transport, rtp_transport,
- rtcp_rtt_stats, rtc_event_log, frame_encryptor, crypto_options,
- extmap_allow_mixed, rtcp_report_interval_ms);
+ clock, encoder_queue, module_process_thread, media_transport,
+ overhead_observer, rtp_transport, rtcp_rtt_stats, rtc_event_log,
+ frame_encryptor, crypto_options, extmap_allow_mixed,
+ rtcp_report_interval_ms);
}
} // namespace voe
diff --git a/audio/channel_send.h b/audio/channel_send.h
index 083e9a6..4ab53c0 100644
--- a/audio/channel_send.h
+++ b/audio/channel_send.h
@@ -17,7 +17,7 @@
#include "api/audio/audio_frame.h"
#include "api/audio_codecs/audio_encoder.h"
-#include "api/crypto/cryptooptions.h"
+#include "api/crypto/crypto_options.h"
#include "api/media_transport_interface.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "rtc_base/function_view.h"
@@ -63,8 +63,13 @@
std::unique_ptr<AudioEncoder> encoder) = 0;
virtual void ModifyEncoder(
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) = 0;
+ virtual void CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) = 0;
virtual void SetLocalSSRC(uint32_t ssrc) = 0;
+ // Use 0 to indicate that the extension should not be registered.
+ virtual void SetRid(const std::string& rid,
+ int extension_id,
+ int repaired_extension_id) = 0;
virtual void SetMid(const std::string& mid, int extension_id) = 0;
virtual void SetRTCP_CNAME(absl::string_view c_name) = 0;
virtual void SetExtmapAllowMixed(bool extmap_allow_mixed) = 0;
@@ -85,7 +90,6 @@
virtual void ProcessAndEncodeAudio(
std::unique_ptr<AudioFrame> audio_frame) = 0;
- virtual void SetTransportOverhead(size_t transport_overhead_per_packet) = 0;
virtual RtpRtcp* GetRtpRtcp() const = 0;
virtual void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) = 0;
@@ -111,9 +115,11 @@
};
std::unique_ptr<ChannelSendInterface> CreateChannelSend(
+ Clock* clock,
rtc::TaskQueue* encoder_queue,
ProcessThread* module_process_thread,
MediaTransportInterface* media_transport,
+ OverheadObserver* overhead_observer,
Transport* rtp_transport,
RtcpRttStats* rtcp_rtt_stats,
RtcEventLog* rtc_event_log,
diff --git a/audio/mock_voe_channel_proxy.h b/audio/mock_voe_channel_proxy.h
index eee25c5..a03ce7e 100644
--- a/audio/mock_voe_channel_proxy.h
+++ b/audio/mock_voe_channel_proxy.h
@@ -14,6 +14,7 @@
#include <map>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "api/test/mock_frame_encryptor.h"
@@ -52,7 +53,10 @@
MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t());
MOCK_CONST_METHOD0(GetSyncInfo, absl::optional<Syncable::Info>());
MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms));
- MOCK_CONST_METHOD1(GetRecCodec, bool(CodecInst* codec_inst));
+ MOCK_METHOD1(SetBaseMinimumPlayoutDelayMs, bool(int delay_ms));
+ MOCK_CONST_METHOD0(GetBaseMinimumPlayoutDelayMs, int());
+ MOCK_CONST_METHOD0(GetReceiveCodec,
+ absl::optional<std::pair<int, SdpAudioFormat>>());
MOCK_METHOD1(SetReceiveCodecs,
void(const std::map<int, SdpAudioFormat>& codecs));
MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>());
@@ -72,6 +76,12 @@
MOCK_METHOD1(
ModifyEncoder,
void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier));
+ MOCK_METHOD1(CallEncoder,
+ void(rtc::FunctionView<void(AudioEncoder*)> modifier));
+ MOCK_METHOD3(SetRid,
+ void(const std::string& rid,
+ int extension_id,
+ int repaired_extension_id));
MOCK_METHOD2(SetMid, void(const std::string& mid, int extension_id));
MOCK_METHOD1(SetLocalSSRC, void(uint32_t ssrc));
MOCK_METHOD1(SetRTCP_CNAME, void(absl::string_view c_name));
diff --git a/audio/null_audio_poller.cc b/audio/null_audio_poller.cc
index d2b1199..063a367 100644
--- a/audio/null_audio_poller.cc
+++ b/audio/null_audio_poller.cc
@@ -15,7 +15,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/location.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
namespace internal {
diff --git a/audio/null_audio_poller.h b/audio/null_audio_poller.h
index f91eb7d..9a81426 100644
--- a/audio/null_audio_poller.h
+++ b/audio/null_audio_poller.h
@@ -14,8 +14,8 @@
#include <stdint.h>
#include "modules/audio_device/include/audio_device_defines.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/thread_checker.h"
namespace webrtc {
diff --git a/audio/remix_resample.cc b/audio/remix_resample.cc
index cc59e2a..e77c386 100644
--- a/audio/remix_resample.cc
+++ b/audio/remix_resample.cc
@@ -80,7 +80,7 @@
// The audio in dst_frame really is mono at this point; MonoToStereo will
// set this back to stereo.
dst_frame->num_channels_ = 1;
- AudioFrameOperations::MonoToStereo(dst_frame);
+ AudioFrameOperations::UpmixChannels(2, dst_frame);
}
}
diff --git a/audio/transport_feedback_packet_loss_tracker_unittest.cc b/audio/transport_feedback_packet_loss_tracker_unittest.cc
index f522635..cc90651 100644
--- a/audio/transport_feedback_packet_loss_tracker_unittest.cc
+++ b/audio/transport_feedback_packet_loss_tracker_unittest.cc
@@ -561,8 +561,8 @@
// to weed out potential bugs with wrap-around handling.
constexpr uint16_t kBases[] = {0x0000, 0x3456, 0xc032, 0xfffe};
-INSTANTIATE_TEST_CASE_P(_,
- TransportFeedbackPacketLossTrackerTest,
- testing::ValuesIn(kBases));
+INSTANTIATE_TEST_SUITE_P(_,
+ TransportFeedbackPacketLossTrackerTest,
+ testing::ValuesIn(kBases));
} // namespace webrtc
diff --git a/audio/utility/BUILD.gn b/audio/utility/BUILD.gn
index 11a65bd..f60b512 100644
--- a/audio/utility/BUILD.gn
+++ b/audio/utility/BUILD.gn
@@ -22,7 +22,9 @@
deps = [
"../../api/audio:audio_frame_api",
+ "../../common_audio",
"../../rtc_base:checks",
+ "../../rtc_base:deprecation",
"../../rtc_base:rtc_base_approved",
]
}
@@ -40,9 +42,5 @@
"../../test:test_support",
"//testing/gtest",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
}
diff --git a/audio/utility/audio_frame_operations.cc b/audio/utility/audio_frame_operations.cc
index 1a8232b..d3180a7 100644
--- a/audio/utility/audio_frame_operations.cc
+++ b/audio/utility/audio_frame_operations.cc
@@ -13,7 +13,9 @@
#include <string.h>
#include <algorithm>
#include <cstdint>
+#include <utility>
+#include "common_audio/include/audio_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
@@ -69,60 +71,20 @@
}
}
-void AudioFrameOperations::MonoToStereo(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio) {
- for (size_t i = 0; i < samples_per_channel; i++) {
- dst_audio[2 * i] = src_audio[i];
- dst_audio[2 * i + 1] = src_audio[i];
- }
-}
-
int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
if (frame->num_channels_ != 1) {
return -1;
}
- if ((frame->samples_per_channel_ * 2) >= AudioFrame::kMaxDataSizeSamples) {
- // Not enough memory to expand from mono to stereo.
- return -1;
- }
-
- if (!frame->muted()) {
- // TODO(yujo): this operation can be done in place.
- int16_t data_copy[AudioFrame::kMaxDataSizeSamples];
- memcpy(data_copy, frame->data(),
- sizeof(int16_t) * frame->samples_per_channel_);
- MonoToStereo(data_copy, frame->samples_per_channel_, frame->mutable_data());
- }
- frame->num_channels_ = 2;
-
+ UpmixChannels(2, frame);
return 0;
}
-void AudioFrameOperations::StereoToMono(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio) {
- for (size_t i = 0; i < samples_per_channel; i++) {
- dst_audio[i] =
- (static_cast<int32_t>(src_audio[2 * i]) + src_audio[2 * i + 1]) >> 1;
- }
-}
-
int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
if (frame->num_channels_ != 2) {
return -1;
}
-
- RTC_DCHECK_LE(frame->samples_per_channel_ * 2,
- AudioFrame::kMaxDataSizeSamples);
-
- if (!frame->muted()) {
- StereoToMono(frame->data(), frame->samples_per_channel_,
- frame->mutable_data());
- }
- frame->num_channels_ = 1;
-
- return 0;
+ DownmixChannels(1, frame);
+ return frame->num_channels_ == 1 ? 0 : -1;
}
void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
@@ -154,65 +116,66 @@
return 0;
}
-void AudioFrameOperations::QuadToMono(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio) {
- for (size_t i = 0; i < samples_per_channel; i++) {
- dst_audio[i] =
- (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] +
- src_audio[4 * i + 2] + src_audio[4 * i + 3]) >>
- 2;
- }
-}
-
-int AudioFrameOperations::QuadToMono(AudioFrame* frame) {
- if (frame->num_channels_ != 4) {
- return -1;
- }
-
- RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
- AudioFrame::kMaxDataSizeSamples);
-
- if (!frame->muted()) {
- QuadToMono(frame->data(), frame->samples_per_channel_,
- frame->mutable_data());
- }
- frame->num_channels_ = 1;
-
- return 0;
-}
-
void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
size_t src_channels,
size_t samples_per_channel,
size_t dst_channels,
int16_t* dst_audio) {
- if (src_channels == 2 && dst_channels == 1) {
- StereoToMono(src_audio, samples_per_channel, dst_audio);
+ if (src_channels > 1 && dst_channels == 1) {
+ DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels,
+ dst_audio);
return;
} else if (src_channels == 4 && dst_channels == 2) {
QuadToStereo(src_audio, samples_per_channel, dst_audio);
return;
- } else if (src_channels == 4 && dst_channels == 1) {
- QuadToMono(src_audio, samples_per_channel, dst_audio);
- return;
}
RTC_NOTREACHED() << "src_channels: " << src_channels
<< ", dst_channels: " << dst_channels;
}
-int AudioFrameOperations::DownmixChannels(size_t dst_channels,
- AudioFrame* frame) {
- if (frame->num_channels_ == 2 && dst_channels == 1) {
- return StereoToMono(frame);
+void AudioFrameOperations::DownmixChannels(size_t dst_channels,
+ AudioFrame* frame) {
+ RTC_DCHECK_LE(frame->samples_per_channel_ * frame->num_channels_,
+ AudioFrame::kMaxDataSizeSamples);
+ if (frame->num_channels_ > 1 && dst_channels == 1) {
+ if (!frame->muted()) {
+ DownmixInterleavedToMono(frame->data(), frame->samples_per_channel_,
+ frame->num_channels_, frame->mutable_data());
+ }
+ frame->num_channels_ = 1;
} else if (frame->num_channels_ == 4 && dst_channels == 2) {
- return QuadToStereo(frame);
- } else if (frame->num_channels_ == 4 && dst_channels == 1) {
- return QuadToMono(frame);
+ int err = QuadToStereo(frame);
+ RTC_DCHECK_EQ(err, 0);
+ } else {
+ RTC_NOTREACHED() << "src_channels: " << frame->num_channels_
+ << ", dst_channels: " << dst_channels;
+ }
+}
+
+void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels,
+ AudioFrame* frame) {
+ RTC_DCHECK_EQ(frame->num_channels_, 1);
+ RTC_DCHECK_LE(frame->samples_per_channel_ * target_number_of_channels,
+ AudioFrame::kMaxDataSizeSamples);
+
+ if (frame->num_channels_ != 1 ||
+ frame->samples_per_channel_ * target_number_of_channels >
+ AudioFrame::kMaxDataSizeSamples) {
+ return;
}
- return -1;
+ if (!frame->muted()) {
+ // Up-mixing done in place. Going backwards through the frame ensure nothing
+ // is irrevocably overwritten.
+ for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) {
+ for (size_t j = 0; j < target_number_of_channels; ++j) {
+ frame->mutable_data()[target_number_of_channels * i + j] =
+ frame->data()[i];
+ }
+ }
+ }
+ frame->num_channels_ = target_number_of_channels;
}
void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
@@ -223,9 +186,7 @@
int16_t* frame_data = frame->mutable_data();
for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
- int16_t temp_data = frame_data[i];
- frame_data[i] = frame_data[i + 1];
- frame_data[i + 1] = temp_data;
+ std::swap(frame_data[i], frame_data[i + 1]);
}
}
diff --git a/audio/utility/audio_frame_operations.h b/audio/utility/audio_frame_operations.h
index c1445b6..65c310c 100644
--- a/audio/utility/audio_frame_operations.h
+++ b/audio/utility/audio_frame_operations.h
@@ -15,6 +15,7 @@
#include <stdint.h>
#include "api/audio/audio_frame.h"
+#include "rtc_base/deprecation.h"
namespace webrtc {
@@ -32,28 +33,15 @@
// |result_frame| is empty.
static void Add(const AudioFrame& frame_to_add, AudioFrame* result_frame);
- // Upmixes mono |src_audio| to stereo |dst_audio|. This is an out-of-place
- // operation, meaning src_audio and dst_audio must point to different
- // buffers. It is the caller's responsibility to ensure that |dst_audio| is
- // sufficiently large.
- static void MonoToStereo(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio);
-
// |frame.num_channels_| will be updated. This version checks for sufficient
- // buffer size and that |num_channels_| is mono.
- static int MonoToStereo(AudioFrame* frame);
-
- // Downmixes stereo |src_audio| to mono |dst_audio|. This is an in-place
- // operation, meaning |src_audio| and |dst_audio| may point to the same
- // buffer.
- static void StereoToMono(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio);
+ // buffer size and that |num_channels_| is mono. Use UpmixChannels
+ // instead. TODO(bugs.webrtc.org/8649): remove.
+ RTC_DEPRECATED static int MonoToStereo(AudioFrame* frame);
// |frame.num_channels_| will be updated. This version checks that
- // |num_channels_| is stereo.
- static int StereoToMono(AudioFrame* frame);
+ // |num_channels_| is stereo. Use DownmixChannels
+ // instead. TODO(bugs.webrtc.org/8649): remove.
+ RTC_DEPRECATED static int StereoToMono(AudioFrame* frame);
// Downmixes 4 channels |src_audio| to stereo |dst_audio|. This is an in-place
// operation, meaning |src_audio| and |dst_audio| may point to the same
@@ -66,17 +54,6 @@
// |num_channels_| is 4 channels.
static int QuadToStereo(AudioFrame* frame);
- // Downmixes 4 channels |src_audio| to mono |dst_audio|. This is an in-place
- // operation, meaning |src_audio| and |dst_audio| may point to the same
- // buffer.
- static void QuadToMono(const int16_t* src_audio,
- size_t samples_per_channel,
- int16_t* dst_audio);
-
- // |frame.num_channels_| will be updated. This version checks that
- // |num_channels_| is 4 channels.
- static int QuadToMono(AudioFrame* frame);
-
// Downmixes |src_channels| |src_audio| to |dst_channels| |dst_audio|.
// This is an in-place operation, meaning |src_audio| and |dst_audio|
// may point to the same buffer. Supported channel combinations are
@@ -88,10 +65,16 @@
int16_t* dst_audio);
// |frame.num_channels_| will be updated. This version checks that
+ // |num_channels_| and |dst_channels| are valid and performs relevant downmix.
+ // Supported channel combinations are N channels to Mono, and Quad to Stereo.
+ static void DownmixChannels(size_t dst_channels, AudioFrame* frame);
+
+ // |frame.num_channels_| will be updated. This version checks that
// |num_channels_| and |dst_channels| are valid and performs relevant
- // downmix. Supported channel combinations are Stereo to Mono, Quad to Mono,
- // and Quad to Stereo.
- static int DownmixChannels(size_t dst_channels, AudioFrame* frame);
+ // downmix. Supported channel combinations are Mono to N
+ // channels. The single channel is replicated.
+ static void UpmixChannels(size_t target_number_of_channels,
+ AudioFrame* frame);
// Swap the left and right channels of |frame|. Fails silently if |frame| is
// not stereo.
diff --git a/audio/utility/audio_frame_operations_unittest.cc b/audio/utility/audio_frame_operations_unittest.cc
index 76f1dcd..dd41d1a 100644
--- a/audio/utility/audio_frame_operations_unittest.cc
+++ b/audio/utility/audio_frame_operations_unittest.cc
@@ -103,19 +103,21 @@
}
}
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(AudioFrameOperationsTest, MonoToStereoFailsWithBadParameters) {
- EXPECT_EQ(-1, AudioFrameOperations::MonoToStereo(&frame_));
-
+ EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), "");
frame_.samples_per_channel_ = AudioFrame::kMaxDataSizeSamples;
frame_.num_channels_ = 1;
- EXPECT_EQ(-1, AudioFrameOperations::MonoToStereo(&frame_));
+ EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), "");
}
+#endif
TEST_F(AudioFrameOperationsTest, MonoToStereoSucceeds) {
frame_.num_channels_ = 1;
SetFrameData(1, &frame_);
- EXPECT_EQ(0, AudioFrameOperations::MonoToStereo(&frame_));
+ AudioFrameOperations::UpmixChannels(2, &frame_);
+ EXPECT_EQ(2u, frame_.num_channels_);
AudioFrame stereo_frame;
stereo_frame.samples_per_channel_ = 320;
@@ -127,36 +129,22 @@
TEST_F(AudioFrameOperationsTest, MonoToStereoMuted) {
frame_.num_channels_ = 1;
ASSERT_TRUE(frame_.muted());
- EXPECT_EQ(0, AudioFrameOperations::MonoToStereo(&frame_));
+ AudioFrameOperations::UpmixChannels(2, &frame_);
+ EXPECT_EQ(2u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
-TEST_F(AudioFrameOperationsTest, MonoToStereoBufferSucceeds) {
- AudioFrame target_frame;
- frame_.num_channels_ = 1;
- SetFrameData(4, &frame_);
-
- target_frame.num_channels_ = 2;
- target_frame.samples_per_channel_ = frame_.samples_per_channel_;
-
- AudioFrameOperations::MonoToStereo(frame_.data(), frame_.samples_per_channel_,
- target_frame.mutable_data());
-
- AudioFrame stereo_frame;
- stereo_frame.samples_per_channel_ = 320;
- stereo_frame.num_channels_ = 2;
- SetFrameData(4, 4, &stereo_frame);
- VerifyFramesAreEqual(stereo_frame, target_frame);
-}
-
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(AudioFrameOperationsTest, StereoToMonoFailsWithBadParameters) {
frame_.num_channels_ = 1;
- EXPECT_EQ(-1, AudioFrameOperations::StereoToMono(&frame_));
+ EXPECT_DEATH(AudioFrameOperations::DownmixChannels(1, &frame_), "");
}
+#endif
TEST_F(AudioFrameOperationsTest, StereoToMonoSucceeds) {
SetFrameData(4, 2, &frame_);
- EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_));
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
@@ -167,7 +155,8 @@
TEST_F(AudioFrameOperationsTest, StereoToMonoMuted) {
ASSERT_TRUE(frame_.muted());
- EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_));
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
@@ -178,8 +167,9 @@
target_frame.num_channels_ = 1;
target_frame.samples_per_channel_ = frame_.samples_per_channel_;
- AudioFrameOperations::StereoToMono(frame_.data(), frame_.samples_per_channel_,
- target_frame.mutable_data());
+ AudioFrameOperations::DownmixChannels(frame_.data(), 2,
+ frame_.samples_per_channel_, 1,
+ target_frame.mutable_data());
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
@@ -190,8 +180,8 @@
TEST_F(AudioFrameOperationsTest, StereoToMonoDoesNotWrapAround) {
SetFrameData(-32768, -32768, &frame_);
- EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_));
-
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
mono_frame.num_channels_ = 1;
@@ -199,18 +189,12 @@
VerifyFramesAreEqual(mono_frame, frame_);
}
-TEST_F(AudioFrameOperationsTest, QuadToMonoFailsWithBadParameters) {
- frame_.num_channels_ = 1;
- EXPECT_EQ(-1, AudioFrameOperations::QuadToMono(&frame_));
- frame_.num_channels_ = 2;
- EXPECT_EQ(-1, AudioFrameOperations::QuadToMono(&frame_));
-}
-
TEST_F(AudioFrameOperationsTest, QuadToMonoSucceeds) {
frame_.num_channels_ = 4;
SetFrameData(4, 2, 6, 8, &frame_);
- EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_));
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
@@ -222,7 +206,8 @@
TEST_F(AudioFrameOperationsTest, QuadToMonoMuted) {
frame_.num_channels_ = 4;
ASSERT_TRUE(frame_.muted());
- EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_));
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
@@ -234,8 +219,9 @@
target_frame.num_channels_ = 1;
target_frame.samples_per_channel_ = frame_.samples_per_channel_;
- AudioFrameOperations::QuadToMono(frame_.data(), frame_.samples_per_channel_,
- target_frame.mutable_data());
+ AudioFrameOperations::DownmixChannels(frame_.data(), 4,
+ frame_.samples_per_channel_, 1,
+ target_frame.mutable_data());
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
mono_frame.num_channels_ = 1;
@@ -246,7 +232,8 @@
TEST_F(AudioFrameOperationsTest, QuadToMonoDoesNotWrapAround) {
frame_.num_channels_ = 4;
SetFrameData(-32768, -32768, -32768, -32768, &frame_);
- EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_));
+ AudioFrameOperations::DownmixChannels(1, &frame_);
+ EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn
index 74b0c60..f7ffa00 100644
--- a/common_audio/BUILD.gn
+++ b/common_audio/BUILD.gn
@@ -58,7 +58,7 @@
"../system_wrappers:cpu_features_api",
"third_party/fft4g:fft4g",
"//third_party/abseil-cpp/absl/container:inlined_vector",
- "//third_party/abseil-cpp/absl/memory:memory",
+ "//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
]
diff --git a/common_audio/audio_converter.cc b/common_audio/audio_converter.cc
index 0f97abb..c560346 100644
--- a/common_audio/audio_converter.cc
+++ b/common_audio/audio_converter.cc
@@ -31,7 +31,7 @@
size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
- ~CopyConverter() override{};
+ ~CopyConverter() override {}
void Convert(const float* const* src,
size_t src_size,
@@ -52,7 +52,7 @@
size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
- ~UpmixConverter() override{};
+ ~UpmixConverter() override {}
void Convert(const float* const* src,
size_t src_size,
@@ -74,7 +74,7 @@
size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
- ~DownmixConverter() override{};
+ ~DownmixConverter() override {}
void Convert(const float* const* src,
size_t src_size,
@@ -103,7 +103,7 @@
resamplers_.push_back(std::unique_ptr<PushSincResampler>(
new PushSincResampler(src_frames, dst_frames)));
}
- ~ResampleConverter() override{};
+ ~ResampleConverter() override {}
void Convert(const float* const* src,
size_t src_size,
@@ -132,7 +132,7 @@
std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>(
(*it)->dst_frames(), (*it)->dst_channels())));
}
- ~CompositionConverter() override{};
+ ~CompositionConverter() override {}
void Convert(const float* const* src,
size_t src_size,
diff --git a/common_audio/audio_converter.h b/common_audio/audio_converter.h
index 24a5e72..73ad1ef 100644
--- a/common_audio/audio_converter.h
+++ b/common_audio/audio_converter.h
@@ -14,7 +14,7 @@
#include <stddef.h>
#include <memory>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_audio/real_fourier_unittest.cc b/common_audio/real_fourier_unittest.cc
index 1324887..eac4fce 100644
--- a/common_audio/real_fourier_unittest.cc
+++ b/common_audio/real_fourier_unittest.cc
@@ -68,7 +68,7 @@
};
using FftTypes = ::testing::Types<RealFourierOoura>;
-TYPED_TEST_CASE(RealFourierTest, FftTypes);
+TYPED_TEST_SUITE(RealFourierTest, FftTypes);
TYPED_TEST(RealFourierTest, SimpleForwardTransform) {
this->real_buffer_[0] = 1.0f;
diff --git a/common_audio/resampler/push_sinc_resampler.h b/common_audio/resampler/push_sinc_resampler.h
index db9cdc1..b002ff7 100644
--- a/common_audio/resampler/push_sinc_resampler.h
+++ b/common_audio/resampler/push_sinc_resampler.h
@@ -16,7 +16,7 @@
#include <memory>
#include "common_audio/resampler/sinc_resampler.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_audio/resampler/push_sinc_resampler_unittest.cc b/common_audio/resampler/push_sinc_resampler_unittest.cc
index 2f53a74..ee111c4 100644
--- a/common_audio/resampler/push_sinc_resampler_unittest.cc
+++ b/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -16,7 +16,7 @@
#include "common_audio/include/audio_util.h"
#include "common_audio/resampler/push_sinc_resampler.h"
#include "common_audio/resampler/sinusoidal_linear_chirp_source.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "test/gmock.h"
#include "test/gtest.h"
@@ -255,7 +255,7 @@
// Thresholds chosen arbitrarily based on what each resampling reported during
// testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
PushSincResamplerTest,
PushSincResamplerTest,
::testing::Values(
diff --git a/common_audio/resampler/sinc_resampler.h b/common_audio/resampler/sinc_resampler.h
index 0be4318..ffd70d9 100644
--- a/common_audio/resampler/sinc_resampler.h
+++ b/common_audio/resampler/sinc_resampler.h
@@ -17,7 +17,7 @@
#include <stddef.h>
#include <memory>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/gtest_prod_util.h"
#include "rtc_base/memory/aligned_malloc.h"
#include "rtc_base/system/arch.h"
diff --git a/common_audio/resampler/sinc_resampler_unittest.cc b/common_audio/resampler/sinc_resampler_unittest.cc
index eb5424d..3aedacc 100644
--- a/common_audio/resampler/sinc_resampler_unittest.cc
+++ b/common_audio/resampler/sinc_resampler_unittest.cc
@@ -24,7 +24,7 @@
#include "common_audio/resampler/sinusoidal_linear_chirp_source.h"
#include "rtc_base/stringize_macros.h"
#include "rtc_base/system/arch.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/cpu_features_wrapper.h"
#include "test/gmock.h"
#include "test/gtest.h"
@@ -340,7 +340,7 @@
// Thresholds chosen arbitrarily based on what each resampling reported during
// testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
SincResamplerTest,
SincResamplerTest,
testing::Values(
diff --git a/common_audio/resampler/sinusoidal_linear_chirp_source.h b/common_audio/resampler/sinusoidal_linear_chirp_source.h
index 71dcff5..81f6a24 100644
--- a/common_audio/resampler/sinusoidal_linear_chirp_source.h
+++ b/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -15,7 +15,7 @@
#define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
#include "common_audio/resampler/sinc_resampler.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_audio/smoothing_filter.cc b/common_audio/smoothing_filter.cc
index 0d5aaa4..e5ce987 100644
--- a/common_audio/smoothing_filter.cc
+++ b/common_audio/smoothing_filter.cc
@@ -13,7 +13,7 @@
#include <cmath>
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
diff --git a/common_audio/smoothing_filter.h b/common_audio/smoothing_filter.h
index c467d85..e5f561e 100644
--- a/common_audio/smoothing_filter.h
+++ b/common_audio/smoothing_filter.h
@@ -14,7 +14,7 @@
#include <stdint.h>
#include "absl/types/optional.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_audio/smoothing_filter_unittest.cc b/common_audio/smoothing_filter_unittest.cc
index abe4272..5f6711e 100644
--- a/common_audio/smoothing_filter_unittest.cc
+++ b/common_audio/smoothing_filter_unittest.cc
@@ -12,7 +12,7 @@
#include <memory>
#include "common_audio/smoothing_filter.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/common_audio/sparse_fir_filter.h b/common_audio/sparse_fir_filter.h
index 22bcdff..5197a8e 100644
--- a/common_audio/sparse_fir_filter.h
+++ b/common_audio/sparse_fir_filter.h
@@ -14,7 +14,7 @@
#include <cstring>
#include <vector>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_audio/wav_file.h b/common_audio/wav_file.h
index cbce59d..7e790e0 100644
--- a/common_audio/wav_file.h
+++ b/common_audio/wav_file.h
@@ -17,7 +17,7 @@
#include <cstddef>
#include <string>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/platform_file.h"
namespace webrtc {
diff --git a/common_audio/wav_file_unittest.cc b/common_audio/wav_file_unittest.cc
index d40229a..b7e5d3f 100644
--- a/common_audio/wav_file_unittest.cc
+++ b/common_audio/wav_file_unittest.cc
@@ -17,7 +17,7 @@
#include "common_audio/wav_file.h"
#include "common_audio/wav_header.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
// WavWriterTest.CPPFileDescriptor and WavWriterTest.CPP flaky on Mac.
// See webrtc:9247.
diff --git a/common_audio/window_generator.h b/common_audio/window_generator.h
index ad3b445..0cbe24a 100644
--- a/common_audio/window_generator.h
+++ b/common_audio/window_generator.h
@@ -13,7 +13,7 @@
#include <stddef.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/common_types.h b/common_types.h
index 848b899..2b877d6 100644
--- a/common_types.h
+++ b/common_types.h
@@ -14,12 +14,8 @@
#include <stddef.h> // For size_t
#include <cstdint>
-#include "absl/strings/match.h"
-// TODO(sprang): Remove this include when all usage includes it directly.
-#include "api/video/video_bitrate_allocation.h"
// TODO(bugs.webrtc.org/7660): Delete include once downstream code is updated.
#include "api/video/video_codec_type.h"
-#include "rtc_base/checks.h"
#if defined(_MSC_VER)
// Disable "new behavior: elements of array will be default initialized"
@@ -27,8 +23,6 @@
#pragma warning(disable : 4351)
#endif
-#define RTP_PAYLOAD_NAME_SIZE 32u
-
namespace webrtc {
enum FrameType {
@@ -158,29 +152,6 @@
virtual void OnOverheadChanged(size_t overhead_bytes_per_packet) = 0;
};
-// ==================================================================
-// Voice specific types
-// ==================================================================
-
-// Each codec supported can be described by this structure.
-struct CodecInst {
- int pltype;
- char plname[RTP_PAYLOAD_NAME_SIZE];
- int plfreq;
- int pacsize;
- size_t channels;
- int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file!
-
- bool operator==(const CodecInst& other) const {
- return pltype == other.pltype &&
- absl::EqualsIgnoreCase(plname, other.plname) &&
- plfreq == other.plfreq && pacsize == other.pacsize &&
- channels == other.channels && rate == other.rate;
- }
-
- bool operator!=(const CodecInst& other) const { return !(*this == other); }
-};
-
// RTP
enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
diff --git a/cras-config/aec_config.cc b/cras-config/aec_config.cc
index d0cf19b..d8fb369 100644
--- a/cras-config/aec_config.cc
+++ b/cras-config/aec_config.cc
@@ -24,8 +24,6 @@
if (ini == NULL)
return;
- config->buffering.use_new_render_buffering =
- AEC_GET_INT(ini, BUFFERING, USE_NEW_RENDER_BUFFERING);
config->buffering.excess_render_detection_interval_blocks =
AEC_GET_INT(ini, BUFFERING,
EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS);
@@ -38,18 +36,10 @@
AEC_GET_INT(ini, DELAY, DOWN_SAMPLING_FACTOR);
config->delay.num_filters =
AEC_GET_INT(ini, DELAY, NUM_FILTERS);
- config->delay.api_call_jitter_blocks =
- AEC_GET_INT(ini, DELAY, API_CALL_JITTER_BLOCKS);
- config->delay.min_echo_path_delay_blocks =
- AEC_GET_INT(ini, DELAY, MIN_ECHO_PATH_DELAY_BLOCKS);
- config->delay.delay_headroom_blocks =
- AEC_GET_INT(ini, DELAY, DELAY_HEADROOM_BLOCKS);
- config->delay.hysteresis_limit_1_blocks =
- AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_1_BLOCKS);
- config->delay.hysteresis_limit_2_blocks =
- AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_2_BLOCKS);
- config->delay.skew_hysteresis_blocks =
- AEC_GET_INT(ini, DELAY, SKEW_HYSTERESIS_BLOCKS);
+ config->delay.delay_headroom_samples =
+ AEC_GET_INT(ini, DELAY, DELAY_HEADROOM_SAMPLES);
+ config->delay.hysteresis_limit_blocks =
+ AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_BLOCKS);
config->delay.fixed_capture_delay_samples =
AEC_GET_INT(ini, DELAY, FIXED_CAPTURE_DELAY_SAMPLES);
config->delay.delay_estimate_smoothing =
@@ -121,12 +111,8 @@
config->erle.num_sections =
AEC_GET_INT(ini, ERLE, NUM_SECTIONS);
- config->ep_strength.lf =
- AEC_GET_FLOAT(ini, EP_STRENGTH, LF);
- config->ep_strength.mf =
- AEC_GET_FLOAT(ini, EP_STRENGTH, MF);
- config->ep_strength.hf =
- AEC_GET_FLOAT(ini, EP_STRENGTH, HF);
+ config->ep_strength.default_gain =
+ AEC_GET_FLOAT(ini, EP_STRENGTH, DEFAULT_GAIN);
config->ep_strength.default_len =
AEC_GET_FLOAT(ini, EP_STRENGTH, DEFAULT_LEN);
config->ep_strength.reverb_based_on_render =
@@ -161,14 +147,6 @@
config->render_levels.poor_excitation_render_limit_ds8 =
AEC_GET_FLOAT(ini, RENDER_LEVELS, POOR_EXCITATION_RENDER_LIMIT_DS8);
- config->echo_removal_control.gain_rampup.initial_gain =
- AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, INITIAL_GAIN);
- config->echo_removal_control.gain_rampup.first_non_zero_gain =
- AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, FIRST_NON_ZERO_GAIN);
- config->echo_removal_control.gain_rampup.non_zero_gain_blocks =
- AEC_GET_INT(ini, ECHO_REMOVAL_CTL, NON_ZERO_GAIN_BLOCKS);
- config->echo_removal_control.gain_rampup.full_gain_blocks =
- AEC_GET_INT(ini, ECHO_REMOVAL_CTL, FULL_GAIN_BLOCKS);
config->echo_removal_control.has_clock_drift =
AEC_GET_INT(ini, ECHO_REMOVAL_CTL, HAS_CLOCK_DRIFT);
config->echo_removal_control.linear_and_stable_echo_path =
@@ -288,8 +266,6 @@
syslog(LOG_ERR, "---- aec config dump ----");
syslog(LOG_ERR, "Buffering:");
- syslog(LOG_ERR, " use_new_render_buffering %d",
- config.buffering.use_new_render_buffering);
syslog(LOG_ERR, " excess_render_detection_interval_blocks %zu",
config.buffering.excess_render_detection_interval_blocks);
syslog(LOG_ERR, " max_allowed_excess_render_blocks %zu",
@@ -300,15 +276,9 @@
config.delay.default_delay,
config.delay.down_sampling_factor,
config.delay.num_filters);
- syslog(LOG_ERR, " api_call_jitter_blocks %zu, min_echo_path_delay_blocks %zu",
- config.delay.api_call_jitter_blocks,
- config.delay.min_echo_path_delay_blocks);
- syslog(LOG_ERR, " delay_headroom_blocks %zu, hysteresis_limit_1_blocks %zu",
- config.delay.delay_headroom_blocks,
- config.delay.hysteresis_limit_1_blocks);
- syslog(LOG_ERR, " hysteresis_limit_2_blocks %zu, skew_hysteresis_blocks %zu",
- config.delay.hysteresis_limit_2_blocks,
- config.delay.skew_hysteresis_blocks);
+ syslog(LOG_ERR, " delay_headroom_samples %zu, hysteresis_limit_blocks %zu",
+ config.delay.delay_headroom_samples,
+ config.delay.hysteresis_limit_blocks);
syslog(LOG_ERR, " fixed_capture_delay_samples %zu",
config.delay.fixed_capture_delay_samples);
syslog(LOG_ERR, " delay_estimate_smoothing %f",
@@ -359,10 +329,8 @@
syslog(LOG_ERR, "Erle: min %f max_l %f max_h %f onset_detection %d",
config.erle.min, config.erle.max_l,
config.erle.max_h, config.erle.onset_detection);
- syslog(LOG_ERR, "Ep strength: lf %f mf %f hf %f default_len %f",
- config.ep_strength.lf,
- config.ep_strength.mf,
- config.ep_strength.hf,
+ syslog(LOG_ERR, "Ep strength: default_gain %f default_len %f",
+ config.ep_strength.default_gain,
config.ep_strength.default_len);
syslog(LOG_ERR, " echo_can_saturate %d, bounded_erl %d,"
" ep_strength.reverb_based_on_render %d",
@@ -394,12 +362,6 @@
config.render_levels.poor_excitation_render_limit_ds8);
syslog(LOG_ERR, "Echo removal control:");
syslog(LOG_ERR, " gain rampup:");
- syslog(LOG_ERR, " initial_gain %f, first_non_zero_gain %f",
- config.echo_removal_control.gain_rampup.initial_gain,
- config.echo_removal_control.gain_rampup.first_non_zero_gain);
- syslog(LOG_ERR, " non_zero_gain_blocks %d, full_gain_blocks %d",
- config.echo_removal_control.gain_rampup.non_zero_gain_blocks,
- config.echo_removal_control.gain_rampup.full_gain_blocks);
syslog(LOG_ERR, " has_clock_drift %d",
config.echo_removal_control.has_clock_drift);
syslog(LOG_ERR, " linear_and_stable_echo_path %d",
diff --git a/cras-config/aec_config.h b/cras-config/aec_config.h
index 33185b3..3b6fd5d 100644
--- a/cras-config/aec_config.h
+++ b/cras-config/aec_config.h
@@ -10,8 +10,6 @@
#include "api/audio/echo_canceller3_config.h"
-#define AEC_BUFFERING_USE_NEW_RENDER_BUFFERING "buffering:use_new_render_buffering"
-#define AEC_BUFFERING_USE_NEW_RENDER_BUFFERING_VALUE 1
#define AEC_BUFFERING_EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS \
"buffering:excess_render_detection_interval_blocks"
#define AEC_BUFFERING_EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS_VALUE 250
@@ -25,18 +23,10 @@
#define AEC_DELAY_DOWN_SAMPLING_FACTOR_VALUE 4
#define AEC_DELAY_NUM_FILTERS "delay:num_filters"
#define AEC_DELAY_NUM_FILTERS_VALUE 5
-#define AEC_DELAY_API_CALL_JITTER_BLOCKS "delay:api_call_jitter_blocks"
-#define AEC_DELAY_API_CALL_JITTER_BLOCKS_VALUE 26
-#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS "delay:min_echo_path_delay_blocks"
-#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS_VALUE 0
-#define AEC_DELAY_DELAY_HEADROOM_BLOCKS "delay:delay_headroom_blocks"
-#define AEC_DELAY_DELAY_HEADROOM_BLOCKS_VALUE 2
-#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS "delay:hysteresis_limit_1_blocks"
-#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS_VALUE 1
-#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS "delay:hysteresis_limit_2_blocks"
-#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS_VALUE 1
-#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS "delay:skew_hysteresis_blocks"
-#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS_VALUE 3
+#define AEC_DELAY_DELAY_HEADROOM_SAMPLES "delay:delay_headroom_samples"
+#define AEC_DELAY_DELAY_HEADROOM_SAMPLES_VALUE 32
+#define AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS "delay:hysteresis_limit_blocks"
+#define AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS_VALUE 1
#define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES \
"delay:fixed_capture_delay_samples"
#define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES_VALUE 0
@@ -124,12 +114,8 @@
#define AEC_ERLE_NUM_SECTIONS_VALUE 1
// EpStrength
-#define AEC_EP_STRENGTH_LF "ep_strength:lf"
-#define AEC_EP_STRENGTH_LF_VALUE 1.f
-#define AEC_EP_STRENGTH_MF "ep_strength:mf"
-#define AEC_EP_STRENGTH_MF_VALUE 1.f
-#define AEC_EP_STRENGTH_HF "ep_strength:hf"
-#define AEC_EP_STRENGTH_HF_VALUE 1.f
+#define AEC_EP_STRENGTH_DEFAULT_GAIN "ep_strength:default_gain"
+#define AEC_EP_STRENGTH_DEFAULT_GAIN_VALUE 1.f
#define AEC_EP_STRENGTH_DEFAULT_LEN "ep_strength:default_len"
#define AEC_EP_STRENGTH_DEFAULT_LEN_VALUE 0.83f
#define AEC_EP_STRENGTH_REVERB_BASED_ON_RENDER \
@@ -175,17 +161,6 @@
#define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT_DS8_VALUE 20.f
// Echo removal controls
-#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN "echo_removal_control:initial_gain"
-#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN_VALUE 0.0f
-#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN \
- "echo_removal_control:first_non_zero_gain"
-#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN_VALUE 0.001f
-#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS \
- "echo_removal_control:non_zero_gain_blocks"
-#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS_VALUE 187
-#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS \
- "echo_removal_control:full_gain_blocks"
-#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS_VALUE 312
#define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT \
"echo_removal_control:has_clock_drift"
#define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT_VALUE 0
diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn
index df4ba23..5a47245 100644
--- a/modules/audio_coding/BUILD.gn
+++ b/modules/audio_coding/BUILD.gn
@@ -8,59 +8,12 @@
import("../../webrtc.gni")
import("audio_coding.gni")
-if (!build_with_mozilla) {
+if (rtc_enable_protobuf) {
import("//third_party/protobuf/proto_library.gni")
}
visibility = [ ":*" ]
-rtc_static_library("audio_format_conversion") {
- visibility += webrtc_default_visibility
- sources = [
- "codecs/audio_format_conversion.cc",
- "codecs/audio_format_conversion.h",
- ]
- deps = [
- "../..:webrtc_common",
- "../../api:array_view",
- "../../api/audio_codecs:audio_codecs_api",
- "../../rtc_base:checks",
- "../../rtc_base:rtc_base_approved",
- "../../rtc_base:sanitizer",
- "//third_party/abseil-cpp/absl/strings",
- "//third_party/abseil-cpp/absl/types:optional",
- ]
-}
-
-rtc_static_library("rent_a_codec") {
- # Client code SHOULD NOT USE THIS TARGET, but for now it needs to be public
- # because there exists client code that uses it.
- # TODO(bugs.webrtc.org/9808): Move to private visibility as soon as that
- # client code gets updated.
- visibility += [ "*" ]
-
- sources = [
- "acm2/acm_codec_database.cc",
- "acm2/acm_codec_database.h",
- "acm2/rent_a_codec.cc",
- "acm2/rent_a_codec.h",
- ]
- deps = [
- ":audio_coding_module_typedefs",
- ":neteq_decoder_enum",
- "../..:webrtc_common",
- "../../api:array_view",
- "../../api/audio_codecs:audio_codecs_api",
- "../../rtc_base:checks",
- "../../rtc_base:protobuf_utils",
- "../../rtc_base:rtc_base_approved",
- "../../system_wrappers",
- "//third_party/abseil-cpp/absl/strings",
- "//third_party/abseil-cpp/absl/types:optional",
- ]
- defines = audio_codec_defines
-}
-
rtc_source_set("audio_coding_module_typedefs") {
sources = [
"include/audio_coding_module_typedefs.h",
@@ -89,8 +42,6 @@
deps = [
":audio_coding_module_typedefs",
":neteq",
- ":neteq_decoder_enum",
- ":rent_a_codec",
"..:module_api",
"..:module_api_public",
"../..:webrtc_common",
@@ -440,6 +391,7 @@
deps = [
":isac_bwinfo",
"../..:webrtc_common",
+ "../../api:scoped_refptr",
"../../api/audio_codecs:audio_codecs_api",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
@@ -815,6 +767,7 @@
"../../api/audio_codecs/opus:audio_encoder_opus_config",
"../../common_audio",
"../../rtc_base:checks",
+ "../../rtc_base:protobuf_utils",
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_numerics",
"../../rtc_base:safe_minmax",
@@ -825,7 +778,6 @@
]
public_deps = [
":webrtc_opus_c",
- "../../rtc_base:protobuf_utils",
]
defines = audio_codec_defines
@@ -948,23 +900,6 @@
":ana_debug_dump_proto",
]
}
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-}
-
-rtc_source_set("neteq_decoder_enum") {
- sources = [
- "neteq/neteq_decoder_enum.cc",
- "neteq/neteq_decoder_enum.h",
- ]
- deps = [
- "../../api/audio_codecs:audio_codecs_api",
- "../../rtc_base:rtc_base_approved",
- "//third_party/abseil-cpp/absl/types:optional",
- ]
}
rtc_static_library("neteq") {
@@ -1003,6 +938,8 @@
"neteq/expand.h",
"neteq/expand_uma_logger.cc",
"neteq/expand_uma_logger.h",
+ "neteq/histogram.cc",
+ "neteq/histogram.h",
"neteq/include/neteq.h",
"neteq/merge.cc",
"neteq/merge.h",
@@ -1039,13 +976,13 @@
deps = [
":audio_coding_module_typedefs",
- ":neteq_decoder_enum",
":webrtc_cng",
"..:module_api",
"..:module_api_public",
"../..:webrtc_common",
"../../api:array_view",
"../../api:libjingle_peerconnection_api",
+ "../../api:scoped_refptr",
"../../api/audio:audio_frame_api",
"../../api/audio_codecs:audio_codecs_api",
"../../common_audio",
@@ -1059,6 +996,7 @@
"../../rtc_base/system:fallthrough",
"../../system_wrappers:field_trial",
"../../system_wrappers:metrics",
+ "//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
@@ -1092,10 +1030,10 @@
"../../api:neteq_simulator_api",
"../../api/audio:audio_frame_api",
"../../api/audio_codecs:audio_codecs_api",
- "../../api/audio_codecs:builtin_audio_decoder_factory",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../rtp_rtcp",
+ "../rtp_rtcp:rtp_rtcp_format",
"//third_party/abseil-cpp/absl/types:optional",
]
defines = audio_codec_defines
@@ -1120,11 +1058,6 @@
"neteq/tools/rtp_generator.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
":pcm16b",
"../..:webrtc_common",
@@ -1170,11 +1103,6 @@
"neteq/tools/neteq_stats_plotter.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
"..:module_api",
"../..:webrtc_common",
@@ -1220,11 +1148,6 @@
"neteq/tools/rtc_event_log_source.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
":neteq_tools_minimal",
"../../logging:rtc_event_log_parser",
@@ -1232,6 +1155,7 @@
"../../rtc_base:rtc_base_approved",
"../rtp_rtcp",
"../rtp_rtcp:rtp_rtcp_format",
+ "//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
]
public_deps = [
@@ -1343,14 +1267,11 @@
"test/opus_test.cc",
"test/opus_test.h",
"test/target_delay_unittest.cc",
- "test/utility.cc",
- "test/utility.h",
]
deps = [
":audio_coding",
":audio_coding_module_typedefs",
":audio_encoder_cng",
- ":audio_format_conversion",
":pcm16b_c",
":red",
":webrtc_opus_c",
@@ -1379,14 +1300,11 @@
"../../system_wrappers",
"../../test:fileutils",
"../../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
defines = audio_coding_defines
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
rtc_source_set("audio_coding_perf_tests") {
@@ -1402,7 +1320,6 @@
":neteq_test_tools",
"../..:webrtc_common",
"../../api/audio_codecs/opus:audio_encoder_opus",
- "../../rtc_base:protobuf_utils",
"../../rtc_base:rtc_base_approved",
"../../system_wrappers",
"../../system_wrappers:field_trial",
@@ -1410,11 +1327,6 @@
"../../test:perf_test",
"../../test:test_support",
]
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
rtc_source_set("acm_receive_test") {
@@ -1427,9 +1339,9 @@
defines = audio_coding_defines
deps = audio_coding_deps + [
+ "../../api:scoped_refptr",
"..:module_api",
":audio_coding",
- ":audio_format_conversion",
"../../api/audio_codecs:audio_codecs_api",
"../../api/audio_codecs:builtin_audio_decoder_factory",
":neteq_tools",
@@ -1453,7 +1365,6 @@
"../../api/audio:audio_frame_api",
"../../rtc_base:checks",
":audio_coding",
- ":audio_format_conversion",
":neteq_tools",
"../../api/audio_codecs:builtin_audio_decoder_factory",
"../../api/audio_codecs:builtin_audio_encoder_factory",
@@ -1495,7 +1406,6 @@
"../../api/audio_codecs:audio_codecs_api",
"../../api/audio_codecs/opus:audio_encoder_opus",
"../../common_audio",
- "../../rtc_base:protobuf_utils",
"../../rtc_base/system:arch",
"../../test:test_main",
"//testing/gtest",
@@ -1528,22 +1438,20 @@
deps = [
"../../rtc_base:checks",
"../../test:fileutils",
+ "//third_party/abseil-cpp/absl/types:optional",
]
sources = [
"neteq/tools/neteq_test_factory.cc",
"neteq/tools/neteq_test_factory.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps += [
":neteq",
":neteq_test_tools",
"../..:webrtc_common",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
"../../rtc_base:rtc_base_approved",
+ "../../test:audio_codec_mocks",
"../../test:test_support",
"//third_party/abseil-cpp/absl/memory",
]
@@ -1594,11 +1502,6 @@
"codecs/tools/audio_codec_speed_test.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
data = audio_codec_speed_tests_resources
if (is_android) {
@@ -1626,17 +1529,10 @@
rtc_source_set("neteq_test_support") {
testonly = true
sources = [
- "neteq/tools/neteq_external_decoder_test.cc",
- "neteq/tools/neteq_external_decoder_test.h",
"neteq/tools/neteq_performance_test.cc",
"neteq/tools/neteq_performance_test.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
":neteq",
":neteq_test_tools",
@@ -1661,11 +1557,6 @@
"neteq/tools/neteq_quality_test.h",
]
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
":neteq",
":neteq_test_tools",
@@ -2033,6 +1924,7 @@
"neteq/dtmf_buffer_unittest.cc",
"neteq/dtmf_tone_generator_unittest.cc",
"neteq/expand_unittest.cc",
+ "neteq/histogram_unittest.cc",
"neteq/merge_unittest.cc",
"neteq/mock/mock_buffer_level_filter.h",
"neteq/mock/mock_decoder_database.h",
@@ -2041,13 +1933,12 @@
"neteq/mock/mock_dtmf_buffer.h",
"neteq/mock/mock_dtmf_tone_generator.h",
"neteq/mock/mock_expand.h",
- "neteq/mock/mock_external_decoder_pcm16b.h",
+ "neteq/mock/mock_histogram.h",
"neteq/mock/mock_packet_buffer.h",
"neteq/mock/mock_red_payload_splitter.h",
"neteq/mock/mock_statistics_calculator.h",
"neteq/nack_tracker_unittest.cc",
"neteq/neteq_decoder_plc_unittest.cc",
- "neteq/neteq_external_decoder_unittest.cc",
"neteq/neteq_impl_unittest.cc",
"neteq/neteq_network_stats_unittest.cc",
"neteq/neteq_stereo_unittest.cc",
@@ -2072,7 +1963,6 @@
":audio_coding",
":audio_coding_module_typedefs",
":audio_encoder_cng",
- ":audio_format_conversion",
":audio_network_adaptor",
":g711",
":ilbc",
@@ -2086,10 +1976,10 @@
":neteq_test_tools",
":pcm16b",
":red",
- ":rent_a_codec",
":webrtc_cng",
":webrtc_opus",
"..:module_api",
+ "..:module_api_public",
"../..:webrtc_common",
"../../api/audio:audio_frame_api",
"../../api/audio_codecs:audio_codecs_api",
@@ -2105,11 +1995,11 @@
"../../logging:rtc_event_log_api",
"../../modules/rtp_rtcp:rtp_rtcp_format",
"../../rtc_base:checks",
- "../../rtc_base:protobuf_utils",
"../../rtc_base:rtc_base",
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_base_tests_utils",
"../../rtc_base:sanitizer",
+ "../../rtc_base:timeutils",
"../../rtc_base/system:arch",
"../../system_wrappers",
"../../system_wrappers:cpu_features_api",
@@ -2135,11 +2025,6 @@
":neteq_unittest_proto",
]
}
-
- if (!build_with_chromium && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
}
diff --git a/modules/audio_coding/acm2/acm_codec_database.cc b/modules/audio_coding/acm2/acm_codec_database.cc
deleted file mode 100644
index cada80c..0000000
--- a/modules/audio_coding/acm2/acm_codec_database.cc
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2012 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.
- */
-
-/*
- * This file generates databases with information about all supported audio
- * codecs.
- */
-
-// TODO(tlegrand): Change constant input pointers in all functions to constant
-// references, where appropriate.
-#include "modules/audio_coding/acm2/acm_codec_database.h"
-
-#include "absl/strings/match.h"
-#include "api/array_view.h"
-#include "modules/audio_coding/acm2/rent_a_codec.h"
-
-#if ((defined WEBRTC_CODEC_ISAC) && (defined WEBRTC_CODEC_ISACFX))
-#error iSAC and iSACFX codecs cannot be enabled at the same time
-#endif
-
-namespace webrtc {
-
-namespace acm2 {
-
-namespace {
-
-// Checks if the bitrate is valid for iSAC.
-bool IsISACRateValid(int rate) {
- return (rate == -1) || ((rate <= 56000) && (rate >= 10000));
-}
-
-// Checks if the bitrate is valid for iLBC.
-bool IsILBCRateValid(int rate, int frame_size_samples) {
- if (((frame_size_samples == 240) || (frame_size_samples == 480)) &&
- (rate == 13300)) {
- return true;
- } else if (((frame_size_samples == 160) || (frame_size_samples == 320)) &&
- (rate == 15200)) {
- return true;
- } else {
- return false;
- }
-}
-
-// Checks if the bitrate is valid for Opus.
-bool IsOpusRateValid(int rate) {
- return (rate >= 6000) && (rate <= 510000);
-}
-
-} // namespace
-
-// Not yet used payload-types.
-// 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68,
-// 67, 66, 65
-
-const CodecInst ACMCodecDB::database_[] = {
-#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
- {103, "ISAC", 16000, 480, 1, 32000},
-#if (defined(WEBRTC_CODEC_ISAC))
- {104, "ISAC", 32000, 960, 1, 56000},
-#endif
-#endif
- // Mono
- {107, "L16", 8000, 80, 1, 128000},
- {108, "L16", 16000, 160, 1, 256000},
- {109, "L16", 32000, 320, 1, 512000},
- // Stereo
- {111, "L16", 8000, 80, 2, 128000},
- {112, "L16", 16000, 160, 2, 256000},
- {113, "L16", 32000, 320, 2, 512000},
- // G.711, PCM mu-law and A-law.
- // Mono
- {0, "PCMU", 8000, 160, 1, 64000},
- {8, "PCMA", 8000, 160, 1, 64000},
- // Stereo
- {110, "PCMU", 8000, 160, 2, 64000},
- {118, "PCMA", 8000, 160, 2, 64000},
-#ifdef WEBRTC_CODEC_ILBC
- {102, "ILBC", 8000, 240, 1, 13300},
-#endif
- // Mono
- {9, "G722", 16000, 320, 1, 64000},
- // Stereo
- {119, "G722", 16000, 320, 2, 64000},
-#ifdef WEBRTC_CODEC_OPUS
- // Opus internally supports 48, 24, 16, 12, 8 kHz.
- // Mono and stereo.
- {120, "opus", 48000, 960, 2, 64000},
-#endif
- // Comfort noise for four different sampling frequencies.
- {13, "CN", 8000, 240, 1, 0},
- {98, "CN", 16000, 480, 1, 0},
- {99, "CN", 32000, 960, 1, 0},
-#ifdef ENABLE_48000_HZ
- {100, "CN", 48000, 1440, 1, 0},
-#endif
- {106, "telephone-event", 8000, 240, 1, 0},
- {114, "telephone-event", 16000, 240, 1, 0},
- {115, "telephone-event", 32000, 240, 1, 0},
- {116, "telephone-event", 48000, 240, 1, 0},
-#ifdef WEBRTC_CODEC_RED
- {127, "red", 8000, 0, 1, 0},
-#endif
- // To prevent compile errors due to trailing commas.
- {-1, "Null", -1, -1, 0, -1}};
-
-// Create database with all codec settings at compile time.
-// Each entry needs the following parameters in the given order:
-// Number of allowed packet sizes, a vector with the allowed packet sizes,
-// Basic block samples, max number of channels that are supported.
-const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = {
-#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
- {2, {480, 960}, 0, 1},
-#if (defined(WEBRTC_CODEC_ISAC))
- {1, {960}, 0, 1},
-#endif
-#endif
- // Mono
- {4, {80, 160, 240, 320}, 0, 2},
- {4, {160, 320, 480, 640}, 0, 2},
- {2, {320, 640}, 0, 2},
- // Stereo
- {4, {80, 160, 240, 320}, 0, 2},
- {4, {160, 320, 480, 640}, 0, 2},
- {2, {320, 640}, 0, 2},
- // G.711, PCM mu-law and A-law.
- // Mono
- {6, {80, 160, 240, 320, 400, 480}, 0, 2},
- {6, {80, 160, 240, 320, 400, 480}, 0, 2},
- // Stereo
- {6, {80, 160, 240, 320, 400, 480}, 0, 2},
- {6, {80, 160, 240, 320, 400, 480}, 0, 2},
-#ifdef WEBRTC_CODEC_ILBC
- {4, {160, 240, 320, 480}, 0, 1},
-#endif
- // Mono
- {6, {160, 320, 480, 640, 800, 960}, 0, 2},
- // Stereo
- {6, {160, 320, 480, 640, 800, 960}, 0, 2},
-#ifdef WEBRTC_CODEC_OPUS
-// Opus supports frames shorter than 10ms,
-// but it doesn't help us to use them.
-// Mono and stereo.
-#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
- {5, {480, 960, 1920, 2880, 5760}, 0, 2},
-#else
- {4, {480, 960, 1920, 2880}, 0, 2},
-#endif
-#endif
- // Comfort noise for three different sampling frequencies.
- {1, {240}, 240, 1},
- {1, {480}, 480, 1},
- {1, {960}, 960, 1},
-// TODO(solenberg): What is this flag? It is never set in the build files.
-#ifdef ENABLE_48000_HZ
- {1, {1440}, 1440, 1},
-#endif
- {1, {240}, 240, 1},
- {1, {240}, 240, 1},
- {1, {240}, 240, 1},
- {1, {240}, 240, 1},
-#ifdef WEBRTC_CODEC_RED
- {1, {0}, 0, 1},
-#endif
- // To prevent compile errors due to trailing commas.
- {-1, {-1}, -1, 0}};
-
-// Create a database of all NetEQ decoders at compile time.
-const NetEqDecoder ACMCodecDB::neteq_decoders_[] = {
-#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
- NetEqDecoder::kDecoderISAC,
-#if (defined(WEBRTC_CODEC_ISAC))
- NetEqDecoder::kDecoderISACswb,
-#endif
-#endif
- // Mono
- NetEqDecoder::kDecoderPCM16B, NetEqDecoder::kDecoderPCM16Bwb,
- NetEqDecoder::kDecoderPCM16Bswb32kHz,
- // Stereo
- NetEqDecoder::kDecoderPCM16B_2ch, NetEqDecoder::kDecoderPCM16Bwb_2ch,
- NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch,
- // G.711, PCM mu-las and A-law.
- // Mono
- NetEqDecoder::kDecoderPCMu, NetEqDecoder::kDecoderPCMa,
- // Stereo
- NetEqDecoder::kDecoderPCMu_2ch, NetEqDecoder::kDecoderPCMa_2ch,
-#ifdef WEBRTC_CODEC_ILBC
- NetEqDecoder::kDecoderILBC,
-#endif
- // Mono
- NetEqDecoder::kDecoderG722,
- // Stereo
- NetEqDecoder::kDecoderG722_2ch,
-#ifdef WEBRTC_CODEC_OPUS
- // Mono and stereo.
- NetEqDecoder::kDecoderOpus,
-#endif
- // Comfort noise for three different sampling frequencies.
- NetEqDecoder::kDecoderCNGnb, NetEqDecoder::kDecoderCNGwb,
- NetEqDecoder::kDecoderCNGswb32kHz,
-#ifdef ENABLE_48000_HZ
- NetEqDecoder::kDecoderCNGswb48kHz,
-#endif
- NetEqDecoder::kDecoderAVT, NetEqDecoder::kDecoderAVT16kHz,
- NetEqDecoder::kDecoderAVT32kHz, NetEqDecoder::kDecoderAVT48kHz,
-#ifdef WEBRTC_CODEC_RED
- NetEqDecoder::kDecoderRED,
-#endif
-};
-
-// Enumerator for error codes when asking for codec database id.
-enum {
- kInvalidCodec = -10,
- kInvalidPayloadtype = -30,
- kInvalidPacketSize = -40,
- kInvalidRate = -50
-};
-
-// Gets the codec id number from the database. If there is some mismatch in
-// the codec settings, the function will return an error code.
-// NOTE! The first mismatch found will generate the return value.
-int ACMCodecDB::CodecNumber(const CodecInst& codec_inst) {
- // Look for a matching codec in the database.
- int codec_id = CodecId(codec_inst);
-
- // Checks if we found a matching codec.
- if (codec_id == -1) {
- return kInvalidCodec;
- }
-
- // Checks the validity of payload type
- if (!RentACodec::IsPayloadTypeValid(codec_inst.pltype)) {
- return kInvalidPayloadtype;
- }
-
- // Comfort Noise is special case, packet-size & rate is not checked.
- if (absl::EqualsIgnoreCase(database_[codec_id].plname, "CN")) {
- return codec_id;
- }
-
- // RED is special case, packet-size & rate is not checked.
- if (absl::EqualsIgnoreCase(database_[codec_id].plname, "red")) {
- return codec_id;
- }
-
- // Checks the validity of packet size.
- if (codec_settings_[codec_id].num_packet_sizes > 0) {
- bool packet_size_ok = false;
- int i;
- int packet_size_samples;
- for (i = 0; i < codec_settings_[codec_id].num_packet_sizes; i++) {
- packet_size_samples = codec_settings_[codec_id].packet_sizes_samples[i];
- if (codec_inst.pacsize == packet_size_samples) {
- packet_size_ok = true;
- break;
- }
- }
-
- if (!packet_size_ok) {
- return kInvalidPacketSize;
- }
- }
-
- if (codec_inst.pacsize < 1) {
- return kInvalidPacketSize;
- }
-
- // Check the validity of rate. Codecs with multiple rates have their own
- // function for this.
- if (absl::EqualsIgnoreCase("isac", codec_inst.plname)) {
- return IsISACRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
- } else if (absl::EqualsIgnoreCase("ilbc", codec_inst.plname)) {
- return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize) ? codec_id
- : kInvalidRate;
- } else if (absl::EqualsIgnoreCase("opus", codec_inst.plname)) {
- return IsOpusRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
- }
-
- return database_[codec_id].rate == codec_inst.rate ? codec_id : kInvalidRate;
-}
-
-// Looks for a matching payload name, frequency, and channels in the
-// codec list. Need to check all three since some codecs have several codec
-// entries with different frequencies and/or channels.
-// Does not check other codec settings, such as payload type and packet size.
-// Returns the id of the codec, or -1 if no match is found.
-int ACMCodecDB::CodecId(const CodecInst& codec_inst) {
- return (CodecId(codec_inst.plname, codec_inst.plfreq, codec_inst.channels));
-}
-
-int ACMCodecDB::CodecId(const char* payload_name,
- int frequency,
- size_t channels) {
- for (const CodecInst& ci : database_) {
- bool name_match = false;
- bool frequency_match = false;
- bool channels_match = false;
-
- // Payload name, sampling frequency and number of channels need to match.
- // NOTE! If |frequency| is -1, the frequency is not applicable, and is
- // always treated as true, like for RED.
- name_match = absl::EqualsIgnoreCase(ci.plname, payload_name);
- frequency_match = (frequency == ci.plfreq) || (frequency == -1);
- // The number of channels must match for all codecs but Opus.
- if (!absl::EqualsIgnoreCase(payload_name, "opus")) {
- channels_match = (channels == ci.channels);
- } else {
- // For opus we just check that number of channels is valid.
- channels_match = (channels == 1 || channels == 2);
- }
-
- if (name_match && frequency_match && channels_match) {
- // We have found a matching codec in the list.
- return &ci - database_;
- }
- }
-
- // We didn't find a matching codec.
- return -1;
-}
-// Gets codec id number from database for the receiver.
-int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst) {
- // Look for a matching codec in the database.
- return CodecId(codec_inst);
-}
-
-} // namespace acm2
-
-} // namespace webrtc
diff --git a/modules/audio_coding/acm2/acm_codec_database.h b/modules/audio_coding/acm2/acm_codec_database.h
deleted file mode 100644
index ee6bb46..0000000
--- a/modules/audio_coding/acm2/acm_codec_database.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2012 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.
- */
-
-/*
- * This file generates databases with information about all supported audio
- * codecs.
- */
-
-#ifndef MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_
-#define MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_
-
-#include "common_types.h" // NOLINT(build/include)
-#include "modules/audio_coding/acm2/rent_a_codec.h"
-
-namespace webrtc {
-
-namespace acm2 {
-
-// TODO(tlegrand): replace class ACMCodecDB with a namespace.
-class ACMCodecDB {
- public:
- // kMaxNumCodecs - Maximum number of codecs that can be activated in one
- // build.
- // kMaxNumPacketSize - Maximum number of allowed packet sizes for one codec.
- // These might need to be increased if adding a new codec to the database
- static const int kMaxNumCodecs = 50;
- static const int kMaxNumPacketSize = 6;
-
- // Codec specific settings
- //
- // num_packet_sizes - number of allowed packet sizes.
- // packet_sizes_samples - list of the allowed packet sizes.
- // basic_block_samples - assigned a value different from 0 if the codec
- // requires to be fed with a specific number of samples
- // that can be different from packet size.
- // channel_support - number of channels supported to encode;
- // 1 = mono, 2 = stereo, etc.
- struct CodecSettings {
- int num_packet_sizes;
- int packet_sizes_samples[kMaxNumPacketSize];
- int basic_block_samples;
- size_t channel_support;
- };
-
- // Returns codec id from database, given the information received in the input
- // [codec_inst].
- // Input:
- // [codec_inst] - Information about the codec for which we require the
- // database id.
- // Return:
- // codec id if successful, otherwise < 0.
- static int CodecNumber(const CodecInst& codec_inst);
- static int CodecId(const CodecInst& codec_inst);
- static int CodecId(const char* payload_name, int frequency, size_t channels);
- static int ReceiverCodecNumber(const CodecInst& codec_inst);
-
- // Databases with information about the supported codecs
- // database_ - stored information about all codecs: payload type, name,
- // sampling frequency, packet size in samples, default channel
- // support, and default rate.
- // codec_settings_ - stored codec settings: number of allowed packet sizes,
- // a vector with the allowed packet sizes, basic block
- // samples, and max number of channels that are supported.
- // neteq_decoders_ - list of supported decoders in NetEQ.
- static const CodecInst database_[kMaxNumCodecs];
- static const CodecSettings codec_settings_[kMaxNumCodecs];
- static const NetEqDecoder neteq_decoders_[kMaxNumCodecs];
-};
-
-} // namespace acm2
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_
diff --git a/modules/audio_coding/acm2/acm_receive_test.cc b/modules/audio_coding/acm2/acm_receive_test.cc
index c149ec1..078c991 100644
--- a/modules/audio_coding/acm2/acm_receive_test.cc
+++ b/modules/audio_coding/acm2/acm_receive_test.cc
@@ -14,9 +14,7 @@
#include <memory>
-#include "absl/strings/match.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/audio_coding/include/audio_coding_module.h"
#include "modules/audio_coding/neteq/tools/audio_sink.h"
#include "modules/audio_coding/neteq/tools/packet.h"
@@ -28,89 +26,6 @@
namespace test {
namespace {
-// Returns true if the codec should be registered, otherwise false. Changes
-// the number of channels for the Opus codec to always be 1.
-bool ModifyAndUseThisCodec(CodecInst* codec_param) {
- if (absl::EqualsIgnoreCase(codec_param->plname, "CN") &&
- codec_param->plfreq == 48000)
- return false; // Skip 48 kHz comfort noise.
-
- if (absl::EqualsIgnoreCase(codec_param->plname, "telephone-event"))
- return false; // Skip DTFM.
-
- return true;
-}
-
-// Remaps payload types from ACM's default to those used in the resource file
-// neteq_universal_new.rtp. Returns true if the codec should be registered,
-// otherwise false. The payload types are set as follows (all are mono codecs):
-// PCMu = 0;
-// PCMa = 8;
-// Comfort noise 8 kHz = 13
-// Comfort noise 16 kHz = 98
-// Comfort noise 32 kHz = 99
-// iLBC = 102
-// iSAC wideband = 103
-// iSAC super-wideband = 104
-// AVT/DTMF = 106
-// RED = 117
-// PCM16b 8 kHz = 93
-// PCM16b 16 kHz = 94
-// PCM16b 32 kHz = 95
-// G.722 = 94
-bool RemapPltypeAndUseThisCodec(const char* plname,
- int plfreq,
- size_t channels,
- int* pltype) {
- if (channels != 1)
- return false; // Don't use non-mono codecs.
-
- // Re-map pltypes to those used in the NetEq test files.
- if (absl::EqualsIgnoreCase(plname, "PCMU") && plfreq == 8000) {
- *pltype = 0;
- } else if (absl::EqualsIgnoreCase(plname, "PCMA") && plfreq == 8000) {
- *pltype = 8;
- } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 8000) {
- *pltype = 13;
- } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 16000) {
- *pltype = 98;
- } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 32000) {
- *pltype = 99;
- } else if (absl::EqualsIgnoreCase(plname, "ILBC")) {
- *pltype = 102;
- } else if (absl::EqualsIgnoreCase(plname, "ISAC") && plfreq == 16000) {
- *pltype = 103;
- } else if (absl::EqualsIgnoreCase(plname, "ISAC") && plfreq == 32000) {
- *pltype = 104;
- } else if (absl::EqualsIgnoreCase(plname, "telephone-event") &&
- plfreq == 8000) {
- *pltype = 106;
- } else if (absl::EqualsIgnoreCase(plname, "telephone-event") &&
- plfreq == 16000) {
- *pltype = 114;
- } else if (absl::EqualsIgnoreCase(plname, "telephone-event") &&
- plfreq == 32000) {
- *pltype = 115;
- } else if (absl::EqualsIgnoreCase(plname, "telephone-event") &&
- plfreq == 48000) {
- *pltype = 116;
- } else if (absl::EqualsIgnoreCase(plname, "red")) {
- *pltype = 117;
- } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 8000) {
- *pltype = 93;
- } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 16000) {
- *pltype = 94;
- } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 32000) {
- *pltype = 95;
- } else if (absl::EqualsIgnoreCase(plname, "G722")) {
- *pltype = 9;
- } else {
- // Don't use any other codecs.
- return false;
- }
- return true;
-}
-
AudioCodingModule::Config MakeAcmConfig(
Clock* clock,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) {
@@ -119,7 +34,6 @@
config.decoder_factory = std::move(decoder_factory);
return config;
}
-
} // namespace
AcmReceiveTestOldApi::AcmReceiveTestOldApi(
@@ -139,36 +53,43 @@
AcmReceiveTestOldApi::~AcmReceiveTestOldApi() = default;
void AcmReceiveTestOldApi::RegisterDefaultCodecs() {
- CodecInst my_codec_param;
- for (int n = 0; n < acm_->NumberOfCodecs(); n++) {
- ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec.";
- if (ModifyAndUseThisCodec(&my_codec_param)) {
- ASSERT_EQ(true,
- acm_->RegisterReceiveCodec(my_codec_param.pltype,
- CodecInstToSdp(my_codec_param)))
- << "Couldn't register receive codec.\n";
- }
- }
+ acm_->SetReceiveCodecs({{103, {"ISAC", 16000, 1}},
+ {104, {"ISAC", 32000, 1}},
+ {107, {"L16", 8000, 1}},
+ {108, {"L16", 16000, 1}},
+ {109, {"L16", 32000, 1}},
+ {111, {"L16", 8000, 2}},
+ {112, {"L16", 16000, 2}},
+ {113, {"L16", 32000, 2}},
+ {0, {"PCMU", 8000, 1}},
+ {110, {"PCMU", 8000, 2}},
+ {8, {"PCMA", 8000, 1}},
+ {118, {"PCMA", 8000, 2}},
+ {102, {"ILBC", 8000, 1}},
+ {9, {"G722", 8000, 1}},
+ {119, {"G722", 8000, 2}},
+ {120, {"OPUS", 48000, 2, {{"stereo", "1"}}}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
}
+// Remaps payload types from ACM's default to those used in the resource file
+// neteq_universal_new.rtp.
void AcmReceiveTestOldApi::RegisterNetEqTestCodecs() {
- CodecInst my_codec_param;
- for (int n = 0; n < acm_->NumberOfCodecs(); n++) {
- ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec.";
- if (!ModifyAndUseThisCodec(&my_codec_param)) {
- // Skip this codec.
- continue;
- }
-
- if (RemapPltypeAndUseThisCodec(my_codec_param.plname, my_codec_param.plfreq,
- my_codec_param.channels,
- &my_codec_param.pltype)) {
- ASSERT_EQ(true,
- acm_->RegisterReceiveCodec(my_codec_param.pltype,
- CodecInstToSdp(my_codec_param)))
- << "Couldn't register receive codec.\n";
- }
- }
+ acm_->SetReceiveCodecs({{103, {"ISAC", 16000, 1}},
+ {104, {"ISAC", 32000, 1}},
+ {93, {"L16", 8000, 1}},
+ {94, {"L16", 16000, 1}},
+ {95, {"L16", 32000, 1}},
+ {0, {"PCMU", 8000, 1}},
+ {8, {"PCMA", 8000, 1}},
+ {102, {"ILBC", 8000, 1}},
+ {9, {"G722", 8000, 1}},
+ {120, {"OPUS", 48000, 2}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
}
void AcmReceiveTestOldApi::Run() {
@@ -199,18 +120,15 @@
AfterGetAudio();
}
- // Insert packet after converting from RTPHeader to WebRtcRTPHeader.
- WebRtcRTPHeader header;
- header.header = packet->header();
- header.frameType = kAudioFrameSpeech;
- EXPECT_EQ(0,
- acm_->IncomingPacket(
- packet->payload(),
- static_cast<int32_t>(packet->payload_length_bytes()), header))
+ EXPECT_EQ(0, acm_->IncomingPacket(
+ packet->payload(),
+ static_cast<int32_t>(packet->payload_length_bytes()),
+ packet->header()))
<< "Failure when inserting packet:" << std::endl
- << " PT = " << static_cast<int>(header.header.payloadType) << std::endl
- << " TS = " << header.header.timestamp << std::endl
- << " SN = " << header.header.sequenceNumber;
+ << " PT = " << static_cast<int>(packet->header().payloadType)
+ << std::endl
+ << " TS = " << packet->header().timestamp << std::endl
+ << " SN = " << packet->header().sequenceNumber;
}
}
diff --git a/modules/audio_coding/acm2/acm_receive_test.h b/modules/audio_coding/acm2/acm_receive_test.h
index 83ffcb3..9d004c6 100644
--- a/modules/audio_coding/acm2/acm_receive_test.h
+++ b/modules/audio_coding/acm2/acm_receive_test.h
@@ -16,14 +16,13 @@
#include <string>
#include "api/audio_codecs/audio_decoder_factory.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/constructor_magic.h"
#include "system_wrappers/include/clock.h"
namespace webrtc {
class AudioCodingModule;
class AudioDecoder;
-struct CodecInst;
namespace test {
class AudioSink;
@@ -34,7 +33,8 @@
enum NumOutputChannels : size_t {
kArbitraryChannels = 0,
kMonoOutput = 1,
- kStereoOutput = 2
+ kStereoOutput = 2,
+ kQuadOutput = 4
};
AcmReceiveTestOldApi(PacketSource* packet_source,
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc
index d3af7c0..da7d621 100644
--- a/modules/audio_coding/acm2/acm_receiver.cc
+++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -20,9 +20,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "modules/audio_coding/acm2/acm_resampler.h"
#include "modules/audio_coding/acm2/call_statistics.h"
-#include "modules/audio_coding/acm2/rent_a_codec.h"
#include "modules/audio_coding/neteq/include/neteq.h"
-#include "modules/audio_coding/neteq/neteq_decoder_enum.h"
#include "modules/include/module_common_types.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
@@ -60,56 +58,66 @@
return -1;
}
+bool AcmReceiver::SetBaseMinimumDelayMs(int delay_ms) {
+ return neteq_->SetBaseMinimumDelayMs(delay_ms);
+}
+
+int AcmReceiver::GetBaseMinimumDelayMs() const {
+ return neteq_->GetBaseMinimumDelayMs();
+}
+
absl::optional<int> AcmReceiver::last_packet_sample_rate_hz() const {
rtc::CritScope lock(&crit_sect_);
- return last_packet_sample_rate_hz_;
+ if (!last_decoder_) {
+ return absl::nullopt;
+ }
+ return last_decoder_->second.clockrate_hz;
}
int AcmReceiver::last_output_sample_rate_hz() const {
return neteq_->last_output_sample_rate_hz();
}
-int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
+int AcmReceiver::InsertPacket(const RTPHeader& rtp_header,
rtc::ArrayView<const uint8_t> incoming_payload) {
- uint32_t receive_timestamp = 0;
- const RTPHeader* header = &rtp_header.header; // Just a shorthand.
-
if (incoming_payload.empty()) {
- neteq_->InsertEmptyPacket(rtp_header.header);
+ neteq_->InsertEmptyPacket(rtp_header);
return 0;
}
+ int payload_type = rtp_header.payloadType;
+ auto format = neteq_->GetDecoderFormat(payload_type);
+ if (format && absl::EqualsIgnoreCase(format->name, "red")) {
+ // This is a RED packet. Get the format of the audio codec.
+ payload_type = incoming_payload[0] & 0x7f;
+ format = neteq_->GetDecoderFormat(payload_type);
+ }
+ if (!format) {
+ RTC_LOG_F(LS_ERROR) << "Payload-type "
+ << payload_type
+ << " is not registered.";
+ return -1;
+ }
+
{
rtc::CritScope lock(&crit_sect_);
-
- const absl::optional<CodecInst> ci =
- RtpHeaderToDecoder(*header, incoming_payload[0]);
- if (!ci) {
- RTC_LOG_F(LS_ERROR) << "Payload-type "
- << static_cast<int>(header->payloadType)
- << " is not registered.";
- return -1;
- }
- receive_timestamp = NowInTimestamp(ci->plfreq);
-
- if (absl::EqualsIgnoreCase(ci->plname, "cn")) {
- if (last_audio_decoder_ && last_audio_decoder_->channels > 1) {
+ if (absl::EqualsIgnoreCase(format->name, "cn")) {
+ if (last_decoder_ && last_decoder_->second.num_channels > 1) {
// This is a CNG and the audio codec is not mono, so skip pushing in
// packets into NetEq.
return 0;
}
} else {
- last_audio_decoder_ = ci;
- last_audio_format_ = neteq_->GetDecoderFormat(ci->pltype);
- RTC_DCHECK(last_audio_format_);
- last_packet_sample_rate_hz_ = ci->plfreq;
+ RTC_DCHECK(format);
+ last_decoder_ = std::make_pair(payload_type, *format);
}
} // |crit_sect_| is released.
- if (neteq_->InsertPacket(rtp_header.header, incoming_payload,
- receive_timestamp) < 0) {
+ uint32_t receive_timestamp = NowInTimestamp(format->clockrate_hz);
+ if (neteq_->InsertPacket(rtp_header, incoming_payload, receive_timestamp) <
+ 0) {
RTC_LOG(LERROR) << "AcmReceiver::InsertPacket "
- << static_cast<int>(header->payloadType)
+ << static_cast<int>(rtp_header.payloadType)
<< " Failed to insert packet";
return -1;
}
@@ -186,85 +194,6 @@
neteq_->SetCodecs(codecs);
}
-int32_t AcmReceiver::AddCodec(int acm_codec_id,
- uint8_t payload_type,
- size_t channels,
- int /*sample_rate_hz*/,
- AudioDecoder* audio_decoder,
- const std::string& name) {
- // TODO(kwiberg): This function has been ignoring the |sample_rate_hz|
- // argument for a long time. Arguably, it should simply be removed.
-
- const auto neteq_decoder = [acm_codec_id, channels]() -> NetEqDecoder {
- if (acm_codec_id == -1)
- return NetEqDecoder::kDecoderArbitrary; // External decoder.
- const absl::optional<RentACodec::CodecId> cid =
- RentACodec::CodecIdFromIndex(acm_codec_id);
- RTC_DCHECK(cid) << "Invalid codec index: " << acm_codec_id;
- const absl::optional<NetEqDecoder> ned =
- RentACodec::NetEqDecoderFromCodecId(*cid, channels);
- RTC_DCHECK(ned) << "Invalid codec ID: " << static_cast<int>(*cid);
- return *ned;
- }();
- const absl::optional<SdpAudioFormat> new_format =
- NetEqDecoderToSdpAudioFormat(neteq_decoder);
-
- rtc::CritScope lock(&crit_sect_);
-
- const auto old_format = neteq_->GetDecoderFormat(payload_type);
- if (old_format && new_format && *old_format == *new_format) {
- // Re-registering the same codec. Do nothing and return.
- return 0;
- }
-
- if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) {
- RTC_LOG(LERROR) << "Cannot remove payload "
- << static_cast<int>(payload_type);
- return -1;
- }
-
- int ret_val;
- if (!audio_decoder) {
- ret_val = neteq_->RegisterPayloadType(neteq_decoder, name, payload_type);
- } else {
- ret_val = neteq_->RegisterExternalDecoder(audio_decoder, neteq_decoder,
- name, payload_type);
- }
- if (ret_val != NetEq::kOK) {
- RTC_LOG(LERROR) << "AcmReceiver::AddCodec " << acm_codec_id
- << static_cast<int>(payload_type)
- << " channels: " << channels;
- return -1;
- }
- return 0;
-}
-
-bool AcmReceiver::AddCodec(int rtp_payload_type,
- const SdpAudioFormat& audio_format) {
- const auto old_format = neteq_->GetDecoderFormat(rtp_payload_type);
- if (old_format && *old_format == audio_format) {
- // Re-registering the same codec. Do nothing and return.
- return true;
- }
-
- if (neteq_->RemovePayloadType(rtp_payload_type) != NetEq::kOK) {
- RTC_LOG(LERROR)
- << "AcmReceiver::AddCodec: Could not remove existing decoder"
- " for payload type "
- << rtp_payload_type;
- return false;
- }
-
- const bool success =
- neteq_->RegisterPayloadType(rtp_payload_type, audio_format);
- if (!success) {
- RTC_LOG(LERROR) << "AcmReceiver::AddCodec failed for payload type "
- << rtp_payload_type << ", decoder format "
- << rtc::ToString(audio_format);
- }
- return success;
-}
-
void AcmReceiver::FlushBuffers() {
neteq_->FlushBuffers();
}
@@ -272,24 +201,7 @@
void AcmReceiver::RemoveAllCodecs() {
rtc::CritScope lock(&crit_sect_);
neteq_->RemoveAllPayloadTypes();
- last_audio_decoder_ = absl::nullopt;
- last_audio_format_ = absl::nullopt;
- last_packet_sample_rate_hz_ = absl::nullopt;
-}
-
-int AcmReceiver::RemoveCodec(uint8_t payload_type) {
- rtc::CritScope lock(&crit_sect_);
- if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) {
- RTC_LOG(LERROR) << "AcmReceiver::RemoveCodec "
- << static_cast<int>(payload_type);
- return -1;
- }
- if (last_audio_decoder_ && payload_type == last_audio_decoder_->pltype) {
- last_audio_decoder_ = absl::nullopt;
- last_audio_format_ = absl::nullopt;
- last_packet_sample_rate_hz_ = absl::nullopt;
- }
- return 0;
+ last_decoder_ = absl::nullopt;
}
absl::optional<uint32_t> AcmReceiver::GetPlayoutTimestamp() {
@@ -304,18 +216,14 @@
return neteq_->TargetDelayMs();
}
-int AcmReceiver::LastAudioCodec(CodecInst* codec) const {
+absl::optional<std::pair<int, SdpAudioFormat>>
+ AcmReceiver::LastDecoder() const {
rtc::CritScope lock(&crit_sect_);
- if (!last_audio_decoder_) {
- return -1;
+ if (!last_decoder_) {
+ return absl::nullopt;
}
- *codec = *last_audio_decoder_;
- return 0;
-}
-
-absl::optional<SdpAudioFormat> AcmReceiver::LastAudioFormat() const {
- rtc::CritScope lock(&crit_sect_);
- return last_audio_format_;
+ RTC_DCHECK_NE(-1, last_decoder_->first); // Payload type should be valid.
+ return last_decoder_;
}
void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) {
@@ -345,8 +253,12 @@
acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples;
acm_stat->concealmentEvents = neteq_lifetime_stat.concealment_events;
acm_stat->jitterBufferDelayMs = neteq_lifetime_stat.jitter_buffer_delay_ms;
+ acm_stat->jitterBufferEmittedCount =
+ neteq_lifetime_stat.jitter_buffer_emitted_count;
acm_stat->delayedPacketOutageSamples =
neteq_lifetime_stat.delayed_packet_outage_samples;
+ acm_stat->relativePacketArrivalDelayMs =
+ neteq_lifetime_stat.relative_packet_arrival_delay_ms;
NetEqOperationsAndState neteq_operations_and_state =
neteq_->GetOperationsAndState();
@@ -354,26 +266,6 @@
neteq_operations_and_state.packet_buffer_flushes;
}
-int AcmReceiver::DecoderByPayloadType(uint8_t payload_type,
- CodecInst* codec) const {
- rtc::CritScope lock(&crit_sect_);
- const absl::optional<CodecInst> ci = neteq_->GetDecoder(payload_type);
- if (ci) {
- *codec = *ci;
- return 0;
- } else {
- RTC_LOG(LERROR) << "AcmReceiver::DecoderByPayloadType "
- << static_cast<int>(payload_type);
- return -1;
- }
-}
-
-absl::optional<SdpAudioFormat> AcmReceiver::DecoderByPayloadType(
- int payload_type) const {
- rtc::CritScope lock(&crit_sect_);
- return neteq_->GetDecoderFormat(payload_type);
-}
-
int AcmReceiver::EnableNack(size_t max_nack_list_size) {
neteq_->EnableNack(max_nack_list_size);
return 0;
@@ -393,19 +285,6 @@
// TODO(turajs): Should NetEq Buffer be flushed?
}
-const absl::optional<CodecInst> AcmReceiver::RtpHeaderToDecoder(
- const RTPHeader& rtp_header,
- uint8_t first_payload_byte) const {
- const absl::optional<CodecInst> ci =
- neteq_->GetDecoder(rtp_header.payloadType);
- if (ci && absl::EqualsIgnoreCase(ci->plname, "red")) {
- // This is a RED packet. Get the payload of the audio codec.
- return neteq_->GetDecoder(first_payload_byte & 0x7f);
- } else {
- return ci;
- }
-}
-
uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const {
// Down-cast the time to (32-6)-bit since we only care about
// the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms.
diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h
index 8e7d839..1f449a3 100644
--- a/modules/audio_coding/acm2/acm_receiver.h
+++ b/modules/audio_coding/acm2/acm_receiver.h
@@ -15,6 +15,7 @@
#include <map>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "absl/types/optional.h"
@@ -24,16 +25,14 @@
#include "modules/audio_coding/acm2/acm_resampler.h"
#include "modules/audio_coding/acm2/call_statistics.h"
#include "modules/audio_coding/include/audio_coding_module.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
class Clock;
-struct CodecInst;
class NetEq;
struct RTPHeader;
-struct WebRtcRTPHeader;
namespace acm2 {
@@ -58,7 +57,7 @@
// Return value : 0 if OK.
// <0 if NetEq returned an error.
//
- int InsertPacket(const WebRtcRTPHeader& rtp_header,
+ int InsertPacket(const RTPHeader& rtp_header,
rtc::ArrayView<const uint8_t> incoming_payload);
//
@@ -85,43 +84,6 @@
void SetCodecs(const std::map<int, SdpAudioFormat>& codecs);
//
- // Adds a new codec to the NetEq codec database.
- //
- // Input:
- // - acm_codec_id : ACM codec ID; -1 means external decoder.
- // - payload_type : payload type.
- // - sample_rate_hz : sample rate.
- // - audio_decoder : pointer to a decoder object. If it's null, then
- // NetEq will internally create a decoder object
- // based on the value of |acm_codec_id| (which
- // mustn't be -1). Otherwise, NetEq will use the
- // given decoder for the given payload type. NetEq
- // won't take ownership of the decoder; it's up to
- // the caller to delete it when it's no longer
- // needed.
- //
- // Providing an existing decoder object here is
- // necessary for external decoders, but may also be
- // used for built-in decoders if NetEq doesn't have
- // all the info it needs to construct them properly
- // (e.g. iSAC, where the decoder needs to be paired
- // with an encoder).
- //
- // Return value : 0 if OK.
- // <0 if NetEq returned an error.
- //
- int AddCodec(int acm_codec_id,
- uint8_t payload_type,
- size_t channels,
- int sample_rate_hz,
- AudioDecoder* audio_decoder,
- const std::string& name);
-
- // Adds a new decoder to the NetEq codec database. Returns true iff
- // successful.
- bool AddCodec(int rtp_payload_type, const SdpAudioFormat& audio_format);
-
- //
// Sets a minimum delay for packet buffer. The given delay is maintained,
// unless channel condition dictates a higher delay.
//
@@ -145,6 +107,16 @@
//
int SetMaximumDelay(int delay_ms);
+ // Sets a base minimum delay in milliseconds for the packet buffer.
+ // Base minimum delay sets lower bound minimum delay value which
+ // is set via SetMinimumDelay.
+ //
+ // Returns true if value was successfully set, false overwise.
+ bool SetBaseMinimumDelayMs(int delay_ms);
+
+ // Returns current value of base minimum delay in milliseconds.
+ int GetBaseMinimumDelayMs() const;
+
//
// Resets the initial delay to zero.
//
@@ -173,17 +145,6 @@
void FlushBuffers();
//
- // Removes a payload-type from the NetEq codec database.
- //
- // Input:
- // - payload_type : the payload-type to be removed.
- //
- // Return value : 0 if OK.
- // -1 if an error occurred.
- //
- int RemoveCodec(uint8_t payload_type);
-
- //
// Remove all registered codecs.
//
void RemoveAllCodecs();
@@ -204,30 +165,10 @@
int TargetDelayMs() const;
//
- // Get the audio codec associated with the last non-CNG/non-DTMF received
- // payload. If no non-CNG/non-DTMF packet is received -1 is returned,
- // otherwise return 0.
+ // Get payload type and format of the last non-CNG/non-DTMF received payload.
+ // If no non-CNG/non-DTMF packet is received absl::nullopt is returned.
//
- int LastAudioCodec(CodecInst* codec) const;
-
- absl::optional<SdpAudioFormat> LastAudioFormat() const;
-
- //
- // Get a decoder given its registered payload-type.
- //
- // Input:
- // -payload_type : the payload-type of the codec to be retrieved.
- //
- // Output:
- // -codec : codec associated with the given payload-type.
- //
- // Return value : 0 if succeeded.
- // -1 if failed, e.g. given payload-type is not
- // registered.
- //
- int DecoderByPayloadType(uint8_t payload_type,
- CodecInst* codec) const;
- absl::optional<SdpAudioFormat> DecoderByPayloadType(int payload_type) const;
+ absl::optional<std::pair<int, SdpAudioFormat>> LastDecoder() const;
//
// Enable NACK and set the maximum size of the NACK list. If NACK is already
@@ -260,32 +201,17 @@
void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
private:
- struct Decoder {
- int acm_codec_id;
- uint8_t payload_type;
- // This field is meaningful for codecs where both mono and
- // stereo versions are registered under the same ID.
- size_t channels;
- int sample_rate_hz;
- };
-
- const absl::optional<CodecInst> RtpHeaderToDecoder(
- const RTPHeader& rtp_header,
- uint8_t first_payload_byte) const
- RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
-
uint32_t NowInTimestamp(int decoder_sampling_rate) const;
rtc::CriticalSection crit_sect_;
- absl::optional<CodecInst> last_audio_decoder_ RTC_GUARDED_BY(crit_sect_);
- absl::optional<SdpAudioFormat> last_audio_format_ RTC_GUARDED_BY(crit_sect_);
+ absl::optional<std::pair<int, SdpAudioFormat>> last_decoder_
+ RTC_GUARDED_BY(crit_sect_);
ACMResampler resampler_ RTC_GUARDED_BY(crit_sect_);
std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(crit_sect_);
CallStatistics call_stats_ RTC_GUARDED_BY(crit_sect_);
const std::unique_ptr<NetEq> neteq_; // NetEq is thread-safe; no lock needed.
- const Clock* const clock_;
+ Clock* const clock_;
bool resampled_last_output_frame_ RTC_GUARDED_BY(crit_sect_);
- absl::optional<int> last_packet_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
};
} // namespace acm2
diff --git a/modules/audio_coding/acm2/acm_receiver_unittest.cc b/modules/audio_coding/acm2/acm_receiver_unittest.cc
index 46384fe..e5a7684 100644
--- a/modules/audio_coding/acm2/acm_receiver_unittest.cc
+++ b/modules/audio_coding/acm2/acm_receiver_unittest.cc
@@ -15,7 +15,6 @@
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
-#include "modules/audio_coding/acm2/rent_a_codec.h"
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
#include "modules/audio_coding/include/audio_coding_module.h"
#include "modules/audio_coding/neteq/tools/rtp_generator.h"
@@ -24,7 +23,7 @@
#include "rtc_base/numerics/safe_conversions.h"
#include "system_wrappers/include/clock.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -51,13 +50,12 @@
acm_->InitializeReceiver();
acm_->RegisterTransportCallback(this);
- rtp_header_.header.sequenceNumber = 0;
- rtp_header_.header.timestamp = 0;
- rtp_header_.header.markerBit = false;
- rtp_header_.header.ssrc = 0x12345678; // Arbitrary.
- rtp_header_.header.numCSRCs = 0;
- rtp_header_.header.payloadType = 0;
- rtp_header_.frameType = kAudioFrameSpeech;
+ rtp_header_.sequenceNumber = 0;
+ rtp_header_.timestamp = 0;
+ rtp_header_.markerBit = false;
+ rtp_header_.ssrc = 0x12345678; // Arbitrary.
+ rtp_header_.numCSRCs = 0;
+ rtp_header_.payloadType = 0;
}
void TearDown() override {}
@@ -105,14 +103,6 @@
return num_10ms_frames;
}
- template <size_t N>
- void AddSetOfCodecs(rtc::ArrayView<SdpAudioFormat> formats) {
- static int payload_type = 0;
- for (const auto& format : formats) {
- EXPECT_TRUE(receiver_->AddCodec(payload_type++, format));
- }
- }
-
int SendData(FrameType frame_type,
uint8_t payload_type,
uint32_t timestamp,
@@ -122,9 +112,8 @@
if (frame_type == kEmptyFrame)
return 0;
- rtp_header_.header.payloadType = payload_type;
- rtp_header_.frameType = frame_type;
- rtp_header_.header.timestamp = timestamp;
+ rtp_header_.payloadType = payload_type;
+ rtp_header_.timestamp = timestamp;
int ret_val = receiver_->InsertPacket(
rtp_header_,
@@ -133,7 +122,7 @@
assert(false);
return -1;
}
- rtp_header_.header.sequenceNumber++;
+ rtp_header_.sequenceNumber++;
packet_sent_ = true;
last_frame_type_ = frame_type;
return 0;
@@ -146,7 +135,7 @@
AudioCodingModule::Config config_;
std::unique_ptr<AcmReceiver> receiver_;
std::unique_ptr<AudioCodingModule> acm_;
- WebRtcRTPHeader rtp_header_;
+ RTPHeader rtp_header_;
uint32_t timestamp_;
bool packet_sent_; // Set when SendData is called reset when inserting audio.
uint32_t last_packet_send_timestamp_;
@@ -154,111 +143,26 @@
};
#if defined(WEBRTC_ANDROID)
-#define MAYBE_AddCodecGetCodec DISABLED_AddCodecGetCodec
-#else
-#define MAYBE_AddCodecGetCodec AddCodecGetCodec
-#endif
-TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecGetCodec) {
- const std::vector<AudioCodecSpec> codecs =
- decoder_factory_->GetSupportedDecoders();
-
- // Add codec.
- for (size_t n = 0; n < codecs.size(); ++n) {
- if (n & 0x1) { // Just add codecs with odd index.
- const int payload_type = rtc::checked_cast<int>(n);
- EXPECT_TRUE(receiver_->AddCodec(payload_type, codecs[n].format));
- }
- }
- // Get codec and compare.
- for (size_t n = 0; n < codecs.size(); ++n) {
- const int payload_type = rtc::checked_cast<int>(n);
- if (n & 0x1) {
- // Codecs with odd index should match the reference.
- EXPECT_EQ(absl::make_optional(codecs[n].format),
- receiver_->DecoderByPayloadType(payload_type));
- } else {
- // Codecs with even index are not registered.
- EXPECT_EQ(absl::nullopt, receiver_->DecoderByPayloadType(payload_type));
- }
- }
-}
-
-#if defined(WEBRTC_ANDROID)
-#define MAYBE_AddCodecChangePayloadType DISABLED_AddCodecChangePayloadType
-#else
-#define MAYBE_AddCodecChangePayloadType AddCodecChangePayloadType
-#endif
-TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecChangePayloadType) {
- const SdpAudioFormat format("giraffe", 8000, 1);
-
- // Register the same codec with different payloads.
- EXPECT_EQ(true, receiver_->AddCodec(17, format));
- EXPECT_EQ(true, receiver_->AddCodec(18, format));
-
- // Both payload types should exist.
- EXPECT_EQ(absl::make_optional(format), receiver_->DecoderByPayloadType(17));
- EXPECT_EQ(absl::make_optional(format), receiver_->DecoderByPayloadType(18));
-}
-
-#if defined(WEBRTC_ANDROID)
-#define MAYBE_AddCodecChangeCodecId DISABLED_AddCodecChangeCodecId
-#else
-#define MAYBE_AddCodecChangeCodecId AddCodecChangeCodecId
-#endif
-TEST_F(AcmReceiverTestOldApi, AddCodecChangeCodecId) {
- const SdpAudioFormat format1("giraffe", 8000, 1);
- const SdpAudioFormat format2("gnu", 16000, 1);
-
- // Register the same payload type with different codec ID.
- EXPECT_EQ(true, receiver_->AddCodec(17, format1));
- EXPECT_EQ(true, receiver_->AddCodec(17, format2));
-
- // Make sure that the last codec is used.
- EXPECT_EQ(absl::make_optional(format2), receiver_->DecoderByPayloadType(17));
-}
-
-#if defined(WEBRTC_ANDROID)
-#define MAYBE_AddCodecRemoveCodec DISABLED_AddCodecRemoveCodec
-#else
-#define MAYBE_AddCodecRemoveCodec AddCodecRemoveCodec
-#endif
-TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecRemoveCodec) {
- EXPECT_EQ(true, receiver_->AddCodec(17, SdpAudioFormat("giraffe", 8000, 1)));
-
- // Remove non-existing codec should not fail. ACM1 legacy.
- EXPECT_EQ(0, receiver_->RemoveCodec(18));
-
- // Remove an existing codec.
- EXPECT_EQ(0, receiver_->RemoveCodec(17));
-
- // Ask for the removed codec, must fail.
- EXPECT_EQ(absl::nullopt, receiver_->DecoderByPayloadType(17));
-}
-
-#if defined(WEBRTC_ANDROID)
#define MAYBE_SampleRate DISABLED_SampleRate
#else
#define MAYBE_SampleRate SampleRate
#endif
TEST_F(AcmReceiverTestOldApi, MAYBE_SampleRate) {
- const std::vector<SdpAudioFormat> codecs = {{"ISAC", 16000, 1},
- {"ISAC", 32000, 1}};
- for (size_t i = 0; i < codecs.size(); ++i) {
- const int payload_type = rtc::checked_cast<int>(i);
- EXPECT_EQ(true, receiver_->AddCodec(payload_type, codecs[i]));
- }
+ const std::map<int, SdpAudioFormat> codecs = {{0, {"ISAC", 16000, 1}},
+ {1, {"ISAC", 32000, 1}}};
+ receiver_->SetCodecs(codecs);
constexpr int kOutSampleRateHz = 8000; // Different than codec sample rate.
for (size_t i = 0; i < codecs.size(); ++i) {
const int payload_type = rtc::checked_cast<int>(i);
const int num_10ms_frames =
- InsertOnePacketOfSilence(SetEncoder(payload_type, codecs[i]));
+ InsertOnePacketOfSilence(SetEncoder(payload_type, codecs.at(i)));
for (int k = 0; k < num_10ms_frames; ++k) {
AudioFrame frame;
bool muted;
EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame, &muted));
}
- EXPECT_EQ(encoder_factory_->QueryAudioEncoder(codecs[i])->sample_rate_hz,
+ EXPECT_EQ(encoder_factory_->QueryAudioEncoder(codecs.at(i))->sample_rate_hz,
receiver_->last_output_sample_rate_hz());
}
}
@@ -278,7 +182,7 @@
EXPECT_TRUE(config_.neteq_config.for_test_no_time_stretching);
constexpr int payload_type = 17;
- EXPECT_TRUE(receiver_->AddCodec(payload_type, codec));
+ receiver_->SetCodecs({{payload_type, codec}});
const AudioCodecInfo info = SetEncoder(payload_type, codec);
const int output_sample_rate_hz = info.sample_rate_hz;
@@ -356,7 +260,7 @@
constexpr int payload_type = 34;
const SdpAudioFormat codec = {"L16", 16000, 1};
const AudioCodecInfo info = SetEncoder(payload_type, codec);
- EXPECT_TRUE(receiver_->AddCodec(payload_type, codec));
+ receiver_->SetCodecs({{payload_type, codec}});
constexpr int kNumPackets = 5;
AudioFrame frame;
for (int n = 0; n < kNumPackets; ++n) {
@@ -387,7 +291,7 @@
const SdpAudioFormat codec = {"L16", 16000, 1};
const AudioCodecInfo info = SetEncoder(payload_type, codec);
encoder_factory_->QueryAudioEncoder(codec).value();
- EXPECT_TRUE(receiver_->AddCodec(payload_type, codec));
+ receiver_->SetCodecs({{payload_type, codec}});
const int kNumPackets = 5;
AudioFrame frame;
for (int n = 0; n < kNumPackets; ++n) {
@@ -407,43 +311,43 @@
#endif
#if defined(WEBRTC_CODEC_ISAC)
TEST_F(AcmReceiverTestOldApi, MAYBE_LastAudioCodec) {
- const std::vector<SdpAudioFormat> codecs = {{"ISAC", 16000, 1},
- {"PCMA", 8000, 1},
- {"ISAC", 32000, 1},
- {"L16", 32000, 1}};
- for (size_t i = 0; i < codecs.size(); ++i) {
- const int payload_type = rtc::checked_cast<int>(i);
- EXPECT_TRUE(receiver_->AddCodec(payload_type, codecs[i]));
- }
-
- const std::map<int, int> cng_payload_types = {
- {8000, 100}, {16000, 101}, {32000, 102}};
- for (const auto& x : cng_payload_types) {
- const int sample_rate_hz = x.first;
- const int payload_type = x.second;
- EXPECT_TRUE(receiver_->AddCodec(payload_type, {"CN", sample_rate_hz, 1}));
+ const std::map<int, SdpAudioFormat> codecs = {{0, {"ISAC", 16000, 1}},
+ {1, {"PCMA", 8000, 1}},
+ {2, {"ISAC", 32000, 1}},
+ {3, {"L16", 32000, 1}}};
+ const std::map<int, int> cng_payload_types = {{8000, 100},
+ {16000, 101},
+ {32000, 102}};
+ {
+ std::map<int, SdpAudioFormat> receive_codecs = codecs;
+ for (const auto& cng_type : cng_payload_types) {
+ receive_codecs.emplace(
+ std::make_pair(cng_type.second, SdpAudioFormat("CN", cng_type.first, 1)));
+ }
+ receiver_->SetCodecs(receive_codecs);
}
// No audio payload is received.
- EXPECT_EQ(absl::nullopt, receiver_->LastAudioFormat());
+ EXPECT_EQ(absl::nullopt, receiver_->LastDecoder());
// Start with sending DTX.
packet_sent_ = false;
InsertOnePacketOfSilence(
- SetEncoder(0, codecs[0], cng_payload_types)); // Enough to test
+ SetEncoder(0, codecs.at(0), cng_payload_types)); // Enough to test
// with one codec.
ASSERT_TRUE(packet_sent_);
EXPECT_EQ(kAudioFrameCN, last_frame_type_);
// Has received, only, DTX. Last Audio codec is undefined.
- EXPECT_EQ(absl::nullopt, receiver_->LastAudioFormat());
- EXPECT_FALSE(receiver_->last_packet_sample_rate_hz());
+ EXPECT_EQ(absl::nullopt, receiver_->LastDecoder());
+ EXPECT_EQ(absl::nullopt, receiver_->last_packet_sample_rate_hz());
for (size_t i = 0; i < codecs.size(); ++i) {
// Set DTX off to send audio payload.
packet_sent_ = false;
const int payload_type = rtc::checked_cast<int>(i);
- const AudioCodecInfo info_without_cng = SetEncoder(payload_type, codecs[i]);
+ const AudioCodecInfo info_without_cng =
+ SetEncoder(payload_type, codecs.at(i));
InsertOnePacketOfSilence(info_without_cng);
// Sanity check if Actually an audio payload received, and it should be
@@ -456,7 +360,7 @@
// Set VAD on to send DTX. Then check if the "Last Audio codec" returns
// the expected codec. Encode repeatedly until a DTX is sent.
const AudioCodecInfo info_with_cng =
- SetEncoder(payload_type, codecs[i], cng_payload_types);
+ SetEncoder(payload_type, codecs.at(i), cng_payload_types);
while (last_frame_type_ != kAudioFrameCN) {
packet_sent_ = false;
InsertOnePacketOfSilence(info_with_cng);
@@ -464,7 +368,7 @@
}
EXPECT_EQ(info_with_cng.sample_rate_hz,
receiver_->last_packet_sample_rate_hz());
- EXPECT_EQ(codecs[i], receiver_->LastAudioFormat());
+ EXPECT_EQ(codecs.at(i), receiver_->LastDecoder()->second);
}
}
#endif
diff --git a/modules/audio_coding/acm2/acm_send_test.cc b/modules/audio_coding/acm2/acm_send_test.cc
index c5e010c..b6110b6 100644
--- a/modules/audio_coding/acm2/acm_send_test.cc
+++ b/modules/audio_coding/acm2/acm_send_test.cc
@@ -14,15 +14,15 @@
#include <stdio.h>
#include <string.h>
+#include "absl/strings/match.h"
#include "api/audio_codecs/audio_encoder.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
-#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/audio_coding/include/audio_coding_module.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
#include "modules/audio_coding/neteq/tools/packet.h"
#include "rtc_base/checks.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
#include "test/gtest.h"
namespace webrtc {
@@ -59,23 +59,28 @@
AcmSendTestOldApi::~AcmSendTestOldApi() = default;
bool AcmSendTestOldApi::RegisterCodec(const char* payload_name,
- int sampling_freq_hz,
- int channels,
+ int clockrate_hz,
+ int num_channels,
int payload_type,
int frame_size_samples) {
- CodecInst codec;
- RTC_CHECK_EQ(0, AudioCodingModule::Codec(payload_name, &codec,
- sampling_freq_hz, channels));
- codec.pltype = payload_type;
- codec.pacsize = frame_size_samples;
- auto factory = CreateBuiltinAudioEncoderFactory();
- SdpAudioFormat format = CodecInstToSdp(codec);
+ SdpAudioFormat format(payload_name, clockrate_hz, num_channels);
+ if (absl::EqualsIgnoreCase(payload_name, "g722")) {
+ RTC_CHECK_EQ(16000, clockrate_hz);
+ format.clockrate_hz = 8000;
+ } else if (absl::EqualsIgnoreCase(payload_name, "opus")) {
+ RTC_CHECK(num_channels == 1 || num_channels == 2);
+ if (num_channels == 2) {
+ format.parameters["stereo"] = "1";
+ }
+ format.num_channels = 2;
+ }
format.parameters["ptime"] = rtc::ToString(rtc::CheckedDivExact(
- frame_size_samples, rtc::CheckedDivExact(sampling_freq_hz, 1000)));
+ frame_size_samples, rtc::CheckedDivExact(clockrate_hz, 1000)));
+ auto factory = CreateBuiltinAudioEncoderFactory();
acm_->SetEncoder(
factory->MakeAudioEncoder(payload_type, format, absl::nullopt));
codec_registered_ = true;
- input_frame_.num_channels_ = channels;
+ input_frame_.num_channels_ = num_channels;
assert(input_block_size_samples_ * input_frame_.num_channels_ <=
AudioFrame::kMaxDataSizeSamples);
return codec_registered_;
@@ -101,13 +106,9 @@
// Insert audio and process until one packet is produced.
while (clock_.TimeInMilliseconds() < test_duration_ms_) {
clock_.AdvanceTimeMilliseconds(kBlockSizeMs);
- RTC_CHECK(audio_source_->Read(input_block_size_samples_,
- input_frame_.mutable_data()));
- if (input_frame_.num_channels_ > 1) {
- InputAudioFile::DuplicateInterleaved(
- input_frame_.data(), input_block_size_samples_,
- input_frame_.num_channels_, input_frame_.mutable_data());
- }
+ RTC_CHECK(audio_source_->Read(
+ input_block_size_samples_ * input_frame_.num_channels_,
+ input_frame_.mutable_data()));
data_to_send_ = false;
RTC_CHECK_GE(acm_->Add10MsData(input_frame_), 0);
input_frame_.timestamp_ += static_cast<uint32_t>(input_block_size_samples_);
diff --git a/modules/audio_coding/acm2/acm_send_test.h b/modules/audio_coding/acm2/acm_send_test.h
index 3479de0..24d230b 100644
--- a/modules/audio_coding/acm2/acm_send_test.h
+++ b/modules/audio_coding/acm2/acm_send_test.h
@@ -17,7 +17,7 @@
#include "api/audio/audio_frame.h"
#include "modules/audio_coding/include/audio_coding_module.h"
#include "modules/audio_coding/neteq/tools/packet_source.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "system_wrappers/include/clock.h"
namespace webrtc {
diff --git a/modules/audio_coding/acm2/audio_coding_module.cc b/modules/audio_coding/acm2/audio_coding_module.cc
index c0aab3a..1547b37 100644
--- a/modules/audio_coding/acm2/audio_coding_module.cc
+++ b/modules/audio_coding/acm2/audio_coding_module.cc
@@ -18,12 +18,11 @@
#include "api/array_view.h"
#include "modules/audio_coding/acm2/acm_receiver.h"
#include "modules/audio_coding/acm2/acm_resampler.h"
-#include "modules/audio_coding/acm2/rent_a_codec.h"
#include "modules/include/module_common_types.h"
#include "modules/include/module_common_types_public.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/thread_annotations.h"
@@ -45,9 +44,6 @@
void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)>
modifier) override;
- // Get current send codec.
- absl::optional<CodecInst> SendCodec() const override;
-
// Sets the bitrate to the specified value in bits/sec. In case the codec does
// not support the requested value it will choose an appropriate value
// instead.
@@ -90,24 +86,13 @@
void SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) override;
- bool RegisterReceiveCodec(int rtp_payload_type,
- const SdpAudioFormat& audio_format) override;
-
- int RegisterExternalReceiveCodec(int rtp_payload_type,
- AudioDecoder* external_decoder,
- int sample_rate_hz,
- int num_channels,
- const std::string& name) override;
-
// Get current received codec.
- int ReceiveCodec(CodecInst* current_codec) const override;
-
- absl::optional<SdpAudioFormat> ReceiveFormat() const override;
+ absl::optional<std::pair<int, SdpAudioFormat>> ReceiveCodec() const override;
// Incoming packet from network parsed and ready for decode.
int IncomingPacket(const uint8_t* incoming_payload,
const size_t payload_length,
- const WebRtcRTPHeader& rtp_info) override;
+ const RTPHeader& rtp_info) override;
// Minimum playout delay.
int SetMinimumPlayoutDelay(int time_ms) override;
@@ -115,6 +100,10 @@
// Maximum playout delay.
int SetMaximumPlayoutDelay(int time_ms) override;
+ bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override;
+
+ int GetBaseMinimumPlayoutDelayMs() const override;
+
absl::optional<uint32_t> PlayoutTimestamp() override;
int FilteredCurrentDelayMs() const override;
@@ -141,8 +130,6 @@
int DisableOpusDtx() override;
- int UnregisterReceiveCodec(uint8_t payload_type) override;
-
int EnableNack(size_t max_nack_list_size) override;
void DisableNack() override;
@@ -317,42 +304,6 @@
}
}
-// Wraps a raw AudioEncoder pointer. The idea is that you can put one of these
-// in a unique_ptr, to protect the contained raw pointer from being deleted
-// when the unique_ptr expires. (This is of course a bad idea in general, but
-// backwards compatibility.)
-class RawAudioEncoderWrapper final : public AudioEncoder {
- public:
- RawAudioEncoderWrapper(AudioEncoder* enc) : enc_(enc) {}
- int SampleRateHz() const override { return enc_->SampleRateHz(); }
- size_t NumChannels() const override { return enc_->NumChannels(); }
- int RtpTimestampRateHz() const override { return enc_->RtpTimestampRateHz(); }
- size_t Num10MsFramesInNextPacket() const override {
- return enc_->Num10MsFramesInNextPacket();
- }
- size_t Max10MsFramesInAPacket() const override {
- return enc_->Max10MsFramesInAPacket();
- }
- int GetTargetBitrate() const override { return enc_->GetTargetBitrate(); }
- EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
- rtc::ArrayView<const int16_t> audio,
- rtc::Buffer* encoded) override {
- return enc_->Encode(rtp_timestamp, audio, encoded);
- }
- void Reset() override { return enc_->Reset(); }
- bool SetFec(bool enable) override { return enc_->SetFec(enable); }
- bool SetDtx(bool enable) override { return enc_->SetDtx(enable); }
- bool SetApplication(Application application) override {
- return enc_->SetApplication(application);
- }
- void SetMaxPlaybackRate(int frequency_hz) override {
- return enc_->SetMaxPlaybackRate(frequency_hz);
- }
-
- private:
- AudioEncoder* enc_;
-};
-
void AudioCodingModuleImpl::ChangeLogger::MaybeLog(int value) {
if (value != last_value_ || first_time_) {
first_time_ = false;
@@ -480,26 +431,6 @@
modifier(&encoder_stack_);
}
-// Get current send codec.
-absl::optional<CodecInst> AudioCodingModuleImpl::SendCodec() const {
- rtc::CritScope lock(&acm_crit_sect_);
- if (encoder_stack_) {
- CodecInst ci;
- ci.channels = encoder_stack_->NumChannels();
- ci.plfreq = encoder_stack_->SampleRateHz();
- ci.pacsize = rtc::CheckedDivExact(
- static_cast<int>(encoder_stack_->Max10MsFramesInAPacket() * ci.plfreq),
- 100);
- ci.pltype = -1; // Not valid.
- ci.rate = -1; // Not valid.
- static const char kName[] = "external";
- memcpy(ci.plname, kName, sizeof(kName));
- return ci;
- } else {
- return absl::nullopt;
- }
-}
-
void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) {
rtc::CritScope lock(&acm_crit_sect_);
if (encoder_stack_) {
@@ -546,7 +477,9 @@
return -1;
}
- if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2) {
+ if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2 &&
+ audio_frame.num_channels_ != 4 && audio_frame.num_channels_ != 6 &&
+ audio_frame.num_channels_ != 8) {
RTC_LOG(LS_ERROR) << "Cannot Add 10 ms audio, invalid number of channels.";
return -1;
}
@@ -721,9 +654,6 @@
// start-up.
if (receiver_initialized_)
receiver_.RemoveAllCodecs();
- receiver_.ResetInitialDelay();
- receiver_.SetMinimumDelay(0);
- receiver_.SetMaximumDelay(0);
receiver_.FlushBuffers();
receiver_initialized_ = true;
@@ -748,60 +678,16 @@
receiver_.SetCodecs(codecs);
}
-bool AudioCodingModuleImpl::RegisterReceiveCodec(
- int rtp_payload_type,
- const SdpAudioFormat& audio_format) {
+absl::optional<std::pair<int, SdpAudioFormat>>
+ AudioCodingModuleImpl::ReceiveCodec() const {
rtc::CritScope lock(&acm_crit_sect_);
- RTC_DCHECK(receiver_initialized_);
-
- if (!acm2::RentACodec::IsPayloadTypeValid(rtp_payload_type)) {
- RTC_LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type
- << " for decoder.";
- return false;
- }
-
- return receiver_.AddCodec(rtp_payload_type, audio_format);
-}
-
-int AudioCodingModuleImpl::RegisterExternalReceiveCodec(
- int rtp_payload_type,
- AudioDecoder* external_decoder,
- int sample_rate_hz,
- int num_channels,
- const std::string& name) {
- rtc::CritScope lock(&acm_crit_sect_);
- RTC_DCHECK(receiver_initialized_);
- if (num_channels > 2 || num_channels < 0) {
- RTC_LOG_F(LS_ERROR) << "Unsupported number of channels: " << num_channels;
- return -1;
- }
-
- // Check if the payload-type is valid.
- if (!acm2::RentACodec::IsPayloadTypeValid(rtp_payload_type)) {
- RTC_LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type
- << " for external decoder.";
- return -1;
- }
-
- return receiver_.AddCodec(-1 /* external */, rtp_payload_type, num_channels,
- sample_rate_hz, external_decoder, name);
-}
-
-// Get current received codec.
-int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
- rtc::CritScope lock(&acm_crit_sect_);
- return receiver_.LastAudioCodec(current_codec);
-}
-
-absl::optional<SdpAudioFormat> AudioCodingModuleImpl::ReceiveFormat() const {
- rtc::CritScope lock(&acm_crit_sect_);
- return receiver_.LastAudioFormat();
+ return receiver_.LastDecoder();
}
// Incoming packet from network parsed and ready for decode.
int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload,
const size_t payload_length,
- const WebRtcRTPHeader& rtp_header) {
+ const RTPHeader& rtp_header) {
RTC_DCHECK_EQ(payload_length == 0, incoming_payload == nullptr);
return receiver_.InsertPacket(
rtp_header,
@@ -825,6 +711,15 @@
return receiver_.SetMaximumDelay(time_ms);
}
+bool AudioCodingModuleImpl::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
+ // All necessary validation happens on NetEq level.
+ return receiver_.SetBaseMinimumDelayMs(delay_ms);
+}
+
+int AudioCodingModuleImpl::GetBaseMinimumPlayoutDelayMs() const {
+ return receiver_.GetBaseMinimumDelayMs();
+}
+
// Get 10 milliseconds of raw audio data to play out.
// Automatic resample to the requested frequency.
int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz,
@@ -902,10 +797,6 @@
return true;
}
-int AudioCodingModuleImpl::UnregisterReceiveCodec(uint8_t payload_type) {
- return receiver_.RemoveCodec(payload_type);
-}
-
int AudioCodingModuleImpl::EnableNack(size_t max_nack_list_size) {
return receiver_.EnableNack(max_nack_list_size);
}
@@ -951,52 +842,4 @@
return new AudioCodingModuleImpl(config);
}
-int AudioCodingModule::NumberOfCodecs() {
- return static_cast<int>(acm2::RentACodec::NumberOfCodecs());
-}
-
-int AudioCodingModule::Codec(int list_id, CodecInst* codec) {
- auto codec_id = acm2::RentACodec::CodecIdFromIndex(list_id);
- if (!codec_id)
- return -1;
- auto ci = acm2::RentACodec::CodecInstById(*codec_id);
- if (!ci)
- return -1;
- *codec = *ci;
- return 0;
-}
-
-int AudioCodingModule::Codec(const char* payload_name,
- CodecInst* codec,
- int sampling_freq_hz,
- size_t channels) {
- absl::optional<CodecInst> ci = acm2::RentACodec::CodecInstByParams(
- payload_name, sampling_freq_hz, channels);
- if (ci) {
- *codec = *ci;
- return 0;
- } else {
- // We couldn't find a matching codec, so set the parameters to unacceptable
- // values and return.
- codec->plname[0] = '\0';
- codec->pltype = -1;
- codec->pacsize = 0;
- codec->rate = 0;
- codec->plfreq = 0;
- return -1;
- }
-}
-
-int AudioCodingModule::Codec(const char* payload_name,
- int sampling_freq_hz,
- size_t channels) {
- absl::optional<acm2::RentACodec::CodecId> ci =
- acm2::RentACodec::CodecIdByParams(payload_name, sampling_freq_hz,
- channels);
- if (!ci)
- return -1;
- absl::optional<int> i = acm2::RentACodec::CodecIndexFromId(*ci);
- return i ? *i : -1;
-}
-
} // namespace webrtc
diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index 4e262f7..4ee9add 100644
--- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -13,17 +13,20 @@
#include <memory>
#include <vector>
+#include "absl/memory/memory.h"
#include "api/audio_codecs/audio_encoder.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "api/audio_codecs/opus/audio_decoder_opus.h"
#include "api/audio_codecs/opus/audio_encoder_opus.h"
#include "modules/audio_coding/acm2/acm_receive_test.h"
#include "modules/audio_coding/acm2/acm_send_test.h"
-#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
#include "modules/audio_coding/codecs/g711/audio_decoder_pcm.h"
#include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
#include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
+#include "modules/audio_coding/codecs/opus/audio_decoder_opus.h"
+#include "modules/audio_coding/codecs/opus/audio_encoder_opus.h"
#include "modules/audio_coding/include/audio_coding_module.h"
#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "modules/audio_coding/neteq/tools/audio_checksum.h"
@@ -34,20 +37,21 @@
#include "modules/audio_coding/neteq/tools/output_wav_file.h"
#include "modules/audio_coding/neteq/tools/packet.h"
#include "modules/audio_coding/neteq/tools/rtp_file_source.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
-#include "rtc_base/messagedigest.h"
+#include "rtc_base/message_digest.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/system/arch.h"
#include "rtc_base/thread_annotations.h"
#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/sleep.h"
+#include "test/audio_decoder_proxy_factory.h"
#include "test/gtest.h"
#include "test/mock_audio_decoder.h"
#include "test/mock_audio_encoder.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
using ::testing::AtLeast;
using ::testing::Invoke;
@@ -71,21 +75,20 @@
virtual ~RtpUtility() {}
- void Populate(WebRtcRTPHeader* rtp_header) {
- rtp_header->header.sequenceNumber = 0xABCD;
- rtp_header->header.timestamp = 0xABCDEF01;
- rtp_header->header.payloadType = payload_type_;
- rtp_header->header.markerBit = false;
- rtp_header->header.ssrc = 0x1234;
- rtp_header->header.numCSRCs = 0;
- rtp_header->frameType = kAudioFrameSpeech;
+ void Populate(RTPHeader* rtp_header) {
+ rtp_header->sequenceNumber = 0xABCD;
+ rtp_header->timestamp = 0xABCDEF01;
+ rtp_header->payloadType = payload_type_;
+ rtp_header->markerBit = false;
+ rtp_header->ssrc = 0x1234;
+ rtp_header->numCSRCs = 0;
- rtp_header->header.payload_type_frequency = kSampleRateHz;
+ rtp_header->payload_type_frequency = kSampleRateHz;
}
- void Forward(WebRtcRTPHeader* rtp_header) {
- ++rtp_header->header.sequenceNumber;
- rtp_header->header.timestamp += samples_per_packet_;
+ void Forward(RTPHeader* rtp_header) {
+ ++rtp_header->sequenceNumber;
+ rtp_header->timestamp += samples_per_packet_;
}
private:
@@ -190,12 +193,11 @@
// Set up L16 codec.
virtual void SetUpL16Codec() {
audio_format_ = SdpAudioFormat("L16", kSampleRateHz, 1);
- ASSERT_EQ(0, AudioCodingModule::Codec("L16", &codec_, kSampleRateHz, 1));
- codec_.pltype = kPayloadType;
+ pac_size_ = 160;
}
virtual void RegisterCodec() {
- EXPECT_EQ(true, acm_->RegisterReceiveCodec(kPayloadType, *audio_format_));
+ acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}});
acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder(
kPayloadType, *audio_format_, absl::nullopt));
}
@@ -226,7 +228,7 @@
virtual void VerifyEncoding() {
int last_length = packet_cb_.last_payload_len_bytes();
- EXPECT_TRUE(last_length == 2 * codec_.pacsize || last_length == 0)
+ EXPECT_TRUE(last_length == 2 * pac_size_ || last_length == 0)
<< "Last encoded packet was " << last_length << " bytes.";
}
@@ -238,13 +240,11 @@
std::unique_ptr<RtpUtility> rtp_utility_;
std::unique_ptr<AudioCodingModule> acm_;
PacketizationCallbackStubOldApi packet_cb_;
- WebRtcRTPHeader rtp_header_;
+ RTPHeader rtp_header_;
AudioFrame input_frame_;
- // These two have to be kept in sync for now. In the future, we'll be able to
- // eliminate the CodecInst and keep only the SdpAudioFormat.
absl::optional<SdpAudioFormat> audio_format_;
- CodecInst codec_;
+ int pac_size_ = -1;
Clock* clock_;
};
@@ -343,7 +343,7 @@
// Also checks that the frame type is kAudioFrameSpeech.
TEST_F(AudioCodingModuleTestOldApi, TransportCallbackIsInvokedForEachPacket) {
const int k10MsBlocksPerPacket = 3;
- codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100;
+ pac_size_ = k10MsBlocksPerPacket * kSampleRateHz / 100;
audio_format_->parameters["ptime"] = "30";
RegisterCodec();
const int kLoops = 10;
@@ -363,7 +363,7 @@
TEST_F(AudioCodingModuleTestOldApi, TimestampSeriesContinuesWhenCodecChanges) {
RegisterCodec(); // This registers the default codec.
uint32_t expected_ts = input_frame_.timestamp_;
- int blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100);
+ int blocks_per_packet = pac_size_ / (kSampleRateHz / 100);
// Encode 5 packets of the first codec type.
const int kNumPackets1 = 5;
for (int j = 0; j < kNumPackets1; ++j) {
@@ -373,14 +373,14 @@
}
EXPECT_EQ(j + 1, packet_cb_.num_calls());
EXPECT_EQ(expected_ts, packet_cb_.last_timestamp());
- expected_ts += codec_.pacsize;
+ expected_ts += pac_size_;
}
// Change codec.
- ASSERT_EQ(0, AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1));
audio_format_ = SdpAudioFormat("ISAC", kSampleRateHz, 1);
+ pac_size_ = 480;
RegisterCodec();
- blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100);
+ blocks_per_packet = pac_size_ / (kSampleRateHz / 100);
// Encode another 5 packets.
const int kNumPackets2 = 5;
for (int j = 0; j < kNumPackets2; ++j) {
@@ -390,7 +390,7 @@
}
EXPECT_EQ(kNumPackets1 + j + 1, packet_cb_.num_calls());
EXPECT_EQ(expected_ts, packet_cb_.last_timestamp());
- expected_ts += codec_.pacsize;
+ expected_ts += pac_size_;
}
}
#endif
@@ -404,9 +404,8 @@
: public AudioCodingModuleTestOldApi {
protected:
void RegisterCngCodec(int rtp_payload_type) {
- EXPECT_EQ(true,
- acm_->RegisterReceiveCodec(
- rtp_payload_type, SdpAudioFormat("cn", kSampleRateHz, 1)));
+ acm_->SetReceiveCodecs({{kPayloadType, *audio_format_},
+ {rtp_payload_type, {"cn", kSampleRateHz, 1}}});
acm_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
AudioEncoderCngConfig config;
config.speech_encoder = std::move(*enc);
@@ -461,7 +460,7 @@
TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi,
TransportCallbackTestForComfortNoiseRegisterCngLast) {
const int k10MsBlocksPerPacket = 3;
- codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100;
+ pac_size_ = k10MsBlocksPerPacket * kSampleRateHz / 100;
audio_format_->parameters["ptime"] = "30";
RegisterCodec();
const int kCngPayloadType = 105;
@@ -650,12 +649,11 @@
void RegisterCodec() override {
static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
audio_format_ = SdpAudioFormat("isac", kSampleRateHz, 1);
- AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1);
- codec_.pltype = kPayloadType;
+ pac_size_ = 480;
// Register iSAC codec in ACM, effectively unregistering the PCM16B codec
// registered in AudioCodingModuleTestOldApi::SetUp();
- EXPECT_EQ(true, acm_->RegisterReceiveCodec(kPayloadType, *audio_format_));
+ acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}});
acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder(
kPayloadType, *audio_format_, absl::nullopt));
}
@@ -755,15 +753,11 @@
}
void RegisterCodec() override {
- static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
- AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1);
- codec_.pltype = kPayloadType;
-
// Register iSAC codec in ACM, effectively unregistering the PCM16B codec
// registered in AudioCodingModuleTestOldApi::SetUp();
// Only register the decoder for now. The encoder is registered later.
- ASSERT_EQ(true, acm_->RegisterReceiveCodec(codec_.pltype,
- CodecInstToSdp(codec_)));
+ static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
+ acm_->SetReceiveCodecs({{kPayloadType, {"ISAC", kSampleRateHz, 1}}});
}
void StartThreads() {
@@ -801,16 +795,15 @@
++receive_packet_count_;
// Encode new frame.
- uint32_t input_timestamp = rtp_header_.header.timestamp;
+ uint32_t input_timestamp = rtp_header_.timestamp;
while (info.encoded_bytes == 0) {
info = isac_encoder_->Encode(input_timestamp,
audio_loop_.GetNextBlock(), &encoded);
input_timestamp += 160; // 10 ms at 16 kHz.
}
- EXPECT_EQ(rtp_header_.header.timestamp + kPacketSizeSamples,
- input_timestamp);
- EXPECT_EQ(rtp_header_.header.timestamp, info.encoded_timestamp);
- EXPECT_EQ(rtp_header_.header.payloadType, info.payload_type);
+ EXPECT_EQ(rtp_header_.timestamp + kPacketSizeSamples, input_timestamp);
+ EXPECT_EQ(rtp_header_.timestamp, info.encoded_timestamp);
+ EXPECT_EQ(rtp_header_.payloadType, info.payload_type);
}
// Now we're not holding the crit sect when calling ACM.
@@ -946,7 +939,7 @@
->test_case_name() +
"_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() +
"_output.wav";
- test::OutputWavFile output_file(output_file_name, output_freq_hz);
+ test::OutputWavFile output_file(output_file_name, output_freq_hz, 1);
test::AudioSinkFork output(&checksum, &output_file);
test::AcmReceiveTestOldApi test(
@@ -968,35 +961,35 @@
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \
defined(WEBRTC_CODEC_ILBC)
TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) {
- Run(8000, PlatformChecksum("7294941b62293e143d6d6c84955923fd",
- "f26b8c9aa8257c7185925fa5b102f46a",
- "65e5ef5c3de9c2abf3c8d0989772e9fc",
+ Run(8000, PlatformChecksum("bcfbe2e89b4317b22e29557168edf187",
+ "af15addb648cf7f032d6415672365fb3",
+ "54a0008eb79537dee1d8fdaa5bc29f4b",
"4598140b5e4f7ee66c5adad609e65a3e",
- "04a1d3e735730b6d7dbd5df10f717d27"));
+ "3155d7f2593a3276986f36221a61783c"));
}
TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) {
- Run(16000, PlatformChecksum("de8143dd3cc23241f1e1d5cf14e04b8a",
- "eada3f321120d8d5afffbe4170a55d2f",
- "135d8c3c7b92aa13d45cad7c91068e3e",
+ Run(16000, PlatformChecksum("1737deef193e6c90e139ce82b7361ae4",
+ "9e2a9f7728c71d6559ce3a32d2b10a5d",
+ "114958862099142ac78b12100c21cb8d",
"f2aad418af974a3b1694d5ae5cc2c3c7",
- "728b69068332efade35b1a9c32029e1b"));
+ "af2889a5ca84fb40c9aa209b9318ee7a"));
}
TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) {
- Run(32000, PlatformChecksum("521d336237bdcc9ab44050e9da8917fc",
- "73d44a7bedb6dfa7c70cf997223d8c10",
- "f3ee2f14b03fb8e98f526f82583f84d9",
+ Run(32000, PlatformChecksum("1bf40ff024c6aa5b832d1d242c29cb3b",
+ "3c9690cd136e9ecd1b26a22f70fe1d5c",
+ "a1a3a01d8e25fcd11f1cedcd02e968b8",
"100869c8dcde51346c2073e52a272d98",
- "5f338b4bc38707d0a14d75a357e1546e"));
+ "33695077e9ec6bca80819ce2ba263a78"));
}
TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) {
- Run(48000, PlatformChecksum("5955e31373828969de7fb308fb58a84e",
- "83c0eca235b1a806426ff6ca8655cdf7",
- "1126a8c03d1ebc6aa7348b9c541e2082",
+ Run(48000, PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5",
+ "c37b110ab50d87620972daee5d1eaf31",
+ "5d55b68be7bcf39b60fcc74519363fb4",
"bd44bf97e7899186532f91235cef444d",
- "9d092dbc96e7ef6870b78c1056e87315"));
+ "32eec738698ffe62b9777d6a349cd596"));
}
TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) {
@@ -1079,13 +1072,23 @@
rtc::scoped_refptr<rtc::RefCountedObject<ADFactory>> factory(
new rtc::RefCountedObject<ADFactory>);
Run(48000,
- PlatformChecksum("5955e31373828969de7fb308fb58a84e",
- "83c0eca235b1a806426ff6ca8655cdf7",
- "1126a8c03d1ebc6aa7348b9c541e2082",
+ PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5",
+ "c37b110ab50d87620972daee5d1eaf31",
+ "5d55b68be7bcf39b60fcc74519363fb4",
"bd44bf97e7899186532f91235cef444d",
- "9d092dbc96e7ef6870b78c1056e87315"),
+ "32eec738698ffe62b9777d6a349cd596"),
factory, [](AudioCodingModule* acm) {
- acm->RegisterReceiveCodec(0, {"MockPCMu", 8000, 1});
+ acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}},
+ {103, {"ISAC", 16000, 1}},
+ {104, {"ISAC", 32000, 1}},
+ {93, {"L16", 8000, 1}},
+ {94, {"L16", 16000, 1}},
+ {95, {"L16", 32000, 1}},
+ {8, {"PCMA", 8000, 1}},
+ {102, {"ILBC", 8000, 1}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
});
}
#endif
@@ -1117,15 +1120,12 @@
// Sets up the test::AcmSendTest object. Returns true on success, otherwise
// false.
- bool SetUpSender() {
- const std::string input_file_name =
- webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ bool SetUpSender(std::string input_file_name, int source_rate) {
// Note that |audio_source_| will loop forever. The test duration is set
// explicitly by |kTestDurationMs|.
audio_source_.reset(new test::InputAudioFile(input_file_name));
- static const int kSourceRateHz = 32000;
- send_test_.reset(new test::AcmSendTestOldApi(
- audio_source_.get(), kSourceRateHz, kTestDurationMs));
+ send_test_.reset(new test::AcmSendTestOldApi(audio_source_.get(),
+ source_rate, kTestDurationMs));
return send_test_.get() != NULL;
}
@@ -1158,7 +1158,11 @@
void Run(const std::string& audio_checksum_ref,
const std::string& payload_checksum_ref,
int expected_packets,
- test::AcmReceiveTestOldApi::NumOutputChannels expected_channels) {
+ test::AcmReceiveTestOldApi::NumOutputChannels expected_channels,
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory = nullptr) {
+ if (!decoder_factory) {
+ decoder_factory = CreateBuiltinAudioDecoderFactory();
+ }
// Set up the receiver used to decode the packets and verify the decoded
// output.
test::AudioChecksum audio_checksum;
@@ -1170,12 +1174,12 @@
"_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() +
"_output.wav";
const int kOutputFreqHz = 8000;
- test::OutputWavFile output_file(output_file_name, kOutputFreqHz);
+ test::OutputWavFile output_file(output_file_name, kOutputFreqHz,
+ expected_channels);
// Have the output audio sent both to file and to the checksum calculator.
test::AudioSinkFork output(&audio_checksum, &output_file);
test::AcmReceiveTestOldApi receive_test(this, &output, kOutputFreqHz,
- expected_channels,
- CreateBuiltinAudioDecoderFactory());
+ expected_channels, decoder_factory);
ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs());
// This is where the actual test is executed.
@@ -1251,7 +1255,8 @@
int payload_type,
int codec_frame_size_samples,
int codec_frame_size_rtp_timestamps) {
- ASSERT_TRUE(SetUpSender());
+ ASSERT_TRUE(SetUpSender(
+ channels == 1 ? kTestFileMono32kHz : kTestFileFakeStereo32kHz, 32000));
ASSERT_TRUE(RegisterSendCodec(codec_name, codec_sample_rate_hz, channels,
payload_type, codec_frame_size_samples,
codec_frame_size_rtp_timestamps));
@@ -1260,7 +1265,7 @@
void SetUpTestExternalEncoder(
std::unique_ptr<AudioEncoder> external_speech_encoder,
int payload_type) {
- ASSERT_TRUE(SetUpSender());
+ ASSERT_TRUE(send_test_);
RegisterExternalSendCodec(std::move(external_speech_encoder), payload_type);
}
@@ -1272,6 +1277,14 @@
uint16_t last_sequence_number_;
uint32_t last_timestamp_;
std::unique_ptr<rtc::MessageDigest> payload_checksum_;
+ const std::string kTestFileMono32kHz =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ const std::string kTestFileFakeStereo32kHz =
+ webrtc::test::ResourcePath("audio_coding/testfile_fake_stereo_32kHz",
+ "pcm");
+ const std::string kTestFileQuad48kHz = webrtc::test::ResourcePath(
+ "audio_coding/speech_4_channels_48k_one_second",
+ "wav");
};
class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {};
@@ -1471,7 +1484,7 @@
"ab88b1a049c36bdfeb7e8b057ef6982a",
"27fef7b799393347ec3b5694369a1c36",
"27fef7b799393347ec3b5694369a1c36");
-}; // namespace
+} // namespace
TEST_F(AcmSenderBitExactnessOldApi, Opus_stereo_20ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
@@ -1482,17 +1495,59 @@
TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) {
const auto config = AudioEncoderOpus::SdpToConfig(
SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}));
+ ASSERT_TRUE(SetUpSender(kTestFileFakeStereo32kHz, 32000));
ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(
AudioEncoderOpus::MakeAudioEncoder(*config, 120), 120));
Run(audio_checksum, payload_checksum, 50,
test::AcmReceiveTestOldApi::kStereoOutput);
}
+TEST_F(AcmSenderBitExactnessNewApi, OpusManyChannels) {
+ constexpr int kNumChannels = 4;
+ constexpr int kOpusPayloadType = 120;
+ constexpr int kBitrateBps = 128000;
+
+ // Read a 4 channel file at 48kHz.
+ ASSERT_TRUE(SetUpSender(kTestFileQuad48kHz, 48000));
+
+ // TODO(webrtc:8649): change to higher level
+ // AudioEncoderOpus::MakeAudioEncoder once a multistream encoder can be set up
+ // from SDP.
+ AudioEncoderOpusConfig config = *AudioEncoderOpus::SdpToConfig(
+ SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}));
+ config.num_channels = kNumChannels;
+ config.bitrate_bps = kBitrateBps;
+
+ ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(
+ absl::make_unique<AudioEncoderOpusImpl>(config, kOpusPayloadType),
+ kOpusPayloadType));
+
+ AudioDecoderOpusImpl opus_decoder(kNumChannels);
+
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory =
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&opus_decoder);
+
+ // Set up an EXTERNAL DECODER to parse 4 channels.
+ Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( // audio checksum
+ "b70470884d9a8613eff019b0d1c8876e|d0a73d377e0ca1be6b06e989e0ad2c35",
+ "d0a73d377e0ca1be6b06e989e0ad2c35",
+ "b45d2ce5fc4723e9eb41350af9c68f56", "android arm64 audio checksum",
+ "1c9a3c9dacdd4b8fc9ff608227e531f2"),
+ // payload_checksum,
+ AcmReceiverBitExactnessOldApi::PlatformChecksum( // payload checksum
+ "c2e7d40f8269ef754bd86d6be9623fa7|76de0f4992e3937ca60d35bbb0d308d6",
+ "76de0f4992e3937ca60d35bbb0d308d6",
+ "2a310aca965c16c2dfd61a9f9fc0c877", "android arm64 payload checksum",
+ "2294f4b61fb8f174f5196776a0a49be7"),
+ 50, test::AcmReceiveTestOldApi::kQuadOutput, decoder_factory);
+}
+
TEST_F(AcmSenderBitExactnessNewApi, OpusFromFormat_stereo_20ms_voip) {
auto config = AudioEncoderOpus::SdpToConfig(
SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}));
// If not set, default will be kAudio in case of stereo.
config->application = AudioEncoderOpusConfig::ApplicationMode::kVoip;
+ ASSERT_TRUE(SetUpSender(kTestFileFakeStereo32kHz, 32000));
ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(
AudioEncoderOpus::MakeAudioEncoder(*config, 120), 120));
// Checksum depends on libopus being compiled with or without SSE.
@@ -1746,11 +1801,11 @@
}
TEST_F(AcmSenderBitExactnessOldApi, External_Pcmu_20ms) {
- CodecInst codec_inst;
- codec_inst.channels = 1;
- codec_inst.pacsize = 160;
- codec_inst.pltype = 0;
- AudioEncoderPcmU encoder(codec_inst);
+ AudioEncoderPcmU::Config config;
+ config.frame_size_ms = 20;
+ config.num_channels = 1;
+ config.payload_type = 0;
+ AudioEncoderPcmU encoder(config);
auto mock_encoder = absl::make_unique<MockAudioEncoder>();
// Set expectations on the mock encoder and also delegate the calls to the
// real encoder.
@@ -1776,8 +1831,9 @@
&encoder, static_cast<AudioEncoder::EncodedInfo (AudioEncoder::*)(
uint32_t, rtc::ArrayView<const int16_t>, rtc::Buffer*)>(
&AudioEncoderPcmU::Encode)));
+ ASSERT_TRUE(SetUpSender(kTestFileMono32kHz, 32000));
ASSERT_NO_FATAL_FAILURE(
- SetUpTestExternalEncoder(std::move(mock_encoder), codec_inst.pltype));
+ SetUpTestExternalEncoder(std::move(mock_encoder), config.payload_type));
Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9",
50, test::AcmReceiveTestOldApi::kMonoOutput);
}
diff --git a/modules/audio_coding/acm2/rent_a_codec.cc b/modules/audio_coding/acm2/rent_a_codec.cc
deleted file mode 100644
index bfddc42b..0000000
--- a/modules/audio_coding/acm2/rent_a_codec.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2015 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/audio_coding/acm2/rent_a_codec.h"
-
-#include <memory>
-#include <utility>
-
-#include "rtc_base/logging.h"
-#include "modules/audio_coding/acm2/acm_codec_database.h"
-
-namespace webrtc {
-namespace acm2 {
-
-absl::optional<RentACodec::CodecId> RentACodec::CodecIdByParams(
- const char* payload_name,
- int sampling_freq_hz,
- size_t channels) {
- return CodecIdFromIndex(
- ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels));
-}
-
-absl::optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) {
- absl::optional<int> mi = CodecIndexFromId(codec_id);
- return mi ? absl::optional<CodecInst>(ACMCodecDB::database_[*mi])
- : absl::nullopt;
-}
-
-absl::optional<RentACodec::CodecId> RentACodec::CodecIdByInst(
- const CodecInst& codec_inst) {
- return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst));
-}
-
-absl::optional<CodecInst> RentACodec::CodecInstByParams(
- const char* payload_name,
- int sampling_freq_hz,
- size_t channels) {
- absl::optional<CodecId> codec_id =
- CodecIdByParams(payload_name, sampling_freq_hz, channels);
- if (!codec_id)
- return absl::nullopt;
- absl::optional<CodecInst> ci = CodecInstById(*codec_id);
- RTC_DCHECK(ci);
-
- // Keep the number of channels from the function call. For most codecs it
- // will be the same value as in default codec settings, but not for all.
- ci->channels = channels;
-
- return ci;
-}
-
-absl::optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId(
- CodecId codec_id,
- size_t num_channels) {
- absl::optional<int> i = CodecIndexFromId(codec_id);
- if (!i)
- return absl::nullopt;
- const NetEqDecoder ned = ACMCodecDB::neteq_decoders_[*i];
- return (ned == NetEqDecoder::kDecoderOpus && num_channels == 2)
- ? NetEqDecoder::kDecoderOpus_2ch
- : ned;
-}
-
-} // namespace acm2
-} // namespace webrtc
diff --git a/modules/audio_coding/acm2/rent_a_codec.h b/modules/audio_coding/acm2/rent_a_codec.h
deleted file mode 100644
index 2cf1c6e..0000000
--- a/modules/audio_coding/acm2/rent_a_codec.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2015 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.
- */
-
-#ifndef MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_
-#define MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_
-
-#include <stddef.h>
-#include <map>
-#include <memory>
-
-#include "absl/types/optional.h"
-#include "api/array_view.h"
-#include "api/audio_codecs/audio_decoder.h"
-#include "api/audio_codecs/audio_encoder.h"
-#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
-#include "modules/audio_coding/neteq/neteq_decoder_enum.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
-
-namespace webrtc {
-
-struct CodecInst;
-class LockedIsacBandwidthInfo;
-
-namespace acm2 {
-
-struct RentACodec {
- enum class CodecId {
-#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
- kISAC,
-#endif
-#ifdef WEBRTC_CODEC_ISAC
- kISACSWB,
-#endif
- // Mono
- kPCM16B,
- kPCM16Bwb,
- kPCM16Bswb32kHz,
- // Stereo
- kPCM16B_2ch,
- kPCM16Bwb_2ch,
- kPCM16Bswb32kHz_2ch,
- // Mono
- kPCMU,
- kPCMA,
- // Stereo
- kPCMU_2ch,
- kPCMA_2ch,
-#ifdef WEBRTC_CODEC_ILBC
- kILBC,
-#endif
- kG722, // Mono
- kG722_2ch, // Stereo
-#ifdef WEBRTC_CODEC_OPUS
- kOpus, // Mono and stereo
-#endif
- kCNNB,
- kCNWB,
- kCNSWB,
-#ifdef ENABLE_48000_HZ
- kCNFB,
-#endif
- kAVT,
- kAVT16kHz,
- kAVT32kHz,
- kAVT48kHz,
-#ifdef WEBRTC_CODEC_RED
- kRED,
-#endif
- kNumCodecs, // Implementation detail. Don't use.
-
-// Set unsupported codecs to -1.
-#if !defined(WEBRTC_CODEC_ISAC) && !defined(WEBRTC_CODEC_ISACFX)
- kISAC = -1,
-#endif
-#ifndef WEBRTC_CODEC_ISAC
- kISACSWB = -1,
-#endif
- // 48 kHz not supported, always set to -1.
- kPCM16Bswb48kHz = -1,
-#ifndef WEBRTC_CODEC_ILBC
- kILBC = -1,
-#endif
-#ifndef WEBRTC_CODEC_OPUS
- kOpus = -1, // Mono and stereo
-#endif
-#ifndef WEBRTC_CODEC_RED
- kRED = -1,
-#endif
-#ifndef ENABLE_48000_HZ
- kCNFB = -1,
-#endif
-
- kNone = -1
- };
-
- static inline size_t NumberOfCodecs() {
- return static_cast<size_t>(CodecId::kNumCodecs);
- }
-
- static inline absl::optional<int> CodecIndexFromId(CodecId codec_id) {
- const int i = static_cast<int>(codec_id);
- return i >= 0 && i < static_cast<int>(NumberOfCodecs())
- ? absl::optional<int>(i)
- : absl::nullopt;
- }
-
- static inline absl::optional<CodecId> CodecIdFromIndex(int codec_index) {
- return static_cast<size_t>(codec_index) < NumberOfCodecs()
- ? absl::optional<RentACodec::CodecId>(
- static_cast<RentACodec::CodecId>(codec_index))
- : absl::nullopt;
- }
-
- static absl::optional<CodecId> CodecIdByParams(const char* payload_name,
- int sampling_freq_hz,
- size_t channels);
- static absl::optional<CodecInst> CodecInstById(CodecId codec_id);
- static absl::optional<CodecId> CodecIdByInst(const CodecInst& codec_inst);
- static absl::optional<CodecInst> CodecInstByParams(const char* payload_name,
- int sampling_freq_hz,
- size_t channels);
-
- static inline bool IsPayloadTypeValid(int payload_type) {
- return payload_type >= 0 && payload_type <= 127;
- }
-
- static absl::optional<NetEqDecoder> NetEqDecoderFromCodecId(
- CodecId codec_id,
- size_t num_channels);
-};
-
-} // namespace acm2
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
index 9e47a06..ff6ac01 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
@@ -18,7 +18,7 @@
#include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h"
#include "modules/audio_coding/audio_network_adaptor/event_log_writer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -29,7 +29,7 @@
constexpr float kEventLogMinPacketLossChangeFraction = 0.5;
} // namespace
-AudioNetworkAdaptorImpl::Config::Config() : event_log(nullptr){};
+AudioNetworkAdaptorImpl::Config::Config() : event_log(nullptr) {}
AudioNetworkAdaptorImpl::Config::~Config() = default;
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
index 4c1c19b..fc2358b 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
@@ -20,7 +20,7 @@
#include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
index be9550a..76531d0 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
@@ -18,7 +18,7 @@
#include "modules/audio_coding/audio_network_adaptor/mock/mock_controller.h"
#include "modules/audio_coding/audio_network_adaptor/mock/mock_controller_manager.h"
#include "modules/audio_coding/audio_network_adaptor/mock/mock_debug_dump_writer.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "test/field_trial.h"
#include "test/gtest.h"
diff --git a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
index 6b6330b..41bfbd1 100644
--- a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
@@ -16,7 +16,7 @@
#include "absl/types/optional.h"
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace audio_network_adaptor {
diff --git a/modules/audio_coding/audio_network_adaptor/channel_controller.h b/modules/audio_coding/audio_network_adaptor/channel_controller.h
index 0d775b1..f211f40 100644
--- a/modules/audio_coding/audio_network_adaptor/channel_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/channel_controller.h
@@ -16,7 +16,7 @@
#include "absl/types/optional.h"
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.cc b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
index 32f9fcb..4c0e61c 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
@@ -11,6 +11,7 @@
#include "modules/audio_coding/audio_network_adaptor/controller_manager.h"
#include <cmath>
+#include <string>
#include <utility>
#include "modules/audio_coding/audio_network_adaptor/bitrate_controller.h"
@@ -22,7 +23,7 @@
#include "modules/audio_coding/audio_network_adaptor/frame_length_controller.h"
#include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h"
#include "rtc_base/ignore_wundef.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#if WEBRTC_ENABLE_PROTOBUF
RTC_PUSH_IGNORING_WUNDEF()
@@ -147,13 +148,13 @@
}
FrameLengthController::Config ctor_config(
- std::vector<int>(), initial_frame_length_ms, min_encoder_bitrate_bps,
+ std::set<int>(), initial_frame_length_ms, min_encoder_bitrate_bps,
config.fl_increasing_packet_loss_fraction(),
config.fl_decreasing_packet_loss_fraction(), fl_increase_overhead_offset,
fl_decrease_overhead_offset, std::move(fl_changing_bandwidths_bps));
for (auto frame_length : encoder_frame_lengths_ms)
- ctor_config.encoder_frame_lengths_ms.push_back(frame_length);
+ ctor_config.encoder_frame_lengths_ms.insert(frame_length);
return std::unique_ptr<FrameLengthController>(
new FrameLengthController(ctor_config));
@@ -213,7 +214,7 @@
ControllerManagerImpl::Config::~Config() = default;
std::unique_ptr<ControllerManager> ControllerManagerImpl::Create(
- const ProtoString& config_string,
+ const std::string& config_string,
size_t num_encoder_channels,
rtc::ArrayView<const int> encoder_frame_lengths_ms,
int min_encoder_bitrate_bps,
@@ -229,7 +230,7 @@
}
std::unique_ptr<ControllerManager> ControllerManagerImpl::Create(
- const ProtoString& config_string,
+ const std::string& config_string,
size_t num_encoder_channels,
rtc::ArrayView<const int> encoder_frame_lengths_ms,
int min_encoder_bitrate_bps,
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.h b/modules/audio_coding/audio_network_adaptor/controller_manager.h
index 1ff9bbf..f46450d 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager.h
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager.h
@@ -13,11 +13,11 @@
#include <map>
#include <memory>
+#include <string>
#include <vector>
#include "modules/audio_coding/audio_network_adaptor/controller.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/protobuf_utils.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -47,7 +47,7 @@
};
static std::unique_ptr<ControllerManager> Create(
- const ProtoString& config_string,
+ const std::string& config_string,
size_t num_encoder_channels,
rtc::ArrayView<const int> encoder_frame_lengths_ms,
int min_encoder_bitrate_bps,
@@ -58,7 +58,7 @@
bool initial_dtx_enabled);
static std::unique_ptr<ControllerManager> Create(
- const ProtoString& config_string,
+ const std::string& config_string,
size_t num_encoder_channels,
rtc::ArrayView<const int> encoder_frame_lengths_ms,
int min_encoder_bitrate_bps,
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
index 061e4aa..ce47699 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string>
#include <utility>
#include "modules/audio_coding/audio_network_adaptor/controller_manager.h"
#include "modules/audio_coding/audio_network_adaptor/mock/mock_controller.h"
#include "modules/audio_coding/audio_network_adaptor/mock/mock_debug_dump_writer.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/ignore_wundef.h"
-#include "rtc_base/protobuf_utils.h"
#include "test/gtest.h"
#if WEBRTC_ENABLE_PROTOBUF
@@ -266,7 +266,7 @@
constexpr int kMinBitrateBps = 6000;
ControllerManagerStates CreateControllerManager(
- const ProtoString& config_string) {
+ const std::string& config_string) {
ControllerManagerStates states;
constexpr size_t kNumEncoderChannels = 2;
const std::vector<int> encoder_frame_lengths_ms = {20, 60};
@@ -319,8 +319,8 @@
}
MATCHER_P(ControllerManagerEqual, value, "") {
- ProtoString value_string;
- ProtoString arg_string;
+ std::string value_string;
+ std::string arg_string;
EXPECT_TRUE(arg.SerializeToString(&arg_string));
EXPECT_TRUE(value.SerializeToString(&value_string));
return arg_string == value_string;
@@ -339,7 +339,7 @@
AddFrameLengthControllerConfig(&config);
AddBitrateControllerConfig(&config);
- ProtoString config_string;
+ std::string config_string;
config.SerializeToString(&config_string);
constexpr size_t kNumEncoderChannels = 2;
@@ -373,7 +373,7 @@
AddFrameLengthControllerConfig(&config);
AddBitrateControllerConfig(&config);
- ProtoString config_string;
+ std::string config_string;
config.SerializeToString(&config_string);
auto states = CreateControllerManager(config_string);
@@ -395,7 +395,7 @@
AddDtxControllerConfig(&config);
AddBitrateControllerConfig(&config);
- ProtoString config_string;
+ std::string config_string;
config.SerializeToString(&config_string);
auto states = CreateControllerManager(config_string);
@@ -426,7 +426,7 @@
AddBitrateControllerConfig(&config);
- ProtoString config_string;
+ std::string config_string;
config.SerializeToString(&config_string);
auto states = CreateControllerManager(config_string);
diff --git a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
index 8e04e8e..805df0a 100644
--- a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
+++ b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
@@ -10,11 +10,12 @@
#include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h"
+#include <string>
+
#include "absl/types/optional.h"
#include "rtc_base/checks.h"
#include "rtc_base/ignore_wundef.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/protobuf_utils.h"
#include "rtc_base/system/file_wrapper.h"
#if WEBRTC_ENABLE_PROTOBUF
@@ -38,7 +39,7 @@
void DumpEventToFile(const Event& event, FileWrapper* dump_file) {
RTC_CHECK(dump_file->is_open());
- ProtoString dump_data;
+ std::string dump_data;
event.SerializeToString(&dump_data);
int32_t size = rtc::checked_cast<int32_t>(event.ByteSizeLong());
dump_file->Write(&size, sizeof(size));
@@ -67,14 +68,13 @@
#endif
private:
- std::unique_ptr<FileWrapper> dump_file_;
+ FileWrapper dump_file_;
};
-DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle)
- : dump_file_(FileWrapper::Create()) {
+DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle) {
#if WEBRTC_ENABLE_PROTOBUF
- dump_file_->OpenFromFileHandle(file_handle);
- RTC_CHECK(dump_file_->is_open());
+ dump_file_ = FileWrapper(file_handle);
+ RTC_CHECK(dump_file_.is_open());
#else
RTC_NOTREACHED();
#endif
@@ -110,7 +110,7 @@
*metrics.uplink_recoverable_packet_loss_fraction);
}
- DumpEventToFile(event, dump_file_.get());
+ DumpEventToFile(event, &dump_file_);
#endif // WEBRTC_ENABLE_PROTOBUF
}
@@ -143,7 +143,7 @@
if (config.num_channels)
dump_config->set_num_channels(*config.num_channels);
- DumpEventToFile(event, dump_file_.get());
+ DumpEventToFile(event, &dump_file_);
#endif // WEBRTC_ENABLE_PROTOBUF
}
@@ -157,7 +157,7 @@
event.set_type(Event::CONTROLLER_MANAGER_CONFIG);
event.mutable_controller_manager_config()->CopyFrom(
controller_manager_config);
- DumpEventToFile(event, dump_file_.get());
+ DumpEventToFile(event, &dump_file_);
}
#endif // WEBRTC_ENABLE_PROTOBUF
diff --git a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h
index b464eb6..367f659 100644
--- a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h
+++ b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h
@@ -15,7 +15,7 @@
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/ignore_wundef.h"
#include "rtc_base/system/file_wrapper.h"
#if WEBRTC_ENABLE_PROTOBUF
diff --git a/modules/audio_coding/audio_network_adaptor/dtx_controller.h b/modules/audio_coding/audio_network_adaptor/dtx_controller.h
index d3334ec..83fdf3d 100644
--- a/modules/audio_coding/audio_network_adaptor/dtx_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/dtx_controller.h
@@ -14,7 +14,7 @@
#include "absl/types/optional.h"
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/event_log_writer.h b/modules/audio_coding/audio_network_adaptor/event_log_writer.h
index 72b5245..c5e57e6 100644
--- a/modules/audio_coding/audio_network_adaptor/event_log_writer.h
+++ b/modules/audio_coding/audio_network_adaptor/event_log_writer.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_EVENT_LOG_WRITER_H_
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class RtcEventLog;
diff --git a/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc b/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc
index 42189c3..b1e3313 100644
--- a/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc
@@ -13,6 +13,7 @@
#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
#include "modules/audio_coding/audio_network_adaptor/event_log_writer.h"
+#include "rtc_base/checks.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
index b7d3d56..87afe2e 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
@@ -18,7 +18,7 @@
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
#include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
index de66717..d3f54ee 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
@@ -422,7 +422,7 @@
// Test that FEC is turned on whenever we're on the curve or above it,
// independent of the starting FEC state.
- for (std::vector<NetworkState> states_list : {on, above}) {
+ for (const std::vector<NetworkState>& states_list : {on, above}) {
for (NetworkState net_state : states_list) {
for (bool initial_fec_enabled : {false, true}) {
auto states =
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
index 421cb70..c547bff 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
@@ -15,7 +15,7 @@
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
#include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
index 8e8704e..4438a23 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
@@ -462,7 +462,7 @@
// Test that FEC is turned on whenever we're on the curve or above it,
// independent of the starting FEC state.
- for (std::vector<NetworkState> states_list : {on, above}) {
+ for (const std::vector<NetworkState>& states_list : {on, above}) {
for (NetworkState net_state : states_list) {
for (bool initial_fec_enabled : {false, true}) {
FecControllerRplrBased controller(
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
index b123c7c..3cb91fd 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
@@ -28,7 +28,7 @@
} // namespace
FrameLengthController::Config::Config(
- const std::vector<int>& encoder_frame_lengths_ms,
+ const std::set<int>& encoder_frame_lengths_ms,
int initial_frame_length_ms,
int min_encoder_bitrate_bps,
float fl_increasing_packet_loss_fraction,
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
index f0a5aab..e182247 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
@@ -13,12 +13,12 @@
#include <stddef.h>
#include <map>
-#include <vector>
+#include <set>
#include "absl/types/optional.h"
#include "modules/audio_coding/audio_network_adaptor/controller.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -33,7 +33,7 @@
int from_frame_length_ms;
int to_frame_length_ms;
};
- Config(const std::vector<int>& encoder_frame_lengths_ms,
+ Config(const std::set<int>& encoder_frame_lengths_ms,
int initial_frame_length_ms,
int min_encoder_bitrate_bps,
float fl_increasing_packet_loss_fraction,
@@ -43,7 +43,7 @@
std::map<FrameLengthChange, int> fl_changing_bandwidths_bps);
Config(const Config& other);
~Config();
- std::vector<int> encoder_frame_lengths_ms;
+ std::set<int> encoder_frame_lengths_ms;
int initial_frame_length_ms;
int min_encoder_bitrate_bps;
// Uplink packet loss fraction below which frame length can increase.
@@ -74,7 +74,7 @@
const Config config_;
- std::vector<int>::const_iterator frame_length_ms_;
+ std::set<int>::const_iterator frame_length_ms_;
absl::optional<int> uplink_bandwidth_bps_;
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
index f97ad4f..8d6d815 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
@@ -42,7 +42,7 @@
std::unique_ptr<FrameLengthController> CreateController(
const std::map<FrameLengthController::Config::FrameLengthChange, int>&
frame_length_change_criteria,
- const std::vector<int>& encoder_frame_lengths_ms,
+ const std::set<int>& encoder_frame_lengths_ms,
int initial_frame_length_ms) {
std::unique_ptr<FrameLengthController> controller(
new FrameLengthController(FrameLengthController::Config(
diff --git a/modules/audio_coding/codecs/audio_format_conversion.cc b/modules/audio_coding/codecs/audio_format_conversion.cc
deleted file mode 100644
index f068301..0000000
--- a/modules/audio_coding/codecs/audio_format_conversion.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2016 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/audio_coding/codecs/audio_format_conversion.h"
-
-#include <string.h>
-#include <string>
-#include <utility>
-
-#include "absl/strings/match.h"
-#include "api/array_view.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/sanitizer.h"
-
-namespace webrtc {
-
-namespace {
-
-CodecInst MakeCodecInst(int payload_type,
- const char* name,
- int sample_rate,
- size_t num_channels) {
- // Create a CodecInst with some fields set. The remaining fields are zeroed,
- // but we tell MSan to consider them uninitialized.
- CodecInst ci = {0};
- rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1));
- ci.pltype = payload_type;
- strncpy(ci.plname, name, sizeof(ci.plname));
- ci.plname[sizeof(ci.plname) - 1] = '\0';
- ci.plfreq = sample_rate;
- ci.channels = num_channels;
- return ci;
-}
-
-} // namespace
-
-SdpAudioFormat CodecInstToSdp(const CodecInst& ci) {
- if (absl::EqualsIgnoreCase(ci.plname, "g722")) {
- RTC_CHECK_EQ(16000, ci.plfreq);
- RTC_CHECK(ci.channels == 1 || ci.channels == 2);
- return {"g722", 8000, ci.channels};
- } else if (absl::EqualsIgnoreCase(ci.plname, "opus")) {
- RTC_CHECK_EQ(48000, ci.plfreq);
- RTC_CHECK(ci.channels == 1 || ci.channels == 2);
- return ci.channels == 1
- ? SdpAudioFormat("opus", 48000, 2)
- : SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}});
- } else {
- return {ci.plname, ci.plfreq, ci.channels};
- }
-}
-
-CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format) {
- if (absl::EqualsIgnoreCase(audio_format.name, "g722")) {
- RTC_CHECK_EQ(8000, audio_format.clockrate_hz);
- RTC_CHECK(audio_format.num_channels == 1 || audio_format.num_channels == 2);
- return MakeCodecInst(payload_type, "g722", 16000,
- audio_format.num_channels);
- } else if (absl::EqualsIgnoreCase(audio_format.name, "opus")) {
- RTC_CHECK_EQ(48000, audio_format.clockrate_hz);
- RTC_CHECK_EQ(2, audio_format.num_channels);
- const int num_channels = [&] {
- auto stereo = audio_format.parameters.find("stereo");
- if (stereo != audio_format.parameters.end()) {
- if (stereo->second == "0") {
- return 1;
- } else if (stereo->second == "1") {
- return 2;
- } else {
- RTC_CHECK(false); // Bad stereo parameter.
- }
- }
- return 1; // Default to mono.
- }();
- return MakeCodecInst(payload_type, "opus", 48000, num_channels);
- } else {
- return MakeCodecInst(payload_type, audio_format.name.c_str(),
- audio_format.clockrate_hz, audio_format.num_channels);
- }
-}
-
-} // namespace webrtc
diff --git a/modules/audio_coding/codecs/audio_format_conversion.h b/modules/audio_coding/codecs/audio_format_conversion.h
deleted file mode 100644
index d981741..0000000
--- a/modules/audio_coding/codecs/audio_format_conversion.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2016 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.
- */
-
-#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_
-#define MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_
-
-#include "api/audio_codecs/audio_format.h"
-#include "common_types.h" // NOLINT(build/include)
-
-namespace webrtc {
-
-SdpAudioFormat CodecInstToSdp(const CodecInst& codec_inst);
-CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format);
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_
diff --git a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
index 64f0159..a548be8 100644
--- a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
+++ b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
@@ -103,9 +103,9 @@
}
}
-INSTANTIATE_TEST_CASE_P(BuiltinAudioEncoderFactoryTest,
- AudioEncoderFactoryTest,
- ::testing::Values(CreateBuiltinAudioEncoderFactory()));
+INSTANTIATE_TEST_SUITE_P(BuiltinAudioEncoderFactoryTest,
+ AudioEncoderFactoryTest,
+ ::testing::Values(CreateBuiltinAudioEncoderFactory()));
TEST(BuiltinAudioEncoderFactoryTest, SupportsTheExpectedFormats) {
using ::testing::ElementsAreArray;
@@ -116,6 +116,7 @@
const std::vector<SdpAudioFormat> supported_formats = [&specs] {
std::vector<SdpAudioFormat> formats;
+ formats.reserve(specs.size());
for (const auto& spec : specs) {
formats.push_back(spec.format);
}
diff --git a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
index e3655b4..3ecefd4 100644
--- a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
+++ b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
@@ -13,7 +13,7 @@
#include "common_audio/vad/mock/mock_vad.h"
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
#include "test/mock_audio_encoder.h"
diff --git a/modules/audio_coding/codecs/cng/cng_unittest.cc b/modules/audio_coding/codecs/cng/cng_unittest.cc
index 81688b1..80349e2 100644
--- a/modules/audio_coding/codecs/cng/cng_unittest.cc
+++ b/modules/audio_coding/codecs/cng/cng_unittest.cc
@@ -12,7 +12,7 @@
#include "modules/audio_coding/codecs/cng/webrtc_cng.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/g711/audio_decoder_pcm.h b/modules/audio_coding/codecs/g711/audio_decoder_pcm.h
index 9a01b8a..8fae71c 100644
--- a/modules/audio_coding/codecs/g711/audio_decoder_pcm.h
+++ b/modules/audio_coding/codecs/g711/audio_decoder_pcm.h
@@ -18,7 +18,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index dce1635..fd560e4 100644
--- a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -12,25 +12,11 @@
#include <cstdint>
-#include "common_types.h"
#include "modules/audio_coding/codecs/g711/g711_interface.h"
#include "rtc_base/checks.h"
namespace webrtc {
-namespace {
-
-template <typename T>
-typename T::Config CreateConfig(const CodecInst& codec_inst) {
- typename T::Config config;
- config.frame_size_ms = codec_inst.pacsize / 8;
- config.num_channels = codec_inst.channels;
- config.payload_type = codec_inst.pltype;
- return config;
-}
-
-} // namespace
-
bool AudioEncoderPcm::Config::IsOk() const {
return (frame_size_ms % 10 == 0) && (num_channels >= 1);
}
@@ -103,9 +89,6 @@
speech_buffer_.clear();
}
-AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst)
- : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {}
-
size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
size_t input_len,
uint8_t* encoded) {
@@ -120,9 +103,6 @@
return AudioEncoder::CodecType::kPcmA;
}
-AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst)
- : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {}
-
size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
size_t input_len,
uint8_t* encoded) {
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.h b/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
index 37b67cf..e41c2a3 100644
--- a/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
+++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
@@ -14,7 +14,7 @@
#include <vector>
#include "api/audio_codecs/audio_encoder.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -69,8 +69,6 @@
uint32_t first_timestamp_in_buffer_;
};
-struct CodecInst;
-
class AudioEncoderPcmA final : public AudioEncoderPcm {
public:
struct Config : public AudioEncoderPcm::Config {
@@ -79,7 +77,6 @@
explicit AudioEncoderPcmA(const Config& config)
: AudioEncoderPcm(config, kSampleRateHz) {}
- explicit AudioEncoderPcmA(const CodecInst& codec_inst);
protected:
size_t EncodeCall(const int16_t* audio,
@@ -103,7 +100,6 @@
explicit AudioEncoderPcmU(const Config& config)
: AudioEncoderPcm(config, kSampleRateHz) {}
- explicit AudioEncoderPcmU(const CodecInst& codec_inst);
protected:
size_t EncodeCall(const int16_t* audio,
diff --git a/modules/audio_coding/codecs/g722/audio_decoder_g722.h b/modules/audio_coding/codecs/g722/audio_decoder_g722.h
index 3240448..6911e0b 100644
--- a/modules/audio_coding/codecs/g722/audio_decoder_g722.h
+++ b/modules/audio_coding/codecs/g722/audio_decoder_g722.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_CODECS_G722_AUDIO_DECODER_G722_H_
#include "api/audio_codecs/audio_decoder.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
typedef struct WebRtcG722DecInst G722DecInst;
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
index e63d590..d293163 100644
--- a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -12,7 +12,6 @@
#include <cstdint>
-#include "common_types.h"
#include "modules/audio_coding/codecs/g722/g722_interface.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
@@ -23,13 +22,6 @@
const size_t kSampleRateHz = 16000;
-AudioEncoderG722Config CreateConfig(const CodecInst& codec_inst) {
- AudioEncoderG722Config config;
- config.num_channels = rtc::dchecked_cast<int>(codec_inst.channels);
- config.frame_size_ms = codec_inst.pacsize / 16;
- return config;
-}
-
} // namespace
AudioEncoderG722Impl::AudioEncoderG722Impl(const AudioEncoderG722Config& config,
@@ -52,9 +44,6 @@
Reset();
}
-AudioEncoderG722Impl::AudioEncoderG722Impl(const CodecInst& codec_inst)
- : AudioEncoderG722Impl(CreateConfig(codec_inst), codec_inst.pltype) {}
-
AudioEncoderG722Impl::~AudioEncoderG722Impl() = default;
int AudioEncoderG722Impl::SampleRateHz() const {
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/modules/audio_coding/codecs/g722/audio_encoder_g722.h
index 3cf1439..cf45fb5 100644
--- a/modules/audio_coding/codecs/g722/audio_encoder_g722.h
+++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.h
@@ -17,16 +17,13 @@
#include "api/audio_codecs/g722/audio_encoder_g722_config.h"
#include "modules/audio_coding/codecs/g722/g722_interface.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
-struct CodecInst;
-
class AudioEncoderG722Impl final : public AudioEncoder {
public:
AudioEncoderG722Impl(const AudioEncoderG722Config& config, int payload_type);
- explicit AudioEncoderG722Impl(const CodecInst& codec_inst);
~AudioEncoderG722Impl() override;
int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h
index fcb2074..d73ef0d 100644
--- a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h
+++ b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h
@@ -17,7 +17,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
typedef struct iLBC_decinst_t_ IlbcDecoderInstance;
diff --git a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
index 8801fd5..ac9214b 100644
--- a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -13,7 +13,6 @@
#include <algorithm>
#include <cstdint>
-#include "common_types.h"
#include "modules/audio_coding/codecs/ilbc/ilbc.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
@@ -24,12 +23,6 @@
const int kSampleRateHz = 8000;
-AudioEncoderIlbcConfig CreateConfig(const CodecInst& codec_inst) {
- AudioEncoderIlbcConfig config;
- config.frame_size_ms = codec_inst.pacsize / 8;
- return config;
-}
-
int GetIlbcBitrate(int ptime) {
switch (ptime) {
case 20:
@@ -58,9 +51,6 @@
Reset();
}
-AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const CodecInst& codec_inst)
- : AudioEncoderIlbcImpl(CreateConfig(codec_inst), codec_inst.pltype) {}
-
AudioEncoderIlbcImpl::~AudioEncoderIlbcImpl() {
RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
}
diff --git a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
index a238689..ada613b 100644
--- a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
+++ b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
@@ -14,16 +14,13 @@
#include "api/audio_codecs/audio_encoder.h"
#include "api/audio_codecs/ilbc/audio_encoder_ilbc_config.h"
#include "modules/audio_coding/codecs/ilbc/ilbc.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
-struct CodecInst;
-
class AudioEncoderIlbcImpl final : public AudioEncoder {
public:
AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig& config, int payload_type);
- explicit AudioEncoderIlbcImpl(const CodecInst& codec_inst);
~AudioEncoderIlbcImpl() override;
int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
index 5ec1219..689292f 100644
--- a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
+++ b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
@@ -103,7 +103,7 @@
// Also test the maximum number of frames in one packet for 20 and 30 ms.
// The maximum is defined by the largest payload length that can be uniquely
// resolved to a frame size of either 38 bytes (20 ms) or 50 bytes (30 ms).
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
IlbcTest,
SplitIlbcTest,
::testing::Values(std::pair<int, int>(1, 20), // 1 frame, 20 ms.
diff --git a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
index f840ffa..7cadd91 100644
--- a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
+++ b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
@@ -15,9 +15,9 @@
#include "absl/types/optional.h"
#include "api/audio_codecs/audio_decoder.h"
+#include "api/scoped_refptr.h"
#include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index 541b90c..c6ef795 100644
--- a/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -14,14 +14,12 @@
#include <vector>
#include "api/audio_codecs/audio_encoder.h"
+#include "api/scoped_refptr.h"
#include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
-struct CodecInst;
-
template <typename T>
class AudioEncoderIsacT final : public AudioEncoder {
public:
@@ -52,9 +50,6 @@
};
explicit AudioEncoderIsacT(const Config& config);
- explicit AudioEncoderIsacT(
- const CodecInst& codec_inst,
- const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo);
~AudioEncoderIsacT() override;
int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index cbf15fc..3448139 100644
--- a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -11,28 +11,11 @@
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
-#include "common_types.h" // NOLINT(build/include)
#include "rtc_base/checks.h"
namespace webrtc {
template <typename T>
-typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
- const CodecInst& codec_inst,
- const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo) {
- typename AudioEncoderIsacT<T>::Config config;
- config.bwinfo = bwinfo;
- config.payload_type = codec_inst.pltype;
- config.sample_rate_hz = codec_inst.plfreq;
- config.frame_size_ms =
- rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
- config.adaptive_mode = (codec_inst.rate == -1);
- if (codec_inst.rate != -1)
- config.bit_rate = codec_inst.rate;
- return config;
-}
-
-template <typename T>
bool AudioEncoderIsacT<T>::Config::IsOk() const {
if (max_bit_rate < 32000 && max_bit_rate != -1)
return false;
@@ -67,12 +50,6 @@
}
template <typename T>
-AudioEncoderIsacT<T>::AudioEncoderIsacT(
- const CodecInst& codec_inst,
- const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo)
- : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
-
-template <typename T>
AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
RTC_CHECK_EQ(0, T::Free(isac_state_));
}
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
index e565e85..7355330 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
@@ -9,7 +9,6 @@
*/
#include "modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h"
-
#include "common_audio/signal_processing/include/signal_processing_library.h"
#include "modules/audio_coding/codecs/isac/fix/source/settings.h"
#include "modules/audio_coding/codecs/isac/fix/source/structs.h"
@@ -55,7 +54,8 @@
const int16_t Gain = 21299; // 1.3 in Q14
int16_t oldLagQ7;
int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12;
- size_t indW32 = 0, frcQQ = 0;
+ size_t frcQQ = 0;
+ int32_t indW32 = 0;
const int16_t* fracoeffQQ = NULL;
// Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM().
diff --git a/modules/audio_coding/codecs/isac/locked_bandwidth_info.h b/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
index 37074f8..0b1bc7d 100644
--- a/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
+++ b/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
@@ -12,8 +12,8 @@
#define MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_
#include "modules/audio_coding/codecs/isac/bandwidth_info.h"
-#include "rtc_base/atomicops.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
index 3ec28cc..6d9b013 100644
--- a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
+++ b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
@@ -11,7 +11,7 @@
#include "modules/audio_coding/codecs/isac/main/include/isac.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
struct WebRtcISACStruct;
diff --git a/modules/audio_coding/codecs/isac/unittest.cc b/modules/audio_coding/codecs/isac/unittest.cc
index 5855d56..076510b 100644
--- a/modules/audio_coding/codecs/isac/unittest.cc
+++ b/modules/audio_coding/codecs/isac/unittest.cc
@@ -19,7 +19,7 @@
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -252,6 +252,6 @@
return cases;
}
-INSTANTIATE_TEST_CASE_P(, IsacCommonTest, testing::ValuesIn(TestCases()));
+INSTANTIATE_TEST_SUITE_P(, IsacCommonTest, testing::ValuesIn(TestCases()));
} // namespace webrtc
diff --git a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
index 9079bcd..2ca1d4c 100644
--- a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
+++ b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
@@ -10,12 +10,28 @@
#include "modules/audio_coding/codecs/legacy_encoded_audio_frame.h"
-#include "modules/audio_coding/acm2/rent_a_codec.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
namespace webrtc {
+enum class NetEqDecoder {
+ kDecoderPCMu,
+ kDecoderPCMa,
+ kDecoderPCMu_2ch,
+ kDecoderPCMa_2ch,
+ kDecoderPCM16B,
+ kDecoderPCM16Bwb,
+ kDecoderPCM16Bswb32kHz,
+ kDecoderPCM16Bswb48kHz,
+ kDecoderPCM16B_2ch,
+ kDecoderPCM16Bwb_2ch,
+ kDecoderPCM16Bswb32kHz_2ch,
+ kDecoderPCM16Bswb48kHz_2ch,
+ kDecoderPCM16B_5ch,
+ kDecoderG722,
+};
+
class SplitBySamplesTest : public ::testing::TestWithParam<NetEqDecoder> {
protected:
virtual void SetUp() {
@@ -144,7 +160,7 @@
}
}
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
LegacyEncodedAudioFrame,
SplitBySamplesTest,
::testing::Values(NetEqDecoder::kDecoderPCMu,
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
index 357cb1a..b6eada9 100644
--- a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
+++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
@@ -71,8 +71,10 @@
AudioDecoderOpusImpl::AudioDecoderOpusImpl(size_t num_channels)
: channels_(num_channels) {
- RTC_DCHECK(num_channels == 1 || num_channels == 2);
- WebRtcOpus_DecoderCreate(&dec_state_, channels_);
+ RTC_DCHECK(num_channels == 1 || num_channels == 2 || num_channels == 4 ||
+ num_channels == 6 || num_channels == 8);
+ const int error = WebRtcOpus_DecoderCreate(&dec_state_, channels_);
+ RTC_DCHECK(error == 0);
WebRtcOpus_DecoderInit(dec_state_);
}
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.h b/modules/audio_coding/codecs/opus/audio_decoder_opus.h
index 8043425..d8cc5c1 100644
--- a/modules/audio_coding/codecs/opus/audio_decoder_opus.h
+++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.h
@@ -18,7 +18,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "modules/audio_coding/codecs/opus/opus_interface.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index 1a88acf..69aa8b9 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -12,11 +12,11 @@
#include <algorithm>
#include <iterator>
+#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
-#include "common_types.h"
#include "modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h"
#include "modules/audio_coding/audio_network_adaptor/controller_manager.h"
#include "modules/audio_coding/codecs/opus/opus_interface.h"
@@ -26,9 +26,8 @@
#include "rtc_base/numerics/exp_filter.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/numerics/safe_minmax.h"
-#include "rtc_base/protobuf_utils.h"
#include "rtc_base/string_to_number.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -334,19 +333,6 @@
return absl::nullopt;
}
-AudioEncoderOpusConfig AudioEncoderOpusImpl::CreateConfig(
- const CodecInst& codec_inst) {
- AudioEncoderOpusConfig config;
- config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
- config.num_channels = codec_inst.channels;
- config.bitrate_bps = codec_inst.rate;
- config.application = config.num_channels == 1
- ? AudioEncoderOpusConfig::ApplicationMode::kVoip
- : AudioEncoderOpusConfig::ApplicationMode::kAudio;
- config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
- return config;
-}
-
absl::optional<AudioEncoderOpusConfig> AudioEncoderOpusImpl::SdpToConfig(
const SdpAudioFormat& format) {
if (!absl::EqualsIgnoreCase(format.name, "opus") ||
@@ -457,7 +443,7 @@
: AudioEncoderOpusImpl(
config,
payload_type,
- [this](const ProtoString& config_string, RtcEventLog* event_log) {
+ [this](const std::string& config_string, RtcEventLog* event_log) {
return DefaultAudioNetworkAdaptorCreator(config_string, event_log);
},
// We choose 5sec as initial time constant due to empirical data.
@@ -494,9 +480,6 @@
SetProjectedPacketLossRate(packet_loss_rate_);
}
-AudioEncoderOpusImpl::AudioEncoderOpusImpl(const CodecInst& codec_inst)
- : AudioEncoderOpusImpl(CreateConfig(codec_inst), codec_inst.pltype) {}
-
AudioEncoderOpusImpl::AudioEncoderOpusImpl(int payload_type,
const SdpAudioFormat& format)
: AudioEncoderOpusImpl(*SdpToConfig(format), payload_type) {}
@@ -784,7 +767,9 @@
AudioEncoderOpusConfig::ApplicationMode::kVoip
? 0
: 1));
- RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config)));
+ const int bitrate = GetBitrateBps(config);
+ RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate));
+ RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps.";
if (config.fec_enabled) {
RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_));
} else {
@@ -847,17 +832,23 @@
}
void AudioEncoderOpusImpl::SetTargetBitrate(int bits_per_second) {
- config_.bitrate_bps = rtc::SafeClamp<int>(
+ const int new_bitrate = rtc::SafeClamp<int>(
bits_per_second, AudioEncoderOpusConfig::kMinBitrateBps,
AudioEncoderOpusConfig::kMaxBitrateBps);
- RTC_DCHECK(config_.IsOk());
- RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config_)));
+ if (config_.bitrate_bps && *config_.bitrate_bps != new_bitrate) {
+ config_.bitrate_bps = new_bitrate;
+ RTC_DCHECK(config_.IsOk());
+ const int bitrate = GetBitrateBps(config_);
+ RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate));
+ RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps.";
+ bitrate_changed_ = true;
+ }
+
const auto new_complexity = GetNewComplexity(config_);
if (new_complexity && complexity_ != *new_complexity) {
complexity_ = *new_complexity;
RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_));
}
- bitrate_changed_ = true;
}
void AudioEncoderOpusImpl::ApplyAudioNetworkAdaptor() {
@@ -879,7 +870,7 @@
std::unique_ptr<AudioNetworkAdaptor>
AudioEncoderOpusImpl::DefaultAudioNetworkAdaptorCreator(
- const ProtoString& config_string,
+ const std::string& config_string,
RtcEventLog* event_log) const {
AudioNetworkAdaptorImpl::Config config;
config.event_log = event_log;
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/modules/audio_coding/codecs/opus/audio_encoder_opus.h
index 150423f..dc14620 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus.h
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -23,15 +23,12 @@
#include "common_audio/smoothing_filter.h"
#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
#include "modules/audio_coding/codecs/opus/opus_interface.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/protobuf_utils.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class RtcEventLog;
-struct CodecInst;
-
class AudioEncoderOpusImpl final : public AudioEncoder {
public:
class NewPacketLossRateOptimizer {
@@ -43,9 +40,9 @@
float OptimizePacketLossRate(float packet_loss_rate) const;
// Getters for testing.
- float min_packet_loss_rate() const { return min_packet_loss_rate_; };
- float max_packet_loss_rate() const { return max_packet_loss_rate_; };
- float slope() const { return slope_; };
+ float min_packet_loss_rate() const { return min_packet_loss_rate_; }
+ float max_packet_loss_rate() const { return max_packet_loss_rate_; }
+ float slope() const { return slope_; }
private:
const float min_packet_loss_rate_;
@@ -54,8 +51,6 @@
RTC_DISALLOW_COPY_AND_ASSIGN(NewPacketLossRateOptimizer);
};
- static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst);
-
// Returns empty if the current bitrate falls within the hysteresis window,
// defined by complexity_threshold_bps +/- complexity_threshold_window_bps.
// Otherwise, returns the current complexity depending on whether the
@@ -83,7 +78,6 @@
const AudioNetworkAdaptorCreator& audio_network_adaptor_creator,
std::unique_ptr<SmoothingFilter> bitrate_smoother);
- explicit AudioEncoderOpusImpl(const CodecInst& codec_inst);
AudioEncoderOpusImpl(int payload_type, const SdpAudioFormat& format);
~AudioEncoderOpusImpl() override;
@@ -176,7 +170,7 @@
void ApplyAudioNetworkAdaptor();
std::unique_ptr<AudioNetworkAdaptor> DefaultAudioNetworkAdaptorCreator(
- const ProtoString& config_string,
+ const std::string& config_string,
RtcEventLog* event_log) const;
void MaybeUpdateUplinkBandwidth();
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
index d5c2c84..b3b531f 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -15,17 +15,16 @@
#include "absl/memory/memory.h"
#include "api/audio_codecs/opus/audio_encoder_opus.h"
#include "common_audio/mocks/mock_smoothing_filter.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h"
#include "modules/audio_coding/codecs/opus/audio_encoder_opus.h"
#include "modules/audio_coding/codecs/opus/opus_interface.h"
#include "modules/audio_coding/neteq/tools/audio_loop.h"
#include "rtc_base/checks.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
using ::testing::NiceMock;
@@ -33,21 +32,11 @@
namespace {
-const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000};
+constexpr int kDefaultOpusPayloadType = 105;
+constexpr int kDefaultOpusRate = 32000;
+constexpr int kDefaultOpusPacSize = 960;
constexpr int64_t kInitialTimeUs = 12345678;
-AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst) {
- AudioEncoderOpusConfig config;
- config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
- config.num_channels = codec_inst.channels;
- config.bitrate_bps = codec_inst.rate;
- config.application = config.num_channels == 1
- ? AudioEncoderOpusConfig::ApplicationMode::kVoip
- : AudioEncoderOpusConfig::ApplicationMode::kAudio;
- config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
- return config;
-}
-
AudioEncoderOpusConfig CreateConfigWithParameters(
const SdpAudioFormat::Parameters& params) {
const SdpAudioFormat format("opus", 48000, 2, params);
@@ -79,16 +68,23 @@
return adaptor;
};
- CodecInst codec_inst = kDefaultOpusSettings;
- codec_inst.channels = num_channels;
- states->config = CreateConfig(codec_inst);
+ AudioEncoderOpusConfig config;
+ config.frame_size_ms = rtc::CheckedDivExact(kDefaultOpusPacSize, 48);
+ config.num_channels = num_channels;
+ config.bitrate_bps = kDefaultOpusRate;
+ config.application = num_channels == 1
+ ? AudioEncoderOpusConfig::ApplicationMode::kVoip
+ : AudioEncoderOpusConfig::ApplicationMode::kAudio;
+ config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
+ states->config = config;
+
std::unique_ptr<MockSmoothingFilter> bitrate_smoother(
new MockSmoothingFilter());
states->mock_bitrate_smoother = bitrate_smoother.get();
- states->encoder.reset(new AudioEncoderOpusImpl(
- states->config, codec_inst.pltype, std::move(creator),
- std::move(bitrate_smoother)));
+ states->encoder.reset(
+ new AudioEncoderOpusImpl(states->config, kDefaultOpusPayloadType, creator,
+ std::move(bitrate_smoother)));
return states;
}
@@ -436,12 +432,12 @@
auto states = CreateCodec(2);
- states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusSettings.rate * 2,
+ states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusRate * 2,
absl::nullopt);
// Since |OnReceivedOverhead| has not been called, the codec bitrate should
// not change.
- EXPECT_EQ(kDefaultOpusSettings.rate, states->encoder->GetTargetBitrate());
+ EXPECT_EQ(kDefaultOpusRate, states->encoder->GetTargetBitrate());
}
TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) {
@@ -456,7 +452,7 @@
constexpr int kTargetBitrateBps = 40000;
states->encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps, absl::nullopt);
- int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize);
+ int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusPacSize);
EXPECT_EQ(kTargetBitrateBps -
8 * static_cast<int>(kOverheadBytesPerPacket) * packet_rate,
states->encoder->GetTargetBitrate());
@@ -474,7 +470,7 @@
constexpr size_t kOverheadBytesPerPacket = 64;
states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket);
- int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize);
+ int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusPacSize);
// Set a target rate that is smaller than |kMinBitrateBps| when overhead is
// subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|.
diff --git a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
index 7e6b626..2c8edf0 100644
--- a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
@@ -16,7 +16,7 @@
#include "modules/audio_coding/neteq/tools/audio_loop.h"
#include "test/field_trial.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace {
diff --git a/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc b/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
index 4c9174d..84bad33 100644
--- a/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
@@ -11,9 +11,9 @@
#include "api/audio_codecs/opus/audio_encoder_opus.h"
#include "modules/audio_coding/neteq/tools/audio_loop.h"
#include "rtc_base/format_macros.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
#include "test/testsupport/perf_test.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/opus/opus_fec_test.cc b/modules/audio_coding/codecs/opus/opus_fec_test.cc
index 4fab8a7..7552c20 100644
--- a/modules/audio_coding/codecs/opus/opus_fec_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_fec_test.cc
@@ -13,7 +13,7 @@
#include "modules/audio_coding/codecs/opus/opus_interface.h"
#include "rtc_base/format_macros.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
using std::string;
using std::tuple;
@@ -238,6 +238,6 @@
string("pcm"))};
// 64 kbps, stereo
-INSTANTIATE_TEST_CASE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set));
+INSTANTIATE_TEST_SUITE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set));
} // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_inst.h b/modules/audio_coding/codecs/opus/opus_inst.h
index 2473a5c..0b31181 100644
--- a/modules/audio_coding/codecs/opus/opus_inst.h
+++ b/modules/audio_coding/codecs/opus/opus_inst.h
@@ -17,16 +17,23 @@
RTC_PUSH_IGNORING_WUNDEF()
#include "opus.h"
+#include "opus_multistream.h"
RTC_POP_IGNORING_WUNDEF()
struct WebRtcOpusEncInst {
- OpusEncoder* encoder;
+ union {
+ OpusEncoder* encoder;
+ OpusMSEncoder* multistream_encoder;
+ } encoder;
size_t channels;
int in_dtx_mode;
};
struct WebRtcOpusDecInst {
- OpusDecoder* decoder;
+ union {
+ OpusDecoder* decoder;
+ OpusMSDecoder* multistream_decoder;
+ } decoder;
int prev_decoded_samples;
size_t channels;
int in_dtx_mode;
diff --git a/modules/audio_coding/codecs/opus/opus_interface.c b/modules/audio_coding/codecs/opus/opus_interface.c
index d219098..3369f8e 100644
--- a/modules/audio_coding/codecs/opus/opus_interface.c
+++ b/modules/audio_coding/codecs/opus/opus_interface.c
@@ -37,6 +37,40 @@
kWebRtcOpusDefaultFrameSize = 960,
};
+int16_t GetSurroundParameters(int channels,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping) {
+ int opus_error;
+ int ret = 0;
+ // Use 'surround encoder create' to get values for 'coupled_streams',
+ // 'streams' and 'mapping'.
+ OpusMSEncoder* ms_encoder_ptr = opus_multistream_surround_encoder_create(
+ 48000,
+ channels,
+ /* mapping family */ channels <= 2 ? 0 : 1,
+ streams,
+ coupled_streams,
+ mapping,
+ OPUS_APPLICATION_VOIP, // Application type shouldn't affect
+ // streams/mapping values.
+ &opus_error);
+
+ // This shouldn't fail; if it fails,
+ // signal an error and return invalid values.
+ if (opus_error != OPUS_OK || ms_encoder_ptr == NULL) {
+ ret = -1;
+ *streams = -1;
+ *coupled_streams = -1;
+ }
+
+ // We don't need the encoder.
+ if (ms_encoder_ptr != NULL) {
+ opus_multistream_encoder_destroy(ms_encoder_ptr);
+ }
+ return ret;
+}
+
int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
size_t channels,
int32_t application) {
@@ -55,13 +89,34 @@
return -1;
}
- OpusEncInst* state = calloc(1, sizeof(OpusEncInst));
+ OpusEncInst* state = (OpusEncInst*)calloc(1, sizeof(OpusEncInst));
RTC_DCHECK(state);
int error;
- state->encoder = opus_encoder_create(48000, (int)channels, opus_app,
- &error);
- if (error != OPUS_OK || !state->encoder) {
+ if (channels <= 2) {
+ state->encoder.encoder = opus_encoder_create(48000, (int)channels, opus_app,
+ &error);
+
+ } else {
+ unsigned char mapping[255];
+ memset(mapping, 0, 255);
+ int streams = -1;
+ int coupled_streams = -1;
+
+ state->encoder.multistream_encoder =
+ opus_multistream_surround_encoder_create(
+ 48000,
+ channels,
+ /* mapping family */ 1,
+ &streams,
+ &coupled_streams,
+ mapping,
+ opus_app,
+ &error);
+ }
+
+ if (error != OPUS_OK || (!state->encoder.encoder &&
+ !state->encoder.multistream_encoder)) {
WebRtcOpus_EncoderFree(state);
return -1;
}
@@ -75,7 +130,11 @@
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) {
if (inst) {
- opus_encoder_destroy(inst->encoder);
+ if (inst->channels <= 2) {
+ opus_encoder_destroy(inst->encoder.encoder);
+ } else {
+ opus_multistream_encoder_destroy(inst->encoder.multistream_encoder);
+ }
free(inst);
return 0;
} else {
@@ -94,11 +153,19 @@
return -1;
}
- res = opus_encode(inst->encoder,
- (const opus_int16*)audio_in,
- (int)samples,
- encoded,
- (opus_int32)length_encoded_buffer);
+ if (inst->channels <= 2) {
+ res = opus_encode(inst->encoder.encoder,
+ (const opus_int16*)audio_in,
+ (int)samples,
+ encoded,
+ (opus_int32)length_encoded_buffer);
+ } else {
+ res = opus_multistream_encode(inst->encoder.multistream_encoder,
+ (const opus_int16*)audio_in,
+ (int)samples,
+ encoded,
+ (opus_int32)length_encoded_buffer);
+ }
if (res <= 0) {
return -1;
@@ -120,9 +187,15 @@
return res;
}
+#define ENCODER_CTL(inst, vargs) ( \
+ inst->channels <= 2 ? \
+ opus_encoder_ctl(inst->encoder.encoder, vargs) \
+ : opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs))
+
+
int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_BITRATE(rate));
+ return ENCODER_CTL(inst, OPUS_SET_BITRATE(rate));
} else {
return -1;
}
@@ -130,8 +203,7 @@
int16_t WebRtcOpus_SetPacketLossRate(OpusEncInst* inst, int32_t loss_rate) {
if (inst) {
- return opus_encoder_ctl(inst->encoder,
- OPUS_SET_PACKET_LOSS_PERC(loss_rate));
+ return ENCODER_CTL(inst, OPUS_SET_PACKET_LOSS_PERC(loss_rate));
} else {
return -1;
}
@@ -154,13 +226,52 @@
} else {
set_bandwidth = OPUS_BANDWIDTH_FULLBAND;
}
- return opus_encoder_ctl(inst->encoder,
- OPUS_SET_MAX_BANDWIDTH(set_bandwidth));
+ return ENCODER_CTL(inst, OPUS_SET_MAX_BANDWIDTH(set_bandwidth));
+}
+
+int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst,
+ int32_t* result_hz) {
+ if (inst->channels <= 2) {
+ if (opus_encoder_ctl(
+ inst->encoder.encoder,
+ OPUS_GET_MAX_BANDWIDTH(result_hz)) == OPUS_OK) {
+ return 0;
+ }
+ return -1;
+ }
+
+ opus_int32 max_bandwidth;
+ int s;
+ int ret;
+
+ max_bandwidth = 0;
+ ret = OPUS_OK;
+ s = 0;
+ while (ret == OPUS_OK) {
+ OpusEncoder *enc;
+ opus_int32 bandwidth;
+
+ ret = ENCODER_CTL(inst, OPUS_MULTISTREAM_GET_ENCODER_STATE(s, &enc));
+ if (ret == OPUS_BAD_ARG)
+ break;
+ if (ret != OPUS_OK)
+ return -1;
+ if (opus_encoder_ctl(enc, OPUS_GET_MAX_BANDWIDTH(&bandwidth)) != OPUS_OK)
+ return -1;
+
+ if (max_bandwidth != 0 && max_bandwidth != bandwidth)
+ return -1;
+
+ max_bandwidth = bandwidth;
+ s++;
+ }
+ *result_hz = max_bandwidth;
+ return 0;
}
int16_t WebRtcOpus_EnableFec(OpusEncInst* inst) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_INBAND_FEC(1));
+ return ENCODER_CTL(inst, OPUS_SET_INBAND_FEC(1));
} else {
return -1;
}
@@ -168,7 +279,7 @@
int16_t WebRtcOpus_DisableFec(OpusEncInst* inst) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_INBAND_FEC(0));
+ return ENCODER_CTL(inst, OPUS_SET_INBAND_FEC(0));
} else {
return -1;
}
@@ -184,21 +295,21 @@
// last long during a pure silence, if the signal type is not forced.
// TODO(minyue): Remove the signal type forcing when Opus DTX works properly
// without it.
- int ret = opus_encoder_ctl(inst->encoder,
- OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
+ int ret = ENCODER_CTL(inst,
+ OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
if (ret != OPUS_OK)
return ret;
- return opus_encoder_ctl(inst->encoder, OPUS_SET_DTX(1));
+ return ENCODER_CTL(inst, OPUS_SET_DTX(1));
}
int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst) {
if (inst) {
- int ret = opus_encoder_ctl(inst->encoder,
- OPUS_SET_SIGNAL(OPUS_AUTO));
+ int ret = ENCODER_CTL(inst,
+ OPUS_SET_SIGNAL(OPUS_AUTO));
if (ret != OPUS_OK)
return ret;
- return opus_encoder_ctl(inst->encoder, OPUS_SET_DTX(0));
+ return ENCODER_CTL(inst, OPUS_SET_DTX(0));
} else {
return -1;
}
@@ -206,7 +317,7 @@
int16_t WebRtcOpus_EnableCbr(OpusEncInst* inst) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(0));
+ return ENCODER_CTL(inst, OPUS_SET_VBR(0));
} else {
return -1;
}
@@ -214,7 +325,7 @@
int16_t WebRtcOpus_DisableCbr(OpusEncInst* inst) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(1));
+ return ENCODER_CTL(inst, OPUS_SET_VBR(1));
} else {
return -1;
}
@@ -222,7 +333,8 @@
int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_COMPLEXITY(complexity));
+ return ENCODER_CTL(inst,
+ OPUS_SET_COMPLEXITY(complexity));
} else {
return -1;
}
@@ -233,7 +345,8 @@
return -1;
}
int32_t bandwidth;
- if (opus_encoder_ctl(inst->encoder, OPUS_GET_BANDWIDTH(&bandwidth)) == 0) {
+ if (ENCODER_CTL(inst,
+ OPUS_GET_BANDWIDTH(&bandwidth)) == 0) {
return bandwidth;
} else {
return -1;
@@ -243,7 +356,8 @@
int16_t WebRtcOpus_SetBandwidth(OpusEncInst* inst, int32_t bandwidth) {
if (inst) {
- return opus_encoder_ctl(inst->encoder, OPUS_SET_BANDWIDTH(bandwidth));
+ return ENCODER_CTL(inst,
+ OPUS_SET_BANDWIDTH(bandwidth));
} else {
return -1;
}
@@ -253,11 +367,11 @@
if (!inst)
return -1;
if (num_channels == 0) {
- return opus_encoder_ctl(inst->encoder,
+ return ENCODER_CTL(inst,
OPUS_SET_FORCE_CHANNELS(OPUS_AUTO));
} else if (num_channels == 1 || num_channels == 2) {
- return opus_encoder_ctl(inst->encoder,
- OPUS_SET_FORCE_CHANNELS(num_channels));
+ return ENCODER_CTL(inst,
+ OPUS_SET_FORCE_CHANNELS(num_channels));
} else {
return -1;
}
@@ -268,16 +382,37 @@
OpusDecInst* state;
if (inst != NULL) {
- /* Create Opus decoder state. */
+ // Create Opus decoder state.
state = (OpusDecInst*) calloc(1, sizeof(OpusDecInst));
if (state == NULL) {
return -1;
}
- /* Create new memory, always at 48000 Hz. */
- state->decoder = opus_decoder_create(48000, (int)channels, &error);
- if (error == OPUS_OK && state->decoder != NULL) {
- /* Creation of memory all ok. */
+ if (channels <= 2) {
+ state->decoder.decoder = opus_decoder_create(48000,
+ (int)channels, &error);
+ } else {
+ unsigned char mapping[255];
+ memset(mapping, 0, 255);
+ int streams = -1;
+ int coupled_streams = -1;
+ if (GetSurroundParameters(channels, &streams,
+ &coupled_streams, mapping) != 0) {
+ free(state);
+ return -1;
+ }
+
+ // Create new memory, always at 48000 Hz.
+ state->decoder.multistream_decoder = opus_multistream_decoder_create(
+ 48000, (int)channels,
+ /* streams = */ streams,
+ /* coupled streams = */ coupled_streams,
+ mapping,
+ &error);
+ }
+ if (error == OPUS_OK && (state->decoder.decoder ||
+ state->decoder.multistream_decoder)) {
+ // Creation of memory all ok.
state->channels = channels;
state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize;
state->in_dtx_mode = 0;
@@ -285,9 +420,12 @@
return 0;
}
- /* If memory allocation was unsuccessful, free the entire state. */
- if (state->decoder) {
- opus_decoder_destroy(state->decoder);
+ // If memory allocation was unsuccessful, free the entire state.
+ if (state->decoder.decoder) {
+ opus_decoder_destroy(state->decoder.decoder);
+
+ } else if (state->decoder.multistream_decoder) {
+ opus_multistream_decoder_destroy(state->decoder.multistream_decoder);
}
free(state);
}
@@ -296,7 +434,11 @@
int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) {
if (inst) {
- opus_decoder_destroy(inst->decoder);
+ if (inst->channels <= 2) {
+ opus_decoder_destroy(inst->decoder.decoder);
+ } else if (inst->channels > 2) {
+ opus_multistream_decoder_destroy(inst->decoder.multistream_decoder);
+ }
free(inst);
return 0;
} else {
@@ -309,7 +451,12 @@
}
void WebRtcOpus_DecoderInit(OpusDecInst* inst) {
- opus_decoder_ctl(inst->decoder, OPUS_RESET_STATE);
+ if (inst->channels <= 2) {
+ opus_decoder_ctl(inst->decoder.decoder, OPUS_RESET_STATE);
+ } else {
+ opus_multistream_decoder_ctl(inst->decoder.multistream_decoder,
+ OPUS_RESET_STATE);
+ }
inst->in_dtx_mode = 0;
}
@@ -324,6 +471,10 @@
// fact a 1-byte TOC with a 1-byte payload. That will be erroneously
// interpreted as comfort noise output, but such a payload is probably
// faulty anyway.
+
+ // TODO(webrtc:10218): This is wrong for multistream opus. Then are several
+ // single-stream packets glued together with some packet size bytes in
+ // between. See https://tools.ietf.org/html/rfc6716#appendix-B
inst->in_dtx_mode = 1;
return 2; // Comfort noise.
} else {
@@ -338,8 +489,15 @@
static int DecodeNative(OpusDecInst* inst, const uint8_t* encoded,
size_t encoded_bytes, int frame_size,
int16_t* decoded, int16_t* audio_type, int decode_fec) {
- int res = opus_decode(inst->decoder, encoded, (opus_int32)encoded_bytes,
- (opus_int16*)decoded, frame_size, decode_fec);
+ int res = -1;
+ if (inst->channels <= 2) {
+ res = opus_decode(inst->decoder.decoder, encoded, (opus_int32)encoded_bytes,
+ (opus_int16*)decoded, frame_size, decode_fec);
+ } else {
+ res = opus_multistream_decode(
+ inst->decoder.multistream_decoder, encoded, (opus_int32)encoded_bytes,
+ (opus_int16*)decoded, frame_size, decode_fec);
+ }
if (res <= 0)
return -1;
diff --git a/modules/audio_coding/codecs/opus/opus_interface.h b/modules/audio_coding/codecs/opus/opus_interface.h
index ddb4ff9..0e97734 100644
--- a/modules/audio_coding/codecs/opus/opus_interface.h
+++ b/modules/audio_coding/codecs/opus/opus_interface.h
@@ -125,6 +125,22 @@
*/
int16_t WebRtcOpus_SetMaxPlaybackRate(OpusEncInst* inst, int32_t frequency_hz);
+/****************************************************************************
+ * WebRtcOpus_GetMaxPlaybackRate(...)
+ *
+ * Queries the maximum playback rate for encoding. If different single-stream
+ * encoders have different maximum playback rates, this function fails.
+ *
+ * Input:
+ * - inst : Encoder context.
+ * Output:
+ * - result_hz : The maximum playback rate in Hz.
+ * Return value : 0 - Success
+ * -1 - Error
+ */
+int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst,
+ int32_t* result_hz);
+
/* TODO(minyue): Check whether an API to check the FEC and the packet loss rate
* is needed. It might not be very useful since there are not many use cases and
* the caller can always maintain the states. */
diff --git a/modules/audio_coding/codecs/opus/opus_speed_test.cc b/modules/audio_coding/codecs/opus/opus_speed_test.cc
index 03b59ed..1a629a8 100644
--- a/modules/audio_coding/codecs/opus/opus_speed_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_speed_test.cc
@@ -96,17 +96,17 @@
EncodeDecode(kDurationSec); \
}
-ADD_TEST(10);
-ADD_TEST(9);
-ADD_TEST(8);
-ADD_TEST(7);
-ADD_TEST(6);
-ADD_TEST(5);
-ADD_TEST(4);
-ADD_TEST(3);
-ADD_TEST(2);
-ADD_TEST(1);
-ADD_TEST(0);
+ADD_TEST(10)
+ADD_TEST(9)
+ADD_TEST(8)
+ADD_TEST(7)
+ADD_TEST(6)
+ADD_TEST(5)
+ADD_TEST(4)
+ADD_TEST(3)
+ADD_TEST(2)
+ADD_TEST(1)
+ADD_TEST(0)
#define ADD_BANDWIDTH_TEST(bandwidth) \
TEST_P(OpusSpeedTest, OpusSetBandwidthTest##bandwidth) { \
@@ -116,11 +116,11 @@
EncodeDecode(kDurationSec); \
}
-ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_NARROWBAND);
-ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_MEDIUMBAND);
-ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_WIDEBAND);
-ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_SUPERWIDEBAND);
-ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_FULLBAND);
+ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_NARROWBAND)
+ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_MEDIUMBAND)
+ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_WIDEBAND)
+ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_SUPERWIDEBAND)
+ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_FULLBAND)
// List all test cases: (channel, bit rat, filename, extension).
const coding_param param_set[] = {
@@ -140,6 +140,8 @@
string("pcm"),
true)};
-INSTANTIATE_TEST_CASE_P(AllTest, OpusSpeedTest, ::testing::ValuesIn(param_set));
+INSTANTIATE_TEST_SUITE_P(AllTest,
+ OpusSpeedTest,
+ ::testing::ValuesIn(param_set));
} // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_unittest.cc b/modules/audio_coding/codecs/opus/opus_unittest.cc
index 034f8cd..56dfd6a 100644
--- a/modules/audio_coding/codecs/opus/opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -17,7 +17,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -27,7 +27,7 @@
using ::testing::Combine;
// Maximum number of bytes in output bitstream.
-const size_t kMaxBytes = 1000;
+const size_t kMaxBytes = 2000;
// Sample rate of Opus.
const size_t kOpusRateKhz = 48;
// Number of samples-per-channel in a 20 ms frame, sampled at 48 kHz.
@@ -86,10 +86,14 @@
void OpusTest::PrepareSpeechData(size_t channel,
int block_length_ms,
int loop_length_ms) {
+ std::map<int, std::string> channel_to_basename = {
+ {1, "audio_coding/testfile32kHz"},
+ {2, "audio_coding/teststereo32kHz"},
+ {4, "audio_coding/speech_4_channels_48k_one_second"}};
+ std::map<int, std::string> channel_to_suffix = {
+ {1, "pcm"}, {2, "pcm"}, {4, "wav"}};
const std::string file_name = webrtc::test::ResourcePath(
- (channel == 1) ? "audio_coding/testfile32kHz"
- : "audio_coding/teststereo32kHz",
- "pcm");
+ channel_to_basename[channel], channel_to_suffix[channel]);
if (loop_length_ms < block_length_ms) {
loop_length_ms = block_length_ms;
}
@@ -103,7 +107,7 @@
int32_t set) {
opus_int32 bandwidth;
EXPECT_EQ(0, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, set));
- opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_MAX_BANDWIDTH(&bandwidth));
+ EXPECT_EQ(0, WebRtcOpus_GetMaxPlaybackRate(opus_encoder_, &bandwidth));
EXPECT_EQ(expect, bandwidth);
}
@@ -354,13 +358,13 @@
// Test to see that an invalid pointer is caught.
EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(NULL, 1, 0));
// Invalid channel number.
- EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 3, 0));
+ EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 257, 0));
// Invalid applciation mode.
EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 1, 2));
EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(NULL, 1));
// Invalid channel number.
- EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 3));
+ EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 257));
}
// Test failing Free.
@@ -382,6 +386,11 @@
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
}
+#define ENCODER_CTL(inst, vargs) \
+ inst->channels <= 2 \
+ ? opus_encoder_ctl(inst->encoder.encoder, vargs) \
+ : opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs)
+
TEST_P(OpusTest, OpusEncodeDecode) {
PrepareSpeechData(channels_, 20, 20);
@@ -399,7 +408,7 @@
// Check application mode.
opus_int32 app;
- opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_APPLICATION(&app));
+ ENCODER_CTL(opus_encoder_, OPUS_GET_APPLICATION(&app));
EXPECT_EQ(application_ == 0 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO,
app);
@@ -450,6 +459,11 @@
}
TEST_P(OpusTest, OpusSetBandwidth) {
+ if (channels_ > 2) {
+ // TODO(webrtc:10217): investigate why multi-stream Opus reports
+ // narrowband when it's configured with FULLBAND.
+ return;
+ }
PrepareSpeechData(channels_, 20, 20);
int16_t audio_type;
@@ -495,7 +509,7 @@
ASSERT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
- if (channels_ == 2) {
+ if (channels_ >= 2) {
EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3));
EXPECT_EQ(0, WebRtcOpus_SetForceChannels(opus_encoder_, 2));
EXPECT_EQ(0, WebRtcOpus_SetForceChannels(opus_encoder_, 1));
@@ -568,17 +582,17 @@
opus_int32 dtx;
// DTX is off by default.
- opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
+ ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx));
EXPECT_EQ(0, dtx);
// Test to enable DTX.
EXPECT_EQ(0, WebRtcOpus_EnableDtx(opus_encoder_));
- opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
+ ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx));
EXPECT_EQ(1, dtx);
// Test to disable DTX.
EXPECT_EQ(0, WebRtcOpus_DisableDtx(opus_encoder_));
- opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
+ ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx));
EXPECT_EQ(0, dtx);
// Free memory.
@@ -592,6 +606,11 @@
}
TEST_P(OpusTest, OpusDtxOn) {
+ if (channels_ > 2) {
+ // TODO(webrtc:10218): adapt the test to the sizes and order of multi-stream
+ // DTX packets.
+ return;
+ }
TestDtxEffect(true, 10);
TestDtxEffect(true, 20);
TestDtxEffect(true, 40);
@@ -723,6 +742,12 @@
}
TEST_P(OpusTest, OpusDecodeRepacketized) {
+ if (channels_ > 2) {
+ // As per the Opus documentation
+ // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__repacketizer.html#details,
+ // multiple streams are not supported.
+ return;
+ }
constexpr size_t kPackets = 6;
PrepareSpeechData(channels_, 20, 20 * kPackets);
@@ -785,8 +810,8 @@
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
}
-INSTANTIATE_TEST_CASE_P(VariousMode,
- OpusTest,
- Combine(Values(1, 2), Values(0, 1)));
+INSTANTIATE_TEST_SUITE_P(VariousMode,
+ OpusTest,
+ Combine(Values(1, 2, 4), Values(0, 1)));
} // namespace webrtc
diff --git a/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h b/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h
index 9b478d8..0334104 100644
--- a/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h
+++ b/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h
@@ -17,7 +17,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
index 106ab16..9445b1e 100644
--- a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
+++ b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
@@ -10,7 +10,6 @@
#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
-#include "common_types.h"
#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
#include "rtc_base/checks.h"
@@ -30,20 +29,6 @@
return CodecType::kOther;
}
-namespace {
-
-AudioEncoderPcm16B::Config CreateConfig(const CodecInst& codec_inst) {
- AudioEncoderPcm16B::Config config;
- config.num_channels = codec_inst.channels;
- config.sample_rate_hz = codec_inst.plfreq;
- config.frame_size_ms = rtc::CheckedDivExact(
- codec_inst.pacsize, rtc::CheckedDivExact(config.sample_rate_hz, 1000));
- config.payload_type = codec_inst.pltype;
- return config;
-}
-
-} // namespace
-
bool AudioEncoderPcm16B::Config::IsOk() const {
if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) &&
(sample_rate_hz != 32000) && (sample_rate_hz != 48000))
@@ -51,7 +36,4 @@
return AudioEncoderPcm::Config::IsOk();
}
-AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst)
- : AudioEncoderPcm16B(CreateConfig(codec_inst)) {}
-
} // namespace webrtc
diff --git a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
index d6fd6e1..71c7572 100644
--- a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
+++ b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
@@ -12,12 +12,10 @@
#define MODULES_AUDIO_CODING_CODECS_PCM16B_AUDIO_ENCODER_PCM16B_H_
#include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
-struct CodecInst;
-
class AudioEncoderPcm16B final : public AudioEncoderPcm {
public:
struct Config : public AudioEncoderPcm::Config {
@@ -30,7 +28,6 @@
explicit AudioEncoderPcm16B(const Config& config)
: AudioEncoderPcm(config, config.sample_rate_hz) {}
- explicit AudioEncoderPcm16B(const CodecInst& codec_inst);
protected:
size_t EncodeCall(const int16_t* audio,
diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
index 5a68876..f05de19 100644
--- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
+++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
@@ -19,7 +19,7 @@
#include "api/array_view.h"
#include "api/audio_codecs/audio_encoder.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
index c539152..1e6b4f0 100644
--- a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
+++ b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
@@ -12,7 +12,7 @@
#include "rtc_base/format_macros.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
using ::std::get;
diff --git a/modules/audio_coding/include/audio_coding_module.h b/modules/audio_coding/include/audio_coding_module.h
index f9fdba5..7e5bf1b 100644
--- a/modules/audio_coding/include/audio_coding_module.h
+++ b/modules/audio_coding/include/audio_coding_module.h
@@ -13,12 +13,12 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "absl/types/optional.h"
#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/audio_codecs/audio_encoder.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "rtc_base/function_view.h"
@@ -27,12 +27,11 @@
namespace webrtc {
// forward declarations
-struct CodecInst;
-struct WebRtcRTPHeader;
class AudioDecoder;
class AudioEncoder;
class AudioFrame;
class RTPFragmentationHeader;
+struct RTPHeader;
#define WEBRTC_10MS_PCM_AUDIO 960 // 16 bits super wideband 48 kHz
@@ -77,80 +76,6 @@
virtual ~AudioCodingModule() = default;
///////////////////////////////////////////////////////////////////////////
- // Utility functions
- //
-
- ///////////////////////////////////////////////////////////////////////////
- // uint8_t NumberOfCodecs()
- // Returns number of supported codecs.
- //
- // Return value:
- // number of supported codecs.
- ///
- static int NumberOfCodecs();
-
- ///////////////////////////////////////////////////////////////////////////
- // int32_t Codec()
- // Get supported codec with list number.
- //
- // Input:
- // -list_id : list number.
- //
- // Output:
- // -codec : a structure where the parameters of the codec,
- // given by list number is written to.
- //
- // Return value:
- // -1 if the list number (list_id) is invalid.
- // 0 if succeeded.
- //
- static int Codec(int list_id, CodecInst* codec);
-
- ///////////////////////////////////////////////////////////////////////////
- // int32_t Codec()
- // Get supported codec with the given codec name, sampling frequency, and
- // a given number of channels.
- //
- // Input:
- // -payload_name : name of the codec.
- // -sampling_freq_hz : sampling frequency of the codec. Note! for RED
- // a sampling frequency of -1 is a valid input.
- // -channels : number of channels ( 1 - mono, 2 - stereo).
- //
- // Output:
- // -codec : a structure where the function returns the
- // default parameters of the codec.
- //
- // Return value:
- // -1 if no codec matches the given parameters.
- // 0 if succeeded.
- //
- static int Codec(const char* payload_name,
- CodecInst* codec,
- int sampling_freq_hz,
- size_t channels);
-
- ///////////////////////////////////////////////////////////////////////////
- // int32_t Codec()
- //
- // Returns the list number of the given codec name, sampling frequency, and
- // a given number of channels.
- //
- // Input:
- // -payload_name : name of the codec.
- // -sampling_freq_hz : sampling frequency of the codec. Note! for RED
- // a sampling frequency of -1 is a valid input.
- // -channels : number of channels ( 1 - mono, 2 - stereo).
- //
- // Return value:
- // if the codec is found, the index of the codec in the list,
- // -1 if the codec is not found.
- //
- static int Codec(const char* payload_name,
- int sampling_freq_hz,
- size_t channels);
-
- ///////////////////////////////////////////////////////////////////////////
// Sender
//
@@ -170,15 +95,6 @@
}
///////////////////////////////////////////////////////////////////////////
- // int32_t SendCodec()
- // Get parameters for the codec currently registered as send codec.
- //
- // Return value:
- // The send codec, or nothing if we don't have one
- //
- virtual absl::optional<CodecInst> SendCodec() const = 0;
-
- ///////////////////////////////////////////////////////////////////////////
// Sets the bitrate to the specified value in bits/sec. If the value is not
// supported by the codec, it will choose another appropriate value.
//
@@ -302,60 +218,17 @@
virtual void SetReceiveCodecs(
const std::map<int, SdpAudioFormat>& codecs) = 0;
- // Registers a decoder for the given payload type. Returns true iff
- // successful.
- virtual bool RegisterReceiveCodec(int rtp_payload_type,
- const SdpAudioFormat& audio_format) = 0;
-
- // Registers an external decoder. The name is only used to provide information
- // back to the caller about the decoder. Hence, the name is arbitrary, and may
- // be empty.
- virtual int RegisterExternalReceiveCodec(int rtp_payload_type,
- AudioDecoder* external_decoder,
- int sample_rate_hz,
- int num_channels,
- const std::string& name) = 0;
-
///////////////////////////////////////////////////////////////////////////
- // int32_t UnregisterReceiveCodec()
- // Unregister the codec currently registered with a specific payload type
- // from the list of possible receive codecs.
- //
- // Input:
- // -payload_type : The number representing the payload type to
- // unregister.
- //
- // Output:
- // -1 if fails to unregister.
- // 0 if the given codec is successfully unregistered.
- //
- virtual int UnregisterReceiveCodec(uint8_t payload_type) = 0;
-
- ///////////////////////////////////////////////////////////////////////////
- // int32_t ReceiveCodec()
- // Get the codec associated with last received payload.
- //
- // Output:
- // -curr_receive_codec : parameters of the codec associated with the last
- // received payload, c.f. common_types.h for
- // the definition of CodecInst.
+ // absl::optional<std::pair<int, SdpAudioFormat>> ReceiveCodec()
+ // Get the codec info associated with last received payload.
//
// Return value:
- // -1 if failed to retrieve the codec,
- // 0 if the codec is successfully retrieved.
- //
- virtual int32_t ReceiveCodec(CodecInst* curr_receive_codec) const = 0;
-
- ///////////////////////////////////////////////////////////////////////////
- // absl::optional<SdpAudioFormat> ReceiveFormat()
- // Get the format associated with last received payload.
- //
- // Return value:
- // An SdpAudioFormat describing the format associated with the last
- // received payload.
+ // A payload type and SdpAudioFormat describing the format associated with
+ // the last received payload.
// An empty Optional if no payload has yet been received.
//
- virtual absl::optional<SdpAudioFormat> ReceiveFormat() const = 0;
+ virtual absl::optional<std::pair<int, SdpAudioFormat>>
+ ReceiveCodec() const = 0;
///////////////////////////////////////////////////////////////////////////
// int32_t IncomingPacket()
@@ -373,7 +246,7 @@
//
virtual int32_t IncomingPacket(const uint8_t* incoming_payload,
const size_t payload_len_bytes,
- const WebRtcRTPHeader& rtp_info) = 0;
+ const RTPHeader& rtp_header) = 0;
///////////////////////////////////////////////////////////////////////////
// int SetMinimumPlayoutDelay()
@@ -402,6 +275,15 @@
//
virtual int SetMaximumPlayoutDelay(int time_ms) = 0;
+ // Sets a base minimum for the playout delay. Base minimum delay sets lower
+ // bound minimum delay value which is set via SetMinimumPlayoutDelay.
+ //
+ // Returns true if value was successfully set, false overwise.
+ virtual bool SetBaseMinimumPlayoutDelayMs(int delay_ms) = 0;
+
+ // Returns current value of base minimum delay in milliseconds.
+ virtual int GetBaseMinimumPlayoutDelayMs() const = 0;
+
///////////////////////////////////////////////////////////////////////////
// int32_t PlayoutTimestamp()
// The send timestamp of an RTP packet is associated with the decoded
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h
index bafff72..7aa7f8b 100644
--- a/modules/audio_coding/include/audio_coding_module_typedefs.h
+++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -80,6 +80,7 @@
uint64_t concealedSamples;
uint64_t concealmentEvents;
uint64_t jitterBufferDelayMs;
+ uint64_t jitterBufferEmittedCount;
// Stats below DO NOT correspond directly to anything in the WebRTC stats
// Loss rate (network + late); fraction between 0 and 1, scaled to Q14.
uint16_t currentPacketLossRate;
@@ -121,6 +122,8 @@
uint64_t packetBufferFlushes;
// number of samples expanded due to delayed packets
uint64_t delayedPacketOutageSamples;
+ // arrival delay of incoming packets
+ uint64_t relativePacketArrivalDelayMs;
};
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/accelerate.h b/modules/audio_coding/neteq/accelerate.h
index 1a3af42..124b633 100644
--- a/modules/audio_coding/neteq/accelerate.h
+++ b/modules/audio_coding/neteq/accelerate.h
@@ -15,7 +15,7 @@
#include <stdint.h>
#include "modules/audio_coding/neteq/time_stretch.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_decoder_unittest.cc b/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 1ad4835..42d96db 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -31,7 +31,7 @@
#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_multi_vector.h b/modules/audio_coding/neteq/audio_multi_vector.h
index a2dd3c3..a21bf57 100644
--- a/modules/audio_coding/neteq/audio_multi_vector.h
+++ b/modules/audio_coding/neteq/audio_multi_vector.h
@@ -17,7 +17,7 @@
#include "api/array_view.h"
#include "modules/audio_coding/neteq/audio_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
index 5b2ec20..d1351d8 100644
--- a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
+++ b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
@@ -309,9 +309,9 @@
}
}
-INSTANTIATE_TEST_CASE_P(TestNumChannels,
- AudioMultiVectorTest,
- ::testing::Values(static_cast<size_t>(1),
- static_cast<size_t>(2),
- static_cast<size_t>(5)));
+INSTANTIATE_TEST_SUITE_P(TestNumChannels,
+ AudioMultiVectorTest,
+ ::testing::Values(static_cast<size_t>(1),
+ static_cast<size_t>(2),
+ static_cast<size_t>(5)));
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/audio_vector.h b/modules/audio_coding/neteq/audio_vector.h
index d0db332..c8279da 100644
--- a/modules/audio_coding/neteq/audio_vector.h
+++ b/modules/audio_coding/neteq/audio_vector.h
@@ -16,7 +16,7 @@
#include <memory>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/background_noise.h b/modules/audio_coding/neteq/background_noise.h
index 84d7eb9..d047942 100644
--- a/modules/audio_coding/neteq/background_noise.h
+++ b/modules/audio_coding/neteq/background_noise.h
@@ -14,7 +14,7 @@
#include <string.h> // size_t
#include <memory>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/buffer_level_filter.h b/modules/audio_coding/neteq/buffer_level_filter.h
index c8d27dc..83388fb 100644
--- a/modules/audio_coding/neteq/buffer_level_filter.h
+++ b/modules/audio_coding/neteq/buffer_level_filter.h
@@ -13,7 +13,7 @@
#include <stddef.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/comfort_noise.h b/modules/audio_coding/neteq/comfort_noise.h
index 3a9bfde..f748772 100644
--- a/modules/audio_coding/neteq/comfort_noise.h
+++ b/modules/audio_coding/neteq/comfort_noise.h
@@ -13,7 +13,7 @@
#include <stddef.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc
index 83c2b3b..fda12c3 100644
--- a/modules/audio_coding/neteq/decision_logic.cc
+++ b/modules/audio_coding/neteq/decision_logic.cc
@@ -23,34 +23,10 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "system_wrappers/include/field_trial.h"
namespace {
-constexpr char kPostponeDecodingFieldTrial[] =
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand";
-int GetPostponeDecodingLevel() {
- const bool enabled =
- webrtc::field_trial::IsEnabled(kPostponeDecodingFieldTrial);
- if (!enabled)
- return 0;
-
- constexpr int kDefaultPostponeDecodingLevel = 50;
- const std::string field_trial_string =
- webrtc::field_trial::FindFullName(kPostponeDecodingFieldTrial);
- int value = -1;
- if (sscanf(field_trial_string.c_str(), "Enabled-%d", &value) == 1) {
- if (value >= 0 && value <= 100) {
- return value;
- } else {
- RTC_LOG(LS_WARNING)
- << "Wrong value (" << value
- << ") for postpone decoding after expand, using default ("
- << kDefaultPostponeDecodingLevel << ")";
- }
- }
- return kDefaultPostponeDecodingLevel;
-}
+constexpr int kPostponeDecodingLevel = 50;
} // namespace
@@ -89,8 +65,7 @@
disallow_time_stretching_(disallow_time_stretching),
timescale_countdown_(
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)),
- num_consecutive_expands_(0),
- postpone_decoding_level_(GetPostponeDecodingLevel()) {
+ num_consecutive_expands_(0) {
delay_manager_->set_streaming_mode(false);
SetSampleRate(fs_hz, output_size_samples);
}
@@ -141,6 +116,7 @@
const size_t samples_left =
sync_buffer.FutureLength() - expand.overlap_length();
+ // TODO(jakobi): Use buffer span instead of num samples.
const size_t cur_size_samples =
samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length);
@@ -194,13 +170,14 @@
// if the mute factor is low enough (otherwise the expansion was short enough
// to not be noticable).
// Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1.
+ size_t current_span =
+ samples_left + packet_buffer_.GetSpanSamples(decoder_frame_length);
if ((prev_mode == kModeExpand || prev_mode == kModeCodecPlc) &&
expand.MuteFactor(0) < 16384 / 2 &&
- cur_size_samples < static_cast<size_t>(
- delay_manager_->TargetLevel() * packet_length_samples_ *
- postpone_decoding_level_ / 100) >> 8 &&
+ current_span < static_cast<size_t>(delay_manager_->TargetLevel() *
+ packet_length_samples_ *
+ kPostponeDecodingLevel / 100)>> 8 &&
!packet_buffer_.ContainsDtxOrCngPacket(decoder_database_)) {
- RTC_DCHECK(webrtc::field_trial::IsEnabled(kPostponeDecodingFieldTrial));
return kExpand;
}
diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h
index 2a53359..ad8e2cd 100644
--- a/modules/audio_coding/neteq/decision_logic.h
+++ b/modules/audio_coding/neteq/decision_logic.h
@@ -13,7 +13,7 @@
#include "modules/audio_coding/neteq/defines.h"
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -108,10 +108,6 @@
}
void set_prev_time_scale(bool value) { prev_time_scale_ = value; }
- int postpone_decoding_level_for_test() const {
- return postpone_decoding_level_;
- }
-
private:
// The value 5 sets maximum time-stretch rate to about 100 ms/s.
static const int kMinTimescaleInterval = 5;
@@ -184,7 +180,6 @@
bool disallow_time_stretching_;
std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
int num_consecutive_expands_;
- const int postpone_decoding_level_;
RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogic);
};
diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc
index 183b9c7..5c3d489 100644
--- a/modules/audio_coding/neteq/decision_logic_unittest.cc
+++ b/modules/audio_coding/neteq/decision_logic_unittest.cc
@@ -16,8 +16,8 @@
#include "modules/audio_coding/neteq/delay_manager.h"
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "modules/audio_coding/neteq/packet_buffer.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "test/field_trial.h"
#include "test/gtest.h"
#include "test/mock_audio_decoder_factory.h"
@@ -29,72 +29,18 @@
DecoderDatabase decoder_database(
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
TickTimer tick_timer;
+ StatisticsCalculator stats;
PacketBuffer packet_buffer(10, &tick_timer);
- DelayPeakDetector delay_peak_detector(&tick_timer);
- DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
+ DelayPeakDetector delay_peak_detector(&tick_timer, false);
+ auto delay_manager = DelayManager::Create(240, 0, false, &delay_peak_detector,
+ &tick_timer, &stats);
BufferLevelFilter buffer_level_filter;
DecisionLogic* logic = DecisionLogic::Create(
fs_hz, output_size_samples, false, &decoder_database, packet_buffer,
- &delay_manager, &buffer_level_filter, &tick_timer);
+ delay_manager.get(), &buffer_level_filter, &tick_timer);
delete logic;
}
-TEST(DecisionLogic, PostponeDecodingAfterExpansionSettings) {
- constexpr int kDefaultPostponeDecodingLevel = 50;
- constexpr int kFsHz = 8000;
- constexpr int kOutputSizeSamples = kFsHz / 100; // Samples per 10 ms.
- DecoderDatabase decoder_database(
- new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
- TickTimer tick_timer;
- PacketBuffer packet_buffer(10, &tick_timer);
- DelayPeakDetector delay_peak_detector(&tick_timer);
- DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
- BufferLevelFilter buffer_level_filter;
- {
- test::ScopedFieldTrials field_trial(
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled/");
- DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database,
- packet_buffer, &delay_manager, &buffer_level_filter,
- &tick_timer);
- EXPECT_EQ(kDefaultPostponeDecodingLevel,
- logic.postpone_decoding_level_for_test());
- }
- {
- test::ScopedFieldTrials field_trial(
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled-65/");
- DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database,
- packet_buffer, &delay_manager, &buffer_level_filter,
- &tick_timer);
- EXPECT_EQ(65, logic.postpone_decoding_level_for_test());
- }
- {
- test::ScopedFieldTrials field_trial(
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Disabled/");
- DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database,
- packet_buffer, &delay_manager, &buffer_level_filter,
- &tick_timer);
- EXPECT_EQ(0, logic.postpone_decoding_level_for_test());
- }
- {
- test::ScopedFieldTrials field_trial(
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled--1/");
- DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database,
- packet_buffer, &delay_manager, &buffer_level_filter,
- &tick_timer);
- EXPECT_EQ(kDefaultPostponeDecodingLevel,
- logic.postpone_decoding_level_for_test());
- }
- {
- test::ScopedFieldTrials field_trial(
- "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled-101/");
- DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database,
- packet_buffer, &delay_manager, &buffer_level_filter,
- &tick_timer);
- EXPECT_EQ(kDefaultPostponeDecodingLevel,
- logic.postpone_decoding_level_for_test());
- }
-}
-
// TODO(hlundin): Write more tests.
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/decoder_database.cc b/modules/audio_coding/neteq/decoder_database.cc
index 0890beb..2049569 100644
--- a/modules/audio_coding/neteq/decoder_database.cc
+++ b/modules/audio_coding/neteq/decoder_database.cc
@@ -18,7 +18,6 @@
#include "absl/strings/match.h"
#include "api/audio_codecs/audio_decoder.h"
-#include "common_types.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/strings/audio_format_to_string.h"
@@ -44,7 +43,6 @@
audio_format_(audio_format),
codec_pair_id_(codec_pair_id),
factory_(factory),
- external_decoder_(nullptr),
cng_decoder_(CngDecoder::Create(audio_format)),
subtype_(SubtypeFromFormat(audio_format)) {}
@@ -54,48 +52,14 @@
AudioDecoderFactory* factory)
: DecoderInfo(audio_format, codec_pair_id, factory, audio_format.name) {}
-DecoderDatabase::DecoderInfo::DecoderInfo(
- NetEqDecoder ct,
- absl::optional<AudioCodecPairId> codec_pair_id,
- AudioDecoderFactory* factory)
- : DecoderInfo(*NetEqDecoderToSdpAudioFormat(ct), codec_pair_id, factory) {}
-
-DecoderDatabase::DecoderInfo::DecoderInfo(const SdpAudioFormat& audio_format,
- AudioDecoder* ext_dec,
- const std::string& codec_name)
- : name_(codec_name),
- audio_format_(audio_format),
- codec_pair_id_(absl::nullopt),
- factory_(nullptr),
- external_decoder_(ext_dec),
- subtype_(Subtype::kNormal) {
- RTC_CHECK(ext_dec);
-}
-
DecoderDatabase::DecoderInfo::DecoderInfo(DecoderInfo&&) = default;
DecoderDatabase::DecoderInfo::~DecoderInfo() = default;
-bool DecoderDatabase::DecoderInfo::CanGetDecoder() const {
- if (subtype_ == Subtype::kNormal && !external_decoder_ && !decoder_) {
- // TODO(ossu): Keep a check here for now, since a number of tests create
- // DecoderInfos without factories.
- RTC_DCHECK(factory_);
- return factory_->IsSupportedDecoder(audio_format_);
- } else {
- return true;
- }
-}
-
AudioDecoder* DecoderDatabase::DecoderInfo::GetDecoder() const {
if (subtype_ != Subtype::kNormal) {
// These are handled internally, so they have no AudioDecoder objects.
return nullptr;
}
- if (external_decoder_) {
- RTC_DCHECK(!decoder_);
- RTC_DCHECK(!cng_decoder_);
- return external_decoder_;
- }
if (!decoder_) {
// TODO(ossu): Keep a check here for now, since a number of tests create
// DecoderInfos without factories.
@@ -187,32 +151,6 @@
return changed_payload_types;
}
-int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& name) {
- if (rtp_payload_type > 0x7F) {
- return kInvalidRtpPayloadType;
- }
- if (codec_type == NetEqDecoder::kDecoderArbitrary) {
- return kCodecNotSupported; // Only supported through InsertExternal.
- }
- const auto opt_format = NetEqDecoderToSdpAudioFormat(codec_type);
- if (!opt_format) {
- return kCodecNotSupported;
- }
- DecoderInfo info(*opt_format, codec_pair_id_, decoder_factory_, name);
- if (!info.CanGetDecoder()) {
- return kCodecNotSupported;
- }
- auto ret =
- decoders_.insert(std::make_pair(rtp_payload_type, std::move(info)));
- if (ret.second == false) {
- // Database already contains a decoder with type |rtp_payload_type|.
- return kDecoderExists;
- }
- return kOK;
-}
-
int DecoderDatabase::RegisterPayload(int rtp_payload_type,
const SdpAudioFormat& audio_format) {
if (rtp_payload_type < 0 || rtp_payload_type > 0x7f) {
@@ -228,31 +166,6 @@
return kOK;
}
-int DecoderDatabase::InsertExternal(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& codec_name,
- AudioDecoder* decoder) {
- if (rtp_payload_type > 0x7F) {
- return kInvalidRtpPayloadType;
- }
- if (!decoder) {
- return kInvalidPointer;
- }
-
- const auto opt_db_format = NetEqDecoderToSdpAudioFormat(codec_type);
- const SdpAudioFormat format =
- opt_db_format.value_or(SdpAudioFormat("arbitrary", 0, 0));
-
- std::pair<DecoderMap::iterator, bool> ret;
- DecoderInfo info(format, decoder, codec_name);
- ret = decoders_.insert(std::make_pair(rtp_payload_type, std::move(info)));
- if (ret.second == false) {
- // Database already contains a decoder with type |rtp_payload_type|.
- return kDecoderExists;
- }
- return kOK;
-}
-
int DecoderDatabase::Remove(uint8_t rtp_payload_type) {
if (decoders_.erase(rtp_payload_type) == 0) {
// No decoder with that |rtp_payload_type|.
diff --git a/modules/audio_coding/neteq/decoder_database.h b/modules/audio_coding/neteq/decoder_database.h
index 131e769..e0a3fe3 100644
--- a/modules/audio_coding/neteq/decoder_database.h
+++ b/modules/audio_coding/neteq/decoder_database.h
@@ -17,12 +17,10 @@
#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/audio_codecs/audio_format.h"
-#include "common_types.h" // NOLINT(build/include) // NULL
+#include "api/scoped_refptr.h"
#include "modules/audio_coding/codecs/cng/webrtc_cng.h"
-#include "modules/audio_coding/neteq/neteq_decoder_enum.h"
#include "modules/audio_coding/neteq/packet.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -48,19 +46,9 @@
explicit DecoderInfo(const SdpAudioFormat& audio_format,
absl::optional<AudioCodecPairId> codec_pair_id,
AudioDecoderFactory* factory = nullptr);
- explicit DecoderInfo(NetEqDecoder ct,
- absl::optional<AudioCodecPairId> codec_pair_id,
- AudioDecoderFactory* factory = nullptr);
- DecoderInfo(const SdpAudioFormat& audio_format,
- AudioDecoder* ext_dec,
- const std::string& codec_name);
DecoderInfo(DecoderInfo&&);
~DecoderInfo();
- // Was this info object created with a specification that allows us to
- // actually produce a decoder?
- bool CanGetDecoder() const;
-
// Get the AudioDecoder object, creating it first if necessary.
AudioDecoder* GetDecoder() const;
@@ -110,9 +98,6 @@
AudioDecoderFactory* const factory_;
mutable std::unique_ptr<AudioDecoder> decoder_;
- // Set iff this is an external decoder.
- AudioDecoder* const external_decoder_;
-
// Set iff this is a comfort noise decoder.
struct CngDecoder {
static absl::optional<CngDecoder> Create(const SdpAudioFormat& format);
@@ -153,26 +138,11 @@
virtual std::vector<int> SetCodecs(
const std::map<int, SdpAudioFormat>& codecs);
- // Registers |rtp_payload_type| as a decoder of type |codec_type|. The |name|
- // is only used to populate the name field in the DecoderInfo struct in the
- // database, and can be arbitrary (including empty). Returns kOK on success;
- // otherwise an error code.
- virtual int RegisterPayload(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& name);
-
// Registers a decoder for the given payload type. Returns kOK on success;
// otherwise an error code.
virtual int RegisterPayload(int rtp_payload_type,
const SdpAudioFormat& audio_format);
- // Registers an externally created AudioDecoder object, and associates it
- // as a decoder of type |codec_type| with |rtp_payload_type|.
- virtual int InsertExternal(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& codec_name,
- AudioDecoder* decoder);
-
// Removes the entry for |rtp_payload_type| from the database.
// Returns kDecoderNotFound or kOK depending on the outcome of the operation.
virtual int Remove(uint8_t rtp_payload_type);
diff --git a/modules/audio_coding/neteq/decoder_database_unittest.cc b/modules/audio_coding/neteq/decoder_database_unittest.cc
index 3c49faa..9a28cac 100644
--- a/modules/audio_coding/neteq/decoder_database_unittest.cc
+++ b/modules/audio_coding/neteq/decoder_database_unittest.cc
@@ -15,7 +15,7 @@
#include <string>
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_audio_decoder.h"
@@ -36,17 +36,12 @@
TEST(DecoderDatabase, InsertAndRemove) {
rtc::scoped_refptr<MockAudioDecoderFactory> factory(
new rtc::RefCountedObject<MockAudioDecoderFactory>);
- EXPECT_CALL(*factory, IsSupportedDecoder(_))
- .WillOnce(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcmu", format.name);
- return true;
- }));
DecoderDatabase db(factory, absl::nullopt);
const uint8_t kPayloadType = 0;
const std::string kCodecName = "Robert\'); DROP TABLE Students;";
EXPECT_EQ(
DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCMu, kCodecName));
+ db.RegisterPayload(kPayloadType, SdpAudioFormat(kCodecName, 8000, 1)));
EXPECT_EQ(1, db.Size());
EXPECT_FALSE(db.Empty());
EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
@@ -57,22 +52,13 @@
TEST(DecoderDatabase, InsertAndRemoveAll) {
rtc::scoped_refptr<MockAudioDecoderFactory> factory(
new rtc::RefCountedObject<MockAudioDecoderFactory>);
- EXPECT_CALL(*factory, IsSupportedDecoder(_))
- .WillOnce(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcmu", format.name);
- return true;
- }))
- .WillOnce(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcma", format.name);
- return true;
- }));
DecoderDatabase db(factory, absl::nullopt);
const std::string kCodecName1 = "Robert\'); DROP TABLE Students;";
const std::string kCodecName2 = "https://xkcd.com/327/";
EXPECT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(0, NetEqDecoder::kDecoderPCMu, kCodecName1));
+ db.RegisterPayload(0, SdpAudioFormat(kCodecName1, 8000, 1)));
EXPECT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(1, NetEqDecoder::kDecoderPCMa, kCodecName2));
+ db.RegisterPayload(1, SdpAudioFormat(kCodecName2, 8000, 1)));
EXPECT_EQ(2, db.Size());
EXPECT_FALSE(db.Empty());
db.RemoveAll();
@@ -83,11 +69,6 @@
TEST(DecoderDatabase, GetDecoderInfo) {
rtc::scoped_refptr<MockAudioDecoderFactory> factory(
new rtc::RefCountedObject<MockAudioDecoderFactory>);
- EXPECT_CALL(*factory, IsSupportedDecoder(_))
- .WillOnce(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcmu", format.name);
- return true;
- }));
auto* decoder = new MockAudioDecoder;
EXPECT_CALL(*factory, MakeAudioDecoderMock(_, _, _))
.WillOnce(Invoke([decoder](const SdpAudioFormat& format,
@@ -98,10 +79,10 @@
}));
DecoderDatabase db(factory, absl::nullopt);
const uint8_t kPayloadType = 0;
- const std::string kCodecName = "Robert\'); DROP TABLE Students;";
+ const std::string kCodecName = "pcmu";
EXPECT_EQ(
DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCMu, kCodecName));
+ db.RegisterPayload(kPayloadType, SdpAudioFormat(kCodecName, 8000, 1)));
const DecoderDatabase::DecoderInfo* info;
info = db.GetDecoderInfo(kPayloadType);
ASSERT_TRUE(info != NULL);
@@ -115,10 +96,8 @@
TEST(DecoderDatabase, GetDecoder) {
DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt);
const uint8_t kPayloadType = 0;
- const std::string kCodecName = "Robert\'); DROP TABLE Students;";
EXPECT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCM16B,
- kCodecName));
+ db.RegisterPayload(kPayloadType, SdpAudioFormat("l16", 8000, 1)));
AudioDecoder* dec = db.GetDecoder(kPayloadType);
ASSERT_TRUE(dec != NULL);
}
@@ -126,11 +105,6 @@
TEST(DecoderDatabase, TypeTests) {
rtc::scoped_refptr<MockAudioDecoderFactory> factory(
new rtc::RefCountedObject<MockAudioDecoderFactory>);
- EXPECT_CALL(*factory, IsSupportedDecoder(_))
- .WillOnce(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcmu", format.name);
- return true;
- }));
DecoderDatabase db(factory, absl::nullopt);
const uint8_t kPayloadTypePcmU = 0;
const uint8_t kPayloadTypeCng = 13;
@@ -140,16 +114,15 @@
// Load into database.
EXPECT_EQ(
DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadTypePcmU, NetEqDecoder::kDecoderPCMu, "pcmu"));
+ db.RegisterPayload(kPayloadTypePcmU, SdpAudioFormat("pcmu", 8000, 1)));
EXPECT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadTypeCng, NetEqDecoder::kDecoderCNGnb,
- "cng-nb"));
+ db.RegisterPayload(kPayloadTypeCng, SdpAudioFormat("cn", 8000, 1)));
+ EXPECT_EQ(DecoderDatabase::kOK,
+ db.RegisterPayload(kPayloadTypeDtmf,
+ SdpAudioFormat("telephone-event", 8000, 1)));
EXPECT_EQ(
DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadTypeDtmf, NetEqDecoder::kDecoderAVT, "avt"));
- EXPECT_EQ(
- DecoderDatabase::kOK,
- db.RegisterPayload(kPayloadTypeRed, NetEqDecoder::kDecoderRED, "red"));
+ db.RegisterPayload(kPayloadTypeRed, SdpAudioFormat("red", 8000, 1)));
EXPECT_EQ(4, db.Size());
// Test.
EXPECT_FALSE(db.IsComfortNoise(kPayloadNotUsed));
@@ -165,52 +138,18 @@
EXPECT_TRUE(db.IsRed(kPayloadTypeRed));
}
-TEST(DecoderDatabase, ExternalDecoder) {
- DecoderDatabase db(new rtc::RefCountedObject<MockAudioDecoderFactory>,
- absl::nullopt);
- const uint8_t kPayloadType = 0;
- const std::string kCodecName = "Robert\'); DROP TABLE Students;";
- MockAudioDecoder decoder;
- // Load into database.
- EXPECT_EQ(DecoderDatabase::kOK,
- db.InsertExternal(kPayloadType, NetEqDecoder::kDecoderPCMu,
- kCodecName, &decoder));
- EXPECT_EQ(1, db.Size());
- // Get decoder and make sure we get the external one.
- EXPECT_EQ(&decoder, db.GetDecoder(kPayloadType));
- // Get the decoder info struct and check it too.
- const DecoderDatabase::DecoderInfo* info;
- info = db.GetDecoderInfo(kPayloadType);
- ASSERT_TRUE(info != NULL);
- EXPECT_TRUE(info->IsType("pcmu"));
- EXPECT_EQ(info->get_name(), kCodecName);
- EXPECT_EQ(kCodecName, info->get_name());
- // Expect not to delete the decoder when removing it from the database, since
- // it was declared externally.
- EXPECT_CALL(decoder, Die()).Times(0);
- EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType));
- EXPECT_TRUE(db.Empty());
-
- EXPECT_CALL(decoder, Die()).Times(1); // Will be called when |db| is deleted.
-}
-
TEST(DecoderDatabase, CheckPayloadTypes) {
constexpr int kNumPayloads = 10;
rtc::scoped_refptr<MockAudioDecoderFactory> factory(
new rtc::RefCountedObject<MockAudioDecoderFactory>);
- EXPECT_CALL(*factory, IsSupportedDecoder(_))
- .Times(kNumPayloads)
- .WillRepeatedly(Invoke([](const SdpAudioFormat& format) {
- EXPECT_EQ("pcmu", format.name);
- return true;
- }));
DecoderDatabase db(factory, absl::nullopt);
// Load a number of payloads into the database. Payload types are 0, 1, ...,
// while the decoder type is the same for all payload types (this does not
// matter for the test).
for (uint8_t payload_type = 0; payload_type < kNumPayloads; ++payload_type) {
- EXPECT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(payload_type, NetEqDecoder::kDecoderPCMu, ""));
+ EXPECT_EQ(
+ DecoderDatabase::kOK,
+ db.RegisterPayload(payload_type, SdpAudioFormat("pcmu", 8000, 1)));
}
PacketList packet_list;
for (int i = 0; i < kNumPayloads + 1; ++i) {
@@ -247,11 +186,11 @@
DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt);
// Load payload types.
ASSERT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(0, NetEqDecoder::kDecoderPCMu, "pcmu"));
+ db.RegisterPayload(0, SdpAudioFormat("pcmu", 8000, 1)));
ASSERT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(103, NetEqDecoder::kDecoderISAC, "isac"));
+ db.RegisterPayload(103, SdpAudioFormat("isac", 16000, 1)));
ASSERT_EQ(DecoderDatabase::kOK,
- db.RegisterPayload(13, NetEqDecoder::kDecoderCNGnb, "cng-nb"));
+ db.RegisterPayload(13, SdpAudioFormat("cn", 8000, 1)));
// Verify that no decoders are active from the start.
EXPECT_EQ(NULL, db.GetActiveDecoder());
EXPECT_EQ(NULL, db.GetActiveCngDecoder());
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index 67e6a13..4e2f3c7 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -17,23 +17,39 @@
#include <numeric>
#include <string>
+#include "absl/memory/memory.h"
#include "modules/audio_coding/neteq/delay_peak_detector.h"
+#include "modules/audio_coding/neteq/histogram.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/include/module_common_types_public.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/numerics/safe_minmax.h"
#include "system_wrappers/include/field_trial.h"
namespace {
-constexpr int kLimitProbability = 53687091; // 1/20 in Q30.
-constexpr int kLimitProbabilityStreaming = 536871; // 1/2000 in Q30.
-constexpr int kMaxStreamingPeakPeriodMs = 600000; // 10 minutes in ms.
+constexpr int kLimitProbability = 1020054733; // 19/20 in Q30.
+constexpr int kLimitProbabilityStreaming = 1073204953; // 1999/2000 in Q30.
+constexpr int kMaxStreamingPeakPeriodMs = 600000; // 10 minutes in ms.
constexpr int kCumulativeSumDrift = 2; // Drift term for cumulative sum
// |iat_cumulative_sum_|.
-// Steady-state forgetting factor for |iat_vector_|, 0.9993 in Q15.
-constexpr int kIatFactor_ = 32745;
-constexpr int kMaxIat = 64; // Max inter-arrival time to register.
+constexpr int kMinBaseMinimumDelayMs = 0;
+constexpr int kMaxBaseMinimumDelayMs = 10000;
+constexpr int kIatFactor = 32745; // 0.9993 in Q15.
+constexpr int kMaxIat = 64; // Max inter-arrival time to register.
+constexpr int kMaxReorderedPackets =
+ 10; // Max number of consecutive reordered packets.
+constexpr int kMaxHistoryPackets =
+ 100; // Max number of packets used to calculate relative packet arrival
+ // delay.
+constexpr int kDelayBuckets = 100;
+constexpr int kBucketSizeMs = 20;
+
+int PercentileToQuantile(double percentile) {
+ return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5);
+}
absl::optional<int> GetForcedLimitProbability() {
constexpr char kForceTargetDelayPercentileFieldTrial[] =
@@ -46,8 +62,8 @@
double percentile = -1.0;
if (sscanf(field_trial_string.c_str(), "Enabled-%lf", &percentile) == 1 &&
percentile >= 0.0 && percentile <= 100.0) {
- return absl::make_optional<int>(static_cast<int>(
- (1 << 30) * (100.0 - percentile) / 100.0 + 0.5)); // in Q30.
+ return absl::make_optional<int>(
+ PercentileToQuantile(percentile)); // in Q30.
} else {
RTC_LOG(LS_WARNING) << "Invalid parameter for "
<< kForceTargetDelayPercentileFieldTrial
@@ -57,64 +73,111 @@
return absl::nullopt;
}
+struct DelayHistogramConfig {
+ int quantile = 1020054733; // 0.95 in Q30.
+ int forget_factor = 32745; // 0.9993 in Q15.
+};
+
+absl::optional<DelayHistogramConfig> GetDelayHistogramConfig() {
+ constexpr char kDelayHistogramFieldTrial[] =
+ "WebRTC-Audio-NetEqDelayHistogram";
+ const bool use_new_delay_manager =
+ webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial);
+ if (use_new_delay_manager) {
+ const auto field_trial_string =
+ webrtc::field_trial::FindFullName(kDelayHistogramFieldTrial);
+ DelayHistogramConfig config;
+ double percentile = -1.0;
+ double forget_factor = -1.0;
+ if (sscanf(field_trial_string.c_str(), "Enabled-%lf-%lf", &percentile,
+ &forget_factor) == 2 &&
+ percentile >= 0.0 && percentile <= 100.0 && forget_factor >= 0.0 &&
+ forget_factor <= 1.0) {
+ config.quantile = PercentileToQuantile(percentile);
+ config.forget_factor = (1 << 15) * forget_factor;
+ }
+ RTC_LOG(LS_INFO) << "Delay histogram config:"
+ << " quantile=" << config.quantile
+ << " forget_factor=" << config.forget_factor;
+ return absl::make_optional(config);
+ }
+ return absl::nullopt;
+}
+
} // namespace
namespace webrtc {
DelayManager::DelayManager(size_t max_packets_in_buffer,
- int base_min_target_delay_ms,
+ int base_minimum_delay_ms,
+ int histogram_quantile,
+ HistogramMode histogram_mode,
+ bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
- const TickTimer* tick_timer)
+ const TickTimer* tick_timer,
+ StatisticsCalculator* statistics,
+ std::unique_ptr<Histogram> histogram)
: first_packet_received_(false),
max_packets_in_buffer_(max_packets_in_buffer),
- iat_vector_(kMaxIat + 1, 0),
- iat_factor_(0),
+ histogram_(std::move(histogram)),
+ histogram_quantile_(histogram_quantile),
+ histogram_mode_(histogram_mode),
tick_timer_(tick_timer),
- base_min_target_delay_ms_(base_min_target_delay_ms),
+ statistics_(statistics),
+ base_minimum_delay_ms_(base_minimum_delay_ms),
+ effective_minimum_delay_ms_(base_minimum_delay_ms),
base_target_level_(4), // In Q0 domain.
target_level_(base_target_level_ << 8), // In Q8 domain.
packet_len_ms_(0),
streaming_mode_(false),
last_seq_no_(0),
last_timestamp_(0),
- minimum_delay_ms_(base_min_target_delay_ms_),
- maximum_delay_ms_(target_level_),
+ minimum_delay_ms_(0),
+ maximum_delay_ms_(0),
iat_cumulative_sum_(0),
max_iat_cumulative_sum_(0),
peak_detector_(*peak_detector),
last_pack_cng_or_dtmf_(1),
frame_length_change_experiment_(
field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")),
- forced_limit_probability_(GetForcedLimitProbability()) {
+ enable_rtx_handling_(enable_rtx_handling) {
assert(peak_detector); // Should never be NULL.
- RTC_DCHECK_GE(base_min_target_delay_ms_, 0);
- RTC_DCHECK_LE(minimum_delay_ms_, maximum_delay_ms_);
+ RTC_CHECK(histogram_);
+ RTC_DCHECK_GE(base_minimum_delay_ms_, 0);
Reset();
}
-DelayManager::~DelayManager() {}
-
-const DelayManager::IATVector& DelayManager::iat_vector() const {
- return iat_vector_;
-}
-
-// Set the histogram vector to an exponentially decaying distribution
-// iat_vector_[i] = 0.5^(i+1), i = 0, 1, 2, ...
-// iat_vector_ is in Q30.
-void DelayManager::ResetHistogram() {
- // Set temp_prob to (slightly more than) 1 in Q14. This ensures that the sum
- // of iat_vector_ is 1.
- uint16_t temp_prob = 0x4002; // 16384 + 2 = 100000000000010 binary.
- IATVector::iterator it = iat_vector_.begin();
- for (; it < iat_vector_.end(); it++) {
- temp_prob >>= 1;
- (*it) = temp_prob << 16;
+std::unique_ptr<DelayManager> DelayManager::Create(
+ size_t max_packets_in_buffer,
+ int base_minimum_delay_ms,
+ bool enable_rtx_handling,
+ DelayPeakDetector* peak_detector,
+ const TickTimer* tick_timer,
+ StatisticsCalculator* statistics) {
+ int quantile;
+ std::unique_ptr<Histogram> histogram;
+ HistogramMode mode;
+ auto delay_histogram_config = GetDelayHistogramConfig();
+ if (delay_histogram_config) {
+ DelayHistogramConfig config = delay_histogram_config.value();
+ quantile = config.quantile;
+ histogram =
+ absl::make_unique<Histogram>(kDelayBuckets, config.forget_factor);
+ mode = RELATIVE_ARRIVAL_DELAY;
+ } else {
+ quantile = GetForcedLimitProbability().value_or(kLimitProbability);
+ histogram = absl::make_unique<Histogram>(kMaxIat + 1, kIatFactor);
+ mode = INTER_ARRIVAL_TIME;
}
- base_target_level_ = 4;
- target_level_ = base_target_level_ << 8;
+ return absl::make_unique<DelayManager>(
+ max_packets_in_buffer, base_minimum_delay_ms, quantile, mode,
+ enable_rtx_handling, peak_detector, tick_timer, statistics,
+ std::move(histogram));
}
+DelayManager::~DelayManager() {}
+
int DelayManager::Update(uint16_t sequence_number,
uint32_t timestamp,
int sample_rate_hz) {
@@ -146,34 +209,62 @@
rtc::saturated_cast<int>(1000 * packet_len_samp / sample_rate_hz);
}
+ bool reordered = false;
if (packet_len_ms > 0) {
// Cannot update statistics unless |packet_len_ms| is valid.
- // Calculate inter-arrival time (IAT) in integer "packet times"
- // (rounding down). This is the value used as index to the histogram
- // vector |iat_vector_|.
- int iat_packets = packet_iat_stopwatch_->ElapsedMs() / packet_len_ms;
-
if (streaming_mode_) {
UpdateCumulativeSums(packet_len_ms, sequence_number);
}
+ // Inter-arrival time (IAT) in integer "packet times" (rounding down). This
+ // is the value added to the inter-arrival time histogram.
+ int iat_ms = packet_iat_stopwatch_->ElapsedMs();
+ int iat_packets = iat_ms / packet_len_ms;
// Check for discontinuous packet sequence and re-ordering.
if (IsNewerSequenceNumber(sequence_number, last_seq_no_ + 1)) {
// Compensate for gap in the sequence numbers. Reduce IAT with the
- // expected extra time due to lost packets, but ensure that the IAT is
- // not negative.
- iat_packets -= static_cast<uint16_t>(sequence_number - last_seq_no_ - 1);
- iat_packets = std::max(iat_packets, 0);
+ // expected extra time due to lost packets.
+ int packet_offset =
+ static_cast<uint16_t>(sequence_number - last_seq_no_ - 1);
+ iat_packets -= packet_offset;
+ iat_ms -= packet_offset * packet_len_ms;
} else if (!IsNewerSequenceNumber(sequence_number, last_seq_no_)) {
- iat_packets += static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number);
+ int packet_offset =
+ static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number);
+ iat_packets += packet_offset;
+ iat_ms += packet_offset * packet_len_ms;
+ reordered = true;
}
- // Saturate IAT at maximum value.
- const int max_iat = kMaxIat;
- iat_packets = std::min(iat_packets, max_iat);
- UpdateHistogram(iat_packets);
+ int iat_delay = iat_ms - packet_len_ms;
+ int relative_delay;
+ if (reordered) {
+ relative_delay = std::max(iat_delay, 0);
+ } else {
+ UpdateDelayHistory(iat_delay);
+ relative_delay = CalculateRelativePacketArrivalDelay();
+ }
+ statistics_->RelativePacketArrivalDelay(relative_delay);
+
+ switch (histogram_mode_) {
+ case RELATIVE_ARRIVAL_DELAY: {
+ const int index = relative_delay / kBucketSizeMs;
+ if (index < histogram_->NumBuckets()) {
+ // Maximum delay to register is 2000 ms.
+ histogram_->Add(index);
+ }
+ break;
+ }
+ case INTER_ARRIVAL_TIME: {
+ // Saturate IAT between 0 and maximum value.
+ iat_packets =
+ std::max(std::min(iat_packets, histogram_->NumBuckets() - 1), 0);
+ histogram_->Add(iat_packets);
+ break;
+ }
+ }
// Calculate new |target_level_| based on updated statistics.
- target_level_ = CalculateTargetLevel(iat_packets);
+ target_level_ = CalculateTargetLevel(iat_packets, reordered);
if (streaming_mode_) {
target_level_ = std::max(target_level_, max_iat_cumulative_sum_);
}
@@ -181,6 +272,12 @@
LimitTargetLevel();
} // End if (packet_len_ms > 0).
+ if (enable_rtx_handling_ && reordered &&
+ num_reordered_packets_ < kMaxReorderedPackets) {
+ ++num_reordered_packets_;
+ return 0;
+ }
+ num_reordered_packets_ = 0;
// Prepare for next packet arrival.
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_seq_no_ = sequence_number;
@@ -188,6 +285,26 @@
return 0;
}
+void DelayManager::UpdateDelayHistory(int iat_delay) {
+ delay_history_.push_back(iat_delay);
+ if (delay_history_.size() > kMaxHistoryPackets) {
+ delay_history_.pop_front();
+ }
+}
+
+int DelayManager::CalculateRelativePacketArrivalDelay() const {
+ // This effectively calculates arrival delay of a packet relative to the
+ // packet preceding the history window. If the arrival delay ever becomes
+ // smaller than zero, it means the reference packet is invalid, and we
+ // move the reference.
+ int relative_delay = 0;
+ for (int delay : delay_history_) {
+ relative_delay += delay;
+ relative_delay = std::max(relative_delay, 0);
+ }
+ return relative_delay;
+}
+
void DelayManager::UpdateCumulativeSums(int packet_len_ms,
uint16_t sequence_number) {
// Calculate IAT in Q8, including fractions of a packet (i.e., more
@@ -214,69 +331,19 @@
}
}
-// Each element in the vector is first multiplied by the forgetting factor
-// |iat_factor_|. Then the vector element indicated by |iat_packets| is then
-// increased (additive) by 1 - |iat_factor_|. This way, the probability of
-// |iat_packets| is slightly increased, while the sum of the histogram remains
-// constant (=1).
-// Due to inaccuracies in the fixed-point arithmetic, the histogram may no
-// longer sum up to 1 (in Q30) after the update. To correct this, a correction
-// term is added or subtracted from the first element (or elements) of the
-// vector.
-// The forgetting factor |iat_factor_| is also updated. When the DelayManager
-// is reset, the factor is set to 0 to facilitate rapid convergence in the
-// beginning. With each update of the histogram, the factor is increased towards
-// the steady-state value |kIatFactor_|.
-void DelayManager::UpdateHistogram(size_t iat_packets) {
- assert(iat_packets < iat_vector_.size());
- int vector_sum = 0; // Sum up the vector elements as they are processed.
- // Multiply each element in |iat_vector_| with |iat_factor_|.
- for (IATVector::iterator it = iat_vector_.begin(); it != iat_vector_.end();
- ++it) {
- *it = (static_cast<int64_t>(*it) * iat_factor_) >> 15;
- vector_sum += *it;
- }
-
- // Increase the probability for the currently observed inter-arrival time
- // by 1 - |iat_factor_|. The factor is in Q15, |iat_vector_| in Q30.
- // Thus, left-shift 15 steps to obtain result in Q30.
- iat_vector_[iat_packets] += (32768 - iat_factor_) << 15;
- vector_sum += (32768 - iat_factor_) << 15; // Add to vector sum.
-
- // |iat_vector_| should sum up to 1 (in Q30), but it may not due to
- // fixed-point rounding errors.
- vector_sum -= 1 << 30; // Should be zero. Compensate if not.
- if (vector_sum != 0) {
- // Modify a few values early in |iat_vector_|.
- int flip_sign = vector_sum > 0 ? -1 : 1;
- IATVector::iterator it = iat_vector_.begin();
- while (it != iat_vector_.end() && abs(vector_sum) > 0) {
- // Add/subtract 1/16 of the element, but not more than |vector_sum|.
- int correction = flip_sign * std::min(abs(vector_sum), (*it) >> 4);
- *it += correction;
- vector_sum += correction;
- ++it;
- }
- }
- assert(vector_sum == 0); // Verify that the above is correct.
-
- // Update |iat_factor_| (changes only during the first seconds after a reset).
- // The factor converges to |kIatFactor_|.
- iat_factor_ += (kIatFactor_ - iat_factor_ + 3) >> 2;
-}
-
// Enforces upper and lower limits for |target_level_|. The upper limit is
// chosen to be minimum of i) 75% of |max_packets_in_buffer_|, to leave some
// headroom for natural fluctuations around the target, and ii) equivalent of
// |maximum_delay_ms_| in packets. Note that in practice, if no
// |maximum_delay_ms_| is specified, this does not have any impact, since the
// target level is far below the buffer capacity in all reasonable cases.
-// The lower limit is equivalent of |minimum_delay_ms_| in packets. We update
-// |least_required_level_| while the above limits are applied.
+// The lower limit is equivalent of |effective_minimum_delay_ms_| in packets.
+// We update |least_required_level_| while the above limits are applied.
// TODO(hlundin): Move this check to the buffer logistics class.
void DelayManager::LimitTargetLevel() {
- if (packet_len_ms_ > 0 && minimum_delay_ms_ > 0) {
- int minimum_delay_packet_q8 = (minimum_delay_ms_ << 8) / packet_len_ms_;
+ if (packet_len_ms_ > 0 && effective_minimum_delay_ms_ > 0) {
+ int minimum_delay_packet_q8 =
+ (effective_minimum_delay_ms_ << 8) / packet_len_ms_;
target_level_ = std::max(target_level_, minimum_delay_packet_q8);
}
@@ -294,40 +361,31 @@
target_level_ = std::max(target_level_, 1 << 8);
}
-int DelayManager::CalculateTargetLevel(int iat_packets) {
- int limit_probability = forced_limit_probability_.value_or(kLimitProbability);
+int DelayManager::CalculateTargetLevel(int iat_packets, bool reordered) {
+ int limit_probability = histogram_quantile_;
if (streaming_mode_) {
limit_probability = kLimitProbabilityStreaming;
}
- // Calculate target buffer level from inter-arrival time histogram.
- // Find the |iat_index| for which the probability of observing an
- // inter-arrival time larger than or equal to |iat_index| is less than or
- // equal to |limit_probability|. The sought probability is estimated using
- // the histogram as the reverse cumulant PDF, i.e., the sum of elements from
- // the end up until |iat_index|. Now, since the sum of all elements is 1
- // (in Q30) by definition, and since the solution is often a low value for
- // |iat_index|, it is more efficient to start with |sum| = 1 and subtract
- // elements from the start of the histogram.
- size_t index = 0; // Start from the beginning of |iat_vector_|.
- int sum = 1 << 30; // Assign to 1 in Q30.
- sum -= iat_vector_[index]; // Ensure that target level is >= 1.
-
- do {
- // Subtract the probabilities one by one until the sum is no longer greater
- // than limit_probability.
- ++index;
- sum -= iat_vector_[index];
- } while ((sum > limit_probability) && (index < iat_vector_.size() - 1));
-
- // This is the base value for the target buffer level.
- int target_level = static_cast<int>(index);
- base_target_level_ = static_cast<int>(index);
-
- // Update detector for delay peaks.
- bool delay_peak_found = peak_detector_.Update(iat_packets, target_level);
- if (delay_peak_found) {
- target_level = std::max(target_level, peak_detector_.MaxPeakHeight());
+ int bucket_index = histogram_->Quantile(limit_probability);
+ int target_level;
+ switch (histogram_mode_) {
+ case RELATIVE_ARRIVAL_DELAY: {
+ target_level = 1 + bucket_index * kBucketSizeMs / packet_len_ms_;
+ base_target_level_ = target_level;
+ break;
+ }
+ case INTER_ARRIVAL_TIME: {
+ target_level = bucket_index;
+ base_target_level_ = target_level;
+ // Update detector for delay peaks.
+ bool delay_peak_found =
+ peak_detector_.Update(iat_packets, reordered, target_level);
+ if (delay_peak_found) {
+ target_level = std::max(target_level, peak_detector_.MaxPeakHeight());
+ }
+ break;
+ }
}
// Sanity check. |target_level| must be strictly positive.
@@ -342,8 +400,10 @@
RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms;
return -1;
}
- if (frame_length_change_experiment_ && packet_len_ms_ != length_ms) {
- iat_vector_ = ScaleHistogram(iat_vector_, packet_len_ms_, length_ms);
+ if (histogram_mode_ == INTER_ARRIVAL_TIME &&
+ frame_length_change_experiment_ && packet_len_ms_ != length_ms &&
+ packet_len_ms_ > 0) {
+ histogram_->Scale(packet_len_ms_, length_ms);
}
packet_len_ms_ = length_ms;
@@ -357,8 +417,9 @@
packet_len_ms_ = 0; // Packet size unknown.
streaming_mode_ = false;
peak_detector_.Reset();
- ResetHistogram(); // Resets target levels too.
- iat_factor_ = 0; // Adapt the histogram faster for the first few packets.
+ histogram_->Reset();
+ base_target_level_ = 4;
+ target_level_ = base_target_level_ << 8;
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
max_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
iat_cumulative_sum_ = 0;
@@ -368,12 +429,14 @@
double DelayManager::EstimatedClockDriftPpm() const {
double sum = 0.0;
- // Calculate the expected value based on the probabilities in |iat_vector_|.
- for (size_t i = 0; i < iat_vector_.size(); ++i) {
- sum += static_cast<double>(iat_vector_[i]) * i;
+ // Calculate the expected value based on the probabilities in
+ // |histogram_|.
+ auto buckets = histogram_->buckets();
+ for (size_t i = 0; i < buckets.size(); ++i) {
+ sum += static_cast<double>(buckets[i]) * i;
}
- // The probabilities in |iat_vector_| are in Q30. Divide by 1 << 30 to convert
- // to Q0; subtract the nominal inter-arrival time (1) to make a zero
+ // The probabilities in |histogram_| are in Q30. Divide by 1 << 30 to
+ // convert to Q0; subtract the nominal inter-arrival time (1) to make a zero
// clockdrift represent as 0; mulitply by 1000000 to produce parts-per-million
// (ppm).
return (sum / (1 << 30) - 1) * 1e6;
@@ -425,87 +488,53 @@
++last_seq_no_;
}
-DelayManager::IATVector DelayManager::ScaleHistogram(const IATVector& histogram,
- int old_packet_length,
- int new_packet_length) {
- if (old_packet_length == 0) {
- // If we don't know the previous frame length, don't make any changes to the
- // histogram.
- return histogram;
- }
- RTC_DCHECK_GT(new_packet_length, 0);
- RTC_DCHECK_EQ(old_packet_length % 10, 0);
- RTC_DCHECK_EQ(new_packet_length % 10, 0);
- IATVector new_histogram(histogram.size(), 0);
- int64_t acc = 0;
- int time_counter = 0;
- size_t new_histogram_idx = 0;
- for (size_t i = 0; i < histogram.size(); i++) {
- acc += histogram[i];
- time_counter += old_packet_length;
- // The bins should be scaled, to ensure the histogram still sums to one.
- const int64_t scaled_acc = acc * new_packet_length / time_counter;
- int64_t actually_used_acc = 0;
- while (time_counter >= new_packet_length) {
- const int64_t old_histogram_val = new_histogram[new_histogram_idx];
- new_histogram[new_histogram_idx] =
- rtc::saturated_cast<int>(old_histogram_val + scaled_acc);
- actually_used_acc += new_histogram[new_histogram_idx] - old_histogram_val;
- new_histogram_idx =
- std::min(new_histogram_idx + 1, new_histogram.size() - 1);
- time_counter -= new_packet_length;
- }
- // Only subtract the part that was succesfully written to the new histogram.
- acc -= actually_used_acc;
- }
- // If there is anything left in acc (due to rounding errors), add it to the
- // last bin. If we cannot add everything to the last bin we need to add as
- // much as possible to the bins after the last bin (this is only possible
- // when compressing a histogram).
- while (acc > 0 && new_histogram_idx < new_histogram.size()) {
- const int64_t old_histogram_val = new_histogram[new_histogram_idx];
- new_histogram[new_histogram_idx] =
- rtc::saturated_cast<int>(old_histogram_val + acc);
- acc -= new_histogram[new_histogram_idx] - old_histogram_val;
- new_histogram_idx++;
- }
- RTC_DCHECK_EQ(histogram.size(), new_histogram.size());
- if (acc == 0) {
- // If acc is non-zero, we were not able to add everything to the new
- // histogram, so this check will not hold.
- RTC_DCHECK_EQ(accumulate(histogram.begin(), histogram.end(), 0ll),
- accumulate(new_histogram.begin(), new_histogram.end(), 0ll));
- }
- return new_histogram;
+bool DelayManager::IsValidMinimumDelay(int delay_ms) const {
+ return 0 <= delay_ms && delay_ms <= MinimumDelayUpperBound();
+}
+
+bool DelayManager::IsValidBaseMinimumDelay(int delay_ms) const {
+ return kMinBaseMinimumDelayMs <= delay_ms &&
+ delay_ms <= kMaxBaseMinimumDelayMs;
}
bool DelayManager::SetMinimumDelay(int delay_ms) {
- // Minimum delay shouldn't be more than maximum delay, if any maximum is set.
- // Also, if possible check |delay| to less than 75% of
- // |max_packets_in_buffer_|.
- if ((maximum_delay_ms_ > 0 && delay_ms > maximum_delay_ms_) ||
- (packet_len_ms_ > 0 &&
- delay_ms >
- static_cast<int>(3 * max_packets_in_buffer_ * packet_len_ms_ / 4))) {
+ if (!IsValidMinimumDelay(delay_ms)) {
return false;
}
- minimum_delay_ms_ = std::max(delay_ms, base_min_target_delay_ms_);
+
+ minimum_delay_ms_ = delay_ms;
+ UpdateEffectiveMinimumDelay();
return true;
}
bool DelayManager::SetMaximumDelay(int delay_ms) {
- if (delay_ms == 0) {
- // Zero input unsets the maximum delay.
- maximum_delay_ms_ = 0;
- return true;
- } else if (delay_ms < minimum_delay_ms_ || delay_ms < packet_len_ms_) {
+ // If |delay_ms| is zero then it unsets the maximum delay and target level is
+ // unconstrained by maximum delay.
+ if (delay_ms != 0 &&
+ (delay_ms < minimum_delay_ms_ || delay_ms < packet_len_ms_)) {
// Maximum delay shouldn't be less than minimum delay or less than a packet.
return false;
}
+
maximum_delay_ms_ = delay_ms;
+ UpdateEffectiveMinimumDelay();
return true;
}
+bool DelayManager::SetBaseMinimumDelay(int delay_ms) {
+ if (!IsValidBaseMinimumDelay(delay_ms)) {
+ return false;
+ }
+
+ base_minimum_delay_ms_ = delay_ms;
+ UpdateEffectiveMinimumDelay();
+ return true;
+}
+
+int DelayManager::GetBaseMinimumDelay() const {
+ return base_minimum_delay_ms_;
+}
+
int DelayManager::base_target_level() const {
return base_target_level_;
}
@@ -519,4 +548,28 @@
void DelayManager::set_last_pack_cng_or_dtmf(int value) {
last_pack_cng_or_dtmf_ = value;
}
+
+void DelayManager::UpdateEffectiveMinimumDelay() {
+ // Clamp |base_minimum_delay_ms_| into the range which can be effectively
+ // used.
+ const int base_minimum_delay_ms =
+ rtc::SafeClamp(base_minimum_delay_ms_, 0, MinimumDelayUpperBound());
+ effective_minimum_delay_ms_ =
+ std::max(minimum_delay_ms_, base_minimum_delay_ms);
+}
+
+int DelayManager::MinimumDelayUpperBound() const {
+ // Choose the lowest possible bound discarding 0 cases which mean the value
+ // is not set and unconstrained.
+ int q75 = MaxBufferTimeQ75();
+ q75 = q75 > 0 ? q75 : kMaxBaseMinimumDelayMs;
+ const int maximum_delay_ms =
+ maximum_delay_ms_ > 0 ? maximum_delay_ms_ : kMaxBaseMinimumDelayMs;
+ return std::min(maximum_delay_ms, q75);
+}
+
+int DelayManager::MaxBufferTimeQ75() const {
+ const int max_buffer_time = max_packets_in_buffer_ * packet_len_ms_;
+ return rtc::dchecked_cast<int>(3 * max_buffer_time / 4);
+}
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h
index 2c8081b..e54e950 100644
--- a/modules/audio_coding/neteq/delay_manager.h
+++ b/modules/audio_coding/neteq/delay_manager.h
@@ -13,12 +13,14 @@
#include <string.h> // Provide access to size_t.
+#include <deque>
#include <memory>
-#include <vector>
#include "absl/types/optional.h"
+#include "modules/audio_coding/neteq/histogram.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -27,23 +29,35 @@
class DelayManager {
public:
- typedef std::vector<int> IATVector;
+ enum HistogramMode {
+ INTER_ARRIVAL_TIME,
+ RELATIVE_ARRIVAL_DELAY,
+ };
+
+ DelayManager(size_t max_packets_in_buffer,
+ int base_minimum_delay_ms,
+ int histogram_quantile,
+ HistogramMode histogram_mode,
+ bool enable_rtx_handling,
+ DelayPeakDetector* peak_detector,
+ const TickTimer* tick_timer,
+ StatisticsCalculator* statistics,
+ std::unique_ptr<Histogram> histogram);
// Create a DelayManager object. Notify the delay manager that the packet
// buffer can hold no more than |max_packets_in_buffer| packets (i.e., this
// is the number of packet slots in the buffer) and that the target delay
- // should be greater than or equal to |base_min_target_delay_ms|. Supply a
+ // should be greater than or equal to |base_minimum_delay_ms|. Supply a
// PeakDetector object to the DelayManager.
- DelayManager(size_t max_packets_in_buffer,
- int base_min_target_delay_ms,
- DelayPeakDetector* peak_detector,
- const TickTimer* tick_timer);
+ static std::unique_ptr<DelayManager> Create(size_t max_packets_in_buffer,
+ int base_minimum_delay_ms,
+ bool enable_rtx_handling,
+ DelayPeakDetector* peak_detector,
+ const TickTimer* tick_timer,
+ StatisticsCalculator* statistics);
virtual ~DelayManager();
- // Read the inter-arrival time histogram. Mainly for testing purposes.
- virtual const IATVector& iat_vector() const;
-
// Updates the delay manager with a new incoming packet, with
// |sequence_number| and |timestamp| from the RTP header. This updates the
// inter-arrival time histogram and other statistics, as well as the
@@ -57,7 +71,7 @@
// Sets target_level_ (in Q8) and returns the same value. Also calculates
// and updates base_target_level_, which is the target buffer level before
// taking delay peaks into account.
- virtual int CalculateTargetLevel(int iat_packets);
+ virtual int CalculateTargetLevel(int iat_packets, bool reordered);
// Notifies the DelayManager of how much audio data is carried in each packet.
// The method updates the DelayPeakDetector too, and resets the inter-arrival
@@ -101,53 +115,74 @@
// packet will shift the sequence numbers for the following packets.
virtual void RegisterEmptyPacket();
- // Apply compression or stretching to the IAT histogram, for a change in frame
- // size. This returns an updated histogram. This function is public for
- // testability.
- static IATVector ScaleHistogram(const IATVector& histogram,
- int old_packet_length,
- int new_packet_length);
-
// Accessors and mutators.
// Assuming |delay| is in valid range.
virtual bool SetMinimumDelay(int delay_ms);
virtual bool SetMaximumDelay(int delay_ms);
+ virtual bool SetBaseMinimumDelay(int delay_ms);
+ virtual int GetBaseMinimumDelay() const;
virtual int base_target_level() const;
virtual void set_streaming_mode(bool value);
virtual int last_pack_cng_or_dtmf() const;
virtual void set_last_pack_cng_or_dtmf(int value);
// This accessor is only intended for testing purposes.
- const absl::optional<int>& forced_limit_probability_for_test() const {
- return forced_limit_probability_;
+ int effective_minimum_delay_ms_for_test() const {
+ return effective_minimum_delay_ms_;
}
+ // This accessor is only intended for testing purposes.
+ HistogramMode histogram_mode() const { return histogram_mode_; }
+ int histogram_quantile() const { return histogram_quantile_; }
+ int histogram_forget_factor() const { return histogram_->forget_factor(); }
+
private:
- // Sets |iat_vector_| to the default start distribution and sets the
- // |base_target_level_| and |target_level_| to the corresponding values.
- void ResetHistogram();
+ // Provides value which minimum delay can't exceed based on current buffer
+ // size and given |maximum_delay_ms_|. Lower bound is a constant 0.
+ int MinimumDelayUpperBound() const;
+
+ // Provides 75% of currently possible maximum buffer size in milliseconds.
+ int MaxBufferTimeQ75() const;
+
+ // Updates |delay_history_|.
+ void UpdateDelayHistory(int iat_delay);
+
+ // Calculate relative packet arrival delay from |delay_history_|.
+ int CalculateRelativePacketArrivalDelay() const;
// Updates |iat_cumulative_sum_| and |max_iat_cumulative_sum_|. (These are
// used by the streaming mode.) This method is called by Update().
void UpdateCumulativeSums(int packet_len_ms, uint16_t sequence_number);
- // Updates the histogram |iat_vector_|. The probability for inter-arrival time
- // equal to |iat_packets| (in integer packets) is increased slightly, while
- // all other entries are decreased. This method is called by Update().
- void UpdateHistogram(size_t iat_packets);
+ // Updates |effective_minimum_delay_ms_| delay based on current
+ // |minimum_delay_ms_|, |base_minimum_delay_ms_| and |maximum_delay_ms_|
+ // and buffer size.
+ void UpdateEffectiveMinimumDelay();
// Makes sure that |target_level_| is not too large, taking
// |max_packets_in_buffer_| and |extra_delay_ms_| into account. This method is
// called by Update().
void LimitTargetLevel();
+ // Makes sure that |delay_ms| is less than maximum delay, if any maximum
+ // is set. Also, if possible check |delay_ms| to be less than 75% of
+ // |max_packets_in_buffer_|.
+ bool IsValidMinimumDelay(int delay_ms) const;
+
+ bool IsValidBaseMinimumDelay(int delay_ms) const;
+
bool first_packet_received_;
const size_t max_packets_in_buffer_; // Capacity of the packet buffer.
- IATVector iat_vector_; // Histogram of inter-arrival times.
- int iat_factor_; // Forgetting factor for updating the IAT histogram (Q15).
+ std::unique_ptr<Histogram> histogram_;
+ const int histogram_quantile_;
+ const HistogramMode histogram_mode_;
const TickTimer* tick_timer_;
- const int base_min_target_delay_ms_; // Lower bound for target_level_ and
- // minimum_delay_ms_.
+ StatisticsCalculator* statistics_;
+ int base_minimum_delay_ms_;
+ // Provides delay which is used by LimitTargetLevel as lower bound on target
+ // delay.
+ int effective_minimum_delay_ms_;
+
// Time elapsed since last packet.
std::unique_ptr<TickTimer::Stopwatch> packet_iat_stopwatch_;
int base_target_level_; // Currently preferred buffer level before peak
@@ -169,7 +204,9 @@
DelayPeakDetector& peak_detector_;
int last_pack_cng_or_dtmf_;
const bool frame_length_change_experiment_;
- const absl::optional<int> forced_limit_probability_;
+ const bool enable_rtx_handling_;
+ int num_reordered_packets_ = 0; // Number of consecutive reordered packets.
+ std::deque<int> delay_history_;
RTC_DISALLOW_COPY_AND_ASSIGN(DelayManager);
};
diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc
index 6281a15..c57f074 100644
--- a/modules/audio_coding/neteq/delay_manager_unittest.cc
+++ b/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -14,25 +14,36 @@
#include <math.h>
+#include "absl/memory/memory.h"
+#include "modules/audio_coding/neteq/histogram.h"
#include "modules/audio_coding/neteq/mock/mock_delay_peak_detector.h"
+#include "modules/audio_coding/neteq/mock/mock_histogram.h"
+#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h"
+#include "rtc_base/checks.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
+namespace {
+constexpr int kMaxNumberOfPackets = 240;
+constexpr int kMinDelayMs = 0;
+constexpr int kTimeStepMs = 10;
+constexpr int kFs = 8000;
+constexpr int kFrameSizeMs = 20;
+constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000;
+constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs;
+constexpr int kDefaultHistogramQuantile = 1020054733;
+constexpr int kMaxIat = 64;
+constexpr int kForgetFactor = 32745;
+} // namespace
+
using ::testing::Return;
using ::testing::_;
class DelayManagerTest : public ::testing::Test {
protected:
- static const int kMaxNumberOfPackets = 240;
- static const int kMinDelayMs = 0;
- static const int kTimeStepMs = 10;
- static const int kFs = 8000;
- static const int kFrameSizeMs = 20;
- static const int kTsIncrement = kFrameSizeMs * kFs / 1000;
-
DelayManagerTest();
virtual void SetUp();
virtual void TearDown();
@@ -43,13 +54,22 @@
std::unique_ptr<DelayManager> dm_;
TickTimer tick_timer_;
+ MockStatisticsCalculator stats_;
MockDelayPeakDetector detector_;
+ MockHistogram* mock_histogram_;
uint16_t seq_no_;
uint32_t ts_;
+ bool enable_rtx_handling_ = false;
+ bool use_mock_histogram_ = false;
+ DelayManager::HistogramMode histogram_mode_ =
+ DelayManager::HistogramMode::INTER_ARRIVAL_TIME;
};
DelayManagerTest::DelayManagerTest()
- : dm_(nullptr), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {}
+ : dm_(nullptr),
+ detector_(&tick_timer_, false),
+ seq_no_(0x1234),
+ ts_(0x12345678) {}
void DelayManagerTest::SetUp() {
RecreateDelayManager();
@@ -57,8 +77,18 @@
void DelayManagerTest::RecreateDelayManager() {
EXPECT_CALL(detector_, Reset()).Times(1);
- dm_.reset(new DelayManager(kMaxNumberOfPackets, kMinDelayMs, &detector_,
- &tick_timer_));
+ if (use_mock_histogram_) {
+ mock_histogram_ = new MockHistogram(kMaxIat, kForgetFactor);
+ std::unique_ptr<Histogram> histogram(mock_histogram_);
+ dm_ = absl::make_unique<DelayManager>(
+ kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile,
+ histogram_mode_, enable_rtx_handling_, &detector_, &tick_timer_,
+ &stats_, std::move(histogram));
+ } else {
+ dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs,
+ enable_rtx_handling_, &detector_, &tick_timer_,
+ &stats_);
+ }
}
void DelayManagerTest::SetPacketAudioLength(int lengt_ms) {
@@ -86,17 +116,6 @@
// object.
}
-TEST_F(DelayManagerTest, VectorInitialization) {
- const DelayManager::IATVector& vec = dm_->iat_vector();
- double sum = 0.0;
- for (size_t i = 0; i < vec.size(); i++) {
- EXPECT_NEAR(ldexp(pow(0.5, static_cast<int>(i + 1)), 30), vec[i], 65537);
- // Tolerance 65537 in Q30 corresponds to a delta of approximately 0.00006.
- sum += vec[i];
- }
- EXPECT_EQ(1 << 30, static_cast<int>(sum)); // Should be 1 in Q30.
-}
-
TEST_F(DelayManagerTest, SetPacketAudioLength) {
const int kLengthMs = 30;
// Expect DelayManager to pass on the new length to the detector object.
@@ -126,7 +145,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return false to indicate no peaks found.
- EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
InsertNextPacket();
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
EXPECT_EQ(1, dm_->base_target_level());
@@ -149,7 +168,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return false to indicate no peaks found.
- EXPECT_CALL(detector_, Update(2, 2)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(2, false, 2)).WillOnce(Return(false));
InsertNextPacket();
EXPECT_EQ(2 << 8, dm_->TargetLevel()); // In Q8.
EXPECT_EQ(2, dm_->base_target_level());
@@ -172,7 +191,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return true to indicate that peaks are found. Let the peak height be 5.
- EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(true));
+ EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(true));
EXPECT_CALL(detector_, MaxPeakHeight()).WillOnce(Return(5));
InsertNextPacket();
EXPECT_EQ(5 << 8, dm_->TargetLevel());
@@ -194,7 +213,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return false to indicate no peaks found.
- EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
InsertNextPacket();
const int kExpectedTarget = 1;
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8.
@@ -216,7 +235,7 @@
// Second packet arrival.
// Expect detector update method to be called once with inter-arrival time
// equal to |kExpectedTarget| packet. Return true to indicate peaks found.
- EXPECT_CALL(detector_, Update(kExpectedTarget, _))
+ EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(detector_, MaxPeakHeight())
.WillRepeatedly(Return(kExpectedTarget));
@@ -246,7 +265,7 @@
// Second packet arrival.
// Expect detector update method to be called once with inter-arrival time
// equal to |kExpectedTarget| packet. Return true to indicate peaks found.
- EXPECT_CALL(detector_, Update(kExpectedTarget, _))
+ EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(detector_, MaxPeakHeight())
.WillRepeatedly(Return(kExpectedTarget));
@@ -264,6 +283,236 @@
EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel());
}
+TEST_F(DelayManagerTest, BaseMinimumDelayCheckValidRange) {
+ SetPacketAudioLength(kFrameSizeMs);
+
+ // Base minimum delay should be between [0, 10000] milliseconds.
+ EXPECT_FALSE(dm_->SetBaseMinimumDelay(-1));
+ EXPECT_FALSE(dm_->SetBaseMinimumDelay(10001));
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), 0);
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(7999));
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), 7999);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMinimumDelay) {
+ SetPacketAudioLength(kFrameSizeMs);
+ constexpr int kBaseMinimumDelayMs = 100;
+ constexpr int kMinimumDelayMs = 200;
+
+ // Base minimum delay sets lower bound on minimum. That is why when base
+ // minimum delay is lower than minimum delay we use minimum delay.
+ RTC_DCHECK_LT(kBaseMinimumDelayMs, kMinimumDelayMs);
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMinimumDelay) {
+ SetPacketAudioLength(kFrameSizeMs);
+ constexpr int kBaseMinimumDelayMs = 70;
+ constexpr int kMinimumDelayMs = 30;
+
+ // Base minimum delay sets lower bound on minimum. That is why when base
+ // minimum delay is greater than minimum delay we use base minimum delay.
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs);
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kBaseMinimumDelayMs);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanBufferSize) {
+ SetPacketAudioLength(kFrameSizeMs);
+ constexpr int kBaseMinimumDelayMs = kMaxBufferSizeMs + 1;
+ constexpr int kMinimumDelayMs = 12;
+ constexpr int kMaximumDelayMs = 20;
+ constexpr int kMaxBufferSizeMsQ75 = 3 * kMaxBufferSizeMs / 4;
+
+ EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs));
+
+ // Base minimum delay is greater than minimum delay, that is why we clamp
+ // it to current the highest possible value which is maximum delay.
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs);
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaxBufferSizeMs);
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaximumDelayMs);
+ RTC_DCHECK_LT(kMaximumDelayMs, kMaxBufferSizeMsQ75);
+
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+
+ // Unset maximum value.
+ EXPECT_TRUE(dm_->SetMaximumDelay(0));
+
+ // With maximum value unset, the highest possible value now is 75% of
+ // currently possible maximum buffer size.
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMaxBufferSizeMsQ75);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMaximumDelay) {
+ SetPacketAudioLength(kFrameSizeMs);
+ constexpr int kMaximumDelayMs = 400;
+ constexpr int kBaseMinimumDelayMs = kMaximumDelayMs + 1;
+ constexpr int kMinimumDelayMs = 20;
+
+ // Base minimum delay is greater than minimum delay, that is why we clamp
+ // it to current the highest possible value which is kMaximumDelayMs.
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs);
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaximumDelayMs);
+ RTC_DCHECK_LT(kMaximumDelayMs, kMaxBufferSizeMs);
+
+ EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs));
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMaximumDelayMs);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMaxSize) {
+ SetPacketAudioLength(kFrameSizeMs);
+ constexpr int kMaximumDelayMs = 400;
+ constexpr int kBaseMinimumDelayMs = kMaximumDelayMs - 1;
+ constexpr int kMinimumDelayMs = 20;
+
+ // Base minimum delay is greater than minimum delay, and lower than maximum
+ // delays that is why it is used.
+ RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs);
+ RTC_DCHECK_LT(kBaseMinimumDelayMs, kMaximumDelayMs);
+
+ EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs));
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kBaseMinimumDelayMs);
+}
+
+TEST_F(DelayManagerTest, MinimumDelayMemorization) {
+ // Check that when we increase base minimum delay to value higher than
+ // minimum delay then minimum delay is still memorized. This allows to
+ // restore effective minimum delay to memorized minimum delay value when we
+ // decrease base minimum delay.
+ SetPacketAudioLength(kFrameSizeMs);
+
+ constexpr int kBaseMinimumDelayMsLow = 10;
+ constexpr int kMinimumDelayMs = 20;
+ constexpr int kBaseMinimumDelayMsHigh = 30;
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsLow));
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ // Minimum delay is used as it is higher than base minimum delay.
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs);
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsHigh));
+ // Base minimum delay is used as it is now higher than minimum delay.
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(),
+ kBaseMinimumDelayMsHigh);
+
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsLow));
+ // Check that minimum delay is memorized and is used again.
+ EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs);
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDelay) {
+ const int kExpectedTarget = 5;
+ const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
+ SetPacketAudioLength(kFrameSizeMs);
+ // First packet arrival.
+ InsertNextPacket();
+ // Second packet arrival.
+ // Expect detector update method to be called once with inter-arrival time
+ // equal to |kExpectedTarget| packet. Return true to indicate peaks found.
+ EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(detector_, MaxPeakHeight())
+ .WillRepeatedly(Return(kExpectedTarget));
+ IncreaseTime(kTimeIncrement);
+ InsertNextPacket();
+
+ // No limit is applied.
+ EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel());
+
+ constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2;
+ constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs;
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
+
+ IncreaseTime(kTimeIncrement);
+ InsertNextPacket();
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
+ EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel());
+}
+
+TEST_F(DelayManagerTest, BaseMinimumDealyAffectTargetLevel) {
+ const int kExpectedTarget = 5;
+ const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
+ SetPacketAudioLength(kFrameSizeMs);
+ // First packet arrival.
+ InsertNextPacket();
+ // Second packet arrival.
+ // Expect detector update method to be called once with inter-arrival time
+ // equal to |kExpectedTarget|. Return true to indicate peaks found.
+ EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(detector_, MaxPeakHeight())
+ .WillRepeatedly(Return(kExpectedTarget));
+ IncreaseTime(kTimeIncrement);
+ InsertNextPacket();
+
+ // No limit is applied.
+ EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel());
+
+ // Minimum delay is lower than base minimum delay, that is why base minimum
+ // delay is used to calculate target level.
+ constexpr int kMinimumDelayPackets = kExpectedTarget + 1;
+ constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2;
+
+ constexpr int kMinimumDelayMs = kMinimumDelayPackets * kFrameSizeMs;
+ constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs;
+
+ EXPECT_TRUE(kMinimumDelayMs < kBaseMinimumDelayMs);
+ EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs));
+ EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
+
+ IncreaseTime(kTimeIncrement);
+ InsertNextPacket();
+ EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
+ EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel());
+}
+
+TEST_F(DelayManagerTest, UpdateReorderedPacket) {
+ SetPacketAudioLength(kFrameSizeMs);
+ InsertNextPacket();
+
+ // Insert packet that was sent before the previous packet.
+ EXPECT_CALL(detector_, Update(_, true, _));
+ EXPECT_EQ(0, dm_->Update(seq_no_ - 1, ts_ - kFrameSizeMs, kFs));
+}
+
+TEST_F(DelayManagerTest, EnableRtxHandling) {
+ enable_rtx_handling_ = true;
+ use_mock_histogram_ = true;
+ RecreateDelayManager();
+ EXPECT_TRUE(mock_histogram_);
+
+ // Insert first packet.
+ SetPacketAudioLength(kFrameSizeMs);
+ InsertNextPacket();
+
+ // Insert reordered packet.
+ EXPECT_CALL(*mock_histogram_, Add(3));
+ EXPECT_EQ(0, dm_->Update(seq_no_ - 3, ts_ - 3 * kFrameSizeMs, kFs));
+
+ // Insert another reordered packet.
+ EXPECT_CALL(*mock_histogram_, Add(2));
+ EXPECT_EQ(0, dm_->Update(seq_no_ - 2, ts_ - 2 * kFrameSizeMs, kFs));
+
+ // Insert the next packet in order and verify that the inter-arrival time is
+ // estimated correctly.
+ IncreaseTime(kFrameSizeMs);
+ EXPECT_CALL(*mock_histogram_, Add(1));
+ InsertNextPacket();
+}
+
// Tests that skipped sequence numbers (simulating empty packets) are handled
// correctly.
TEST_F(DelayManagerTest, EmptyPacketsReported) {
@@ -285,7 +534,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return false to indicate no peaks found.
- EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
InsertNextPacket();
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
@@ -309,7 +558,7 @@
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet, and (base) target level equal to 1 as well.
// Return false to indicate no peaks found.
- EXPECT_CALL(detector_, Update(10, 10)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(10, false, 10)).WillOnce(Return(false));
InsertNextPacket();
// Note 10 times higher target value.
@@ -337,8 +586,7 @@
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-0/");
RecreateDelayManager();
- EXPECT_EQ(absl::make_optional<int>(1 << 30),
- dm_->forced_limit_probability_for_test());
+ EXPECT_EQ(0, dm_->histogram_quantile());
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival.
@@ -348,7 +596,7 @@
// Second packet arrival.
// Expect detector update method to be called once with inter-arrival time
// equal to 1 packet.
- EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
+ EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
InsertNextPacket();
constexpr int kExpectedTarget = 1;
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8.
@@ -359,145 +607,122 @@
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-95/");
RecreateDelayManager();
- EXPECT_EQ(absl::make_optional<int>(53687091),
- dm_->forced_limit_probability_for_test()); // 1/20 in Q30
+ EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile());
}
{
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-99.95/");
RecreateDelayManager();
- EXPECT_EQ(absl::make_optional<int>(536871),
- dm_->forced_limit_probability_for_test()); // 1/2000 in Q30
+ EXPECT_EQ(1073204953, dm_->histogram_quantile()); // 0.9995 in Q30.
}
{
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Disabled/");
RecreateDelayManager();
- EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test());
+ EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile());
}
{
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled--1/");
- EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test());
+ EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile());
}
{
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-100.1/");
RecreateDelayManager();
- EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test());
+ EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile());
}
}
-// Test if the histogram is stretched correctly if the packet size is decreased.
-TEST(DelayManagerIATScalingTest, StretchTest) {
- using IATVector = DelayManager::IATVector;
- // Test a straightforward 60ms to 20ms change.
- IATVector iat = {12, 0, 0, 0, 0, 0};
- IATVector expected_result = {4, 4, 4, 0, 0, 0};
- IATVector stretched_iat = DelayManager::ScaleHistogram(iat, 60, 20);
- EXPECT_EQ(stretched_iat, expected_result);
-
- // Test an example where the last bin in the stretched histogram should
- // contain the sum of the elements that don't fit into the new histogram.
- iat = {18, 15, 12, 9, 6, 3, 0};
- expected_result = {6, 6, 6, 5, 5, 5, 30};
- stretched_iat = DelayManager::ScaleHistogram(iat, 60, 20);
- EXPECT_EQ(stretched_iat, expected_result);
-
- // Test a 120ms to 60ms change.
- iat = {18, 16, 14, 4, 0};
- expected_result = {9, 9, 8, 8, 18};
- stretched_iat = DelayManager::ScaleHistogram(iat, 120, 60);
- EXPECT_EQ(stretched_iat, expected_result);
-
- // Test a 120ms to 20ms change.
- iat = {19, 12, 0, 0, 0, 0, 0, 0};
- expected_result = {3, 3, 3, 3, 3, 3, 2, 11};
- stretched_iat = DelayManager::ScaleHistogram(iat, 120, 20);
- EXPECT_EQ(stretched_iat, expected_result);
-
- // Test a 70ms to 40ms change.
- iat = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
- expected_result = {7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 6, 22};
- stretched_iat = DelayManager::ScaleHistogram(iat, 70, 40);
- EXPECT_EQ(stretched_iat, expected_result);
-
- // Test a 30ms to 20ms change.
- iat = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
- expected_result = {8, 6, 6, 3, 2, 2, 1, 3, 3, 8, 7, 11};
- stretched_iat = DelayManager::ScaleHistogram(iat, 30, 20);
- EXPECT_EQ(stretched_iat, expected_result);
+TEST_F(DelayManagerTest, DelayHistogramFieldTrial) {
+ {
+ test::ScopedFieldTrials field_trial(
+ "WebRTC-Audio-NetEqDelayHistogram/Enabled-96-0.998/");
+ RecreateDelayManager();
+ EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
+ dm_->histogram_mode());
+ EXPECT_EQ(1030792151, dm_->histogram_quantile()); // 0.96 in Q30.
+ EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15.
+ }
+ {
+ test::ScopedFieldTrials field_trial(
+ "WebRTC-Audio-NetEqDelayHistogram/Enabled-97.5-0.998/");
+ RecreateDelayManager();
+ EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
+ dm_->histogram_mode());
+ EXPECT_EQ(1046898278, dm_->histogram_quantile()); // 0.975 in Q30.
+ EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15.
+ }
+ {
+ // NetEqDelayHistogram should take precedence over
+ // NetEqForceTargetDelayPercentile.
+ test::ScopedFieldTrials field_trial(
+ "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-99.95/"
+ "WebRTC-Audio-NetEqDelayHistogram/Enabled-96-0.998/");
+ RecreateDelayManager();
+ EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
+ dm_->histogram_mode());
+ EXPECT_EQ(1030792151, dm_->histogram_quantile()); // 0.96 in Q30.
+ EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15.
+ }
+ {
+ // Invalid parameters.
+ test::ScopedFieldTrials field_trial(
+ "WebRTC-Audio-NetEqDelayHistogram/Enabled-96/");
+ RecreateDelayManager();
+ EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
+ dm_->histogram_mode());
+ EXPECT_EQ(kDefaultHistogramQuantile,
+ dm_->histogram_quantile()); // 0.95 in Q30.
+ EXPECT_EQ(kForgetFactor, dm_->histogram_forget_factor()); // 0.9993 in Q15.
+ }
+ {
+ test::ScopedFieldTrials field_trial(
+ "WebRTC-Audio-NetEqDelayHistogram/Disabled/");
+ RecreateDelayManager();
+ EXPECT_EQ(DelayManager::HistogramMode::INTER_ARRIVAL_TIME,
+ dm_->histogram_mode());
+ EXPECT_EQ(kDefaultHistogramQuantile,
+ dm_->histogram_quantile()); // 0.95 in Q30.
+ EXPECT_EQ(kForgetFactor, dm_->histogram_forget_factor()); // 0.9993 in Q15.
+ }
}
-// Test if the histogram is compressed correctly if the packet size is
-// increased.
-TEST(DelayManagerIATScalingTest, CompressionTest) {
- using IATVector = DelayManager::IATVector;
- // Test a 20 to 60 ms change.
- IATVector iat = {12, 11, 10, 3, 2, 1};
- IATVector expected_result = {33, 6, 0, 0, 0, 0};
- IATVector compressed_iat = DelayManager::ScaleHistogram(iat, 20, 60);
- EXPECT_EQ(compressed_iat, expected_result);
+TEST_F(DelayManagerTest, RelativeArrivalDelayMode) {
+ histogram_mode_ = DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY;
+ use_mock_histogram_ = true;
+ RecreateDelayManager();
- // Test a 60ms to 120ms change.
- iat = {18, 16, 14, 4, 1};
- expected_result = {34, 18, 1, 0, 0};
- compressed_iat = DelayManager::ScaleHistogram(iat, 60, 120);
- EXPECT_EQ(compressed_iat, expected_result);
+ SetPacketAudioLength(kFrameSizeMs);
+ InsertNextPacket();
- // Test a 20ms to 120ms change.
- iat = {18, 12, 5, 4, 4, 3, 5, 1};
- expected_result = {46, 6, 0, 0, 0, 0, 0, 0};
- compressed_iat = DelayManager::ScaleHistogram(iat, 20, 120);
- EXPECT_EQ(compressed_iat, expected_result);
+ IncreaseTime(kFrameSizeMs);
+ EXPECT_CALL(*mock_histogram_, Add(0)); // Not delayed.
+ InsertNextPacket();
- // Test a 70ms to 80ms change.
- iat = {13, 7, 5, 3, 1, 5, 12, 11, 3};
- expected_result = {11, 8, 6, 2, 5, 12, 13, 3, 0};
- compressed_iat = DelayManager::ScaleHistogram(iat, 70, 80);
- EXPECT_EQ(compressed_iat, expected_result);
+ IncreaseTime(2 * kFrameSizeMs);
+ EXPECT_CALL(*mock_histogram_, Add(1)); // 20ms delayed.
+ EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs));
- // Test a 50ms to 110ms change.
- iat = {13, 7, 5, 3, 1, 5, 12, 11, 3};
- expected_result = {18, 8, 16, 16, 2, 0, 0, 0, 0};
- compressed_iat = DelayManager::ScaleHistogram(iat, 50, 110);
- EXPECT_EQ(compressed_iat, expected_result);
+ IncreaseTime(2 * kFrameSizeMs);
+ EXPECT_CALL(*mock_histogram_, Add(2)); // 40ms delayed.
+ EXPECT_EQ(0, dm_->Update(seq_no_ + 1, ts_ + kTsIncrement, kFs));
+
+ EXPECT_CALL(*mock_histogram_, Add(1)); // Reordered, 20ms delayed.
+ EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs));
}
-// Test if the histogram scaling function handles overflows correctly.
-TEST(DelayManagerIATScalingTest, OverflowTest) {
- using IATVector = DelayManager::IATVector;
- // Test a compression operation that can cause overflow.
- IATVector iat = {733544448, 0, 0, 0, 0, 0, 0, 340197376, 0, 0, 0, 0, 0, 0};
- IATVector expected_result = {733544448, 340197376, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0};
- IATVector scaled_iat = DelayManager::ScaleHistogram(iat, 10, 60);
- EXPECT_EQ(scaled_iat, expected_result);
+TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
+ SetPacketAudioLength(kFrameSizeMs);
+ InsertNextPacket();
- iat = {655591163, 39962288, 360736736, 1930514, 4003853, 1782764,
- 114119, 2072996, 0, 2149354, 0};
- expected_result = {1056290187, 7717131, 2187115, 2149354, 0, 0,
- 0, 0, 0, 0, 0};
- scaled_iat = DelayManager::ScaleHistogram(iat, 20, 60);
- EXPECT_EQ(scaled_iat, expected_result);
+ IncreaseTime(kFrameSizeMs);
+ EXPECT_CALL(stats_, RelativePacketArrivalDelay(0));
+ InsertNextPacket();
- // In this test case we will not be able to add everything to the final bin in
- // the scaled histogram. Check that the last bin doesn't overflow.
- iat = {2000000000, 2000000000, 2000000000,
- 2000000000, 2000000000, 2000000000};
- expected_result = {666666666, 666666666, 666666666,
- 666666667, 666666667, 2147483647};
- scaled_iat = DelayManager::ScaleHistogram(iat, 60, 20);
- EXPECT_EQ(scaled_iat, expected_result);
-
- // In this test case we will not be able to add enough to each of the bins,
- // so the values should be smeared out past the end of the normal range.
- iat = {2000000000, 2000000000, 2000000000,
- 2000000000, 2000000000, 2000000000};
- expected_result = {2147483647, 2147483647, 2147483647,
- 2147483647, 2147483647, 1262581765};
- scaled_iat = DelayManager::ScaleHistogram(iat, 20, 60);
- EXPECT_EQ(scaled_iat, expected_result);
+ IncreaseTime(2 * kFrameSizeMs);
+ EXPECT_CALL(stats_, RelativePacketArrivalDelay(20));
+ InsertNextPacket();
}
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/delay_peak_detector.cc b/modules/audio_coding/neteq/delay_peak_detector.cc
index 893ce3e..5669d72 100644
--- a/modules/audio_coding/neteq/delay_peak_detector.cc
+++ b/modules/audio_coding/neteq/delay_peak_detector.cc
@@ -26,10 +26,12 @@
DelayPeakDetector::~DelayPeakDetector() = default;
-DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer)
+DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer,
+ bool ignore_reordered_packets)
: peak_found_(false),
peak_detection_threshold_(0),
tick_timer_(tick_timer),
+ ignore_reordered_packets_(ignore_reordered_packets),
frame_length_change_experiment_(
field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) {
RTC_DCHECK(!peak_period_stopwatch_);
@@ -79,7 +81,12 @@
return max_period_element->period_ms;
}
-bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
+bool DelayPeakDetector::Update(int inter_arrival_time,
+ bool reordered,
+ int target_level) {
+ if (ignore_reordered_packets_ && reordered) {
+ return CheckPeakConditions();
+ }
if (inter_arrival_time > target_level + peak_detection_threshold_ ||
inter_arrival_time > 2 * target_level) {
// A delay peak is observed.
diff --git a/modules/audio_coding/neteq/delay_peak_detector.h b/modules/audio_coding/neteq/delay_peak_detector.h
index 272d50e..8cd198d 100644
--- a/modules/audio_coding/neteq/delay_peak_detector.h
+++ b/modules/audio_coding/neteq/delay_peak_detector.h
@@ -17,13 +17,13 @@
#include <memory>
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class DelayPeakDetector {
public:
- DelayPeakDetector(const TickTimer* tick_timer);
+ DelayPeakDetector(const TickTimer* tick_timer, bool ignore_reordered_packets);
virtual ~DelayPeakDetector();
virtual void Reset();
@@ -43,10 +43,11 @@
// larger than 0), or 0 if no delay peaks have been observed recently.
virtual uint64_t MaxPeakPeriod() const;
- // Updates the DelayPeakDetector with a new inter-arrival time (in packets)
- // and the current target buffer level (needed to decide if a peak is observed
- // or not). Returns true if peak-mode is active, false if not.
- virtual bool Update(int inter_arrival_time, int target_level);
+ // Updates the DelayPeakDetector with a new inter-arrival time (in packets),
+ // the current target buffer level (needed to decide if a peak is observed or
+ // not) and if the new inter-arrival time includes a compensation for
+ // reordering. Returns true if peak-mode is active, false if not.
+ virtual bool Update(int inter_arrival_time, bool reordered, int target_level);
private:
static const size_t kMaxNumPeaks = 8;
@@ -66,6 +67,7 @@
int peak_detection_threshold_;
const TickTimer* tick_timer_;
std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_;
+ const bool ignore_reordered_packets_;
const bool frame_length_change_experiment_;
RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
diff --git a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
index fd4dded..6590dc2 100644
--- a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
+++ b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
@@ -18,14 +18,14 @@
TEST(DelayPeakDetector, CreateAndDestroy) {
TickTimer tick_timer;
- DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer);
+ DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer, false);
EXPECT_FALSE(detector->peak_found());
delete detector;
}
TEST(DelayPeakDetector, EmptyHistory) {
TickTimer tick_timer;
- DelayPeakDetector detector(&tick_timer);
+ DelayPeakDetector detector(&tick_timer, false);
EXPECT_EQ(-1, detector.MaxPeakHeight());
EXPECT_EQ(0u, detector.MaxPeakPeriod());
}
@@ -35,7 +35,7 @@
// start. This should then continue until it is disengaged due to lack of peaks.
TEST(DelayPeakDetector, TriggerPeakMode) {
TickTimer tick_timer;
- DelayPeakDetector detector(&tick_timer);
+ DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
@@ -69,9 +69,9 @@
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
const int kTargetBufferLevel = 1; // Define peaks to be iat > 2.
if (time < peak_mode_start_ms || time > peak_mode_end_ms) {
- EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
+ EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
} else {
- EXPECT_TRUE(detector.Update(iat_packets, kTargetBufferLevel));
+ EXPECT_TRUE(detector.Update(iat_packets, false, kTargetBufferLevel));
EXPECT_EQ(kWorstPeakPeriod, detector.MaxPeakPeriod());
EXPECT_EQ(kPeakDelayMs / kPacketSizeMs + 1, detector.MaxPeakHeight());
}
@@ -87,7 +87,7 @@
// The delay pattern has peaks with delay = 3, thus should not trigger.
TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
TickTimer tick_timer;
- DelayPeakDetector detector(&tick_timer);
+ DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
@@ -115,7 +115,7 @@
int iat_packets =
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
- EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
+ EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
++next;
}
tick_timer.Increment();
@@ -129,15 +129,33 @@
// problems.
TEST(DelayPeakDetector, ZeroDistancePeaks) {
TickTimer tick_timer;
- DelayPeakDetector detector(&tick_timer);
+ DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
- const int kInterArrivalTime = 3 * kTargetBufferLevel; // Will trigger a peak.
- EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
- EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
- EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
+ const int kInterArrivalTime =
+ 3 * kTargetBufferLevel; // Above peak threshold.
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+ tick_timer.Increment();
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+ // The following would fail if there were non-zero time between the updates.
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+}
+
+TEST(DelayPeakDetector, IgnoreReorderedPacket) {
+ TickTimer tick_timer;
+ DelayPeakDetector detector(&tick_timer, true);
+
+ const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
+ const int kInterArrivalTime =
+ 3 * kTargetBufferLevel; // Above peak threshold.
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+ tick_timer.Increment();
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
+ tick_timer.Increment();
+ // The following would fail if the packet was not reordered.
+ EXPECT_FALSE(detector.Update(kInterArrivalTime, true, kTargetBufferLevel));
}
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/dsp_helper.h b/modules/audio_coding/neteq/dsp_helper.h
index 8379461..82fe14e 100644
--- a/modules/audio_coding/neteq/dsp_helper.h
+++ b/modules/audio_coding/neteq/dsp_helper.h
@@ -16,7 +16,7 @@
#include "modules/audio_coding/neteq/audio_multi_vector.h"
#include "modules/audio_coding/neteq/audio_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/dtmf_buffer.h b/modules/audio_coding/neteq/dtmf_buffer.h
index 24b14ec..a994e3a 100644
--- a/modules/audio_coding/neteq/dtmf_buffer.h
+++ b/modules/audio_coding/neteq/dtmf_buffer.h
@@ -15,7 +15,7 @@
#include <stdint.h>
#include <list>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/dtmf_tone_generator.h b/modules/audio_coding/neteq/dtmf_tone_generator.h
index 22e166e..968bc7f 100644
--- a/modules/audio_coding/neteq/dtmf_tone_generator.h
+++ b/modules/audio_coding/neteq/dtmf_tone_generator.h
@@ -15,7 +15,7 @@
#include <stdint.h>
#include "modules/audio_coding/neteq/audio_multi_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand.h b/modules/audio_coding/neteq/expand.h
index 30c34a2..7c041b8 100644
--- a/modules/audio_coding/neteq/expand.h
+++ b/modules/audio_coding/neteq/expand.h
@@ -15,7 +15,7 @@
#include <memory>
#include "modules/audio_coding/neteq/audio_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand_uma_logger.h b/modules/audio_coding/neteq/expand_uma_logger.h
index bd079c6..7cb11b1 100644
--- a/modules/audio_coding/neteq/expand_uma_logger.h
+++ b/modules/audio_coding/neteq/expand_uma_logger.h
@@ -16,7 +16,7 @@
#include "absl/types/optional.h"
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand_unittest.cc b/modules/audio_coding/neteq/expand_unittest.cc
index 09914da..4c8c174 100644
--- a/modules/audio_coding/neteq/expand_unittest.cc
+++ b/modules/audio_coding/neteq/expand_unittest.cc
@@ -20,7 +20,7 @@
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/histogram.cc b/modules/audio_coding/neteq/histogram.cc
new file mode 100644
index 0000000..b8e4e52
--- /dev/null
+++ b/modules/audio_coding/neteq/histogram.cc
@@ -0,0 +1,174 @@
+/*
+ * 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 <algorithm>
+#include <numeric>
+
+#include "modules/audio_coding/neteq/histogram.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+Histogram::Histogram(size_t num_buckets, int forget_factor)
+ : buckets_(num_buckets, 0),
+ forget_factor_(0),
+ base_forget_factor_(forget_factor) {}
+
+Histogram::~Histogram() {}
+
+// Each element in the vector is first multiplied by the forgetting factor
+// |forget_factor_|. Then the vector element indicated by |iat_packets| is then
+// increased (additive) by 1 - |forget_factor_|. This way, the probability of
+// |iat_packets| is slightly increased, while the sum of the histogram remains
+// constant (=1).
+// Due to inaccuracies in the fixed-point arithmetic, the histogram may no
+// longer sum up to 1 (in Q30) after the update. To correct this, a correction
+// term is added or subtracted from the first element (or elements) of the
+// vector.
+// The forgetting factor |forget_factor_| is also updated. When the DelayManager
+// is reset, the factor is set to 0 to facilitate rapid convergence in the
+// beginning. With each update of the histogram, the factor is increased towards
+// the steady-state value |kIatFactor_|.
+void Histogram::Add(int value) {
+ RTC_DCHECK(value >= 0);
+ RTC_DCHECK(value < static_cast<int>(buckets_.size()));
+ int vector_sum = 0; // Sum up the vector elements as they are processed.
+ // Multiply each element in |buckets_| with |forget_factor_|.
+ for (int& bucket : buckets_) {
+ bucket = (static_cast<int64_t>(bucket) * forget_factor_) >> 15;
+ vector_sum += bucket;
+ }
+
+ // Increase the probability for the currently observed inter-arrival time
+ // by 1 - |forget_factor_|. The factor is in Q15, |buckets_| in Q30.
+ // Thus, left-shift 15 steps to obtain result in Q30.
+ buckets_[value] += (32768 - forget_factor_) << 15;
+ vector_sum += (32768 - forget_factor_) << 15; // Add to vector sum.
+
+ // |buckets_| should sum up to 1 (in Q30), but it may not due to
+ // fixed-point rounding errors.
+ vector_sum -= 1 << 30; // Should be zero. Compensate if not.
+ if (vector_sum != 0) {
+ // Modify a few values early in |buckets_|.
+ int flip_sign = vector_sum > 0 ? -1 : 1;
+ for (int& bucket : buckets_) {
+ // Add/subtract 1/16 of the element, but not more than |vector_sum|.
+ int correction = flip_sign * std::min(abs(vector_sum), bucket >> 4);
+ bucket += correction;
+ vector_sum += correction;
+ if (abs(vector_sum) == 0) {
+ break;
+ }
+ }
+ }
+ RTC_DCHECK(vector_sum == 0); // Verify that the above is correct.
+
+ // Update |forget_factor_| (changes only during the first seconds after a
+ // reset). The factor converges to |base_forget_factor_|.
+ forget_factor_ += (base_forget_factor_ - forget_factor_ + 3) >> 2;
+}
+
+int Histogram::Quantile(int probability) {
+ // Find the bucket for which the probability of observing an
+ // inter-arrival time larger than or equal to |index| is larger than or
+ // equal to |probability|. The sought probability is estimated using
+ // the histogram as the reverse cumulant PDF, i.e., the sum of elements from
+ // the end up until |index|. Now, since the sum of all elements is 1
+ // (in Q30) by definition, and since the solution is often a low value for
+ // |iat_index|, it is more efficient to start with |sum| = 1 and subtract
+ // elements from the start of the histogram.
+ int inverse_probability = (1 << 30) - probability;
+ size_t index = 0; // Start from the beginning of |buckets_|.
+ int sum = 1 << 30; // Assign to 1 in Q30.
+ sum -= buckets_[index]; // Ensure that target level is >= 1.
+
+ do {
+ // Subtract the probabilities one by one until the sum is no longer greater
+ // than |inverse_probability|.
+ ++index;
+ sum -= buckets_[index];
+ } while ((sum > inverse_probability) && (index < buckets_.size() - 1));
+ return static_cast<int>(index);
+}
+
+// Set the histogram vector to an exponentially decaying distribution
+// buckets_[i] = 0.5^(i+1), i = 0, 1, 2, ...
+// buckets_ is in Q30.
+void Histogram::Reset() {
+ // Set temp_prob to (slightly more than) 1 in Q14. This ensures that the sum
+ // of buckets_ is 1.
+ uint16_t temp_prob = 0x4002; // 16384 + 2 = 100000000000010 binary.
+ for (int& bucket : buckets_) {
+ temp_prob >>= 1;
+ bucket = temp_prob << 16;
+ }
+ forget_factor_ = 0; // Adapt the histogram faster for the first few packets.
+}
+
+int Histogram::NumBuckets() const {
+ return buckets_.size();
+}
+
+void Histogram::Scale(int old_bucket_width, int new_bucket_width) {
+ buckets_ = ScaleBuckets(buckets_, old_bucket_width, new_bucket_width);
+}
+
+std::vector<int> Histogram::ScaleBuckets(const std::vector<int>& buckets,
+ int old_bucket_width,
+ int new_bucket_width) {
+ RTC_DCHECK_GT(old_bucket_width, 0);
+ RTC_DCHECK_GT(new_bucket_width, 0);
+ RTC_DCHECK_EQ(old_bucket_width % 10, 0);
+ RTC_DCHECK_EQ(new_bucket_width % 10, 0);
+ std::vector<int> new_histogram(buckets.size(), 0);
+ int64_t acc = 0;
+ int time_counter = 0;
+ size_t new_histogram_idx = 0;
+ for (size_t i = 0; i < buckets.size(); i++) {
+ acc += buckets[i];
+ time_counter += old_bucket_width;
+ // The bins should be scaled, to ensure the histogram still sums to one.
+ const int64_t scaled_acc = acc * new_bucket_width / time_counter;
+ int64_t actually_used_acc = 0;
+ while (time_counter >= new_bucket_width) {
+ const int64_t old_histogram_val = new_histogram[new_histogram_idx];
+ new_histogram[new_histogram_idx] =
+ rtc::saturated_cast<int>(old_histogram_val + scaled_acc);
+ actually_used_acc += new_histogram[new_histogram_idx] - old_histogram_val;
+ new_histogram_idx =
+ std::min(new_histogram_idx + 1, new_histogram.size() - 1);
+ time_counter -= new_bucket_width;
+ }
+ // Only subtract the part that was succesfully written to the new histogram.
+ acc -= actually_used_acc;
+ }
+ // If there is anything left in acc (due to rounding errors), add it to the
+ // last bin. If we cannot add everything to the last bin we need to add as
+ // much as possible to the bins after the last bin (this is only possible
+ // when compressing a histogram).
+ while (acc > 0 && new_histogram_idx < new_histogram.size()) {
+ const int64_t old_histogram_val = new_histogram[new_histogram_idx];
+ new_histogram[new_histogram_idx] =
+ rtc::saturated_cast<int>(old_histogram_val + acc);
+ acc -= new_histogram[new_histogram_idx] - old_histogram_val;
+ new_histogram_idx++;
+ }
+ RTC_DCHECK_EQ(buckets.size(), new_histogram.size());
+ if (acc == 0) {
+ // If acc is non-zero, we were not able to add everything to the new
+ // histogram, so this check will not hold.
+ RTC_DCHECK_EQ(accumulate(buckets.begin(), buckets.end(), 0ll),
+ accumulate(new_histogram.begin(), new_histogram.end(), 0ll));
+ }
+ return new_histogram;
+}
+
+} // namespace webrtc
diff --git a/modules/audio_coding/neteq/histogram.h b/modules/audio_coding/neteq/histogram.h
new file mode 100644
index 0000000..fc8f612
--- /dev/null
+++ b/modules/audio_coding/neteq/histogram.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_
+#define MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_
+
+#include <string.h> // Provide access to size_t.
+
+#include <vector>
+
+namespace webrtc {
+
+class Histogram {
+ public:
+ // Creates histogram with capacity |num_buckets| and |forget_factor| in Q15.
+ Histogram(size_t num_buckets, int forget_factor);
+
+ virtual ~Histogram();
+
+ // Resets the histogram to the default start distribution.
+ virtual void Reset();
+
+ // Add entry in bucket |index|.
+ virtual void Add(int index);
+
+ // Calculates the quantile at |probability| (in Q30) of the histogram
+ // distribution.
+ virtual int Quantile(int probability);
+
+ // Apply compression or stretching to the histogram.
+ virtual void Scale(int old_bucket_width, int new_bucket_width);
+
+ // Returns the number of buckets in the histogram.
+ virtual int NumBuckets() const;
+
+ // Returns the probability for each bucket in Q30.
+ std::vector<int> buckets() const { return buckets_; }
+
+ int forget_factor() const { return base_forget_factor_; }
+
+ // Made public for testing.
+ static std::vector<int> ScaleBuckets(const std::vector<int>& buckets,
+ int old_bucket_width,
+ int new_bucket_width);
+
+ private:
+ std::vector<int> buckets_;
+ int forget_factor_; // Q15
+ const int base_forget_factor_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_
diff --git a/modules/audio_coding/neteq/histogram_unittest.cc b/modules/audio_coding/neteq/histogram_unittest.cc
new file mode 100644
index 0000000..7a887c8
--- /dev/null
+++ b/modules/audio_coding/neteq/histogram_unittest.cc
@@ -0,0 +1,171 @@
+/*
+ * 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 <cmath>
+
+#include "modules/audio_coding/neteq/histogram.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(HistogramTest, Initialization) {
+ Histogram histogram(65, 32440);
+ histogram.Reset();
+ const auto& buckets = histogram.buckets();
+ double sum = 0.0;
+ for (size_t i = 0; i < buckets.size(); i++) {
+ EXPECT_NEAR(ldexp(std::pow(0.5, static_cast<int>(i + 1)), 30), buckets[i],
+ 65537);
+ // Tolerance 65537 in Q30 corresponds to a delta of approximately 0.00006.
+ sum += buckets[i];
+ }
+ EXPECT_EQ(1 << 30, static_cast<int>(sum)); // Should be 1 in Q30.
+}
+
+TEST(HistogramTest, Add) {
+ Histogram histogram(10, 32440);
+ histogram.Reset();
+ const std::vector<int> before = histogram.buckets();
+ const int index = 5;
+ histogram.Add(index);
+ const std::vector<int> after = histogram.buckets();
+ EXPECT_GT(after[index], before[index]);
+ int sum = 0;
+ for (int bucket : after) {
+ sum += bucket;
+ }
+ EXPECT_EQ(1 << 30, sum);
+}
+
+TEST(HistogramTest, ForgetFactor) {
+ Histogram histogram(10, 32440);
+ histogram.Reset();
+ const std::vector<int> before = histogram.buckets();
+ const int index = 4;
+ histogram.Add(index);
+ const std::vector<int> after = histogram.buckets();
+ for (int i = 0; i < histogram.NumBuckets(); ++i) {
+ if (i != index) {
+ EXPECT_LT(after[i], before[i]);
+ }
+ }
+}
+
+// Test if the histogram is scaled correctly if the bucket width is decreased.
+TEST(HistogramTest, DownScale) {
+ // Test a straightforward 60 to 20 change.
+ std::vector<int> buckets = {12, 0, 0, 0, 0, 0};
+ std::vector<int> expected_result = {4, 4, 4, 0, 0, 0};
+ std::vector<int> stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
+ EXPECT_EQ(stretched_buckets, expected_result);
+
+ // Test an example where the last bin in the stretched histogram should
+ // contain the sum of the elements that don't fit into the new histogram.
+ buckets = {18, 15, 12, 9, 6, 3, 0};
+ expected_result = {6, 6, 6, 5, 5, 5, 30};
+ stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
+ EXPECT_EQ(stretched_buckets, expected_result);
+
+ // Test a 120 to 60 change.
+ buckets = {18, 16, 14, 4, 0};
+ expected_result = {9, 9, 8, 8, 18};
+ stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 60);
+ EXPECT_EQ(stretched_buckets, expected_result);
+
+ // Test a 120 to 20 change.
+ buckets = {19, 12, 0, 0, 0, 0, 0, 0};
+ expected_result = {3, 3, 3, 3, 3, 3, 2, 11};
+ stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 20);
+ EXPECT_EQ(stretched_buckets, expected_result);
+
+ // Test a 70 to 40 change.
+ buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
+ expected_result = {7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 6, 22};
+ stretched_buckets = Histogram::ScaleBuckets(buckets, 70, 40);
+ EXPECT_EQ(stretched_buckets, expected_result);
+
+ // Test a 30 to 20 change.
+ buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
+ expected_result = {8, 6, 6, 3, 2, 2, 1, 3, 3, 8, 7, 11};
+ stretched_buckets = Histogram::ScaleBuckets(buckets, 30, 20);
+ EXPECT_EQ(stretched_buckets, expected_result);
+}
+
+// Test if the histogram is scaled correctly if the bucket width is increased.
+TEST(HistogramTest, UpScale) {
+ // Test a 20 to 60 change.
+ std::vector<int> buckets = {12, 11, 10, 3, 2, 1};
+ std::vector<int> expected_result = {33, 6, 0, 0, 0, 0};
+ std::vector<int> compressed_buckets =
+ Histogram::ScaleBuckets(buckets, 20, 60);
+ EXPECT_EQ(compressed_buckets, expected_result);
+
+ // Test a 60 to 120 change.
+ buckets = {18, 16, 14, 4, 1};
+ expected_result = {34, 18, 1, 0, 0};
+ compressed_buckets = Histogram::ScaleBuckets(buckets, 60, 120);
+ EXPECT_EQ(compressed_buckets, expected_result);
+
+ // Test a 20 to 120 change.
+ buckets = {18, 12, 5, 4, 4, 3, 5, 1};
+ expected_result = {46, 6, 0, 0, 0, 0, 0, 0};
+ compressed_buckets = Histogram::ScaleBuckets(buckets, 20, 120);
+ EXPECT_EQ(compressed_buckets, expected_result);
+
+ // Test a 70 to 80 change.
+ buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3};
+ expected_result = {11, 8, 6, 2, 5, 12, 13, 3, 0};
+ compressed_buckets = Histogram::ScaleBuckets(buckets, 70, 80);
+ EXPECT_EQ(compressed_buckets, expected_result);
+
+ // Test a 50 to 110 change.
+ buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3};
+ expected_result = {18, 8, 16, 16, 2, 0, 0, 0, 0};
+ compressed_buckets = Histogram::ScaleBuckets(buckets, 50, 110);
+ EXPECT_EQ(compressed_buckets, expected_result);
+}
+
+// Test if the histogram scaling function handles overflows correctly.
+TEST(HistogramTest, OverflowTest) {
+ // Test a upscale operation that can cause overflow.
+ std::vector<int> buckets = {733544448, 0, 0, 0, 0, 0, 0,
+ 340197376, 0, 0, 0, 0, 0, 0};
+ std::vector<int> expected_result = {733544448, 340197376, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0};
+ std::vector<int> scaled_buckets = Histogram::ScaleBuckets(buckets, 10, 60);
+ EXPECT_EQ(scaled_buckets, expected_result);
+
+ buckets = {655591163, 39962288, 360736736, 1930514, 4003853, 1782764,
+ 114119, 2072996, 0, 2149354, 0};
+ expected_result = {1056290187, 7717131, 2187115, 2149354, 0, 0,
+ 0, 0, 0, 0, 0};
+ scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60);
+ EXPECT_EQ(scaled_buckets, expected_result);
+
+ // In this test case we will not be able to add everything to the final bin in
+ // the scaled histogram. Check that the last bin doesn't overflow.
+ buckets = {2000000000, 2000000000, 2000000000,
+ 2000000000, 2000000000, 2000000000};
+ expected_result = {666666666, 666666666, 666666666,
+ 666666667, 666666667, 2147483647};
+ scaled_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
+ EXPECT_EQ(scaled_buckets, expected_result);
+
+ // In this test case we will not be able to add enough to each of the bins,
+ // so the values should be smeared out past the end of the normal range.
+ buckets = {2000000000, 2000000000, 2000000000,
+ 2000000000, 2000000000, 2000000000};
+ expected_result = {2147483647, 2147483647, 2147483647,
+ 2147483647, 2147483647, 1262581765};
+ scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60);
+ EXPECT_EQ(scaled_buckets, expected_result);
+}
+
+} // namespace webrtc
diff --git a/modules/audio_coding/neteq/include/neteq.h b/modules/audio_coding/neteq/include/neteq.h
index 2820fd8..549d355 100644
--- a/modules/audio_coding/neteq/include/neteq.h
+++ b/modules/audio_coding/neteq/include/neteq.h
@@ -13,18 +13,18 @@
#include <string.h> // Provide access to size_t.
+#include <map>
#include <string>
#include <vector>
#include "absl/types/optional.h"
#include "api/audio_codecs/audio_codec_pair_id.h"
#include "api/audio_codecs/audio_decoder.h"
+#include "api/audio_codecs/audio_format.h"
#include "api/rtp_headers.h"
-#include "common_types.h" // NOLINT(build/include)
+#include "api/scoped_refptr.h"
#include "modules/audio_coding/neteq/defines.h"
-#include "modules/audio_coding/neteq/neteq_decoder_enum.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -70,9 +70,19 @@
uint64_t concealed_samples = 0;
uint64_t concealment_events = 0;
uint64_t jitter_buffer_delay_ms = 0;
- // Below stat is not part of the spec.
+ uint64_t jitter_buffer_emitted_count = 0;
+ // Below stats are not part of the spec.
uint64_t voice_concealed_samples = 0;
uint64_t delayed_packet_outage_samples = 0;
+ // This is sum of relative packet arrival delays of received packets so far.
+ // Since end-to-end delay of a packet is difficult to measure and is not
+ // necessarily useful for measuring jitter buffer performance, we report a
+ // relative packet arrival delay. The relative packet arrival delay of a
+ // packet is defined as the arrival delay compared to the first packet
+ // received, given that it had zero delay. To avoid clock drift, the "first"
+ // packet can be made dynamic.
+ uint64_t relative_packet_arrival_delay_ms = 0;
+ uint64_t jitter_buffer_packets_received = 0;
};
// Metrics that describe the operations performed in NetEq, and the internal
@@ -85,6 +95,8 @@
uint64_t accelerate_samples = 0;
// Count of the number of buffer flushes.
uint64_t packet_buffer_flushes = 0;
+ // The number of primary packets that were discarded.
+ uint64_t discarded_primary_packets = 0;
// The statistics below are not cumulative.
// The waiting time of the last decoded packet.
uint64_t last_waiting_time_ms = 0;
@@ -111,11 +123,12 @@
int sample_rate_hz = 16000; // Initial value. Will change with input data.
bool enable_post_decode_vad = false;
- size_t max_packets_in_buffer = 50;
- int max_delay_ms = 2000;
+ size_t max_packets_in_buffer = 200;
+ int max_delay_ms = 0;
int min_delay_ms = 0;
bool enable_fast_accelerate = false;
bool enable_muted_state = false;
+ bool enable_rtx_handling = false;
absl::optional<AudioCodecPairId> codec_pair_id;
bool for_test_no_time_stretching = false; // Use only for testing.
};
@@ -165,25 +178,6 @@
// Replaces the current set of decoders with the given one.
virtual void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) = 0;
- // Associates |rtp_payload_type| with |codec| and |codec_name|, and stores the
- // information in the codec database. Returns 0 on success, -1 on failure.
- // The name is only used to provide information back to the caller about the
- // decoders. Hence, the name is arbitrary, and may be empty.
- virtual int RegisterPayloadType(NetEqDecoder codec,
- const std::string& codec_name,
- uint8_t rtp_payload_type) = 0;
-
- // Provides an externally created decoder object |decoder| to insert in the
- // decoder database. The decoder implements a decoder of type |codec| and
- // associates it with |rtp_payload_type| and |codec_name|. Returns kOK on
- // success, kFail on failure. The name is only used to provide information
- // back to the caller about the decoders. Hence, the name is arbitrary, and
- // may be empty.
- virtual int RegisterExternalDecoder(AudioDecoder* decoder,
- NetEqDecoder codec,
- const std::string& codec_name,
- uint8_t rtp_payload_type) = 0;
-
// Associates |rtp_payload_type| with the given codec, which NetEq will
// instantiate when it needs it. Returns true iff successful.
virtual bool RegisterPayloadType(int rtp_payload_type,
@@ -209,13 +203,20 @@
// the |max_delay_ms| value in the NetEq::Config struct.
virtual bool SetMaximumDelay(int delay_ms) = 0;
+ // Sets a base minimum delay in milliseconds for packet buffer. The minimum
+ // delay which is set via |SetMinimumDelay| can't be lower than base minimum
+ // delay. Calling this method is similar to setting the |min_delay_ms| value
+ // in the NetEq::Config struct. Returns true if the base minimum is
+ // successfully applied, otherwise false is returned.
+ virtual bool SetBaseMinimumDelayMs(int delay_ms) = 0;
+
+ // Returns current value of base minimum delay in milliseconds.
+ virtual int GetBaseMinimumDelayMs() const = 0;
+
// Returns the current target delay in ms. This includes any extra delay
// requested through SetMinimumDelay.
virtual int TargetDelayMs() const = 0;
- // Returns the current total delay (packet buffer and sync buffer) in ms.
- virtual int CurrentDelayMs() const = 0;
-
// Returns the current total delay (packet buffer and sync buffer) in ms,
// with smoothing applied to even out short-time fluctuations due to jitter.
// The packet buffer part of the delay is not updated during DTX/CNG periods.
@@ -249,11 +250,7 @@
// (Config::sample_rate_hz) is returned.
virtual int last_output_sample_rate_hz() const = 0;
- // Returns info about the decoder for the given payload type, or an empty
- // value if we have no decoder for that payload type.
- virtual absl::optional<CodecInst> GetDecoder(int payload_type) const = 0;
-
- // Returns the decoder format for the given payload type. Returns empty if no
+ // Returns the decoder info for the given payload type. Returns empty if no
// such payload type was registered.
virtual absl::optional<SdpAudioFormat> GetDecoderFormat(
int payload_type) const = 0;
diff --git a/modules/audio_coding/neteq/merge.h b/modules/audio_coding/neteq/merge.h
index e7e0bf9..a062a95 100644
--- a/modules/audio_coding/neteq/merge.h
+++ b/modules/audio_coding/neteq/merge.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_NETEQ_MERGE_H_
#include "modules/audio_coding/neteq/audio_multi_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/mock/mock_decoder_database.h b/modules/audio_coding/neteq/mock/mock_decoder_database.h
index b1d8151..d1db213 100644
--- a/modules/audio_coding/neteq/mock/mock_decoder_database.h
+++ b/modules/audio_coding/neteq/mock/mock_decoder_database.h
@@ -29,17 +29,8 @@
MOCK_CONST_METHOD0(Empty, bool());
MOCK_CONST_METHOD0(Size, int());
MOCK_METHOD0(Reset, void());
- MOCK_METHOD3(RegisterPayload,
- int(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& name));
MOCK_METHOD2(RegisterPayload,
int(int rtp_payload_type, const SdpAudioFormat& audio_format));
- MOCK_METHOD4(InsertExternal,
- int(uint8_t rtp_payload_type,
- NetEqDecoder codec_type,
- const std::string& codec_name,
- AudioDecoder* decoder));
MOCK_METHOD1(Remove, int(uint8_t rtp_payload_type));
MOCK_METHOD0(RemoveAll, void());
MOCK_CONST_METHOD1(GetDecoderInfo,
diff --git a/modules/audio_coding/neteq/mock/mock_delay_manager.h b/modules/audio_coding/neteq/mock/mock_delay_manager.h
index 206cea7..3a128ce 100644
--- a/modules/audio_coding/neteq/mock/mock_delay_manager.h
+++ b/modules/audio_coding/neteq/mock/mock_delay_manager.h
@@ -11,8 +11,11 @@
#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_MANAGER_H_
#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_MANAGER_H_
-#include "modules/audio_coding/neteq/delay_manager.h"
+#include <algorithm>
+#include "modules/audio_coding/neteq/delay_manager.h"
+#include "modules/audio_coding/neteq/histogram.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "test/gmock.h"
namespace webrtc {
@@ -21,26 +24,37 @@
public:
MockDelayManager(size_t max_packets_in_buffer,
int base_min_target_delay_ms,
+ int histogram_quantile,
+ HistogramMode histogram_mode,
+ bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
- const TickTimer* tick_timer)
+ const TickTimer* tick_timer,
+ StatisticsCalculator* stats,
+ std::unique_ptr<Histogram> histogram)
: DelayManager(max_packets_in_buffer,
base_min_target_delay_ms,
+ histogram_quantile,
+ histogram_mode,
+ enable_rtx_handling,
peak_detector,
- tick_timer) {}
+ tick_timer,
+ stats,
+ std::move(histogram)) {}
virtual ~MockDelayManager() { Die(); }
MOCK_METHOD0(Die, void());
- MOCK_CONST_METHOD0(iat_vector, const IATVector&());
MOCK_METHOD3(Update,
int(uint16_t sequence_number,
uint32_t timestamp,
int sample_rate_hz));
- MOCK_METHOD1(CalculateTargetLevel, int(int iat_packets));
+ MOCK_METHOD2(CalculateTargetLevel, int(int iat_packets, bool reordered));
MOCK_METHOD1(SetPacketAudioLength, int(int length_ms));
MOCK_METHOD0(Reset, void());
MOCK_CONST_METHOD0(PeakFound, bool());
MOCK_METHOD1(UpdateCounters, void(int elapsed_time_ms));
MOCK_METHOD0(ResetPacketIatCount, void());
MOCK_CONST_METHOD2(BufferLimits, void(int* lower_limit, int* higher_limit));
+ MOCK_METHOD1(SetBaseMinimumDelay, bool(int delay_ms));
+ MOCK_CONST_METHOD0(GetBaseMinimumDelay, int());
MOCK_CONST_METHOD0(TargetLevel, int());
MOCK_METHOD0(RegisterEmptyPacket, void());
MOCK_METHOD1(set_extra_delay_ms, void(int16_t delay));
diff --git a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
index f6cdea0..f7f0465 100644
--- a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
+++ b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
@@ -19,8 +19,9 @@
class MockDelayPeakDetector : public DelayPeakDetector {
public:
- MockDelayPeakDetector(const TickTimer* tick_timer)
- : DelayPeakDetector(tick_timer) {}
+ MockDelayPeakDetector(const TickTimer* tick_timer,
+ bool ignore_reordered_packets)
+ : DelayPeakDetector(tick_timer, ignore_reordered_packets) {}
virtual ~MockDelayPeakDetector() { Die(); }
MOCK_METHOD0(Die, void());
MOCK_METHOD0(Reset, void());
@@ -28,7 +29,8 @@
MOCK_METHOD0(peak_found, bool());
MOCK_CONST_METHOD0(MaxPeakHeight, int());
MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t());
- MOCK_METHOD2(Update, bool(int inter_arrival_time, int target_level));
+ MOCK_METHOD3(Update,
+ bool(int inter_arrival_time, bool reordered, int target_level));
};
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
deleted file mode 100644
index 1fb3db5..0000000
--- a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2013 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.
- */
-
-#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_
-#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_
-
-#include "api/audio_codecs/audio_decoder.h"
-#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
-#include "rtc_base/constructormagic.h"
-#include "test/gmock.h"
-
-namespace webrtc {
-
-using ::testing::_;
-using ::testing::Invoke;
-
-// Implement an external version of the PCM16b decoder.
-class ExternalPcm16B : public AudioDecoder {
- public:
- explicit ExternalPcm16B(int sample_rate_hz)
- : sample_rate_hz_(sample_rate_hz) {}
- void Reset() override {}
-
- int DecodeInternal(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- int16_t* decoded,
- SpeechType* speech_type) override {
- EXPECT_EQ(sample_rate_hz_, sample_rate_hz);
- size_t ret = WebRtcPcm16b_Decode(encoded, encoded_len, decoded);
- *speech_type = ConvertSpeechType(1);
- return static_cast<int>(ret);
- }
- int SampleRateHz() const override { return sample_rate_hz_; }
- size_t Channels() const override { return 1; }
-
- private:
- const int sample_rate_hz_;
- RTC_DISALLOW_COPY_AND_ASSIGN(ExternalPcm16B);
-};
-
-// Create a mock of ExternalPcm16B which delegates all calls to the real object.
-// The reason is that we can then track that the correct calls are being made.
-class MockExternalPcm16B : public AudioDecoder {
- public:
- explicit MockExternalPcm16B(int sample_rate_hz) : real_(sample_rate_hz) {
- // By default, all calls are delegated to the real object.
- ON_CALL(*this, DecodeInternal(_, _, _, _, _))
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::DecodeInternal));
- ON_CALL(*this, HasDecodePlc())
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::HasDecodePlc));
- ON_CALL(*this, DecodePlc(_, _))
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::DecodePlc));
- ON_CALL(*this, Reset())
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::Reset));
- ON_CALL(*this, IncomingPacket(_, _, _, _, _))
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::IncomingPacket));
- ON_CALL(*this, ErrorCode())
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::ErrorCode));
- }
- virtual ~MockExternalPcm16B() { Die(); }
-
- MOCK_METHOD0(Die, void());
- MOCK_METHOD5(DecodeInternal,
- int(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- int16_t* decoded,
- SpeechType* speech_type));
- MOCK_CONST_METHOD0(HasDecodePlc, bool());
- MOCK_METHOD2(DecodePlc, size_t(size_t num_frames, int16_t* decoded));
- MOCK_METHOD0(Reset, void());
- MOCK_METHOD5(IncomingPacket,
- int(const uint8_t* payload,
- size_t payload_len,
- uint16_t rtp_sequence_number,
- uint32_t rtp_timestamp,
- uint32_t arrival_timestamp));
- MOCK_METHOD0(ErrorCode, int());
-
- int SampleRateHz() const /* override */ { return real_.SampleRateHz(); }
- size_t Channels() const /* override */ { return real_.Channels(); }
-
- private:
- ExternalPcm16B real_;
-};
-
-} // namespace webrtc
-#endif // MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_
diff --git a/modules/audio_coding/neteq/mock/mock_histogram.h b/modules/audio_coding/neteq/mock/mock_histogram.h
new file mode 100644
index 0000000..09b1b89
--- /dev/null
+++ b/modules/audio_coding/neteq/mock/mock_histogram.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_
+#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_
+
+#include "modules/audio_coding/neteq/histogram.h"
+
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockHistogram : public Histogram {
+ public:
+ MockHistogram(size_t num_buckets, int forget_factor)
+ : Histogram(num_buckets, forget_factor) {}
+ virtual ~MockHistogram() {}
+
+ MOCK_METHOD1(Add, void(int));
+ MOCK_METHOD1(Quantile, int(int));
+};
+
+} // namespace webrtc
+#endif // MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_
diff --git a/modules/audio_coding/neteq/mock/mock_statistics_calculator.h b/modules/audio_coding/neteq/mock/mock_statistics_calculator.h
index 85f2620..aedb1df 100644
--- a/modules/audio_coding/neteq/mock/mock_statistics_calculator.h
+++ b/modules/audio_coding/neteq/mock/mock_statistics_calculator.h
@@ -21,6 +21,7 @@
public:
MOCK_METHOD1(PacketsDiscarded, void(size_t num_packets));
MOCK_METHOD1(SecondaryPacketsDiscarded, void(size_t num_packets));
+ MOCK_METHOD1(RelativePacketArrivalDelay, void(size_t delay_ms));
};
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq.cc b/modules/audio_coding/neteq/neteq.cc
index 0e6147e..a84c942 100644
--- a/modules/audio_coding/neteq/neteq.cc
+++ b/modules/audio_coding/neteq/neteq.cc
@@ -28,9 +28,10 @@
ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
<< (enable_post_decode_vad ? "true" : "false")
<< ", max_packets_in_buffer=" << max_packets_in_buffer
- << ", enable_fast_accelerate="
- << (enable_fast_accelerate ? " true" : "false")
- << ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
+ << ", min_delay_ms=" << min_delay_ms << ", enable_fast_accelerate="
+ << (enable_fast_accelerate ? "true" : "false")
+ << ", enable_muted_state=" << (enable_muted_state ? "true" : "false")
+ << ", enable_rtx_handling=" << (enable_rtx_handling ? "true" : "false");
return ss.str();
}
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.cc b/modules/audio_coding/neteq/neteq_decoder_enum.cc
deleted file mode 100644
index e3b633e..0000000
--- a/modules/audio_coding/neteq/neteq_decoder_enum.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2017 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 <map>
-#include <string>
-
-#include "modules/audio_coding/neteq/neteq_decoder_enum.h"
-
-namespace webrtc {
-
-absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd) {
- switch (nd) {
- case NetEqDecoder::kDecoderPCMu:
- return SdpAudioFormat("pcmu", 8000, 1);
- case NetEqDecoder::kDecoderPCMa:
- return SdpAudioFormat("pcma", 8000, 1);
- case NetEqDecoder::kDecoderPCMu_2ch:
- return SdpAudioFormat("pcmu", 8000, 2);
- case NetEqDecoder::kDecoderPCMa_2ch:
- return SdpAudioFormat("pcma", 8000, 2);
- case NetEqDecoder::kDecoderILBC:
- return SdpAudioFormat("ilbc", 8000, 1);
- case NetEqDecoder::kDecoderISAC:
- return SdpAudioFormat("isac", 16000, 1);
- case NetEqDecoder::kDecoderISACswb:
- return SdpAudioFormat("isac", 32000, 1);
- case NetEqDecoder::kDecoderPCM16B:
- return SdpAudioFormat("l16", 8000, 1);
- case NetEqDecoder::kDecoderPCM16Bwb:
- return SdpAudioFormat("l16", 16000, 1);
- case NetEqDecoder::kDecoderPCM16Bswb32kHz:
- return SdpAudioFormat("l16", 32000, 1);
- case NetEqDecoder::kDecoderPCM16Bswb48kHz:
- return SdpAudioFormat("l16", 48000, 1);
- case NetEqDecoder::kDecoderPCM16B_2ch:
- return SdpAudioFormat("l16", 8000, 2);
- case NetEqDecoder::kDecoderPCM16Bwb_2ch:
- return SdpAudioFormat("l16", 16000, 2);
- case NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch:
- return SdpAudioFormat("l16", 32000, 2);
- case NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch:
- return SdpAudioFormat("l16", 48000, 2);
- case NetEqDecoder::kDecoderPCM16B_5ch:
- return SdpAudioFormat("l16", 8000, 5);
- case NetEqDecoder::kDecoderG722:
- return SdpAudioFormat("g722", 8000, 1);
- case NetEqDecoder::kDecoderG722_2ch:
- return SdpAudioFormat("g722", 8000, 2);
- case NetEqDecoder::kDecoderOpus:
- return SdpAudioFormat("opus", 48000, 2);
- case NetEqDecoder::kDecoderOpus_2ch:
- return SdpAudioFormat(
- "opus", 48000, 2,
- std::map<std::string, std::string>{{"stereo", "1"}});
- case NetEqDecoder::kDecoderRED:
- return SdpAudioFormat("red", 8000, 1);
- case NetEqDecoder::kDecoderAVT:
- return SdpAudioFormat("telephone-event", 8000, 1);
- case NetEqDecoder::kDecoderAVT16kHz:
- return SdpAudioFormat("telephone-event", 16000, 1);
- case NetEqDecoder::kDecoderAVT32kHz:
- return SdpAudioFormat("telephone-event", 32000, 1);
- case NetEqDecoder::kDecoderAVT48kHz:
- return SdpAudioFormat("telephone-event", 48000, 1);
- case NetEqDecoder::kDecoderCNGnb:
- return SdpAudioFormat("cn", 8000, 1);
- case NetEqDecoder::kDecoderCNGwb:
- return SdpAudioFormat("cn", 16000, 1);
- case NetEqDecoder::kDecoderCNGswb32kHz:
- return SdpAudioFormat("cn", 32000, 1);
- case NetEqDecoder::kDecoderCNGswb48kHz:
- return SdpAudioFormat("cn", 48000, 1);
- default:
- return absl::nullopt;
- }
-}
-
-} // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.h b/modules/audio_coding/neteq/neteq_decoder_enum.h
deleted file mode 100644
index 00629bc..0000000
--- a/modules/audio_coding/neteq/neteq_decoder_enum.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2017 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.
- */
-
-#ifndef MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
-#define MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
-
-#include "absl/types/optional.h"
-#include "api/audio_codecs/audio_format.h"
-
-namespace webrtc {
-
-enum class NetEqDecoder {
- kDecoderPCMu,
- kDecoderPCMa,
- kDecoderPCMu_2ch,
- kDecoderPCMa_2ch,
- kDecoderILBC,
- kDecoderISAC,
- kDecoderISACswb,
- kDecoderPCM16B,
- kDecoderPCM16Bwb,
- kDecoderPCM16Bswb32kHz,
- kDecoderPCM16Bswb48kHz,
- kDecoderPCM16B_2ch,
- kDecoderPCM16Bwb_2ch,
- kDecoderPCM16Bswb32kHz_2ch,
- kDecoderPCM16Bswb48kHz_2ch,
- kDecoderPCM16B_5ch,
- kDecoderG722,
- kDecoderG722_2ch,
- kDecoderRED,
- kDecoderAVT,
- kDecoderAVT16kHz,
- kDecoderAVT32kHz,
- kDecoderAVT48kHz,
- kDecoderCNGnb,
- kDecoderCNGwb,
- kDecoderCNGswb32kHz,
- kDecoderCNGswb48kHz,
- kDecoderArbitrary,
- kDecoderOpus,
- kDecoderOpus_2ch,
-};
-
-absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd);
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
diff --git a/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc b/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc
index 8d0972c..21b15a9 100644
--- a/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc
@@ -14,6 +14,7 @@
#include <utility>
#include <vector>
+#include "absl/memory/memory.h"
#include "absl/types/optional.h"
#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
#include "modules/audio_coding/neteq/tools/audio_checksum.h"
@@ -23,8 +24,10 @@
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
#include "modules/audio_coding/neteq/tools/neteq_test.h"
#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/audio_decoder_proxy_factory.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace test {
@@ -174,10 +177,7 @@
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"));
AudioDecoderPlc dec(std::move(input_file), kSampleRateHz);
// Masquerading as a PCM16b decoder.
- NetEqTest::ExternalDecoderInfo dec_info = {
- &dec, NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16b_PLC"};
- NetEqTest::ExtDecoderMap external_decoders;
- external_decoders.insert(std::make_pair(kPayloadType, dec_info));
+ decoders.emplace(kPayloadType, SdpAudioFormat("l16", 32000, 1));
// Output is simply a checksum calculator.
auto output = absl::make_unique<AudioChecksumWithOutput>(checksum);
@@ -185,8 +185,9 @@
// No callback objects.
NetEqTest::Callbacks callbacks;
- NetEqTest neteq_test(config, decoders, external_decoders,
- std::move(lossy_input), std::move(output), callbacks);
+ NetEqTest neteq_test(
+ config, new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&dec),
+ decoders, nullptr, std::move(lossy_input), std::move(output), callbacks);
EXPECT_LE(kRunTimeMs, neteq_test.Run());
auto lifetime_stats = neteq_test.LifetimeStats();
diff --git a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
index 872829c..8214ed2 100644
--- a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
@@ -14,14 +14,13 @@
#include "api/audio/audio_frame.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
#include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h"
#include "modules/audio_coding/neteq/tools/rtp_generator.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gmock.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index 2a025f3..f1e8527 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -41,6 +41,7 @@
#include "modules/audio_coding/neteq/post_decode_vad.h"
#include "modules/audio_coding/neteq/preemptive_expand.h"
#include "modules/audio_coding/neteq/red_payload_splitter.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/audio_coding/neteq/sync_buffer.h"
#include "modules/audio_coding/neteq/tick_timer.h"
#include "modules/audio_coding/neteq/time_stretch.h"
@@ -58,14 +59,18 @@
const NetEq::Config& config,
const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)
: tick_timer(new TickTimer),
+ stats(new StatisticsCalculator),
buffer_level_filter(new BufferLevelFilter),
decoder_database(
new DecoderDatabase(decoder_factory, config.codec_pair_id)),
- delay_peak_detector(new DelayPeakDetector(tick_timer.get())),
- delay_manager(new DelayManager(config.max_packets_in_buffer,
- config.min_delay_ms,
- delay_peak_detector.get(),
- tick_timer.get())),
+ delay_peak_detector(
+ new DelayPeakDetector(tick_timer.get(), config.enable_rtx_handling)),
+ delay_manager(DelayManager::Create(config.max_packets_in_buffer,
+ config.min_delay_ms,
+ config.enable_rtx_handling,
+ delay_peak_detector.get(),
+ tick_timer.get(),
+ stats.get())),
dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)),
dtmf_tone_generator(new DtmfToneGenerator),
packet_buffer(
@@ -95,6 +100,7 @@
expand_factory_(std::move(deps.expand_factory)),
accelerate_factory_(std::move(deps.accelerate_factory)),
preemptive_expand_factory_(std::move(deps.preemptive_expand_factory)),
+ stats_(std::move(deps.stats)),
last_mode_(kModeNormal),
decoded_buffer_length_(kMaxFrameSize),
decoded_buffer_(new int16_t[decoded_buffer_length_]),
@@ -102,7 +108,6 @@
new_codec_(false),
timestamp_(0),
reset_decoder_(false),
- ssrc_(0),
first_packet_(true),
enable_fast_accelerate_(config.enable_fast_accelerate),
nack_enabled_(false),
@@ -113,7 +118,8 @@
speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
10, // Report once every 10 s.
tick_timer_.get()),
- no_time_stretching_(config.for_test_no_time_stretching) {
+ no_time_stretching_(config.for_test_no_time_stretching),
+ enable_rtx_handling_(config.enable_rtx_handling) {
RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
int fs = config.sample_rate_hz;
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
@@ -231,44 +237,10 @@
const std::vector<int> changed_payload_types =
decoder_database_->SetCodecs(codecs);
for (const int pt : changed_payload_types) {
- packet_buffer_->DiscardPacketsWithPayloadType(pt, &stats_);
+ packet_buffer_->DiscardPacketsWithPayloadType(pt, stats_.get());
}
}
-int NetEqImpl::RegisterPayloadType(NetEqDecoder codec,
- const std::string& name,
- uint8_t rtp_payload_type) {
- rtc::CritScope lock(&crit_sect_);
- RTC_LOG(LS_VERBOSE) << "RegisterPayloadType "
- << static_cast<int>(rtp_payload_type) << " "
- << static_cast<int>(codec);
- if (decoder_database_->RegisterPayload(rtp_payload_type, codec, name) !=
- DecoderDatabase::kOK) {
- return kFail;
- }
- return kOK;
-}
-
-int NetEqImpl::RegisterExternalDecoder(AudioDecoder* decoder,
- NetEqDecoder codec,
- const std::string& codec_name,
- uint8_t rtp_payload_type) {
- rtc::CritScope lock(&crit_sect_);
- RTC_LOG(LS_VERBOSE) << "RegisterExternalDecoder "
- << static_cast<int>(rtp_payload_type) << " "
- << static_cast<int>(codec);
- if (!decoder) {
- RTC_LOG(LS_ERROR) << "Cannot register external decoder with NULL pointer";
- assert(false);
- return kFail;
- }
- if (decoder_database_->InsertExternal(rtp_payload_type, codec, codec_name,
- decoder) != DecoderDatabase::kOK) {
- return kFail;
- }
- return kOK;
-}
-
bool NetEqImpl::RegisterPayloadType(int rtp_payload_type,
const SdpAudioFormat& audio_format) {
RTC_LOG(LS_VERBOSE) << "NetEqImpl::RegisterPayloadType: payload type "
@@ -283,7 +255,8 @@
rtc::CritScope lock(&crit_sect_);
int ret = decoder_database_->Remove(rtp_payload_type);
if (ret == DecoderDatabase::kOK || ret == DecoderDatabase::kDecoderNotFound) {
- packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type, &stats_);
+ packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type,
+ stats_.get());
return kOK;
}
return kFail;
@@ -312,6 +285,19 @@
return false;
}
+bool NetEqImpl::SetBaseMinimumDelayMs(int delay_ms) {
+ rtc::CritScope lock(&crit_sect_);
+ if (delay_ms >= 0 && delay_ms <= 10000) {
+ return delay_manager_->SetBaseMinimumDelay(delay_ms);
+ }
+ return false;
+}
+
+int NetEqImpl::GetBaseMinimumDelayMs() const {
+ rtc::CritScope lock(&crit_sect_);
+ return delay_manager_->GetBaseMinimumDelay();
+}
+
int NetEqImpl::TargetDelayMs() const {
rtc::CritScope lock(&crit_sect_);
RTC_DCHECK(delay_manager_.get());
@@ -322,21 +308,6 @@
rtc::CheckedDivExact(fs_hz_, 1000);
}
-int NetEqImpl::CurrentDelayMs() const {
- rtc::CritScope lock(&crit_sect_);
- if (fs_hz_ == 0)
- return 0;
- // Sum up the samples in the packet buffer with the future length of the sync
- // buffer, and divide the sum by the sample rate.
- const size_t delay_samples =
- packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
- sync_buffer_->FutureLength();
- // The division below will truncate.
- const int delay_ms =
- static_cast<int>(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000);
- return delay_ms;
-}
-
int NetEqImpl::FilteredCurrentDelayMs() const {
rtc::CritScope lock(&crit_sect_);
// Calculate the filtered packet buffer level in samples. The value from
@@ -363,20 +334,21 @@
assert(decision_logic_.get());
const int ms_per_packet = rtc::dchecked_cast<int>(
decision_logic_->packet_length_samples() / (fs_hz_ / 1000));
- stats_.PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(), stats);
- stats_.GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
- decoder_frame_length_, stats);
+ stats_->PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(),
+ stats);
+ stats_->GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
+ decoder_frame_length_, stats);
return 0;
}
NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const {
rtc::CritScope lock(&crit_sect_);
- return stats_.GetLifetimeStatistics();
+ return stats_->GetLifetimeStatistics();
}
NetEqOperationsAndState NetEqImpl::GetOperationsAndState() const {
rtc::CritScope lock(&crit_sect_);
- auto result = stats_.GetOperationsAndState();
+ auto result = stats_->GetOperationsAndState();
result.current_buffer_size_ms =
(packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
sync_buffer_->FutureLength()) *
@@ -417,27 +389,6 @@
return last_output_sample_rate_hz_;
}
-absl::optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const {
- rtc::CritScope lock(&crit_sect_);
- const DecoderDatabase::DecoderInfo* di =
- decoder_database_->GetDecoderInfo(payload_type);
- if (!di) {
- return absl::nullopt;
- }
-
- // Create a CodecInst with some fields set. The remaining fields are zeroed,
- // but we tell MSan to consider them uninitialized.
- CodecInst ci = {0};
- rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1));
- ci.pltype = payload_type;
- std::strncpy(ci.plname, di->get_name().c_str(), sizeof(ci.plname));
- ci.plname[sizeof(ci.plname) - 1] = '\0';
- ci.plfreq = di->IsRed() ? 8000 : di->SampleRateHz();
- AudioDecoder* const decoder = di->GetDecoder();
- ci.channels = decoder ? decoder->Channels() : 1;
- return ci;
-}
-
absl::optional<SdpAudioFormat> NetEqImpl::GetDecoderFormat(
int payload_type) const {
rtc::CritScope lock(&crit_sect_);
@@ -446,7 +397,13 @@
if (!di) {
return absl::nullopt; // Payload type not registered.
}
- return di->GetFormat();
+
+ SdpAudioFormat format = di->GetFormat();
+ // TODO(solenberg): This is legacy but messed up - mixing RTP rate and SR.
+ format.clockrate_hz = di->IsRed() ? 8000 : di->SampleRateHz();
+ const AudioDecoder* const decoder = di->GetDecoder();
+ format.num_channels = decoder ? decoder->Channels() : 1;
+ return format;
}
void NetEqImpl::FlushBuffers() {
@@ -518,6 +475,7 @@
RTC_LOG_F(LS_ERROR) << "payload is empty";
return kInvalidPointer;
}
+ stats_->ReceivedPacket();
PacketList packet_list;
// Insert packet in a packet list.
@@ -533,8 +491,7 @@
return packet;
}());
- bool update_sample_rate_and_channels =
- first_packet_ || (rtp_header.ssrc != ssrc_);
+ bool update_sample_rate_and_channels = first_packet_;
if (update_sample_rate_and_channels) {
// Reset timestamp scaling.
@@ -561,9 +518,6 @@
packet_buffer_->Flush();
dtmf_buffer_->Flush();
- // Store new SSRC.
- ssrc_ = rtp_header.ssrc;
-
// Update audio buffer timestamp.
sync_buffer_->IncreaseEndTimestamp(main_timestamp - timestamp_);
@@ -707,7 +661,7 @@
// Insert packets in buffer.
const int ret = packet_buffer_->InsertPacketList(
&parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_,
- ¤t_cng_rtp_payload_type_, &stats_);
+ ¤t_cng_rtp_payload_type_, stats_.get());
if (ret == PacketBuffer::kFlushed) {
// Reset DSP timestamp etc. if packet buffer flushed.
new_codec_ = true;
@@ -777,9 +731,11 @@
}
// Update statistics.
- if ((int32_t)(main_timestamp - timestamp_) >= 0 && !new_codec_) {
+ if ((enable_rtx_handling_ || (int32_t)(main_timestamp - timestamp_) >= 0) &&
+ !new_codec_) {
// Only update statistics if incoming packet is not older than last played
- // out packet, and if new codec flag is not set.
+ // out packet or RTX handling is enabled, and if new codec flag is not
+ // set.
delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz_);
}
} else if (delay_manager_->last_pack_cng_or_dtmf() == -1) {
@@ -802,8 +758,8 @@
*muted = false;
last_decoded_timestamps_.clear();
tick_timer_->Increment();
- stats_.IncreaseCounter(output_size_samples_, fs_hz_);
- const auto lifetime_stats = stats_.GetLifetimeStatistics();
+ stats_->IncreaseCounter(output_size_samples_, fs_hz_);
+ const auto lifetime_stats = stats_->GetLifetimeStatistics();
expand_uma_logger_.UpdateSampleCounter(lifetime_stats.concealed_samples,
fs_hz_);
speech_expand_uma_logger_.UpdateSampleCounter(
@@ -823,7 +779,7 @@
: timestamp_scaler_->ToExternal(playout_timestamp_) -
static_cast<uint32_t>(audio_frame->samples_per_channel_);
audio_frame->num_channels_ = sync_buffer_->Channels();
- stats_.ExpandedNoiseSamples(output_size_samples_, false);
+ stats_->ExpandedNoiseSamples(output_size_samples_, false);
*muted = true;
return 0;
}
@@ -1032,7 +988,7 @@
if (!new_codec_) {
const uint32_t five_seconds_samples = 5 * fs_hz_;
packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples,
- &stats_);
+ stats_.get());
}
const Packet* packet = packet_buffer_->PeekNextPacket();
@@ -1052,12 +1008,14 @@
(end_timestamp >= packet->timestamp ||
end_timestamp + generated_noise_samples > packet->timestamp)) {
// Don't use this packet, discard it.
- if (packet_buffer_->DiscardNextPacket(&stats_) != PacketBuffer::kOK) {
+ if (packet_buffer_->DiscardNextPacket(stats_.get()) !=
+ PacketBuffer::kOK) {
assert(false); // Must be ok by design.
}
// Check buffer again.
if (!new_codec_) {
- packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_, &stats_);
+ packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_,
+ stats_.get());
}
packet = packet_buffer_->PeekNextPacket();
}
@@ -1139,7 +1097,7 @@
decision_logic_->SoftReset();
buffer_level_filter_->Reset();
delay_manager_->Reset();
- stats_.ResetMcu();
+ stats_->ResetMcu();
}
size_t required_samples = output_size_samples_;
@@ -1244,7 +1202,7 @@
// if comfort noise is not played. If comfort noise was just played,
// this adjustment of timestamp is only done to get back in sync with the
// stream timestamp; no loss to report.
- stats_.LostSamples(packet->timestamp - end_timestamp);
+ stats_->LostSamples(packet->timestamp - end_timestamp);
}
if (*operation != kRfc3389Cng) {
@@ -1511,10 +1469,10 @@
// Update in-call and post-call statistics.
if (expand_->MuteFactor(0) == 0) {
// Expand generates only noise.
- stats_.ExpandedNoiseSamplesCorrection(expand_length_correction);
+ stats_->ExpandedNoiseSamplesCorrection(expand_length_correction);
} else {
// Expansion generates more than only noise.
- stats_.ExpandedVoiceSamplesCorrection(expand_length_correction);
+ stats_->ExpandedVoiceSamplesCorrection(expand_length_correction);
}
last_mode_ = kModeMerge;
@@ -1555,12 +1513,12 @@
if (std::all_of(concealment_audio_.cbegin(), concealment_audio_.cend(),
[](int16_t i) { return i == 0; })) {
// Expand operation generates only noise.
- stats_.ExpandedNoiseSamples(concealed_samples_per_channel,
- is_new_concealment_event);
+ stats_->ExpandedNoiseSamples(concealed_samples_per_channel,
+ is_new_concealment_event);
} else {
// Expand operation generates more than only noise.
- stats_.ExpandedVoiceSamples(concealed_samples_per_channel,
- is_new_concealment_event);
+ stats_->ExpandedVoiceSamples(concealed_samples_per_channel,
+ is_new_concealment_event);
}
last_mode_ = kModeCodecPlc;
if (!generated_noise_stopwatch_) {
@@ -1581,10 +1539,10 @@
// Update in-call and post-call statistics.
if (expand_->MuteFactor(0) == 0) {
// Expand operation generates only noise.
- stats_.ExpandedNoiseSamples(length, is_new_concealment_event);
+ stats_->ExpandedNoiseSamples(length, is_new_concealment_event);
} else {
// Expand operation generates more than only noise.
- stats_.ExpandedVoiceSamples(length, is_new_concealment_event);
+ stats_->ExpandedVoiceSamples(length, is_new_concealment_event);
}
last_mode_ = kModeExpand;
@@ -1633,7 +1591,7 @@
Accelerate::ReturnCodes return_code =
accelerate_->Process(decoded_buffer, decoded_length, fast_accelerate,
algorithm_buffer_.get(), &samples_removed);
- stats_.AcceleratedSamples(samples_removed);
+ stats_->AcceleratedSamples(samples_removed);
switch (return_code) {
case Accelerate::kSuccess:
last_mode_ = kModeAccelerateSuccess;
@@ -1711,7 +1669,7 @@
PreemptiveExpand::ReturnCodes return_code = preemptive_expand_->Process(
decoded_buffer, decoded_length, old_borrowed_samples_per_channel,
algorithm_buffer_.get(), &samples_added);
- stats_.PreemptiveExpandedSamples(samples_added);
+ stats_->PreemptiveExpandedSamples(samples_added);
switch (return_code) {
case PreemptiveExpand::kSuccess:
last_mode_ = kModePreemptiveExpandSuccess;
@@ -1926,7 +1884,7 @@
return -1;
}
const uint64_t waiting_time_ms = packet->waiting_time->ElapsedMs();
- stats_.StoreWaitingTime(waiting_time_ms);
+ stats_->StoreWaitingTime(waiting_time_ms);
RTC_DCHECK(!packet->empty());
if (first_packet) {
@@ -1950,7 +1908,7 @@
packet_duration = packet->frame->Duration();
// TODO(ossu): Is this the correct way to track Opus FEC packets?
if (packet->priority.codec_level > 0) {
- stats_.SecondaryDecodedSamples(
+ stats_->SecondaryDecodedSamples(
rtc::dchecked_cast<int>(packet_duration));
}
} else if (!has_cng_packet) {
@@ -1966,7 +1924,7 @@
}
extracted_samples = packet->timestamp - first_timestamp + packet_duration;
- stats_.JitterBufferDelay(extracted_samples, waiting_time_ms);
+ stats_->JitterBufferDelay(packet_duration, waiting_time_ms);
packet_list->push_back(std::move(*packet)); // Store packet in list.
packet = absl::nullopt; // Ensure it's never used after the move.
@@ -1978,13 +1936,14 @@
!has_cng_packet) {
int16_t seq_no_diff = next_packet->sequence_number - prev_sequence_number;
size_t ts_diff = next_packet->timestamp - prev_timestamp;
- if (seq_no_diff == 1 ||
- (seq_no_diff == 0 && ts_diff == decoder_frame_length_)) {
+ if ((seq_no_diff == 1 || seq_no_diff == 0) &&
+ ts_diff <= packet_duration) {
// The next sequence number is available, or the next part of a packet
// that was split into pieces upon insertion.
next_packet_available = true;
}
prev_sequence_number = next_packet->sequence_number;
+ prev_timestamp = next_packet->timestamp;
}
} while (extracted_samples < required_samples && next_packet_available);
@@ -1993,7 +1952,7 @@
// we could end up in the situation where we never decode anything, since
// all incoming packets are considered too old but the buffer will also
// never be flooded and flushed.
- packet_buffer_->DiscardAllOldPackets(timestamp_, &stats_);
+ packet_buffer_->DiscardAllOldPackets(timestamp_, stats_.get());
}
return rtc::dchecked_cast<int>(extracted_samples);
@@ -2003,7 +1962,7 @@
// Delete objects and create new ones.
expand_.reset(expand_factory_->Create(background_noise_.get(),
sync_buffer_.get(), &random_vector_,
- &stats_, fs_hz, channels));
+ stats_.get(), fs_hz, channels));
merge_.reset(new Merge(fs_hz, channels, expand_.get(), sync_buffer_.get()));
}
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index 525ae61..34a5c71 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -24,8 +24,8 @@
#include "modules/audio_coding/neteq/random_vector.h"
#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/audio_coding/neteq/tick_timer.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@@ -99,6 +99,7 @@
~Dependencies();
std::unique_ptr<TickTimer> tick_timer;
+ std::unique_ptr<StatisticsCalculator> stats;
std::unique_ptr<BufferLevelFilter> buffer_level_filter;
std::unique_ptr<DecoderDatabase> decoder_database;
std::unique_ptr<DelayPeakDetector> delay_peak_detector;
@@ -137,15 +138,6 @@
void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) override;
- int RegisterPayloadType(NetEqDecoder codec,
- const std::string& codec_name,
- uint8_t rtp_payload_type) override;
-
- int RegisterExternalDecoder(AudioDecoder* decoder,
- NetEqDecoder codec,
- const std::string& codec_name,
- uint8_t rtp_payload_type) override;
-
bool RegisterPayloadType(int rtp_payload_type,
const SdpAudioFormat& audio_format) override;
@@ -159,9 +151,11 @@
bool SetMaximumDelay(int delay_ms) override;
- int TargetDelayMs() const override;
+ bool SetBaseMinimumDelayMs(int delay_ms) override;
- int CurrentDelayMs() const override;
+ int GetBaseMinimumDelayMs() const override;
+
+ int TargetDelayMs() const override;
int FilteredCurrentDelayMs() const override;
@@ -184,8 +178,6 @@
int last_output_sample_rate_hz() const override;
- absl::optional<CodecInst> GetDecoder(int payload_type) const override;
-
absl::optional<SdpAudioFormat> GetDecoderFormat(
int payload_type) const override;
@@ -370,6 +362,7 @@
RTC_GUARDED_BY(crit_sect_);
const std::unique_ptr<PreemptiveExpandFactory> preemptive_expand_factory_
RTC_GUARDED_BY(crit_sect_);
+ const std::unique_ptr<StatisticsCalculator> stats_ RTC_GUARDED_BY(crit_sect_);
std::unique_ptr<BackgroundNoise> background_noise_ RTC_GUARDED_BY(crit_sect_);
std::unique_ptr<DecisionLogic> decision_logic_ RTC_GUARDED_BY(crit_sect_);
@@ -384,7 +377,6 @@
RTC_GUARDED_BY(crit_sect_);
RandomVector random_vector_ RTC_GUARDED_BY(crit_sect_);
std::unique_ptr<ComfortNoise> comfort_noise_ RTC_GUARDED_BY(crit_sect_);
- StatisticsCalculator stats_ RTC_GUARDED_BY(crit_sect_);
int fs_hz_ RTC_GUARDED_BY(crit_sect_);
int fs_mult_ RTC_GUARDED_BY(crit_sect_);
int last_output_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
@@ -401,7 +393,6 @@
absl::optional<uint8_t> current_rtp_payload_type_ RTC_GUARDED_BY(crit_sect_);
absl::optional<uint8_t> current_cng_rtp_payload_type_
RTC_GUARDED_BY(crit_sect_);
- uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
bool first_packet_ RTC_GUARDED_BY(crit_sect_);
bool enable_fast_accelerate_ RTC_GUARDED_BY(crit_sect_);
std::unique_ptr<NackTracker> nack_ RTC_GUARDED_BY(crit_sect_);
@@ -416,6 +407,7 @@
ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_); // Only used for test.
rtc::BufferT<int16_t> concealment_audio_ RTC_GUARDED_BY(crit_sect_);
+ const bool enable_rtx_handling_ RTC_GUARDED_BY(crit_sect_);
private:
RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 0e087c8..5875493 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -10,10 +10,11 @@
#include <memory>
+#include "absl/memory/memory.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/accelerate.h"
#include "modules/audio_coding/neteq/expand.h"
+#include "modules/audio_coding/neteq/histogram.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/mock/mock_buffer_level_filter.h"
#include "modules/audio_coding/neteq/mock/mock_decoder_database.h"
@@ -25,9 +26,12 @@
#include "modules/audio_coding/neteq/mock/mock_red_payload_splitter.h"
#include "modules/audio_coding/neteq/neteq_impl.h"
#include "modules/audio_coding/neteq/preemptive_expand.h"
+#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "modules/audio_coding/neteq/sync_buffer.h"
#include "modules/audio_coding/neteq/timestamp_scaler.h"
#include "rtc_base/numerics/safe_conversions.h"
+#include "test/audio_decoder_proxy_factory.h"
+#include "test/function_audio_decoder_factory.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_audio_decoder.h"
@@ -59,8 +63,10 @@
protected:
NetEqImplTest() { config_.sample_rate_hz = 8000; }
- void CreateInstance() {
- NetEqImpl::Dependencies deps(config_, CreateBuiltinAudioDecoderFactory());
+ void CreateInstance(
+ const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
+ ASSERT_TRUE(decoder_factory);
+ NetEqImpl::Dependencies deps(config_, decoder_factory);
// Get a local pointer to NetEq's TickTimer object.
tick_timer_ = deps.tick_timer.get();
@@ -83,7 +89,7 @@
if (use_mock_delay_peak_detector_) {
std::unique_ptr<MockDelayPeakDetector> mock(
- new MockDelayPeakDetector(tick_timer_));
+ new MockDelayPeakDetector(tick_timer_, config_.enable_rtx_handling));
mock_delay_peak_detector_ = mock.get();
EXPECT_CALL(*mock_delay_peak_detector_, Reset()).Times(1);
deps.delay_peak_detector = std::move(mock);
@@ -92,8 +98,10 @@
if (use_mock_delay_manager_) {
std::unique_ptr<MockDelayManager> mock(new MockDelayManager(
- config_.max_packets_in_buffer, config_.min_delay_ms,
- delay_peak_detector_, tick_timer_));
+ config_.max_packets_in_buffer, config_.min_delay_ms, 1020054733,
+ DelayManager::HistogramMode::INTER_ARRIVAL_TIME,
+ config_.enable_rtx_handling, delay_peak_detector_, tick_timer_,
+ deps.stats.get(), absl::make_unique<Histogram>(50, 32745)));
mock_delay_manager_ = mock.get();
EXPECT_CALL(*mock_delay_manager_, set_streaming_mode(false)).Times(1);
deps.delay_manager = std::move(mock);
@@ -137,6 +145,8 @@
ASSERT_TRUE(neteq_ != NULL);
}
+ void CreateInstance() { CreateInstance(CreateBuiltinAudioDecoderFactory()); }
+
void UseNoMocks() {
ASSERT_TRUE(neteq_ == NULL) << "Must call UseNoMocks before CreateInstance";
use_mock_buffer_level_filter_ = false;
@@ -173,7 +183,7 @@
}
}
- void TestDtmfPacket(NetEqDecoder decoder_type) {
+ void TestDtmfPacket(int sample_rate_hz) {
const size_t kPayloadLength = 4;
const uint8_t kPayloadType = 110;
const uint32_t kReceiveTime = 17;
@@ -189,8 +199,8 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
- decoder_type, "telephone-event", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(
+ kPayloadType, SdpAudioFormat("telephone-event", sample_rate_hz, 1)));
// Insert first packet.
EXPECT_EQ(NetEq::kOK,
@@ -257,16 +267,6 @@
delete neteq;
}
-TEST_F(NetEqImplTest, RegisterPayloadTypeNetEqDecoder) {
- CreateInstance();
- uint8_t rtp_payload_type = 0;
- NetEqDecoder codec_type = NetEqDecoder::kDecoderPCMu;
- const std::string kCodecName = "Robert\'); DROP TABLE Students;";
- EXPECT_CALL(*mock_decoder_database_,
- RegisterPayload(rtp_payload_type, codec_type, kCodecName));
- neteq_->RegisterPayloadType(codec_type, kCodecName, rtp_payload_type);
-}
-
TEST_F(NetEqImplTest, RegisterPayloadType) {
CreateInstance();
constexpr int rtp_payload_type = 0;
@@ -335,8 +335,8 @@
*dec = std::move(mock_decoder);
}));
- DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, absl::nullopt,
- mock_decoder_factory);
+ DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
+ absl::nullopt, mock_decoder_factory);
// Expectations for decoder database.
EXPECT_CALL(*mock_decoder_database_, GetDecoderInfo(kPayloadType))
@@ -405,8 +405,8 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
- NetEqDecoder::kDecoderPCM16B, "", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", 8000, 1)));
// Insert packets. The buffer should not flush.
for (size_t i = 1; i <= config_.max_packets_in_buffer; ++i) {
@@ -428,27 +428,24 @@
}
TEST_F(NetEqImplTest, TestDtmfPacketAVT) {
- TestDtmfPacket(NetEqDecoder::kDecoderAVT);
+ TestDtmfPacket(8000);
}
TEST_F(NetEqImplTest, TestDtmfPacketAVT16kHz) {
- TestDtmfPacket(NetEqDecoder::kDecoderAVT16kHz);
+ TestDtmfPacket(16000);
}
TEST_F(NetEqImplTest, TestDtmfPacketAVT32kHz) {
- TestDtmfPacket(NetEqDecoder::kDecoderAVT32kHz);
+ TestDtmfPacket(32000);
}
TEST_F(NetEqImplTest, TestDtmfPacketAVT48kHz) {
- TestDtmfPacket(NetEqDecoder::kDecoderAVT48kHz);
+ TestDtmfPacket(48000);
}
// This test verifies that timestamps propagate from the incoming packets
// through to the sync buffer and to the playout timestamp.
TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
- UseNoMocks();
- CreateInstance();
-
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
const int kSampleRateHz = 8000;
@@ -494,9 +491,14 @@
int16_t next_value_;
} decoder_;
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &decoder_, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory =
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&decoder_);
+
+ UseNoMocks();
+ CreateInstance(decoder_factory);
+
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("L16", 8000, 1)));
// Insert one packet.
EXPECT_EQ(NetEq::kOK,
@@ -541,7 +543,11 @@
TEST_F(NetEqImplTest, ReorderedPacket) {
UseNoMocks();
- CreateInstance();
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder));
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
@@ -556,8 +562,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- // Create a mock decoder object.
- MockAudioDecoder mock_decoder;
EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return());
EXPECT_CALL(mock_decoder, SampleRateHz())
.WillRepeatedly(Return(kSampleRateHz));
@@ -575,9 +579,8 @@
dummy_output + kPayloadLengthSamples),
SetArgPointee<4>(AudioDecoder::kSpeech),
Return(rtc::checked_cast<int>(kPayloadLengthSamples))));
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &mock_decoder, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("L16", 8000, 1)));
// Insert one packet.
EXPECT_EQ(NetEq::kOK,
@@ -662,8 +665,8 @@
EXPECT_EQ(AudioFrame::kPLC, output.speech_type_);
// Register the payload type.
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
- NetEqDecoder::kDecoderPCM16B, "", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", 8000, 1)));
// Insert 10 packets.
for (size_t i = 0; i < 10; ++i) {
@@ -689,7 +692,10 @@
// internal CNG mode properly.
TEST_F(NetEqImplTest, CodecInternalCng) {
UseNoMocks();
- CreateInstance();
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder));
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
@@ -706,8 +712,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- // Create a mock decoder object.
- MockAudioDecoder mock_decoder;
EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return());
EXPECT_CALL(mock_decoder, SampleRateHz())
.WillRepeatedly(Return(kSampleRateKhz * 1000));
@@ -751,9 +755,8 @@
SetArgPointee<4>(AudioDecoder::kSpeech),
Return(rtc::checked_cast<int>(kPayloadLengthSamples))));
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &mock_decoder, NetEqDecoder::kDecoderOpus,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("opus", 48000, 2)));
// Insert one packet (decoder will return speech).
EXPECT_EQ(NetEq::kOK,
@@ -834,7 +837,10 @@
TEST_F(NetEqImplTest, UnsupportedDecoder) {
UseNoMocks();
- CreateInstance();
+ ::testing::NiceMock<MockAudioDecoder> decoder;
+
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&decoder));
static const size_t kNetEqMaxFrameSize = 5760; // 120 ms @ 48 kHz.
static const size_t kChannels = 2;
@@ -853,8 +859,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- ::testing::NiceMock<MockAudioDecoder> decoder;
-
const uint8_t kFirstPayloadValue = 1;
const uint8_t kSecondPayloadValue = 2;
@@ -886,9 +890,8 @@
EXPECT_CALL(decoder, Channels())
.WillRepeatedly(Return(kChannels));
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &decoder, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("L16", 8000, 1)));
// Insert one packet.
payload[0] = kFirstPayloadValue; // This will make Decode() fail.
@@ -945,8 +948,8 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
- NetEqDecoder::kDecoderPCM16B, "", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", 8000, 1)));
// Insert packets until the buffer flushes.
for (size_t i = 0; i <= config_.max_packets_in_buffer; ++i) {
@@ -965,7 +968,11 @@
TEST_F(NetEqImplTest, DecodedPayloadTooShort) {
UseNoMocks();
- CreateInstance();
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder));
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
@@ -980,8 +987,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- // Create a mock decoder object.
- MockAudioDecoder mock_decoder;
EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return());
EXPECT_CALL(mock_decoder, SampleRateHz())
.WillRepeatedly(Return(kSampleRateHz));
@@ -1001,9 +1006,8 @@
dummy_output + kPayloadLengthSamples - 5),
SetArgPointee<4>(AudioDecoder::kSpeech),
Return(rtc::checked_cast<int>(kPayloadLengthSamples - 5))));
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &mock_decoder, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("L16", 8000, 1)));
// Insert one packet.
EXPECT_EQ(NetEq::kOK,
@@ -1026,7 +1030,11 @@
// This test checks the behavior of NetEq when audio decoder fails.
TEST_F(NetEqImplTest, DecodingError) {
UseNoMocks();
- CreateInstance();
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder));
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
@@ -1047,8 +1055,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- // Create a mock decoder object.
- MockAudioDecoder mock_decoder;
EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return());
EXPECT_CALL(mock_decoder, SampleRateHz())
.WillRepeatedly(Return(kSampleRateHz));
@@ -1094,9 +1100,8 @@
Return(rtc::checked_cast<int>(kFrameLengthSamples))));
}
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &mock_decoder, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("L16", 8000, 1)));
// Insert packets.
for (int i = 0; i < 6; ++i) {
@@ -1140,7 +1145,11 @@
// This test checks the behavior of NetEq when audio decoder fails during CNG.
TEST_F(NetEqImplTest, DecodingErrorDuringInternalCng) {
UseNoMocks();
- CreateInstance();
+
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+ CreateInstance(
+ new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder));
const uint8_t kPayloadType = 17; // Just an arbitrary number.
const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
@@ -1161,8 +1170,6 @@
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
- // Create a mock decoder object.
- MockAudioDecoder mock_decoder;
EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return());
EXPECT_CALL(mock_decoder, SampleRateHz())
.WillRepeatedly(Return(kSampleRateHz));
@@ -1204,9 +1211,8 @@
Return(rtc::checked_cast<int>(kFrameLengthSamples))));
}
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- &mock_decoder, NetEqDecoder::kDecoderPCM16B,
- "dummy name", kPayloadType));
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", 8000, 1)));
// Insert 2 packets. This will make netEq into codec internal CNG mode.
for (int i = 0; i < 2; ++i) {
@@ -1261,6 +1267,34 @@
EXPECT_EQ(1u, tick_timer_->ticks());
}
+TEST_F(NetEqImplTest, SetBaseMinimumDelay) {
+ UseNoMocks();
+ use_mock_delay_manager_ = true;
+ CreateInstance();
+
+ EXPECT_CALL(*mock_delay_manager_, SetBaseMinimumDelay(_))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+
+ const int delay_ms = 200;
+
+ EXPECT_EQ(true, neteq_->SetBaseMinimumDelayMs(delay_ms));
+ EXPECT_EQ(false, neteq_->SetBaseMinimumDelayMs(delay_ms));
+}
+
+TEST_F(NetEqImplTest, GetBaseMinimumDelayMs) {
+ UseNoMocks();
+ use_mock_delay_manager_ = true;
+ CreateInstance();
+
+ const int delay_ms = 200;
+
+ EXPECT_CALL(*mock_delay_manager_, GetBaseMinimumDelay())
+ .WillOnce(Return(delay_ms));
+
+ EXPECT_EQ(delay_ms, neteq_->GetBaseMinimumDelayMs());
+}
+
TEST_F(NetEqImplTest, TargetDelayMs) {
UseNoMocks();
use_mock_delay_manager_ = true;
@@ -1289,6 +1323,43 @@
neteq_->InsertEmptyPacket(rtp_header);
}
+TEST_F(NetEqImplTest, EnableRtxHandling) {
+ UseNoMocks();
+ use_mock_delay_manager_ = true;
+ config_.enable_rtx_handling = true;
+ CreateInstance();
+ EXPECT_CALL(*mock_delay_manager_, BufferLimits(_, _))
+ .Times(1)
+ .WillOnce(DoAll(SetArgPointee<0>(0), SetArgPointee<1>(0)));
+
+ const int kPayloadLengthSamples = 80;
+ const size_t kPayloadLengthBytes = 2 * kPayloadLengthSamples; // PCM 16-bit.
+ const uint8_t kPayloadType = 17; // Just an arbitrary number.
+ const uint32_t kReceiveTime = 17;
+ uint8_t payload[kPayloadLengthBytes] = {0};
+ RTPHeader rtp_header;
+ rtp_header.payloadType = kPayloadType;
+ rtp_header.sequenceNumber = 0x1234;
+ rtp_header.timestamp = 0x12345678;
+ rtp_header.ssrc = 0x87654321;
+
+ EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", 8000, 1)));
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
+ AudioFrame output;
+ bool muted;
+ EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
+
+ // Insert second packet that was sent before the first packet.
+ rtp_header.sequenceNumber -= 1;
+ rtp_header.timestamp -= kPayloadLengthSamples;
+ EXPECT_CALL(*mock_delay_manager_,
+ Update(rtp_header.sequenceNumber, rtp_header.timestamp, _));
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
+}
+
class Decoder120ms : public AudioDecoder {
public:
Decoder120ms(int sample_rate_hz, SpeechType speech_type)
@@ -1328,13 +1399,17 @@
void CreateInstanceNoMocks() {
UseNoMocks();
- CreateInstance();
+ CreateInstance(decoder_factory_);
+ EXPECT_TRUE(neteq_->RegisterPayloadType(
+ kPayloadType, SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}})));
}
void CreateInstanceWithDelayManagerMock() {
UseNoMocks();
use_mock_delay_manager_ = true;
- CreateInstance();
+ CreateInstance(decoder_factory_);
+ EXPECT_TRUE(neteq_->RegisterPayloadType(
+ kPayloadType, SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}})));
}
uint32_t timestamp_diff_between_packets() const {
@@ -1364,14 +1439,18 @@
}
void Register120msCodec(AudioDecoder::SpeechType speech_type) {
- decoder_.reset(new Decoder120ms(kSamplingFreq_, speech_type));
- ASSERT_EQ(2u, decoder_->Channels());
- EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
- decoder_.get(), NetEqDecoder::kDecoderOpus_2ch,
- "120ms codec", kPayloadType));
+ const uint32_t sampling_freq = kSamplingFreq_;
+ decoder_factory_ =
+ new rtc::RefCountedObject<test::FunctionAudioDecoderFactory>(
+ [sampling_freq, speech_type]() {
+ std::unique_ptr<AudioDecoder> decoder =
+ absl::make_unique<Decoder120ms>(sampling_freq, speech_type);
+ RTC_CHECK_EQ(2, decoder->Channels());
+ return decoder;
+ });
}
- std::unique_ptr<Decoder120ms> decoder_;
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
AudioFrame output_;
const uint32_t kPayloadType = 17;
const uint32_t kSamplingFreq_ = 48000;
@@ -1379,8 +1458,8 @@
};
TEST_F(NetEqImplTest120ms, CodecInternalCng) {
- CreateInstanceNoMocks();
Register120msCodec(AudioDecoder::kComfortNoise);
+ CreateInstanceNoMocks();
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1391,8 +1470,8 @@
}
TEST_F(NetEqImplTest120ms, Normal) {
- CreateInstanceNoMocks();
Register120msCodec(AudioDecoder::kSpeech);
+ CreateInstanceNoMocks();
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1401,9 +1480,9 @@
}
TEST_F(NetEqImplTest120ms, Merge) {
+ Register120msCodec(AudioDecoder::kSpeech);
CreateInstanceWithDelayManagerMock();
- Register120msCodec(AudioDecoder::kSpeech);
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1420,8 +1499,8 @@
}
TEST_F(NetEqImplTest120ms, Expand) {
- CreateInstanceNoMocks();
Register120msCodec(AudioDecoder::kSpeech);
+ CreateInstanceNoMocks();
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1432,8 +1511,8 @@
}
TEST_F(NetEqImplTest120ms, FastAccelerate) {
- CreateInstanceWithDelayManagerMock();
Register120msCodec(AudioDecoder::kSpeech);
+ CreateInstanceWithDelayManagerMock();
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1450,8 +1529,8 @@
}
TEST_F(NetEqImplTest120ms, PreemptiveExpand) {
- CreateInstanceWithDelayManagerMock();
Register120msCodec(AudioDecoder::kSpeech);
+ CreateInstanceWithDelayManagerMock();
InsertPacket(first_timestamp());
GetFirstPacket();
@@ -1469,8 +1548,8 @@
}
TEST_F(NetEqImplTest120ms, Accelerate) {
- CreateInstanceWithDelayManagerMock();
Register120msCodec(AudioDecoder::kSpeech);
+ CreateInstanceWithDelayManagerMock();
InsertPacket(first_timestamp());
GetFirstPacket();
diff --git a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
index 57fc682..79059b7 100644
--- a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
@@ -10,10 +10,15 @@
#include <memory>
+#include "absl/memory/memory.h"
#include "api/audio/audio_frame.h"
+#include "api/audio_codecs/audio_decoder.h"
#include "common_types.h" // NOLINT(build/include)
-#include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h"
+
+#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/rtp_generator.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/audio_decoder_proxy_factory.h"
#include "test/gmock.h"
namespace webrtc {
@@ -118,10 +123,12 @@
bool fec_enabled_;
};
-class NetEqNetworkStatsTest : public NetEqExternalDecoderTest {
+class NetEqNetworkStatsTest {
public:
static const int kPayloadSizeByte = 30;
static const int kFrameSizeMs = 20;
+ static const uint8_t kPayloadType = 95;
+ static const int kOutputLengthMs = 10;
enum logic {
kIgnore,
@@ -146,17 +153,19 @@
NetEqNetworkStatistics stats_ref;
};
- NetEqNetworkStatsTest(NetEqDecoder codec,
- int sample_rate_hz,
- MockAudioDecoder* decoder)
- : NetEqExternalDecoderTest(codec, sample_rate_hz, decoder),
- external_decoder_(decoder),
- samples_per_ms_(sample_rate_hz / 1000),
+ NetEqNetworkStatsTest(const SdpAudioFormat& format, MockAudioDecoder* decoder)
+ : decoder_(decoder),
+ decoder_factory_(
+ new rtc::RefCountedObject<AudioDecoderProxyFactory>(decoder)),
+ samples_per_ms_(format.clockrate_hz / 1000),
frame_size_samples_(kFrameSizeMs * samples_per_ms_),
- rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
+ rtp_generator_(new RtpGenerator(samples_per_ms_)),
last_lost_time_(0),
packet_loss_interval_(0xffffffff) {
- Init();
+ NetEq::Config config;
+ config.sample_rate_hz = format.clockrate_hz;
+ neteq_ = absl::WrapUnique(NetEq::Create(config, decoder_factory_));
+ neteq_->RegisterPayloadType(kPayloadType, format);
}
bool Lost(uint32_t send_time) {
@@ -180,7 +189,7 @@
// expects.x = 2, 'x' in current stats should > 'x' in |stats_ref|
void CheckNetworkStatistics(NetEqNetworkStatsCheck expects) {
NetEqNetworkStatistics stats;
- neteq()->NetworkStatistics(&stats);
+ neteq_->NetworkStatistics(&stats);
#define CHECK_NETEQ_NETWORK_STATS(x) \
switch (expects.x) { \
@@ -211,9 +220,6 @@
CHECK_NETEQ_NETWORK_STATS(added_zero_samples);
#undef CHECK_NETEQ_NETWORK_STATS
-
- // Compare with CurrentDelay, which should be identical.
- EXPECT_EQ(stats.current_buffer_size_ms, neteq()->CurrentDelayMs());
}
void RunTest(int num_loops, NetEqNetworkStatsCheck expects) {
@@ -230,18 +236,26 @@
kPayloadType, frame_size_samples_, &rtp_header_);
if (!Lost(next_send_time)) {
static const uint8_t payload[kPayloadSizeByte] = {0};
- InsertPacket(rtp_header_, payload, next_send_time);
+ ASSERT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(rtp_header_, payload, next_send_time));
}
}
- GetOutputAudio(&output_frame_);
+ bool muted = true;
+ EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_frame_, &muted));
+ ASSERT_FALSE(muted);
+ EXPECT_EQ(decoder_->Channels(), output_frame_.num_channels_);
+ EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * samples_per_ms_),
+ output_frame_.samples_per_channel_);
+ EXPECT_EQ(48000, neteq_->last_output_sample_rate_hz());
+
time_now += kOutputLengthMs;
}
CheckNetworkStatistics(expects);
- neteq()->FlushBuffers();
+ neteq_->FlushBuffers();
}
void DecodeFecTest() {
- external_decoder_->set_fec_enabled(false);
+ decoder_->set_fec_enabled(false);
NetEqNetworkStatsCheck expects = {kIgnore, // current_buffer_size_ms
kIgnore, // preferred_buffer_size_ms
kIgnore, // jitter_peaks_found
@@ -264,7 +278,7 @@
RunTest(50, expects);
// Next we enable FEC.
- external_decoder_->set_fec_enabled(true);
+ decoder_->set_fec_enabled(true);
// If FEC fills in the lost packets, no packet loss will be counted.
expects.stats_ref.packet_loss_rate = 0;
expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 0;
@@ -296,10 +310,13 @@
}
private:
- MockAudioDecoder* external_decoder_;
+ MockAudioDecoder* decoder_;
+ rtc::scoped_refptr<AudioDecoderProxyFactory> decoder_factory_;
+ std::unique_ptr<NetEq> neteq_;
+
const int samples_per_ms_;
const size_t frame_size_samples_;
- std::unique_ptr<test::RtpGenerator> rtp_generator_;
+ std::unique_ptr<RtpGenerator> rtp_generator_;
RTPHeader rtp_header_;
uint32_t last_lost_time_;
uint32_t packet_loss_interval_;
@@ -308,21 +325,21 @@
TEST(NetEqNetworkStatsTest, DecodeFec) {
MockAudioDecoder decoder(48000, 1);
- NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder);
+ NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder);
test.DecodeFecTest();
EXPECT_CALL(decoder, Die()).Times(1);
}
TEST(NetEqNetworkStatsTest, StereoDecodeFec) {
MockAudioDecoder decoder(48000, 2);
- NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder);
+ NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder);
test.DecodeFecTest();
EXPECT_CALL(decoder, Die()).Times(1);
}
TEST(NetEqNetworkStatsTest, NoiseExpansionTest) {
MockAudioDecoder decoder(48000, 1);
- NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder);
+ NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder);
test.NoiseExpansionTest();
EXPECT_CALL(decoder, Die()).Times(1);
}
diff --git a/modules/audio_coding/neteq/neteq_stereo_unittest.cc b/modules/audio_coding/neteq/neteq_stereo_unittest.cc
index 3f86944..d25e8d6 100644
--- a/modules/audio_coding/neteq/neteq_stereo_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_stereo_unittest.cc
@@ -17,14 +17,13 @@
#include "api/audio/audio_frame.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
#include "modules/audio_coding/neteq/tools/rtp_generator.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -90,51 +89,12 @@
const std::string file_name =
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
input_file_.reset(new test::InputAudioFile(file_name));
- NetEqDecoder mono_decoder;
- NetEqDecoder multi_decoder;
- switch (sample_rate_hz_) {
- case 8000:
- mono_decoder = NetEqDecoder::kDecoderPCM16B;
- if (num_channels_ == 2) {
- multi_decoder = NetEqDecoder::kDecoderPCM16B_2ch;
- } else if (num_channels_ == 5) {
- multi_decoder = NetEqDecoder::kDecoderPCM16B_5ch;
- } else {
- FAIL() << "Only 2 and 5 channels supported for 8000 Hz.";
- }
- break;
- case 16000:
- mono_decoder = NetEqDecoder::kDecoderPCM16Bwb;
- if (num_channels_ == 2) {
- multi_decoder = NetEqDecoder::kDecoderPCM16Bwb_2ch;
- } else {
- FAIL() << "More than 2 channels is not supported for 16000 Hz.";
- }
- break;
- case 32000:
- mono_decoder = NetEqDecoder::kDecoderPCM16Bswb32kHz;
- if (num_channels_ == 2) {
- multi_decoder = NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch;
- } else {
- FAIL() << "More than 2 channels is not supported for 32000 Hz.";
- }
- break;
- case 48000:
- mono_decoder = NetEqDecoder::kDecoderPCM16Bswb48kHz;
- if (num_channels_ == 2) {
- multi_decoder = NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch;
- } else {
- FAIL() << "More than 2 channels is not supported for 48000 Hz.";
- }
- break;
- default:
- FAIL() << "We shouldn't get here.";
- }
- ASSERT_EQ(NetEq::kOK, neteq_mono_->RegisterPayloadType(mono_decoder, "mono",
- kPayloadTypeMono));
- ASSERT_EQ(NetEq::kOK,
- neteq_->RegisterPayloadType(multi_decoder, "multi-channel",
- kPayloadTypeMulti));
+ RTC_CHECK_GE(num_channels_, 2);
+ ASSERT_TRUE(neteq_mono_->RegisterPayloadType(
+ kPayloadTypeMono, SdpAudioFormat("l16", sample_rate_hz_, 1)));
+ ASSERT_TRUE(neteq_->RegisterPayloadType(
+ kPayloadTypeMulti,
+ SdpAudioFormat("l16", sample_rate_hz_, num_channels_)));
}
virtual void TearDown() {}
@@ -404,24 +364,24 @@
// Instantiate the tests. Each test is instantiated using the function above,
// so that all different parameter combinations are tested.
-INSTANTIATE_TEST_CASE_P(MultiChannel,
- NetEqStereoTestNoJitter,
- ::testing::ValuesIn(GetTestParameters()));
+INSTANTIATE_TEST_SUITE_P(MultiChannel,
+ NetEqStereoTestNoJitter,
+ ::testing::ValuesIn(GetTestParameters()));
-INSTANTIATE_TEST_CASE_P(MultiChannel,
- NetEqStereoTestPositiveDrift,
- ::testing::ValuesIn(GetTestParameters()));
+INSTANTIATE_TEST_SUITE_P(MultiChannel,
+ NetEqStereoTestPositiveDrift,
+ ::testing::ValuesIn(GetTestParameters()));
-INSTANTIATE_TEST_CASE_P(MultiChannel,
- NetEqStereoTestNegativeDrift,
- ::testing::ValuesIn(GetTestParameters()));
+INSTANTIATE_TEST_SUITE_P(MultiChannel,
+ NetEqStereoTestNegativeDrift,
+ ::testing::ValuesIn(GetTestParameters()));
-INSTANTIATE_TEST_CASE_P(MultiChannel,
- NetEqStereoTestDelays,
- ::testing::ValuesIn(GetTestParameters()));
+INSTANTIATE_TEST_SUITE_P(MultiChannel,
+ NetEqStereoTestDelays,
+ ::testing::ValuesIn(GetTestParameters()));
-INSTANTIATE_TEST_CASE_P(MultiChannel,
- NetEqStereoTestLosses,
- ::testing::ValuesIn(GetTestParameters()));
+INSTANTIATE_TEST_SUITE_P(MultiChannel,
+ NetEqStereoTestLosses,
+ ::testing::ValuesIn(GetTestParameters()));
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc
index e8b5023..6c67ca8 100644
--- a/modules/audio_coding/neteq/neteq_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_unittest.cc
@@ -27,17 +27,18 @@
#include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
#include "modules/audio_coding/neteq/tools/neteq_test.h"
#include "modules/audio_coding/neteq/tools/rtp_file_source.h"
+#include "modules/include/module_common_types_public.h"
#include "modules/rtp_rtcp/include/rtcp_statistics.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/ignore_wundef.h"
-#include "rtc_base/messagedigest.h"
+#include "rtc_base/message_digest.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/protobuf_utils.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/arch.h"
#include "test/field_trial.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
// This must come after test/gtest.h
#include "rtc_base/flags.h" // NOLINT(build/include)
@@ -129,10 +130,8 @@
void LoadDecoders(webrtc::NetEq* neteq) {
ASSERT_EQ(true,
neteq->RegisterPayloadType(0, SdpAudioFormat("pcmu", 8000, 1)));
- // Use non-SdpAudioFormat argument when registering PCMa, so that we get test
- // coverage for that as well.
- ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderPCMa,
- "pcma", 8));
+ ASSERT_EQ(true,
+ neteq->RegisterPayloadType(8, SdpAudioFormat("pcma", 8000, 1)));
#ifdef WEBRTC_CODEC_ILBC
ASSERT_EQ(true,
neteq->RegisterPayloadType(102, SdpAudioFormat("ilbc", 8000, 1)));
@@ -208,7 +207,7 @@
neteq_unittest::NetEqNetworkStatistics stats;
Convert(stats_raw, &stats);
- ProtoString stats_string;
+ std::string stats_string;
ASSERT_TRUE(stats.SerializeToString(&stats_string));
AddMessage(output_fp_, digest_.get(), stats_string);
#else
@@ -221,7 +220,7 @@
neteq_unittest::RtcpStatistics stats;
Convert(stats_raw, &stats);
- ProtoString stats_string;
+ std::string stats_string;
ASSERT_TRUE(stats.SerializeToString(&stats_string));
AddMessage(output_fp_, digest_.get(), stats_string);
#else
@@ -258,7 +257,6 @@
NetEqDecodingTest();
virtual void SetUp();
virtual void TearDown();
- void SelectDecoders(NetEqDecoder* used_codec);
void OpenInputFile(const std::string& rtp_file);
void Process();
@@ -402,10 +400,6 @@
ASSERT_EQ(0, neteq_->NetworkStatistics(¤t_network_stats));
ASSERT_NO_FATAL_FAILURE(network_stats.AddResult(current_network_stats));
- // Compare with CurrentDelay, which should be identical.
- EXPECT_EQ(current_network_stats.current_buffer_size_ms,
- neteq_->CurrentDelayMs());
-
// Verify that liftime stats and network stats report similar loss
// concealment rates.
auto lifetime_stats = neteq_->GetLifetimeStatistics();
@@ -464,16 +458,16 @@
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
const std::string output_checksum =
- PlatformChecksum("0c6dc227f781c81a229970f8fceda1a012498cba",
- "15c4a2202877a414515e218bdb7992f0ad53e5af", "not used",
- "0c6dc227f781c81a229970f8fceda1a012498cba",
- "25fc4c863caa499aa447a5b8d059f5452cbcc500");
+ PlatformChecksum("9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee",
+ "54a7e32f163663c0af35bf70bf45cefc24ad62ef", "not used",
+ "9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee",
+ "79496b0a1ef0a3824f3ee04789748a461bed643f");
const std::string network_stats_checksum =
- PlatformChecksum("4b2370f5c794741d2a46be5c7935c66ef3fb53e9",
- "e339cb2adf5ab3dfc21cb7205d670a34751e8336", "not used",
- "4b2370f5c794741d2a46be5c7935c66ef3fb53e9",
- "4b2370f5c794741d2a46be5c7935c66ef3fb53e9");
+ PlatformChecksum("c59b1f9f282b6d8733cdff975e3c150ca4a47d51",
+ "bca95e565996a4ffd6e2ac15736e08843bdca93b", "not used",
+ "c59b1f9f282b6d8733cdff975e3c150ca4a47d51",
+ "c59b1f9f282b6d8733cdff975e3c150ca4a47d51");
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
FLAG_gen_ref);
@@ -1661,6 +1655,7 @@
int packets_sent = 0;
int packets_received = 0;
int expected_delay = 0;
+ uint64_t expected_emitted_count = 0;
while (packets_received < kNumPackets) {
// Insert packet.
if (packets_sent < kNumPackets) {
@@ -1684,6 +1679,7 @@
// number of samples that are sent for play out.
int current_delay_ms = packets_delay * kPacketLenMs;
expected_delay += current_delay_ms * kSamples;
+ expected_emitted_count += kSamples;
}
}
@@ -1695,6 +1691,7 @@
// Check jitter buffer delay.
NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics();
EXPECT_EQ(expected_delay, static_cast<int>(stats.jitter_buffer_delay_ms));
+ EXPECT_EQ(expected_emitted_count, stats.jitter_buffer_emitted_count);
}
TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithoutLoss) {
@@ -1705,12 +1702,43 @@
TestJitterBufferDelay(true);
}
+TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithAcceleration) {
+ const int kPacketLenMs = 10; // All packets are of 10 ms size.
+ const size_t kSamples = kPacketLenMs * 16;
+ const size_t kPayloadBytes = kSamples * 2;
+ RTPHeader rtp_info;
+ rtp_info.ssrc = 0x1234; // Just an arbitrary SSRC.
+ rtp_info.payloadType = 94; // PCM16b WB codec.
+ rtp_info.markerBit = 0;
+ const uint8_t payload[kPayloadBytes] = {0};
+
+ neteq_->InsertPacket(rtp_info, payload, 0);
+
+ bool muted;
+ neteq_->GetAudio(&out_frame_, &muted);
+
+ rtp_info.sequenceNumber += 1;
+ rtp_info.timestamp += kSamples;
+ neteq_->InsertPacket(rtp_info, payload, 0);
+ rtp_info.sequenceNumber += 1;
+ rtp_info.timestamp += kSamples;
+ neteq_->InsertPacket(rtp_info, payload, 0);
+
+ // We have two packets in the buffer and kAccelerate operation will
+ // extract 20 ms of data.
+ neteq_->GetAudio(&out_frame_, &muted, Operations::kAccelerate);
+
+ // Check jitter buffer delay.
+ NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics();
+ EXPECT_EQ(10 * kSamples * 3, stats.jitter_buffer_delay_ms);
+ EXPECT_EQ(kSamples * 3, stats.jitter_buffer_emitted_count);
+}
+
namespace test {
TEST(NetEqNoTimeStretchingMode, RunTest) {
NetEq::Config config;
config.for_test_no_time_stretching = true;
auto codecs = NetEqTest::StandardDecoderMap();
- NetEqTest::ExtDecoderMap ext_codecs;
NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
{1, kRtpExtensionAudioLevel},
{3, kRtpExtensionAbsoluteSendTime},
@@ -1724,8 +1752,8 @@
new TimeLimitedNetEqInput(std::move(input), 20000));
std::unique_ptr<AudioSink> output(new VoidAudioSink);
NetEqTest::Callbacks callbacks;
- NetEqTest test(config, codecs, ext_codecs, std::move(input_time_limit),
- std::move(output), callbacks);
+ NetEqTest test(config, CreateBuiltinAudioDecoderFactory(), codecs, nullptr,
+ std::move(input_time_limit), std::move(output), callbacks);
test.Run();
const auto stats = test.SimulationStats();
EXPECT_EQ(0, stats.accelerate_rate);
diff --git a/modules/audio_coding/neteq/normal.h b/modules/audio_coding/neteq/normal.h
index 80451b5..2059c5a 100644
--- a/modules/audio_coding/neteq/normal.h
+++ b/modules/audio_coding/neteq/normal.h
@@ -16,7 +16,7 @@
#include "modules/audio_coding/neteq/defines.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc
index 343763b..e90fadc 100644
--- a/modules/audio_coding/neteq/packet_buffer.cc
+++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -287,6 +287,20 @@
return num_samples;
}
+size_t PacketBuffer::GetSpanSamples(size_t last_decoded_length) const {
+ if (buffer_.size() == 0) {
+ return 0;
+ }
+
+ size_t span = buffer_.back().timestamp - buffer_.front().timestamp;
+ if (buffer_.back().frame && buffer_.back().frame->Duration() > 0) {
+ span += buffer_.back().frame->Duration();
+ } else {
+ span += last_decoded_length;
+ }
+ return span;
+}
+
bool PacketBuffer::ContainsDtxOrCngPacket(
const DecoderDatabase* decoder_database) const {
RTC_DCHECK(decoder_database);
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h
index 0f5cd7f..0837027 100644
--- a/modules/audio_coding/neteq/packet_buffer.h
+++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -15,7 +15,7 @@
#include "modules/audio_coding/neteq/decoder_database.h"
#include "modules/audio_coding/neteq/packet.h"
#include "modules/include/module_common_types_public.h" // IsNewerTimestamp
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -121,6 +121,10 @@
// duplicate and redundant packets.
virtual size_t NumSamplesInBuffer(size_t last_decoded_length) const;
+ // Returns the total duration in samples that the packets in the buffer spans
+ // across.
+ virtual size_t GetSpanSamples(size_t last_decoded_length) const;
+
// Returns true if the packet buffer contains any DTX or CNG packets.
virtual bool ContainsDtxOrCngPacket(
const DecoderDatabase* decoder_database) const;
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc
index cb40d7d..7a381ee 100644
--- a/modules/audio_coding/neteq/packet_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -175,7 +175,7 @@
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(0))
.WillRepeatedly(Return(&info));
@@ -220,11 +220,11 @@
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info0(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info0(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(0))
.WillRepeatedly(Return(&info0));
- const DecoderDatabase::DecoderInfo info1(NetEqDecoder::kDecoderPCMa,
+ const DecoderDatabase::DecoderInfo info1(SdpAudioFormat("pcma", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(1))
.WillRepeatedly(Return(&info1));
@@ -407,7 +407,7 @@
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(0))
.WillRepeatedly(Return(&info));
@@ -447,12 +447,12 @@
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGnb,
+ const DecoderDatabase::DecoderInfo info_cng(SdpAudioFormat("cn", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(kCngPt))
.WillRepeatedly(Return(&info_cng));
- const DecoderDatabase::DecoderInfo info_speech(NetEqDecoder::kDecoderPCM16Bwb,
- absl::nullopt, factory);
+ const DecoderDatabase::DecoderInfo info_speech(
+ SdpAudioFormat("l16", 16000, 1), absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(kSpeechPt))
.WillRepeatedly(Return(&info_speech));
@@ -549,7 +549,7 @@
list.push_back(gen.NextPacket(payload_len)); // Valid packet.
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
EXPECT_CALL(decoder_database, GetDecoderInfo(0))
.WillRepeatedly(Return(&info));
diff --git a/modules/audio_coding/neteq/post_decode_vad.h b/modules/audio_coding/neteq/post_decode_vad.h
index 27d69a6..ca7cabf 100644
--- a/modules/audio_coding/neteq/post_decode_vad.h
+++ b/modules/audio_coding/neteq/post_decode_vad.h
@@ -16,7 +16,7 @@
#include "api/audio_codecs/audio_decoder.h"
#include "common_audio/vad/include/webrtc_vad.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/preemptive_expand.h b/modules/audio_coding/neteq/preemptive_expand.h
index 0f7b3bc..e7d2bad 100644
--- a/modules/audio_coding/neteq/preemptive_expand.h
+++ b/modules/audio_coding/neteq/preemptive_expand.h
@@ -15,7 +15,7 @@
#include <stdint.h>
#include "modules/audio_coding/neteq/time_stretch.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/random_vector.h b/modules/audio_coding/neteq/random_vector.h
index e8c7ba8..1d37600 100644
--- a/modules/audio_coding/neteq/random_vector.h
+++ b/modules/audio_coding/neteq/random_vector.h
@@ -14,7 +14,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/red_payload_splitter.h b/modules/audio_coding/neteq/red_payload_splitter.h
index 55063e7..c2e0a44 100644
--- a/modules/audio_coding/neteq/red_payload_splitter.h
+++ b/modules/audio_coding/neteq/red_payload_splitter.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_NETEQ_RED_PAYLOAD_SPLITTER_H_
#include "modules/audio_coding/neteq/packet.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
index 52fc1ba..b4cd8d7 100644
--- a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
+++ b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
@@ -18,7 +18,7 @@
#include <utility> // pair
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "modules/audio_coding/neteq/mock/mock_decoder_database.h"
+#include "modules/audio_coding/neteq/decoder_database.h"
#include "modules/audio_coding/neteq/packet.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
@@ -300,10 +300,11 @@
// do its job.
DecoderDatabase decoder_database(
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
- decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderCNGnb, "cng-nb");
- decoder_database.RegisterPayload(1, NetEqDecoder::kDecoderPCMu, "pcmu");
- decoder_database.RegisterPayload(2, NetEqDecoder::kDecoderAVT, "avt");
- decoder_database.RegisterPayload(3, NetEqDecoder::kDecoderILBC, "ilbc");
+ decoder_database.RegisterPayload(0, SdpAudioFormat("cn", 8000, 1));
+ decoder_database.RegisterPayload(1, SdpAudioFormat("pcmu", 8000, 1));
+ decoder_database.RegisterPayload(2,
+ SdpAudioFormat("telephone-event", 8000, 1));
+ decoder_database.RegisterPayload(3, SdpAudioFormat("ilbc", 8000, 1));
RedPayloadSplitter splitter;
splitter.CheckRedPayloads(&packet_list, decoder_database);
@@ -334,8 +335,8 @@
// do its job.
DecoderDatabase decoder_database(
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
- decoder_database.RegisterPayload(kRedPayloadType, NetEqDecoder::kDecoderRED,
- "red");
+ decoder_database.RegisterPayload(kRedPayloadType,
+ SdpAudioFormat("red", 8000, 1));
RedPayloadSplitter splitter;
splitter.CheckRedPayloads(&packet_list, decoder_database);
diff --git a/modules/audio_coding/neteq/statistics_calculator.cc b/modules/audio_coding/neteq/statistics_calculator.cc
index 50521fb..a0e9bca 100644
--- a/modules/audio_coding/neteq/statistics_calculator.cc
+++ b/modules/audio_coding/neteq/statistics_calculator.cc
@@ -216,7 +216,7 @@
}
void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
- discarded_packets_ += num_packets;
+ operations_and_state_.discarded_primary_packets += num_packets;
}
void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
@@ -246,6 +246,7 @@
void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
uint64_t waiting_time_ms) {
lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
+ lifetime_stats_.jitter_buffer_emitted_count += num_samples;
}
void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
@@ -257,6 +258,14 @@
buffer_full_counter_.RegisterSample();
}
+void StatisticsCalculator::ReceivedPacket() {
+ ++lifetime_stats_.jitter_buffer_packets_received;
+}
+
+void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) {
+ lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms;
+}
+
void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
int fs_hz) {
int outage_duration_ms = num_samples / (fs_hz / 1000);
diff --git a/modules/audio_coding/neteq/statistics_calculator.h b/modules/audio_coding/neteq/statistics_calculator.h
index 49b74a0..cb92f37 100644
--- a/modules/audio_coding/neteq/statistics_calculator.h
+++ b/modules/audio_coding/neteq/statistics_calculator.h
@@ -15,7 +15,7 @@
#include <string>
#include "modules/audio_coding/neteq/include/neteq.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -83,9 +83,15 @@
// Reports that |num_samples| samples were decoded from secondary packets.
void SecondaryDecodedSamples(int num_samples);
- // Rerport that the packet buffer was flushed.
+ // Reports that the packet buffer was flushed.
void FlushedPacketBuffer();
+ // Reports that the jitter buffer received a packet.
+ void ReceivedPacket();
+
+ // Reports that a received packet was delayed by |delay_ms| milliseconds.
+ virtual void RelativePacketArrivalDelay(size_t delay_ms);
+
// Logs a delayed packet outage event of |num_samples| expanded at a sample
// rate of |fs_hz|. A delayed packet outage event is defined as an expand
// period caused not by an actual packet loss, but by a delayed packet.
diff --git a/modules/audio_coding/neteq/statistics_calculator_unittest.cc b/modules/audio_coding/neteq/statistics_calculator_unittest.cc
index 0a4901d..1fb8e1c 100644
--- a/modules/audio_coding/neteq/statistics_calculator_unittest.cc
+++ b/modules/audio_coding/neteq/statistics_calculator_unittest.cc
@@ -104,4 +104,28 @@
EXPECT_EQ((50u << 14) / k10MsSamples, stats_output.speech_expand_rate);
}
+TEST(StatisticsCalculator, RelativePacketArrivalDelay) {
+ StatisticsCalculator stats;
+
+ stats.RelativePacketArrivalDelay(50);
+ NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics();
+ EXPECT_EQ(50u, stats_output.relative_packet_arrival_delay_ms);
+
+ stats.RelativePacketArrivalDelay(20);
+ stats_output = stats.GetLifetimeStatistics();
+ EXPECT_EQ(70u, stats_output.relative_packet_arrival_delay_ms);
+}
+
+TEST(StatisticsCalculator, ReceivedPacket) {
+ StatisticsCalculator stats;
+
+ stats.ReceivedPacket();
+ NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics();
+ EXPECT_EQ(1u, stats_output.jitter_buffer_packets_received);
+
+ stats.ReceivedPacket();
+ stats_output = stats.GetLifetimeStatistics();
+ EXPECT_EQ(2u, stats_output.jitter_buffer_packets_received);
+}
+
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/sync_buffer.h b/modules/audio_coding/neteq/sync_buffer.h
index d645e91..7f6c111 100644
--- a/modules/audio_coding/neteq/sync_buffer.h
+++ b/modules/audio_coding/neteq/sync_buffer.h
@@ -19,7 +19,7 @@
#include "modules/audio_coding/neteq/audio_multi_vector.h"
#include "modules/audio_coding/neteq/audio_vector.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/tick_timer.h b/modules/audio_coding/neteq/tick_timer.h
index 02f083e..724dd12 100644
--- a/modules/audio_coding/neteq/tick_timer.h
+++ b/modules/audio_coding/neteq/tick_timer.h
@@ -15,7 +15,7 @@
#include <memory>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/time_stretch.h b/modules/audio_coding/neteq/time_stretch.h
index 13ad2c8..9f86649 100644
--- a/modules/audio_coding/neteq/time_stretch.h
+++ b/modules/audio_coding/neteq/time_stretch.h
@@ -15,7 +15,7 @@
#include <string.h> // memset, size_t
#include "modules/audio_coding/neteq/audio_multi_vector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/time_stretch_unittest.cc b/modules/audio_coding/neteq/time_stretch_unittest.cc
index c96c7d4..6fced38 100644
--- a/modules/audio_coding/neteq/time_stretch_unittest.cc
+++ b/modules/audio_coding/neteq/time_stretch_unittest.cc
@@ -21,7 +21,7 @@
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
#include "rtc_base/checks.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/timestamp_scaler.h b/modules/audio_coding/neteq/timestamp_scaler.h
index 62f535c..93cb953 100644
--- a/modules/audio_coding/neteq/timestamp_scaler.h
+++ b/modules/audio_coding/neteq/timestamp_scaler.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_NETEQ_TIMESTAMP_SCALER_H_
#include "modules/audio_coding/neteq/packet.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
index 1f1445a..5b14189 100644
--- a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
+++ b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
@@ -25,7 +25,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use PCMu, because it doesn't use scaled timestamps.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 0;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -47,7 +47,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use PCMu, because it doesn't use scaled timestamps.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 0;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -74,7 +74,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -100,7 +100,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -130,9 +130,9 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info_g722(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info_g722(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
- const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGwb,
+ const DecoderDatabase::DecoderInfo info_cng(SdpAudioFormat("cn", 16000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadTypeG722 = 17;
static const uint8_t kRtpPayloadTypeCng = 13;
@@ -174,7 +174,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -204,7 +204,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -238,7 +238,7 @@
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
// Use G722, which has a factor 2 scaling.
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
@@ -279,7 +279,7 @@
TEST(TimestampScaler, TestOpusLargeStep) {
MockDecoderDatabase db;
auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderOpus,
+ const DecoderDatabase::DecoderInfo info(SdpAudioFormat("opus", 48000, 2),
absl::nullopt, factory);
static const uint8_t kRtpPayloadType = 17;
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
diff --git a/modules/audio_coding/neteq/tools/audio_checksum.h b/modules/audio_coding/neteq/tools/audio_checksum.h
index ee8c582..e4306fa 100644
--- a/modules/audio_coding/neteq/tools/audio_checksum.h
+++ b/modules/audio_coding/neteq/tools/audio_checksum.h
@@ -16,9 +16,9 @@
#include "modules/audio_coding/neteq/tools/audio_sink.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/string_encode.h"
#include "rtc_base/system/arch.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/tools/audio_loop.h b/modules/audio_coding/neteq/tools/audio_loop.h
index c7788a6..cd764cc 100644
--- a/modules/audio_coding/neteq/tools/audio_loop.h
+++ b/modules/audio_coding/neteq/tools/audio_loop.h
@@ -15,7 +15,7 @@
#include <string>
#include "api/array_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/audio_sink.h b/modules/audio_coding/neteq/tools/audio_sink.h
index be2a315..68825eb 100644
--- a/modules/audio_coding/neteq/tools/audio_sink.h
+++ b/modules/audio_coding/neteq/tools/audio_sink.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_SINK_H_
#include "api/audio/audio_frame.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h b/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h
index 4e216e4..7adb15b 100644
--- a/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h
+++ b/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h
@@ -14,9 +14,8 @@
#include <stdio.h>
#include <string>
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/tools/packet_source.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.cc b/modules/audio_coding/neteq/tools/input_audio_file.cc
index 6d11064..d5e2862 100644
--- a/modules/audio_coding/neteq/tools/input_audio_file.cc
+++ b/modules/audio_coding/neteq/tools/input_audio_file.cc
@@ -18,9 +18,11 @@
InputAudioFile::InputAudioFile(const std::string file_name, bool loop_at_end)
: loop_at_end_(loop_at_end) {
fp_ = fopen(file_name.c_str(), "rb");
+ RTC_DCHECK(fp_) << file_name << " could not be opened.";
}
InputAudioFile::~InputAudioFile() {
+ RTC_DCHECK(fp_);
fclose(fp_);
}
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.h b/modules/audio_coding/neteq/tools/input_audio_file.h
index b36dc24..4335a99 100644
--- a/modules/audio_coding/neteq/tools/input_audio_file.h
+++ b/modules/audio_coding/neteq/tools/input_audio_file.h
@@ -15,7 +15,7 @@
#include <string>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
deleted file mode 100644
index 3bd218b..0000000
--- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2015 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/audio_coding/neteq/tools/neteq_external_decoder_test.h"
-
-#include "api/audio/audio_frame.h"
-#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "rtc_base/format_macros.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace test {
-
-NetEqExternalDecoderTest::NetEqExternalDecoderTest(NetEqDecoder codec,
- int sample_rate_hz,
- AudioDecoder* decoder)
- : codec_(codec),
- decoder_(decoder),
- sample_rate_hz_(sample_rate_hz),
- channels_(decoder_->Channels()) {
- NetEq::Config config;
- config.sample_rate_hz = sample_rate_hz_;
- neteq_.reset(NetEq::Create(config, CreateBuiltinAudioDecoderFactory()));
-}
-
-void NetEqExternalDecoderTest::Init() {
- ASSERT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(decoder_, codec_, name_,
- kPayloadType));
-}
-
-void NetEqExternalDecoderTest::InsertPacket(
- RTPHeader rtp_header,
- rtc::ArrayView<const uint8_t> payload,
- uint32_t receive_timestamp) {
- ASSERT_EQ(NetEq::kOK,
- neteq_->InsertPacket(rtp_header, payload, receive_timestamp));
-}
-
-void NetEqExternalDecoderTest::GetOutputAudio(AudioFrame* output) {
- // Get audio from regular instance.
- bool muted;
- EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(output, &muted));
- ASSERT_FALSE(muted);
- EXPECT_EQ(channels_, output->num_channels_);
- EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
- output->samples_per_channel_);
- EXPECT_EQ(sample_rate_hz_, neteq_->last_output_sample_rate_hz());
-}
-
-} // namespace test
-} // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h
deleted file mode 100644
index 78f0085..0000000
--- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2015 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.
- */
-
-#ifndef MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_
-#define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_
-
-#include <memory>
-#include <string>
-
-#include "api/audio_codecs/audio_decoder.h"
-#include "common_types.h" // NOLINT(build/include)
-#include "modules/audio_coding/neteq/include/neteq.h"
-
-namespace webrtc {
-namespace test {
-// This test class provides a way run NetEQ with an external decoder.
-class NetEqExternalDecoderTest {
- protected:
- static const uint8_t kPayloadType = 95;
- static const int kOutputLengthMs = 10;
-
- // The external decoder |decoder| is suppose to be of type |codec|.
- NetEqExternalDecoderTest(NetEqDecoder codec,
- int sample_rate_hz,
- AudioDecoder* decoder);
-
- virtual ~NetEqExternalDecoderTest() {}
-
- // In Init(), we register the external decoder.
- void Init();
-
- // Inserts a new packet with |rtp_header| and |payload| of
- // |payload_size_bytes| bytes. The |receive_timestamp| is an indication
- // of the time when the packet was received, and should be measured with
- // the same tick rate as the RTP timestamp of the current payload.
- virtual void InsertPacket(RTPHeader rtp_header,
- rtc::ArrayView<const uint8_t> payload,
- uint32_t receive_timestamp);
-
- // Get 10 ms of audio data.
- void GetOutputAudio(AudioFrame* output);
-
- NetEq* neteq() { return neteq_.get(); }
-
- private:
- NetEqDecoder codec_;
- std::string name_ = "dummy name";
- AudioDecoder* decoder_;
- int sample_rate_hz_;
- size_t channels_;
- std::unique_ptr<NetEq> neteq_;
-};
-
-} // namespace test
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_
diff --git a/modules/audio_coding/neteq/tools/neteq_input.h b/modules/audio_coding/neteq/tools/neteq_input.h
index b9cba09..732b807 100644
--- a/modules/audio_coding/neteq/tools/neteq_input.h
+++ b/modules/audio_coding/neteq/tools/neteq_input.h
@@ -16,7 +16,6 @@
#include <string>
#include "absl/types/optional.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/tools/packet.h"
#include "modules/audio_coding/neteq/tools/packet_source.h"
#include "rtc_base/buffer.h"
diff --git a/modules/audio_coding/neteq/tools/neteq_performance_test.cc b/modules/audio_coding/neteq/tools/neteq_performance_test.cc
index 52524fe..61f52bb 100644
--- a/modules/audio_coding/neteq/tools/neteq_performance_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_performance_test.cc
@@ -12,14 +12,13 @@
#include "api/audio/audio_frame.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/audio_loop.h"
#include "modules/audio_coding/neteq/tools/rtp_generator.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/clock.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
using webrtc::NetEq;
using webrtc::test::AudioLoop;
@@ -34,8 +33,6 @@
const std::string kInputFileName =
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
const int kSampRateHz = 32000;
- const webrtc::NetEqDecoder kDecoderType =
- webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz;
const std::string kDecoderName = "pcm16-swb32";
const int kPayloadType = 95;
@@ -44,7 +41,8 @@
config.sample_rate_hz = kSampRateHz;
NetEq* neteq = NetEq::Create(config, CreateBuiltinAudioDecoderFactory());
// Register decoder in |neteq|.
- if (neteq->RegisterPayloadType(kDecoderType, kDecoderName, kPayloadType) != 0)
+ if (!neteq->RegisterPayloadType(kPayloadType,
+ SdpAudioFormat("l16", kSampRateHz, 1)))
return -1;
// Set up AudioLoop object.
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.cc b/modules/audio_coding/neteq/tools/neteq_quality_test.cc
index 2ee6779..a0e7667 100644
--- a/modules/audio_coding/neteq/tools/neteq_quality_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_quality_test.cc
@@ -17,7 +17,7 @@
#include "modules/audio_coding/neteq/tools/output_wav_file.h"
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "rtc_base/checks.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace test {
@@ -135,8 +135,8 @@
NetEqQualityTest::NetEqQualityTest(int block_duration_ms,
int in_sampling_khz,
int out_sampling_khz,
- NetEqDecoder decoder_type)
- : decoder_type_(decoder_type),
+ const SdpAudioFormat& format)
+ : audio_format_(format),
channels_(static_cast<size_t>(FLAG_channels)),
decoded_time_ms_(0),
decodable_time_ms_(0),
@@ -271,8 +271,7 @@
}
void NetEqQualityTest::SetUp() {
- ASSERT_EQ(0,
- neteq_->RegisterPayloadType(decoder_type_, "noname", kPayloadType));
+ ASSERT_TRUE(neteq_->RegisterPayloadType(kPayloadType, audio_format_));
rtp_generator_->set_drift_factor(drift_factor_);
int units = block_duration_ms_ / kPacketLossTimeUnitMs;
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.h b/modules/audio_coding/neteq/tools/neteq_quality_test.h
index 3d7760e..82a6a64 100644
--- a/modules/audio_coding/neteq/tools/neteq_quality_test.h
+++ b/modules/audio_coding/neteq/tools/neteq_quality_test.h
@@ -14,7 +14,6 @@
#include <fstream>
#include <memory>
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/audio_sink.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
@@ -35,7 +34,7 @@
class LossModel {
public:
- virtual ~LossModel(){};
+ virtual ~LossModel() {}
virtual bool Lost(int now_ms) = 0;
};
@@ -99,7 +98,7 @@
NetEqQualityTest(int block_duration_ms,
int in_sampling_khz,
int out_sampling_khz,
- NetEqDecoder decoder_type);
+ const SdpAudioFormat& format);
~NetEqQualityTest() override;
void SetUp() override;
@@ -133,7 +132,7 @@
// Write to log file. Usage Log() << ...
std::ofstream& Log();
- NetEqDecoder decoder_type_;
+ SdpAudioFormat audio_format_;
const size_t channels_;
private:
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index c2726eb..36c03b8 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -17,6 +17,10 @@
#include "system_wrappers/include/field_trial.h"
#include "test/field_trial.h"
+namespace {
+
+using TestConfig = webrtc::test::NetEqTestFactory::Config;
+
WEBRTC_DEFINE_bool(codec_map,
false,
"Prints the mapping between RTP payload type and "
@@ -28,6 +32,185 @@
"E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
" will assign the group Enable to field trial WebRTC-FooFeature.");
WEBRTC_DEFINE_bool(help, false, "Prints this message");
+// Define command line flags.
+WEBRTC_DEFINE_int(pcmu,
+ TestConfig::default_pcmu(),
+ "RTP payload type for PCM-u");
+WEBRTC_DEFINE_int(pcma,
+ TestConfig::default_pcma(),
+ "RTP payload type for PCM-a");
+WEBRTC_DEFINE_int(ilbc,
+ TestConfig::default_ilbc(),
+ "RTP payload type for iLBC");
+WEBRTC_DEFINE_int(isac,
+ TestConfig::default_isac(),
+ "RTP payload type for iSAC");
+WEBRTC_DEFINE_int(isac_swb,
+ TestConfig::default_isac_swb(),
+ "RTP payload type for iSAC-swb (32 kHz)");
+WEBRTC_DEFINE_int(opus,
+ TestConfig::default_opus(),
+ "RTP payload type for Opus");
+WEBRTC_DEFINE_int(pcm16b,
+ TestConfig::default_pcm16b(),
+ "RTP payload type for PCM16b-nb (8 kHz)");
+WEBRTC_DEFINE_int(pcm16b_wb,
+ TestConfig::default_pcm16b_wb(),
+ "RTP payload type for PCM16b-wb (16 kHz)");
+WEBRTC_DEFINE_int(pcm16b_swb32,
+ TestConfig::default_pcm16b_swb32(),
+ "RTP payload type for PCM16b-swb32 (32 kHz)");
+WEBRTC_DEFINE_int(pcm16b_swb48,
+ TestConfig::default_pcm16b_swb48(),
+ "RTP payload type for PCM16b-swb48 (48 kHz)");
+WEBRTC_DEFINE_int(g722,
+ TestConfig::default_g722(),
+ "RTP payload type for G.722");
+WEBRTC_DEFINE_int(avt,
+ TestConfig::default_avt(),
+ "RTP payload type for AVT/DTMF (8 kHz)");
+WEBRTC_DEFINE_int(avt_16,
+ TestConfig::default_avt_16(),
+ "RTP payload type for AVT/DTMF (16 kHz)");
+WEBRTC_DEFINE_int(avt_32,
+ TestConfig::default_avt_32(),
+ "RTP payload type for AVT/DTMF (32 kHz)");
+WEBRTC_DEFINE_int(avt_48,
+ TestConfig::default_avt_48(),
+ "RTP payload type for AVT/DTMF (48 kHz)");
+WEBRTC_DEFINE_int(red,
+ TestConfig::default_red(),
+ "RTP payload type for redundant audio (RED)");
+WEBRTC_DEFINE_int(cn_nb,
+ TestConfig::default_cn_nb(),
+ "RTP payload type for comfort noise (8 kHz)");
+WEBRTC_DEFINE_int(cn_wb,
+ TestConfig::default_cn_wb(),
+ "RTP payload type for comfort noise (16 kHz)");
+WEBRTC_DEFINE_int(cn_swb32,
+ TestConfig::default_cn_swb32(),
+ "RTP payload type for comfort noise (32 kHz)");
+WEBRTC_DEFINE_int(cn_swb48,
+ TestConfig::default_cn_swb48(),
+ "RTP payload type for comfort noise (48 kHz)");
+WEBRTC_DEFINE_string(replacement_audio_file,
+ "",
+ "A PCM file that will be used to populate dummy"
+ " RTP packets");
+WEBRTC_DEFINE_string(
+ ssrc,
+ "",
+ "Only use packets with this SSRC (decimal or hex, the latter "
+ "starting with 0x)");
+WEBRTC_DEFINE_int(audio_level,
+ TestConfig::default_audio_level(),
+ "Extension ID for audio level (RFC 6464)");
+WEBRTC_DEFINE_int(abs_send_time,
+ TestConfig::default_abs_send_time(),
+ "Extension ID for absolute sender time");
+WEBRTC_DEFINE_int(transport_seq_no,
+ TestConfig::default_transport_seq_no(),
+ "Extension ID for transport sequence number");
+WEBRTC_DEFINE_int(video_content_type,
+ TestConfig::default_video_content_type(),
+ "Extension ID for video content type");
+WEBRTC_DEFINE_int(video_timing,
+ TestConfig::default_video_timing(),
+ "Extension ID for video timing");
+WEBRTC_DEFINE_bool(matlabplot,
+ false,
+ "Generates a matlab script for plotting the delay profile");
+WEBRTC_DEFINE_bool(pythonplot,
+ false,
+ "Generates a python script for plotting the delay profile");
+WEBRTC_DEFINE_bool(textlog,
+ false,
+ "Generates a text log describing the simulation on a "
+ "step-by-step basis.");
+WEBRTC_DEFINE_bool(concealment_events, false, "Prints concealment events");
+WEBRTC_DEFINE_int(max_nr_packets_in_buffer,
+ TestConfig::default_max_nr_packets_in_buffer(),
+ "Maximum allowed number of packets in the buffer");
+WEBRTC_DEFINE_bool(enable_fast_accelerate,
+ false,
+ "Enables jitter buffer fast accelerate");
+
+// Parses the input string for a valid SSRC (at the start of the string). If a
+// valid SSRC is found, it is written to the output variable |ssrc|, and true is
+// returned. Otherwise, false is returned.
+bool ParseSsrc(const std::string& str, uint32_t* ssrc) {
+ if (str.empty())
+ return true;
+ int base = 10;
+ // Look for "0x" or "0X" at the start and change base to 16 if found.
+ if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0))
+ base = 16;
+ errno = 0;
+ char* end_ptr;
+ unsigned long value = strtoul(str.c_str(), &end_ptr, base); // NOLINT
+ if (value == ULONG_MAX && errno == ERANGE)
+ return false; // Value out of range for unsigned long.
+ if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) // NOLINT
+ return false; // Value out of range for uint32_t.
+ if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length()))
+ return false; // Part of the string was not parsed.
+ *ssrc = static_cast<uint32_t>(value);
+ return true;
+}
+
+static bool ValidateExtensionId(int value) {
+ if (value > 0 && value <= 255) // Value is ok.
+ return true;
+ printf("Extension ID must be between 1 and 255, not %d\n",
+ static_cast<int>(value));
+ return false;
+}
+
+// Flag validators.
+bool ValidatePayloadType(int value) {
+ if (value >= 0 && value <= 127) // Value is ok.
+ return true;
+ printf("Payload type must be between 0 and 127, not %d\n",
+ static_cast<int>(value));
+ return false;
+}
+
+bool ValidateSsrcValue(const std::string& str) {
+ uint32_t dummy_ssrc;
+ if (ParseSsrc(str, &dummy_ssrc)) // Value is ok.
+ return true;
+ printf("Invalid SSRC: %s\n", str.c_str());
+ return false;
+}
+
+void PrintCodecMappingEntry(const char* codec, int flag) {
+ std::cout << codec << ": " << flag << std::endl;
+}
+
+void PrintCodecMapping() {
+ PrintCodecMappingEntry("PCM-u", FLAG_pcmu);
+ PrintCodecMappingEntry("PCM-a", FLAG_pcma);
+ PrintCodecMappingEntry("iLBC", FLAG_ilbc);
+ PrintCodecMappingEntry("iSAC", FLAG_isac);
+ PrintCodecMappingEntry("iSAC-swb (32 kHz)", FLAG_isac_swb);
+ PrintCodecMappingEntry("Opus", FLAG_opus);
+ PrintCodecMappingEntry("PCM16b-nb (8 kHz)", FLAG_pcm16b);
+ PrintCodecMappingEntry("PCM16b-wb (16 kHz)", FLAG_pcm16b_wb);
+ PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)", FLAG_pcm16b_swb32);
+ PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)", FLAG_pcm16b_swb48);
+ PrintCodecMappingEntry("G.722", FLAG_g722);
+ PrintCodecMappingEntry("AVT/DTMF (8 kHz)", FLAG_avt);
+ PrintCodecMappingEntry("AVT/DTMF (16 kHz)", FLAG_avt_16);
+ PrintCodecMappingEntry("AVT/DTMF (32 kHz)", FLAG_avt_32);
+ PrintCodecMappingEntry("AVT/DTMF (48 kHz)", FLAG_avt_48);
+ PrintCodecMappingEntry("redundant audio (RED)", FLAG_red);
+ PrintCodecMappingEntry("comfort noise (8 kHz)", FLAG_cn_nb);
+ PrintCodecMappingEntry("comfort noise (16 kHz)", FLAG_cn_wb);
+ PrintCodecMappingEntry("comfort noise (32 kHz)", FLAG_cn_swb32);
+ PrintCodecMappingEntry("comfort noise (48 kHz)", FLAG_cn_swb48);
+}
+
+} // namespace
int main(int argc, char* argv[]) {
webrtc::test::NetEqTestFactory factory;
@@ -48,21 +231,85 @@
exit(0);
}
if (FLAG_codec_map) {
- factory.PrintCodecMap();
+ PrintCodecMapping();
+ exit(0);
}
if (argc != 3) {
- if (FLAG_codec_map) {
- // We have already printed the codec map. Just end the program.
- exit(0);
- }
// Print usage information.
std::cout << usage;
exit(0);
}
+ RTC_CHECK(ValidatePayloadType(FLAG_pcmu));
+ RTC_CHECK(ValidatePayloadType(FLAG_pcma));
+ RTC_CHECK(ValidatePayloadType(FLAG_ilbc));
+ RTC_CHECK(ValidatePayloadType(FLAG_isac));
+ RTC_CHECK(ValidatePayloadType(FLAG_isac_swb));
+ RTC_CHECK(ValidatePayloadType(FLAG_opus));
+ RTC_CHECK(ValidatePayloadType(FLAG_pcm16b));
+ RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_wb));
+ RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb32));
+ RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb48));
+ RTC_CHECK(ValidatePayloadType(FLAG_g722));
+ RTC_CHECK(ValidatePayloadType(FLAG_avt));
+ RTC_CHECK(ValidatePayloadType(FLAG_avt_16));
+ RTC_CHECK(ValidatePayloadType(FLAG_avt_32));
+ RTC_CHECK(ValidatePayloadType(FLAG_avt_48));
+ RTC_CHECK(ValidatePayloadType(FLAG_red));
+ RTC_CHECK(ValidatePayloadType(FLAG_cn_nb));
+ RTC_CHECK(ValidatePayloadType(FLAG_cn_wb));
+ RTC_CHECK(ValidatePayloadType(FLAG_cn_swb32));
+ RTC_CHECK(ValidatePayloadType(FLAG_cn_swb48));
+ RTC_CHECK(ValidateSsrcValue(FLAG_ssrc));
+ RTC_CHECK(ValidateExtensionId(FLAG_audio_level));
+ RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time));
+ RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no));
+ RTC_CHECK(ValidateExtensionId(FLAG_video_content_type));
+ RTC_CHECK(ValidateExtensionId(FLAG_video_timing));
+
webrtc::test::ValidateFieldTrialsStringOrDie(FLAG_force_fieldtrials);
webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials);
+ webrtc::test::NetEqTestFactory::Config config;
+ config.pcmu = FLAG_pcmu;
+ config.pcma = FLAG_pcma;
+ config.ilbc = FLAG_ilbc;
+ config.isac = FLAG_isac;
+ config.isac_swb = FLAG_isac_swb;
+ config.opus = FLAG_opus;
+ config.pcm16b = FLAG_pcm16b;
+ config.pcm16b_wb = FLAG_pcm16b_wb;
+ config.pcm16b_swb32 = FLAG_pcm16b_swb32;
+ config.pcm16b_swb48 = FLAG_pcm16b_swb48;
+ config.g722 = FLAG_g722;
+ config.avt = FLAG_avt;
+ config.avt_16 = FLAG_avt_16;
+ config.avt_32 = FLAG_avt_32;
+ config.avt_48 = FLAG_avt_48;
+ config.red = FLAG_red;
+ config.cn_nb = FLAG_cn_nb;
+ config.cn_wb = FLAG_cn_wb;
+ config.cn_swb32 = FLAG_cn_swb32;
+ config.cn_swb48 = FLAG_cn_swb48;
+ config.replacement_audio_file = FLAG_replacement_audio_file;
+ config.audio_level = FLAG_audio_level;
+ config.abs_send_time = FLAG_abs_send_time;
+ config.transport_seq_no = FLAG_transport_seq_no;
+ config.video_content_type = FLAG_video_content_type;
+ config.video_timing = FLAG_video_timing;
+ config.matlabplot = FLAG_matlabplot;
+ config.pythonplot = FLAG_pythonplot;
+ config.textlog = FLAG_textlog;
+ config.concealment_events = FLAG_concealment_events;
+ config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
+ config.enable_fast_accelerate = FLAG_enable_fast_accelerate;
+ // Check if an SSRC value was provided.
+ if (strlen(FLAG_ssrc) > 0) {
+ uint32_t ssrc;
+ RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed.";
+ config.ssrc_filter = absl::make_optional(ssrc);
+ }
+
std::unique_ptr<webrtc::test::NetEqTest> test =
- factory.InitializeTest(argv[1], argv[2]);
+ factory.InitializeTest(argv[1], argv[2], config);
test->Run();
return 0;
}
diff --git a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
index 1a52176..291fc24 100644
--- a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
+++ b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
@@ -16,7 +16,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/neteq_test.cc b/modules/audio_coding/neteq/tools/neteq_test.cc
index 421f380..97e71bf 100644
--- a/modules/audio_coding/neteq/tools/neteq_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_test.cc
@@ -10,9 +10,10 @@
#include "modules/audio_coding/neteq/tools/neteq_test.h"
+#include <iomanip>
#include <iostream>
-#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
namespace webrtc {
namespace test {
@@ -50,20 +51,21 @@
}
NetEqTest::NetEqTest(const NetEq::Config& config,
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
const DecoderMap& codecs,
- const ExtDecoderMap& ext_codecs,
+ std::unique_ptr<std::ofstream> text_log,
std::unique_ptr<NetEqInput> input,
std::unique_ptr<AudioSink> output,
Callbacks callbacks)
- : neteq_(NetEq::Create(config, CreateBuiltinAudioDecoderFactory())),
+ : neteq_(NetEq::Create(config, decoder_factory)),
input_(std::move(input)),
output_(std::move(output)),
callbacks_(callbacks),
- sample_rate_hz_(config.sample_rate_hz) {
+ sample_rate_hz_(config.sample_rate_hz),
+ text_log_(std::move(text_log)) {
RTC_CHECK(!config.enable_muted_state)
<< "The code does not handle enable_muted_state";
RegisterDecoders(codecs);
- RegisterExternalDecoders(ext_codecs);
}
NetEqTest::~NetEqTest() = default;
@@ -117,7 +119,36 @@
current_state_.packet_iat_ms.push_back(time_now_ms -
*last_packet_time_ms_);
}
+ if (text_log_) {
+ const auto ops_state = neteq_->GetOperationsAndState();
+ const auto delta_wallclock =
+ last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1;
+ const auto delta_timestamp =
+ last_packet_timestamp_
+ ? (static_cast<int64_t>(packet_data->header.timestamp) -
+ *last_packet_timestamp_) *
+ 1000 / sample_rate_hz_
+ : -1;
+ const auto packet_size_bytes =
+ packet_data->payload.size() == 12
+ ? ByteReader<uint32_t>::ReadLittleEndian(
+ &packet_data->payload[8])
+ : -1;
+ *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms
+ << ", delta wc: " << std::setw(4) << delta_wallclock
+ << ", seq_no: " << packet_data->header.sequenceNumber
+ << ", timestamp: " << std::setw(10)
+ << packet_data->header.timestamp
+ << ", delta ts: " << std::setw(4) << delta_timestamp
+ << ", size: " << std::setw(5) << packet_size_bytes
+ << ", frame size: " << std::setw(3)
+ << ops_state.current_frame_size_ms
+ << ", buffer size: " << std::setw(4)
+ << ops_state.current_buffer_size_ms << std::endl;
+ }
last_packet_time_ms_ = absl::make_optional<int>(time_now_ms);
+ last_packet_timestamp_ =
+ absl::make_optional<uint32_t>(packet_data->header.timestamp);
}
// Check if it is time to get output audio.
@@ -186,6 +217,39 @@
// Consider the whole frame to be the result of normal playout.
result.action_times_ms[Action::kNormal] = 10;
}
+ auto lifetime_stats = LifetimeStats();
+ if (text_log_) {
+ const bool plc =
+ (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC) ||
+ (out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG);
+ const bool cng = out_frame.speech_type_ == AudioFrame::SpeechType::kCNG;
+ const bool voice_concealed =
+ lifetime_stats.voice_concealed_samples >
+ prev_lifetime_stats_.voice_concealed_samples;
+ *text_log_ << "GetAudio - wallclock: " << std::setw(5) << time_now_ms
+ << ", delta wc: " << std::setw(4)
+ << (input_->NextEventTime().value_or(time_now_ms) -
+ start_time_ms)
+ << ", CNG: " << cng << ", PLC: " << plc
+ << ", voice concealed: " << voice_concealed
+ << ", buffer size: " << std::setw(4)
+ << current_state_.current_delay_ms << std::endl;
+ if (operations_state.discarded_primary_packets >
+ prev_ops_state_.discarded_primary_packets) {
+ *text_log_ << "Discarded "
+ << (operations_state.discarded_primary_packets -
+ prev_ops_state_.discarded_primary_packets)
+ << " primary packets." << std::endl;
+ }
+ if (operations_state.packet_buffer_flushes >
+ prev_ops_state_.packet_buffer_flushes) {
+ *text_log_ << "Flushed packet buffer "
+ << (operations_state.packet_buffer_flushes -
+ prev_ops_state_.packet_buffer_flushes)
+ << " times." << std::endl;
+ }
+ }
+ prev_lifetime_stats_ = lifetime_stats;
result.is_simulation_finished = input_->ended();
prev_ops_state_ = operations_state;
return result;
@@ -217,53 +281,40 @@
NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
DecoderMap codecs = {
- {0, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")},
- {8, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")},
+ {0, SdpAudioFormat("pcmu", 8000, 1)},
+ {8, SdpAudioFormat("pcma", 8000, 1)},
#ifdef WEBRTC_CODEC_ILBC
- {102, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")},
+ {102, SdpAudioFormat("ilbc", 8000, 1)},
#endif
- {103, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")},
+ {103, SdpAudioFormat("isac", 16000, 1)},
#if !defined(WEBRTC_ANDROID)
- {104, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")},
+ {104, SdpAudioFormat("isac", 32000, 1)},
#endif
#ifdef WEBRTC_CODEC_OPUS
- {111, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")},
+ {111, SdpAudioFormat("opus", 48000, 2)},
#endif
- {93, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")},
- {94, std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")},
- {95, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")},
- {96, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")},
- {9, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
- {106, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
- {114, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
- {115, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
- {116, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
- {117, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
- {13, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
- {98, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
- {99, std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")},
- {100, std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")}
+ {93, SdpAudioFormat("l16", 8000, 1)},
+ {94, SdpAudioFormat("l16", 16000, 1)},
+ {95, SdpAudioFormat("l16", 32000, 1)},
+ {96, SdpAudioFormat("l16", 48000, 1)},
+ {9, SdpAudioFormat("g722", 8000, 1)},
+ {106, SdpAudioFormat("telephone-event", 8000, 1)},
+ {114, SdpAudioFormat("telephone-event", 16000, 1)},
+ {115, SdpAudioFormat("telephone-event", 32000, 1)},
+ {116, SdpAudioFormat("telephone-event", 48000, 1)},
+ {117, SdpAudioFormat("red", 8000, 1)},
+ {13, SdpAudioFormat("cn", 8000, 1)},
+ {98, SdpAudioFormat("cn", 16000, 1)},
+ {99, SdpAudioFormat("cn", 32000, 1)},
+ {100, SdpAudioFormat("cn", 48000, 1)}
};
return codecs;
}
void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
for (const auto& c : codecs) {
- RTC_CHECK_EQ(
- neteq_->RegisterPayloadType(c.second.first, c.second.second, c.first),
- NetEq::kOK)
- << "Cannot register " << c.second.second << " to payload type "
- << c.first;
- }
-}
-
-void NetEqTest::RegisterExternalDecoders(const ExtDecoderMap& codecs) {
- for (const auto& c : codecs) {
- RTC_CHECK_EQ(
- neteq_->RegisterExternalDecoder(c.second.decoder, c.second.codec,
- c.second.codec_name, c.first),
- NetEq::kOK)
- << "Cannot register " << c.second.codec_name << " to payload type "
+ RTC_CHECK(neteq_->RegisterPayloadType(c.first, c.second))
+ << "Cannot register " << c.second.name << " to payload type "
<< c.first;
}
}
diff --git a/modules/audio_coding/neteq/tools/neteq_test.h b/modules/audio_coding/neteq/tools/neteq_test.h
index 23d7c22..5261dd7 100644
--- a/modules/audio_coding/neteq/tools/neteq_test.h
+++ b/modules/audio_coding/neteq/tools/neteq_test.h
@@ -11,12 +11,14 @@
#ifndef MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_TEST_H_
#define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_TEST_H_
+#include <fstream>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "absl/types/optional.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/test/neteq_simulator.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/audio_sink.h"
@@ -65,15 +67,7 @@
// directed to an AudioSink object.
class NetEqTest : public NetEqSimulator {
public:
- using DecoderMap = std::map<int, std::pair<NetEqDecoder, std::string> >;
-
- struct ExternalDecoderInfo {
- AudioDecoder* decoder;
- NetEqDecoder codec;
- std::string codec_name;
- };
-
- using ExtDecoderMap = std::map<int, ExternalDecoderInfo>;
+ using DecoderMap = std::map<int, SdpAudioFormat>;
struct Callbacks {
NetEqTestErrorCallback* error_callback = nullptr;
@@ -85,8 +79,9 @@
// Sets up the test with given configuration, codec mappings, input, ouput,
// and callback objects for error reporting.
NetEqTest(const NetEq::Config& config,
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
const DecoderMap& codecs,
- const ExtDecoderMap& ext_codecs,
+ std::unique_ptr<std::ofstream> text_log,
std::unique_ptr<NetEqInput> input,
std::unique_ptr<AudioSink> output,
Callbacks callbacks);
@@ -111,7 +106,6 @@
private:
void RegisterDecoders(const DecoderMap& codecs);
- void RegisterExternalDecoders(const ExtDecoderMap& codecs);
absl::optional<Action> next_action_;
absl::optional<int> last_packet_time_ms_;
std::unique_ptr<NetEq> neteq_;
@@ -121,6 +115,9 @@
int sample_rate_hz_;
NetEqState current_state_;
NetEqOperationsAndState prev_ops_state_;
+ NetEqLifetimeStatistics prev_lifetime_stats_;
+ absl::optional<uint32_t> last_packet_timestamp_;
+ std::unique_ptr<std::ofstream> text_log_;
};
} // namespace test
diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.cc b/modules/audio_coding/neteq/tools/neteq_test_factory.cc
index aa956ce..1d38bc4 100644
--- a/modules/audio_coding/neteq/tools/neteq_test_factory.cc
+++ b/modules/audio_coding/neteq/tools/neteq_test_factory.cc
@@ -14,6 +14,7 @@
#include <limits.h> // For ULONG_MAX returned by strtoul.
#include <stdio.h>
#include <stdlib.h> // For strtoul.
+#include <fstream>
#include <iostream>
#include <memory>
#include <set>
@@ -21,6 +22,7 @@
#include <utility>
#include "absl/memory/memory.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "modules/audio_coding/neteq/include/neteq.h"
#include "modules/audio_coding/neteq/tools/fake_decode_from_file.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
@@ -36,210 +38,32 @@
#include "modules/audio_coding/neteq/tools/rtp_file_source.h"
#include "rtc_base/checks.h"
#include "rtc_base/flags.h"
-#include "test/testsupport/fileutils.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/function_audio_decoder_factory.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace test {
namespace {
-// Parses the input string for a valid SSRC (at the start of the string). If a
-// valid SSRC is found, it is written to the output variable |ssrc|, and true is
-// returned. Otherwise, false is returned.
-bool ParseSsrc(const std::string& str, uint32_t* ssrc) {
- if (str.empty())
- return true;
- int base = 10;
- // Look for "0x" or "0X" at the start and change base to 16 if found.
- if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0))
- base = 16;
- errno = 0;
- char* end_ptr;
- unsigned long value = strtoul(str.c_str(), &end_ptr, base); // NOLINT
- if (value == ULONG_MAX && errno == ERANGE)
- return false; // Value out of range for unsigned long.
- if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) // NOLINT
- return false; // Value out of range for uint32_t.
- if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length()))
- return false; // Part of the string was not parsed.
- *ssrc = static_cast<uint32_t>(value);
- return true;
-}
-
-// Flag validators.
-bool ValidatePayloadType(int value) {
- if (value >= 0 && value <= 127) // Value is ok.
- return true;
- printf("Payload type must be between 0 and 127, not %d\n",
- static_cast<int>(value));
- return false;
-}
-
-bool ValidateSsrcValue(const std::string& str) {
- uint32_t dummy_ssrc;
- if (ParseSsrc(str, &dummy_ssrc)) // Value is ok.
- return true;
- printf("Invalid SSRC: %s\n", str.c_str());
- return false;
-}
-
-static bool ValidateExtensionId(int value) {
- if (value > 0 && value <= 255) // Value is ok.
- return true;
- printf("Extension ID must be between 1 and 255, not %d\n",
- static_cast<int>(value));
- return false;
-}
-
-// Define command line flags.
-WEBRTC_DEFINE_int(pcmu, 0, "RTP payload type for PCM-u");
-WEBRTC_DEFINE_int(pcma, 8, "RTP payload type for PCM-a");
-WEBRTC_DEFINE_int(ilbc, 102, "RTP payload type for iLBC");
-WEBRTC_DEFINE_int(isac, 103, "RTP payload type for iSAC");
-WEBRTC_DEFINE_int(isac_swb, 104, "RTP payload type for iSAC-swb (32 kHz)");
-WEBRTC_DEFINE_int(opus, 111, "RTP payload type for Opus");
-WEBRTC_DEFINE_int(pcm16b, 93, "RTP payload type for PCM16b-nb (8 kHz)");
-WEBRTC_DEFINE_int(pcm16b_wb, 94, "RTP payload type for PCM16b-wb (16 kHz)");
-WEBRTC_DEFINE_int(pcm16b_swb32,
- 95,
- "RTP payload type for PCM16b-swb32 (32 kHz)");
-WEBRTC_DEFINE_int(pcm16b_swb48,
- 96,
- "RTP payload type for PCM16b-swb48 (48 kHz)");
-WEBRTC_DEFINE_int(g722, 9, "RTP payload type for G.722");
-WEBRTC_DEFINE_int(avt, 106, "RTP payload type for AVT/DTMF (8 kHz)");
-WEBRTC_DEFINE_int(avt_16, 114, "RTP payload type for AVT/DTMF (16 kHz)");
-WEBRTC_DEFINE_int(avt_32, 115, "RTP payload type for AVT/DTMF (32 kHz)");
-WEBRTC_DEFINE_int(avt_48, 116, "RTP payload type for AVT/DTMF (48 kHz)");
-WEBRTC_DEFINE_int(red, 117, "RTP payload type for redundant audio (RED)");
-WEBRTC_DEFINE_int(cn_nb, 13, "RTP payload type for comfort noise (8 kHz)");
-WEBRTC_DEFINE_int(cn_wb, 98, "RTP payload type for comfort noise (16 kHz)");
-WEBRTC_DEFINE_int(cn_swb32, 99, "RTP payload type for comfort noise (32 kHz)");
-WEBRTC_DEFINE_int(cn_swb48, 100, "RTP payload type for comfort noise (48 kHz)");
-WEBRTC_DEFINE_string(replacement_audio_file,
- "",
- "A PCM file that will be used to populate "
- "dummy"
- " RTP packets");
-WEBRTC_DEFINE_string(
- ssrc,
- "",
- "Only use packets with this SSRC (decimal or hex, the latter "
- "starting with 0x)");
-WEBRTC_DEFINE_int(audio_level, 1, "Extension ID for audio level (RFC 6464)");
-WEBRTC_DEFINE_int(abs_send_time, 3, "Extension ID for absolute sender time");
-WEBRTC_DEFINE_int(transport_seq_no,
- 5,
- "Extension ID for transport sequence number");
-WEBRTC_DEFINE_int(video_content_type, 7, "Extension ID for video content type");
-WEBRTC_DEFINE_int(video_timing, 8, "Extension ID for video timing");
-WEBRTC_DEFINE_bool(matlabplot,
- false,
- "Generates a matlab script for plotting the delay profile");
-WEBRTC_DEFINE_bool(pythonplot,
- false,
- "Generates a python script for plotting the delay profile");
-WEBRTC_DEFINE_bool(concealment_events, false, "Prints concealment events");
-WEBRTC_DEFINE_int(max_nr_packets_in_buffer,
- 50,
- "Maximum allowed number of packets in the buffer");
-WEBRTC_DEFINE_bool(enable_fast_accelerate,
- false,
- "Enables jitter buffer fast accelerate");
-
-// Maps a codec type to a printable name string.
-std::string CodecName(NetEqDecoder codec) {
- switch (codec) {
- case NetEqDecoder::kDecoderPCMu:
- return "PCM-u";
- case NetEqDecoder::kDecoderPCMa:
- return "PCM-a";
- case NetEqDecoder::kDecoderILBC:
- return "iLBC";
- case NetEqDecoder::kDecoderISAC:
- return "iSAC";
- case NetEqDecoder::kDecoderISACswb:
- return "iSAC-swb (32 kHz)";
- case NetEqDecoder::kDecoderOpus:
- return "Opus";
- case NetEqDecoder::kDecoderPCM16B:
- return "PCM16b-nb (8 kHz)";
- case NetEqDecoder::kDecoderPCM16Bwb:
- return "PCM16b-wb (16 kHz)";
- case NetEqDecoder::kDecoderPCM16Bswb32kHz:
- return "PCM16b-swb32 (32 kHz)";
- case NetEqDecoder::kDecoderPCM16Bswb48kHz:
- return "PCM16b-swb48 (48 kHz)";
- case NetEqDecoder::kDecoderG722:
- return "G.722";
- case NetEqDecoder::kDecoderRED:
- return "redundant audio (RED)";
- case NetEqDecoder::kDecoderAVT:
- return "AVT/DTMF (8 kHz)";
- case NetEqDecoder::kDecoderAVT16kHz:
- return "AVT/DTMF (16 kHz)";
- case NetEqDecoder::kDecoderAVT32kHz:
- return "AVT/DTMF (32 kHz)";
- case NetEqDecoder::kDecoderAVT48kHz:
- return "AVT/DTMF (48 kHz)";
- case NetEqDecoder::kDecoderCNGnb:
- return "comfort noise (8 kHz)";
- case NetEqDecoder::kDecoderCNGwb:
- return "comfort noise (16 kHz)";
- case NetEqDecoder::kDecoderCNGswb32kHz:
- return "comfort noise (32 kHz)";
- case NetEqDecoder::kDecoderCNGswb48kHz:
- return "comfort noise (48 kHz)";
- default:
- FATAL();
- return "undefined";
- }
-}
-
-void PrintCodecMappingEntry(NetEqDecoder codec, int flag) {
- std::cout << CodecName(codec) << ": " << flag << std::endl;
-}
-
-void PrintCodecMapping() {
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCMu, FLAG_pcmu);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCMa, FLAG_pcma);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderILBC, FLAG_ilbc);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderISAC, FLAG_isac);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderISACswb, FLAG_isac_swb);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderOpus, FLAG_opus);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCM16B, FLAG_pcm16b);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCM16Bwb, FLAG_pcm16b_wb);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCM16Bswb32kHz,
- FLAG_pcm16b_swb32);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderPCM16Bswb48kHz,
- FLAG_pcm16b_swb48);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderG722, FLAG_g722);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderAVT, FLAG_avt);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderAVT16kHz, FLAG_avt_16);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderAVT32kHz, FLAG_avt_32);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderAVT48kHz, FLAG_avt_48);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderRED, FLAG_red);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderCNGnb, FLAG_cn_nb);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderCNGwb, FLAG_cn_wb);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderCNGswb32kHz, FLAG_cn_swb32);
- PrintCodecMappingEntry(NetEqDecoder::kDecoderCNGswb48kHz, FLAG_cn_swb48);
-}
-
-absl::optional<int> CodecSampleRate(uint8_t payload_type) {
- if (payload_type == FLAG_pcmu || payload_type == FLAG_pcma ||
- payload_type == FLAG_ilbc || payload_type == FLAG_pcm16b ||
- payload_type == FLAG_cn_nb || payload_type == FLAG_avt)
+absl::optional<int> CodecSampleRate(
+ uint8_t payload_type,
+ webrtc::test::NetEqTestFactory::Config config) {
+ if (payload_type == config.pcmu || payload_type == config.pcma ||
+ payload_type == config.ilbc || payload_type == config.pcm16b ||
+ payload_type == config.cn_nb || payload_type == config.avt)
return 8000;
- if (payload_type == FLAG_isac || payload_type == FLAG_pcm16b_wb ||
- payload_type == FLAG_g722 || payload_type == FLAG_cn_wb ||
- payload_type == FLAG_avt_16)
+ if (payload_type == config.isac || payload_type == config.pcm16b_wb ||
+ payload_type == config.g722 || payload_type == config.cn_wb ||
+ payload_type == config.avt_16)
return 16000;
- if (payload_type == FLAG_isac_swb || payload_type == FLAG_pcm16b_swb32 ||
- payload_type == FLAG_cn_swb32 || payload_type == FLAG_avt_32)
+ if (payload_type == config.isac_swb || payload_type == config.pcm16b_swb32 ||
+ payload_type == config.cn_swb32 || payload_type == config.avt_32)
return 32000;
- if (payload_type == FLAG_opus || payload_type == FLAG_pcm16b_swb48 ||
- payload_type == FLAG_cn_swb48 || payload_type == FLAG_avt_48)
+ if (payload_type == config.opus || payload_type == config.pcm16b_swb48 ||
+ payload_type == config.cn_swb48 || payload_type == config.avt_48)
return 48000;
- if (payload_type == FLAG_red)
+ if (payload_type == config.red)
return 0;
return absl::nullopt;
}
@@ -277,66 +101,31 @@
};
NetEqTestFactory::NetEqTestFactory() = default;
-
NetEqTestFactory::~NetEqTestFactory() = default;
-void NetEqTestFactory::PrintCodecMap() {
- PrintCodecMapping();
-}
+NetEqTestFactory::Config::Config() = default;
+NetEqTestFactory::Config::Config(const Config& other) = default;
+NetEqTestFactory::Config::~Config() = default;
std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
std::string input_file_name,
- std::string output_file_name) {
- RTC_CHECK(ValidatePayloadType(FLAG_pcmu));
- RTC_CHECK(ValidatePayloadType(FLAG_pcma));
- RTC_CHECK(ValidatePayloadType(FLAG_ilbc));
- RTC_CHECK(ValidatePayloadType(FLAG_isac));
- RTC_CHECK(ValidatePayloadType(FLAG_isac_swb));
- RTC_CHECK(ValidatePayloadType(FLAG_opus));
- RTC_CHECK(ValidatePayloadType(FLAG_pcm16b));
- RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_wb));
- RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb32));
- RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb48));
- RTC_CHECK(ValidatePayloadType(FLAG_g722));
- RTC_CHECK(ValidatePayloadType(FLAG_avt));
- RTC_CHECK(ValidatePayloadType(FLAG_avt_16));
- RTC_CHECK(ValidatePayloadType(FLAG_avt_32));
- RTC_CHECK(ValidatePayloadType(FLAG_avt_48));
- RTC_CHECK(ValidatePayloadType(FLAG_red));
- RTC_CHECK(ValidatePayloadType(FLAG_cn_nb));
- RTC_CHECK(ValidatePayloadType(FLAG_cn_wb));
- RTC_CHECK(ValidatePayloadType(FLAG_cn_swb32));
- RTC_CHECK(ValidatePayloadType(FLAG_cn_swb48));
- RTC_CHECK(ValidateSsrcValue(FLAG_ssrc));
- RTC_CHECK(ValidateExtensionId(FLAG_audio_level));
- RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time));
- RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no));
- RTC_CHECK(ValidateExtensionId(FLAG_video_content_type));
- RTC_CHECK(ValidateExtensionId(FLAG_video_timing));
-
+ std::string output_file_name,
+ const Config& config) {
// Gather RTP header extensions in a map.
NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
- {FLAG_audio_level, kRtpExtensionAudioLevel},
- {FLAG_abs_send_time, kRtpExtensionAbsoluteSendTime},
- {FLAG_transport_seq_no, kRtpExtensionTransportSequenceNumber},
- {FLAG_video_content_type, kRtpExtensionVideoContentType},
- {FLAG_video_timing, kRtpExtensionVideoTiming}};
-
- absl::optional<uint32_t> ssrc_filter;
- // Check if an SSRC value was provided.
- if (strlen(FLAG_ssrc) > 0) {
- uint32_t ssrc;
- RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed.";
- ssrc_filter = ssrc;
- }
+ {config.audio_level, kRtpExtensionAudioLevel},
+ {config.abs_send_time, kRtpExtensionAbsoluteSendTime},
+ {config.transport_seq_no, kRtpExtensionTransportSequenceNumber},
+ {config.video_content_type, kRtpExtensionVideoContentType},
+ {config.video_timing, kRtpExtensionVideoTiming}};
std::unique_ptr<NetEqInput> input;
if (RtpFileSource::ValidRtpDump(input_file_name) ||
RtpFileSource::ValidPcap(input_file_name)) {
- input.reset(
- new NetEqRtpDumpInput(input_file_name, rtp_ext_map, ssrc_filter));
+ input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map,
+ config.ssrc_filter));
} else {
- input.reset(new NetEqEventLogInput(input_file_name, ssrc_filter));
+ input.reset(new NetEqEventLogInput(input_file_name, config.ssrc_filter));
}
std::cout << "Input file: " << input_file_name << std::endl;
@@ -348,7 +137,7 @@
std::set<std::pair<int, uint32_t>> discarded_pt_and_ssrc;
while (absl::optional<RTPHeader> first_rtp_header = input->NextHeader()) {
RTC_DCHECK(first_rtp_header);
- sample_rate_hz = CodecSampleRate(first_rtp_header->payloadType);
+ sample_rate_hz = CodecSampleRate(first_rtp_header->payloadType, config);
if (sample_rate_hz) {
std::cout << "Found valid packet with payload type "
<< static_cast<int>(first_rtp_header->payloadType)
@@ -391,46 +180,16 @@
std::cout << "Output file: " << output_file_name << std::endl;
- NetEqTest::DecoderMap codecs = {
- {FLAG_pcmu, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")},
- {FLAG_pcma, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")},
-#ifdef WEBRTC_CODEC_ILBC
- {FLAG_ilbc, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")},
-#endif
- {FLAG_isac, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")},
-#if !defined(WEBRTC_ANDROID)
- {FLAG_isac_swb, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")},
-#endif
-#ifdef WEBRTC_CODEC_OPUS
- {FLAG_opus, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")},
-#endif
- {FLAG_pcm16b, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")},
- {FLAG_pcm16b_wb,
- std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")},
- {FLAG_pcm16b_swb32,
- std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")},
- {FLAG_pcm16b_swb48,
- std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")},
- {FLAG_g722, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
- {FLAG_avt, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
- {FLAG_avt_16, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
- {FLAG_avt_32, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
- {FLAG_avt_48, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
- {FLAG_red, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
- {FLAG_cn_nb, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
- {FLAG_cn_wb, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
- {FLAG_cn_swb32,
- std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")},
- {FLAG_cn_swb48,
- std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")}
- };
+ NetEqTest::DecoderMap codecs = NetEqTest::StandardDecoderMap();
+
+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory =
+ CreateBuiltinAudioDecoderFactory();
// Check if a replacement audio file was provided.
- if (strlen(FLAG_replacement_audio_file) > 0) {
+ if (config.replacement_audio_file.size() > 0) {
// Find largest unused payload type.
int replacement_pt = 127;
- while (!(codecs.find(replacement_pt) == codecs.end() &&
- ext_codecs_.find(replacement_pt) == ext_codecs_.end())) {
+ while (codecs.find(replacement_pt) != codecs.end()) {
--replacement_pt;
RTC_CHECK_GE(replacement_pt, 0);
}
@@ -444,39 +203,59 @@
};
std::set<uint8_t> cn_types = std_set_int32_to_uint8(
- {FLAG_cn_nb, FLAG_cn_wb, FLAG_cn_swb32, FLAG_cn_swb48});
- std::set<uint8_t> forbidden_types = std_set_int32_to_uint8(
- {FLAG_g722, FLAG_red, FLAG_avt, FLAG_avt_16, FLAG_avt_32, FLAG_avt_48});
+ {config.cn_nb, config.cn_wb, config.cn_swb32, config.cn_swb48});
+ std::set<uint8_t> forbidden_types =
+ std_set_int32_to_uint8({config.g722, config.red, config.avt,
+ config.avt_16, config.avt_32, config.avt_48});
input.reset(new NetEqReplacementInput(std::move(input), replacement_pt,
cn_types, forbidden_types));
- replacement_decoder_.reset(new FakeDecodeFromFile(
- std::unique_ptr<InputAudioFile>(
- new InputAudioFile(FLAG_replacement_audio_file)),
- 48000, false));
- NetEqTest::ExternalDecoderInfo ext_dec_info = {
- replacement_decoder_.get(), NetEqDecoder::kDecoderArbitrary,
- "replacement codec"};
- ext_codecs_[replacement_pt] = ext_dec_info;
+ // Note that capture-by-copy implies that the lambda captures the value of
+ // decoder_factory before it's reassigned on the left-hand side.
+ decoder_factory = new rtc::RefCountedObject<FunctionAudioDecoderFactory>(
+ [decoder_factory, config](
+ const SdpAudioFormat& format,
+ absl::optional<AudioCodecPairId> codec_pair_id) {
+ std::unique_ptr<AudioDecoder> decoder =
+ decoder_factory->MakeAudioDecoder(format, codec_pair_id);
+ if (!decoder && format.name == "replacement") {
+ decoder = absl::make_unique<FakeDecodeFromFile>(
+ absl::make_unique<InputAudioFile>(
+ config.replacement_audio_file),
+ format.clockrate_hz, format.num_channels > 1);
+ }
+ return decoder;
+ });
+
+ RTC_CHECK(
+ codecs.insert({replacement_pt, SdpAudioFormat("replacement", 48000, 1)})
+ .second);
+ }
+
+ // Create a text log file if needed.
+ std::unique_ptr<std::ofstream> text_log;
+ if (config.textlog) {
+ text_log =
+ absl::make_unique<std::ofstream>(output_file_name + ".text_log.txt");
}
NetEqTest::Callbacks callbacks;
- stats_plotter_.reset(new NetEqStatsPlotter(FLAG_matlabplot, FLAG_pythonplot,
- FLAG_concealment_events,
- output_file_name));
+ stats_plotter_.reset(
+ new NetEqStatsPlotter(config.matlabplot, config.pythonplot,
+ config.concealment_events, output_file_name));
ssrc_switch_detector_.reset(
new SsrcSwitchDetector(stats_plotter_->stats_getter()->delay_analyzer()));
callbacks.post_insert_packet = ssrc_switch_detector_.get();
callbacks.get_audio_callback = stats_plotter_->stats_getter();
callbacks.simulation_ended_callback = stats_plotter_.get();
- NetEq::Config config;
- config.sample_rate_hz = *sample_rate_hz;
- config.max_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
- config.enable_fast_accelerate = FLAG_enable_fast_accelerate;
- return absl::make_unique<NetEqTest>(config, codecs, ext_codecs_,
- std::move(input), std::move(output),
- callbacks);
+ NetEq::Config neteq_config;
+ neteq_config.sample_rate_hz = *sample_rate_hz;
+ neteq_config.max_packets_in_buffer = config.max_nr_packets_in_buffer;
+ neteq_config.enable_fast_accelerate = config.enable_fast_accelerate;
+ return absl::make_unique<NetEqTest>(neteq_config, decoder_factory, codecs,
+ std::move(text_log), std::move(input),
+ std::move(output), callbacks);
}
} // namespace test
diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.h b/modules/audio_coding/neteq/tools/neteq_test_factory.h
index a249186..dbcdf1a 100644
--- a/modules/audio_coding/neteq/tools/neteq_test_factory.h
+++ b/modules/audio_coding/neteq/tools/neteq_test_factory.h
@@ -14,6 +14,7 @@
#include <memory>
#include <string>
+#include "absl/types/optional.h"
#include "modules/audio_coding/neteq/tools/neteq_test.h"
namespace webrtc {
@@ -29,13 +30,109 @@
public:
NetEqTestFactory();
~NetEqTestFactory();
- void PrintCodecMap();
+ struct Config {
+ Config();
+ Config(const Config& other);
+ ~Config();
+ // RTP payload type for PCM-u.
+ static constexpr int default_pcmu() { return 0; }
+ int pcmu = default_pcmu();
+ // RTP payload type for PCM-a.
+ static constexpr int default_pcma() { return 8; }
+ int pcma = default_pcma();
+ // RTP payload type for iLBC.
+ static constexpr int default_ilbc() { return 102; }
+ int ilbc = default_ilbc();
+ // RTP payload type for iSAC.
+ static constexpr int default_isac() { return 103; }
+ int isac = default_isac();
+ // RTP payload type for iSAC-swb (32 kHz).
+ static constexpr int default_isac_swb() { return 104; }
+ int isac_swb = default_isac_swb();
+ // RTP payload type for Opus.
+ static constexpr int default_opus() { return 111; }
+ int opus = default_opus();
+ // RTP payload type for PCM16b-nb (8 kHz).
+ static constexpr int default_pcm16b() { return 93; }
+ int pcm16b = default_pcm16b();
+ // RTP payload type for PCM16b-wb (16 kHz).
+ static constexpr int default_pcm16b_wb() { return 94; }
+ int pcm16b_wb = default_pcm16b_wb();
+ // RTP payload type for PCM16b-swb32 (32 kHz).
+ static constexpr int default_pcm16b_swb32() { return 95; }
+ int pcm16b_swb32 = default_pcm16b_swb32();
+ // RTP payload type for PCM16b-swb48 (48 kHz).
+ static constexpr int default_pcm16b_swb48() { return 96; }
+ int pcm16b_swb48 = default_pcm16b_swb48();
+ // RTP payload type for G.722.
+ static constexpr int default_g722() { return 9; }
+ int g722 = default_g722();
+ // RTP payload type for AVT/DTMF (8 kHz).
+ static constexpr int default_avt() { return 106; }
+ int avt = default_avt();
+ // RTP payload type for AVT/DTMF (16 kHz).
+ static constexpr int default_avt_16() { return 114; }
+ int avt_16 = default_avt_16();
+ // RTP payload type for AVT/DTMF (32 kHz).
+ static constexpr int default_avt_32() { return 115; }
+ int avt_32 = default_avt_32();
+ // RTP payload type for AVT/DTMF (48 kHz).
+ static constexpr int default_avt_48() { return 116; }
+ int avt_48 = default_avt_48();
+ // RTP payload type for redundant audio (RED).
+ static constexpr int default_red() { return 117; }
+ int red = default_red();
+ // RTP payload type for comfort noise (8 kHz).
+ static constexpr int default_cn_nb() { return 13; }
+ int cn_nb = default_cn_nb();
+ // RTP payload type for comfort noise (16 kHz).
+ static constexpr int default_cn_wb() { return 98; }
+ int cn_wb = default_cn_wb();
+ // RTP payload type for comfort noise (32 kHz).
+ static constexpr int default_cn_swb32() { return 99; }
+ int cn_swb32 = default_cn_swb32();
+ // RTP payload type for comfort noise (48 kHz).
+ static constexpr int default_cn_swb48() { return 100; }
+ int cn_swb48 = default_cn_swb48();
+ // A PCM file that will be used to populate dummy RTP packets.
+ std::string replacement_audio_file;
+ // Only use packets with this SSRC.
+ absl::optional<uint32_t> ssrc_filter;
+ // Extension ID for audio level (RFC 6464).
+ static constexpr int default_audio_level() { return 1; }
+ int audio_level = default_audio_level();
+ // Extension ID for absolute sender time.
+ static constexpr int default_abs_send_time() { return 3; }
+ int abs_send_time = default_abs_send_time();
+ // Extension ID for transport sequence number.
+ static constexpr int default_transport_seq_no() { return 5; }
+ int transport_seq_no = default_transport_seq_no();
+ // Extension ID for video content type.
+ static constexpr int default_video_content_type() { return 7; }
+ int video_content_type = default_video_content_type();
+ // Extension ID for video timing.
+ static constexpr int default_video_timing() { return 8; }
+ int video_timing = default_video_timing();
+ // Generate a matlab script for plotting the delay profile.
+ bool matlabplot = false;
+ // Generates a python script for plotting the delay profile.
+ bool pythonplot = false;
+ // Generates a text log describing the simulation on a step-by-step basis.
+ bool textlog = false;
+ // Prints concealment events.
+ bool concealment_events = false;
+ // Maximum allowed number of packets in the buffer.
+ static constexpr int default_max_nr_packets_in_buffer() { return 50; }
+ int max_nr_packets_in_buffer = default_max_nr_packets_in_buffer();
+ // Enables jitter buffer fast accelerate.
+ bool enable_fast_accelerate = false;
+ };
+
std::unique_ptr<NetEqTest> InitializeTest(std::string input_filename,
- std::string output_filename);
+ std::string output_filename,
+ const Config& config);
private:
- std::unique_ptr<AudioDecoder> replacement_decoder_;
- NetEqTest::ExtDecoderMap ext_codecs_;
std::unique_ptr<SsrcSwitchDetector> ssrc_switch_detector_;
std::unique_ptr<NetEqStatsPlotter> stats_plotter_;
};
diff --git a/modules/audio_coding/neteq/tools/output_audio_file.h b/modules/audio_coding/neteq/tools/output_audio_file.h
index 7e65bc2..c923a1e 100644
--- a/modules/audio_coding/neteq/tools/output_audio_file.h
+++ b/modules/audio_coding/neteq/tools/output_audio_file.h
@@ -16,7 +16,7 @@
#include <string>
#include "modules/audio_coding/neteq/tools/audio_sink.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/output_wav_file.h b/modules/audio_coding/neteq/tools/output_wav_file.h
index 031a8cb..6982a76 100644
--- a/modules/audio_coding/neteq/tools/output_wav_file.h
+++ b/modules/audio_coding/neteq/tools/output_wav_file.h
@@ -15,7 +15,7 @@
#include "common_audio/wav_file.h"
#include "modules/audio_coding/neteq/tools/audio_sink.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
@@ -24,8 +24,10 @@
public:
// Creates an OutputWavFile, opening a file named |file_name| for writing.
// The output file is a PCM encoded wav file.
- OutputWavFile(const std::string& file_name, int sample_rate_hz)
- : wav_writer_(file_name, sample_rate_hz, 1) {}
+ OutputWavFile(const std::string& file_name,
+ int sample_rate_hz,
+ int num_channels = 1)
+ : wav_writer_(file_name, sample_rate_hz, num_channels) {}
bool WriteArray(const int16_t* audio, size_t num_samples) override {
wav_writer_.WriteSamples(audio, num_samples);
diff --git a/modules/audio_coding/neteq/tools/packet.h b/modules/audio_coding/neteq/tools/packet.h
index 39137aa..5748ba2 100644
--- a/modules/audio_coding/neteq/tools/packet.h
+++ b/modules/audio_coding/neteq/tools/packet.h
@@ -15,8 +15,7 @@
#include <memory>
#include "api/rtp_headers.h" // NOLINT(build/include)
-#include "common_types.h" // NOLINT(build/include)
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/tools/packet_source.h b/modules/audio_coding/neteq/tools/packet_source.h
index cb86a98..975680f 100644
--- a/modules/audio_coding/neteq/tools/packet_source.h
+++ b/modules/audio_coding/neteq/tools/packet_source.h
@@ -15,7 +15,7 @@
#include <memory>
#include "modules/audio_coding/neteq/tools/packet.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/resample_input_audio_file.h b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
index 4e2e9b0..d961f33 100644
--- a/modules/audio_coding/neteq/tools/resample_input_audio_file.h
+++ b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
@@ -15,7 +15,7 @@
#include "common_audio/resampler/include/resampler.h"
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
index 582c2f2..591e2b9 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
@@ -13,8 +13,10 @@
#include <string.h>
#include <iostream>
#include <limits>
+#include <set>
#include <utility>
+#include "absl/memory/memory.h"
#include "logging/rtc_event_log/rtc_event_processor.h"
#include "modules/audio_coding/neteq/tools/packet.h"
#include "rtc_base/checks.h"
@@ -23,10 +25,10 @@
namespace test {
namespace {
-bool ShouldSkipStream(ParsedRtcEventLogNew::MediaType media_type,
+bool ShouldSkipStream(ParsedRtcEventLog::MediaType media_type,
uint32_t ssrc,
absl::optional<uint32_t> ssrc_filter) {
- if (media_type != ParsedRtcEventLogNew::MediaType::AUDIO)
+ if (media_type != ParsedRtcEventLog::MediaType::AUDIO)
return true;
if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
return true;
@@ -64,7 +66,7 @@
bool RtcEventLogSource::OpenFile(const std::string& file_name,
absl::optional<uint32_t> ssrc_filter) {
- ParsedRtcEventLogNew parsed_log;
+ ParsedRtcEventLog parsed_log;
if (!parsed_log.ParseFile(file_name))
return false;
@@ -73,54 +75,59 @@
? std::numeric_limits<int64_t>::max()
: parsed_log.stop_log_events().front().log_time_us();
+ std::set<uint32_t> packet_ssrcs;
auto handle_rtp_packet =
- [this,
- first_log_end_time_us](const webrtc::LoggedRtpPacketIncoming& incoming) {
+ [this, first_log_end_time_us,
+ &packet_ssrcs](const webrtc::LoggedRtpPacketIncoming& incoming) {
if (!filter_.test(incoming.rtp.header.payloadType) &&
incoming.log_time_us() < first_log_end_time_us) {
rtp_packets_.emplace_back(absl::make_unique<Packet>(
incoming.rtp.header, incoming.rtp.total_length,
incoming.rtp.total_length - incoming.rtp.header_length,
static_cast<double>(incoming.log_time_ms())));
+ packet_ssrcs.insert(rtp_packets_.back()->header().ssrc);
}
};
+ std::set<uint32_t> ignored_ssrcs;
auto handle_audio_playout =
- [this, first_log_end_time_us](
- const webrtc::LoggedAudioPlayoutEvent& audio_playout) {
+ [this, first_log_end_time_us, &packet_ssrcs,
+ &ignored_ssrcs](const webrtc::LoggedAudioPlayoutEvent& audio_playout) {
if (audio_playout.log_time_us() < first_log_end_time_us) {
- audio_outputs_.emplace_back(audio_playout.log_time_ms());
+ if (packet_ssrcs.count(audio_playout.ssrc) > 0) {
+ audio_outputs_.emplace_back(audio_playout.log_time_ms());
+ } else {
+ ignored_ssrcs.insert(audio_playout.ssrc);
+ }
}
};
// This wouldn't be needed if we knew that there was at most one audio stream.
webrtc::RtcEventProcessor event_processor;
for (const auto& rtp_packets : parsed_log.incoming_rtp_packets_by_ssrc()) {
- ParsedRtcEventLogNew::MediaType media_type =
+ ParsedRtcEventLog::MediaType media_type =
parsed_log.GetMediaType(rtp_packets.ssrc, webrtc::kIncomingPacket);
if (ShouldSkipStream(media_type, rtp_packets.ssrc, ssrc_filter)) {
continue;
}
- auto rtp_view = absl::make_unique<
- webrtc::ProcessableEventList<webrtc::LoggedRtpPacketIncoming>>(
- rtp_packets.incoming_packets.begin(),
- rtp_packets.incoming_packets.end(), handle_rtp_packet);
- event_processor.AddEvents(std::move(rtp_view));
+ event_processor.AddEvents(rtp_packets.incoming_packets, handle_rtp_packet);
}
for (const auto& audio_playouts : parsed_log.audio_playout_events()) {
if (ssrc_filter.has_value() && audio_playouts.first != *ssrc_filter)
continue;
- auto audio_view = absl::make_unique<
- webrtc::ProcessableEventList<webrtc::LoggedAudioPlayoutEvent>>(
- audio_playouts.second.begin(), audio_playouts.second.end(),
- handle_audio_playout);
- event_processor.AddEvents(std::move(audio_view));
+ event_processor.AddEvents(audio_playouts.second, handle_audio_playout);
}
// Fills in rtp_packets_ and audio_outputs_.
event_processor.ProcessEventsInOrder();
+ for (const auto& ssrc : ignored_ssrcs) {
+ std::cout << "Ignoring GetAudio events from SSRC 0x" << std::hex << ssrc
+ << " because no packets were found with a matching SSRC."
+ << std::endl;
+ }
+
return true;
}
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.h b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
index 6b761f7..5238efb 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.h
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
@@ -16,10 +16,10 @@
#include <vector>
#include "absl/types/optional.h"
-#include "logging/rtc_event_log/rtc_event_log_parser_new.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "modules/audio_coding/neteq/tools/packet_source.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.h b/modules/audio_coding/neteq/tools/rtp_file_source.h
index 02ab897..77e435a 100644
--- a/modules/audio_coding/neteq/tools/rtp_file_source.h
+++ b/modules/audio_coding/neteq/tools/rtp_file_source.h
@@ -17,10 +17,9 @@
#include <string>
#include "absl/types/optional.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/neteq/tools/packet_source.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_coding/neteq/tools/rtp_generator.h b/modules/audio_coding/neteq/tools/rtp_generator.h
index ca7b04f..1454c57 100644
--- a/modules/audio_coding/neteq/tools/rtp_generator.h
+++ b/modules/audio_coding/neteq/tools/rtp_generator.h
@@ -12,8 +12,7 @@
#define MODULES_AUDIO_CODING_NETEQ_TOOLS_RTP_GENERATOR_H_
#include "api/rtp_headers.h"
-#include "common_types.h" // NOLINT(build/include)
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index 66b07df..39d492b 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -7,7 +7,7 @@
# be found in the AUTHORS file in the root of the source tree.
import("../../webrtc.gni")
-if (!build_with_mozilla) {
+if (rtc_enable_protobuf) {
import("//third_party/protobuf/proto_library.gni")
}
@@ -50,23 +50,47 @@
":audio_processing_statistics",
":config",
":gain_control_interface",
+ "../../api:scoped_refptr",
"../../api/audio:aec3_config",
"../../api/audio:echo_control",
"../../rtc_base:deprecation",
"../../rtc_base:macromagic",
- "../../rtc_base:ptr_util",
"../../rtc_base:rtc_base_approved",
"../../rtc_base/system:rtc_export",
+ "//third_party/abseil-cpp/absl/memory:memory",
"//third_party/abseil-cpp/absl/types:optional",
]
}
+rtc_static_library("audio_buffer") {
+ visibility = [ "*" ]
+
+ configs += [ ":apm_debug_dump" ]
+
+ sources = [
+ "audio_buffer.cc",
+ "audio_buffer.h",
+ "splitting_filter.cc",
+ "splitting_filter.h",
+ "three_band_filter_bank.cc",
+ "three_band_filter_bank.h",
+ ]
+
+ defines = []
+
+ deps = [
+ ":api",
+ "../../api/audio:audio_frame_api",
+ "../../common_audio:common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ ]
+}
+
rtc_static_library("audio_processing") {
visibility = [ "*" ]
configs += [ ":apm_debug_dump" ]
sources = [
- "audio_buffer.cc",
- "audio_buffer.h",
"audio_processing_impl.cc",
"audio_processing_impl.h",
"common.h",
@@ -101,10 +125,6 @@
"residual_echo_detector.h",
"rms_level.cc",
"rms_level.h",
- "splitting_filter.cc",
- "splitting_filter.h",
- "three_band_filter_bank.cc",
- "three_band_filter_bank.h",
"transient/common.h",
"transient/daubechies_8_wavelet_coeffs.h",
"transient/dyadic_decimator.h",
@@ -128,12 +148,14 @@
deps = [
":api",
":apm_logging",
+ ":audio_buffer",
":audio_frame_view",
":audio_generator_interface",
":audio_processing_c",
":audio_processing_statistics",
":config",
":gain_control_interface",
+ ":noise_suppression_proxy",
"../..:webrtc_common",
"../../api:array_view",
"../../api/audio:aec3_config",
@@ -154,6 +176,7 @@
"../../system_wrappers:metrics",
"aec:aec",
"aec:aec_core",
+ "aec3:aec3",
"aecm:aecm_core",
"agc",
"agc:agc_legacy_c",
@@ -161,6 +184,7 @@
"agc2:fixed_digital",
"agc2:gain_applier",
"vad",
+ "//third_party/abseil-cpp/absl/memory:memory",
"//third_party/abseil-cpp/absl/types:optional",
]
@@ -189,6 +213,17 @@
]
}
+rtc_source_set("noise_suppression_proxy") {
+ sources = [
+ "noise_suppression_proxy.cc",
+ "noise_suppression_proxy.h",
+ ]
+ deps = [
+ ":api",
+ "../../rtc_base:macromagic",
+ ]
+}
+
rtc_source_set("audio_processing_statistics") {
visibility = [ "*" ]
sources = [
@@ -331,7 +366,6 @@
"../../common_audio:common_audio",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
- "../../rtc_base:stringutils",
]
defines = []
}
@@ -397,6 +431,7 @@
":analog_mic_simulation",
":api",
":apm_logging",
+ ":audio_buffer",
":audio_frame_view",
":audio_processing",
":audioproc_test_utils",
@@ -405,6 +440,7 @@
":mocks",
"../..:webrtc_common",
"../../api:array_view",
+ "../../api:scoped_refptr",
"../../api/audio:aec3_config",
"../../api/audio:aec3_factory",
"../../common_audio:common_audio",
@@ -437,6 +473,7 @@
"test/conversational_speech:unittest",
"utility:block_mean_calculator_unittest",
"utility:legacy_delay_estimator_unittest",
+ "utility:pffft_wrapper_unittest",
"vad:vad_unittests",
"//testing/gtest",
"//third_party/abseil-cpp/absl/memory",
@@ -460,6 +497,8 @@
":audioproc_unittest_proto",
":runtime_settings_protobuf_utils",
"../../api/audio:audio_frame_api",
+ "../../api/audio:echo_control",
+ "../../rtc_base:rtc_base_tests_utils",
"../../rtc_base:rtc_task_queue",
"aec_dump",
"aec_dump:aec_dump_unittests",
@@ -486,15 +525,11 @@
"test/echo_canceller_test_tools.cc",
"test/echo_canceller_test_tools.h",
"test/echo_canceller_test_tools_unittest.cc",
+ "test/echo_control_mock.h",
"test/test_utils.h",
"voice_detection_unittest.cc",
]
}
-
- if ((!build_with_chromium || is_win) && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
}
rtc_source_set("audio_processing_perf_tests") {
@@ -583,7 +618,6 @@
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_json",
"../../rtc_base:rtc_task_queue",
- "../../rtc_base:stringutils",
"../../system_wrappers",
"../../test:test_support",
"aec_dump",
@@ -627,6 +661,7 @@
deps = [
":api",
+ ":audio_buffer",
":audio_processing",
"../../api:array_view",
"../../api/audio:audio_frame_api",
diff --git a/modules/audio_processing/aec/aec_core.h b/modules/audio_processing/aec/aec_core.h
index 35a6c9b..06ae2a4 100644
--- a/modules/audio_processing/aec/aec_core.h
+++ b/modules/audio_processing/aec/aec_core.h
@@ -25,7 +25,7 @@
#include "modules/audio_processing/aec/aec_common.h"
#include "modules/audio_processing/utility/block_mean_calculator.h"
#include "modules/audio_processing/utility/ooura_fft.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/BUILD.gn b/modules/audio_processing/aec3/BUILD.gn
index 189bcfd..259403c 100644
--- a/modules/audio_processing/aec3/BUILD.gn
+++ b/modules/audio_processing/aec3/BUILD.gn
@@ -28,7 +28,6 @@
"block_framer.h",
"block_processor.cc",
"block_processor.h",
- "block_processor2.cc",
"block_processor_metrics.cc",
"block_processor_metrics.h",
"cascaded_biquad_filter.cc",
@@ -81,10 +80,8 @@
"render_buffer.h",
"render_delay_buffer.cc",
"render_delay_buffer.h",
- "render_delay_buffer2.cc",
"render_delay_controller.cc",
"render_delay_controller.h",
- "render_delay_controller2.cc",
"render_delay_controller_metrics.cc",
"render_delay_controller_metrics.h",
"render_reverb_model.cc",
@@ -123,8 +120,6 @@
"suppression_filter.h",
"suppression_gain.cc",
"suppression_gain.h",
- "suppression_gain_limiter.cc",
- "suppression_gain_limiter.h",
"vector_buffer.cc",
"vector_buffer.h",
"vector_math.h",
@@ -138,7 +133,7 @@
deps = [
"..:apm_logging",
- "..:audio_processing",
+ "..:audio_buffer",
"../../../api:array_view",
"../../../api/audio:aec3_config",
"../../../api/audio:echo_control",
@@ -174,6 +169,7 @@
deps = [
":aec3",
"..:apm_logging",
+ "..:audio_buffer",
"..:audio_processing",
"..:audio_processing_unittests",
"../../../api:array_view",
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter.cc b/modules/audio_processing/aec3/adaptive_fir_filter.cc
index 3ab1ebc..8837c2c 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter.cc
+++ b/modules/audio_processing/aec3/adaptive_fir_filter.cc
@@ -24,7 +24,6 @@
#include "modules/audio_processing/aec3/fft_data.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -417,21 +416,12 @@
} // namespace aec3
-namespace {
-
-bool EnablePartialFilterReset() {
- return !field_trial::IsEnabled("WebRTC-Aec3PartialFilterResetKillSwitch");
-}
-
-} // namespace
-
AdaptiveFirFilter::AdaptiveFirFilter(size_t max_size_partitions,
size_t initial_size_partitions,
size_t size_change_duration_blocks,
Aec3Optimization optimization,
ApmDataDumper* data_dumper)
: data_dumper_(data_dumper),
- use_partial_filter_reset_(EnablePartialFilterReset()),
fft_(),
optimization_(optimization),
max_size_partitions_(max_size_partitions),
@@ -464,18 +454,14 @@
void AdaptiveFirFilter::HandleEchoPathChange() {
size_t current_h_size = h_.size();
h_.resize(GetTimeDomainLength(max_size_partitions_));
- const size_t begin_coeffficient =
- use_partial_filter_reset_ ? current_h_size : 0;
- std::fill(h_.begin() + begin_coeffficient, h_.end(), 0.f);
+ std::fill(h_.begin() + current_h_size, h_.end(), 0.f);
h_.resize(current_h_size);
size_t current_size_partitions = H_.size();
H_.resize(max_size_partitions_);
H2_.resize(max_size_partitions_);
- const size_t begin_partition =
- use_partial_filter_reset_ ? current_size_partitions : 0;
- for (size_t k = begin_partition; k < max_size_partitions_; ++k) {
+ for (size_t k = current_size_partitions; k < max_size_partitions_; ++k) {
H_[k].Clear();
H2_[k].fill(0.f);
}
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter.h b/modules/audio_processing/aec3/adaptive_fir_filter.h
index 7c832a6..5afb80e 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter.h
+++ b/modules/audio_processing/aec3/adaptive_fir_filter.h
@@ -21,7 +21,7 @@
#include "modules/audio_processing/aec3/fft_data.h"
#include "modules/audio_processing/aec3/render_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/arch.h"
namespace webrtc {
@@ -164,7 +164,6 @@
void UpdateSize();
ApmDataDumper* const data_dumper_;
- const bool use_partial_filter_reset_;
const Aec3Fft fft_;
const Aec3Optimization optimization_;
const size_t max_size_partitions_;
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
index 3d583e8..3c4f5a5 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
+++ b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
@@ -317,7 +317,6 @@
config.filter.config_change_duration_blocks,
DetectOptimization(), &data_dumper);
Aec3Fft fft;
- config.delay.min_echo_path_delay_blocks = 0;
config.delay.default_delay = 1;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
RenderDelayBuffer::Create(config, 3));
diff --git a/modules/audio_processing/aec3/aec3_fft.h b/modules/audio_processing/aec3/aec3_fft.h
index 6cd649a..d5db83e 100644
--- a/modules/audio_processing/aec3/aec3_fft.h
+++ b/modules/audio_processing/aec3/aec3_fft.h
@@ -18,7 +18,7 @@
#include "modules/audio_processing/aec3/fft_data.h"
#include "modules/audio_processing/utility/ooura_fft.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc
index 45b361f..99791a7 100644
--- a/modules/audio_processing/aec3/aec_state.cc
+++ b/modules/audio_processing/aec3/aec_state.cc
@@ -19,33 +19,12 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnableErleResetsAtGainChanges() {
- return !field_trial::IsEnabled("WebRTC-Aec3ResetErleAtGainChangesKillSwitch");
-}
-
-bool UseLegacyFilterQualityState() {
- return field_trial::IsEnabled("WebRTC-Aec3FilterQualityStateKillSwitch");
-}
-
-bool EnableLegacySaturationBehavior() {
- return field_trial::IsEnabled("WebRTC-Aec3NewSaturationBehaviorKillSwitch");
-}
-
-bool UseSuppressionGainLimiter() {
- return field_trial::IsEnabled("WebRTC-Aec3GainLimiterDeactivationKillSwitch");
-}
-bool EnableErleUpdatesDuringReverb() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3EnableErleUpdatesDuringReverbKillSwitch");
-}
-
constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
@@ -68,7 +47,7 @@
}
absl::optional<float> AecState::ErleUncertainty() const {
- if (SaturatedEcho() && use_legacy_saturation_behavior_) {
+ if (SaturatedEcho()) {
return 1.f;
}
@@ -79,11 +58,6 @@
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
config_(config),
- use_legacy_saturation_behavior_(EnableLegacySaturationBehavior()),
- enable_erle_resets_at_gain_changes_(EnableErleResetsAtGainChanges()),
- enable_erle_updates_during_reverb_(EnableErleUpdatesDuringReverb()),
- use_legacy_filter_quality_(UseLegacyFilterQualityState()),
- use_suppressor_gain_limiter_(UseSuppressionGainLimiter()),
initial_state_(config_),
delay_state_(config_),
transparent_state_(config_),
@@ -92,7 +66,6 @@
legacy_saturation_detector_(config_),
erl_estimator_(2 * kNumBlocksPerSecond),
erle_estimator_(2 * kNumBlocksPerSecond, config_),
- suppression_gain_limiter_(config_),
filter_analyzer_(config_),
echo_audibility_(
config_.echo_audibility.use_stationarity_properties_at_init),
@@ -107,21 +80,12 @@
capture_signal_saturation_ = false;
strong_not_saturated_render_blocks_ = 0;
blocks_with_active_render_ = 0;
- if (use_suppressor_gain_limiter_) {
- suppression_gain_limiter_.Reset();
- }
initial_state_.Reset();
transparent_state_.Reset();
- if (use_legacy_saturation_behavior_) {
legacy_saturation_detector_.Reset();
- }
erle_estimator_.Reset(true);
erl_estimator_.Reset();
- if (use_legacy_filter_quality_) {
- legacy_filter_quality_state_.Reset();
- } else {
filter_quality_state_.Reset();
- }
};
// TODO(peah): Refine the reset scheme according to the type of gain and
@@ -130,8 +94,7 @@
if (echo_path_variability.delay_change !=
EchoPathVariability::DelayAdjustment::kNone) {
full_reset();
- } else if (enable_erle_resets_at_gain_changes_ &&
- echo_path_variability.gain_change) {
+ } else if (echo_path_variability.gain_change) {
erle_estimator_.Reset(false);
}
subtractor_output_analyzer_.HandleEchoPathChange();
@@ -172,17 +135,6 @@
strong_not_saturated_render_blocks_ +=
active_render && !SaturatedCapture() ? 1 : 0;
- if (use_suppressor_gain_limiter_) {
- // Update the limit on the echo suppression after an echo path change to
- // avoid an initial echo burst.
- suppression_gain_limiter_.Update(render_buffer.GetRenderActivity(),
- TransparentMode());
-
- if (subtractor_output_analyzer_.ConvergedFilter()) {
- suppression_gain_limiter_.Deactivate();
- }
- }
-
std::array<float, kFftLengthBy2Plus1> X2_reverb;
render_reverb_.Apply(
render_buffer.GetSpectrumBuffer(), delay_state_.DirectPathFilterDelay(),
@@ -203,8 +155,7 @@
}
const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay());
- const auto& X2_input_erle =
- enable_erle_updates_during_reverb_ ? X2_reverb : X2;
+ const auto& X2_input_erle = X2_reverb;
erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response,
X2_input_erle, Y2, E2_main,
@@ -214,14 +165,9 @@
erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2);
// Detect and flag echo saturation.
- if (use_legacy_saturation_behavior_) {
- legacy_saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
- EchoPathGain());
- } else {
- saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
- UsableLinearEstimate(), subtractor_output,
- EchoPathGain());
- }
+ saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
+ UsableLinearEstimate(), subtractor_output,
+ EchoPathGain());
// Update the decision on whether to use the initial state parameter set.
initial_state_.Update(active_render, SaturatedCapture());
@@ -234,17 +180,10 @@
active_render, SaturatedCapture());
// Analyze the quality of the filter.
- if (use_legacy_filter_quality_) {
- legacy_filter_quality_state_.Update(
- SaturatedEcho(), active_render, SaturatedCapture(), TransparentMode(),
- external_delay, subtractor_output_analyzer_.ConvergedFilter(),
- subtractor_output_analyzer_.DivergedFilter());
- } else {
- filter_quality_state_.Update(active_render, TransparentMode(),
- SaturatedCapture(),
- filter_analyzer_.Consistent(), external_delay,
- subtractor_output_analyzer_.ConvergedFilter());
- }
+ filter_quality_state_.Update(active_render, TransparentMode(),
+ SaturatedCapture(),
+ filter_analyzer_.Consistent(), external_delay,
+ subtractor_output_analyzer_.ConvergedFilter());
// Update the reverb estimate.
const bool stationary_block =
@@ -261,13 +200,13 @@
reverb_model_estimator_.Dump(data_dumper_.get());
data_dumper_->DumpRaw("aec3_erl", Erl());
data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
+ data_dumper_->DumpRaw("aec3_erle", Erle());
data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks());
data_dumper_->DumpRaw("aec3_consistent_filter",
filter_analyzer_.Consistent());
- data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
data_dumper_->DumpRaw("aec3_initial_state",
initial_state_.InitialStateActive());
data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
@@ -279,8 +218,6 @@
data_dumper_->DumpRaw("aec3_external_delay_avaliable",
external_delay ? 1 : 0);
- data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
- IsSuppressionGainLimitActive());
data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
GetReverbFrequencyResponse());
}
@@ -314,7 +251,7 @@
}
AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config)
- : delay_headroom_blocks_(config.delay.delay_headroom_blocks) {}
+ : delay_headroom_samples_(config.delay.delay_headroom_samples) {}
void AecState::FilterDelay::Update(
const FilterAnalyzer& filter_analyzer,
@@ -332,7 +269,7 @@
const bool delay_estimator_may_not_have_converged =
blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
if (delay_estimator_may_not_have_converged && external_delay_) {
- filter_delay_blocks_ = delay_headroom_blocks_;
+ filter_delay_blocks_ = delay_headroom_samples_ / kBlockSize;
} else {
filter_delay_blocks_ = filter_analyzer.DelayBlocks();
}
diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h
index c9d9cf3..e323b2c 100644
--- a/modules/audio_processing/aec3/aec_state.h
+++ b/modules/audio_processing/aec3/aec_state.h
@@ -31,7 +31,6 @@
#include "modules/audio_processing/aec3/reverb_model_estimator.h"
#include "modules/audio_processing/aec3/subtractor_output.h"
#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
-#include "modules/audio_processing/aec3/suppression_gain_limiter.h"
namespace webrtc {
@@ -46,17 +45,11 @@
// Returns whether the echo subtractor can be used to determine the residual
// echo.
bool UsableLinearEstimate() const {
- if (use_legacy_filter_quality_) {
- return legacy_filter_quality_state_.LinearFilterUsable();
- }
return filter_quality_state_.LinearFilterUsable();
}
// Returns whether the echo subtractor output should be used as output.
bool UseLinearFilterOutput() const {
- if (use_legacy_filter_quality_) {
- return legacy_filter_quality_state_.LinearFilterUsable();
- }
return filter_quality_state_.LinearFilterUsable();
}
@@ -105,11 +98,7 @@
bool SaturatedCapture() const { return capture_signal_saturation_; }
// Returns whether the echo signal is saturated.
- bool SaturatedEcho() const {
- return use_legacy_saturation_behavior_
- ? legacy_saturation_detector_.SaturatedEcho()
- : saturation_detector_.SaturatedEcho();
- }
+ bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); }
// Updates the capture signal saturation.
void UpdateCaptureSaturation(bool capture_signal_saturation) {
@@ -130,20 +119,6 @@
return reverb_model_estimator_.GetReverbFrequencyResponse();
}
- // Returns the upper limit for the echo suppression gain.
- float SuppressionGainLimit() const {
- if (use_suppressor_gain_limiter_) {
- return suppression_gain_limiter_.Limit();
- } else {
- return 1.f;
- }
- }
-
- // Returns whether the suppression gain limiter is active.
- bool IsSuppressionGainLimitActive() const {
- return suppression_gain_limiter_.IsActive();
- }
-
// Returns whether the transition for going out of the initial stated has
// been triggered.
bool TransitionTriggered() const {
@@ -170,11 +145,6 @@
static int instance_count_;
std::unique_ptr<ApmDataDumper> data_dumper_;
const EchoCanceller3Config config_;
- const bool use_legacy_saturation_behavior_;
- const bool enable_erle_resets_at_gain_changes_;
- const bool enable_erle_updates_during_reverb_;
- const bool use_legacy_filter_quality_;
- const bool use_suppressor_gain_limiter_;
// Class for controlling the transition from the intial state, which in turn
// controls when the filter parameters for the initial state should be used.
@@ -222,7 +192,7 @@
size_t blocks_with_proper_filter_adaptation);
private:
- const int delay_headroom_blocks_;
+ const int delay_headroom_samples_;
bool external_delay_reported_ = false;
int filter_delay_blocks_ = 0;
absl::optional<DelayEstimate> external_delay_;
@@ -336,7 +306,7 @@
class SaturationDetector {
public:
// Returns whether the echo is to be considered saturated.
- bool SaturatedEcho() const { return saturated_echo_; };
+ bool SaturatedEcho() const { return saturated_echo_; }
// Updates the detection decision based on new data.
void Update(rtc::ArrayView<const float> x,
@@ -357,7 +327,7 @@
explicit LegacySaturationDetector(const EchoCanceller3Config& config);
// Returns whether the echo is to be considered saturated.
- bool SaturatedEcho() const { return saturated_echo_; };
+ bool SaturatedEcho() const { return saturated_echo_; }
// Resets the state of the detector.
void Reset();
@@ -378,8 +348,6 @@
size_t strong_not_saturated_render_blocks_ = 0;
size_t blocks_with_active_render_ = 0;
bool capture_signal_saturation_ = false;
-
- SuppressionGainUpperLimiter suppression_gain_limiter_;
FilterAnalyzer filter_analyzer_;
absl::optional<DelayEstimate> external_delay_;
EchoAudibility echo_audibility_;
diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc
index a331006..314d05f 100644
--- a/modules/audio_processing/aec3/aec_state_unittest.cc
+++ b/modules/audio_processing/aec3/aec_state_unittest.cc
@@ -25,7 +25,7 @@
absl::optional<DelayEstimate> delay_estimate =
DelayEstimate(DelayEstimate::Quality::kRefined, 10);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::array<float, kFftLengthBy2Plus1> E2_main = {};
std::array<float, kFftLengthBy2Plus1> Y2 = {};
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
@@ -179,7 +179,7 @@
EchoCanceller3Config config;
AecState state(config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
absl::optional<DelayEstimate> delay_estimate;
std::array<float, kFftLengthBy2Plus1> E2_main;
std::array<float, kFftLengthBy2Plus1> Y2;
diff --git a/modules/audio_processing/aec3/block_framer.h b/modules/audio_processing/aec3/block_framer.h
index 923e4cf..fae4b29 100644
--- a/modules/audio_processing/aec3/block_framer.h
+++ b/modules/audio_processing/aec3/block_framer.h
@@ -15,7 +15,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc
index ef25e7c..b08be68 100644
--- a/modules/audio_processing/aec3/block_processor.cc
+++ b/modules/audio_processing/aec3/block_processor.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2018 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
@@ -7,19 +7,25 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "modules/audio_processing/aec3/block_processor.h"
-
+#include <stddef.h>
+#include <memory>
#include <utility>
+#include <vector>
#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/block_processor.h"
#include "modules/audio_processing/aec3/block_processor_metrics.h"
#include "modules/audio_processing/aec3/delay_estimate.h"
#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/echo_remover.h"
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
+#include "modules/audio_processing/aec3/render_delay_controller.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
#include "rtc_base/logging.h"
namespace webrtc {
@@ -35,6 +41,8 @@
std::unique_ptr<RenderDelayController> delay_controller,
std::unique_ptr<EchoRemover> echo_remover);
+ BlockProcessorImpl() = delete;
+
~BlockProcessorImpl() override;
void ProcessCapture(bool echo_path_gain_change,
@@ -64,7 +72,6 @@
size_t capture_call_counter_ = 0;
absl::optional<DelayEstimate> estimated_delay_;
absl::optional<int> echo_remover_delay_;
- RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorImpl);
};
int BlockProcessorImpl::instance_count_ = 0;
@@ -127,35 +134,16 @@
RTC_LOG(LS_WARNING) << "Reset due to render buffer overrun at block "
<< capture_call_counter_;
}
+ render_event_ = RenderDelayBuffer::BufferingEvent::kNone;
// Update the render buffers with any newly arrived render blocks and prepare
// the render buffers for reading the render data corresponding to the current
// capture block.
- render_event_ = render_buffer_->PrepareCaptureProcessing();
- RTC_DCHECK(RenderDelayBuffer::BufferingEvent::kRenderOverrun !=
- render_event_);
- if (render_event_ == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) {
- if (estimated_delay_ &&
- estimated_delay_->quality == DelayEstimate::Quality::kRefined) {
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kDelayReset;
- delay_controller_->Reset(true);
- capture_properly_started_ = false;
- render_properly_started_ = false;
-
- RTC_LOG(LS_WARNING) << "Reset due to render buffer underrun at block "
- << capture_call_counter_;
- }
- } else if (render_event_ == RenderDelayBuffer::BufferingEvent::kApiCallSkew) {
- // There have been too many render calls in a row. Reset to avoid noncausal
- // echo.
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kDelayReset;
- delay_controller_->Reset(true);
- capture_properly_started_ = false;
- render_properly_started_ = false;
- RTC_LOG(LS_WARNING) << "Reset due to render buffer api skew at block "
- << capture_call_counter_;
+ RenderDelayBuffer::BufferingEvent buffer_event =
+ render_buffer_->PrepareCaptureProcessing();
+ // Reset the delay controller at render buffer underrun.
+ if (buffer_event == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) {
+ delay_controller_->Reset(false);
}
data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize,
@@ -169,28 +157,12 @@
echo_remover_delay_, (*capture_block)[0]);
if (estimated_delay_) {
- if (render_buffer_->CausalDelay(estimated_delay_->delay)) {
- bool delay_change = render_buffer_->SetDelay(estimated_delay_->delay);
- if (delay_change) {
- RTC_LOG(LS_WARNING) << "Delay changed to " << estimated_delay_->delay
- << " at block " << capture_call_counter_;
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kNewDetectedDelay;
- }
- } else {
- // A noncausal delay has been detected. This can only happen if there is
- // clockdrift, an audio pipeline issue has occurred, an unreliable delay
- // estimate is used or the specified minimum delay is too short.
- if (estimated_delay_->quality == DelayEstimate::Quality::kRefined) {
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kDelayReset;
- delay_controller_->Reset(true);
- render_buffer_->Reset();
- capture_properly_started_ = false;
- render_properly_started_ = false;
- RTC_LOG(LS_WARNING) << "Reset due to noncausal delay at block "
- << capture_call_counter_;
- }
+ bool delay_change = render_buffer_->SetDelay(estimated_delay_->delay);
+ if (delay_change) {
+ RTC_LOG(LS_WARNING) << "Delay changed to " << estimated_delay_->delay
+ << " at block " << capture_call_counter_;
+ echo_path_variability.delay_change =
+ EchoPathVariability::DelayAdjustment::kNewDetectedDelay;
}
}
@@ -207,8 +179,6 @@
// Update the metrics.
metrics_.UpdateCapture(false);
-
- render_event_ = RenderDelayBuffer::BufferingEvent::kNone;
}
void BlockProcessorImpl::BufferRender(
@@ -253,9 +223,7 @@
std::unique_ptr<RenderDelayBuffer> render_buffer(
RenderDelayBuffer::Create(config, NumBandsForRate(sample_rate_hz)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create(
- config, RenderDelayBuffer::DelayEstimatorOffset(config),
- sample_rate_hz));
+ RenderDelayController::Create(config, sample_rate_hz));
std::unique_ptr<EchoRemover> echo_remover(
EchoRemover::Create(config, sample_rate_hz));
return Create(config, sample_rate_hz, std::move(render_buffer),
@@ -267,9 +235,7 @@
int sample_rate_hz,
std::unique_ptr<RenderDelayBuffer> render_buffer) {
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create(
- config, RenderDelayBuffer::DelayEstimatorOffset(config),
- sample_rate_hz));
+ RenderDelayController::Create(config, sample_rate_hz));
std::unique_ptr<EchoRemover> echo_remover(
EchoRemover::Create(config, sample_rate_hz));
return Create(config, sample_rate_hz, std::move(render_buffer),
diff --git a/modules/audio_processing/aec3/block_processor.h b/modules/audio_processing/aec3/block_processor.h
index 5f7ec7c..bcee3b7 100644
--- a/modules/audio_processing/aec3/block_processor.h
+++ b/modules/audio_processing/aec3/block_processor.h
@@ -26,33 +26,19 @@
// Class for performing echo cancellation on 64 sample blocks of audio data.
class BlockProcessor {
public:
- // Create a block processor with the legacy render buffering.
static BlockProcessor* Create(const EchoCanceller3Config& config,
int sample_rate_hz);
- // Create a block processor with the new render buffering.
- static BlockProcessor* Create2(const EchoCanceller3Config& config,
- int sample_rate_hz);
// Only used for testing purposes.
static BlockProcessor* Create(
const EchoCanceller3Config& config,
int sample_rate_hz,
std::unique_ptr<RenderDelayBuffer> render_buffer);
- static BlockProcessor* Create2(
- const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer);
static BlockProcessor* Create(
const EchoCanceller3Config& config,
int sample_rate_hz,
std::unique_ptr<RenderDelayBuffer> render_buffer,
std::unique_ptr<RenderDelayController> delay_controller,
std::unique_ptr<EchoRemover> echo_remover);
- static BlockProcessor* Create2(
- const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer,
- std::unique_ptr<RenderDelayController> delay_controller,
- std::unique_ptr<EchoRemover> echo_remover);
virtual ~BlockProcessor() = default;
diff --git a/modules/audio_processing/aec3/block_processor2.cc b/modules/audio_processing/aec3/block_processor2.cc
deleted file mode 100644
index 30bd3ee..0000000
--- a/modules/audio_processing/aec3/block_processor2.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 2018 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 <stddef.h>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "absl/types/optional.h"
-#include "api/audio/echo_canceller3_config.h"
-#include "api/audio/echo_control.h"
-#include "modules/audio_processing/aec3/aec3_common.h"
-#include "modules/audio_processing/aec3/block_processor.h"
-#include "modules/audio_processing/aec3/block_processor_metrics.h"
-#include "modules/audio_processing/aec3/delay_estimate.h"
-#include "modules/audio_processing/aec3/echo_path_variability.h"
-#include "modules/audio_processing/aec3/echo_remover.h"
-#include "modules/audio_processing/aec3/render_delay_buffer.h"
-#include "modules/audio_processing/aec3/render_delay_controller.h"
-#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-namespace {
-
-enum class BlockProcessorApiCall { kCapture, kRender };
-
-class BlockProcessorImpl2 final : public BlockProcessor {
- public:
- BlockProcessorImpl2(const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer,
- std::unique_ptr<RenderDelayController> delay_controller,
- std::unique_ptr<EchoRemover> echo_remover);
-
- BlockProcessorImpl2() = delete;
-
- ~BlockProcessorImpl2() override;
-
- void ProcessCapture(bool echo_path_gain_change,
- bool capture_signal_saturation,
- std::vector<std::vector<float>>* capture_block) override;
-
- void BufferRender(const std::vector<std::vector<float>>& block) override;
-
- void UpdateEchoLeakageStatus(bool leakage_detected) override;
-
- void GetMetrics(EchoControl::Metrics* metrics) const override;
-
- void SetAudioBufferDelay(size_t delay_ms) override;
-
- private:
- static int instance_count_;
- std::unique_ptr<ApmDataDumper> data_dumper_;
- const EchoCanceller3Config config_;
- bool capture_properly_started_ = false;
- bool render_properly_started_ = false;
- const size_t sample_rate_hz_;
- std::unique_ptr<RenderDelayBuffer> render_buffer_;
- std::unique_ptr<RenderDelayController> delay_controller_;
- std::unique_ptr<EchoRemover> echo_remover_;
- BlockProcessorMetrics metrics_;
- RenderDelayBuffer::BufferingEvent render_event_;
- size_t capture_call_counter_ = 0;
- absl::optional<DelayEstimate> estimated_delay_;
- absl::optional<int> echo_remover_delay_;
-};
-
-int BlockProcessorImpl2::instance_count_ = 0;
-
-BlockProcessorImpl2::BlockProcessorImpl2(
- const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer,
- std::unique_ptr<RenderDelayController> delay_controller,
- std::unique_ptr<EchoRemover> echo_remover)
- : data_dumper_(
- new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
- config_(config),
- sample_rate_hz_(sample_rate_hz),
- render_buffer_(std::move(render_buffer)),
- delay_controller_(std::move(delay_controller)),
- echo_remover_(std::move(echo_remover)),
- render_event_(RenderDelayBuffer::BufferingEvent::kNone) {
- RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
-}
-
-BlockProcessorImpl2::~BlockProcessorImpl2() = default;
-
-void BlockProcessorImpl2::ProcessCapture(
- bool echo_path_gain_change,
- bool capture_signal_saturation,
- std::vector<std::vector<float>>* capture_block) {
- RTC_DCHECK(capture_block);
- RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size());
- RTC_DCHECK_EQ(kBlockSize, (*capture_block)[0].size());
-
- capture_call_counter_++;
-
- data_dumper_->DumpRaw("aec3_processblock_call_order",
- static_cast<int>(BlockProcessorApiCall::kCapture));
- data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize,
- &(*capture_block)[0][0],
- LowestBandRate(sample_rate_hz_), 1);
-
- if (render_properly_started_) {
- if (!capture_properly_started_) {
- capture_properly_started_ = true;
- render_buffer_->Reset();
- delay_controller_->Reset(true);
- }
- } else {
- // If no render data has yet arrived, do not process the capture signal.
- return;
- }
-
- EchoPathVariability echo_path_variability(
- echo_path_gain_change, EchoPathVariability::DelayAdjustment::kNone,
- false);
-
- if (render_event_ == RenderDelayBuffer::BufferingEvent::kRenderOverrun &&
- render_properly_started_) {
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kBufferFlush;
- delay_controller_->Reset(true);
- RTC_LOG(LS_WARNING) << "Reset due to render buffer overrun at block "
- << capture_call_counter_;
- }
- render_event_ = RenderDelayBuffer::BufferingEvent::kNone;
-
- // Update the render buffers with any newly arrived render blocks and prepare
- // the render buffers for reading the render data corresponding to the current
- // capture block.
- RenderDelayBuffer::BufferingEvent buffer_event =
- render_buffer_->PrepareCaptureProcessing();
- // Reset the delay controller at render buffer underrun.
- if (buffer_event == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) {
- delay_controller_->Reset(false);
- }
-
- data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize,
- &(*capture_block)[0][0],
- LowestBandRate(sample_rate_hz_), 1);
-
- // Compute and and apply the render delay required to achieve proper signal
- // alignment.
- estimated_delay_ = delay_controller_->GetDelay(
- render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(),
- echo_remover_delay_, (*capture_block)[0]);
-
- if (estimated_delay_) {
- bool delay_change = render_buffer_->SetDelay(estimated_delay_->delay);
- if (delay_change) {
- RTC_LOG(LS_WARNING) << "Delay changed to " << estimated_delay_->delay
- << " at block " << capture_call_counter_;
- echo_path_variability.delay_change =
- EchoPathVariability::DelayAdjustment::kNewDetectedDelay;
- }
- }
-
- echo_path_variability.clock_drift = delay_controller_->HasClockdrift();
-
- // Remove the echo from the capture signal.
- echo_remover_->ProcessCapture(
- echo_path_variability, capture_signal_saturation, estimated_delay_,
- render_buffer_->GetRenderBuffer(), capture_block);
-
- // Check to see if a refined delay estimate has been obtained from the echo
- // remover.
- echo_remover_delay_ = echo_remover_->Delay();
-
- // Update the metrics.
- metrics_.UpdateCapture(false);
-}
-
-void BlockProcessorImpl2::BufferRender(
- const std::vector<std::vector<float>>& block) {
- RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.size());
- RTC_DCHECK_EQ(kBlockSize, block[0].size());
- data_dumper_->DumpRaw("aec3_processblock_call_order",
- static_cast<int>(BlockProcessorApiCall::kRender));
- data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize,
- &block[0][0], LowestBandRate(sample_rate_hz_), 1);
- data_dumper_->DumpWav("aec3_processblock_render_input2", kBlockSize,
- &block[0][0], LowestBandRate(sample_rate_hz_), 1);
-
- render_event_ = render_buffer_->Insert(block);
-
- metrics_.UpdateRender(render_event_ !=
- RenderDelayBuffer::BufferingEvent::kNone);
-
- render_properly_started_ = true;
- delay_controller_->LogRenderCall();
-}
-
-void BlockProcessorImpl2::UpdateEchoLeakageStatus(bool leakage_detected) {
- echo_remover_->UpdateEchoLeakageStatus(leakage_detected);
-}
-
-void BlockProcessorImpl2::GetMetrics(EchoControl::Metrics* metrics) const {
- echo_remover_->GetMetrics(metrics);
- const int block_size_ms = sample_rate_hz_ == 8000 ? 8 : 4;
- absl::optional<size_t> delay = render_buffer_->Delay();
- metrics->delay_ms = delay ? static_cast<int>(*delay) * block_size_ms : 0;
-}
-
-void BlockProcessorImpl2::SetAudioBufferDelay(size_t delay_ms) {
- render_buffer_->SetAudioBufferDelay(delay_ms);
-}
-
-} // namespace
-
-BlockProcessor* BlockProcessor::Create2(const EchoCanceller3Config& config,
- int sample_rate_hz) {
- std::unique_ptr<RenderDelayBuffer> render_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(sample_rate_hz)));
- std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, sample_rate_hz));
- std::unique_ptr<EchoRemover> echo_remover(
- EchoRemover::Create(config, sample_rate_hz));
- return Create2(config, sample_rate_hz, std::move(render_buffer),
- std::move(delay_controller), std::move(echo_remover));
-}
-
-BlockProcessor* BlockProcessor::Create2(
- const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer) {
- std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, sample_rate_hz));
- std::unique_ptr<EchoRemover> echo_remover(
- EchoRemover::Create(config, sample_rate_hz));
- return Create2(config, sample_rate_hz, std::move(render_buffer),
- std::move(delay_controller), std::move(echo_remover));
-}
-
-BlockProcessor* BlockProcessor::Create2(
- const EchoCanceller3Config& config,
- int sample_rate_hz,
- std::unique_ptr<RenderDelayBuffer> render_buffer,
- std::unique_ptr<RenderDelayController> delay_controller,
- std::unique_ptr<EchoRemover> echo_remover) {
- return new BlockProcessorImpl2(
- config, sample_rate_hz, std::move(render_buffer),
- std::move(delay_controller), std::move(echo_remover));
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/aec3/block_processor_metrics.h b/modules/audio_processing/aec3/block_processor_metrics.h
index 9b437c0..4ba0536 100644
--- a/modules/audio_processing/aec3/block_processor_metrics.h
+++ b/modules/audio_processing/aec3/block_processor_metrics.h
@@ -11,7 +11,7 @@
#ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_
#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/block_processor_unittest.cc b/modules/audio_processing/aec3/block_processor_unittest.cc
index 8aba5b5..7145786 100644
--- a/modules/audio_processing/aec3/block_processor_unittest.cc
+++ b/modules/audio_processing/aec3/block_processor_unittest.cc
@@ -37,7 +37,7 @@
// methods are callable.
void RunBasicSetupAndApiCallTest(int sample_rate_hz, int num_iterations) {
std::unique_ptr<BlockProcessor> block_processor(
- BlockProcessor::Create2(EchoCanceller3Config(), sample_rate_hz));
+ BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz));
std::vector<std::vector<float>> block(NumBandsForRate(sample_rate_hz),
std::vector<float>(kBlockSize, 1000.f));
@@ -51,7 +51,7 @@
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
void RunRenderBlockSizeVerificationTest(int sample_rate_hz) {
std::unique_ptr<BlockProcessor> block_processor(
- BlockProcessor::Create2(EchoCanceller3Config(), sample_rate_hz));
+ BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz));
std::vector<std::vector<float>> block(
NumBandsForRate(sample_rate_hz), std::vector<float>(kBlockSize - 1, 0.f));
@@ -60,7 +60,7 @@
void RunCaptureBlockSizeVerificationTest(int sample_rate_hz) {
std::unique_ptr<BlockProcessor> block_processor(
- BlockProcessor::Create2(EchoCanceller3Config(), sample_rate_hz));
+ BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz));
std::vector<std::vector<float>> block(
NumBandsForRate(sample_rate_hz), std::vector<float>(kBlockSize - 1, 0.f));
@@ -72,7 +72,7 @@
? NumBandsForRate(sample_rate_hz) + 1
: 1;
std::unique_ptr<BlockProcessor> block_processor(
- BlockProcessor::Create2(EchoCanceller3Config(), sample_rate_hz));
+ BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz));
std::vector<std::vector<float>> block(wrong_num_bands,
std::vector<float>(kBlockSize, 0.f));
@@ -84,7 +84,7 @@
? NumBandsForRate(sample_rate_hz) + 1
: 1;
std::unique_ptr<BlockProcessor> block_processor(
- BlockProcessor::Create2(EchoCanceller3Config(), sample_rate_hz));
+ BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz));
std::vector<std::vector<float>> block(wrong_num_bands,
std::vector<float>(kBlockSize, 0.f));
@@ -124,7 +124,7 @@
EXPECT_CALL(*render_delay_buffer_mock, Delay())
.Times(kNumBlocks + 1)
.WillRepeatedly(Return(0));
- std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create2(
+ std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
EchoCanceller3Config(), rate, std::move(render_delay_buffer_mock)));
std::vector<std::vector<float>> render_block(
@@ -173,7 +173,7 @@
EXPECT_CALL(*echo_remover_mock, UpdateEchoLeakageStatus(_))
.Times(kNumBlocks);
- std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create2(
+ std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
EchoCanceller3Config(), rate, std::move(render_delay_buffer_mock),
std::move(render_delay_controller_mock), std::move(echo_remover_mock)));
@@ -239,7 +239,7 @@
// Verifiers that the verification for null ProcessCapture input works.
TEST(BlockProcessor, NullProcessCaptureParameter) {
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(
- BlockProcessor::Create2(EchoCanceller3Config(), 8000))
+ BlockProcessor::Create(EchoCanceller3Config(), 8000))
->ProcessCapture(false, false, nullptr),
"");
}
@@ -249,7 +249,7 @@
// tests on test bots has been fixed.
TEST(BlockProcessor, DISABLED_WrongSampleRate) {
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(
- BlockProcessor::Create2(EchoCanceller3Config(), 8001)),
+ BlockProcessor::Create(EchoCanceller3Config(), 8001)),
"");
}
diff --git a/modules/audio_processing/aec3/cascaded_biquad_filter.h b/modules/audio_processing/aec3/cascaded_biquad_filter.h
index 2a3b6d6..3d9b14b 100644
--- a/modules/audio_processing/aec3/cascaded_biquad_filter.h
+++ b/modules/audio_processing/aec3/cascaded_biquad_filter.h
@@ -16,7 +16,7 @@
#include <vector>
#include "api/array_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/comfort_noise_generator.cc b/modules/audio_processing/aec3/comfort_noise_generator.cc
index 766e658..1e3cdf2 100644
--- a/modules/audio_processing/aec3/comfort_noise_generator.cc
+++ b/modules/audio_processing/aec3/comfort_noise_generator.cc
@@ -31,17 +31,15 @@
namespace {
-// Creates an array of uniformly distributed variables.
-void TableRandomValue(int16_t* vector, int16_t vector_length, uint32_t* seed) {
- for (int i = 0; i < vector_length; i++) {
- seed[0] = (seed[0] * ((int32_t)69069) + 1) & (0x80000000 - 1);
- vector[i] = (int16_t)(seed[0] >> 16);
- }
-}
-
-} // namespace
-
-namespace {
+// Table of sqrt(2) * sin(2*pi*i/32).
+constexpr float kSqrt2Sin[32] = {
+ +0.0000000f, +0.2758994f, +0.5411961f, +0.7856950f, +1.0000000f,
+ +1.1758756f, +1.3065630f, +1.3870398f, +1.4142136f, +1.3870398f,
+ +1.3065630f, +1.1758756f, +1.0000000f, +0.7856950f, +0.5411961f,
+ +0.2758994f, +0.0000000f, -0.2758994f, -0.5411961f, -0.7856950f,
+ -1.0000000f, -1.1758756f, -1.3065630f, -1.3870398f, -1.4142136f,
+ -1.3870398f, -1.3065630f, -1.1758756f, -1.0000000f, -0.7856950f,
+ -0.5411961f, -0.2758994f};
void GenerateComfortNoise(Aec3Optimization optimization,
const std::array<float, kFftLengthBy2Plus1>& N2,
@@ -63,39 +61,33 @@
std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) *
kOneByNumBands;
- // Generate complex noise.
- std::array<int16_t, kFftLengthBy2 - 1> random_values_int;
- TableRandomValue(random_values_int.data(), random_values_int.size(), seed);
-
// The analysis and synthesis windowing cause loss of power when
// cross-fading the noise where frames are completely uncorrelated
// (generated with random phase), hence the factor sqrt(2).
// This is not the case for the speech signal where the input is overlapping
// (strong correlation).
- std::array<float, kFftLengthBy2 - 1> sin;
- std::array<float, kFftLengthBy2 - 1> cos;
- constexpr float kScale = 6.28318530717959f / 32768.0f;
- constexpr float kSqrt2 = 1.4142135623f;
- std::transform(random_values_int.begin(), random_values_int.end(),
- sin.begin(),
- [&](int16_t a) { return -sinf(kScale * a) * kSqrt2; });
- std::transform(random_values_int.begin(), random_values_int.end(),
- cos.begin(),
- [&](int16_t a) { return cosf(kScale * a) * kSqrt2; });
-
- // Form low-frequency noise via spectral shaping.
N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] =
N_high->re[kFftLengthBy2] = 0.f;
- std::transform(cos.begin(), cos.end(), N.begin() + 1, N_low->re.begin() + 1,
- std::multiplies<float>());
- std::transform(sin.begin(), sin.end(), N.begin() + 1, N_low->im.begin() + 1,
- std::multiplies<float>());
+ for (size_t k = 1; k < kFftLengthBy2; k++) {
+ constexpr int kIndexMask = 32 - 1;
+ // Generate a random 31-bit integer.
+ seed[0] = (seed[0] * 69069 + 1) & (0x80000000 - 1);
+ // Convert to a 5-bit index.
+ int i = seed[0] >> 26;
- // Form the high-frequency noise via simple levelling.
- std::transform(cos.begin(), cos.end(), N_high->re.begin() + 1,
- [&](float a) { return high_band_noise_level * a; });
- std::transform(sin.begin(), sin.end(), N_high->im.begin() + 1,
- [&](float a) { return high_band_noise_level * a; });
+ // y = sqrt(2) * sin(a)
+ const float x = kSqrt2Sin[i];
+ // x = sqrt(2) * cos(a) = sqrt(2) * sin(a + pi/2)
+ const float y = kSqrt2Sin[(i + 8) & kIndexMask];
+
+ // Form low-frequency noise via spectral shaping.
+ N_low->re[k] = N[k] * x;
+ N_low->im[k] = N[k] * y;
+
+ // Form the high-frequency noise via simple levelling.
+ N_high->re[k] = high_band_noise_level * x;
+ N_high->im[k] = high_band_noise_level * y;
+ }
}
} // namespace
diff --git a/modules/audio_processing/aec3/comfort_noise_generator.h b/modules/audio_processing/aec3/comfort_noise_generator.h
index 3be386b..f78fda2 100644
--- a/modules/audio_processing/aec3/comfort_noise_generator.h
+++ b/modules/audio_processing/aec3/comfort_noise_generator.h
@@ -18,7 +18,7 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/aec_state.h"
#include "modules/audio_processing/aec3/fft_data.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/arch.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/decimator.h b/modules/audio_processing/aec3/decimator.h
index 2bb60a4..a505014 100644
--- a/modules/audio_processing/aec3/decimator.h
+++ b/modules/audio_processing/aec3/decimator.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/cascaded_biquad_filter.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/echo_audibility.h b/modules/audio_processing/aec3/echo_audibility.h
index b903ca0..7b85321 100644
--- a/modules/audio_processing/aec3/echo_audibility.h
+++ b/modules/audio_processing/aec3/echo_audibility.h
@@ -19,7 +19,7 @@
#include "modules/audio_processing/aec3/render_buffer.h"
#include "modules/audio_processing/aec3/stationarity_estimator.h"
#include "modules/audio_processing/aec3/vector_buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc
index f05edb1..8a4d8c2 100644
--- a/modules/audio_processing/aec3/echo_canceller3.cc
+++ b/modules/audio_processing/aec3/echo_canceller3.cc
@@ -14,7 +14,7 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -32,136 +32,13 @@
return false;
}
-bool UseShortDelayEstimatorWindow() {
- return field_trial::IsEnabled("WebRTC-Aec3UseShortDelayEstimatorWindow");
-}
-
-bool EnableReverbBasedOnRender() {
- return !field_trial::IsEnabled("WebRTC-Aec3ReverbBasedOnRenderKillSwitch");
-}
-
-bool EnableReverbModelling() {
- return !field_trial::IsEnabled("WebRTC-Aec3ReverbModellingKillSwitch");
-}
-
-bool EnableUnityInitialRampupGain() {
- return field_trial::IsEnabled("WebRTC-Aec3EnableUnityInitialRampupGain");
-}
-
-bool EnableUnityNonZeroRampupGain() {
- return field_trial::IsEnabled("WebRTC-Aec3EnableUnityNonZeroRampupGain");
-}
-
-bool EnableLongReverb() {
- return field_trial::IsEnabled("WebRTC-Aec3ShortReverbKillSwitch");
-}
-
-bool EnableNewFilterParams() {
- return !field_trial::IsEnabled("WebRTC-Aec3NewFilterParamsKillSwitch");
-}
-
-bool EnableLegacyDominantNearend() {
- return field_trial::IsEnabled("WebRTC-Aec3EnableLegacyDominantNearend");
-}
-
-bool UseLegacyNormalSuppressorTuning() {
- return field_trial::IsEnabled("WebRTC-Aec3UseLegacyNormalSuppressorTuning");
-}
-
-bool ActivateStationarityProperties() {
- return field_trial::IsEnabled("WebRTC-Aec3UseStationarityProperties");
-}
-
-bool ActivateStationarityPropertiesAtInit() {
- return field_trial::IsEnabled("WebRTC-Aec3UseStationarityPropertiesAtInit");
-}
-
-bool EnableNewRenderBuffering() {
- return !field_trial::IsEnabled("WebRTC-Aec3NewRenderBufferingKillSwitch");
-}
-
-bool UseEarlyDelayDetection() {
- return !field_trial::IsEnabled("WebRTC-Aec3EarlyDelayDetectionKillSwitch");
-}
-
// Method for adjusting config parameter dependencies..
EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
EchoCanceller3Config adjusted_cfg = config;
- const EchoCanceller3Config default_cfg;
- if (!EnableReverbModelling()) {
- adjusted_cfg.ep_strength.default_len = 0.f;
- }
-
- if (UseShortDelayEstimatorWindow()) {
- adjusted_cfg.delay.num_filters =
- std::min(adjusted_cfg.delay.num_filters, static_cast<size_t>(5));
- }
-
- bool use_new_render_buffering =
- EnableNewRenderBuffering() && config.buffering.use_new_render_buffering;
- // Old render buffering needs one more filter to cover the same delay.
- if (!use_new_render_buffering) {
- adjusted_cfg.delay.num_filters += 1;
- }
-
- if (EnableReverbBasedOnRender() == false) {
- adjusted_cfg.ep_strength.reverb_based_on_render = false;
- }
-
- if (!EnableNewFilterParams()) {
- adjusted_cfg.filter.main.leakage_diverged = 0.01f;
- adjusted_cfg.filter.main.error_floor = 0.1f;
- adjusted_cfg.filter.main.error_ceil = 1E10f;
- adjusted_cfg.filter.main_initial.error_ceil = 1E10f;
- }
-
- if (EnableUnityInitialRampupGain() &&
- adjusted_cfg.echo_removal_control.gain_rampup.initial_gain ==
- default_cfg.echo_removal_control.gain_rampup.initial_gain) {
- adjusted_cfg.echo_removal_control.gain_rampup.initial_gain = 1.f;
- }
-
- if (EnableUnityNonZeroRampupGain() &&
- adjusted_cfg.echo_removal_control.gain_rampup.first_non_zero_gain ==
- default_cfg.echo_removal_control.gain_rampup.first_non_zero_gain) {
- adjusted_cfg.echo_removal_control.gain_rampup.first_non_zero_gain = 1.f;
- }
-
- if (EnableLongReverb()) {
- adjusted_cfg.ep_strength.default_len = 0.88f;
- }
-
- if (EnableLegacyDominantNearend()) {
- adjusted_cfg.suppressor.nearend_tuning =
- EchoCanceller3Config::Suppressor::Tuning(
- EchoCanceller3Config::Suppressor::MaskingThresholds(.2f, .3f, .3f),
- EchoCanceller3Config::Suppressor::MaskingThresholds(.07f, .1f, .3f),
- 2.0f, 0.25f);
- }
-
- if (UseLegacyNormalSuppressorTuning()) {
- adjusted_cfg.suppressor.normal_tuning =
- EchoCanceller3Config::Suppressor::Tuning(
- EchoCanceller3Config::Suppressor::MaskingThresholds(.2f, .3f, .3f),
- EchoCanceller3Config::Suppressor::MaskingThresholds(.07f, .1f, .3f),
- 2.0f, 0.25f);
-
- adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 10.f;
- adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold = 10.f;
- adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration = 25;
- }
-
- if (ActivateStationarityProperties()) {
- adjusted_cfg.echo_audibility.use_stationary_properties = true;
- }
-
- if (ActivateStationarityPropertiesAtInit()) {
- adjusted_cfg.echo_audibility.use_stationarity_properties_at_init = true;
- }
-
- if (!UseEarlyDelayDetection()) {
- adjusted_cfg.delay.delay_selection_thresholds = {25, 25};
+ if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) {
+ // Two blocks headroom.
+ adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2;
}
return adjusted_cfg;
@@ -347,16 +224,12 @@
EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config,
int sample_rate_hz,
bool use_highpass_filter)
- : EchoCanceller3(AdjustConfig(config),
- sample_rate_hz,
- use_highpass_filter,
- std::unique_ptr<BlockProcessor>(
- EnableNewRenderBuffering() &&
- config.buffering.use_new_render_buffering
- ? BlockProcessor::Create2(AdjustConfig(config),
- sample_rate_hz)
- : BlockProcessor::Create(AdjustConfig(config),
- sample_rate_hz))) {}
+ : EchoCanceller3(
+ AdjustConfig(config),
+ sample_rate_hz,
+ use_highpass_filter,
+ std::unique_ptr<BlockProcessor>(
+ BlockProcessor::Create(AdjustConfig(config), sample_rate_hz))) {}
EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config,
int sample_rate_hz,
bool use_highpass_filter,
diff --git a/modules/audio_processing/aec3/echo_canceller3.h b/modules/audio_processing/aec3/echo_canceller3.h
index 671d271..c1298d2 100644
--- a/modules/audio_processing/aec3/echo_canceller3.h
+++ b/modules/audio_processing/aec3/echo_canceller3.h
@@ -27,7 +27,7 @@
#include "modules/audio_processing/audio_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/race_checker.h"
#include "rtc_base/swap_queue.h"
#include "rtc_base/thread_annotations.h"
diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc
index 3f1e059..267213e 100644
--- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc
+++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc
@@ -104,7 +104,7 @@
void GetMetrics(EchoControl::Metrics* metrics) const override {}
- void SetAudioBufferDelay(size_t delay_ms) override{};
+ void SetAudioBufferDelay(size_t delay_ms) override {}
private:
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTransportVerificationProcessor);
@@ -134,7 +134,7 @@
void GetMetrics(EchoControl::Metrics* metrics) const override {}
- void SetAudioBufferDelay(size_t delay_ms) override{};
+ void SetAudioBufferDelay(size_t delay_ms) override {}
private:
std::deque<std::vector<std::vector<float>>> received_render_blocks_;
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.h b/modules/audio_processing/aec3/echo_path_delay_estimator.h
index 1f14735..11255a4 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator.h
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator.h
@@ -20,7 +20,7 @@
#include "modules/audio_processing/aec3/delay_estimate.h"
#include "modules/audio_processing/aec3/matched_filter.h"
#include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
index a4e3133..3be8260 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
@@ -39,7 +39,7 @@
ApmDataDumper data_dumper(0);
EchoCanceller3Config config;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
EchoPathDelayEstimator estimator(&data_dumper, config);
std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
std::vector<float> capture(kBlockSize);
@@ -65,7 +65,7 @@
for (size_t delay_samples : {30, 64, 150, 200, 800, 4000}) {
SCOPED_TRACE(ProduceDebugText(delay_samples, down_sampling_factor));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
DelayBuffer<float> signal_delay_buffer(delay_samples);
EchoPathDelayEstimator estimator(&data_dumper, config);
@@ -113,7 +113,7 @@
ApmDataDumper data_dumper(0);
EchoPathDelayEstimator estimator(&data_dumper, config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
for (size_t k = 0; k < 100; ++k) {
RandomizeSampleVector(&random_generator, render[0]);
for (auto& render_k : render[0]) {
@@ -137,7 +137,7 @@
EchoCanceller3Config config;
EchoPathDelayEstimator estimator(&data_dumper, config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::vector<float> capture(kBlockSize);
EXPECT_DEATH(estimator.EstimateDelay(
render_delay_buffer->GetDownsampledRenderBuffer(), capture),
@@ -152,7 +152,7 @@
EchoCanceller3Config config;
EchoPathDelayEstimator estimator(&data_dumper, config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::vector<float> capture(std::vector<float>(kBlockSize - 1));
EXPECT_DEATH(estimator.EstimateDelay(
render_delay_buffer->GetDownsampledRenderBuffer(), capture),
diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc
index cfb7395..b010152 100644
--- a/modules/audio_processing/aec3/echo_remover.cc
+++ b/modules/audio_processing/aec3/echo_remover.cc
@@ -31,30 +31,15 @@
#include "modules/audio_processing/aec3/suppression_filter.h"
#include "modules/audio_processing/aec3/suppression_gain.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/logging.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool UseShadowFilterOutput() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch");
-}
-
-bool UseSmoothSignalTransitions() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3SmoothSignalTransitionsKillSwitch");
-}
-
-bool EnableBoundedNearend() {
- return !field_trial::IsEnabled("WebRTC-Aec3BoundedNearendKillSwitch");
-}
-
void LinearEchoPower(const FftData& E,
const FftData& Y,
std::array<float, kFftLengthBy2Plus1>* S2) {
@@ -127,8 +112,7 @@
// Selects which of the shadow and main linear filter outputs that is most
// appropriate to pass to the suppressor and forms the linear filter output by
// smoothly transition between those.
- void FormLinearFilterOutput(bool smooth_transition,
- const SubtractorOutput& subtractor_output,
+ void FormLinearFilterOutput(const SubtractorOutput& subtractor_output,
rtc::ArrayView<float> output);
static int instance_count_;
@@ -138,8 +122,6 @@
const Aec3Optimization optimization_;
const int sample_rate_hz_;
const bool use_shadow_filter_output_;
- const bool use_smooth_signal_transitions_;
- const bool enable_bounded_nearend_;
Subtractor subtractor_;
SuppressionGain suppression_gain_;
ComfortNoiseGenerator cng_;
@@ -171,10 +153,7 @@
optimization_(DetectOptimization()),
sample_rate_hz_(sample_rate_hz),
use_shadow_filter_output_(
- UseShadowFilterOutput() &&
config_.filter.enable_shadow_filter_output_usage),
- use_smooth_signal_transitions_(UseSmoothSignalTransitions()),
- enable_bounded_nearend_(EnableBoundedNearend()),
subtractor_(config, data_dumper_.get(), optimization_),
suppression_gain_(config_, optimization_, sample_rate_hz),
cng_(optimization_),
@@ -275,7 +254,7 @@
subtractor_.Process(*render_buffer, y0, render_signal_analyzer_, aec_state_,
&subtractor_output);
std::array<float, kBlockSize> e;
- FormLinearFilterOutput(use_smooth_signal_transitions_, subtractor_output, e);
+ FormLinearFilterOutput(subtractor_output, e);
// Compute spectra.
WindowedPaddedFft(fft_, y0, y_old_, &Y);
@@ -293,14 +272,13 @@
data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0],
LowestBandRate(sample_rate_hz_), 1);
if (aec_state_.UseLinearFilterOutput()) {
- if (!linear_filter_output_last_selected_ &&
- use_smooth_signal_transitions_) {
+ if (!linear_filter_output_last_selected_) {
SignalTransition(y0, e, y0);
} else {
std::copy(e.begin(), e.end(), y0.begin());
}
} else {
- if (linear_filter_output_last_selected_ && use_smooth_signal_transitions_) {
+ if (linear_filter_output_last_selected_) {
SignalTransition(e, y0, y0);
}
}
@@ -322,12 +300,8 @@
aec_state_.UsableLinearEstimate() ? S2_linear : R2;
std::array<float, kFftLengthBy2Plus1> E2_bounded;
- if (enable_bounded_nearend_) {
- std::transform(E2.begin(), E2.end(), Y2.begin(), E2_bounded.begin(),
- [](float a, float b) { return std::min(a, b); });
- } else {
- std::copy(E2.begin(), E2.end(), E2_bounded.begin());
- }
+ std::transform(E2.begin(), E2.end(), Y2.begin(), E2_bounded.begin(),
+ [](float a, float b) { return std::min(a, b); });
suppression_gain_.GetGain(E2, E2_bounded, echo_spectrum, R2,
cng_.NoiseSpectrum(), E, Y, render_signal_analyzer_,
@@ -367,7 +341,6 @@
}
void EchoRemoverImpl::FormLinearFilterOutput(
- bool smooth_transition,
const SubtractorOutput& subtractor_output,
rtc::ArrayView<float> output) {
RTC_DCHECK_EQ(subtractor_output.e_main.size(), output.size());
@@ -393,7 +366,7 @@
}
if (use_main_output) {
- if (!main_filter_output_last_selected_ && smooth_transition) {
+ if (!main_filter_output_last_selected_) {
SignalTransition(subtractor_output.e_shadow, subtractor_output.e_main,
output);
} else {
@@ -401,7 +374,7 @@
subtractor_output.e_main.end(), output.begin());
}
} else {
- if (main_filter_output_last_selected_ && smooth_transition) {
+ if (main_filter_output_last_selected_) {
SignalTransition(subtractor_output.e_main, subtractor_output.e_shadow,
output);
} else {
diff --git a/modules/audio_processing/aec3/echo_remover_metrics.h b/modules/audio_processing/aec3/echo_remover_metrics.h
index 0707a5f..da740fb 100644
--- a/modules/audio_processing/aec3/echo_remover_metrics.h
+++ b/modules/audio_processing/aec3/echo_remover_metrics.h
@@ -15,7 +15,7 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/aec_state.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/echo_remover_unittest.cc b/modules/audio_processing/aec3/echo_remover_unittest.cc
index 8bf76c4..82d149a 100644
--- a/modules/audio_processing/aec3/echo_remover_unittest.cc
+++ b/modules/audio_processing/aec3/echo_remover_unittest.cc
@@ -48,7 +48,7 @@
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<EchoRemover> remover(
EchoRemover::Create(EchoCanceller3Config(), rate));
- std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create2(
+ std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create(
EchoCanceller3Config(), NumBandsForRate(rate)));
std::vector<std::vector<float>> render(NumBandsForRate(rate),
@@ -89,7 +89,7 @@
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<EchoRemover> remover(
EchoRemover::Create(EchoCanceller3Config(), rate));
- std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create2(
+ std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create(
EchoCanceller3Config(), NumBandsForRate(rate)));
std::vector<std::vector<float>> capture(
NumBandsForRate(rate), std::vector<float>(kBlockSize - 1, 0.f));
@@ -111,7 +111,7 @@
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<EchoRemover> remover(
EchoRemover::Create(EchoCanceller3Config(), rate));
- std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create2(
+ std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create(
EchoCanceller3Config(), NumBandsForRate(rate)));
std::vector<std::vector<float>> capture(
NumBandsForRate(rate == 48000 ? 16000 : rate + 16000),
@@ -131,7 +131,7 @@
std::unique_ptr<EchoRemover> remover(
EchoRemover::Create(EchoCanceller3Config(), 8000));
std::unique_ptr<RenderDelayBuffer> render_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
EchoPathVariability echo_path_variability(
false, EchoPathVariability::DelayAdjustment::kNone, false);
EXPECT_DEATH(
@@ -158,10 +158,9 @@
for (size_t delay_samples : {0, 64, 150, 200, 301}) {
SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
EchoCanceller3Config config;
- config.delay.min_echo_path_delay_blocks = 0;
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(config, rate));
std::unique_ptr<RenderDelayBuffer> render_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
render_buffer->SetDelay(delay_samples / kBlockSize);
std::vector<std::unique_ptr<DelayBuffer<float>>> delay_buffers(x.size());
diff --git a/modules/audio_processing/aec3/erl_estimator.h b/modules/audio_processing/aec3/erl_estimator.h
index 29718c3..060fb91 100644
--- a/modules/audio_processing/aec3/erl_estimator.h
+++ b/modules/audio_processing/aec3/erl_estimator.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/erle_estimator_unittest.cc b/modules/audio_processing/aec3/erle_estimator_unittest.cc
index 59a7471..5ef4f24 100644
--- a/modules/audio_processing/aec3/erle_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/erle_estimator_unittest.cc
@@ -86,8 +86,8 @@
void GetFilterFreq(std::vector<std::array<float, kFftLengthBy2Plus1>>&
filter_frequency_response,
- size_t delay_headroom_blocks) {
- RTC_DCHECK_GE(filter_frequency_response.size(), delay_headroom_blocks);
+ size_t delay_headroom_samples) {
+ const size_t delay_headroom_blocks = delay_headroom_samples / kBlockSize;
for (auto& block_freq_resp : filter_frequency_response) {
block_freq_resp.fill(0.f);
}
@@ -108,9 +108,9 @@
std::vector<std::array<float, kFftLengthBy2Plus1>> filter_frequency_response(
config.filter.main.length_blocks);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
- GetFilterFreq(filter_frequency_response, config.delay.delay_headroom_blocks);
+ GetFilterFreq(filter_frequency_response, config.delay.delay_headroom_samples);
ErleEstimator estimator(0, config);
@@ -152,9 +152,9 @@
config.filter.main.length_blocks);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
- GetFilterFreq(filter_frequency_response, config.delay.delay_headroom_blocks);
+ GetFilterFreq(filter_frequency_response, config.delay.delay_headroom_samples);
ErleEstimator estimator(0, config);
diff --git a/modules/audio_processing/aec3/filter_analyzer.cc b/modules/audio_processing/aec3/filter_analyzer.cc
index 3e69be6..7a6471a 100644
--- a/modules/audio_processing/aec3/filter_analyzer.cc
+++ b/modules/audio_processing/aec3/filter_analyzer.cc
@@ -18,9 +18,8 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/render_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
@@ -43,16 +42,6 @@
return peak_index_out;
}
-bool EnableFilterPreprocessing() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch");
-}
-
-bool EnableIncrementalAnalysis() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3FilterAnalyzerIncrementalAnalysisKillSwitch");
-}
-
} // namespace
int FilterAnalyzer::instance_count_ = 0;
@@ -60,10 +49,8 @@
FilterAnalyzer::FilterAnalyzer(const EchoCanceller3Config& config)
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
- use_preprocessed_filter_(EnableFilterPreprocessing()),
bounded_erl_(config.ep_strength.bounded_erl),
- default_gain_(config.ep_strength.lf),
- use_incremental_analysis_(EnableIncrementalAnalysis()),
+ default_gain_(config.ep_strength.default_gain),
h_highpass_(GetTimeDomainLength(config.filter.main.length_blocks), 0.f),
filter_length_blocks_(config.filter.main_initial.length_blocks),
consistent_filter_detector_(config) {
@@ -99,19 +86,17 @@
PreProcessFilter(filter_time_domain);
data_dumper_->DumpRaw("aec3_linear_filter_processed_td", h_highpass_);
- const auto& filter_to_analyze =
- use_preprocessed_filter_ ? h_highpass_ : filter_time_domain;
- RTC_DCHECK_EQ(filter_to_analyze.size(), filter_time_domain.size());
+ RTC_DCHECK_EQ(h_highpass_.size(), filter_time_domain.size());
- peak_index_ = FindPeakIndex(filter_to_analyze, peak_index_,
- region_.start_sample_, region_.end_sample_);
+ peak_index_ = FindPeakIndex(h_highpass_, peak_index_, region_.start_sample_,
+ region_.end_sample_);
delay_blocks_ = peak_index_ >> kBlockSizeLog2;
- UpdateFilterGain(filter_to_analyze, peak_index_);
+ UpdateFilterGain(h_highpass_, peak_index_);
filter_length_blocks_ = filter_time_domain.size() * (1.f / kBlockSize);
consistent_estimate_ = consistent_filter_detector_.Detect(
- filter_to_analyze, region_, render_buffer.Block(-delay_blocks_)[0],
- peak_index_, delay_blocks_);
+ h_highpass_, region_, render_buffer.Block(-delay_blocks_)[0], peak_index_,
+ delay_blocks_);
}
void FilterAnalyzer::UpdateFilterGain(
@@ -159,17 +144,11 @@
rtc::ArrayView<const float> filter_time_domain) {
constexpr size_t kNumberBlocksToUpdate = 1;
auto& r = region_;
- if (use_incremental_analysis_) {
r.start_sample_ =
r.end_sample_ == filter_time_domain.size() - 1 ? 0 : r.end_sample_ + 1;
r.end_sample_ =
std::min(r.start_sample_ + kNumberBlocksToUpdate * kBlockSize - 1,
filter_time_domain.size() - 1);
-
- } else {
- r.start_sample_ = 0;
- r.end_sample_ = filter_time_domain.size() - 1;
- }
}
FilterAnalyzer::ConsistentFilterDetector::ConsistentFilterDetector(
diff --git a/modules/audio_processing/aec3/filter_analyzer.h b/modules/audio_processing/aec3/filter_analyzer.h
index e0fd069..37d8efd 100644
--- a/modules/audio_processing/aec3/filter_analyzer.h
+++ b/modules/audio_processing/aec3/filter_analyzer.h
@@ -19,7 +19,7 @@
#include "api/array_view.h"
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -97,10 +97,8 @@
static int instance_count_;
std::unique_ptr<ApmDataDumper> data_dumper_;
- const bool use_preprocessed_filter_;
const bool bounded_erl_;
const float default_gain_;
- const bool use_incremental_analysis_;
std::vector<float> h_highpass_;
int delay_blocks_ = 0;
size_t blocks_since_reset_ = 0;
diff --git a/modules/audio_processing/aec3/frame_blocker.h b/modules/audio_processing/aec3/frame_blocker.h
index 08e1e1d..68cee97 100644
--- a/modules/audio_processing/aec3/frame_blocker.h
+++ b/modules/audio_processing/aec3/frame_blocker.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/main_filter_update_gain.cc b/modules/audio_processing/aec3/main_filter_update_gain.cc
index ef87d14..11a97e2 100644
--- a/modules/audio_processing/aec3/main_filter_update_gain.cc
+++ b/modules/audio_processing/aec3/main_filter_update_gain.cc
@@ -20,7 +20,7 @@
#include "modules/audio_processing/aec3/render_signal_analyzer.h"
#include "modules/audio_processing/aec3/subtractor_output.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/main_filter_update_gain.h b/modules/audio_processing/aec3/main_filter_update_gain.h
index 892ff68..5c817cd 100644
--- a/modules/audio_processing/aec3/main_filter_update_gain.h
+++ b/modules/audio_processing/aec3/main_filter_update_gain.h
@@ -17,7 +17,7 @@
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
index 093b194..46165e5 100644
--- a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
+++ b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
@@ -63,10 +63,9 @@
Random random_generator(42U);
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
std::vector<float> y(kBlockSize, 0.f);
- config.delay.min_echo_path_delay_blocks = 0;
config.delay.default_delay = 1;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
AecState aec_state(config);
RenderSignalAnalyzer render_signal_analyzer(config);
absl::optional<DelayEstimate> delay_estimate;
diff --git a/modules/audio_processing/aec3/matched_filter.h b/modules/audio_processing/aec3/matched_filter.h
index 2a65339..084267f 100644
--- a/modules/audio_processing/aec3/matched_filter.h
+++ b/modules/audio_processing/aec3/matched_filter.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/arch.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
index f59525e..603a864 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
@@ -57,6 +57,7 @@
// TODO(peah): Remove this logging once all development is done.
data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_best_index",
best_lag_estimate_index);
+ data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_histogram", histogram_);
if (best_lag_estimate_index != -1) {
RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]);
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
index d7f34ae..0cc7789 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
@@ -17,7 +17,7 @@
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/delay_estimate.h"
#include "modules/audio_processing/aec3/matched_filter.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/matched_filter_unittest.cc b/modules/audio_processing/aec3/matched_filter_unittest.cc
index 0c17118..bf650bc 100644
--- a/modules/audio_processing/aec3/matched_filter_unittest.cc
+++ b/modules/audio_processing/aec3/matched_filter_unittest.cc
@@ -153,8 +153,6 @@
EchoCanceller3Config config;
config.delay.down_sampling_factor = down_sampling_factor;
config.delay.num_filters = kNumMatchedFilters;
- config.delay.min_echo_path_delay_blocks = 0;
- config.delay.api_call_jitter_blocks = 0;
Decimator capture_decimator(down_sampling_factor);
DelayBuffer<float> signal_delay_buffer(down_sampling_factor *
delay_samples);
@@ -165,7 +163,7 @@
config.delay.delay_candidate_detection_threshold);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
// Analyze the correlation between render and capture.
for (size_t k = 0; k < (600 + delay_samples / sub_block_size); ++k) {
@@ -261,7 +259,7 @@
std::fill(capture.begin(), capture.end(), 0.f);
ApmDataDumper data_dumper(0);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
MatchedFilter filter(&data_dumper, DetectOptimization(), sub_block_size,
kWindowSizeSubBlocks, kNumMatchedFilters,
kAlignmentShiftSubBlocks, 150,
@@ -306,7 +304,7 @@
config.delay.delay_estimate_smoothing,
config.delay.delay_candidate_detection_threshold);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
Decimator capture_decimator(down_sampling_factor);
// Analyze the correlation between render and capture.
diff --git a/modules/audio_processing/aec3/render_buffer.h b/modules/audio_processing/aec3/render_buffer.h
index 4c7c60c..cc6cd1c 100644
--- a/modules/audio_processing/aec3/render_buffer.h
+++ b/modules/audio_processing/aec3/render_buffer.h
@@ -22,7 +22,7 @@
#include "modules/audio_processing/aec3/matrix_buffer.h"
#include "modules/audio_processing/aec3/vector_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/render_delay_buffer.cc b/modules/audio_processing/aec3/render_delay_buffer.cc
index 1ec2779..fea2d6e 100644
--- a/modules/audio_processing/aec3/render_delay_buffer.cc
+++ b/modules/audio_processing/aec3/render_delay_buffer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2018 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
@@ -8,47 +8,44 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "modules/audio_processing/aec3/render_delay_buffer.h"
-
-#include <stdlib.h>
+#include <string.h>
#include <algorithm>
#include <memory>
#include <numeric>
+#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/aec3_fft.h"
#include "modules/audio_processing/aec3/decimator.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
#include "modules/audio_processing/aec3/fft_buffer.h"
#include "modules/audio_processing/aec3/fft_data.h"
#include "modules/audio_processing/aec3/matrix_buffer.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
#include "modules/audio_processing/aec3/vector_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
#include "rtc_base/logging.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnableZeroExternalDelayHeadroom() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch");
-}
-
class RenderDelayBufferImpl final : public RenderDelayBuffer {
public:
RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands);
+ RenderDelayBufferImpl() = delete;
~RenderDelayBufferImpl() override;
void Reset() override;
BufferingEvent Insert(const std::vector<std::vector<float>>& block) override;
BufferingEvent PrepareCaptureProcessing() override;
bool SetDelay(size_t delay) override;
- size_t Delay() const override { return MapInternalDelayToExternalDelay(); }
+ size_t Delay() const override { return ComputeDelay(); }
size_t MaxDelay() const override {
return blocks_.buffer.size() - 1 - buffer_headroom_;
}
@@ -58,8 +55,7 @@
return low_rate_;
}
- bool CausalDelay(size_t delay) const override;
-
+ int BufferLatency() const;
void SetAudioBufferDelay(size_t delay_ms) override;
private:
@@ -68,17 +64,14 @@
const Aec3Optimization optimization_;
const EchoCanceller3Config config_;
size_t down_sampling_factor_;
- const bool use_zero_external_delay_headroom_;
const int sub_block_size_;
MatrixBuffer blocks_;
VectorBuffer spectra_;
FftBuffer ffts_;
absl::optional<size_t> delay_;
- absl::optional<int> internal_delay_;
RenderBuffer echo_remover_buffer_;
DownsampledRenderBuffer low_rate_;
Decimator render_decimator_;
- const std::vector<std::vector<float>> zero_block_;
const Aec3Fft fft_;
std::vector<float> render_ds_;
const int buffer_headroom_;
@@ -90,81 +83,25 @@
bool render_activity_ = false;
size_t render_activity_counter_ = 0;
absl::optional<size_t> external_audio_buffer_delay_;
- bool external_delay_verified_after_reset_ = false;
+ bool external_audio_buffer_delay_verified_after_reset_ = false;
+ size_t min_latency_blocks_ = 0;
+ size_t excess_render_detection_counter_ = 0;
+ size_t num_bands_;
- int LowRateBufferOffset() const { return DelayEstimatorOffset(config_) >> 1; }
- int MapExternalDelayToInternalDelay(size_t external_delay_blocks) const;
- int MapInternalDelayToExternalDelay() const;
- void ApplyDelay(int delay);
+ int MapDelayToTotalDelay(size_t delay) const;
+ int ComputeDelay() const;
+ void ApplyTotalDelay(int delay);
void InsertBlock(const std::vector<std::vector<float>>& block,
int previous_write);
bool DetectActiveRender(rtc::ArrayView<const float> x) const;
-
- RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayBufferImpl);
+ bool DetectExcessRenderBlocks();
+ void IncrementWriteIndices();
+ void IncrementLowRateReadIndices();
+ void IncrementReadIndices();
+ bool RenderOverrun();
+ bool RenderUnderrun();
};
-// Increases the write indices for the render buffers.
-void IncreaseWriteIndices(int sub_block_size,
- MatrixBuffer* blocks,
- VectorBuffer* spectra,
- FftBuffer* ffts,
- DownsampledRenderBuffer* low_rate) {
- low_rate->UpdateWriteIndex(-sub_block_size);
- blocks->IncWriteIndex();
- spectra->DecWriteIndex();
- ffts->DecWriteIndex();
-}
-
-// Increases the read indices for the render buffers.
-void IncreaseReadIndices(const absl::optional<int>& delay,
- int sub_block_size,
- MatrixBuffer* blocks,
- VectorBuffer* spectra,
- FftBuffer* ffts,
- DownsampledRenderBuffer* low_rate) {
- RTC_DCHECK_NE(low_rate->read, low_rate->write);
- low_rate->UpdateReadIndex(-sub_block_size);
-
- if (blocks->read != blocks->write) {
- blocks->IncReadIndex();
- spectra->DecReadIndex();
- ffts->DecReadIndex();
- } else {
- // Only allow underrun for blocks_ when the delay is not set.
- RTC_DCHECK(!delay);
- }
-}
-
-// Checks for a render buffer overrun.
-bool RenderOverrun(const MatrixBuffer& b, const DownsampledRenderBuffer& l) {
- return l.read == l.write || b.read == b.write;
-}
-
-// Checks for a render buffer underrun. If the delay is not specified, only the
-// low rate buffer underrun is counted as the delay offset for the other buffers
-// is unknown.
-bool RenderUnderrun(const absl::optional<int>& delay,
- const MatrixBuffer& b,
- const DownsampledRenderBuffer& l) {
- return l.read == l.write || (delay && b.read == b.write);
-}
-
-// Computes the latency in the buffer (the number of unread elements).
-int BufferLatency(const DownsampledRenderBuffer& l) {
- return (l.buffer.size() + l.read - l.write) % l.buffer.size();
-}
-
-// Computes the mismatch between the number of render and capture calls based on
-// the known offset (achieved during reset) of the low rate buffer.
-bool ApiCallSkew(const DownsampledRenderBuffer& low_rate_buffer,
- int sub_block_size,
- int low_rate_buffer_offset_sub_blocks) {
- int latency = BufferLatency(low_rate_buffer);
- int skew = abs(low_rate_buffer_offset_sub_blocks * sub_block_size - latency);
- int skew_limit = low_rate_buffer_offset_sub_blocks * sub_block_size;
- return skew >= skew_limit;
-}
-
int RenderDelayBufferImpl::instance_count_ = 0;
RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
@@ -174,7 +111,6 @@
optimization_(DetectOptimization()),
config_(config),
down_sampling_factor_(config.delay.down_sampling_factor),
- use_zero_external_delay_headroom_(EnableZeroExternalDelayHeadroom()),
sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
? kBlockSize / down_sampling_factor_
: kBlockSize)),
@@ -190,15 +126,13 @@
low_rate_(GetDownSampledBufferSize(down_sampling_factor_,
config.delay.num_filters)),
render_decimator_(down_sampling_factor_),
- zero_block_(num_bands, std::vector<float>(kBlockSize, 0.f)),
fft_(),
render_ds_(sub_block_size_, 0.f),
- buffer_headroom_(config.filter.main.length_blocks) {
+ buffer_headroom_(config.filter.main.length_blocks),
+ num_bands_(num_bands) {
RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
- // Necessary condition to avoid unrecoverable echp due to noncausal alignment.
- RTC_DCHECK_EQ(DelayEstimatorOffset(config_), LowRateBufferOffset() * 2);
Reset();
}
@@ -208,39 +142,38 @@
void RenderDelayBufferImpl::Reset() {
last_call_was_render_ = false;
num_api_calls_in_a_row_ = 1;
+ min_latency_blocks_ = 0;
+ excess_render_detection_counter_ = 0;
- // Pre-fill the low rate buffer (which is used for delay estimation) to add
- // headroom for the allowed api call jitter.
- low_rate_.read = low_rate_.OffsetIndex(
- low_rate_.write, LowRateBufferOffset() * sub_block_size_);
+ // Initialize the read index to one sub-block before the write index.
+ low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, sub_block_size_);
// Check for any external audio buffer delay and whether it is feasible.
if (external_audio_buffer_delay_) {
- const size_t headroom = use_zero_external_delay_headroom_ ? 0 : 2;
- size_t external_delay_to_set = 0;
- if (*external_audio_buffer_delay_ < headroom) {
- external_delay_to_set = 0;
+ const size_t headroom = 2;
+ size_t audio_buffer_delay_to_set;
+ // Minimum delay is 1 (like the low-rate render buffer).
+ if (*external_audio_buffer_delay_ <= headroom) {
+ audio_buffer_delay_to_set = 1;
} else {
- external_delay_to_set = *external_audio_buffer_delay_ - headroom;
+ audio_buffer_delay_to_set = *external_audio_buffer_delay_ - headroom;
}
- external_delay_to_set = std::min(external_delay_to_set, MaxDelay());
+ audio_buffer_delay_to_set = std::min(audio_buffer_delay_to_set, MaxDelay());
// When an external delay estimate is available, use that delay as the
// initial render buffer delay.
- internal_delay_ = external_delay_to_set;
- ApplyDelay(*internal_delay_);
- delay_ = MapInternalDelayToExternalDelay();
+ ApplyTotalDelay(audio_buffer_delay_to_set);
+ delay_ = ComputeDelay();
- external_delay_verified_after_reset_ = false;
+ external_audio_buffer_delay_verified_after_reset_ = false;
} else {
// If an external delay estimate is not available, use that delay as the
// initial delay. Set the render buffer delays to the default delay.
- ApplyDelay(config_.delay.default_delay);
+ ApplyTotalDelay(config_.delay.default_delay);
// Unset the delays which are set by SetDelay.
delay_ = absl::nullopt;
- internal_delay_ = absl::nullopt;
}
}
@@ -265,14 +198,12 @@
// Increase the write indices to where the new blocks should be written.
const int previous_write = blocks_.write;
- IncreaseWriteIndices(sub_block_size_, &blocks_, &spectra_, &ffts_,
- &low_rate_);
+ IncrementWriteIndices();
// Allow overrun and do a reset when render overrun occurrs due to more render
// data being inserted than capture data is received.
- BufferingEvent event = RenderOverrun(blocks_, low_rate_)
- ? BufferingEvent::kRenderOverrun
- : BufferingEvent::kNone;
+ BufferingEvent event =
+ RenderOverrun() ? BufferingEvent::kRenderOverrun : BufferingEvent::kNone;
// Detect and update render activity.
if (!render_activity_) {
@@ -293,7 +224,7 @@
// Prepares the render buffers for processing another capture block.
RenderDelayBuffer::BufferingEvent
RenderDelayBufferImpl::PrepareCaptureProcessing() {
- BufferingEvent event = BufferingEvent::kNone;
+ RenderDelayBuffer::BufferingEvent event = BufferingEvent::kNone;
++capture_call_counter_;
if (delay_) {
@@ -311,26 +242,29 @@
}
}
- if (RenderUnderrun(internal_delay_, blocks_, low_rate_)) {
- // Don't increase the read indices if there is a render underrun.
+ if (DetectExcessRenderBlocks()) {
+ // Too many render blocks compared to capture blocks. Risk of delay ending
+ // up before the filter used by the delay estimator.
+ RTC_LOG(LS_WARNING) << "Excess render blocks detected at block "
+ << capture_call_counter_;
+ Reset();
+ event = BufferingEvent::kRenderOverrun;
+ } else if (RenderUnderrun()) {
+ // Don't increment the read indices of the low rate buffer if there is a
+ // render underrun.
+ RTC_LOG(LS_WARNING) << "Render buffer underrun detected at block "
+ << capture_call_counter_;
+ IncrementReadIndices();
+ // Incrementing the buffer index without increasing the low rate buffer
+ // index means that the delay is reduced by one.
+ if (delay_ && *delay_ > 0)
+ delay_ = *delay_ - 1;
event = BufferingEvent::kRenderUnderrun;
} else {
- // Increase the read indices in the render buffers to point to the most
+ // Increment the read indices in the render buffers to point to the most
// recent block to use in the capture processing.
- IncreaseReadIndices(internal_delay_, sub_block_size_, &blocks_, &spectra_,
- &ffts_, &low_rate_);
-
- // Check for skew in the API calls which, if too large, causes the delay
- // estimation to be noncausal. Doing this check after the render indice
- // increase saves one unit of allowed skew. Note that the skew check only
- // should need to be one-sided as one of the skew directions results in an
- // underrun.
- bool skew = ApiCallSkew(low_rate_, sub_block_size_, LowRateBufferOffset());
- event = skew ? BufferingEvent::kApiCallSkew : BufferingEvent::kNone;
- }
-
- if (event != BufferingEvent::kNone) {
- Reset();
+ IncrementLowRateReadIndices();
+ IncrementReadIndices();
}
echo_remover_buffer_.SetRenderActivity(render_activity_);
@@ -344,76 +278,60 @@
// Sets the delay and returns a bool indicating whether the delay was changed.
bool RenderDelayBufferImpl::SetDelay(size_t delay) {
- if (!external_delay_verified_after_reset_ && external_audio_buffer_delay_ &&
- delay_) {
+ if (!external_audio_buffer_delay_verified_after_reset_ &&
+ external_audio_buffer_delay_ && delay_) {
int difference = static_cast<int>(delay) - static_cast<int>(*delay_);
RTC_LOG(LS_WARNING) << "Mismatch between first estimated delay after reset "
- "and external delay: "
+ "and externally reported audio buffer delay: "
<< difference << " blocks";
- external_delay_verified_after_reset_ = true;
+ external_audio_buffer_delay_verified_after_reset_ = true;
}
if (delay_ && *delay_ == delay) {
return false;
}
delay_ = delay;
- // Compute the internal delay and limit the delay to the allowed range.
- int internal_delay = MapExternalDelayToInternalDelay(*delay_);
- internal_delay_ =
- std::min(MaxDelay(), static_cast<size_t>(std::max(internal_delay, 0)));
+ // Compute the total delay and limit the delay to the allowed range.
+ int total_delay = MapDelayToTotalDelay(*delay_);
+ total_delay =
+ std::min(MaxDelay(), static_cast<size_t>(std::max(total_delay, 0)));
// Apply the delay to the buffers.
- ApplyDelay(*internal_delay_);
+ ApplyTotalDelay(total_delay);
return true;
}
-// Returns whether the specified delay is causal.
-bool RenderDelayBufferImpl::CausalDelay(size_t delay) const {
- // Compute the internal delay and limit the delay to the allowed range.
- int internal_delay = MapExternalDelayToInternalDelay(delay);
- internal_delay =
- std::min(MaxDelay(), static_cast<size_t>(std::max(internal_delay, 0)));
-
- return internal_delay >=
- static_cast<int>(config_.delay.min_echo_path_delay_blocks);
-}
-
void RenderDelayBufferImpl::SetAudioBufferDelay(size_t delay_ms) {
if (!external_audio_buffer_delay_) {
RTC_LOG(LS_WARNING)
- << "Receiving a first reported externally buffer delay of " << delay_ms
- << " ms.";
+ << "Receiving a first externally reported audio buffer delay of "
+ << delay_ms << " ms.";
}
// Convert delay from milliseconds to blocks (rounded down).
- external_audio_buffer_delay_ = delay_ms / 4;
+ external_audio_buffer_delay_ = delay_ms >> ((num_bands_ == 1) ? 1 : 2);
}
// Maps the externally computed delay to the delay used internally.
-int RenderDelayBufferImpl::MapExternalDelayToInternalDelay(
+int RenderDelayBufferImpl::MapDelayToTotalDelay(
size_t external_delay_blocks) const {
- const int latency = BufferLatency(low_rate_);
- RTC_DCHECK_LT(0, sub_block_size_);
- RTC_DCHECK_EQ(0, latency % sub_block_size_);
- int latency_blocks = latency / sub_block_size_;
- return latency_blocks + static_cast<int>(external_delay_blocks) -
- DelayEstimatorOffset(config_);
+ const int latency_blocks = BufferLatency();
+ return latency_blocks + static_cast<int>(external_delay_blocks);
}
-// Maps the internally used delay to the delay used externally.
-int RenderDelayBufferImpl::MapInternalDelayToExternalDelay() const {
- const int latency = BufferLatency(low_rate_);
- int latency_blocks = latency / sub_block_size_;
+// Returns the delay (not including call jitter).
+int RenderDelayBufferImpl::ComputeDelay() const {
+ const int latency_blocks = BufferLatency();
int internal_delay = spectra_.read >= spectra_.write
? spectra_.read - spectra_.write
: spectra_.size + spectra_.read - spectra_.write;
- return internal_delay - latency_blocks + DelayEstimatorOffset(config_);
+ return internal_delay - latency_blocks;
}
// Set the read indices according to the delay.
-void RenderDelayBufferImpl::ApplyDelay(int delay) {
- RTC_LOG(LS_WARNING) << "Applying internal delay of " << delay << " blocks.";
+void RenderDelayBufferImpl::ApplyTotalDelay(int delay) {
+ RTC_LOG(LS_WARNING) << "Applying total delay of " << delay << " blocks.";
blocks_.read = blocks_.OffsetIndex(blocks_.write, -delay);
spectra_.read = spectra_.OffsetIndex(spectra_.write, delay);
ffts_.read = ffts_.OffsetIndex(ffts_.write, delay);
@@ -452,13 +370,72 @@
kFftLengthBy2;
}
-} // namespace
+bool RenderDelayBufferImpl::DetectExcessRenderBlocks() {
+ bool excess_render_detected = false;
+ const size_t latency_blocks = static_cast<size_t>(BufferLatency());
+ // The recently seen minimum latency in blocks. Should be close to 0.
+ min_latency_blocks_ = std::min(min_latency_blocks_, latency_blocks);
+ // After processing a configurable number of blocks the minimum latency is
+ // checked.
+ if (++excess_render_detection_counter_ >=
+ config_.buffering.excess_render_detection_interval_blocks) {
+ // If the minimum latency is not lower than the threshold there have been
+ // more render than capture frames.
+ excess_render_detected = min_latency_blocks_ >
+ config_.buffering.max_allowed_excess_render_blocks;
+ // Reset the counter and let the minimum latency be the current latency.
+ min_latency_blocks_ = latency_blocks;
+ excess_render_detection_counter_ = 0;
+ }
-int RenderDelayBuffer::RenderDelayBuffer::DelayEstimatorOffset(
- const EchoCanceller3Config& config) {
- return config.delay.api_call_jitter_blocks * 2;
+ data_dumper_->DumpRaw("aec3_latency_blocks", latency_blocks);
+ data_dumper_->DumpRaw("aec3_min_latency_blocks", min_latency_blocks_);
+ data_dumper_->DumpRaw("aec3_excess_render_detected", excess_render_detected);
+ return excess_render_detected;
}
+// Computes the latency in the buffer (the number of unread sub-blocks).
+int RenderDelayBufferImpl::BufferLatency() const {
+ const DownsampledRenderBuffer& l = low_rate_;
+ int latency_samples = (l.buffer.size() + l.read - l.write) % l.buffer.size();
+ int latency_blocks = latency_samples / sub_block_size_;
+ return latency_blocks;
+}
+
+// Increments the write indices for the render buffers.
+void RenderDelayBufferImpl::IncrementWriteIndices() {
+ low_rate_.UpdateWriteIndex(-sub_block_size_);
+ blocks_.IncWriteIndex();
+ spectra_.DecWriteIndex();
+ ffts_.DecWriteIndex();
+}
+
+// Increments the read indices of the low rate render buffers.
+void RenderDelayBufferImpl::IncrementLowRateReadIndices() {
+ low_rate_.UpdateReadIndex(-sub_block_size_);
+}
+
+// Increments the read indices for the render buffers.
+void RenderDelayBufferImpl::IncrementReadIndices() {
+ if (blocks_.read != blocks_.write) {
+ blocks_.IncReadIndex();
+ spectra_.DecReadIndex();
+ ffts_.DecReadIndex();
+ }
+}
+
+// Checks for a render buffer overrun.
+bool RenderDelayBufferImpl::RenderOverrun() {
+ return low_rate_.read == low_rate_.write || blocks_.read == blocks_.write;
+}
+
+// Checks for a render buffer underrun.
+bool RenderDelayBufferImpl::RenderUnderrun() {
+ return low_rate_.read == low_rate_.write;
+}
+
+} // namespace
+
RenderDelayBuffer* RenderDelayBuffer::Create(const EchoCanceller3Config& config,
size_t num_bands) {
return new RenderDelayBufferImpl(config, num_bands);
diff --git a/modules/audio_processing/aec3/render_delay_buffer.h b/modules/audio_processing/aec3/render_delay_buffer.h
index bd242f7..6926c67 100644
--- a/modules/audio_processing/aec3/render_delay_buffer.h
+++ b/modules/audio_processing/aec3/render_delay_buffer.h
@@ -33,8 +33,6 @@
static RenderDelayBuffer* Create(const EchoCanceller3Config& config,
size_t num_bands);
- static RenderDelayBuffer* Create2(const EchoCanceller3Config& config,
- size_t num_bands);
virtual ~RenderDelayBuffer() = default;
// Resets the buffer alignment.
@@ -64,9 +62,6 @@
// Returns the downsampled render buffer.
virtual const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const = 0;
- // Returns whether the current delay is noncausal.
- virtual bool CausalDelay(size_t delay) const = 0;
-
// Returns the maximum non calusal offset that can occur in the delay buffer.
static int DelayEstimatorOffset(const EchoCanceller3Config& config);
diff --git a/modules/audio_processing/aec3/render_delay_buffer2.cc b/modules/audio_processing/aec3/render_delay_buffer2.cc
deleted file mode 100644
index 6992c5b..0000000
--- a/modules/audio_processing/aec3/render_delay_buffer2.cc
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (c) 2018 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 <string.h>
-#include <algorithm>
-#include <memory>
-#include <numeric>
-#include <vector>
-
-#include "absl/types/optional.h"
-#include "api/array_view.h"
-#include "api/audio/echo_canceller3_config.h"
-#include "modules/audio_processing/aec3/aec3_common.h"
-#include "modules/audio_processing/aec3/aec3_fft.h"
-#include "modules/audio_processing/aec3/decimator.h"
-#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
-#include "modules/audio_processing/aec3/fft_buffer.h"
-#include "modules/audio_processing/aec3/fft_data.h"
-#include "modules/audio_processing/aec3/matrix_buffer.h"
-#include "modules/audio_processing/aec3/render_buffer.h"
-#include "modules/audio_processing/aec3/render_delay_buffer.h"
-#include "modules/audio_processing/aec3/vector_buffer.h"
-#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-namespace {
-
-class RenderDelayBufferImpl2 final : public RenderDelayBuffer {
- public:
- RenderDelayBufferImpl2(const EchoCanceller3Config& config, size_t num_bands);
- RenderDelayBufferImpl2() = delete;
- ~RenderDelayBufferImpl2() override;
-
- void Reset() override;
- BufferingEvent Insert(const std::vector<std::vector<float>>& block) override;
- BufferingEvent PrepareCaptureProcessing() override;
- bool SetDelay(size_t delay) override;
- size_t Delay() const override { return ComputeDelay(); }
- size_t MaxDelay() const override {
- return blocks_.buffer.size() - 1 - buffer_headroom_;
- }
- RenderBuffer* GetRenderBuffer() override { return &echo_remover_buffer_; }
-
- const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override {
- return low_rate_;
- }
-
- int BufferLatency() const;
- bool CausalDelay(size_t delay) const override;
- void SetAudioBufferDelay(size_t delay_ms) override;
-
- private:
- static int instance_count_;
- std::unique_ptr<ApmDataDumper> data_dumper_;
- const Aec3Optimization optimization_;
- const EchoCanceller3Config config_;
- size_t down_sampling_factor_;
- const int sub_block_size_;
- MatrixBuffer blocks_;
- VectorBuffer spectra_;
- FftBuffer ffts_;
- absl::optional<size_t> delay_;
- RenderBuffer echo_remover_buffer_;
- DownsampledRenderBuffer low_rate_;
- Decimator render_decimator_;
- const Aec3Fft fft_;
- std::vector<float> render_ds_;
- const int buffer_headroom_;
- bool last_call_was_render_ = false;
- int num_api_calls_in_a_row_ = 0;
- int max_observed_jitter_ = 1;
- size_t capture_call_counter_ = 0;
- size_t render_call_counter_ = 0;
- bool render_activity_ = false;
- size_t render_activity_counter_ = 0;
- absl::optional<size_t> external_audio_buffer_delay_;
- bool external_audio_buffer_delay_verified_after_reset_ = false;
- size_t min_latency_blocks_ = 0;
- size_t excess_render_detection_counter_ = 0;
- size_t num_bands_;
-
- int MapDelayToTotalDelay(size_t delay) const;
- int ComputeDelay() const;
- void ApplyTotalDelay(int delay);
- void InsertBlock(const std::vector<std::vector<float>>& block,
- int previous_write);
- bool DetectActiveRender(rtc::ArrayView<const float> x) const;
- bool DetectExcessRenderBlocks();
- void IncrementWriteIndices();
- void IncrementLowRateReadIndices();
- void IncrementReadIndices();
- bool RenderOverrun();
- bool RenderUnderrun();
-};
-
-int RenderDelayBufferImpl2::instance_count_ = 0;
-
-RenderDelayBufferImpl2::RenderDelayBufferImpl2(
- const EchoCanceller3Config& config,
- size_t num_bands)
- : data_dumper_(
- new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
- optimization_(DetectOptimization()),
- config_(config),
- down_sampling_factor_(config.delay.down_sampling_factor),
- sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
- ? kBlockSize / down_sampling_factor_
- : kBlockSize)),
- blocks_(GetRenderDelayBufferSize(down_sampling_factor_,
- config.delay.num_filters,
- config.filter.main.length_blocks),
- num_bands,
- kBlockSize),
- spectra_(blocks_.buffer.size(), kFftLengthBy2Plus1),
- ffts_(blocks_.buffer.size()),
- delay_(config_.delay.default_delay),
- echo_remover_buffer_(&blocks_, &spectra_, &ffts_),
- low_rate_(GetDownSampledBufferSize(down_sampling_factor_,
- config.delay.num_filters)),
- render_decimator_(down_sampling_factor_),
- fft_(),
- render_ds_(sub_block_size_, 0.f),
- buffer_headroom_(config.filter.main.length_blocks),
- num_bands_(num_bands) {
- RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
- RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
-
- Reset();
-}
-
-RenderDelayBufferImpl2::~RenderDelayBufferImpl2() = default;
-
-// Resets the buffer delays and clears the reported delays.
-void RenderDelayBufferImpl2::Reset() {
- last_call_was_render_ = false;
- num_api_calls_in_a_row_ = 1;
- min_latency_blocks_ = 0;
- excess_render_detection_counter_ = 0;
-
- // Initialize the read index to one sub-block before the write index.
- low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, sub_block_size_);
-
- // Check for any external audio buffer delay and whether it is feasible.
- if (external_audio_buffer_delay_) {
- const size_t headroom = 2;
- size_t audio_buffer_delay_to_set;
- // Minimum delay is 1 (like the low-rate render buffer).
- if (*external_audio_buffer_delay_ <= headroom) {
- audio_buffer_delay_to_set = 1;
- } else {
- audio_buffer_delay_to_set = *external_audio_buffer_delay_ - headroom;
- }
-
- audio_buffer_delay_to_set = std::min(audio_buffer_delay_to_set, MaxDelay());
-
- // When an external delay estimate is available, use that delay as the
- // initial render buffer delay.
- ApplyTotalDelay(audio_buffer_delay_to_set);
- delay_ = ComputeDelay();
-
- external_audio_buffer_delay_verified_after_reset_ = false;
- } else {
- // If an external delay estimate is not available, use that delay as the
- // initial delay. Set the render buffer delays to the default delay.
- ApplyTotalDelay(config_.delay.default_delay);
-
- // Unset the delays which are set by SetDelay.
- delay_ = absl::nullopt;
- }
-}
-
-// Inserts a new block into the render buffers.
-RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl2::Insert(
- const std::vector<std::vector<float>>& block) {
- ++render_call_counter_;
- if (delay_) {
- if (!last_call_was_render_) {
- last_call_was_render_ = true;
- num_api_calls_in_a_row_ = 1;
- } else {
- if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
- max_observed_jitter_ = num_api_calls_in_a_row_;
- RTC_LOG(LS_WARNING)
- << "New max number api jitter observed at render block "
- << render_call_counter_ << ": " << num_api_calls_in_a_row_
- << " blocks";
- }
- }
- }
-
- // Increase the write indices to where the new blocks should be written.
- const int previous_write = blocks_.write;
- IncrementWriteIndices();
-
- // Allow overrun and do a reset when render overrun occurrs due to more render
- // data being inserted than capture data is received.
- BufferingEvent event =
- RenderOverrun() ? BufferingEvent::kRenderOverrun : BufferingEvent::kNone;
-
- // Detect and update render activity.
- if (!render_activity_) {
- render_activity_counter_ += DetectActiveRender(block[0]) ? 1 : 0;
- render_activity_ = render_activity_counter_ >= 20;
- }
-
- // Insert the new render block into the specified position.
- InsertBlock(block, previous_write);
-
- if (event != BufferingEvent::kNone) {
- Reset();
- }
-
- return event;
-}
-
-// Prepares the render buffers for processing another capture block.
-RenderDelayBuffer::BufferingEvent
-RenderDelayBufferImpl2::PrepareCaptureProcessing() {
- RenderDelayBuffer::BufferingEvent event = BufferingEvent::kNone;
- ++capture_call_counter_;
-
- if (delay_) {
- if (last_call_was_render_) {
- last_call_was_render_ = false;
- num_api_calls_in_a_row_ = 1;
- } else {
- if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
- max_observed_jitter_ = num_api_calls_in_a_row_;
- RTC_LOG(LS_WARNING)
- << "New max number api jitter observed at capture block "
- << capture_call_counter_ << ": " << num_api_calls_in_a_row_
- << " blocks";
- }
- }
- }
-
- if (DetectExcessRenderBlocks()) {
- // Too many render blocks compared to capture blocks. Risk of delay ending
- // up before the filter used by the delay estimator.
- RTC_LOG(LS_WARNING) << "Excess render blocks detected at block "
- << capture_call_counter_;
- Reset();
- event = BufferingEvent::kRenderOverrun;
- } else if (RenderUnderrun()) {
- // Don't increment the read indices of the low rate buffer if there is a
- // render underrun.
- RTC_LOG(LS_WARNING) << "Render buffer underrun detected at block "
- << capture_call_counter_;
- IncrementReadIndices();
- // Incrementing the buffer index without increasing the low rate buffer
- // index means that the delay is reduced by one.
- if (delay_ && *delay_ > 0)
- delay_ = *delay_ - 1;
- event = BufferingEvent::kRenderUnderrun;
- } else {
- // Increment the read indices in the render buffers to point to the most
- // recent block to use in the capture processing.
- IncrementLowRateReadIndices();
- IncrementReadIndices();
- }
-
- echo_remover_buffer_.SetRenderActivity(render_activity_);
- if (render_activity_) {
- render_activity_counter_ = 0;
- render_activity_ = false;
- }
-
- return event;
-}
-
-// Sets the delay and returns a bool indicating whether the delay was changed.
-bool RenderDelayBufferImpl2::SetDelay(size_t delay) {
- if (!external_audio_buffer_delay_verified_after_reset_ &&
- external_audio_buffer_delay_ && delay_) {
- int difference = static_cast<int>(delay) - static_cast<int>(*delay_);
- RTC_LOG(LS_WARNING) << "Mismatch between first estimated delay after reset "
- "and externally reported audio buffer delay: "
- << difference << " blocks";
- external_audio_buffer_delay_verified_after_reset_ = true;
- }
- if (delay_ && *delay_ == delay) {
- return false;
- }
- delay_ = delay;
-
- // Compute the total delay and limit the delay to the allowed range.
- int total_delay = MapDelayToTotalDelay(*delay_);
- total_delay =
- std::min(MaxDelay(), static_cast<size_t>(std::max(total_delay, 0)));
-
- // Apply the delay to the buffers.
- ApplyTotalDelay(total_delay);
- return true;
-}
-
-// Returns whether the specified delay is causal.
-bool RenderDelayBufferImpl2::CausalDelay(size_t delay) const {
- // TODO(gustaf): Remove this from RenderDelayBuffer.
- return true;
-}
-
-void RenderDelayBufferImpl2::SetAudioBufferDelay(size_t delay_ms) {
- if (!external_audio_buffer_delay_) {
- RTC_LOG(LS_WARNING)
- << "Receiving a first externally reported audio buffer delay of "
- << delay_ms << " ms.";
- }
-
- // Convert delay from milliseconds to blocks (rounded down).
- external_audio_buffer_delay_ = delay_ms >> ((num_bands_ == 1) ? 1 : 2);
-}
-
-// Maps the externally computed delay to the delay used internally.
-int RenderDelayBufferImpl2::MapDelayToTotalDelay(
- size_t external_delay_blocks) const {
- const int latency_blocks = BufferLatency();
- return latency_blocks + static_cast<int>(external_delay_blocks);
-}
-
-// Returns the delay (not including call jitter).
-int RenderDelayBufferImpl2::ComputeDelay() const {
- const int latency_blocks = BufferLatency();
- int internal_delay = spectra_.read >= spectra_.write
- ? spectra_.read - spectra_.write
- : spectra_.size + spectra_.read - spectra_.write;
-
- return internal_delay - latency_blocks;
-}
-
-// Set the read indices according to the delay.
-void RenderDelayBufferImpl2::ApplyTotalDelay(int delay) {
- RTC_LOG(LS_WARNING) << "Applying total delay of " << delay << " blocks.";
- blocks_.read = blocks_.OffsetIndex(blocks_.write, -delay);
- spectra_.read = spectra_.OffsetIndex(spectra_.write, delay);
- ffts_.read = ffts_.OffsetIndex(ffts_.write, delay);
-}
-
-// Inserts a block into the render buffers.
-void RenderDelayBufferImpl2::InsertBlock(
- const std::vector<std::vector<float>>& block,
- int previous_write) {
- auto& b = blocks_;
- auto& lr = low_rate_;
- auto& ds = render_ds_;
- auto& f = ffts_;
- auto& s = spectra_;
- RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size());
- for (size_t k = 0; k < block.size(); ++k) {
- RTC_DCHECK_EQ(block[k].size(), b.buffer[b.write][k].size());
- std::copy(block[k].begin(), block[k].end(), b.buffer[b.write][k].begin());
- }
-
- data_dumper_->DumpWav("aec3_render_decimator_input", block[0].size(),
- block[0].data(), 16000, 1);
- render_decimator_.Decimate(block[0], ds);
- data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
- 16000 / down_sampling_factor_, 1);
- std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
- fft_.PaddedFft(block[0], b.buffer[previous_write][0], &f.buffer[f.write]);
- f.buffer[f.write].Spectrum(optimization_, s.buffer[s.write]);
-}
-
-bool RenderDelayBufferImpl2::DetectActiveRender(
- rtc::ArrayView<const float> x) const {
- const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f);
- return x_energy > (config_.render_levels.active_render_limit *
- config_.render_levels.active_render_limit) *
- kFftLengthBy2;
-}
-
-bool RenderDelayBufferImpl2::DetectExcessRenderBlocks() {
- bool excess_render_detected = false;
- const size_t latency_blocks = static_cast<size_t>(BufferLatency());
- // The recently seen minimum latency in blocks. Should be close to 0.
- min_latency_blocks_ = std::min(min_latency_blocks_, latency_blocks);
- // After processing a configurable number of blocks the minimum latency is
- // checked.
- if (++excess_render_detection_counter_ >=
- config_.buffering.excess_render_detection_interval_blocks) {
- // If the minimum latency is not lower than the threshold there have been
- // more render than capture frames.
- excess_render_detected = min_latency_blocks_ >
- config_.buffering.max_allowed_excess_render_blocks;
- // Reset the counter and let the minimum latency be the current latency.
- min_latency_blocks_ = latency_blocks;
- excess_render_detection_counter_ = 0;
- }
-
- data_dumper_->DumpRaw("aec3_latency_blocks", latency_blocks);
- data_dumper_->DumpRaw("aec3_min_latency_blocks", min_latency_blocks_);
- data_dumper_->DumpRaw("aec3_excess_render_detected", excess_render_detected);
- return excess_render_detected;
-}
-
-// Computes the latency in the buffer (the number of unread sub-blocks).
-int RenderDelayBufferImpl2::BufferLatency() const {
- const DownsampledRenderBuffer& l = low_rate_;
- int latency_samples = (l.buffer.size() + l.read - l.write) % l.buffer.size();
- int latency_blocks = latency_samples / sub_block_size_;
- return latency_blocks;
-}
-
-// Increments the write indices for the render buffers.
-void RenderDelayBufferImpl2::IncrementWriteIndices() {
- low_rate_.UpdateWriteIndex(-sub_block_size_);
- blocks_.IncWriteIndex();
- spectra_.DecWriteIndex();
- ffts_.DecWriteIndex();
-}
-
-// Increments the read indices of the low rate render buffers.
-void RenderDelayBufferImpl2::IncrementLowRateReadIndices() {
- low_rate_.UpdateReadIndex(-sub_block_size_);
-}
-
-// Increments the read indices for the render buffers.
-void RenderDelayBufferImpl2::IncrementReadIndices() {
- if (blocks_.read != blocks_.write) {
- blocks_.IncReadIndex();
- spectra_.DecReadIndex();
- ffts_.DecReadIndex();
- }
-}
-
-// Checks for a render buffer overrun.
-bool RenderDelayBufferImpl2::RenderOverrun() {
- return low_rate_.read == low_rate_.write || blocks_.read == blocks_.write;
-}
-
-// Checks for a render buffer underrun.
-bool RenderDelayBufferImpl2::RenderUnderrun() {
- return low_rate_.read == low_rate_.write;
-}
-
-} // namespace
-
-RenderDelayBuffer* RenderDelayBuffer::Create2(
- const EchoCanceller3Config& config,
- size_t num_bands) {
- return new RenderDelayBufferImpl2(config, num_bands);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/aec3/render_delay_buffer_unittest.cc b/modules/audio_processing/aec3/render_delay_buffer_unittest.cc
index d1530c6..641a081 100644
--- a/modules/audio_processing/aec3/render_delay_buffer_unittest.cc
+++ b/modules/audio_processing/aec3/render_delay_buffer_unittest.cc
@@ -38,7 +38,7 @@
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::vector<std::vector<float>> block_to_insert(
NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
for (size_t k = 0; k < 10; ++k) {
@@ -62,7 +62,7 @@
TEST(RenderDelayBuffer, AvailableBlock) {
constexpr size_t kNumBands = 1;
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), kNumBands));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), kNumBands));
std::vector<std::vector<float>> input_block(
kNumBands, std::vector<float>(kBlockSize, 1.f));
EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone,
@@ -74,11 +74,10 @@
TEST(RenderDelayBuffer, SetDelay) {
EchoCanceller3Config config;
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(config, 1));
+ RenderDelayBuffer::Create(config, 1));
ASSERT_TRUE(delay_buffer->Delay());
delay_buffer->Reset();
- size_t initial_internal_delay = config.delay.min_echo_path_delay_blocks +
- config.delay.api_call_jitter_blocks;
+ size_t initial_internal_delay = 0;
for (size_t delay = initial_internal_delay;
delay < initial_internal_delay + 20; ++delay) {
ASSERT_TRUE(delay_buffer->SetDelay(delay));
@@ -93,7 +92,7 @@
// tests on test bots has been fixed.
TEST(RenderDelayBuffer, DISABLED_WrongDelay) {
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
EXPECT_DEATH(delay_buffer->SetDelay(21), "");
}
@@ -101,7 +100,7 @@
TEST(RenderDelayBuffer, WrongNumberOfBands) {
for (auto rate : {16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
- std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create2(
+ std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
EchoCanceller3Config(), NumBandsForRate(rate)));
std::vector<std::vector<float>> block_to_insert(
NumBandsForRate(rate < 48000 ? rate + 16000 : 16000),
@@ -115,7 +114,7 @@
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
std::vector<std::vector<float>> block_to_insert(
NumBandsForRate(rate), std::vector<float>(kBlockSize - 1, 0.f));
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
diff --git a/modules/audio_processing/aec3/render_delay_controller.cc b/modules/audio_processing/aec3/render_delay_controller.cc
index c4665ea..4f9fa8e 100644
--- a/modules/audio_processing/aec3/render_delay_controller.cc
+++ b/modules/audio_processing/aec3/render_delay_controller.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2018 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
@@ -7,54 +7,31 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "modules/audio_processing/aec3/render_delay_controller.h"
-
-#include <stdlib.h>
+#include <stddef.h>
#include <algorithm>
#include <memory>
-#include <vector>
+#include "absl/types/optional.h"
+#include "api/array_view.h"
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
+#include "modules/audio_processing/aec3/render_delay_controller.h"
#include "modules/audio_processing/aec3/render_delay_controller_metrics.h"
-#include "modules/audio_processing/aec3/skew_estimator.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/logging.h"
-#include "system_wrappers/include/field_trial.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace {
-int GetSkewHysteresis(const EchoCanceller3Config& config) {
- if (field_trial::IsEnabled("WebRTC-Aec3EnforceSkewHysteresis1")) {
- return 1;
- }
- if (field_trial::IsEnabled("WebRTC-Aec3EnforceSkewHysteresis2")) {
- return 2;
- }
-
- return static_cast<int>(config.delay.skew_hysteresis_blocks);
-}
-
-bool UseOffsetBlocks() {
- return field_trial::IsEnabled("WebRTC-Aec3UseOffsetBlocks");
-}
-
-bool UseEarlyDelayDetection() {
- return !field_trial::IsEnabled("WebRTC-Aec3EarlyDelayDetectionKillSwitch");
-}
-
-constexpr int kSkewHistorySizeLog2 = 8;
-
class RenderDelayControllerImpl final : public RenderDelayController {
public:
RenderDelayControllerImpl(const EchoCanceller3Config& config,
- int non_causal_offset,
int sample_rate_hz);
~RenderDelayControllerImpl() override;
void Reset(bool reset_delay_confidence) override;
@@ -69,58 +46,36 @@
private:
static int instance_count_;
std::unique_ptr<ApmDataDumper> data_dumper_;
- const bool use_early_delay_detection_;
- const int delay_headroom_blocks_;
- const int hysteresis_limit_1_blocks_;
- const int hysteresis_limit_2_blocks_;
- const int skew_hysteresis_blocks_;
- const bool use_offset_blocks_;
+ const int hysteresis_limit_blocks_;
+ const int delay_headroom_samples_;
absl::optional<DelayEstimate> delay_;
EchoPathDelayEstimator delay_estimator_;
- std::vector<float> delay_buf_;
- int delay_buf_index_ = 0;
RenderDelayControllerMetrics metrics_;
- SkewEstimator skew_estimator_;
absl::optional<DelayEstimate> delay_samples_;
- absl::optional<int> skew_;
- int previous_offset_blocks_ = 0;
- int skew_shift_reporting_counter_ = 0;
size_t capture_call_counter_ = 0;
int delay_change_counter_ = 0;
- size_t soft_reset_counter_ = 0;
DelayEstimate::Quality last_delay_estimate_quality_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayControllerImpl);
};
DelayEstimate ComputeBufferDelay(
const absl::optional<DelayEstimate>& current_delay,
- int delay_headroom_blocks,
- int hysteresis_limit_1_blocks,
- int hysteresis_limit_2_blocks,
- int offset_blocks,
+ int hysteresis_limit_blocks,
+ int delay_headroom_samples,
DelayEstimate estimated_delay) {
- // The below division is not exact and the truncation is intended.
- const int echo_path_delay_blocks = estimated_delay.delay >> kBlockSizeLog2;
+ // Subtract delay headroom.
+ const int delay_with_headroom_samples = std::max(
+ static_cast<int>(estimated_delay.delay) - delay_headroom_samples, 0);
// Compute the buffer delay increase required to achieve the desired latency.
- size_t new_delay_blocks = std::max(
- echo_path_delay_blocks + offset_blocks - delay_headroom_blocks, 0);
+ size_t new_delay_blocks = delay_with_headroom_samples >> kBlockSizeLog2;
// Add hysteresis.
if (current_delay) {
size_t current_delay_blocks = current_delay->delay;
- if (new_delay_blocks > current_delay_blocks) {
- if (new_delay_blocks <=
- current_delay_blocks + hysteresis_limit_1_blocks) {
- new_delay_blocks = current_delay_blocks;
- }
- } else if (new_delay_blocks < current_delay_blocks) {
- size_t hysteresis_limit = std::max(
- static_cast<int>(current_delay_blocks) - hysteresis_limit_2_blocks,
- 0);
- if (new_delay_blocks >= hysteresis_limit) {
- new_delay_blocks = current_delay_blocks;
- }
+ if (new_delay_blocks > current_delay_blocks &&
+ new_delay_blocks <= current_delay_blocks + hysteresis_limit_blocks) {
+ new_delay_blocks = current_delay_blocks;
}
}
@@ -133,26 +88,16 @@
RenderDelayControllerImpl::RenderDelayControllerImpl(
const EchoCanceller3Config& config,
- int non_causal_offset,
int sample_rate_hz)
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
- use_early_delay_detection_(UseEarlyDelayDetection()),
- delay_headroom_blocks_(
- static_cast<int>(config.delay.delay_headroom_blocks)),
- hysteresis_limit_1_blocks_(
- static_cast<int>(config.delay.hysteresis_limit_1_blocks)),
- hysteresis_limit_2_blocks_(
- static_cast<int>(config.delay.hysteresis_limit_2_blocks)),
- skew_hysteresis_blocks_(GetSkewHysteresis(config)),
- use_offset_blocks_(UseOffsetBlocks()),
+ hysteresis_limit_blocks_(
+ static_cast<int>(config.delay.hysteresis_limit_blocks)),
+ delay_headroom_samples_(config.delay.delay_headroom_samples),
delay_estimator_(data_dumper_.get(), config),
- delay_buf_(kBlockSize * non_causal_offset, 0.f),
- skew_estimator_(kSkewHistorySizeLog2),
last_delay_estimate_quality_(DelayEstimate::Quality::kCoarse) {
RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
- delay_estimator_.LogDelayEstimationProperties(sample_rate_hz,
- delay_buf_.size());
+ delay_estimator_.LogDelayEstimationProperties(sample_rate_hz, 0);
}
RenderDelayControllerImpl::~RenderDelayControllerImpl() = default;
@@ -160,21 +105,14 @@
void RenderDelayControllerImpl::Reset(bool reset_delay_confidence) {
delay_ = absl::nullopt;
delay_samples_ = absl::nullopt;
- skew_ = absl::nullopt;
- previous_offset_blocks_ = 0;
- std::fill(delay_buf_.begin(), delay_buf_.end(), 0.f);
delay_estimator_.Reset(reset_delay_confidence);
- skew_estimator_.Reset();
delay_change_counter_ = 0;
- soft_reset_counter_ = 0;
if (reset_delay_confidence) {
last_delay_estimate_quality_ = DelayEstimate::Quality::kCoarse;
}
}
-void RenderDelayControllerImpl::LogRenderCall() {
- skew_estimator_.LogRenderCall();
-}
+void RenderDelayControllerImpl::LogRenderCall() {}
absl::optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
const DownsampledRenderBuffer& render_buffer,
@@ -184,12 +122,7 @@
RTC_DCHECK_EQ(kBlockSize, capture.size());
++capture_call_counter_;
- // Estimate the delay with a delayed capture.
- RTC_DCHECK_LT(delay_buf_index_ + kBlockSize - 1, delay_buf_.size());
- rtc::ArrayView<const float> capture_delayed(&delay_buf_[delay_buf_index_],
- kBlockSize);
- auto delay_samples =
- delay_estimator_.EstimateDelay(render_buffer, capture_delayed);
+ auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
// Overrule the delay estimator delay if the echo remover reports a delay.
if (echo_remover_delay) {
@@ -199,13 +132,6 @@
total_echo_remover_delay_samples);
}
- std::copy(capture.begin(), capture.end(),
- delay_buf_.begin() + delay_buf_index_);
- delay_buf_index_ = (delay_buf_index_ + kBlockSize) % delay_buf_.size();
-
- // Compute the latest skew update.
- absl::optional<int> skew = skew_estimator_.GetSkewFromCapture();
-
if (delay_samples) {
if (!delay_samples_ || delay_samples->delay != delay_samples_->delay) {
delay_change_counter_ = 0;
@@ -230,46 +156,6 @@
if (delay_change_counter_ < 2 * kNumBlocksPerSecond) {
++delay_change_counter_;
- // If a new delay estimate is recently obtained, store the skew for that.
- skew_ = skew;
- } else {
- // A reliable skew should have been obtained after 2 seconds.
- RTC_DCHECK(skew_);
- RTC_DCHECK(skew);
- }
-
- ++soft_reset_counter_;
- int offset_blocks = 0;
- if (skew_ && skew && delay_samples_ &&
- delay_samples_->quality == DelayEstimate::Quality::kRefined) {
- // Compute the skew offset and add a margin.
- offset_blocks = *skew_ - *skew;
- if (abs(offset_blocks) <= skew_hysteresis_blocks_) {
- offset_blocks = 0;
- } else if (soft_reset_counter_ > 10 * kNumBlocksPerSecond) {
- // Soft reset the delay estimator if there is a significant offset
- // detected.
- delay_estimator_.Reset(false);
- soft_reset_counter_ = 0;
- }
- }
- if (!use_offset_blocks_)
- offset_blocks = 0;
-
- // Log any changes in the skew.
- skew_shift_reporting_counter_ =
- std::max(0, skew_shift_reporting_counter_ - 1);
- absl::optional<int> skew_shift =
- skew_shift_reporting_counter_ == 0 &&
- previous_offset_blocks_ != offset_blocks
- ? absl::optional<int>(offset_blocks - previous_offset_blocks_)
- : absl::nullopt;
- previous_offset_blocks_ = offset_blocks;
- if (skew_shift) {
- RTC_LOG(LS_WARNING) << "API call skew shift of " << *skew_shift
- << " blocks detected at capture block "
- << capture_call_counter_;
- skew_shift_reporting_counter_ = 3 * kNumBlocksPerSecond;
}
if (delay_samples_) {
@@ -277,29 +163,21 @@
const bool use_hysteresis =
last_delay_estimate_quality_ == DelayEstimate::Quality::kRefined &&
delay_samples_->quality == DelayEstimate::Quality::kRefined;
- delay_ = ComputeBufferDelay(delay_, delay_headroom_blocks_,
- use_hysteresis ? hysteresis_limit_1_blocks_ : 0,
- use_hysteresis ? hysteresis_limit_2_blocks_ : 0,
- offset_blocks, *delay_samples_);
+ delay_ = ComputeBufferDelay(delay_,
+ use_hysteresis ? hysteresis_limit_blocks_ : 0,
+ delay_headroom_samples_, *delay_samples_);
last_delay_estimate_quality_ = delay_samples_->quality;
}
metrics_.Update(delay_samples_ ? absl::optional<size_t>(delay_samples_->delay)
: absl::nullopt,
- delay_ ? delay_->delay : 0, skew_shift,
- delay_estimator_.Clockdrift());
+ delay_ ? delay_->delay : 0, 0, delay_estimator_.Clockdrift());
data_dumper_->DumpRaw("aec3_render_delay_controller_delay",
delay_samples ? delay_samples->delay : 0);
data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay",
delay_ ? delay_->delay : 0);
- data_dumper_->DumpRaw("aec3_render_delay_controller_new_skew",
- skew ? *skew : 0);
- data_dumper_->DumpRaw("aec3_render_delay_controller_old_skew",
- skew_ ? *skew_ : 0);
- data_dumper_->DumpRaw("aec3_render_delay_controller_offset", offset_blocks);
-
return delay_;
}
@@ -311,10 +189,8 @@
RenderDelayController* RenderDelayController::Create(
const EchoCanceller3Config& config,
- int non_causal_offset,
int sample_rate_hz) {
- return new RenderDelayControllerImpl(config, non_causal_offset,
- sample_rate_hz);
+ return new RenderDelayControllerImpl(config, sample_rate_hz);
}
} // namespace webrtc
diff --git a/modules/audio_processing/aec3/render_delay_controller.h b/modules/audio_processing/aec3/render_delay_controller.h
index b46ed89..fb86529 100644
--- a/modules/audio_processing/aec3/render_delay_controller.h
+++ b/modules/audio_processing/aec3/render_delay_controller.h
@@ -25,10 +25,7 @@
class RenderDelayController {
public:
static RenderDelayController* Create(const EchoCanceller3Config& config,
- int non_causal_offset,
int sample_rate_hz);
- static RenderDelayController* Create2(const EchoCanceller3Config& config,
- int sample_rate_hz);
virtual ~RenderDelayController() = default;
// Resets the delay controller. If the delay confidence is reset, the reset
diff --git a/modules/audio_processing/aec3/render_delay_controller2.cc b/modules/audio_processing/aec3/render_delay_controller2.cc
deleted file mode 100644
index 00daf8f..0000000
--- a/modules/audio_processing/aec3/render_delay_controller2.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 2018 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 <stddef.h>
-#include <algorithm>
-#include <memory>
-
-#include "absl/types/optional.h"
-#include "api/array_view.h"
-#include "api/audio/echo_canceller3_config.h"
-#include "modules/audio_processing/aec3/aec3_common.h"
-#include "modules/audio_processing/aec3/delay_estimate.h"
-#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
-#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
-#include "modules/audio_processing/aec3/render_delay_controller.h"
-#include "modules/audio_processing/aec3/render_delay_controller_metrics.h"
-#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "system_wrappers/include/field_trial.h"
-
-namespace webrtc {
-
-namespace {
-
-bool UseEarlyDelayDetection() {
- return !field_trial::IsEnabled("WebRTC-Aec3EarlyDelayDetectionKillSwitch");
-}
-
-class RenderDelayControllerImpl2 final : public RenderDelayController {
- public:
- RenderDelayControllerImpl2(const EchoCanceller3Config& config,
- int sample_rate_hz);
- ~RenderDelayControllerImpl2() override;
- void Reset(bool reset_delay_confidence) override;
- void LogRenderCall() override;
- absl::optional<DelayEstimate> GetDelay(
- const DownsampledRenderBuffer& render_buffer,
- size_t render_delay_buffer_delay,
- const absl::optional<int>& echo_remover_delay,
- rtc::ArrayView<const float> capture) override;
- bool HasClockdrift() const override;
-
- private:
- static int instance_count_;
- std::unique_ptr<ApmDataDumper> data_dumper_;
- const bool use_early_delay_detection_;
- const int delay_headroom_blocks_;
- const int hysteresis_limit_1_blocks_;
- const int hysteresis_limit_2_blocks_;
- absl::optional<DelayEstimate> delay_;
- EchoPathDelayEstimator delay_estimator_;
- RenderDelayControllerMetrics metrics_;
- absl::optional<DelayEstimate> delay_samples_;
- size_t capture_call_counter_ = 0;
- int delay_change_counter_ = 0;
- DelayEstimate::Quality last_delay_estimate_quality_;
- RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayControllerImpl2);
-};
-
-DelayEstimate ComputeBufferDelay(
- const absl::optional<DelayEstimate>& current_delay,
- int delay_headroom_blocks,
- int hysteresis_limit_1_blocks,
- int hysteresis_limit_2_blocks,
- DelayEstimate estimated_delay) {
- // The below division is not exact and the truncation is intended.
- const int echo_path_delay_blocks = estimated_delay.delay >> kBlockSizeLog2;
-
- // Compute the buffer delay increase required to achieve the desired latency.
- size_t new_delay_blocks =
- std::max(echo_path_delay_blocks - delay_headroom_blocks, 0);
-
- // Add hysteresis.
- if (current_delay) {
- size_t current_delay_blocks = current_delay->delay;
- if (new_delay_blocks > current_delay_blocks) {
- if (new_delay_blocks <=
- current_delay_blocks + hysteresis_limit_1_blocks) {
- new_delay_blocks = current_delay_blocks;
- }
- } else if (new_delay_blocks < current_delay_blocks) {
- size_t hysteresis_limit = std::max(
- static_cast<int>(current_delay_blocks) - hysteresis_limit_2_blocks,
- 0);
- if (new_delay_blocks >= hysteresis_limit) {
- new_delay_blocks = current_delay_blocks;
- }
- }
- }
-
- DelayEstimate new_delay = estimated_delay;
- new_delay.delay = new_delay_blocks;
- return new_delay;
-}
-
-int RenderDelayControllerImpl2::instance_count_ = 0;
-
-RenderDelayControllerImpl2::RenderDelayControllerImpl2(
- const EchoCanceller3Config& config,
- int sample_rate_hz)
- : data_dumper_(
- new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
- use_early_delay_detection_(UseEarlyDelayDetection()),
- delay_headroom_blocks_(
- static_cast<int>(config.delay.delay_headroom_blocks)),
- hysteresis_limit_1_blocks_(
- static_cast<int>(config.delay.hysteresis_limit_1_blocks)),
- hysteresis_limit_2_blocks_(
- static_cast<int>(config.delay.hysteresis_limit_2_blocks)),
- delay_estimator_(data_dumper_.get(), config),
- last_delay_estimate_quality_(DelayEstimate::Quality::kCoarse) {
- RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
- delay_estimator_.LogDelayEstimationProperties(sample_rate_hz, 0);
-}
-
-RenderDelayControllerImpl2::~RenderDelayControllerImpl2() = default;
-
-void RenderDelayControllerImpl2::Reset(bool reset_delay_confidence) {
- delay_ = absl::nullopt;
- delay_samples_ = absl::nullopt;
- delay_estimator_.Reset(reset_delay_confidence);
- delay_change_counter_ = 0;
- if (reset_delay_confidence) {
- last_delay_estimate_quality_ = DelayEstimate::Quality::kCoarse;
- }
-}
-
-void RenderDelayControllerImpl2::LogRenderCall() {}
-
-absl::optional<DelayEstimate> RenderDelayControllerImpl2::GetDelay(
- const DownsampledRenderBuffer& render_buffer,
- size_t render_delay_buffer_delay,
- const absl::optional<int>& echo_remover_delay,
- rtc::ArrayView<const float> capture) {
- RTC_DCHECK_EQ(kBlockSize, capture.size());
- ++capture_call_counter_;
-
- auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
-
- // Overrule the delay estimator delay if the echo remover reports a delay.
- if (echo_remover_delay) {
- int total_echo_remover_delay_samples =
- (render_delay_buffer_delay + *echo_remover_delay) * kBlockSize;
- delay_samples = DelayEstimate(DelayEstimate::Quality::kRefined,
- total_echo_remover_delay_samples);
- }
-
- if (delay_samples) {
- if (!delay_samples_ || delay_samples->delay != delay_samples_->delay) {
- delay_change_counter_ = 0;
- }
- if (delay_samples_) {
- delay_samples_->blocks_since_last_change =
- delay_samples_->delay == delay_samples->delay
- ? delay_samples_->blocks_since_last_change + 1
- : 0;
- delay_samples_->blocks_since_last_update = 0;
- delay_samples_->delay = delay_samples->delay;
- delay_samples_->quality = delay_samples->quality;
- } else {
- delay_samples_ = delay_samples;
- }
- } else {
- if (delay_samples_) {
- ++delay_samples_->blocks_since_last_change;
- ++delay_samples_->blocks_since_last_update;
- }
- }
-
- if (delay_change_counter_ < 2 * kNumBlocksPerSecond) {
- ++delay_change_counter_;
- }
-
- if (delay_samples_) {
- // Compute the render delay buffer delay.
- const bool use_hysteresis =
- last_delay_estimate_quality_ == DelayEstimate::Quality::kRefined &&
- delay_samples_->quality == DelayEstimate::Quality::kRefined;
- delay_ = ComputeBufferDelay(delay_, delay_headroom_blocks_,
- use_hysteresis ? hysteresis_limit_1_blocks_ : 0,
- use_hysteresis ? hysteresis_limit_2_blocks_ : 0,
- *delay_samples_);
- last_delay_estimate_quality_ = delay_samples_->quality;
- }
-
- metrics_.Update(delay_samples_ ? absl::optional<size_t>(delay_samples_->delay)
- : absl::nullopt,
- delay_ ? delay_->delay : 0, 0, delay_estimator_.Clockdrift());
-
- data_dumper_->DumpRaw("aec3_render_delay_controller_delay",
- delay_samples ? delay_samples->delay : 0);
- data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay",
- delay_ ? delay_->delay : 0);
-
- return delay_;
-}
-
-bool RenderDelayControllerImpl2::HasClockdrift() const {
- return delay_estimator_.Clockdrift() != ClockdriftDetector::Level::kNone;
-}
-
-} // namespace
-
-RenderDelayController* RenderDelayController::Create2(
- const EchoCanceller3Config& config,
- int sample_rate_hz) {
- return new RenderDelayControllerImpl2(config, sample_rate_hz);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/aec3/render_delay_controller_metrics.h b/modules/audio_processing/aec3/render_delay_controller_metrics.h
index 22cc202..8c527a1 100644
--- a/modules/audio_processing/aec3/render_delay_controller_metrics.h
+++ b/modules/audio_processing/aec3/render_delay_controller_metrics.h
@@ -15,7 +15,7 @@
#include "absl/types/optional.h"
#include "modules/audio_processing/aec3/clockdrift_detector.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/render_delay_controller_unittest.cc b/modules/audio_processing/aec3/render_delay_controller_unittest.cc
index e9f02d3..c8405d8 100644
--- a/modules/audio_processing/aec3/render_delay_controller_unittest.cc
+++ b/modules/audio_processing/aec3/render_delay_controller_unittest.cc
@@ -57,14 +57,14 @@
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<RenderDelayBuffer> delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, rate));
+ RenderDelayController::Create(config, rate));
for (size_t k = 0; k < 100; ++k) {
auto delay = delay_controller->GetDelay(
delay_buffer->GetDownsampledRenderBuffer(), delay_buffer->Delay(),
echo_remover_delay_, block);
- EXPECT_EQ(config.delay.min_echo_path_delay_blocks, delay->delay);
+ EXPECT_FALSE(delay->delay);
}
}
}
@@ -86,9 +86,9 @@
std::vector<std::vector<float>> render_block(
NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(EchoCanceller3Config(), rate));
+ RenderDelayController::Create(EchoCanceller3Config(), rate));
for (size_t k = 0; k < 10; ++k) {
render_delay_buffer->Insert(render_block);
render_delay_buffer->PrepareCaptureProcessing();
@@ -98,7 +98,7 @@
render_delay_buffer->Delay(), echo_remover_delay, capture_block);
}
EXPECT_TRUE(delay_blocks);
- EXPECT_EQ(config.delay.min_echo_path_delay_blocks, delay_blocks->delay);
+ EXPECT_FALSE(delay_blocks->delay);
}
}
}
@@ -125,9 +125,9 @@
absl::optional<DelayEstimate> delay_blocks;
SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, rate));
+ RenderDelayController::Create(config, rate));
DelayBuffer<float> signal_delay_buffer(delay_samples);
for (size_t k = 0; k < (400 + delay_samples / kBlockSize); ++k) {
RandomizeSampleVector(&random_generator, render_block[0]);
@@ -174,9 +174,9 @@
absl::optional<DelayEstimate> delay_blocks;
SCOPED_TRACE(ProduceDebugText(rate, -delay_samples));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(EchoCanceller3Config(), rate));
+ RenderDelayController::Create(EchoCanceller3Config(), rate));
DelayBuffer<float> signal_delay_buffer(-delay_samples);
for (int k = 0;
k < (400 - delay_samples / static_cast<int>(kBlockSize)); ++k) {
@@ -216,24 +216,23 @@
absl::optional<DelayEstimate> delay_blocks;
SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, rate));
+ RenderDelayController::Create(config, rate));
DelayBuffer<float> signal_delay_buffer(delay_samples);
- for (size_t j = 0; j < (1000 + delay_samples / kBlockSize) /
- config.delay.api_call_jitter_blocks +
- 1;
+ constexpr size_t kMaxTestJitterBlocks = 26;
+ for (size_t j = 0;
+ j <
+ (1000 + delay_samples / kBlockSize) / kMaxTestJitterBlocks + 1;
++j) {
std::vector<std::vector<float>> capture_block_buffer;
- for (size_t k = 0; k < (config.delay.api_call_jitter_blocks - 1);
- ++k) {
+ for (size_t k = 0; k < (kMaxTestJitterBlocks - 1); ++k) {
RandomizeSampleVector(&random_generator, render_block[0]);
signal_delay_buffer.Delay(render_block[0], capture_block);
capture_block_buffer.push_back(capture_block);
render_delay_buffer->Insert(render_block);
}
- for (size_t k = 0; k < (config.delay.api_call_jitter_blocks - 1);
- ++k) {
+ for (size_t k = 0; k < (kMaxTestJitterBlocks - 1); ++k) {
render_delay_buffer->PrepareCaptureProcessing();
delay_blocks = delay_controller->GetDelay(
render_delay_buffer->GetDownsampledRenderBuffer(),
@@ -271,10 +270,10 @@
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
std::unique_ptr<RenderDelayController> delay_controller(
- RenderDelayController::Create2(config, rate));
+ RenderDelayController::Create(config, rate));
}
}
}
@@ -290,10 +289,10 @@
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
EXPECT_DEATH(
std::unique_ptr<RenderDelayController>(
- RenderDelayController::Create2(EchoCanceller3Config(), rate))
+ RenderDelayController::Create(EchoCanceller3Config(), rate))
->GetDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
render_delay_buffer->Delay(), echo_remover_delay, block),
"");
@@ -308,10 +307,10 @@
SCOPED_TRACE(ProduceDebugText(rate));
EchoCanceller3Config config;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, NumBandsForRate(rate)));
+ RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
EXPECT_DEATH(
std::unique_ptr<RenderDelayController>(
- RenderDelayController::Create2(EchoCanceller3Config(), rate)),
+ RenderDelayController::Create(EchoCanceller3Config(), rate)),
"");
}
}
diff --git a/modules/audio_processing/aec3/render_signal_analyzer.h b/modules/audio_processing/aec3/render_signal_analyzer.h
index 8a44232..c7a3d8b 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer.h
+++ b/modules/audio_processing/aec3/render_signal_analyzer.h
@@ -20,7 +20,7 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/render_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
index a993f8f..a15cd9a 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
+++ b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
@@ -59,7 +59,7 @@
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
std::array<float, kBlockSize> x_old;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(EchoCanceller3Config(), 3));
+ RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
std::array<float, kFftLengthBy2Plus1> mask;
x_old.fill(0.f);
@@ -91,9 +91,8 @@
std::array<float, kBlockSize> x_old;
Aec3Fft fft;
EchoCanceller3Config config;
- config.delay.min_echo_path_delay_blocks = 0;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::array<float, kFftLengthBy2Plus1> mask;
x_old.fill(0.f);
diff --git a/modules/audio_processing/aec3/residual_echo_estimator.cc b/modules/audio_processing/aec3/residual_echo_estimator.cc
index 627dd90..d47fa4c 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -1,4 +1,3 @@
-
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
@@ -19,70 +18,36 @@
#include "modules/audio_processing/aec3/reverb_model.h"
#include "modules/audio_processing/aec3/reverb_model_fallback.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnableSoftTransparentMode() {
- return !field_trial::IsEnabled("WebRTC-Aec3SoftTransparentModeKillSwitch");
-}
-
-bool OverrideEstimatedEchoPathGain() {
- return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch");
-}
-
-bool UseFixedNonLinearReverbModel() {
- return field_trial::IsEnabled(
- "WebRTC-Aec3StandardNonlinearReverbModelKillSwitch");
-}
-
// Computes the indexes that will be used for computing spectral power over
// the blocks surrounding the delay.
void GetRenderIndexesToAnalyze(
const VectorBuffer& spectrum_buffer,
const EchoCanceller3Config::EchoModel& echo_model,
int filter_delay_blocks,
- bool gain_limiter_running,
int headroom,
int* idx_start,
int* idx_stop) {
RTC_DCHECK(idx_start);
RTC_DCHECK(idx_stop);
- if (gain_limiter_running) {
- if (static_cast<size_t>(headroom) >
- echo_model.render_post_window_size_init) {
- *idx_start = spectrum_buffer.OffsetIndex(
- spectrum_buffer.read,
- -static_cast<int>(echo_model.render_post_window_size_init));
- } else {
- *idx_start = spectrum_buffer.IncIndex(spectrum_buffer.write);
- }
-
- *idx_stop = spectrum_buffer.OffsetIndex(
- spectrum_buffer.read, echo_model.render_pre_window_size_init);
- } else {
- size_t window_start;
- size_t window_end;
- window_start =
- std::max(0, filter_delay_blocks -
- static_cast<int>(echo_model.render_pre_window_size));
- window_end = filter_delay_blocks +
- static_cast<int>(echo_model.render_post_window_size);
- *idx_start =
- spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
- *idx_stop =
- spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
- }
+ size_t window_start;
+ size_t window_end;
+ window_start =
+ std::max(0, filter_delay_blocks -
+ static_cast<int>(echo_model.render_pre_window_size));
+ window_end = filter_delay_blocks +
+ static_cast<int>(echo_model.render_post_window_size);
+ *idx_start = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
+ *idx_stop = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
}
} // namespace
ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
- : config_(config),
- soft_transparent_mode_(EnableSoftTransparentMode()),
- override_estimated_echo_path_gain_(OverrideEstimatedEchoPathGain()),
- use_fixed_nonlinear_reverb_model_(UseFixedNonLinearReverbModel()) {
+ : config_(config) {
if (config_.ep_strength.reverb_based_on_render) {
echo_reverb_.reset(new ReverbModel());
} else {
@@ -136,7 +101,6 @@
EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model,
render_buffer.Headroom(), aec_state.FilterDelayBlocks(),
- aec_state.IsSuppressionGainLimitActive(),
!aec_state.UseStationaryProperties(), &X2);
// Subtract the stationary noise power to avoid stationary noise causing
@@ -148,15 +112,8 @@
});
float echo_path_gain;
- if (override_estimated_echo_path_gain_) {
- echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
- ? 0.01f
- : config_.ep_strength.lf;
- } else {
- echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
- ? 0.01f
- : aec_state.EchoPathGain();
- }
+ echo_path_gain =
+ aec_state.TransparentMode() ? 0.01f : config_.ep_strength.default_gain;
NonLinearEstimate(echo_path_gain, X2, Y2, R2);
// When there is saturated echo, assume the same spectral content as is
@@ -165,7 +122,7 @@
std::copy(Y2.begin(), Y2.end(), R2->begin());
}
- if (!(aec_state.TransparentMode() && soft_transparent_mode_)) {
+ if (!(aec_state.TransparentMode())) {
if (echo_reverb_) {
echo_reverb_->AddReverbNoFreqShaping(
render_buffer.Spectrum(aec_state.FilterDelayBlocks() + 1),
@@ -190,14 +147,6 @@
}
}
}
- if (!soft_transparent_mode_) {
- // If the echo is deemed inaudible, set the residual echo to zero.
- if (aec_state.TransparentMode()) {
- R2->fill(0.f);
- R2_old_.fill(0.f);
- R2_hold_counter_.fill(0.f);
- }
- }
std::copy(R2->begin(), R2->end(), R2_old_.begin());
}
@@ -243,22 +192,6 @@
std::transform(X2.begin(), X2.end(), R2->begin(), [echo_path_gain](float a) {
return a * echo_path_gain * echo_path_gain;
});
-
- if (use_fixed_nonlinear_reverb_model_) {
- for (size_t k = 0; k < R2->size(); ++k) {
- // Update hold counter.
- R2_hold_counter_[k] = R2_old_[k] < (*R2)[k] ? 0 : R2_hold_counter_[k] + 1;
-
- // Compute the residual echo by holding a maximum echo powers and an echo
- // fading corresponding to a room with an RT60 value of about 50 ms.
- (*R2)[k] =
- R2_hold_counter_[k] < config_.echo_model.nonlinear_hold
- ? std::max((*R2)[k], R2_old_[k])
- : std::min((*R2)[k] +
- R2_old_[k] * config_.echo_model.nonlinear_release,
- Y2[k]);
- }
- }
}
void ResidualEchoEstimator::EchoGeneratingPower(
@@ -266,15 +199,14 @@
const EchoCanceller3Config::EchoModel& echo_model,
int headroom_spectrum_buffer,
int filter_delay_blocks,
- bool gain_limiter_running,
bool apply_noise_gating,
std::array<float, kFftLengthBy2Plus1>* X2) const {
int idx_stop, idx_start;
RTC_DCHECK(X2);
GetRenderIndexesToAnalyze(spectrum_buffer, config_.echo_model,
- filter_delay_blocks, gain_limiter_running,
- headroom_spectrum_buffer, &idx_start, &idx_stop);
+ filter_delay_blocks, headroom_spectrum_buffer,
+ &idx_start, &idx_stop);
X2->fill(0.f);
for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
diff --git a/modules/audio_processing/aec3/residual_echo_estimator.h b/modules/audio_processing/aec3/residual_echo_estimator.h
index 52885a5..3909054 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.h
+++ b/modules/audio_processing/aec3/residual_echo_estimator.h
@@ -23,7 +23,7 @@
#include "modules/audio_processing/aec3/reverb_model_fallback.h"
#include "modules/audio_processing/aec3/vector_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -72,7 +72,6 @@
const EchoCanceller3Config::EchoModel& echo_model,
int headroom_spectrum_buffer,
int filter_delay_blocks,
- bool gain_limiter_running,
bool apply_noise_gating,
std::array<float, kFftLengthBy2Plus1>* X2) const;
@@ -88,9 +87,6 @@
std::array<int, kFftLengthBy2Plus1> R2_hold_counter_;
std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
- const bool soft_transparent_mode_;
- const bool override_estimated_echo_path_gain_;
- const bool use_fixed_nonlinear_reverb_model_;
std::unique_ptr<ReverbModel> echo_reverb_;
std::unique_ptr<ReverbModelFallback> echo_reverb_fallback;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ResidualEchoEstimator);
diff --git a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
index 2e73a7e..6214025 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
@@ -27,7 +27,7 @@
EchoCanceller3Config config;
AecState aec_state(config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::vector<std::array<float, kFftLengthBy2Plus1>> H2;
std::array<float, kFftLengthBy2Plus1> S2_linear;
std::array<float, kFftLengthBy2Plus1> Y2;
@@ -44,11 +44,10 @@
TEST(ResidualEchoEstimator, DISABLED_BasicTest) {
EchoCanceller3Config config;
config.ep_strength.default_len = 0.f;
- config.delay.min_echo_path_delay_blocks = 0;
ResidualEchoEstimator estimator(config);
AecState aec_state(config);
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::array<float, kFftLengthBy2Plus1> E2_main;
std::array<float, kFftLengthBy2Plus1> E2_shadow;
diff --git a/modules/audio_processing/aec3/reverb_decay_estimator.cc b/modules/audio_processing/aec3/reverb_decay_estimator.cc
index 95fd13a..cdcbee5 100644
--- a/modules/audio_processing/aec3/reverb_decay_estimator.cc
+++ b/modules/audio_processing/aec3/reverb_decay_estimator.cc
@@ -19,17 +19,11 @@
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnforceAdaptiveEchoReverbEstimation() {
- return field_trial::IsEnabled(
- "WebRTC-Aec3EnableAdaptiveEchoReverbEstimation");
-}
-
constexpr int kEarlyReverbMinSizeBlocks = 3;
constexpr int kBlocksPerSection = 6;
// Linear regression approach assumes symmetric index around 0.
@@ -92,8 +86,7 @@
ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config)
: filter_length_blocks_(config.filter.main.length_blocks),
filter_length_coefficients_(GetTimeDomainLength(filter_length_blocks_)),
- use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f ||
- EnforceAdaptiveEchoReverbEstimation()),
+ use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f),
early_reverb_estimator_(config.filter.main.length_blocks -
kEarlyReverbMinSizeBlocks),
late_reverb_start_(kEarlyReverbMinSizeBlocks),
@@ -287,7 +280,7 @@
// Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
nn_ = SymmetricArithmetricSum(N);
// The linear regression approach assumes symmetric index around 0.
- count_ = N > 0 ? count_ = -N * 0.5f + 0.5f : 0.f;
+ count_ = N > 0 ? -N * 0.5f + 0.5f : 0.f;
N_ = N;
n_ = 0;
}
diff --git a/modules/audio_processing/aec3/reverb_frequency_response.cc b/modules/audio_processing/aec3/reverb_frequency_response.cc
index d2103d4..98eeca6 100644
--- a/modules/audio_processing/aec3/reverb_frequency_response.cc
+++ b/modules/audio_processing/aec3/reverb_frequency_response.cc
@@ -18,17 +18,11 @@
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnableSmoothUpdatesTailFreqResp() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch");
-}
-
// Computes the ratio of the energies between the direct path and the tail. The
// energy is computed in the power spectrum domain discarding the DC
// contributions.
@@ -54,8 +48,7 @@
} // namespace
-ReverbFrequencyResponse::ReverbFrequencyResponse()
- : enable_smooth_tail_response_updates_(EnableSmoothUpdatesTailFreqResp()) {
+ReverbFrequencyResponse::ReverbFrequencyResponse() {
tail_response_.fill(0.f);
}
ReverbFrequencyResponse::~ReverbFrequencyResponse() = default;
@@ -66,10 +59,6 @@
int filter_delay_blocks,
const absl::optional<float>& linear_filter_quality,
bool stationary_block) {
- if (!enable_smooth_tail_response_updates_) {
- Update(frequency_response, filter_delay_blocks, 0.5f);
- return;
- }
if (stationary_block || !linear_filter_quality) {
return;
diff --git a/modules/audio_processing/aec3/reverb_frequency_response.h b/modules/audio_processing/aec3/reverb_frequency_response.h
index eb63b8e..b164186 100644
--- a/modules/audio_processing/aec3/reverb_frequency_response.h
+++ b/modules/audio_processing/aec3/reverb_frequency_response.h
@@ -44,7 +44,6 @@
int filter_delay_blocks,
float linear_filter_quality);
- const bool enable_smooth_tail_response_updates_;
float average_decay_ = 0.f;
std::array<float, kFftLengthBy2Plus1> tail_response_;
};
diff --git a/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
index 017c679..9d87cc8 100644
--- a/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
+++ b/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
@@ -50,10 +50,9 @@
DetectOptimization(), &data_dumper);
Aec3Fft fft;
- config.delay.min_echo_path_delay_blocks = 0;
config.delay.default_delay = 1;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
std::array<float, kBlockSize> x_old;
x_old.fill(0.f);
diff --git a/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc b/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc
index 32b36ab..6a8d7e3 100644
--- a/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc
+++ b/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc
@@ -122,7 +122,7 @@
: min_erle_(config.erle.min),
num_sections_(config.erle.num_sections),
num_blocks_(config.filter.main.length_blocks),
- delay_headroom_blocks_(config.delay.delay_headroom_blocks),
+ delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize),
band_to_subband_(FormSubbandMap()),
max_erle_(SetMaxErleSubbands(config.erle.max_l,
config.erle.max_h,
@@ -201,7 +201,6 @@
for (auto& factor : correction_factors_) {
data_dumper->DumpRaw("aec3_erle_correction_factor", factor);
}
- data_dumper->DumpRaw("aec3_erle", erle_);
}
// Estimates for each band the smallest number of sections in the filter that
diff --git a/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc b/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc
index aec605f..4e62c94 100644
--- a/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/signal_dependent_erle_estimator_unittest.cc
@@ -62,7 +62,7 @@
};
TestInputs::TestInputs(const EchoCanceller3Config& cfg)
- : render_delay_buffer_(RenderDelayBuffer::Create2(cfg, 1)),
+ : render_delay_buffer_(RenderDelayBuffer::Create(cfg, 1)),
H2_(cfg.filter.main.length_blocks),
x_(1, std::vector<float>(kBlockSize, 0.f)) {
render_delay_buffer_->SetDelay(4);
@@ -115,7 +115,7 @@
cfg.filter.main.length_blocks = blocks;
cfg.filter.main_initial.length_blocks =
std::min(cfg.filter.main_initial.length_blocks, blocks);
- cfg.delay.delay_headroom_blocks = delay_headroom;
+ cfg.delay.delay_headroom_samples = delay_headroom * kBlockSize;
cfg.erle.num_sections = num_sections;
if (EchoCanceller3Config::Validate(&cfg)) {
SignalDependentErleEstimator s(cfg);
@@ -137,8 +137,8 @@
EchoCanceller3Config cfg;
cfg.filter.main.length_blocks = 2;
cfg.filter.main_initial.length_blocks = 1;
- cfg.delay.delay_headroom_blocks = 0;
- cfg.delay.hysteresis_limit_1_blocks = 0;
+ cfg.delay.delay_headroom_samples = 0;
+ cfg.delay.hysteresis_limit_blocks = 0;
cfg.erle.num_sections = 2;
EXPECT_EQ(EchoCanceller3Config::Validate(&cfg), true);
std::array<float, kFftLengthBy2Plus1> average_erle;
diff --git a/modules/audio_processing/aec3/skew_estimator.h b/modules/audio_processing/aec3/skew_estimator.h
index b0946d8..8a457cb 100644
--- a/modules/audio_processing/aec3/skew_estimator.h
+++ b/modules/audio_processing/aec3/skew_estimator.h
@@ -15,7 +15,7 @@
#include <vector>
#include "absl/types/optional.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/stationarity_estimator.cc b/modules/audio_processing/aec3/stationarity_estimator.cc
index 25100bf..47f04bf 100644
--- a/modules/audio_processing/aec3/stationarity_estimator.cc
+++ b/modules/audio_processing/aec3/stationarity_estimator.cc
@@ -18,7 +18,7 @@
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/vector_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/subband_erle_estimator.cc b/modules/audio_processing/aec3/subband_erle_estimator.cc
index 9453e57..82f3dab 100644
--- a/modules/audio_processing/aec3/subband_erle_estimator.cc
+++ b/modules/audio_processing/aec3/subband_erle_estimator.cc
@@ -26,10 +26,6 @@
constexpr int kBlocksForOnsetDetection = kBlocksToHoldErle + 150;
constexpr int kPointsToAccumulate = 6;
-bool EnableAdaptErleOnLowRender() {
- return !field_trial::IsEnabled("WebRTC-Aec3AdaptErleOnLowRenderKillSwitch");
-}
-
std::array<float, kFftLengthBy2Plus1> SetMaxErleBands(float max_erle_l,
float max_erle_h) {
std::array<float, kFftLengthBy2Plus1> max_erle;
@@ -38,12 +34,16 @@
return max_erle;
}
+bool EnableMinErleDuringOnsets() {
+ return !field_trial::IsEnabled("WebRTC-Aec3MinErleDuringOnsetsKillSwitch");
+}
+
} // namespace
SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config)
: min_erle_(config.erle.min),
max_erle_(SetMaxErleBands(config.erle.max_l, config.erle.max_h)),
- adapt_on_low_render_(EnableAdaptErleOnLowRender()) {
+ use_min_erle_during_onsets_(EnableMinErleDuringOnsets()) {
Reset();
}
@@ -101,10 +101,12 @@
if (is_erle_updated[k] && !accum_spectra_.low_render_energy_[k]) {
if (coming_onset_[k]) {
coming_onset_[k] = false;
- float alpha = new_erle[k] < erle_onsets_[k] ? 0.3f : 0.15f;
- erle_onsets_[k] = rtc::SafeClamp(
- erle_onsets_[k] + alpha * (new_erle[k] - erle_onsets_[k]),
- min_erle_, max_erle_[k]);
+ if (!use_min_erle_during_onsets_) {
+ float alpha = new_erle[k] < erle_onsets_[k] ? 0.3f : 0.15f;
+ erle_onsets_[k] = rtc::SafeClamp(
+ erle_onsets_[k] + alpha * (new_erle[k] - erle_onsets_[k]),
+ min_erle_, max_erle_[k]);
+ }
}
hold_counters_[k] = kBlocksForOnsetDetection;
}
@@ -151,43 +153,23 @@
rtc::ArrayView<const float> Y2,
rtc::ArrayView<const float> E2) {
auto& st = accum_spectra_;
- if (adapt_on_low_render_) {
- if (st.num_points_[0] == kPointsToAccumulate) {
- st.num_points_[0] = 0;
- st.Y2_.fill(0.f);
- st.E2_.fill(0.f);
- st.low_render_energy_.fill(false);
- }
- std::transform(Y2.begin(), Y2.end(), st.Y2_.begin(), st.Y2_.begin(),
- std::plus<float>());
- std::transform(E2.begin(), E2.end(), st.E2_.begin(), st.E2_.begin(),
- std::plus<float>());
-
- for (size_t k = 0; k < X2.size(); ++k) {
- st.low_render_energy_[k] =
- st.low_render_energy_[k] || X2[k] < kX2BandEnergyThreshold;
- }
- st.num_points_[0]++;
- st.num_points_.fill(st.num_points_[0]);
-
- } else {
- // The update is always done using high render energy signals and
- // therefore the field accum_spectra_.low_render_energy_ does not need to
- // be modified.
- for (size_t k = 0; k < X2.size(); ++k) {
- if (X2[k] > kX2BandEnergyThreshold) {
- if (st.num_points_[k] == kPointsToAccumulate) {
- st.Y2_[k] = 0.f;
- st.E2_[k] = 0.f;
- st.num_points_[k] = 0;
- }
- st.Y2_[k] += Y2[k];
- st.E2_[k] += E2[k];
- st.num_points_[k]++;
- }
- RTC_DCHECK_EQ(st.low_render_energy_[k], false);
- }
+ if (st.num_points_[0] == kPointsToAccumulate) {
+ st.num_points_[0] = 0;
+ st.Y2_.fill(0.f);
+ st.E2_.fill(0.f);
+ st.low_render_energy_.fill(false);
}
+ std::transform(Y2.begin(), Y2.end(), st.Y2_.begin(), st.Y2_.begin(),
+ std::plus<float>());
+ std::transform(E2.begin(), E2.end(), st.E2_.begin(), st.E2_.begin(),
+ std::plus<float>());
+
+ for (size_t k = 0; k < X2.size(); ++k) {
+ st.low_render_energy_[k] =
+ st.low_render_energy_[k] || X2[k] < kX2BandEnergyThreshold;
+ }
+ st.num_points_[0]++;
+ st.num_points_.fill(st.num_points_[0]);
}
} // namespace webrtc
diff --git a/modules/audio_processing/aec3/subband_erle_estimator.h b/modules/audio_processing/aec3/subband_erle_estimator.h
index b9862db..903c629 100644
--- a/modules/audio_processing/aec3/subband_erle_estimator.h
+++ b/modules/audio_processing/aec3/subband_erle_estimator.h
@@ -66,7 +66,7 @@
const float min_erle_;
const std::array<float, kFftLengthBy2Plus1> max_erle_;
- const bool adapt_on_low_render_;
+ const bool use_min_erle_during_onsets_;
AccumulatedSpectra accum_spectra_;
std::array<float, kFftLengthBy2Plus1> erle_;
std::array<float, kFftLengthBy2Plus1> erle_onsets_;
diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc
index 90069c7..aa38a34 100644
--- a/modules/audio_processing/aec3/subtractor.cc
+++ b/modules/audio_processing/aec3/subtractor.cc
@@ -18,44 +18,16 @@
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-bool EnableAgcGainChangeResponse() {
- return !field_trial::IsEnabled("WebRTC-Aec3AgcGainChangeResponseKillSwitch");
-}
-
-bool EnableAdaptationDuringSaturation() {
- return !field_trial::IsEnabled("WebRTC-Aec3RapidAgcGainRecoveryKillSwitch");
-}
-
-bool EnableMisadjustmentEstimator() {
- return !field_trial::IsEnabled("WebRTC-Aec3MisadjustmentEstimatorKillSwitch");
-}
-
-bool EnableShadowFilterJumpstart() {
- return !field_trial::IsEnabled("WebRTC-Aec3ShadowFilterJumpstartKillSwitch");
-}
-
-bool EnableShadowFilterBoostedJumpstart() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3ShadowFilterBoostedJumpstartKillSwitch");
-}
-
-bool EnableEarlyShadowFilterJumpstart() {
- return !field_trial::IsEnabled(
- "WebRTC-Aec3EarlyShadowFilterJumpstartKillSwitch");
-}
-
void PredictionError(const Aec3Fft& fft,
const FftData& S,
rtc::ArrayView<const float> y,
std::array<float, kBlockSize>* e,
std::array<float, kBlockSize>* s,
- bool adaptation_during_saturation,
bool* saturation) {
std::array<float, kFftLength> tmp;
fft.Ifft(S, &tmp);
@@ -77,12 +49,7 @@
*saturation = *result.first <= -32768 || *result.first >= 32767;
}
- if (!adaptation_during_saturation) {
- std::for_each(e->begin(), e->end(),
- [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
- } else {
- *saturation = false;
- }
+ *saturation = false;
}
void ScaleFilterOutput(rtc::ArrayView<const float> y,
@@ -106,13 +73,6 @@
data_dumper_(data_dumper),
optimization_(optimization),
config_(config),
- adaptation_during_saturation_(EnableAdaptationDuringSaturation()),
- enable_misadjustment_estimator_(EnableMisadjustmentEstimator()),
- enable_agc_gain_change_response_(EnableAgcGainChangeResponse()),
- enable_shadow_filter_jumpstart_(EnableShadowFilterJumpstart()),
- enable_shadow_filter_boosted_jumpstart_(
- EnableShadowFilterBoostedJumpstart()),
- enable_early_shadow_filter_jumpstart_(EnableEarlyShadowFilterJumpstart()),
main_filter_(config_.filter.main.length_blocks,
config_.filter.main_initial.length_blocks,
config.filter.config_change_duration_blocks,
@@ -152,7 +112,7 @@
full_reset();
}
- if (echo_path_variability.gain_change && enable_agc_gain_change_response_) {
+ if (echo_path_variability.gain_change) {
G_main_.HandleEchoPathChange(echo_path_variability);
}
}
@@ -182,28 +142,24 @@
// Form the outputs of the main and shadow filters.
main_filter_.Filter(render_buffer, &S);
bool main_saturation = false;
- PredictionError(fft_, S, y, &e_main, &output->s_main,
- adaptation_during_saturation_, &main_saturation);
+ PredictionError(fft_, S, y, &e_main, &output->s_main, &main_saturation);
shadow_filter_.Filter(render_buffer, &S);
bool shadow_saturation = false;
- PredictionError(fft_, S, y, &e_shadow, &output->s_shadow,
- adaptation_during_saturation_, &shadow_saturation);
+ PredictionError(fft_, S, y, &e_shadow, &output->s_shadow, &shadow_saturation);
// Compute the signal powers in the subtractor output.
output->ComputeMetrics(y);
// Adjust the filter if needed.
bool main_filter_adjusted = false;
- if (enable_misadjustment_estimator_) {
- filter_misadjustment_estimator_.Update(*output);
- if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
- float scale = filter_misadjustment_estimator_.GetMisadjustment();
- main_filter_.ScaleFilter(scale);
- ScaleFilterOutput(y, scale, e_main, output->s_main);
- filter_misadjustment_estimator_.Reset();
- main_filter_adjusted = true;
- }
+ filter_misadjustment_estimator_.Update(*output);
+ if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
+ float scale = filter_misadjustment_estimator_.GetMisadjustment();
+ main_filter_.ScaleFilter(scale);
+ ScaleFilterOutput(y, scale, e_main, output->s_main);
+ filter_misadjustment_estimator_.Reset();
+ main_filter_adjusted = true;
}
// Compute the FFts of the main and shadow filter outputs.
@@ -248,40 +204,26 @@
// Update the shadow filter.
poor_shadow_filter_counter_ =
output->e2_main < output->e2_shadow ? poor_shadow_filter_counter_ + 1 : 0;
- if (((poor_shadow_filter_counter_ < 5 &&
- enable_early_shadow_filter_jumpstart_) ||
- (poor_shadow_filter_counter_ < 10 &&
- !enable_early_shadow_filter_jumpstart_)) ||
- !enable_shadow_filter_jumpstart_) {
+ if (poor_shadow_filter_counter_ < 5) {
G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_shadow,
shadow_filter_.SizePartitions(),
aec_state.SaturatedCapture() || shadow_saturation, &G);
- shadow_filter_.Adapt(render_buffer, G);
} else {
poor_shadow_filter_counter_ = 0;
- if (enable_shadow_filter_boosted_jumpstart_) {
- shadow_filter_.SetFilter(main_filter_.GetFilter());
- G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main,
- shadow_filter_.SizePartitions(),
- aec_state.SaturatedCapture() || main_saturation, &G);
- shadow_filter_.Adapt(render_buffer, G);
- } else {
- G.re.fill(0.f);
- G.im.fill(0.f);
- shadow_filter_.Adapt(render_buffer, G);
- shadow_filter_.SetFilter(main_filter_.GetFilter());
- }
+ shadow_filter_.SetFilter(main_filter_.GetFilter());
+ G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main,
+ shadow_filter_.SizePartitions(),
+ aec_state.SaturatedCapture() || main_saturation, &G);
}
+ shadow_filter_.Adapt(render_buffer, G);
data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re);
data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im);
filter_misadjustment_estimator_.Dump(data_dumper_);
DumpFilters();
- if (adaptation_during_saturation_) {
- std::for_each(e_main.begin(), e_main.end(),
- [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
- }
+ std::for_each(e_main.begin(), e_main.end(),
+ [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
data_dumper_->DumpWav("aec3_main_filter_output", kBlockSize, &e_main[0],
16000, 1);
diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h
index bec014d..910be18 100644
--- a/modules/audio_processing/aec3/subtractor.h
+++ b/modules/audio_processing/aec3/subtractor.h
@@ -30,7 +30,7 @@
#include "modules/audio_processing/aec3/subtractor_output.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -107,12 +107,6 @@
ApmDataDumper* data_dumper_;
const Aec3Optimization optimization_;
const EchoCanceller3Config config_;
- const bool adaptation_during_saturation_;
- const bool enable_misadjustment_estimator_;
- const bool enable_agc_gain_change_response_;
- const bool enable_shadow_filter_jumpstart_;
- const bool enable_shadow_filter_boosted_jumpstart_;
- const bool enable_early_shadow_filter_jumpstart_;
AdaptiveFirFilter main_filter_;
AdaptiveFirFilter shadow_filter_;
diff --git a/modules/audio_processing/aec3/subtractor_output_analyzer.cc b/modules/audio_processing/aec3/subtractor_output_analyzer.cc
index 9374b80..9a0e0bb 100644
--- a/modules/audio_processing/aec3/subtractor_output_analyzer.cc
+++ b/modules/audio_processing/aec3/subtractor_output_analyzer.cc
@@ -13,19 +13,10 @@
#include <algorithm>
#include "modules/audio_processing/aec3/aec3_common.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
-namespace {
-bool EnableStrictDivergenceCheck() {
- return !field_trial::IsEnabled("WebRTC-Aec3StrictDivergenceCheckKillSwitch");
-}
-
-} // namespace
-
-SubtractorOutputAnalyzer::SubtractorOutputAnalyzer()
- : strict_divergence_check_(EnableStrictDivergenceCheck()) {}
+SubtractorOutputAnalyzer::SubtractorOutputAnalyzer() {}
void SubtractorOutputAnalyzer::Update(
const SubtractorOutput& subtractor_output) {
@@ -37,8 +28,7 @@
main_filter_converged_ = e2_main < 0.5f * y2 && y2 > kConvergenceThreshold;
shadow_filter_converged_ =
e2_shadow < 0.05f * y2 && y2 > kConvergenceThreshold;
- float min_e2 =
- strict_divergence_check_ ? std::min(e2_main, e2_shadow) : e2_main;
+ float min_e2 = std::min(e2_main, e2_shadow);
filter_diverged_ = min_e2 > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize;
}
diff --git a/modules/audio_processing/aec3/subtractor_output_analyzer.h b/modules/audio_processing/aec3/subtractor_output_analyzer.h
index 0e23ad5..76a2560 100644
--- a/modules/audio_processing/aec3/subtractor_output_analyzer.h
+++ b/modules/audio_processing/aec3/subtractor_output_analyzer.h
@@ -34,7 +34,6 @@
void HandleEchoPathChange();
private:
- const bool strict_divergence_check_;
bool shadow_filter_converged_ = false;
bool main_filter_converged_ = false;
bool filter_diverged_ = false;
diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc
index 8d14cc1..99d8e1b 100644
--- a/modules/audio_processing/aec3/subtractor_unittest.cc
+++ b/modules/audio_processing/aec3/subtractor_unittest.cc
@@ -41,10 +41,9 @@
std::vector<float> y(kBlockSize, 0.f);
std::array<float, kBlockSize> x_old;
SubtractorOutput output;
- config.delay.min_echo_path_delay_blocks = 0;
config.delay.default_delay = 1;
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
RenderSignalAnalyzer render_signal_analyzer(config);
Random random_generator(42U);
Aec3Fft fft;
@@ -127,7 +126,7 @@
EchoCanceller3Config config;
Subtractor subtractor(config, &data_dumper, DetectOptimization());
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
RenderSignalAnalyzer render_signal_analyzer(config);
std::vector<float> y(kBlockSize, 0.f);
@@ -143,7 +142,7 @@
EchoCanceller3Config config;
Subtractor subtractor(config, &data_dumper, DetectOptimization());
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
RenderSignalAnalyzer render_signal_analyzer(config);
std::vector<float> y(kBlockSize - 1, 0.f);
SubtractorOutput output;
diff --git a/modules/audio_processing/aec3/suppression_filter.h b/modules/audio_processing/aec3/suppression_filter.h
index edd1290..63569b1 100644
--- a/modules/audio_processing/aec3/suppression_filter.h
+++ b/modules/audio_processing/aec3/suppression_filter.h
@@ -18,7 +18,7 @@
#include "modules/audio_processing/aec3/aec3_fft.h"
#include "modules/audio_processing/aec3/fft_data.h"
#include "modules/audio_processing/utility/ooura_fft.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/suppression_gain.cc b/modules/audio_processing/aec3/suppression_gain.cc
index c6d2bf6..e258682 100644
--- a/modules/audio_processing/aec3/suppression_gain.cc
+++ b/modules/audio_processing/aec3/suppression_gain.cc
@@ -18,7 +18,7 @@
#include "modules/audio_processing/aec3/moving_average.h"
#include "modules/audio_processing/aec3/vector_math.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
namespace webrtc {
@@ -346,14 +346,6 @@
nearend_average, residual_echo_spectrum, comfort_noise_spectrum,
low_band_gain);
- // Limit the gain of the lower bands during start up and after resets.
- const float gain_upper_bound = aec_state.SuppressionGainLimit();
- if (gain_upper_bound < 1.f) {
- for (size_t k = 0; k < low_band_gain->size(); ++k) {
- (*low_band_gain)[k] = std::min((*low_band_gain)[k], gain_upper_bound);
- }
- }
-
// Compute the gain for the upper bands.
const absl::optional<int> narrow_peak_band =
render_signal_analyzer.NarrowPeakBand();
diff --git a/modules/audio_processing/aec3/suppression_gain.h b/modules/audio_processing/aec3/suppression_gain.h
index e74cd96..9e33c28 100644
--- a/modules/audio_processing/aec3/suppression_gain.h
+++ b/modules/audio_processing/aec3/suppression_gain.h
@@ -24,7 +24,7 @@
#include "modules/audio_processing/aec3/moving_average.h"
#include "modules/audio_processing/aec3/render_signal_analyzer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.cc b/modules/audio_processing/aec3/suppression_gain_limiter.cc
deleted file mode 100644
index 6625a77..0000000
--- a/modules/audio_processing/aec3/suppression_gain_limiter.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2018 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/audio_processing/aec3/suppression_gain_limiter.h"
-
-#include <math.h>
-#include <algorithm>
-
-#include "modules/audio_processing/aec3/aec3_common.h"
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-namespace {
-
-// Computes the gain rampup factor to use.
-float ComputeGainRampupIncrease(
- const EchoCanceller3Config::EchoRemovalControl::GainRampup& rampup_config) {
- return powf(1.f / rampup_config.first_non_zero_gain,
- 1.f / rampup_config.non_zero_gain_blocks);
-}
-
-} // namespace
-
-SuppressionGainUpperLimiter::SuppressionGainUpperLimiter(
- const EchoCanceller3Config& config)
- : rampup_config_(config.echo_removal_control.gain_rampup),
- gain_rampup_increase_(ComputeGainRampupIncrease(rampup_config_)) {
- Reset();
-}
-
-void SuppressionGainUpperLimiter::Reset() {
- recent_reset_ = true;
-}
-
-void SuppressionGainUpperLimiter::Update(bool render_activity,
- bool transparent_mode) {
- if (transparent_mode) {
- active_render_seen_ = true;
- call_startup_phase_ = false;
- recent_reset_ = false;
- suppressor_gain_limit_ = 1.f;
- return;
- }
-
- if (recent_reset_ && !call_startup_phase_) {
- // Only enforce 250 ms full suppression after in-call resets,
- constexpr int kMuteFramesAfterReset = kNumBlocksPerSecond / 4;
- realignment_counter_ = kMuteFramesAfterReset;
- } else if (!active_render_seen_ && render_activity) {
- // Enforce a tailormade suppression limiting during call startup.
- active_render_seen_ = true;
- realignment_counter_ = rampup_config_.full_gain_blocks;
- } else if (realignment_counter_ > 0) {
- if (--realignment_counter_ == 0) {
- call_startup_phase_ = false;
- }
- }
- recent_reset_ = false;
-
- // Do not enforce any gain limit on the suppressor.
- if (!IsActive()) {
- suppressor_gain_limit_ = 1.f;
- return;
- }
-
- // Enforce full suppression.
- if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
- (!call_startup_phase_ && realignment_counter_ > 0)) {
- suppressor_gain_limit_ = rampup_config_.initial_gain;
- return;
- }
-
- // Start increasing the gain limit.
- if (realignment_counter_ == rampup_config_.non_zero_gain_blocks) {
- suppressor_gain_limit_ = rampup_config_.first_non_zero_gain;
- return;
- }
-
- // Increase the gain limit until it reaches 1.f.
- RTC_DCHECK_LT(0.f, suppressor_gain_limit_);
- suppressor_gain_limit_ =
- std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_);
- RTC_DCHECK_GE(1.f, suppressor_gain_limit_);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.h b/modules/audio_processing/aec3/suppression_gain_limiter.h
deleted file mode 100644
index eade949..0000000
--- a/modules/audio_processing/aec3/suppression_gain_limiter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2018 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.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
-#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
-
-#include "api/array_view.h"
-#include "api/audio/echo_canceller3_config.h"
-#include "rtc_base/constructormagic.h"
-
-namespace webrtc {
-
-// Class for applying a smoothly increasing limit for the suppression gain
-// during call startup and after in-call resets.
-class SuppressionGainUpperLimiter {
- public:
- explicit SuppressionGainUpperLimiter(const EchoCanceller3Config& config);
-
- // Reset the limiting behavior.
- void Reset();
-
- // Updates the limiting behavior for the current capture bloc.
- void Update(bool render_activity, bool transparent_mode);
-
- // Returns the current suppressor gain limit.
- float Limit() const { return suppressor_gain_limit_; }
-
- // Return whether the suppressor gain limit is active.
- bool IsActive() const { return (realignment_counter_ > 0); }
-
- // Inactivate limiter.
- void Deactivate() {
- realignment_counter_ = 0;
- suppressor_gain_limit_ = 1.f;
- }
-
- private:
- const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
- const float gain_rampup_increase_;
- bool call_startup_phase_ = true;
- int realignment_counter_ = 0;
- bool active_render_seen_ = false;
- float suppressor_gain_limit_ = 1.f;
- bool recent_reset_ = false;
-
- RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SuppressionGainUpperLimiter);
-};
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc
index 651fd36..1ff96ca 100644
--- a/modules/audio_processing/aec3/suppression_gain_unittest.cc
+++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc
@@ -77,7 +77,7 @@
ApmDataDumper data_dumper(42);
Subtractor subtractor(config, &data_dumper, DetectOptimization());
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
- RenderDelayBuffer::Create2(config, 3));
+ RenderDelayBuffer::Create(config, 3));
absl::optional<DelayEstimate> delay_estimate;
// Ensure that a strong noise is detected to mask any echoes.
diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.cc b/modules/audio_processing/aec_dump/aec_dump_impl.cc
index 9020f2b..588d24d 100644
--- a/modules/audio_processing/aec_dump/aec_dump_impl.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_impl.cc
@@ -55,7 +55,7 @@
} // namespace
-AecDumpImpl::AecDumpImpl(std::unique_ptr<FileWrapper> debug_file,
+AecDumpImpl::AecDumpImpl(FileWrapper debug_file,
int64_t max_log_size_bytes,
rtc::TaskQueue* worker_queue)
: debug_file_(std::move(debug_file)),
@@ -196,7 +196,7 @@
}
std::unique_ptr<WriteToFileTask> AecDumpImpl::CreateWriteToFileTask() {
- return absl::make_unique<WriteToFileTask>(debug_file_.get(),
+ return absl::make_unique<WriteToFileTask>(&debug_file_,
&num_bytes_left_for_log_);
}
@@ -204,24 +204,20 @@
int64_t max_log_size_bytes,
rtc::TaskQueue* worker_queue) {
RTC_DCHECK(worker_queue);
- std::unique_ptr<FileWrapper> debug_file(FileWrapper::Create());
FILE* handle = rtc::FdopenPlatformFileForWriting(file);
if (!handle) {
return nullptr;
}
- if (!debug_file->OpenFromFileHandle(handle)) {
- return nullptr;
- }
- return absl::make_unique<AecDumpImpl>(std::move(debug_file),
- max_log_size_bytes, worker_queue);
+ return absl::make_unique<AecDumpImpl>(FileWrapper(handle), max_log_size_bytes,
+ worker_queue);
}
std::unique_ptr<AecDump> AecDumpFactory::Create(std::string file_name,
int64_t max_log_size_bytes,
rtc::TaskQueue* worker_queue) {
RTC_DCHECK(worker_queue);
- std::unique_ptr<FileWrapper> debug_file(FileWrapper::Create());
- if (!debug_file->OpenFile(file_name.c_str(), false)) {
+ FileWrapper debug_file = FileWrapper::OpenWriteOnly(file_name.c_str());
+ if (!debug_file.is_open()) {
return nullptr;
}
return absl::make_unique<AecDumpImpl>(std::move(debug_file),
@@ -233,11 +229,7 @@
rtc::TaskQueue* worker_queue) {
RTC_DCHECK(worker_queue);
RTC_DCHECK(handle);
- std::unique_ptr<FileWrapper> debug_file(FileWrapper::Create());
- if (!debug_file->OpenFromFileHandle(handle)) {
- return nullptr;
- }
- return absl::make_unique<AecDumpImpl>(std::move(debug_file),
- max_log_size_bytes, worker_queue);
+ return absl::make_unique<AecDumpImpl>(FileWrapper(handle), max_log_size_bytes,
+ worker_queue);
}
} // namespace webrtc
diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.h b/modules/audio_processing/aec_dump/aec_dump_impl.h
index df949ca..c247c1b 100644
--- a/modules/audio_processing/aec_dump/aec_dump_impl.h
+++ b/modules/audio_processing/aec_dump/aec_dump_impl.h
@@ -46,7 +46,7 @@
class AecDumpImpl : public AecDump {
public:
// Does member variables initialization shared across all c-tors.
- AecDumpImpl(std::unique_ptr<FileWrapper> debug_file,
+ AecDumpImpl(FileWrapper debug_file,
int64_t max_log_size_bytes,
rtc::TaskQueue* worker_queue);
@@ -73,7 +73,7 @@
private:
std::unique_ptr<WriteToFileTask> CreateWriteToFileTask();
- std::unique_ptr<FileWrapper> debug_file_;
+ FileWrapper debug_file_;
int64_t num_bytes_left_for_log_ = 0;
rtc::RaceChecker race_checker_;
rtc::TaskQueue* worker_queue_;
diff --git a/modules/audio_processing/aec_dump/aec_dump_unittest.cc b/modules/audio_processing/aec_dump/aec_dump_unittest.cc
index 75ed529..1f9ca0a 100644
--- a/modules/audio_processing/aec_dump/aec_dump_unittest.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_unittest.cc
@@ -14,7 +14,7 @@
#include "rtc_base/task_queue.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
TEST(AecDumper, APICallsDoNotCrash) {
// Note order of initialization: Task queue has to be initialized
diff --git a/modules/audio_processing/aec_dump/write_to_file_task.cc b/modules/audio_processing/aec_dump/write_to_file_task.cc
index 8dddd47..4839a09 100644
--- a/modules/audio_processing/aec_dump/write_to_file_task.cc
+++ b/modules/audio_processing/aec_dump/write_to_file_task.cc
@@ -10,7 +10,7 @@
#include "modules/audio_processing/aec_dump/write_to_file_task.h"
-#include "rtc_base/protobuf_utils.h"
+#include <string>
namespace webrtc {
@@ -39,17 +39,15 @@
}
bool WriteToFileTask::Run() {
- if (!debug_file_->is_open()) {
- return true;
- }
-
- ProtoString event_string;
+ std::string event_string;
event_.SerializeToString(&event_string);
const size_t event_byte_size = event_.ByteSizeLong();
if (!IsRoomForNextEvent(event_byte_size)) {
- debug_file_->CloseFile();
+ // Ensure that no further events are written, even if they're smaller than
+ // the current event.
+ *num_bytes_left_for_log_ = 0;
return true;
}
diff --git a/modules/audio_processing/aec_dump/write_to_file_task.h b/modules/audio_processing/aec_dump/write_to_file_task.h
index 711afb2..4b04a45 100644
--- a/modules/audio_processing/aec_dump/write_to_file_task.h
+++ b/modules/audio_processing/aec_dump/write_to_file_task.h
@@ -48,9 +48,9 @@
bool Run() override;
- webrtc::FileWrapper* debug_file_;
+ webrtc::FileWrapper* const debug_file_;
audioproc::Event event_;
- int64_t* num_bytes_left_for_log_;
+ int64_t* const num_bytes_left_for_log_;
};
} // namespace webrtc
diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn
index a5c15ec..4c0e768 100644
--- a/modules/audio_processing/agc/BUILD.gn
+++ b/modules/audio_processing/agc/BUILD.gn
@@ -108,11 +108,6 @@
]
configs += [ "..:apm_debug_dump" ]
- if ((!build_with_chromium || is_win) && is_clang) {
- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
":agc",
":level_estimation",
diff --git a/modules/audio_processing/agc/agc_manager_direct.h b/modules/audio_processing/agc/agc_manager_direct.h
index cbfd6a1..8c9fc4d 100644
--- a/modules/audio_processing/agc/agc_manager_direct.h
+++ b/modules/audio_processing/agc/agc_manager_direct.h
@@ -15,7 +15,7 @@
#include "modules/audio_processing/agc/agc.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/gtest_prod_util.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc/agc_manager_direct_unittest.cc b/modules/audio_processing/agc/agc_manager_direct_unittest.cc
index 73ea55d..4be420a 100644
--- a/modules/audio_processing/agc/agc_manager_direct_unittest.cc
+++ b/modules/audio_processing/agc/agc_manager_direct_unittest.cc
@@ -10,7 +10,6 @@
#include "modules/audio_processing/agc/agc_manager_direct.h"
-#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_processing/agc/mock_agc.h"
#include "modules/audio_processing/include/mock_audio_processing.h"
#include "test/gmock.h"
diff --git a/modules/audio_processing/agc/loudness_histogram_unittest.cc b/modules/audio_processing/agc/loudness_histogram_unittest.cc
index 8c61710..0c291d8 100644
--- a/modules/audio_processing/agc/loudness_histogram_unittest.cc
+++ b/modules/audio_processing/agc/loudness_histogram_unittest.cc
@@ -19,7 +19,7 @@
#include "modules/audio_processing/agc/utility.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc2/agc2_common.cc b/modules/audio_processing/agc2/agc2_common.cc
index af943df..1107885 100644
--- a/modules/audio_processing/agc2/agc2_common.cc
+++ b/modules/audio_processing/agc2/agc2_common.cc
@@ -54,4 +54,4 @@
constexpr float kDefaultExtraSaturationMarginDb = 2.f;
return kDefaultExtraSaturationMarginDb;
}
-}; // namespace webrtc
+} // namespace webrtc
diff --git a/modules/audio_processing/agc2/agc2_common.h b/modules/audio_processing/agc2/agc2_common.h
index 55dd648..a6389f4 100644
--- a/modules/audio_processing/agc2/agc2_common.h
+++ b/modules/audio_processing/agc2/agc2_common.h
@@ -41,10 +41,10 @@
// This is the threshold for speech. Speech frames are used for updating the
// speech level, measuring the amount of speech, and decide when to allow target
// gain reduction.
-constexpr float kVadConfidenceThreshold = 0.4f;
+constexpr float kVadConfidenceThreshold = 0.9f;
// The amount of 'memory' of the Level Estimator. Decides leak factors.
-constexpr size_t kFullBufferSizeMs = 1600;
+constexpr size_t kFullBufferSizeMs = 1200;
constexpr float kFullBufferLeakFactor = 1.f - 1.f / kFullBufferSizeMs;
constexpr float kInitialSpeechLevelEstimateDbfs = -30.f;
diff --git a/modules/audio_processing/agc2/biquad_filter.h b/modules/audio_processing/agc2/biquad_filter.h
index 3d78c07..7bf3301 100644
--- a/modules/audio_processing/agc2/biquad_filter.h
+++ b/modules/audio_processing/agc2/biquad_filter.h
@@ -15,7 +15,7 @@
#include "api/array_view.h"
#include "rtc_base/arraysize.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc2/down_sampler.h b/modules/audio_processing/agc2/down_sampler.h
index a609ea8..61d1b00 100644
--- a/modules/audio_processing/agc2/down_sampler.h
+++ b/modules/audio_processing/agc2/down_sampler.h
@@ -13,7 +13,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/agc2/biquad_filter.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc2/fixed_digital_level_estimator.h b/modules/audio_processing/agc2/fixed_digital_level_estimator.h
index 84429d3..aa84a2e 100644
--- a/modules/audio_processing/agc2/fixed_digital_level_estimator.h
+++ b/modules/audio_processing/agc2/fixed_digital_level_estimator.h
@@ -16,7 +16,7 @@
#include "modules/audio_processing/agc2/agc2_common.h"
#include "modules/audio_processing/include/audio_frame_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc2/gain_applier.h b/modules/audio_processing/agc2/gain_applier.h
index 7f9f00e..d9aa19d 100644
--- a/modules/audio_processing/agc2/gain_applier.h
+++ b/modules/audio_processing/agc2/gain_applier.h
@@ -22,7 +22,7 @@
void ApplyGain(AudioFrameView<float> signal);
void SetGainFactor(float gain_factor);
- float GetGainFactor() const { return current_gain_factor_; };
+ float GetGainFactor() const { return current_gain_factor_; }
private:
void Initialize(size_t samples_per_channel);
diff --git a/modules/audio_processing/agc2/interpolated_gain_curve.h b/modules/audio_processing/agc2/interpolated_gain_curve.h
index 68d4532..1ecb94e 100644
--- a/modules/audio_processing/agc2/interpolated_gain_curve.h
+++ b/modules/audio_processing/agc2/interpolated_gain_curve.h
@@ -16,7 +16,7 @@
#include "modules/audio_processing/agc2/agc2_common.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/gtest_prod_util.h"
#include "system_wrappers/include/metrics.h"
diff --git a/modules/audio_processing/agc2/limiter.h b/modules/audio_processing/agc2/limiter.h
index 1e0ab71..599fd0f 100644
--- a/modules/audio_processing/agc2/limiter.h
+++ b/modules/audio_processing/agc2/limiter.h
@@ -17,7 +17,7 @@
#include "modules/audio_processing/agc2/fixed_digital_level_estimator.h"
#include "modules/audio_processing/agc2/interpolated_gain_curve.h"
#include "modules/audio_processing/include/audio_frame_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class ApmDataDumper;
diff --git a/modules/audio_processing/agc2/noise_level_estimator.h b/modules/audio_processing/agc2/noise_level_estimator.h
index 24067a1..ca2f9f2 100644
--- a/modules/audio_processing/agc2/noise_level_estimator.h
+++ b/modules/audio_processing/agc2/noise_level_estimator.h
@@ -13,7 +13,7 @@
#include "modules/audio_processing/agc2/signal_classifier.h"
#include "modules/audio_processing/include/audio_frame_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class ApmDataDumper;
diff --git a/modules/audio_processing/agc2/noise_spectrum_estimator.h b/modules/audio_processing/agc2/noise_spectrum_estimator.h
index fd1cc13..b22f9bb 100644
--- a/modules/audio_processing/agc2/noise_spectrum_estimator.h
+++ b/modules/audio_processing/agc2/noise_spectrum_estimator.h
@@ -12,7 +12,7 @@
#define MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_
#include "api/array_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/agc2/rnn_vad/BUILD.gn b/modules/audio_processing/agc2/rnn_vad/BUILD.gn
index d1edece..b26aef0 100644
--- a/modules/audio_processing/agc2/rnn_vad/BUILD.gn
+++ b/modules/audio_processing/agc2/rnn_vad/BUILD.gn
@@ -52,8 +52,8 @@
]
deps = [
"../../../../api:array_view",
+ "../../../../api:scoped_refptr",
"../../../../rtc_base:checks",
- "../../../../rtc_base:ptr_util",
"../../../../test:fileutils",
"../../../../test:test_support",
"//third_party/abseil-cpp/absl/memory",
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util.cc b/modules/audio_processing/agc2/rnn_vad/fft_util.cc
index a1c5dac..4825e2b 100644
--- a/modules/audio_processing/agc2/rnn_vad/fft_util.cc
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util.cc
@@ -11,6 +11,7 @@
#include "modules/audio_processing/agc2/rnn_vad/fft_util.h"
#include <stddef.h>
+#include <algorithm>
#include <cmath>
#include "rtc_base/checks.h"
@@ -42,8 +43,8 @@
void BandAnalysisFft::ForwardFft(rtc::ArrayView<const float> samples,
rtc::ArrayView<std::complex<float>> dst) {
- RTC_DCHECK_EQ(input_buf_.size(), samples.size());
- RTC_DCHECK_EQ(samples.size(), dst.size());
+ RTC_DCHECK_EQ(samples.size(), kFrameSize20ms24kHz);
+ RTC_DCHECK_EQ(dst.size(), kFrameSize20ms24kHz / 2 + 1);
// Apply windowing.
RTC_DCHECK_EQ(input_buf_.size(), 2 * half_window_.size());
for (size_t i = 0; i < input_buf_.size() / 2; ++i) {
@@ -52,7 +53,10 @@
input_buf_[j].real(samples[j] * half_window_[i]);
}
fft_.ForwardFft(kFrameSize20ms24kHz, input_buf_.data(), kFrameSize20ms24kHz,
- dst.data());
+ output_buf_.data());
+ // Copy the first symmetric conjugate part.
+ RTC_DCHECK_LT(dst.size(), output_buf_.size());
+ std::copy(output_buf_.begin(), output_buf_.begin() + dst.size(), dst.begin());
}
} // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util.h b/modules/audio_processing/agc2/rnn_vad/fft_util.h
index f4265f4..c744ff6 100644
--- a/modules/audio_processing/agc2/rnn_vad/fft_util.h
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util.h
@@ -21,6 +21,8 @@
namespace webrtc {
namespace rnn_vad {
+// TODO(alessiob): Switch to PFFFT using its own wrapper.
+// TODO(alessiob): Delete this class when switching to PFFFT.
// FFT implementation wrapper for the band-wise analysis step in which 20 ms
// frames at 24 kHz are analyzed in the frequency domain. The goal of this class
// are (i) making easy to switch to another FFT implementation, (ii) own the
@@ -34,6 +36,8 @@
~BandAnalysisFft();
// Applies a windowing function to |samples|, computes the real forward FFT
// and writes the result in |dst|.
+ // The size of |samples| must be 480 (20 ms at 24 kHz).
+ // The size of |dst| must be 241 since the complex conjugate is not written.
void ForwardFft(rtc::ArrayView<const float> samples,
rtc::ArrayView<std::complex<float>> dst);
@@ -42,6 +46,7 @@
"kFrameSize20ms24kHz must be even.");
const std::array<float, kFrameSize20ms24kHz / 2> half_window_;
std::array<std::complex<float>, kFrameSize20ms24kHz> input_buf_{};
+ std::array<std::complex<float>, kFrameSize20ms24kHz> output_buf_{};
rnnoise::KissFft fft_;
};
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc b/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc
index 9854600..28f56bd 100644
--- a/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc
@@ -8,7 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <array>
+#include <algorithm>
+#include <cmath>
+#include <vector>
#include "modules/audio_processing/agc2/rnn_vad/common.h"
#include "modules/audio_processing/agc2/rnn_vad/fft_util.h"
@@ -20,27 +22,40 @@
namespace webrtc {
namespace rnn_vad {
namespace test {
+namespace {
-TEST(RnnVadTest, CheckBandAnalysisFftOutput) {
- // Input data.
- std::array<float, kFrameSize20ms24kHz> samples{};
- for (int i = 0; i < static_cast<int>(kFrameSize20ms24kHz); ++i) {
- samples[i] = i - static_cast<int>(kFrameSize20ms24kHz / 2);
+std::vector<float> CreateSine(float amplitude,
+ float frequency_hz,
+ float duration_s,
+ int sample_rate_hz) {
+ size_t num_samples = static_cast<size_t>(duration_s * sample_rate_hz);
+ std::vector<float> signal(num_samples);
+ for (size_t i = 0; i < num_samples; ++i) {
+ signal[i] =
+ amplitude * std::sin(i * 2.0 * kPi * frequency_hz / sample_rate_hz);
}
- // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
- // FloatingPointExceptionObserver fpe_observer;
- BandAnalysisFft fft;
- std::array<std::complex<float>, kFrameSize20ms24kHz> fft_coeffs;
- fft.ForwardFft(samples, fft_coeffs);
- // First coefficient is DC - i.e., real number.
- EXPECT_EQ(0.f, fft_coeffs[0].imag());
- // Check conjugated symmetry of the FFT output.
- for (size_t i = 1; i < fft_coeffs.size() / 2; ++i) {
- SCOPED_TRACE(i);
- const auto& a = fft_coeffs[i];
- const auto& b = fft_coeffs[fft_coeffs.size() - i];
- EXPECT_NEAR(a.real(), b.real(), 2e-6f);
- EXPECT_NEAR(a.imag(), -b.imag(), 2e-6f);
+ return signal;
+}
+
+} // namespace
+
+TEST(RnnVadTest, BandAnalysisFftTest) {
+ for (float frequency_hz : {200.f, 450.f, 1500.f}) {
+ SCOPED_TRACE(frequency_hz);
+ auto x = CreateSine(
+ /*amplitude=*/1000.f, frequency_hz,
+ /*duration_s=*/0.02f,
+ /*sample_rate_hz=*/kSampleRate24kHz);
+ BandAnalysisFft analyzer;
+ std::vector<std::complex<float>> x_fft(x.size() / 2 + 1);
+ analyzer.ForwardFft(x, x_fft);
+ int peak_fft_bin_index = std::distance(
+ x_fft.begin(),
+ std::max_element(x_fft.begin(), x_fft.end(),
+ [](std::complex<float> a, std::complex<float> b) {
+ return std::abs(a) < std::abs(b);
+ }));
+ EXPECT_EQ(frequency_hz, kSampleRate24kHz * peak_fft_bin_index / x.size());
}
}
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_info.h b/modules/audio_processing/agc2/rnn_vad/pitch_info.h
index f0998d1..c9fdd18 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_info.h
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_info.h
@@ -18,8 +18,8 @@
// strength of the pitch (the higher, the stronger).
struct PitchInfo {
PitchInfo() : period(0), gain(0.f) {}
- PitchInfo(size_t p, float g) : period(p), gain(g) {}
- size_t period;
+ PitchInfo(int p, float g) : period(p), gain(g) {}
+ int period;
float gain;
};
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
index 32ee8c0..7c17dfb 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
@@ -128,12 +128,12 @@
// sn = mex({n * i for i in S} | {1})
// S = S | {Fraction(1, n), Fraction(sn, n)}
// print(sn, end=', ')
-constexpr std::array<size_t, 14> kSubHarmonicMultipliers = {
+constexpr std::array<int, 14> kSubHarmonicMultipliers = {
{3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}};
// Initial pitch period candidate thresholds for ComputePitchGainThreshold() for
// a sample rate of 24 kHz. Computed as [5*k*k for k in range(16)].
-constexpr std::array<size_t, 14> kInitialPitchPeriodThresholds = {
+constexpr std::array<int, 14> kInitialPitchPeriodThresholds = {
{20, 45, 80, 125, 180, 245, 320, 405, 500, 605, 720, 845, 980, 1125}};
} // namespace
@@ -147,31 +147,34 @@
}
}
-float ComputePitchGainThreshold(size_t candidate_pitch_period,
- size_t pitch_period_ratio,
- size_t initial_pitch_period,
+float ComputePitchGainThreshold(int candidate_pitch_period,
+ int pitch_period_ratio,
+ int initial_pitch_period,
float initial_pitch_gain,
- size_t prev_pitch_period,
- size_t prev_pitch_gain) {
+ int prev_pitch_period,
+ float prev_pitch_gain) {
// Map arguments to more compact aliases.
- const size_t& t1 = candidate_pitch_period;
- const size_t& k = pitch_period_ratio;
- const size_t& t0 = initial_pitch_period;
+ const int& t1 = candidate_pitch_period;
+ const int& k = pitch_period_ratio;
+ const int& t0 = initial_pitch_period;
const float& g0 = initial_pitch_gain;
- const size_t& t_prev = prev_pitch_period;
- const size_t& g_prev = prev_pitch_gain;
+ const int& t_prev = prev_pitch_period;
+ const float& g_prev = prev_pitch_gain;
// Validate input.
+ RTC_DCHECK_GE(t1, 0);
RTC_DCHECK_GE(k, 2);
+ RTC_DCHECK_GE(t0, 0);
+ RTC_DCHECK_GE(t_prev, 0);
// Compute a term that lowers the threshold when |t1| is close to the last
// estimated period |t_prev| - i.e., pitch tracking.
float lower_threshold_term = 0;
- if (abs(static_cast<int>(t1) - static_cast<int>(t_prev)) <= 1) {
+ if (abs(t1 - t_prev) <= 1) {
// The candidate pitch period is within 1 sample from the previous one.
// Make the candidate at |t1| very easy to be accepted.
lower_threshold_term = g_prev;
- } else if (abs(static_cast<int>(t1) - static_cast<int>(t_prev)) == 2 &&
+ } else if (abs(t1 - t_prev) == 2 &&
t0 > kInitialPitchPeriodThresholds[k - 2]) {
// The candidate pitch period is 2 samples far from the previous one and the
// period |t0| (from which |t1| has been derived) is greater than a
@@ -182,9 +185,11 @@
// reduce the chance of false positives caused by a bias towards high
// frequencies (originating from short-term correlations).
float threshold = std::max(0.3f, 0.7f * g0 - lower_threshold_term);
- if (t1 < 3 * kMinPitch24kHz) { // High frequency.
+ if (static_cast<size_t>(t1) < 3 * kMinPitch24kHz) {
+ // High frequency.
threshold = std::max(0.4f, 0.85f * g0 - lower_threshold_term);
- } else if (t1 < 2 * kMinPitch24kHz) { // Even higher frequency.
+ } else if (static_cast<size_t>(t1) < 2 * kMinPitch24kHz) {
+ // Even higher frequency.
threshold = std::max(0.5f, 0.9f * g0 - lower_threshold_term);
}
return threshold;
@@ -350,16 +355,16 @@
PitchInfo CheckLowerPitchPeriodsAndComputePitchGain(
rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
- size_t initial_pitch_period_48kHz,
+ int initial_pitch_period_48kHz,
PitchInfo prev_pitch_48kHz) {
RTC_DCHECK_LE(kMinPitch48kHz, initial_pitch_period_48kHz);
RTC_DCHECK_LE(initial_pitch_period_48kHz, kMaxPitch48kHz);
// Stores information for a refined pitch candidate.
struct RefinedPitchCandidate {
RefinedPitchCandidate() {}
- RefinedPitchCandidate(size_t period_24kHz, float gain, float xy, float yy)
+ RefinedPitchCandidate(int period_24kHz, float gain, float xy, float yy)
: period_24kHz(period_24kHz), gain(gain), xy(xy), yy(yy) {}
- size_t period_24kHz;
+ int period_24kHz;
// Pitch strength information.
float gain;
// Additional pitch strength information used for the final estimation of
@@ -380,8 +385,8 @@
};
// Initial pitch candidate gain.
RefinedPitchCandidate best_pitch;
- best_pitch.period_24kHz =
- std::min(initial_pitch_period_48kHz / 2, kMaxPitch24kHz - 1);
+ best_pitch.period_24kHz = std::min(initial_pitch_period_48kHz / 2,
+ static_cast<int>(kMaxPitch24kHz - 1));
best_pitch.xy = ComputeAutoCorrelationCoeff(
pitch_buf, GetInvertedLag(best_pitch.period_24kHz), kMaxPitch24kHz);
best_pitch.yy = yy_values[best_pitch.period_24kHz];
@@ -392,24 +397,27 @@
const float initial_pitch_gain = best_pitch.gain;
// Given the initial pitch estimation, check lower periods (i.e., harmonics).
- const auto alternative_period = [](size_t period, size_t k,
- size_t n) -> size_t {
- RTC_DCHECK_LT(0, k);
+ const auto alternative_period = [](int period, int k, int n) -> int {
+ RTC_DCHECK_GT(k, 0);
return (2 * n * period + k) / (2 * k); // Same as round(n*period/k).
};
- for (size_t k = 2; k < kSubHarmonicMultipliers.size() + 2; ++k) {
- size_t candidate_pitch_period =
- alternative_period(initial_pitch_period, k, 1);
- if (candidate_pitch_period < kMinPitch24kHz)
+ for (int k = 2; k < static_cast<int>(kSubHarmonicMultipliers.size() + 2);
+ ++k) {
+ int candidate_pitch_period = alternative_period(initial_pitch_period, k, 1);
+ if (static_cast<size_t>(candidate_pitch_period) < kMinPitch24kHz) {
break;
+ }
// When looking at |candidate_pitch_period|, we also look at one of its
// sub-harmonics. |kSubHarmonicMultipliers| is used to know where to look.
// |k| == 2 is a special case since |candidate_pitch_secondary_period| might
// be greater than the maximum pitch period.
- size_t candidate_pitch_secondary_period = alternative_period(
+ int candidate_pitch_secondary_period = alternative_period(
initial_pitch_period, k, kSubHarmonicMultipliers[k - 2]);
- if (k == 2 && candidate_pitch_secondary_period > kMaxPitch24kHz)
+ RTC_DCHECK_GT(candidate_pitch_secondary_period, 0);
+ if (k == 2 &&
+ candidate_pitch_secondary_period > static_cast<int>(kMaxPitch24kHz)) {
candidate_pitch_secondary_period = initial_pitch_period;
+ }
RTC_DCHECK_NE(candidate_pitch_period, candidate_pitch_secondary_period)
<< "The lower pitch period and the additional sub-harmonic must not "
<< "coincide.";
@@ -442,7 +450,7 @@
? 1.f
: best_pitch.xy / (best_pitch.yy + 1.f);
final_pitch_gain = std::min(best_pitch.gain, final_pitch_gain);
- size_t final_pitch_period_48kHz = std::max(
+ int final_pitch_period_48kHz = std::max(
kMinPitch48kHz,
PitchPseudoInterpolationLagPitchBuf(best_pitch.period_24kHz, pitch_buf));
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
index bb747bb..aabf713 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
@@ -41,12 +41,12 @@
// Computes a gain threshold for a candidate pitch period given the initial and
// the previous pitch period and gain estimates and the pitch period ratio used
// to derive the candidate pitch period from the initial period.
-float ComputePitchGainThreshold(size_t candidate_pitch_period,
- size_t pitch_period_ratio,
- size_t initial_pitch_period,
+float ComputePitchGainThreshold(int candidate_pitch_period,
+ int pitch_period_ratio,
+ int initial_pitch_period,
float initial_pitch_gain,
- size_t prev_pitch_period,
- size_t prev_pitch_gain);
+ int prev_pitch_period,
+ float prev_pitch_gain);
// Computes the sum of squared samples for every sliding frame in the pitch
// buffer. |yy_values| indexes are lags.
@@ -99,7 +99,7 @@
// refined pitch estimation data at 48 kHz.
PitchInfo CheckLowerPitchPeriodsAndComputePitchGain(
rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
- size_t initial_pitch_period_48kHz,
+ int initial_pitch_period_48kHz,
PitchInfo prev_pitch_48kHz);
} // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
index 82b4810..8ff6ac1 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
@@ -24,8 +24,9 @@
namespace test {
namespace {
-constexpr std::array<size_t, 2> kTestPitchPeriods = {
- 3 * kMinPitch48kHz / 2, (3 * kMinPitch48kHz + kMaxPitch48kHz) / 2,
+constexpr std::array<int, 2> kTestPitchPeriods = {
+ 3 * kMinPitch48kHz / 2,
+ (3 * kMinPitch48kHz + kMaxPitch48kHz) / 2,
};
constexpr std::array<float, 2> kTestPitchGains = {0.35f, 0.75f};
@@ -87,7 +88,7 @@
}
}
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
RnnVadTest,
ComputePitchGainThresholdTest,
::testing::Values(
@@ -197,14 +198,14 @@
class CheckLowerPitchPeriodsAndComputePitchGainTest
: public testing::Test,
public ::testing::WithParamInterface<
- std::tuple<size_t, size_t, float, size_t, float>> {};
+ std::tuple<int, int, float, int, float>> {};
TEST_P(CheckLowerPitchPeriodsAndComputePitchGainTest, BitExactness) {
const auto params = GetParam();
- const size_t initial_pitch_period = std::get<0>(params);
- const size_t prev_pitch_period = std::get<1>(params);
+ const int initial_pitch_period = std::get<0>(params);
+ const int prev_pitch_period = std::get<1>(params);
const float prev_pitch_gain = std::get<2>(params);
- const size_t expected_pitch_period = std::get<3>(params);
+ const int expected_pitch_period = std::get<3>(params);
const float expected_pitch_gain = std::get<4>(params);
TestData test_data;
{
@@ -218,48 +219,48 @@
}
}
-INSTANTIATE_TEST_CASE_P(RnnVadTest,
- CheckLowerPitchPeriodsAndComputePitchGainTest,
- ::testing::Values(std::make_tuple(kTestPitchPeriods[0],
- kTestPitchPeriods[0],
- kTestPitchGains[0],
- 91,
- -0.0188608f),
- std::make_tuple(kTestPitchPeriods[0],
- kTestPitchPeriods[0],
- kTestPitchGains[1],
- 91,
- -0.0188608f),
- std::make_tuple(kTestPitchPeriods[0],
- kTestPitchPeriods[1],
- kTestPitchGains[0],
- 91,
- -0.0188608f),
- std::make_tuple(kTestPitchPeriods[0],
- kTestPitchPeriods[1],
- kTestPitchGains[1],
- 91,
- -0.0188608f),
- std::make_tuple(kTestPitchPeriods[1],
- kTestPitchPeriods[0],
- kTestPitchGains[0],
- 475,
- -0.0904344f),
- std::make_tuple(kTestPitchPeriods[1],
- kTestPitchPeriods[0],
- kTestPitchGains[1],
- 475,
- -0.0904344f),
- std::make_tuple(kTestPitchPeriods[1],
- kTestPitchPeriods[1],
- kTestPitchGains[0],
- 475,
- -0.0904344f),
- std::make_tuple(kTestPitchPeriods[1],
- kTestPitchPeriods[1],
- kTestPitchGains[1],
- 475,
- -0.0904344f)));
+INSTANTIATE_TEST_SUITE_P(RnnVadTest,
+ CheckLowerPitchPeriodsAndComputePitchGainTest,
+ ::testing::Values(std::make_tuple(kTestPitchPeriods[0],
+ kTestPitchPeriods[0],
+ kTestPitchGains[0],
+ 91,
+ -0.0188608f),
+ std::make_tuple(kTestPitchPeriods[0],
+ kTestPitchPeriods[0],
+ kTestPitchGains[1],
+ 91,
+ -0.0188608f),
+ std::make_tuple(kTestPitchPeriods[0],
+ kTestPitchPeriods[1],
+ kTestPitchGains[0],
+ 91,
+ -0.0188608f),
+ std::make_tuple(kTestPitchPeriods[0],
+ kTestPitchPeriods[1],
+ kTestPitchGains[1],
+ 91,
+ -0.0188608f),
+ std::make_tuple(kTestPitchPeriods[1],
+ kTestPitchPeriods[0],
+ kTestPitchGains[0],
+ 475,
+ -0.0904344f),
+ std::make_tuple(kTestPitchPeriods[1],
+ kTestPitchPeriods[0],
+ kTestPitchGains[1],
+ 475,
+ -0.0904344f),
+ std::make_tuple(kTestPitchPeriods[1],
+ kTestPitchPeriods[1],
+ kTestPitchGains[0],
+ 475,
+ -0.0904344f),
+ std::make_tuple(kTestPitchPeriods[1],
+ kTestPitchPeriods[1],
+ kTestPitchGains[1],
+ 475,
+ -0.0904344f)));
} // namespace test
} // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
index 4c56238..eac332e 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
@@ -39,7 +39,7 @@
lp_residual_reader.first->ReadValue(&expected_pitch_period);
lp_residual_reader.first->ReadValue(&expected_pitch_gain);
PitchInfo pitch_info = pitch_estimator.Estimate(lp_residual);
- EXPECT_EQ(static_cast<size_t>(expected_pitch_period), pitch_info.period);
+ EXPECT_EQ(static_cast<int>(expected_pitch_period), pitch_info.period);
EXPECT_NEAR(expected_pitch_gain, pitch_info.gain, 1e-5f);
}
}
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features.cc b/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
index 695eed5..84db2df 100644
--- a/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
@@ -68,8 +68,8 @@
SpectralFeaturesExtractor::SpectralFeaturesExtractor()
: fft_(),
- reference_frame_fft_(kFrameSize20ms24kHz),
- lagged_frame_fft_(kFrameSize20ms24kHz),
+ reference_frame_fft_(kFrameSize20ms24kHz / 2 + 1),
+ lagged_frame_fft_(kFrameSize20ms24kHz / 2 + 1),
band_boundaries_(
ComputeBandBoundaryIndexes(kSampleRate24kHz, kFrameSize20ms24kHz)),
dct_table_(ComputeDctTable()) {}
diff --git a/modules/audio_processing/agc2/rnn_vad/test_utils.cc b/modules/audio_processing/agc2/rnn_vad/test_utils.cc
index db38cab..8decbd0 100644
--- a/modules/audio_processing/agc2/rnn_vad/test_utils.cc
+++ b/modules/audio_processing/agc2/rnn_vad/test_utils.cc
@@ -13,7 +13,7 @@
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace rnn_vad {
diff --git a/modules/audio_processing/agc2/signal_classifier.h b/modules/audio_processing/agc2/signal_classifier.h
index 23fe315..e0d6771 100644
--- a/modules/audio_processing/agc2/signal_classifier.h
+++ b/modules/audio_processing/agc2/signal_classifier.h
@@ -18,7 +18,7 @@
#include "modules/audio_processing/agc2/down_sampler.h"
#include "modules/audio_processing/agc2/noise_spectrum_estimator.h"
#include "modules/audio_processing/utility/ooura_fft.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/audio_buffer.h b/modules/audio_processing/audio_buffer.h
index 469646e..a85144b 100644
--- a/modules/audio_processing/audio_buffer.h
+++ b/modules/audio_processing/audio_buffer.h
@@ -19,7 +19,6 @@
#include "api/audio/audio_frame.h"
#include "common_audio/channel_buffer.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/gtest_prod_util.h"
namespace webrtc {
diff --git a/modules/audio_processing/audio_generator/file_audio_generator.h b/modules/audio_processing/audio_generator/file_audio_generator.h
index 01979a4..f322b09 100644
--- a/modules/audio_processing/audio_generator/file_audio_generator.h
+++ b/modules/audio_processing/audio_generator/file_audio_generator.h
@@ -15,7 +15,7 @@
#include "common_audio/wav_file.h"
#include "modules/audio_processing/include/audio_generator.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/audio_generator/file_audio_generator_unittest.cc b/modules/audio_processing/audio_generator/file_audio_generator_unittest.cc
index 6ed3b94..6569bfe 100644
--- a/modules/audio_processing/audio_generator/file_audio_generator_unittest.cc
+++ b/modules/audio_processing/audio_generator/file_audio_generator_unittest.cc
@@ -13,7 +13,7 @@
#include "modules/audio_processing/include/audio_generator_factory.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace test {
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 2937c06..504eb31 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -16,10 +16,12 @@
#include <type_traits>
#include <utility>
+#include "absl/memory/memory.h"
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "common_audio/audio_converter.h"
#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/aec3/echo_canceller3.h"
#include "modules/audio_processing/agc/agc_manager_direct.h"
#include "modules/audio_processing/agc2/gain_applier.h"
#include "modules/audio_processing/audio_buffer.h"
@@ -34,15 +36,16 @@
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "modules/audio_processing/low_cut_filter.h"
#include "modules/audio_processing/noise_suppression_impl.h"
+#include "modules/audio_processing/noise_suppression_proxy.h"
#include "modules/audio_processing/residual_echo_detector.h"
#include "modules/audio_processing/transient/transient_suppressor.h"
#include "modules/audio_processing/voice_detection_impl.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/logging.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
#include "system_wrappers/include/metrics.h"
@@ -107,6 +110,23 @@
return uppermost_native_rate;
}
+NoiseSuppression::Level NsConfigLevelToInterfaceLevel(
+ AudioProcessing::Config::NoiseSuppression::Level level) {
+ using NsConfig = AudioProcessing::Config::NoiseSuppression;
+ switch (level) {
+ case NsConfig::kLow:
+ return NoiseSuppression::kLow;
+ case NsConfig::kModerate:
+ return NoiseSuppression::kModerate;
+ case NsConfig::kHigh:
+ return NoiseSuppression::kHigh;
+ case NsConfig::kVeryHigh:
+ return NoiseSuppression::kVeryHigh;
+ default:
+ RTC_NOTREACHED();
+ }
+}
+
// Maximum lengths that frame of samples being passed from the render side to
// the capture side can have (does not apply to AEC3).
static const size_t kMaxAllowedValuesOfSamplesPerBand = 160;
@@ -140,6 +160,7 @@
bool pre_amplifier_enabled,
bool echo_controller_enabled,
bool voice_activity_detector_enabled,
+ bool private_voice_detector_enabled,
bool level_estimator_enabled,
bool transient_suppressor_enabled) {
bool changed = false;
@@ -159,6 +180,8 @@
changed |= (level_estimator_enabled != level_estimator_enabled_);
changed |=
(voice_activity_detector_enabled != voice_activity_detector_enabled_);
+ changed |=
+ (private_voice_detector_enabled != private_voice_detector_enabled_);
changed |= (transient_suppressor_enabled != transient_suppressor_enabled_);
if (changed) {
high_pass_filter_enabled_ = high_pass_filter_enabled;
@@ -172,6 +195,7 @@
echo_controller_enabled_ = echo_controller_enabled;
level_estimator_enabled_ = level_estimator_enabled;
voice_activity_detector_enabled_ = voice_activity_detector_enabled;
+ private_voice_detector_enabled_ = private_voice_detector_enabled;
transient_suppressor_enabled_ = transient_suppressor_enabled;
}
@@ -182,7 +206,8 @@
bool AudioProcessingImpl::ApmSubmoduleStates::CaptureMultiBandSubModulesActive()
const {
- return CaptureMultiBandProcessingActive() || voice_activity_detector_enabled_;
+ return CaptureMultiBandProcessingActive() ||
+ voice_activity_detector_enabled_ || private_voice_detector_enabled_;
}
bool AudioProcessingImpl::ApmSubmoduleStates::CaptureMultiBandProcessingActive()
@@ -227,9 +252,12 @@
struct AudioProcessingImpl::ApmPublicSubmodules {
ApmPublicSubmodules() {}
// Accessed externally of APM without any lock acquired.
+ // TODO(bugs.webrtc.org/9947): Move these submodules into private_submodules_
+ // when their pointer-to-submodule API functions are gone.
std::unique_ptr<GainControlImpl> gain_control;
std::unique_ptr<LevelEstimatorImpl> level_estimator;
std::unique_ptr<NoiseSuppressionImpl> noise_suppression;
+ std::unique_ptr<NoiseSuppressionProxy> noise_suppression_proxy;
std::unique_ptr<VoiceDetectionImpl> voice_detection;
std::unique_ptr<GainControlForExperimentalAgc>
gain_control_for_experimental_agc;
@@ -260,6 +288,7 @@
std::unique_ptr<GainApplier> pre_amplifier;
std::unique_ptr<CustomAudioAnalyzer> capture_analyzer;
std::unique_ptr<LevelEstimatorImpl> output_level_estimator;
+ std::unique_ptr<VoiceDetectionImpl> voice_detector;
};
AudioProcessingBuilder::AudioProcessingBuilder() = default;
@@ -360,46 +389,42 @@
capture_(config.Get<ExperimentalNs>().enabled),
#endif
capture_nonlocked_() {
- {
- rtc::CritScope cs_render(&crit_render_);
- rtc::CritScope cs_capture(&crit_capture_);
+ // Mark Echo Controller enabled if a factory is injected.
+ capture_nonlocked_.echo_controller_enabled =
+ static_cast<bool>(echo_control_factory_);
- // Mark Echo Controller enabled if a factory is injected.
- capture_nonlocked_.echo_controller_enabled =
- static_cast<bool>(echo_control_factory_);
+ public_submodules_->gain_control.reset(new GainControlImpl(&crit_capture_));
+ public_submodules_->level_estimator.reset(
+ new LevelEstimatorImpl(&crit_capture_));
+ public_submodules_->noise_suppression.reset(
+ new NoiseSuppressionImpl(&crit_capture_));
+ public_submodules_->noise_suppression_proxy.reset(new NoiseSuppressionProxy(
+ this, public_submodules_->noise_suppression.get()));
+ public_submodules_->voice_detection.reset(
+ new VoiceDetectionImpl(&crit_capture_));
+ public_submodules_->gain_control_for_experimental_agc.reset(
+ new GainControlForExperimentalAgc(public_submodules_->gain_control.get(),
+ &crit_capture_));
- public_submodules_->gain_control.reset(
- new GainControlImpl(&crit_render_, &crit_capture_));
- public_submodules_->level_estimator.reset(
- new LevelEstimatorImpl(&crit_capture_));
- public_submodules_->noise_suppression.reset(
- new NoiseSuppressionImpl(&crit_capture_));
- public_submodules_->voice_detection.reset(
- new VoiceDetectionImpl(&crit_capture_));
- public_submodules_->gain_control_for_experimental_agc.reset(
- new GainControlForExperimentalAgc(
- public_submodules_->gain_control.get(), &crit_capture_));
-
- // If no echo detector is injected, use the ResidualEchoDetector.
- if (!private_submodules_->echo_detector) {
- private_submodules_->echo_detector =
- new rtc::RefCountedObject<ResidualEchoDetector>();
- }
-
- private_submodules_->echo_cancellation.reset(new EchoCancellationImpl());
- private_submodules_->echo_control_mobile.reset(new EchoControlMobileImpl());
- // TODO(alessiob): Move the injected gain controller once injection is
- // implemented.
- private_submodules_->gain_controller2.reset(new GainController2());
-
- RTC_LOG(LS_INFO) << "Capture analyzer activated: "
- << !!private_submodules_->capture_analyzer
- << "\nCapture post processor activated: "
- << !!private_submodules_->capture_post_processor
- << "\nRender pre processor activated: "
- << !!private_submodules_->render_pre_processor;
+ // If no echo detector is injected, use the ResidualEchoDetector.
+ if (!private_submodules_->echo_detector) {
+ private_submodules_->echo_detector =
+ new rtc::RefCountedObject<ResidualEchoDetector>();
}
+ private_submodules_->echo_cancellation.reset(new EchoCancellationImpl());
+ private_submodules_->echo_control_mobile.reset(new EchoControlMobileImpl());
+ // TODO(alessiob): Move the injected gain controller once injection is
+ // implemented.
+ private_submodules_->gain_controller2.reset(new GainController2());
+
+ RTC_LOG(LS_INFO) << "Capture analyzer activated: "
+ << !!private_submodules_->capture_analyzer
+ << "\nCapture post processor activated: "
+ << !!private_submodules_->capture_post_processor
+ << "\nRender pre processor activated: "
+ << !!private_submodules_->render_pre_processor;
+
SetExtraOptions(config);
}
@@ -540,6 +565,10 @@
public_submodules_->noise_suppression->Initialize(num_proc_channels(),
proc_sample_rate_hz());
public_submodules_->voice_detection->Initialize(proc_split_sample_rate_hz());
+ if (private_submodules_->voice_detector) {
+ private_submodules_->voice_detector->Initialize(
+ proc_split_sample_rate_hz());
+ }
public_submodules_->level_estimator->Initialize();
InitializeResidualEchoDetector();
InitializeEchoController();
@@ -642,17 +671,25 @@
rtc::CritScope cs_render(&crit_render_);
rtc::CritScope cs_capture(&crit_capture_);
+ const bool aec_config_changed =
+ config_.echo_canceller.enabled != config.echo_canceller.enabled ||
+ config_.echo_canceller.use_legacy_aec !=
+ config.echo_canceller.use_legacy_aec ||
+ config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode ||
+ (config_.echo_canceller.enabled && config.echo_canceller.use_legacy_aec &&
+ config_.echo_canceller.legacy_moderate_suppression_level !=
+ config.echo_canceller.legacy_moderate_suppression_level);
+
config_ = config;
- private_submodules_->echo_cancellation->Enable(
- config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode);
- private_submodules_->echo_control_mobile->Enable(
- config_.echo_canceller.enabled && config_.echo_canceller.mobile_mode);
+ if (aec_config_changed) {
+ InitializeEchoController();
+ }
- private_submodules_->echo_cancellation->set_suppression_level(
- config.echo_canceller.legacy_moderate_suppression_level
- ? EchoCancellationImpl::SuppressionLevel::kModerateSuppression
- : EchoCancellationImpl::SuppressionLevel::kHighSuppression);
+ public_submodules_->noise_suppression->Enable(
+ config.noise_suppression.enabled);
+ public_submodules_->noise_suppression->set_level(
+ NsConfigLevelToInterfaceLevel(config.noise_suppression.level));
InitializeLowCutFilter();
@@ -681,6 +718,16 @@
new LevelEstimatorImpl(&crit_capture_));
private_submodules_->output_level_estimator->Enable(true);
}
+
+ if (config_.voice_detection.enabled && !private_submodules_->voice_detector) {
+ private_submodules_->voice_detector.reset(
+ new VoiceDetectionImpl(&crit_capture_));
+ private_submodules_->voice_detector->Enable(true);
+ private_submodules_->voice_detector->set_likelihood(
+ VoiceDetection::kVeryLowLikelihood);
+ private_submodules_->voice_detector->Initialize(
+ proc_split_sample_rate_hz());
+ }
}
void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) {
@@ -1285,6 +1332,13 @@
}
public_submodules_->voice_detection->ProcessCaptureAudio(capture_buffer);
+ if (config_.voice_detection.enabled) {
+ private_submodules_->voice_detector->ProcessCaptureAudio(capture_buffer);
+ capture_.stats.voice_detected =
+ private_submodules_->voice_detector->stream_has_voice();
+ } else {
+ capture_.stats.voice_detected = absl::nullopt;
+ }
if (constants_.use_experimental_agc &&
public_submodules_->gain_control->is_enabled() &&
@@ -1293,6 +1347,7 @@
capture_buffer->split_bands_const(0)[kBand0To8kHz],
capture_buffer->num_frames_per_band(), capture_nonlocked_.split_rate);
}
+ // TODO(peah): Add reporting from AEC3 whether there is echo.
RETURN_ON_ERR(public_submodules_->gain_control->ProcessCaptureAudio(
capture_buffer,
private_submodules_->echo_cancellation->stream_has_echo()));
@@ -1663,7 +1718,7 @@
}
NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
- return public_submodules_->noise_suppression.get();
+ return public_submodules_->noise_suppression_proxy.get();
}
VoiceDetection* AudioProcessingImpl::voice_detection() const {
@@ -1695,6 +1750,7 @@
config_.gain_controller2.enabled, config_.pre_amplifier.enabled,
capture_nonlocked_.echo_controller_enabled,
public_submodules_->voice_detection->is_enabled(),
+ config_.voice_detection.enabled,
public_submodules_->level_estimator->is_enabled(),
capture_.transient_suppressor_enabled);
}
@@ -1720,11 +1776,31 @@
}
void AudioProcessingImpl::InitializeEchoController() {
- if (echo_control_factory_) {
- private_submodules_->echo_controller =
- echo_control_factory_->Create(proc_sample_rate_hz());
+ if (echo_control_factory_ ||
+ (config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode &&
+ !config_.echo_canceller.use_legacy_aec)) {
+ if (echo_control_factory_) {
+ private_submodules_->echo_controller =
+ echo_control_factory_->Create(proc_sample_rate_hz());
+ } else {
+ private_submodules_->echo_controller = absl::make_unique<EchoCanceller3>(
+ EchoCanceller3Config(), proc_sample_rate_hz(), true);
+ }
+
+ capture_nonlocked_.echo_controller_enabled = true;
} else {
+ private_submodules_->echo_cancellation->Enable(
+ config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode);
+ private_submodules_->echo_control_mobile->Enable(
+ config_.echo_canceller.enabled && config_.echo_canceller.mobile_mode);
+
+ private_submodules_->echo_cancellation->set_suppression_level(
+ config_.echo_canceller.legacy_moderate_suppression_level
+ ? EchoCancellationImpl::SuppressionLevel::kModerateSuppression
+ : EchoCancellationImpl::SuppressionLevel::kHighSuppression);
+
private_submodules_->echo_controller.reset();
+ capture_nonlocked_.echo_controller_enabled = false;
}
}
@@ -1865,7 +1941,7 @@
InternalAPMConfig apm_config;
- apm_config.aec_enabled = private_submodules_->echo_cancellation->is_enabled();
+ apm_config.aec_enabled = config_.echo_canceller.enabled;
apm_config.aec_delay_agnostic_enabled =
private_submodules_->echo_cancellation->is_delay_agnostic_enabled();
apm_config.aec_drift_compensation_enabled =
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index 2f946c5..9b66c26 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -21,7 +21,7 @@
#include "modules/audio_processing/include/audio_processing_statistics.h"
#include "modules/audio_processing/render_queue_item_verifier.h"
#include "modules/audio_processing/rms_level.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/function_view.h"
#include "rtc_base/gtest_prod_util.h"
#include "rtc_base/ignore_wundef.h"
@@ -181,6 +181,7 @@
bool pre_amplifier_enabled,
bool echo_controller_enabled,
bool voice_activity_detector_enabled,
+ bool private_voice_detector_enabled,
bool level_estimator_enabled,
bool transient_suppressor_enabled);
bool CaptureMultiBandSubModulesActive() const;
@@ -207,6 +208,7 @@
bool echo_controller_enabled_ = false;
bool level_estimator_enabled_ = false;
bool voice_activity_detector_enabled_ = false;
+ bool private_voice_detector_enabled_ = false;
bool transient_suppressor_enabled_ = false;
bool first_update_ = true;
};
diff --git a/modules/audio_processing/audio_processing_impl_locking_unittest.cc b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
index 9685ef9..828e2e7 100644
--- a/modules/audio_processing/audio_processing_impl_locking_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/test/test_utils.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/random.h"
@@ -527,21 +527,20 @@
void AudioProcessingImplLockTest::SetUp() {
test_config_ = static_cast<TestConfig>(GetParam());
- ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
ASSERT_EQ(apm_->kNoError,
apm_->gain_control()->set_mode(GainControl::kAdaptiveDigital));
ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
- ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
- ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
-
- AudioProcessing::Config apm_config;
+ AudioProcessing::Config apm_config = apm_->GetConfig();
apm_config.echo_canceller.enabled =
(test_config_.aec_type != AecType::AecTurnedOff);
apm_config.echo_canceller.mobile_mode =
(test_config_.aec_type == AecType::BasicWebRtcAecSettingsWithAecMobile);
+ apm_config.noise_suppression.enabled = true;
+ apm_config.voice_detection.enabled = true;
+ apm_config.level_estimation.enabled = true;
apm_->ApplyConfig(apm_config);
Config config;
@@ -584,12 +583,14 @@
EXPECT_FALSE(apm_config.echo_canceller.enabled);
}
EXPECT_TRUE(apm_->gain_control()->is_enabled());
- EXPECT_TRUE(apm_->noise_suppression()->is_enabled());
+ EXPECT_TRUE(apm_config.noise_suppression.enabled);
// The below return values are not testable.
apm_->noise_suppression()->speech_probability();
apm_->voice_detection()->is_enabled();
+ apm_->GetStatistics(/*has_remote_tracks=*/true);
+
return true;
}
@@ -1108,12 +1109,12 @@
}
// Instantiate tests from the extreme test configuration set.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
DISABLED_AudioProcessingImplLockExtensive,
AudioProcessingImplLockTest,
::testing::ValuesIn(TestConfig::GenerateExtensiveTestConfigs()));
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
AudioProcessingImplLockBrief,
AudioProcessingImplLockTest,
::testing::ValuesIn(TestConfig::GenerateBriefTestConfigs()));
diff --git a/modules/audio_processing/audio_processing_impl_unittest.cc b/modules/audio_processing/audio_processing_impl_unittest.cc
index 8926f02..69fc779 100644
--- a/modules/audio_processing/audio_processing_impl_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_unittest.cc
@@ -10,18 +10,24 @@
#include "modules/audio_processing/audio_processing_impl.h"
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "api/scoped_refptr.h"
#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/test/echo_control_mock.h"
#include "modules/audio_processing/test/test_utils.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/ref_counted_object.h"
#include "test/gmock.h"
#include "test/gtest.h"
-using ::testing::Invoke;
-
namespace webrtc {
namespace {
+using ::testing::Invoke;
+using ::testing::NotNull;
+
class MockInitialize : public AudioProcessingImpl {
public:
explicit MockInitialize(const webrtc::Config& config)
@@ -36,6 +42,28 @@
MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
};
+// Creates MockEchoControl instances and provides a raw pointer access to
+// the next created one. The raw pointer is meant to be used with gmock.
+// Returning a pointer of the next created MockEchoControl instance is necessary
+// for the following reasons: (i) gmock expectations must be set before any call
+// occurs, (ii) APM is initialized the first time that
+// AudioProcessingImpl::ProcessStream() is called and the initialization leads
+// to the creation of a new EchoControl object.
+class MockEchoControlFactory : public EchoControlFactory {
+ public:
+ MockEchoControlFactory() : next_mock_(absl::make_unique<MockEchoControl>()) {}
+ // Returns a pointer to the next MockEchoControl that this factory creates.
+ MockEchoControl* GetNext() const { return next_mock_.get(); }
+ std::unique_ptr<EchoControl> Create(int sample_rate_hz) override {
+ std::unique_ptr<EchoControl> mock = std::move(next_mock_);
+ next_mock_ = absl::make_unique<MockEchoControl>();
+ return mock;
+ }
+
+ private:
+ std::unique_ptr<MockEchoControl> next_mock_;
+};
+
void InitializeAudioFrame(size_t input_rate,
size_t num_channels,
AudioFrame* frame) {
@@ -105,7 +133,7 @@
std::transform(channel_view.begin(), channel_view.end(),
channel_view.begin(), ProcessSample);
}
- };
+ }
std::string ToString() const override { return "TestRenderPreProcessor"; }
void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
// Modifies a sample. This member is used in Process() to modify a frame and
@@ -183,6 +211,87 @@
<< "Frame should be amplified.";
}
+TEST(AudioProcessingImplTest,
+ EchoControllerObservesPreAmplifierEchoPathGainChange) {
+ // Tests that the echo controller observes an echo path gain change when the
+ // pre-amplifier submodule changes the gain.
+ auto echo_control_factory = absl::make_unique<MockEchoControlFactory>();
+ const auto* echo_control_factory_ptr = echo_control_factory.get();
+
+ std::unique_ptr<AudioProcessing> apm(
+ AudioProcessingBuilder()
+ .SetEchoControlFactory(std::move(echo_control_factory))
+ .Create());
+ apm->gain_control()->Enable(false); // Disable AGC.
+ apm->gain_control()->set_mode(GainControl::Mode::kFixedDigital);
+ webrtc::AudioProcessing::Config apm_config;
+ apm_config.gain_controller2.enabled = false;
+ apm_config.pre_amplifier.enabled = true;
+ apm_config.pre_amplifier.fixed_gain_factor = 1.f;
+ apm->ApplyConfig(apm_config);
+
+ AudioFrame frame;
+ constexpr int16_t kAudioLevel = 10000;
+ constexpr size_t kSampleRateHz = 48000;
+ constexpr size_t kNumChannels = 2;
+ InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
+ FillFixedFrame(kAudioLevel, &frame);
+
+ MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
+
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
+ EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), false)).Times(1);
+ apm->ProcessStream(&frame);
+
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
+ EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), true)).Times(1);
+ apm->SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
+ apm->ProcessStream(&frame);
+}
+
+TEST(AudioProcessingImplTest,
+ EchoControllerObservesAnalogAgc1EchoPathGainChange) {
+ // Tests that the echo controller observes an echo path gain change when the
+ // AGC1 analog adaptive submodule changes the analog gain.
+ auto echo_control_factory = absl::make_unique<MockEchoControlFactory>();
+ const auto* echo_control_factory_ptr = echo_control_factory.get();
+
+ std::unique_ptr<AudioProcessing> apm(
+ AudioProcessingBuilder()
+ .SetEchoControlFactory(std::move(echo_control_factory))
+ .Create());
+ apm->gain_control()->Enable(true); // Enable AGC.
+ apm->gain_control()->set_mode(GainControl::Mode::kAdaptiveAnalog);
+ webrtc::AudioProcessing::Config apm_config;
+ apm_config.gain_controller2.enabled = false;
+ apm_config.pre_amplifier.enabled = false;
+ apm->ApplyConfig(apm_config);
+
+ AudioFrame frame;
+ constexpr int16_t kAudioLevel = 1000;
+ constexpr size_t kSampleRateHz = 48000;
+ constexpr size_t kNumChannels = 2;
+ InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
+ FillFixedFrame(kAudioLevel, &frame);
+
+ MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
+
+ const int initial_analog_gain = apm->gain_control()->stream_analog_level();
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
+ EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), false)).Times(1);
+ apm->ProcessStream(&frame);
+
+ // Force an analog gain change if it did not happen.
+ if (initial_analog_gain == apm->gain_control()->stream_analog_level()) {
+ apm->gain_control()->set_stream_analog_level(initial_analog_gain + 1);
+ }
+
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
+ EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), true)).Times(1);
+ apm->ProcessStream(&frame);
+}
+
TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
// Make sure that signal changes caused by a render pre-processing sub-module
// take place before any echo detector analysis.
diff --git a/modules/audio_processing/audio_processing_performance_unittest.cc b/modules/audio_processing/audio_processing_performance_unittest.cc
index 84cb574..70c91c4 100644
--- a/modules/audio_processing/audio_processing_performance_unittest.cc
+++ b/modules/audio_processing/audio_processing_performance_unittest.cc
@@ -17,7 +17,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/test/test_utils.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/event.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
@@ -450,10 +450,10 @@
apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
- ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
AudioProcessing::Config apm_config = apm->GetConfig();
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = false;
+ apm_config.voice_detection.enabled = true;
apm->ApplyConfig(apm_config);
};
@@ -465,10 +465,10 @@
apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
- ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
AudioProcessing::Config apm_config = apm->GetConfig();
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = true;
+ apm_config.voice_detection.enabled = true;
apm->ApplyConfig(apm_config);
};
@@ -481,9 +481,9 @@
apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(false));
- ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(false));
AudioProcessing::Config apm_config = apm->GetConfig();
apm_config.echo_canceller.enabled = false;
+ apm_config.voice_detection.enabled = false;
apm->ApplyConfig(apm_config);
};
@@ -621,7 +621,7 @@
EXPECT_TRUE(Run());
}
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
AudioProcessingPerformanceTest,
CallSimulator,
::testing::ValuesIn(SimulationConfig::GenerateSimulationConfigs()));
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 6809ab9..59feb9b 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -28,21 +28,20 @@
#include "modules/audio_processing/test/test_utils.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/gtest_prod_util.h"
#include "rtc_base/ignore_wundef.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/numerics/safe_minmax.h"
#include "rtc_base/protobuf_utils.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/swap_queue.h"
#include "rtc_base/system/arch.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread.h"
-#include "system_wrappers/include/event_wrapper.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
RTC_PUSH_IGNORING_WUNDEF()
#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
@@ -183,10 +182,11 @@
apm_config.echo_canceller.enabled = true;
#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
apm_config.echo_canceller.mobile_mode = true;
-
EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveDigital));
EXPECT_NOERR(ap->gain_control()->Enable(true));
#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
+ // TODO(peah): Update tests to instead use AEC3.
+ apm_config.echo_canceller.use_legacy_aec = true;
apm_config.echo_canceller.mobile_mode = false;
apm_config.echo_canceller.legacy_moderate_suppression_level = true;
@@ -196,6 +196,7 @@
#endif
apm_config.high_pass_filter.enabled = true;
+ apm_config.level_estimation.enabled = true;
ap->ApplyConfig(apm_config);
EXPECT_NOERR(ap->level_estimator()->Enable(true));
@@ -720,28 +721,24 @@
// -- Missing delay --
EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
- EXPECT_EQ(apm_->kStreamParameterNotSetError,
- ProcessStreamChooser(format));
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
// Resets after successful ProcessStream().
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
- EXPECT_EQ(apm_->kStreamParameterNotSetError,
- ProcessStreamChooser(format));
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
// Other stream parameters set correctly.
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(127));
- EXPECT_EQ(apm_->kStreamParameterNotSetError,
- ProcessStreamChooser(format));
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
// -- No stream parameters --
EXPECT_EQ(apm_->kNoError,
AnalyzeReverseStreamChooser(format));
- EXPECT_EQ(apm_->kStreamParameterNotSetError,
- ProcessStreamChooser(format));
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
// -- All there --
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
@@ -873,6 +870,8 @@
// Enable AEC only.
AudioProcessing::Config apm_config = apm_->GetConfig();
apm_config.echo_canceller.enabled = true;
+ // TODO(peah): Update tests to instead use AEC3.
+ apm_config.echo_canceller.use_legacy_aec = true;
apm_config.echo_canceller.mobile_mode = false;
apm_->ApplyConfig(apm_config);
Config config;
@@ -1277,6 +1276,8 @@
AudioProcessing::Config config = apm_->GetConfig();
EXPECT_FALSE(config.echo_canceller.enabled);
EXPECT_FALSE(config.high_pass_filter.enabled);
+ EXPECT_FALSE(config.level_estimation.enabled);
+ EXPECT_FALSE(config.voice_detection.enabled);
EXPECT_FALSE(apm_->gain_control()->is_enabled());
EXPECT_FALSE(apm_->level_estimator()->is_enabled());
EXPECT_FALSE(apm_->noise_suppression()->is_enabled());
@@ -1398,21 +1399,38 @@
EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
- // 4. Both VAD and the level estimator are enabled...
+ // 4. Only GetStatistics-reporting VAD is enabled...
+ SetFrameTo(frame_, 1000);
+ frame_copy.CopyFrom(*frame_);
+ auto apm_config = apm_->GetConfig();
+ apm_config.voice_detection.enabled = true;
+ apm_->ApplyConfig(apm_config);
+ EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
+ EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
+ EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
+ apm_config.voice_detection.enabled = false;
+ apm_->ApplyConfig(apm_config);
+
+ // 5. Both VADs and the level estimator are enabled...
SetFrameTo(frame_, 1000);
frame_copy.CopyFrom(*frame_);
EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
+ apm_config.voice_detection.enabled = true;
+ apm_->ApplyConfig(apm_config);
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(false));
EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false));
+ apm_config.voice_detection.enabled = false;
+ apm_->ApplyConfig(apm_config);
// Check the test is valid. We should have distortion from the filter
// when AEC is enabled (which won't affect the audio).
- AudioProcessing::Config apm_config = apm_->GetConfig();
apm_config.echo_canceller.enabled = true;
+ // TODO(peah): Update tests to instead use AEC3.
+ apm_config.echo_canceller.use_legacy_aec = true;
apm_config.echo_canceller.mobile_mode = false;
apm_->ApplyConfig(apm_config);
frame_->samples_per_channel_ = 320;
@@ -1836,6 +1854,7 @@
int analog_level_average = 0;
int max_output_average = 0;
float ns_speech_prob_average = 0.0f;
+ float rms_dbfs_average = 0.0f;
#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
int stats_index = 0;
#endif
@@ -1870,6 +1889,9 @@
}
ns_speech_prob_average += apm_->noise_suppression()->speech_probability();
+ AudioProcessingStats stats =
+ apm_->GetStatistics(/*has_remote_tracks=*/false);
+ rms_dbfs_average += *stats.output_rms_dbfs;
size_t frame_size = frame_->samples_per_channel_ * frame_->num_channels_;
size_t write_count = fwrite(frame_->data(),
@@ -1905,11 +1927,6 @@
const int32_t delay_standard_deviation_ms =
stats.delay_standard_deviation_ms.value_or(-1.0);
- // Get RMS.
- int rms_level = apm_->level_estimator()->RMS();
- EXPECT_LE(0, rms_level);
- EXPECT_GE(127, rms_level);
-
if (!write_ref_data) {
const audioproc::Test::EchoMetrics& reference =
test->echo_metrics(stats_index);
@@ -1930,8 +1947,6 @@
EXPECT_EQ(reference_delay.median(), delay_median_ms);
EXPECT_EQ(reference_delay.std(), delay_standard_deviation_ms);
- EXPECT_EQ(test->rms_level(stats_index), rms_level);
-
++stats_index;
} else {
audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
@@ -1947,8 +1962,6 @@
test->add_delay_metrics();
message_delay->set_median(delay_median_ms);
message_delay->set_std(delay_standard_deviation_ms);
-
- test->add_rms_level(rms_level);
}
}
#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
@@ -1956,6 +1969,7 @@
max_output_average /= frame_count;
analog_level_average /= frame_count;
ns_speech_prob_average /= frame_count;
+ rms_dbfs_average /= frame_count;
if (!write_ref_data) {
const int kIntNear = 1;
@@ -1990,6 +2004,7 @@
EXPECT_NEAR(test->ns_speech_probability_average(),
ns_speech_prob_average,
kFloatNear);
+ EXPECT_NEAR(test->rms_dbfs_average(), rms_dbfs_average, kFloatNear);
#endif
} else {
test->set_has_voice_count(has_voice_count);
@@ -2002,6 +2017,7 @@
EXPECT_LE(0.0f, ns_speech_prob_average);
EXPECT_GE(1.0f, ns_speech_prob_average);
test->set_ns_speech_probability_average(ns_speech_prob_average);
+ test->set_rms_dbfs_average(rms_dbfs_average);
#endif
}
@@ -2398,7 +2414,7 @@
}
#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
CommonFormats,
AudioProcessingTest,
testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
@@ -2428,11 +2444,11 @@
std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
std::make_tuple(32000, 48000, 48000, 48000, 30, 0),
- std::make_tuple(32000, 48000, 32000, 48000, 35, 30),
+ std::make_tuple(32000, 48000, 32000, 48000, 32, 30),
std::make_tuple(32000, 48000, 16000, 48000, 30, 20),
- std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
- std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
- std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
+ std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
+ std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
+ std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
std::make_tuple(32000, 32000, 16000, 32000, 40, 20),
@@ -2440,21 +2456,21 @@
std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
- std::make_tuple(16000, 48000, 48000, 48000, 25, 0),
- std::make_tuple(16000, 48000, 32000, 48000, 25, 30),
- std::make_tuple(16000, 48000, 16000, 48000, 25, 20),
+ std::make_tuple(16000, 48000, 48000, 48000, 24, 0),
+ std::make_tuple(16000, 48000, 32000, 48000, 24, 30),
+ std::make_tuple(16000, 48000, 16000, 48000, 24, 20),
std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
- std::make_tuple(16000, 16000, 48000, 16000, 40, 20),
+ std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
std::make_tuple(16000, 16000, 32000, 16000, 40, 20),
std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
CommonFormats,
AudioProcessingTest,
testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 20, 0),
@@ -2669,12 +2685,14 @@
}
// Disable all components except for an AEC and the residual echo detector.
+ // TODO(peah): Update this to also work on AEC3.
AudioProcessing::Config apm_config;
apm_config.residual_echo_detector.enabled = true;
apm_config.high_pass_filter.enabled = false;
apm_config.gain_controller2.enabled = false;
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = !use_AEC2;
+ apm_config.echo_canceller.use_legacy_aec = use_AEC2;
apm->ApplyConfig(apm_config);
EXPECT_EQ(apm->gain_control()->Enable(false), 0);
EXPECT_EQ(apm->level_estimator()->Enable(false), 0);
@@ -2693,11 +2711,16 @@
// Set up APM with AEC2 and process some audio.
std::unique_ptr<AudioProcessing> apm = CreateApm(true);
ASSERT_TRUE(apm);
+ AudioProcessing::Config apm_config;
+ apm_config.echo_canceller.enabled = true;
+ // TODO(peah): Update tests to instead use AEC3.
+ apm_config.echo_canceller.use_legacy_aec = true;
+ apm->ApplyConfig(apm_config);
// Set up an audioframe.
AudioFrame frame;
frame.num_channels_ = 1;
- SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate48kHz);
+ SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
// Fill the audio frame with a sawtooth pattern.
int16_t* ptr = frame.mutable_data();
@@ -2756,7 +2779,7 @@
// Set up an audioframe.
AudioFrame frame;
frame.num_channels_ = 1;
- SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate48kHz);
+ SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
// Fill the audio frame with a sawtooth pattern.
int16_t* ptr = frame.mutable_data();
@@ -2810,7 +2833,7 @@
// Set up an audioframe.
AudioFrame frame;
frame.num_channels_ = 1;
- SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate48kHz);
+ SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
// Fill the audio frame with a sawtooth pattern.
int16_t* ptr = frame.mutable_data();
@@ -2839,4 +2862,41 @@
EXPECT_EQ(apm->ProcessStream(&frame), 0);
EXPECT_FALSE(apm->GetStatistics(false).output_rms_dbfs);
}
+
+TEST(ApmStatistics, ReportHasVoice) {
+ ProcessingConfig processing_config = {
+ {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
+ AudioProcessing::Config config;
+
+ // Set up an audioframe.
+ AudioFrame frame;
+ frame.num_channels_ = 1;
+ SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
+
+ // Fill the audio frame with a sawtooth pattern.
+ int16_t* ptr = frame.mutable_data();
+ for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
+ ptr[i] = 10000 * ((i % 3) - 1);
+ }
+
+ std::unique_ptr<AudioProcessing> apm(AudioProcessingBuilder().Create());
+ apm->Initialize(processing_config);
+
+ // If not enabled, no metric should be reported.
+ EXPECT_EQ(apm->ProcessStream(&frame), 0);
+ EXPECT_FALSE(apm->GetStatistics(false).voice_detected);
+
+ // If enabled, metrics should be reported.
+ config.voice_detection.enabled = true;
+ apm->ApplyConfig(config);
+ EXPECT_EQ(apm->ProcessStream(&frame), 0);
+ auto stats = apm->GetStatistics(false);
+ EXPECT_TRUE(stats.voice_detected);
+
+ // If re-disabled, the value is again not reported.
+ config.voice_detection.enabled = false;
+ apm->ApplyConfig(config);
+ EXPECT_EQ(apm->ProcessStream(&frame), 0);
+ EXPECT_FALSE(apm->GetStatistics(false).voice_detected);
+}
} // namespace webrtc
diff --git a/modules/audio_processing/echo_cancellation_impl.cc b/modules/audio_processing/echo_cancellation_impl.cc
index 73fe51b..96b9789 100644
--- a/modules/audio_processing/echo_cancellation_impl.cc
+++ b/modules/audio_processing/echo_cancellation_impl.cc
@@ -322,7 +322,12 @@
}
std::string EchoCancellationImpl::GetExperimentsDescription() {
- return refined_adaptive_filter_enabled_ ? "RefinedAdaptiveFilter;" : "";
+ if (enabled_) {
+ return refined_adaptive_filter_enabled_
+ ? "Legacy AEC;RefinedAdaptiveFilter;"
+ : "Legacy AEC;";
+ }
+ return "";
}
bool EchoCancellationImpl::is_refined_adaptive_filter_enabled() const {
diff --git a/modules/audio_processing/echo_cancellation_impl.h b/modules/audio_processing/echo_cancellation_impl.h
index a8b43a8..79be73b 100644
--- a/modules/audio_processing/echo_cancellation_impl.h
+++ b/modules/audio_processing/echo_cancellation_impl.h
@@ -18,8 +18,8 @@
#include "api/array_view.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/modules/audio_processing/echo_cancellation_impl_unittest.cc b/modules/audio_processing/echo_cancellation_impl_unittest.cc
index 9d81c1d..841ea0d 100644
--- a/modules/audio_processing/echo_cancellation_impl_unittest.cc
+++ b/modules/audio_processing/echo_cancellation_impl_unittest.cc
@@ -13,7 +13,7 @@
#include "modules/audio_processing/aec/aec_core.h"
#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/modules/audio_processing/echo_control_mobile_impl.cc b/modules/audio_processing/echo_control_mobile_impl.cc
index b9fbf42..3655eb1 100644
--- a/modules/audio_processing/echo_control_mobile_impl.cc
+++ b/modules/audio_processing/echo_control_mobile_impl.cc
@@ -17,7 +17,7 @@
#include "modules/audio_processing/audio_buffer.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/echo_control_mobile_unittest.cc b/modules/audio_processing/echo_control_mobile_unittest.cc
index f0e6048..6b054d1 100644
--- a/modules/audio_processing/echo_control_mobile_unittest.cc
+++ b/modules/audio_processing/echo_control_mobile_unittest.cc
@@ -13,7 +13,7 @@
#include "modules/audio_processing/echo_control_mobile_impl.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/modules/audio_processing/gain_control_for_experimental_agc.cc b/modules/audio_processing/gain_control_for_experimental_agc.cc
index 1479d58..5cb22f8 100644
--- a/modules/audio_processing/gain_control_for_experimental_agc.cc
+++ b/modules/audio_processing/gain_control_for_experimental_agc.cc
@@ -12,8 +12,8 @@
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
diff --git a/modules/audio_processing/gain_control_for_experimental_agc.h b/modules/audio_processing/gain_control_for_experimental_agc.h
index b20fbc9..8f5681f 100644
--- a/modules/audio_processing/gain_control_for_experimental_agc.h
+++ b/modules/audio_processing/gain_control_for_experimental_agc.h
@@ -13,8 +13,8 @@
#include "modules/audio_processing/agc/agc_manager_direct.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_checker.h"
namespace webrtc {
diff --git a/modules/audio_processing/gain_control_impl.cc b/modules/audio_processing/gain_control_impl.cc
index d5118ba..cd21e4c 100644
--- a/modules/audio_processing/gain_control_impl.cc
+++ b/modules/audio_processing/gain_control_impl.cc
@@ -18,7 +18,7 @@
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -89,10 +89,8 @@
int GainControlImpl::instance_counter_ = 0;
-GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_render,
- rtc::CriticalSection* crit_capture)
- : crit_render_(crit_render),
- crit_capture_(crit_capture),
+GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_capture)
+ : crit_capture_(crit_capture),
data_dumper_(new ApmDataDumper(instance_counter_)),
mode_(kAdaptiveAnalog),
minimum_capture_level_(0),
@@ -103,7 +101,6 @@
analog_capture_level_(0),
was_analog_level_set_(false),
stream_is_saturated_(false) {
- RTC_DCHECK(crit_render);
RTC_DCHECK(crit_capture);
}
@@ -267,7 +264,6 @@
}
int GainControlImpl::Enable(bool enable) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
if (enable && !enabled_) {
enabled_ = enable; // Must be set before Initialize() is called.
@@ -287,7 +283,6 @@
}
int GainControlImpl::set_mode(Mode mode) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
if (MapSetting(mode) == -1) {
return AudioProcessing::kBadParameterError;
@@ -354,10 +349,8 @@
if (level > 31 || level < 0) {
return AudioProcessing::kBadParameterError;
}
- {
- rtc::CritScope cs(crit_capture_);
- target_level_dbfs_ = level;
- }
+ rtc::CritScope cs(crit_capture_);
+ target_level_dbfs_ = level;
return Configure();
}
@@ -370,18 +363,14 @@
if (gain < 0 || gain > 90) {
return AudioProcessing::kBadParameterError;
}
- {
- rtc::CritScope cs(crit_capture_);
- compression_gain_db_ = gain;
- }
+ rtc::CritScope cs(crit_capture_);
+ compression_gain_db_ = gain;
return Configure();
}
int GainControlImpl::enable_limiter(bool enable) {
- {
- rtc::CritScope cs(crit_capture_);
- limiter_enabled_ = enable;
- }
+ rtc::CritScope cs(crit_capture_);
+ limiter_enabled_ = enable;
return Configure();
}
@@ -391,7 +380,6 @@
}
void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
data_dumper_->InitiateNewSetOfRecordings();
@@ -415,8 +403,6 @@
}
int GainControlImpl::Configure() {
- rtc::CritScope cs_render(crit_render_);
- rtc::CritScope cs_capture(crit_capture_);
WebRtcAgcConfig config;
// TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
// change the interface.
diff --git a/modules/audio_processing/gain_control_impl.h b/modules/audio_processing/gain_control_impl.h
index c21d911..9dfe0f1 100644
--- a/modules/audio_processing/gain_control_impl.h
+++ b/modules/audio_processing/gain_control_impl.h
@@ -19,8 +19,8 @@
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "modules/audio_processing/include/gain_control.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@@ -30,8 +30,7 @@
class GainControlImpl : public GainControl {
public:
- GainControlImpl(rtc::CriticalSection* crit_render,
- rtc::CriticalSection* crit_capture);
+ explicit GainControlImpl(rtc::CriticalSection* crit_capture);
~GainControlImpl() override;
void ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio);
@@ -67,9 +66,8 @@
int analog_level_maximum() const override;
bool stream_is_saturated() const override;
- int Configure();
+ int Configure() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
- rtc::CriticalSection* const crit_render_ RTC_ACQUIRED_BEFORE(crit_capture_);
rtc::CriticalSection* const crit_capture_;
std::unique_ptr<ApmDataDumper> data_dumper_;
diff --git a/modules/audio_processing/gain_control_unittest.cc b/modules/audio_processing/gain_control_unittest.cc
index 62908c7..891e78a 100644
--- a/modules/audio_processing/gain_control_unittest.cc
+++ b/modules/audio_processing/gain_control_unittest.cc
@@ -72,9 +72,8 @@
int analog_level_max,
int achieved_stream_analog_level_reference,
rtc::ArrayView<const float> output_reference) {
- rtc::CriticalSection crit_render;
rtc::CriticalSection crit_capture;
- GainControlImpl gain_controller(&crit_render, &crit_capture);
+ GainControlImpl gain_controller(&crit_capture);
SetupComponent(sample_rate_hz, mode, target_level_dbfs, stream_analog_level,
compression_gain_db, enable_limiter, analog_level_min,
analog_level_max, &gain_controller);
diff --git a/modules/audio_processing/gain_controller2.cc b/modules/audio_processing/gain_controller2.cc
index 2a32744..a1bbb1b 100644
--- a/modules/audio_processing/gain_controller2.cc
+++ b/modules/audio_processing/gain_controller2.cc
@@ -14,7 +14,7 @@
#include "modules/audio_processing/audio_buffer.h"
#include "modules/audio_processing/include/audio_frame_view.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
diff --git a/modules/audio_processing/gain_controller2.h b/modules/audio_processing/gain_controller2.h
index 3a11810..7ed310e 100644
--- a/modules/audio_processing/gain_controller2.h
+++ b/modules/audio_processing/gain_controller2.h
@@ -18,7 +18,7 @@
#include "modules/audio_processing/agc2/gain_applier.h"
#include "modules/audio_processing/agc2/limiter.h"
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/gain_controller2_unittest.cc b/modules/audio_processing/gain_controller2_unittest.cc
index 27d540a..258832a 100644
--- a/modules/audio_processing/gain_controller2_unittest.cc
+++ b/modules/audio_processing/gain_controller2_unittest.cc
@@ -227,7 +227,7 @@
}
static_assert(test::kLimiterMaxInputLevelDbFs < 10, "");
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
GainController2,
FixedDigitalTest,
::testing::Values(
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index df51313..6a0917a 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -25,6 +25,7 @@
#include "absl/types/optional.h"
#include "api/audio/echo_canceller3_config.h"
#include "api/audio/echo_control.h"
+#include "api/scoped_refptr.h"
#include "modules/audio_processing/include/audio_generator.h"
#include "modules/audio_processing/include/audio_processing_statistics.h"
#include "modules/audio_processing/include/config.h"
@@ -32,8 +33,7 @@
#include "rtc_base/arraysize.h"
#include "rtc_base/deprecation.h"
#include "rtc_base/platform_file.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/ref_count.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@@ -240,22 +240,6 @@
// by changing the default values in the AudioProcessing::Config struct.
// The config is applied by passing the struct to the ApplyConfig method.
struct Config {
- struct EchoCanceller {
- bool enabled = false;
- bool mobile_mode = false;
- // Recommended not to use. Will be removed in the future.
- // APM components are not fine-tuned for legacy suppression levels.
- bool legacy_moderate_suppression_level = false;
- } echo_canceller;
-
- struct ResidualEchoDetector {
- bool enabled = true;
- } residual_echo_detector;
-
- struct HighPassFilter {
- bool enabled = false;
- } high_pass_filter;
-
// Enabled the pre-amplifier. It amplifies the capture signal
// before any other processing is done.
struct PreAmplifier {
@@ -263,6 +247,32 @@
float fixed_gain_factor = 1.f;
} pre_amplifier;
+ struct HighPassFilter {
+ bool enabled = false;
+ } high_pass_filter;
+
+ struct EchoCanceller {
+ bool enabled = false;
+ bool mobile_mode = false;
+ // Recommended not to use. Will be removed in the future.
+ // APM components are not fine-tuned for legacy suppression levels.
+ bool legacy_moderate_suppression_level = false;
+ // Recommended not to use. Will be removed in the future.
+ bool use_legacy_aec = false;
+ } echo_canceller;
+
+ // Enables background noise suppression.
+ struct NoiseSuppression {
+ bool enabled = false;
+ enum Level { kLow, kModerate, kHigh, kVeryHigh };
+ Level level = kModerate;
+ } noise_suppression;
+
+ // Enables reporting of |has_voice| in webrtc::AudioProcessingStats.
+ struct VoiceDetection {
+ bool enabled = false;
+ } voice_detection;
+
// Enables the next generation AGC functionality. This feature replaces the
// standard methods of gain control in the previous AGC. Enabling this
// submodule enables an adaptive digital AGC followed by a limiter. By
@@ -283,6 +293,10 @@
} adaptive_digital;
} gain_controller2;
+ struct ResidualEchoDetector {
+ bool enabled = true;
+ } residual_echo_detector;
+
// Enables reporting of |output_rms_dbfs| in webrtc::AudioProcessingStats.
struct LevelEstimation {
bool enabled = false;
diff --git a/modules/audio_processing/include/audio_processing_statistics.h b/modules/audio_processing/include/audio_processing_statistics.h
index 683db05..87babee 100644
--- a/modules/audio_processing/include/audio_processing_statistics.h
+++ b/modules/audio_processing/include/audio_processing_statistics.h
@@ -32,6 +32,12 @@
// Only reported if level estimation is enabled in AudioProcessing::Config.
absl::optional<int> output_rms_dbfs;
+ // True if voice is detected in the last capture frame, after processing.
+ // It is conservative in flagging audio as speech, with low likelihood of
+ // incorrectly flagging a frame as voice.
+ // Only reported if voice detection is enabled in AudioProcessing::Config.
+ absl::optional<bool> voice_detected;
+
// AEC Statistics.
// ERL = 10log_10(P_far / P_echo)
absl::optional<double> echo_return_loss;
diff --git a/modules/audio_processing/include/config.h b/modules/audio_processing/include/config.h
index e77d3fd..930cf7e 100644
--- a/modules/audio_processing/include/config.h
+++ b/modules/audio_processing/include/config.h
@@ -13,7 +13,7 @@
#include <map>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
diff --git a/modules/audio_processing/level_estimator_impl.h b/modules/audio_processing/level_estimator_impl.h
index 901ae4c..da217bb 100644
--- a/modules/audio_processing/level_estimator_impl.h
+++ b/modules/audio_processing/level_estimator_impl.h
@@ -14,8 +14,8 @@
#include <memory>
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
diff --git a/modules/audio_processing/logging/apm_data_dumper.cc b/modules/audio_processing/logging/apm_data_dumper.cc
index cc879c8..6d84750 100644
--- a/modules/audio_processing/logging/apm_data_dumper.cc
+++ b/modules/audio_processing/logging/apm_data_dumper.cc
@@ -54,7 +54,7 @@
ApmDataDumper::ApmDataDumper(int instance_index)
: instance_index_(instance_index) {}
#else
-ApmDataDumper::ApmDataDumper(int instance_index){};
+ApmDataDumper::ApmDataDumper(int instance_index) {}
#endif
ApmDataDumper::~ApmDataDumper() = default;
diff --git a/modules/audio_processing/logging/apm_data_dumper.h b/modules/audio_processing/logging/apm_data_dumper.h
index b541ae8..92adf86 100644
--- a/modules/audio_processing/logging/apm_data_dumper.h
+++ b/modules/audio_processing/logging/apm_data_dumper.h
@@ -17,6 +17,7 @@
#include <string>
#if WEBRTC_APM_DEBUG_DUMP == 1
+#include <memory>
#include <unordered_map>
#endif
@@ -25,7 +26,7 @@
#include "common_audio/wav_file.h"
#include "rtc_base/checks.h"
#endif
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
// Check to verify that the define is properly set.
#if !defined(WEBRTC_APM_DEBUG_DUMP) || \
diff --git a/modules/audio_processing/low_cut_filter.cc b/modules/audio_processing/low_cut_filter.cc
index 581d6bc..12a6e73 100644
--- a/modules/audio_processing/low_cut_filter.cc
+++ b/modules/audio_processing/low_cut_filter.cc
@@ -79,7 +79,7 @@
}
private:
- const int16_t* const ba_ = nullptr;
+ const int16_t* const ba_;
int16_t x_[2];
int16_t y_[4];
};
diff --git a/modules/audio_processing/low_cut_filter.h b/modules/audio_processing/low_cut_filter.h
index fd4c6f1..86fbddd 100644
--- a/modules/audio_processing/low_cut_filter.h
+++ b/modules/audio_processing/low_cut_filter.h
@@ -14,7 +14,7 @@
#include <memory>
#include <vector>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/module.mk b/modules/audio_processing/module.mk
index ee33c73..c12c290 100644
--- a/modules/audio_processing/module.mk
+++ b/modules/audio_processing/module.mk
@@ -27,6 +27,7 @@
modules/audio_processing/level_estimator_impl.o \
modules/audio_processing/low_cut_filter.o \
modules/audio_processing/noise_suppression_impl.o \
+ modules/audio_processing/noise_suppression_proxy.o \
modules/audio_processing/residual_echo_detector.o \
modules/audio_processing/rms_level.o \
modules/audio_processing/splitting_filter.o \
@@ -94,7 +95,6 @@
modules/audio_processing/aec3/block_delay_buffer.o \
modules/audio_processing/aec3/block_framer.o \
modules/audio_processing/aec3/block_processor.o \
- modules/audio_processing/aec3/block_processor2.o \
modules/audio_processing/aec3/block_processor_metrics.o \
modules/audio_processing/aec3/cascaded_biquad_filter.o \
modules/audio_processing/aec3/clockdrift_detector.o \
@@ -120,9 +120,7 @@
modules/audio_processing/aec3/moving_average.o \
modules/audio_processing/aec3/render_buffer.o \
modules/audio_processing/aec3/render_delay_buffer.o \
- modules/audio_processing/aec3/render_delay_buffer2.o \
modules/audio_processing/aec3/render_delay_controller.o \
- modules/audio_processing/aec3/render_delay_controller2.o \
modules/audio_processing/aec3/render_delay_controller_metrics.o \
modules/audio_processing/aec3/render_reverb_model.o \
modules/audio_processing/aec3/render_signal_analyzer.o \
@@ -142,7 +140,6 @@
modules/audio_processing/aec3/subtractor_output_analyzer.o \
modules/audio_processing/aec3/suppression_filter.o \
modules/audio_processing/aec3/suppression_gain.o \
- modules/audio_processing/aec3/suppression_gain_limiter.o \
modules/audio_processing/aec3/vector_buffer.o
aec3_factory_CXX_OBJECTS = \
diff --git a/modules/audio_processing/noise_suppression_impl.cc b/modules/audio_processing/noise_suppression_impl.cc
index d8d9e32..bfaddd9 100644
--- a/modules/audio_processing/noise_suppression_impl.cc
+++ b/modules/audio_processing/noise_suppression_impl.cc
@@ -12,7 +12,7 @@
#include "modules/audio_processing/audio_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#if defined(WEBRTC_NS_FLOAT)
#include "modules/audio_processing/ns/noise_suppression.h"
diff --git a/modules/audio_processing/noise_suppression_impl.h b/modules/audio_processing/noise_suppression_impl.h
index fba716e..414ca31 100644
--- a/modules/audio_processing/noise_suppression_impl.h
+++ b/modules/audio_processing/noise_suppression_impl.h
@@ -15,8 +15,8 @@
#include <vector>
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
diff --git a/modules/audio_processing/noise_suppression_proxy.cc b/modules/audio_processing/noise_suppression_proxy.cc
new file mode 100644
index 0000000..a83c9b2
--- /dev/null
+++ b/modules/audio_processing/noise_suppression_proxy.cc
@@ -0,0 +1,71 @@
+/*
+ * 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/audio_processing/noise_suppression_proxy.h"
+
+namespace webrtc {
+NoiseSuppressionProxy::NoiseSuppressionProxy(AudioProcessing* apm,
+ NoiseSuppression* ns)
+ : apm_(apm), ns_(ns) {}
+
+NoiseSuppressionProxy::~NoiseSuppressionProxy() {}
+
+int NoiseSuppressionProxy::Enable(bool enable) {
+ AudioProcessing::Config config = apm_->GetConfig();
+ if (config.noise_suppression.enabled != enable) {
+ config.noise_suppression.enabled = enable;
+ apm_->ApplyConfig(config);
+ }
+ return AudioProcessing::kNoError;
+}
+
+bool NoiseSuppressionProxy::is_enabled() const {
+ return ns_->is_enabled();
+}
+
+int NoiseSuppressionProxy::set_level(Level level) {
+ AudioProcessing::Config config = apm_->GetConfig();
+ using NsConfig = AudioProcessing::Config::NoiseSuppression;
+ NsConfig::Level new_level;
+ switch (level) {
+ case NoiseSuppression::kLow:
+ new_level = NsConfig::kLow;
+ break;
+ case NoiseSuppression::kModerate:
+ new_level = NsConfig::kModerate;
+ break;
+ case NoiseSuppression::kHigh:
+ new_level = NsConfig::kHigh;
+ break;
+ case NoiseSuppression::kVeryHigh:
+ new_level = NsConfig::kVeryHigh;
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+ if (config.noise_suppression.level != new_level) {
+ config.noise_suppression.level = new_level;
+ apm_->ApplyConfig(config);
+ }
+ return AudioProcessing::kNoError;
+}
+
+NoiseSuppression::Level NoiseSuppressionProxy::level() const {
+ return ns_->level();
+}
+
+float NoiseSuppressionProxy::speech_probability() const {
+ return ns_->speech_probability();
+}
+
+std::vector<float> NoiseSuppressionProxy::NoiseEstimate() {
+ return ns_->NoiseEstimate();
+}
+} // namespace webrtc
diff --git a/modules/audio_processing/noise_suppression_proxy.h b/modules/audio_processing/noise_suppression_proxy.h
new file mode 100644
index 0000000..959887f
--- /dev/null
+++ b/modules/audio_processing/noise_suppression_proxy.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_PROXY_H_
+#define MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_PROXY_H_
+
+#include <vector>
+
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+// This class ensures interoperability with the pointer-to-submodule interface
+// AudioProcessing::noise_suppression() and AudioProcessing::ApplyConfig:
+// Enable(..) and set_level(..) calls are applied via
+// AudioProcessing::ApplyConfig, while all other function calls are forwarded
+// directly to a wrapped NoiseSuppression instance.
+class NoiseSuppressionProxy : public NoiseSuppression {
+ public:
+ NoiseSuppressionProxy(AudioProcessing* apm, NoiseSuppression* ns);
+ ~NoiseSuppressionProxy() override;
+
+ // NoiseSuppression implementation.
+ int Enable(bool enable) override;
+ bool is_enabled() const override;
+ int set_level(Level level) override;
+ Level level() const override;
+ float speech_probability() const override;
+ std::vector<float> NoiseEstimate() override;
+
+ private:
+ AudioProcessing* apm_;
+ NoiseSuppression* ns_;
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(NoiseSuppressionProxy);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_PROXY_H_
diff --git a/modules/audio_processing/residual_echo_detector.cc b/modules/audio_processing/residual_echo_detector.cc
index 3454214..0b53cc2 100644
--- a/modules/audio_processing/residual_echo_detector.cc
+++ b/modules/audio_processing/residual_echo_detector.cc
@@ -16,7 +16,7 @@
#include "absl/types/optional.h"
#include "modules/audio_processing/audio_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/metrics.h"
diff --git a/modules/audio_processing/residual_echo_detector_unittest.cc b/modules/audio_processing/residual_echo_detector_unittest.cc
index c6fb8e4..6658999 100644
--- a/modules/audio_processing/residual_echo_detector_unittest.cc
+++ b/modules/audio_processing/residual_echo_detector_unittest.cc
@@ -11,7 +11,7 @@
#include <vector>
#include "modules/audio_processing/residual_echo_detector.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/modules/audio_processing/rms_level_unittest.cc b/modules/audio_processing/rms_level_unittest.cc
index cf7683d..c2d6a50 100644
--- a/modules/audio_processing/rms_level_unittest.cc
+++ b/modules/audio_processing/rms_level_unittest.cc
@@ -14,7 +14,7 @@
#include "api/array_view.h"
#include "modules/audio_processing/rms_level.h"
#include "rtc_base/checks.h"
-#include "rtc_base/numerics/mathutils.h"
+#include "rtc_base/numerics/math_utils.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "test/gtest.h"
diff --git a/modules/audio_processing/transient/click_annotate.cc b/modules/audio_processing/transient/click_annotate.cc
index ce646b5..21641f8 100644
--- a/modules/audio_processing/transient/click_annotate.cc
+++ b/modules/audio_processing/transient/click_annotate.cc
@@ -39,16 +39,14 @@
return 0;
}
- std::unique_ptr<FileWrapper> pcm_file(FileWrapper::Create());
- pcm_file->OpenFile(argv[1], true);
- if (!pcm_file->is_open()) {
+ FileWrapper pcm_file = FileWrapper::OpenReadOnly(argv[1]);
+ if (!pcm_file.is_open()) {
printf("\nThe %s could not be opened.\n\n", argv[1]);
return -1;
}
- std::unique_ptr<FileWrapper> dat_file(FileWrapper::Create());
- dat_file->OpenFile(argv[2], false);
- if (!dat_file->is_open()) {
+ FileWrapper dat_file = FileWrapper::OpenWriteOnly(argv[2]);
+ if (!dat_file.is_open()) {
printf("\nThe %s could not be opened.\n\n", argv[2]);
return -1;
}
@@ -73,7 +71,7 @@
// Read first buffer from the PCM test file.
size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
- pcm_file.get(), audio_buffer_length, audio_buffer.get());
+ &pcm_file, audio_buffer_length, audio_buffer.get());
for (int time = 0; file_samples_read > 0; time += chunk_size_ms) {
// Pad the rest of the buffer with zeros.
for (size_t i = file_samples_read; i < audio_buffer_length; ++i) {
@@ -91,19 +89,19 @@
// Read next buffer from the PCM test file.
file_samples_read = ReadInt16FromFileToFloatBuffer(
- pcm_file.get(), audio_buffer_length, audio_buffer.get());
+ &pcm_file, audio_buffer_length, audio_buffer.get());
}
size_t floats_written =
- WriteFloatBufferToFile(dat_file.get(), send_times.size(), &send_times[0]);
+ WriteFloatBufferToFile(&dat_file, send_times.size(), &send_times[0]);
if (floats_written == 0) {
printf("\nThe send times could not be written to DAT file\n\n");
return -1;
}
- pcm_file->CloseFile();
- dat_file->CloseFile();
+ pcm_file.Close();
+ dat_file.Close();
return lost_packets;
}
diff --git a/modules/audio_processing/transient/file_utils_unittest.cc b/modules/audio_processing/transient/file_utils_unittest.cc
index 89902ec..0bded02 100644
--- a/modules/audio_processing/transient/file_utils_unittest.cc
+++ b/modules/audio_processing/transient/file_utils_unittest.cc
@@ -17,7 +17,7 @@
#include "rtc_base/system/file_wrapper.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -158,22 +158,20 @@
TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16BufferFromFile) {
std::string test_filename = kTestFileName;
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileName.c_str();
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
const size_t kBufferLength = 12;
std::unique_ptr<int16_t[]> buffer(new int16_t[kBufferLength]);
EXPECT_EQ(kBufferLength,
- ReadInt16BufferFromFile(file.get(), kBufferLength, buffer.get()));
+ ReadInt16BufferFromFile(&file, kBufferLength, buffer.get()));
EXPECT_EQ(22377, buffer[4]);
EXPECT_EQ(16389, buffer[7]);
EXPECT_EQ(17631, buffer[kBufferLength - 1]);
- file->Rewind();
+ file.Rewind();
// The next test is for checking the case where there are not as much data as
// needed in the file, but reads to the end, and it returns the number of
@@ -181,7 +179,7 @@
const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
buffer.reset(new int16_t[kBufferLenghtLargerThanFile]);
EXPECT_EQ(kBufferLength,
- ReadInt16BufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+ ReadInt16BufferFromFile(&file, kBufferLenghtLargerThanFile,
buffer.get()));
EXPECT_EQ(11544, buffer[0]);
EXPECT_EQ(22377, buffer[4]);
@@ -198,24 +196,22 @@
TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToFloatBuffer) {
std::string test_filename = kTestFileName;
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileName.c_str();
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
const size_t kBufferLength = 12;
std::unique_ptr<float[]> buffer(new float[kBufferLength]);
- EXPECT_EQ(kBufferLength, ReadInt16FromFileToFloatBuffer(
- file.get(), kBufferLength, buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ ReadInt16FromFileToFloatBuffer(&file, kBufferLength, buffer.get()));
EXPECT_DOUBLE_EQ(11544, buffer[0]);
EXPECT_DOUBLE_EQ(22377, buffer[4]);
EXPECT_DOUBLE_EQ(16389, buffer[7]);
EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
- file->Rewind();
+ file.Rewind();
// The next test is for checking the case where there are not as much data as
// needed in the file, but reads to the end, and it returns the number of
@@ -223,8 +219,8 @@
const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
buffer.reset(new float[kBufferLenghtLargerThanFile]);
EXPECT_EQ(kBufferLength,
- ReadInt16FromFileToFloatBuffer(
- file.get(), kBufferLenghtLargerThanFile, buffer.get()));
+ ReadInt16FromFileToFloatBuffer(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
EXPECT_DOUBLE_EQ(11544, buffer[0]);
EXPECT_DOUBLE_EQ(22377, buffer[4]);
EXPECT_DOUBLE_EQ(16389, buffer[7]);
@@ -240,23 +236,21 @@
TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToDoubleBuffer) {
std::string test_filename = kTestFileName;
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileName.c_str();
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
const size_t kBufferLength = 12;
std::unique_ptr<double[]> buffer(new double[kBufferLength]);
- EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(
- file.get(), kBufferLength, buffer.get()));
+ EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(&file, kBufferLength,
+ buffer.get()));
EXPECT_DOUBLE_EQ(11544, buffer[0]);
EXPECT_DOUBLE_EQ(22377, buffer[4]);
EXPECT_DOUBLE_EQ(16389, buffer[7]);
EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
- file->Rewind();
+ file.Rewind();
// The next test is for checking the case where there are not as much data as
// needed in the file, but reads to the end, and it returns the number of
@@ -264,8 +258,8 @@
const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
buffer.reset(new double[kBufferLenghtLargerThanFile]);
EXPECT_EQ(kBufferLength,
- ReadInt16FromFileToDoubleBuffer(
- file.get(), kBufferLenghtLargerThanFile, buffer.get()));
+ ReadInt16FromFileToDoubleBuffer(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
EXPECT_DOUBLE_EQ(11544, buffer[0]);
EXPECT_DOUBLE_EQ(22377, buffer[4]);
EXPECT_DOUBLE_EQ(16389, buffer[7]);
@@ -280,22 +274,20 @@
TEST_F(TransientFileUtilsTest, MAYBE_ReadFloatBufferFromFile) {
std::string test_filename = kTestFileNamef;
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileNamef.c_str();
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileNamef.c_str();
const size_t kBufferLength = 3;
std::unique_ptr<float[]> buffer(new float[kBufferLength]);
EXPECT_EQ(kBufferLength,
- ReadFloatBufferFromFile(file.get(), kBufferLength, buffer.get()));
+ ReadFloatBufferFromFile(&file, kBufferLength, buffer.get()));
EXPECT_FLOAT_EQ(kPi, buffer[0]);
EXPECT_FLOAT_EQ(kE, buffer[1]);
EXPECT_FLOAT_EQ(kAvogadro, buffer[2]);
- file->Rewind();
+ file.Rewind();
// The next test is for checking the case where there are not as much data as
// needed in the file, but reads to the end, and it returns the number of
@@ -303,7 +295,7 @@
const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
buffer.reset(new float[kBufferLenghtLargerThanFile]);
EXPECT_EQ(kBufferLength,
- ReadFloatBufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+ ReadFloatBufferFromFile(&file, kBufferLenghtLargerThanFile,
buffer.get()));
EXPECT_FLOAT_EQ(kPi, buffer[0]);
EXPECT_FLOAT_EQ(kE, buffer[1]);
@@ -318,22 +310,20 @@
TEST_F(TransientFileUtilsTest, MAYBE_ReadDoubleBufferFromFile) {
std::string test_filename = kTestFileName;
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileName.c_str();
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
const size_t kBufferLength = 3;
std::unique_ptr<double[]> buffer(new double[kBufferLength]);
EXPECT_EQ(kBufferLength,
- ReadDoubleBufferFromFile(file.get(), kBufferLength, buffer.get()));
+ ReadDoubleBufferFromFile(&file, kBufferLength, buffer.get()));
EXPECT_DOUBLE_EQ(kPi, buffer[0]);
EXPECT_DOUBLE_EQ(kE, buffer[1]);
EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]);
- file->Rewind();
+ file.Rewind();
// The next test is for checking the case where there are not as much data as
// needed in the file, but reads to the end, and it returns the number of
@@ -341,7 +331,7 @@
const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
buffer.reset(new double[kBufferLenghtLargerThanFile]);
EXPECT_EQ(kBufferLength,
- ReadDoubleBufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+ ReadDoubleBufferFromFile(&file, kBufferLenghtLargerThanFile,
buffer.get()));
EXPECT_DOUBLE_EQ(kPi, buffer[0]);
EXPECT_DOUBLE_EQ(kE, buffer[1]);
@@ -354,14 +344,12 @@
#define MAYBE_WriteInt16BufferToFile WriteInt16BufferToFile
#endif
TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) {
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
std::string kOutFileName =
CreateTempFilename(test::OutputPath(), "utils_test");
- file->OpenFile(kOutFileName.c_str(), false); // Write mode.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
const size_t kBufferLength = 3;
std::unique_ptr<int16_t[]> written_buffer(new int16_t[kBufferLength]);
@@ -371,17 +359,17 @@
written_buffer[1] = 2;
written_buffer[2] = 3;
- EXPECT_EQ(kBufferLength, WriteInt16BufferToFile(file.get(), kBufferLength,
- written_buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ WriteInt16BufferToFile(&file, kBufferLength, written_buffer.get()));
- file->CloseFile();
+ file.Close();
- file->OpenFile(kOutFileName.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ file = FileWrapper::OpenReadOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
- EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(), kBufferLength,
- read_buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ ReadInt16BufferFromFile(&file, kBufferLength, read_buffer.get()));
EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
kBufferLength * sizeof(written_buffer[0])));
}
@@ -392,14 +380,12 @@
#define MAYBE_WriteFloatBufferToFile WriteFloatBufferToFile
#endif
TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) {
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
std::string kOutFileName =
CreateTempFilename(test::OutputPath(), "utils_test");
- file->OpenFile(kOutFileName.c_str(), false); // Write mode.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
const size_t kBufferLength = 3;
std::unique_ptr<float[]> written_buffer(new float[kBufferLength]);
@@ -409,17 +395,17 @@
written_buffer[1] = static_cast<float>(kE);
written_buffer[2] = static_cast<float>(kAvogadro);
- EXPECT_EQ(kBufferLength, WriteFloatBufferToFile(file.get(), kBufferLength,
- written_buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ WriteFloatBufferToFile(&file, kBufferLength, written_buffer.get()));
- file->CloseFile();
+ file.Close();
- file->OpenFile(kOutFileName.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ file = FileWrapper::OpenReadOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
- EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(), kBufferLength,
- read_buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ ReadFloatBufferFromFile(&file, kBufferLength, read_buffer.get()));
EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
kBufferLength * sizeof(written_buffer[0])));
}
@@ -430,14 +416,12 @@
#define MAYBE_WriteDoubleBufferToFile WriteDoubleBufferToFile
#endif
TEST_F(TransientFileUtilsTest, MAYBE_WriteDoubleBufferToFile) {
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
-
std::string kOutFileName =
CreateTempFilename(test::OutputPath(), "utils_test");
- file->OpenFile(kOutFileName.c_str(), false); // Write mode.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
const size_t kBufferLength = 3;
std::unique_ptr<double[]> written_buffer(new double[kBufferLength]);
@@ -447,17 +431,17 @@
written_buffer[1] = kE;
written_buffer[2] = kAvogadro;
- EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(file.get(), kBufferLength,
+ EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(&file, kBufferLength,
written_buffer.get()));
- file->CloseFile();
+ file.Close();
- file->OpenFile(kOutFileName.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kOutFileName.c_str();
+ file = FileWrapper::OpenReadOnly(kOutFileName.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
- EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(), kBufferLength,
- read_buffer.get()));
+ EXPECT_EQ(kBufferLength,
+ ReadDoubleBufferFromFile(&file, kBufferLength, read_buffer.get()));
EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
kBufferLength * sizeof(written_buffer[0])));
}
@@ -473,7 +457,7 @@
double value;
std::unique_ptr<int16_t[]> int16_buffer(new int16_t[1]);
std::unique_ptr<double[]> double_buffer(new double[1]);
- std::unique_ptr<FileWrapper> file(FileWrapper::Create());
+ FileWrapper file;
EXPECT_EQ(-1, ConvertByteArrayToDouble(NULL, &value));
EXPECT_EQ(-1, ConvertByteArrayToDouble(kPiBytes, NULL));
@@ -481,37 +465,35 @@
EXPECT_EQ(-1, ConvertDoubleToByteArray(kPi, NULL));
// Tests with file not opened.
- EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 1, int16_buffer.get()));
- EXPECT_EQ(
- 0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, double_buffer.get()));
- EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, double_buffer.get()));
- EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 1, int16_buffer.get()));
- EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 1, double_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, double_buffer.get()));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, double_buffer.get()));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, double_buffer.get()));
- file->OpenFile(test_filename.c_str(), true); // Read only.
- ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
- << kTestFileName.c_str();
+ file = FileWrapper::OpenReadOnly(test_filename.c_str());
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
EXPECT_EQ(0u, ReadInt16BufferFromFile(NULL, 1, int16_buffer.get()));
- EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 1, NULL));
- EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 0, int16_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 0, int16_buffer.get()));
EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(NULL, 1, double_buffer.get()));
- EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, NULL));
- EXPECT_EQ(
- 0u, ReadInt16FromFileToDoubleBuffer(file.get(), 0, double_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 0, double_buffer.get()));
EXPECT_EQ(0u, ReadDoubleBufferFromFile(NULL, 1, double_buffer.get()));
- EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, NULL));
- EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 0, double_buffer.get()));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 0, double_buffer.get()));
EXPECT_EQ(0u, WriteInt16BufferToFile(NULL, 1, int16_buffer.get()));
- EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 1, NULL));
- EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 0, int16_buffer.get()));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, NULL));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 0, int16_buffer.get()));
EXPECT_EQ(0u, WriteDoubleBufferToFile(NULL, 1, double_buffer.get()));
- EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 1, NULL));
- EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 0, double_buffer.get()));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, NULL));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 0, double_buffer.get()));
}
} // namespace webrtc
diff --git a/modules/audio_processing/transient/transient_detector_unittest.cc b/modules/audio_processing/transient/transient_detector_unittest.cc
index 091a573..0425133 100644
--- a/modules/audio_processing/transient/transient_detector_unittest.cc
+++ b/modules/audio_processing/transient/transient_detector_unittest.cc
@@ -18,7 +18,7 @@
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/file_wrapper.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -47,13 +47,10 @@
detect_file_name << "audio_processing/transient/detect"
<< (sample_rate_hz / 1000) << "kHz";
- std::unique_ptr<FileWrapper> detect_file(FileWrapper::Create());
+ FileWrapper detect_file = FileWrapper::OpenReadOnly(
+ test::ResourcePath(detect_file_name.str(), "dat").c_str());
- detect_file->OpenFile(
- test::ResourcePath(detect_file_name.str(), "dat").c_str(),
- true); // Read only.
-
- bool file_opened = detect_file->is_open();
+ bool file_opened = detect_file.is_open();
ASSERT_TRUE(file_opened) << "File could not be opened.\n"
<< detect_file_name.str().c_str();
@@ -62,11 +59,8 @@
audio_file_name << "audio_processing/transient/audio"
<< (sample_rate_hz / 1000) << "kHz";
- std::unique_ptr<FileWrapper> audio_file(FileWrapper::Create());
-
- audio_file->OpenFile(
- test::ResourcePath(audio_file_name.str(), "pcm").c_str(),
- true); // Read only.
+ FileWrapper audio_file = FileWrapper::OpenReadOnly(
+ test::ResourcePath(audio_file_name.str(), "pcm").c_str());
// Create detector.
TransientDetector detector(sample_rate_hz);
@@ -78,14 +72,14 @@
size_t frames_read = 0;
- while (ReadInt16FromFileToFloatBuffer(audio_file.get(), buffer_length,
+ while (ReadInt16FromFileToFloatBuffer(&audio_file, buffer_length,
buffer.get()) == buffer_length) {
++frames_read;
float detector_value =
detector.Detect(buffer.get(), buffer_length, NULL, 0);
double file_value;
- ASSERT_EQ(1u, ReadDoubleBufferFromFile(detect_file.get(), 1, &file_value))
+ ASSERT_EQ(1u, ReadDoubleBufferFromFile(&detect_file, 1, &file_value))
<< "Detect test file is malformed.\n";
// Compare results with data from the matlab test file.
@@ -93,8 +87,8 @@
<< "Frame: " << frames_read;
}
- detect_file->CloseFile();
- audio_file->CloseFile();
+ detect_file.Close();
+ audio_file.Close();
}
}
diff --git a/modules/audio_processing/transient/transient_suppression_test.cc b/modules/audio_processing/transient/transient_suppression_test.cc
index e15f69c..57bddb6 100644
--- a/modules/audio_processing/transient/transient_suppression_test.cc
+++ b/modules/audio_processing/transient/transient_suppression_test.cc
@@ -21,7 +21,7 @@
#include "modules/audio_processing/agc/agc.h"
#include "rtc_base/flags.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
WEBRTC_DEFINE_string(in_file_name, "", "PCM file that contains the signal.");
WEBRTC_DEFINE_string(detection_file_name,
diff --git a/modules/audio_processing/transient/wpd_tree_unittest.cc b/modules/audio_processing/transient/wpd_tree_unittest.cc
index 830a5df..11f75e6 100644
--- a/modules/audio_processing/transient/wpd_tree_unittest.cc
+++ b/modules/audio_processing/transient/wpd_tree_unittest.cc
@@ -18,7 +18,7 @@
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/file_wrapper.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
@@ -80,31 +80,27 @@
kDaubechies8LowPassCoefficients, kDaubechies8CoefficientsLength,
kLevels);
// Allocate and open all matlab and out files.
- std::unique_ptr<FileWrapper> matlab_files_data[kLeaves];
- std::unique_ptr<FileWrapper> out_files_data[kLeaves];
+ FileWrapper matlab_files_data[kLeaves];
+ FileWrapper out_files_data[kLeaves];
for (int i = 0; i < kLeaves; ++i) {
// Matlab files.
- matlab_files_data[i].reset(FileWrapper::Create());
-
rtc::StringBuilder matlab_stream;
matlab_stream << "audio_processing/transient/wpd" << i;
std::string matlab_string = test::ResourcePath(matlab_stream.str(), "dat");
- matlab_files_data[i]->OpenFile(matlab_string.c_str(), true); // Read only.
+ matlab_files_data[i] = FileWrapper::OpenReadOnly(matlab_string.c_str());
- bool file_opened = matlab_files_data[i]->is_open();
+ bool file_opened = matlab_files_data[i].is_open();
ASSERT_TRUE(file_opened) << "File could not be opened.\n" << matlab_string;
// Out files.
- out_files_data[i].reset(FileWrapper::Create());
-
rtc::StringBuilder out_stream;
out_stream << test::OutputPath() << "wpd_" << i << ".out";
std::string out_string = out_stream.str();
- out_files_data[i]->OpenFile(out_string.c_str(), false); // Write mode.
+ out_files_data[i] = FileWrapper::OpenWriteOnly(out_string.c_str());
- file_opened = out_files_data[i]->is_open();
+ file_opened = out_files_data[i].is_open();
ASSERT_TRUE(file_opened) << "File could not be opened.\n" << out_string;
}
@@ -112,11 +108,9 @@
std::string test_file_name = test::ResourcePath(
"audio_processing/transient/ajm-macbook-1-spke16m", "pcm");
- std::unique_ptr<FileWrapper> test_file(FileWrapper::Create());
+ FileWrapper test_file = FileWrapper::OpenReadOnly(test_file_name.c_str());
- test_file->OpenFile(test_file_name.c_str(), true); // Read only.
-
- bool file_opened = test_file->is_open();
+ bool file_opened = test_file.is_open();
ASSERT_TRUE(file_opened) << "File could not be opened.\n" << test_file_name;
float test_buffer[kTestBufferSize];
@@ -129,8 +123,8 @@
size_t frames_read = 0;
// Read first buffer from the PCM test file.
- size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
- test_file.get(), kTestBufferSize, test_buffer);
+ size_t file_samples_read =
+ ReadInt16FromFileToFloatBuffer(&test_file, kTestBufferSize, test_buffer);
while (file_samples_read > 0 && frames_read < kMaxFramesToTest) {
++frames_read;
@@ -147,7 +141,7 @@
for (int i = 0; i < kLeaves; ++i) {
// Compare data values
size_t matlab_samples_read = ReadDoubleBufferFromFile(
- matlab_files_data[i].get(), kLeavesSamples, matlab_buffer);
+ &matlab_files_data[i], kLeavesSamples, matlab_buffer);
ASSERT_EQ(kLeavesSamples, matlab_samples_read)
<< "Matlab test files are malformed.\n"
@@ -162,22 +156,21 @@
}
// Write results to out files.
- WriteFloatBufferToFile(out_files_data[i].get(), kLeavesSamples,
- node_data);
+ WriteFloatBufferToFile(&out_files_data[i], kLeavesSamples, node_data);
}
// Read next buffer from the PCM test file.
file_samples_read = ReadInt16FromFileToFloatBuffer(
- test_file.get(), kTestBufferSize, test_buffer);
+ &test_file, kTestBufferSize, test_buffer);
}
// Close all matlab and out files.
for (int i = 0; i < kLeaves; ++i) {
- matlab_files_data[i]->CloseFile();
- out_files_data[i]->CloseFile();
+ matlab_files_data[i].Close();
+ out_files_data[i].Close();
}
- test_file->CloseFile();
+ test_file.Close();
}
} // namespace webrtc
diff --git a/modules/audio_processing/utility/BUILD.gn b/modules/audio_processing/utility/BUILD.gn
index 6a4304d..f469cd4 100644
--- a/modules/audio_processing/utility/BUILD.gn
+++ b/modules/audio_processing/utility/BUILD.gn
@@ -83,6 +83,18 @@
}
}
+rtc_source_set("pffft_wrapper") {
+ sources = [
+ "pffft_wrapper.cc",
+ "pffft_wrapper.h",
+ ]
+ deps = [
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "//third_party/pffft",
+ ]
+}
+
if (rtc_include_tests) {
rtc_source_set("block_mean_calculator_unittest") {
testonly = true
@@ -111,4 +123,17 @@
"//testing/gtest",
]
}
+
+ rtc_source_set("pffft_wrapper_unittest") {
+ testonly = true
+ sources = [
+ "pffft_wrapper_unittest.cc",
+ ]
+ deps = [
+ ":pffft_wrapper",
+ "../../../test:test_support",
+ "//testing/gtest",
+ "//third_party/pffft",
+ ]
+ }
}
diff --git a/modules/audio_processing/utility/DEPS b/modules/audio_processing/utility/DEPS
new file mode 100644
index 0000000..c72d810
--- /dev/null
+++ b/modules/audio_processing/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/pffft",
+]
diff --git a/modules/audio_processing/utility/block_mean_calculator.h b/modules/audio_processing/utility/block_mean_calculator.h
index cfa7cfb..5ccdbef 100644
--- a/modules/audio_processing/utility/block_mean_calculator.h
+++ b/modules/audio_processing/utility/block_mean_calculator.h
@@ -13,7 +13,7 @@
#include <stddef.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/audio_processing/utility/pffft_wrapper.cc b/modules/audio_processing/utility/pffft_wrapper.cc
new file mode 100644
index 0000000..eb0bff7
--- /dev/null
+++ b/modules/audio_processing/utility/pffft_wrapper.cc
@@ -0,0 +1,110 @@
+/*
+ * 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/audio_processing/utility/pffft_wrapper.h"
+
+#include "rtc_base/checks.h"
+#include "third_party/pffft/src/pffft.h"
+
+namespace webrtc {
+namespace {
+
+size_t GetBufferSize(size_t fft_size, Pffft::FftType fft_type) {
+ return fft_size * (fft_type == Pffft::FftType::kReal ? 1 : 2);
+}
+
+float* AllocatePffftBuffer(size_t size) {
+ return static_cast<float*>(pffft_aligned_malloc(size * sizeof(float)));
+}
+
+} // namespace
+
+Pffft::FloatBuffer::FloatBuffer(size_t fft_size, FftType fft_type)
+ : size_(GetBufferSize(fft_size, fft_type)),
+ data_(AllocatePffftBuffer(size_)) {}
+
+Pffft::FloatBuffer::~FloatBuffer() {
+ pffft_aligned_free(data_);
+}
+
+rtc::ArrayView<const float> Pffft::FloatBuffer::GetConstView() const {
+ return {data_, size_};
+}
+
+rtc::ArrayView<float> Pffft::FloatBuffer::GetView() {
+ return {data_, size_};
+}
+
+Pffft::Pffft(size_t fft_size, FftType fft_type)
+ : fft_size_(fft_size),
+ fft_type_(fft_type),
+ pffft_status_(pffft_new_setup(
+ fft_size_,
+ fft_type == Pffft::FftType::kReal ? PFFFT_REAL : PFFFT_COMPLEX)),
+ scratch_buffer_(
+ AllocatePffftBuffer(GetBufferSize(fft_size_, fft_type_))) {
+ RTC_DCHECK(pffft_status_);
+ RTC_DCHECK(scratch_buffer_);
+}
+
+Pffft::~Pffft() {
+ pffft_destroy_setup(pffft_status_);
+ pffft_aligned_free(scratch_buffer_);
+}
+
+bool Pffft::IsValidFftSize(size_t fft_size, FftType fft_type) {
+ if (fft_size == 0) {
+ return false;
+ }
+ // PFFFT only supports transforms for inputs of length N of the form
+ // N = (2^a)*(3^b)*(5^c) where b >=0 and c >= 0 and a >= 5 for the real FFT
+ // and a >= 4 for the complex FFT.
+ constexpr int kFactors[] = {2, 3, 5};
+ int factorization[] = {0, 0, 0};
+ int n = static_cast<int>(fft_size);
+ for (int i = 0; i < 3; ++i) {
+ while (n % kFactors[i] == 0) {
+ n = n / kFactors[i];
+ factorization[i]++;
+ }
+ }
+ int a_min = (fft_type == Pffft::FftType::kReal) ? 5 : 4;
+ return factorization[0] >= a_min && n == 1;
+}
+
+bool Pffft::IsSimdEnabled() {
+ return pffft_simd_size() > 1;
+}
+
+std::unique_ptr<Pffft::FloatBuffer> Pffft::CreateBuffer() const {
+ // Cannot use make_unique from absl because Pffft is the only friend of
+ // Pffft::FloatBuffer.
+ std::unique_ptr<Pffft::FloatBuffer> buffer(
+ new Pffft::FloatBuffer(fft_size_, fft_type_));
+ return buffer;
+}
+
+void Pffft::ForwardTransform(const FloatBuffer& in, FloatBuffer* out) {
+ RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
+ RTC_DCHECK_EQ(in.size(), out->size());
+ RTC_DCHECK(scratch_buffer_);
+ pffft_transform(pffft_status_, in.const_data(), out->data(), scratch_buffer_,
+ PFFFT_FORWARD);
+}
+
+void Pffft::BackwardTransform(const FloatBuffer& in, FloatBuffer* out) {
+ RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
+ RTC_DCHECK_EQ(in.size(), out->size());
+ RTC_DCHECK(scratch_buffer_);
+ pffft_transform(pffft_status_, in.const_data(), out->data(), scratch_buffer_,
+ PFFFT_BACKWARD);
+}
+
+} // namespace webrtc
diff --git a/modules/audio_processing/utility/pffft_wrapper.h b/modules/audio_processing/utility/pffft_wrapper.h
new file mode 100644
index 0000000..c190430
--- /dev/null
+++ b/modules/audio_processing/utility/pffft_wrapper.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
+
+#include <memory>
+
+#include "api/array_view.h"
+
+// Forward declaration.
+struct PFFFT_Setup;
+
+namespace webrtc {
+
+// Pretty-Fast Fast Fourier Transform (PFFFT) wrapper class.
+// Not thread safe.
+class Pffft {
+ public:
+ enum class FftType { kReal, kComplex };
+
+ // 1D floating point buffer used as input/output data type for the FFT ops.
+ // It must be constructed using Pffft::CreateBuffer().
+ class FloatBuffer {
+ public:
+ FloatBuffer(const FloatBuffer&) = delete;
+ FloatBuffer& operator=(const FloatBuffer&) = delete;
+ ~FloatBuffer();
+
+ rtc::ArrayView<const float> GetConstView() const;
+ rtc::ArrayView<float> GetView();
+
+ private:
+ friend class Pffft;
+ FloatBuffer(size_t fft_size, FftType fft_type);
+ const float* const_data() const { return data_; }
+ float* data() { return data_; }
+ size_t size() const { return size_; }
+
+ const size_t size_;
+ float* const data_;
+ };
+
+ // TODO(https://crbug.com/webrtc/9577): Consider adding a factory and making
+ // the ctor private.
+ // static std::unique_ptr<Pffft> Create(size_t fft_size,
+ // FftType fft_type); Ctor. |fft_size| must be a supported size (see
+ // Pffft::IsValidFftSize()). If not supported, the code will crash.
+ Pffft(size_t fft_size, FftType fft_type);
+ Pffft(const Pffft&) = delete;
+ Pffft& operator=(const Pffft&) = delete;
+ ~Pffft();
+
+ // Returns true if the FFT size is supported.
+ static bool IsValidFftSize(size_t fft_size, FftType fft_type);
+
+ // Returns true if SIMD code optimizations are being used.
+ static bool IsSimdEnabled();
+
+ // Creates a buffer of the right size.
+ std::unique_ptr<FloatBuffer> CreateBuffer() const;
+
+ // TODO(https://crbug.com/webrtc/9577): Overload with rtc::ArrayView args.
+ // Computes the forward fast Fourier transform.
+ void ForwardTransform(const FloatBuffer& in, FloatBuffer* out);
+ // Computes the backward fast Fourier transform.
+ void BackwardTransform(const FloatBuffer& in, FloatBuffer* out);
+
+ private:
+ const size_t fft_size_;
+ const FftType fft_type_;
+ PFFFT_Setup* pffft_status_;
+ float* const scratch_buffer_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
diff --git a/modules/audio_processing/utility/pffft_wrapper_unittest.cc b/modules/audio_processing/utility/pffft_wrapper_unittest.cc
new file mode 100644
index 0000000..8ec2208
--- /dev/null
+++ b/modules/audio_processing/utility/pffft_wrapper_unittest.cc
@@ -0,0 +1,154 @@
+/*
+ * 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/audio_processing/utility/pffft_wrapper.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <memory>
+
+#include "test/gtest.h"
+#include "third_party/pffft/src/pffft.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+constexpr size_t kMaxValidSizeCheck = 1024;
+
+static constexpr int kFftSizes[] = {
+ 16, 32, 64, 96, 128, 160, 192, 256, 288, 384, 5 * 96, 512,
+ 576, 5 * 128, 800, 864, 1024, 2048, 2592, 4000, 4096, 12000, 36864};
+
+void CreatePffftWrapper(size_t fft_size, Pffft::FftType fft_type) {
+ Pffft pffft_wrapper(fft_size, fft_type);
+}
+
+float* AllocateScratchBuffer(size_t fft_size, bool complex_fft) {
+ return static_cast<float*>(
+ pffft_aligned_malloc(fft_size * (complex_fft ? 2 : 1) * sizeof(float)));
+}
+
+double frand() {
+ return std::rand() / static_cast<double>(RAND_MAX);
+}
+
+void ExpectArrayViewsEquality(rtc::ArrayView<const float> a,
+ rtc::ArrayView<const float> b) {
+ ASSERT_EQ(a.size(), b.size());
+ for (size_t i = 0; i < a.size(); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(a[i], b[i]);
+ }
+}
+
+// Compares the output of the PFFFT C++ wrapper to that of the C PFFFT.
+// Bit-exactness is expected.
+void PffftValidateWrapper(size_t fft_size, bool complex_fft) {
+ // Always use the same seed to avoid flakiness.
+ std::srand(0);
+
+ // Init PFFFT.
+ PFFFT_Setup* pffft_status =
+ pffft_new_setup(fft_size, complex_fft ? PFFFT_COMPLEX : PFFFT_REAL);
+ ASSERT_TRUE(pffft_status) << "FFT size (" << fft_size << ") not supported.";
+ size_t num_floats = fft_size * (complex_fft ? 2 : 1);
+ int num_bytes = static_cast<int>(num_floats) * sizeof(float);
+ float* in = static_cast<float*>(pffft_aligned_malloc(num_bytes));
+ float* out = static_cast<float*>(pffft_aligned_malloc(num_bytes));
+ float* scratch = AllocateScratchBuffer(fft_size, complex_fft);
+
+ // Init PFFFT C++ wrapper.
+ Pffft::FftType fft_type =
+ complex_fft ? Pffft::FftType::kComplex : Pffft::FftType::kReal;
+ ASSERT_TRUE(Pffft::IsValidFftSize(fft_size, fft_type));
+ Pffft pffft_wrapper(fft_size, fft_type);
+ auto in_wrapper = pffft_wrapper.CreateBuffer();
+ auto out_wrapper = pffft_wrapper.CreateBuffer();
+
+ // Input and output buffers views.
+ rtc::ArrayView<float> in_view(in, num_floats);
+ rtc::ArrayView<float> out_view(out, num_floats);
+ auto in_wrapper_view = in_wrapper->GetView();
+ EXPECT_EQ(in_wrapper_view.size(), num_floats);
+ auto out_wrapper_view = out_wrapper->GetConstView();
+ EXPECT_EQ(out_wrapper_view.size(), num_floats);
+
+ // Random input data.
+ for (size_t i = 0; i < num_floats; ++i) {
+ in_wrapper_view[i] = in[i] = static_cast<float>(frand() * 2.0 - 1.0);
+ }
+
+ // Forward transform.
+ pffft_transform(pffft_status, in, out, scratch, PFFFT_FORWARD);
+ pffft_wrapper.ForwardTransform(*in_wrapper, out_wrapper.get());
+ ExpectArrayViewsEquality(out_view, out_wrapper_view);
+
+ // Copy the FFT results into the input buffers to compute the backward FFT.
+ std::copy(out_view.begin(), out_view.end(), in_view.begin());
+ std::copy(out_wrapper_view.begin(), out_wrapper_view.end(),
+ in_wrapper_view.begin());
+
+ // Backward transform.
+ pffft_transform(pffft_status, in, out, scratch, PFFFT_BACKWARD);
+ pffft_wrapper.BackwardTransform(*in_wrapper, out_wrapper.get());
+ ExpectArrayViewsEquality(out_view, out_wrapper_view);
+
+ pffft_destroy_setup(pffft_status);
+ pffft_aligned_free(in);
+ pffft_aligned_free(out);
+ pffft_aligned_free(scratch);
+}
+
+} // namespace
+
+TEST(PffftTest, CreateWrapperWithValidSize) {
+ for (size_t fft_size = 0; fft_size < kMaxValidSizeCheck; ++fft_size) {
+ SCOPED_TRACE(fft_size);
+ if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal)) {
+ CreatePffftWrapper(fft_size, Pffft::FftType::kReal);
+ }
+ if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex)) {
+ CreatePffftWrapper(fft_size, Pffft::FftType::kComplex);
+ }
+ }
+}
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+TEST(PffftTest, DoNotCreateWrapperWithInvalidSize) {
+ for (size_t fft_size = 0; fft_size < kMaxValidSizeCheck; ++fft_size) {
+ SCOPED_TRACE(fft_size);
+ if (!Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal)) {
+ EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kReal), "");
+ }
+ if (!Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex)) {
+ EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kComplex), "");
+ }
+ }
+}
+#endif
+
+// TODO(https://crbug.com/webrtc/9577): Enable once SIMD is always enabled.
+TEST(PffftTest, DISABLED_CheckSimd) {
+ EXPECT_TRUE(Pffft::IsSimdEnabled());
+}
+
+TEST(PffftTest, FftBitExactness) {
+ for (int fft_size : kFftSizes) {
+ SCOPED_TRACE(fft_size);
+ if (fft_size != 16) {
+ PffftValidateWrapper(fft_size, /*complex_fft=*/false);
+ }
+ PffftValidateWrapper(fft_size, /*complex_fft=*/true);
+ }
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/modules/audio_processing/vad/pitch_based_vad_unittest.cc b/modules/audio_processing/vad/pitch_based_vad_unittest.cc
index fb6daa5..4a8331a 100644
--- a/modules/audio_processing/vad/pitch_based_vad_unittest.cc
+++ b/modules/audio_processing/vad/pitch_based_vad_unittest.cc
@@ -16,7 +16,7 @@
#include <string>
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_processing/vad/pole_zero_filter_unittest.cc b/modules/audio_processing/vad/pole_zero_filter_unittest.cc
index 38ee10f..8088b40 100644
--- a/modules/audio_processing/vad/pole_zero_filter_unittest.cc
+++ b/modules/audio_processing/vad/pole_zero_filter_unittest.cc
@@ -17,7 +17,7 @@
#include "modules/audio_processing/vad/vad_audio_proc_internal.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_processing/vad/standalone_vad_unittest.cc b/modules/audio_processing/vad/standalone_vad_unittest.cc
index 512276e..22b1f49 100644
--- a/modules/audio_processing/vad/standalone_vad_unittest.cc
+++ b/modules/audio_processing/vad/standalone_vad_unittest.cc
@@ -15,7 +15,7 @@
#include <memory>
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_processing/vad/vad_audio_proc_unittest.cc b/modules/audio_processing/vad/vad_audio_proc_unittest.cc
index 5b96be6..0afed84 100644
--- a/modules/audio_processing/vad/vad_audio_proc_unittest.cc
+++ b/modules/audio_processing/vad/vad_audio_proc_unittest.cc
@@ -21,7 +21,7 @@
#include "modules/audio_processing/vad/common.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
diff --git a/modules/audio_processing/vad/voice_activity_detector_unittest.cc b/modules/audio_processing/vad/voice_activity_detector_unittest.cc
index 62eda2b..3214bd9 100644
--- a/modules/audio_processing/vad/voice_activity_detector_unittest.cc
+++ b/modules/audio_processing/vad/voice_activity_detector_unittest.cc
@@ -14,7 +14,7 @@
#include <vector>
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace webrtc {
namespace {
diff --git a/modules/audio_processing/voice_detection_impl.cc b/modules/audio_processing/voice_detection_impl.cc
index c55ca4a..7bf6c4a 100644
--- a/modules/audio_processing/voice_detection_impl.cc
+++ b/modules/audio_processing/voice_detection_impl.cc
@@ -14,7 +14,7 @@
#include "common_audio/vad/include/webrtc_vad.h"
#include "modules/audio_processing/audio_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
class VoiceDetectionImpl::Vad {
diff --git a/modules/audio_processing/voice_detection_impl.h b/modules/audio_processing/voice_detection_impl.h
index c438473..6800566 100644
--- a/modules/audio_processing/voice_detection_impl.h
+++ b/modules/audio_processing/voice_detection_impl.h
@@ -15,8 +15,8 @@
#include <memory>
#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/modules/include/module_common_types.h b/modules/include/module_common_types.h
index e058cc8..26122b1 100644
--- a/modules/include/module_common_types.h
+++ b/modules/include/module_common_types.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <vector>
#include "api/rtp_headers.h"
#include "common_types.h" // NOLINT(build/include)
@@ -96,6 +97,17 @@
virtual ~KeyFrameRequestSender() {}
};
+// Interface used by LossNotificationController to communicate to RtpRtcp.
+// TODO(bugs.webrtc.org/10336): Hook up to RtpRtcp.
+class LossNotificationSender {
+ public:
+ virtual ~LossNotificationSender() {}
+
+ virtual void SendLossNotification(uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag) = 0;
+};
+
// Used to indicate if a received packet contain a complete NALU (or equivalent)
enum VCMNaluCompleteness {
kNaluUnset = 0, // Packet has not been filled.
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index edb981b..d66d437 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -25,6 +25,7 @@
"source/rtcp_packet/extended_jitter_report.h",
"source/rtcp_packet/extended_reports.h",
"source/rtcp_packet/fir.h",
+ "source/rtcp_packet/loss_notification.h",
"source/rtcp_packet/nack.h",
"source/rtcp_packet/pli.h",
"source/rtcp_packet/psfb.h",
@@ -59,6 +60,7 @@
"source/rtcp_packet/extended_jitter_report.cc",
"source/rtcp_packet/extended_reports.cc",
"source/rtcp_packet/fir.cc",
+ "source/rtcp_packet/loss_notification.cc",
"source/rtcp_packet/nack.cc",
"source/rtcp_packet/pli.cc",
"source/rtcp_packet/psfb.cc",
@@ -97,6 +99,7 @@
"../../rtc_base:checks",
"../../rtc_base:deprecation",
"../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:unused",
"../../system_wrappers",
"../video_coding:codec_globals_headers",
"//third_party/abseil-cpp/absl/types:optional",
@@ -196,8 +199,11 @@
"../..:webrtc_common",
"../../api:array_view",
"../../api:libjingle_peerconnection_api",
+ "../../api:scoped_refptr",
"../../api:transport_api",
"../../api/audio_codecs:audio_codecs_api",
+ "../../api/transport:field_trial_based_config",
+ "../../api/transport:webrtc_key_value_config",
"../../api/video:video_bitrate_allocation",
"../../api/video:video_bitrate_allocator",
"../../api/video:video_frame",
@@ -215,13 +221,10 @@
"../../rtc_base:rtc_numerics",
"../../rtc_base:safe_minmax",
"../../rtc_base:sequenced_task_checker",
- "../../rtc_base:stringutils",
"../../rtc_base/system:fallthrough",
"../../rtc_base/time:timestamp_extrapolator",
"../../system_wrappers",
- "../../system_wrappers:field_trial",
"../../system_wrappers:metrics",
- "../audio_coding:audio_format_conversion",
"../remote_bitrate_estimator",
"../video_coding:codec_globals_headers",
"//third_party/abseil-cpp/absl/container:inlined_vector",
@@ -254,8 +257,9 @@
"../../api/video:video_bitrate_allocation",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
- "../../rtc_base:rtc_cancelable_task",
"../../rtc_base:rtc_task_queue",
+ "../../rtc_base/task_utils:repeating_task",
+ "../../rtc_base/task_utils:to_queued_task",
"../../system_wrappers",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
@@ -376,6 +380,7 @@
"source/rtcp_packet/extended_jitter_report_unittest.cc",
"source/rtcp_packet/extended_reports_unittest.cc",
"source/rtcp_packet/fir_unittest.cc",
+ "source/rtcp_packet/loss_notification_unittest.cc",
"source/rtcp_packet/nack_unittest.cc",
"source/rtcp_packet/pli_unittest.cc",
"source/rtcp_packet/rapid_resync_request_unittest.cc",
@@ -408,7 +413,9 @@
"source/rtp_packet_history_unittest.cc",
"source/rtp_packet_unittest.cc",
"source/rtp_rtcp_impl_unittest.cc",
+ "source/rtp_sender_audio_unittest.cc",
"source/rtp_sender_unittest.cc",
+ "source/rtp_sender_video_unittest.cc",
"source/rtp_utility_unittest.cc",
"source/time_util_unittest.cc",
"source/ulpfec_generator_unittest.cc",
@@ -425,13 +432,17 @@
"../..:webrtc_common",
"../../api:array_view",
"../../api:libjingle_peerconnection_api",
+ "../../api:scoped_refptr",
"../../api:transport_api",
+ "../../api/transport:field_trial_based_config",
"../../api/video:video_bitrate_allocation",
"../../api/video:video_bitrate_allocator",
+ "../../api/video:video_codec_constants",
"../../api/video:video_frame",
"../../api/video_codecs:video_codecs_api",
"../../call:rtp_receiver",
"../../common_video:common_video",
+ "../../common_video/test:utilities",
"../../logging:mocks",
"../../logging:rtc_event_log_api",
"../../rtc_base:checks",
@@ -444,7 +455,6 @@
"../../test:rtp_test_utils",
"../../test:test_common",
"../../test:test_support",
- "../audio_coding:audio_format_conversion",
"../video_coding:codec_globals_headers",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
diff --git a/modules/rtp_rtcp/DEPS b/modules/rtp_rtcp/DEPS
index 9d9f33c..dac95dd 100644
--- a/modules/rtp_rtcp/DEPS
+++ b/modules/rtp_rtcp/DEPS
@@ -3,4 +3,6 @@
"+common_video",
"+logging/rtc_event_log",
"+system_wrappers",
+ # Avoid directly using field_trial. Instead use WebRtcKeyValueConfig.
+ "-system_wrappers/include/field_trial.h",
]
diff --git a/modules/rtp_rtcp/include/flexfec_receiver.h b/modules/rtp_rtcp/include/flexfec_receiver.h
index f0ed576..2426559 100644
--- a/modules/rtp_rtcp/include/flexfec_receiver.h
+++ b/modules/rtp_rtcp/include/flexfec_receiver.h
@@ -30,6 +30,10 @@
FlexfecReceiver(uint32_t ssrc,
uint32_t protected_media_ssrc,
RecoveredPacketReceiver* recovered_packet_receiver);
+ FlexfecReceiver(Clock* clock,
+ uint32_t ssrc,
+ uint32_t protected_media_ssrc,
+ RecoveredPacketReceiver* recovered_packet_receiver);
~FlexfecReceiver();
// Inserts a received packet (can be either media or FlexFEC) into the
diff --git a/modules/rtp_rtcp/include/flexfec_sender.h b/modules/rtp_rtcp/include/flexfec_sender.h
index acee117..aa0e8e0 100644
--- a/modules/rtp_rtcp/include/flexfec_sender.h
+++ b/modules/rtp_rtcp/include/flexfec_sender.h
@@ -16,7 +16,7 @@
#include <vector>
#include "api/array_view.h"
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "modules/include/module_common_types.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
diff --git a/modules/rtp_rtcp/include/remote_ntp_time_estimator.h b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
index e6d269c..dd0e0de 100644
--- a/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
+++ b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
@@ -13,7 +13,7 @@
#include <stdint.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/numerics/moving_median_filter.h"
#include "system_wrappers/include/rtp_to_ntp_estimator.h"
diff --git a/modules/rtp_rtcp/include/rtp_header_extension_map.h b/modules/rtp_rtcp/include/rtp_header_extension_map.h
index 391c5be..07b31a3 100644
--- a/modules/rtp_rtcp/include/rtp_header_extension_map.h
+++ b/modules/rtp_rtcp/include/rtp_header_extension_map.h
@@ -15,7 +15,7 @@
#include <string>
#include "api/array_view.h"
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/checks.h"
diff --git a/modules/rtp_rtcp/include/rtp_header_parser.h b/modules/rtp_rtcp/include/rtp_header_parser.h
index 85eab90..1b0156b 100644
--- a/modules/rtp_rtcp/include/rtp_header_parser.h
+++ b/modules/rtp_rtcp/include/rtp_header_parser.h
@@ -10,7 +10,7 @@
#ifndef MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_
#define MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h
index d136a5e..6e1b4a5 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp.h
@@ -16,13 +16,16 @@
#include <utility>
#include <vector>
+#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "api/transport/webrtc_key_value_config.h"
#include "api/video/video_bitrate_allocation.h"
#include "modules/include/module.h"
#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/constructormagic.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/deprecation.h"
namespace webrtc {
@@ -86,12 +89,13 @@
TransportSequenceNumberAllocator* transport_sequence_number_allocator =
nullptr;
BitrateStatisticsObserver* send_bitrate_observer = nullptr;
- FrameCountObserver* send_frame_count_observer = nullptr;
SendSideDelayObserver* send_side_delay_observer = nullptr;
RtcEventLog* event_log = nullptr;
SendPacketObserver* send_packet_observer = nullptr;
RateLimiter* retransmission_rate_limiter = nullptr;
OverheadObserver* overhead_observer = nullptr;
+ RtcpAckObserver* ack_observer = nullptr;
+
RtpKeepAliveConfig keepalive_config;
int rtcp_report_interval_ms = 0;
@@ -107,6 +111,10 @@
// Corresponds to extmap-allow-mixed in SDP negotiation.
bool extmap_allow_mixed = false;
+ // If set, field trials are read from |field_trials|, otherwise
+ // defaults to webrtc::FieldTrialBasedConfig.
+ const WebRtcKeyValueConfig* field_trials = nullptr;
+
private:
RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);
};
@@ -135,11 +143,13 @@
// FEC/ULP/RED overhead (when FEC is enabled).
virtual size_t MaxRtpPacketSize() const = 0;
- // Sets codec name and payload type. Returns -1 on failure else 0.
- virtual int32_t RegisterSendPayload(const CodecInst& voice_codec) = 0;
-
- virtual void RegisterVideoSendPayload(int payload_type,
- const char* payload_name) = 0;
+ virtual void RegisterAudioSendPayload(int payload_type,
+ absl::string_view payload_name,
+ int frequency,
+ int channels,
+ int rate) = 0;
+ virtual void RegisterSendPayloadFrequency(int payload_type,
+ int payload_frequency) = 0;
// Unregisters a send payload.
// |payload_type| - payload type of codec
@@ -183,6 +193,12 @@
// Sets SSRC, default is a random number.
virtual void SetSSRC(uint32_t ssrc) = 0;
+ // Sets the value for sending in the RID (and Repaired) RTP header extension.
+ // RIDs are used to identify an RTP stream if SSRCs are not negotiated.
+ // If the RID and Repaired RID extensions are not registered, the RID will
+ // not be sent.
+ virtual void SetRid(const std::string& rid) = 0;
+
// Sets the value for sending in the MID RTP header extension.
// The MID RTP header extension should be registered for this to do anything.
// Once set, this value can not be changed or removed.
@@ -229,12 +245,15 @@
// bitrate estimate since the stream participates in the bitrate allocation.
virtual void SetAsPartOfAllocation(bool part_of_allocation) = 0;
- // Returns current bitrate in Kbit/s.
+ // Fetches the current send bitrates in bits/s.
virtual void BitrateSent(uint32_t* total_rate,
uint32_t* video_rate,
uint32_t* fec_rate,
uint32_t* nack_rate) const = 0;
+ virtual RTPSender* RtpSender() = 0;
+ virtual const RTPSender* RtpSender() const = 0;
+
// Used by the codec module to deliver a video or audio frame for
// packetization.
// |frame_type| - type of frame to send
@@ -256,6 +275,13 @@
const RTPVideoHeader* rtp_video_header,
uint32_t* transport_frame_id_out) = 0;
+ // Record that a frame is about to be sent. Returns true on success, and false
+ // if the module isn't ready to send.
+ virtual bool OnSendingRtpFrame(uint32_t timestamp,
+ int64_t capture_time_ms,
+ int payload_type,
+ bool force_sender_report) = 0;
+
virtual bool TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
int64_t capture_time_ms,
@@ -313,6 +339,9 @@
int64_t* min_rtt,
int64_t* max_rtt) const = 0;
+ // Returns the estimated RTT, with fallback to a default value.
+ virtual int64_t ExpectedRetransmissionTimeMs() const = 0;
+
// Forces a send of a RTCP packet. Periodic SR and RR are triggered via the
// process function.
// Returns -1 on failure else 0.
@@ -370,21 +399,6 @@
// (NACK)
- // TODO(holmer): Propagate this API to VideoEngine.
- // Returns the currently configured selective retransmission settings.
- virtual int SelectiveRetransmissions() const = 0;
-
- // TODO(holmer): Propagate this API to VideoEngine.
- // Sets the selective retransmission settings, which will decide which
- // packets will be retransmitted if NACKed. Settings are constructed by
- // combining the constants in enum RetransmissionMode with bitwise OR.
- // All packets are retransmitted if kRetransmitAllPackets is set, while no
- // packets are retransmitted if kRetransmitOff is set.
- // By default all packets except FEC packets are retransmitted. For VP8
- // with temporal scalability only base layer packets are retransmitted.
- // Returns -1 on failure, otherwise 0.
- virtual int SetSelectiveRetransmissions(uint8_t settings) = 0;
-
// Sends a Negative acknowledgement packet.
// Returns -1 on failure else 0.
// TODO(philipel): Deprecate this and start using SendNack instead, mostly
@@ -435,23 +449,6 @@
// Video
// **************************************************************************
- // Set RED and ULPFEC payload types. A payload type of -1 means that the
- // corresponding feature is turned off. Note that we DO NOT support enabling
- // ULPFEC without enabling RED, and RED is only ever used when ULPFEC is
- // enabled.
- virtual void SetUlpfecConfig(int red_payload_type,
- int ulpfec_payload_type) = 0;
-
- // Set FEC rates, max frames before FEC is sent, and type of FEC masks.
- // Returns false on failure.
- virtual bool SetFecParameters(const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params) = 0;
-
- // Deprecated version of member function above.
- RTC_DEPRECATED
- int32_t SetFecParameters(const FecProtectionParams* delta_params,
- const FecProtectionParams* key_params);
-
// Set method for requestion a new key frame.
// Returns -1 on failure else 0.
virtual int32_t SetKeyFrameRequestMethod(KeyFrameRequestMethod method) = 0;
@@ -459,6 +456,12 @@
// Sends a request for a keyframe.
// Returns -1 on failure else 0.
virtual int32_t RequestKeyFrame() = 0;
+
+ // Sends a LossNotification RTCP message.
+ // Returns -1 on failure else 0.
+ virtual int32_t SendLossNotification(uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag) = 0;
};
} // namespace webrtc
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.cc b/modules/rtp_rtcp/include/rtp_rtcp_defines.cc
index d743f52..d23d82d 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.cc
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.cc
@@ -53,15 +53,6 @@
// and thus assume trivial destructibility.
static_assert(std::is_trivially_destructible<StreamId>::value, "");
-PayloadUnion::PayloadUnion(const AudioPayload& payload) : payload_(payload) {}
-PayloadUnion::PayloadUnion(const VideoPayload& payload) : payload_(payload) {}
-PayloadUnion::PayloadUnion(const PayloadUnion&) = default;
-PayloadUnion::PayloadUnion(PayloadUnion&&) = default;
-PayloadUnion::~PayloadUnion() = default;
-
-PayloadUnion& PayloadUnion::operator=(const PayloadUnion&) = default;
-PayloadUnion& PayloadUnion::operator=(PayloadUnion&&) = default;
-
PacketFeedback::PacketFeedback(int64_t arrival_time_ms,
uint16_t sequence_number)
: PacketFeedback(-1,
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index ab4fcae..b648942 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -41,47 +41,6 @@
// Minimum RTP header size in bytes.
const uint8_t kRtpHeaderSize = 12;
-struct AudioPayload {
- SdpAudioFormat format;
- uint32_t rate;
-};
-
-struct VideoPayload {
- VideoCodecType videoCodecType;
- // The H264 profile only matters if videoCodecType == kVideoCodecH264.
- H264::Profile h264_profile;
-};
-
-class PayloadUnion {
- public:
- explicit PayloadUnion(const AudioPayload& payload);
- explicit PayloadUnion(const VideoPayload& payload);
- PayloadUnion(const PayloadUnion&);
- PayloadUnion(PayloadUnion&&);
- ~PayloadUnion();
-
- PayloadUnion& operator=(const PayloadUnion&);
- PayloadUnion& operator=(PayloadUnion&&);
-
- bool is_audio() const {
- return absl::holds_alternative<AudioPayload>(payload_);
- }
- bool is_video() const {
- return absl::holds_alternative<VideoPayload>(payload_);
- }
- const AudioPayload& audio_payload() const {
- return absl::get<AudioPayload>(payload_);
- }
- const VideoPayload& video_payload() const {
- return absl::get<VideoPayload>(payload_);
- }
- AudioPayload& audio_payload() { return absl::get<AudioPayload>(payload_); }
- VideoPayload& video_payload() { return absl::get<VideoPayload>(payload_); }
-
- private:
- absl::variant<AudioPayload, VideoPayload> payload_;
-};
-
enum ProtectionType { kUnprotectedPacket, kProtectedPacket };
enum StorageType { kDontRetransmit, kAllowRetransmission };
@@ -96,6 +55,7 @@
kRtpExtensionAbsoluteSendTime,
kRtpExtensionVideoRotation,
kRtpExtensionTransportSequenceNumber,
+ kRtpExtensionTransportSequenceNumber02,
kRtpExtensionPlayoutDelay,
kRtpExtensionVideoContentType,
kRtpExtensionVideoTiming,
@@ -103,7 +63,9 @@
kRtpExtensionRtpStreamId,
kRtpExtensionRepairedRtpStreamId,
kRtpExtensionMid,
- kRtpExtensionGenericFrameDescriptor,
+ kRtpExtensionGenericFrameDescriptor00,
+ kRtpExtensionGenericFrameDescriptor = kRtpExtensionGenericFrameDescriptor00,
+ kRtpExtensionGenericFrameDescriptor01,
kRtpExtensionColorSpace,
kRtpExtensionNumberOfExtensions // Must be the last entity in the enum.
};
@@ -124,6 +86,7 @@
kRtcpTmmbn = 0x0200,
kRtcpSrReq = 0x0400,
kRtcpApp = 0x1000,
+ kRtcpLossNotification = 0x2000,
kRtcpRemb = 0x10000,
kRtcpTransmissionTimeOffset = 0x20000,
kRtcpXrReceiverReferenceTime = 0x40000,
@@ -136,19 +99,6 @@
enum RtpRtcpPacketType { kPacketRtp = 0, kPacketKeepAlive = 1 };
-// kConditionallyRetransmitHigherLayers allows retransmission of video frames
-// in higher layers if either the last frame in that layer was too far back in
-// time, or if we estimate that a new frame will be available in a lower layer
-// in a shorter time than it would take to request and receive a retransmission.
-enum RetransmissionMode : uint8_t {
- kRetransmitOff = 0x0,
- kRetransmitFECPackets = 0x1,
- kRetransmitBaseLayer = 0x2,
- kRetransmitHigherLayers = 0x4,
- kConditionallyRetransmitHigherLayers = 0x8,
- kRetransmitAllPackets = 0xFF
-};
-
enum RtxMode {
kRtxOff = 0x0,
kRtxRetransmitted = 0x1, // Only send retransmissions over RTX.
@@ -509,5 +459,18 @@
uint32_t ssrc) = 0;
};
+class RtcpAckObserver {
+ public:
+ // This method is called on received report blocks matching the sender ssrc.
+ // TODO(nisse): Use of "extended" sequence number is a bit brittle, since the
+ // observer for this callback typically has its own sequence number unwrapper,
+ // and there's no guarantee that they are in sync. Change to pass raw sequence
+ // number, possibly augmented with timestamp (if available) to aid
+ // disambiguation.
+ virtual void OnReceivedAck(int64_t extended_highest_sequence_number) = 0;
+
+ virtual ~RtcpAckObserver() = default;
+};
+
} // namespace webrtc
#endif // MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 3b9b943..7d4f0f1 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -37,9 +37,14 @@
MOCK_METHOD1(SetRemoteSSRC, void(uint32_t ssrc));
MOCK_METHOD1(SetMaxRtpPacketSize, void(size_t size));
MOCK_CONST_METHOD0(MaxRtpPacketSize, size_t());
- MOCK_METHOD1(RegisterSendPayload, int32_t(const CodecInst& voice_codec));
- MOCK_METHOD2(RegisterVideoSendPayload,
- void(int payload_type, const char* payload_name));
+ MOCK_METHOD5(RegisterAudioSendPayload,
+ void(int payload_type,
+ absl::string_view payload_name,
+ int frequency,
+ int channels,
+ int rate));
+ MOCK_METHOD2(RegisterSendPayloadFrequency,
+ void(int payload_type, int frequency));
MOCK_METHOD1(DeRegisterSendPayload, int32_t(int8_t payload_type));
MOCK_METHOD1(SetExtmapAllowMixed, void(bool extmap_allow_mixed));
MOCK_METHOD2(RegisterSendRtpHeaderExtension,
@@ -59,6 +64,7 @@
MOCK_CONST_METHOD0(GetRtxState, RtpState());
MOCK_CONST_METHOD0(SSRC, uint32_t());
MOCK_METHOD1(SetSSRC, void(uint32_t ssrc));
+ MOCK_METHOD1(SetRid, void(const std::string& rid));
MOCK_METHOD1(SetMid, void(const std::string& mid));
MOCK_CONST_METHOD1(CSRCs, int32_t(uint32_t csrcs[kRtpCsrcSize]));
MOCK_METHOD1(SetCsrcs, void(const std::vector<uint32_t>& csrcs));
@@ -91,6 +97,7 @@
const RTPFragmentationHeader* fragmentation,
const RTPVideoHeader* rtp_video_header,
uint32_t* frame_id_out));
+ MOCK_METHOD4(OnSendingRtpFrame, bool(uint32_t, int64_t, int, bool));
MOCK_METHOD5(TimeToSendPacket,
bool(uint32_t ssrc,
uint16_t sequence_number,
@@ -123,6 +130,7 @@
int64_t* avg_rtt,
int64_t* min_rtt,
int64_t* max_rtt));
+ MOCK_CONST_METHOD0(ExpectedRetransmissionTimeMs, int64_t());
MOCK_METHOD1(SendRTCP, int32_t(RTCPPacketType packet_type));
MOCK_METHOD1(SendCompoundRTCP,
int32_t(const std::set<RTCPPacketType>& packet_types));
@@ -146,8 +154,6 @@
MOCK_CONST_METHOD0(TMMBR, bool());
MOCK_METHOD1(SetTMMBRStatus, void(bool enable));
MOCK_METHOD1(OnBandwidthEstimateUpdate, void(uint16_t bandwidth_kbit));
- MOCK_CONST_METHOD0(SelectiveRetransmissions, int());
- MOCK_METHOD1(SetSelectiveRetransmissions, int(uint8_t settings));
MOCK_METHOD2(SendNACK, int32_t(const uint16_t* nack_list, uint16_t size));
MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers));
MOCK_METHOD2(SetStorePacketsStatus,
@@ -160,19 +166,21 @@
int32_t(uint8_t key, uint16_t time_ms, uint8_t level));
MOCK_METHOD1(SetAudioLevel, int32_t(uint8_t level_dbov));
MOCK_METHOD1(SetTargetSendBitrate, void(uint32_t bitrate_bps));
- MOCK_METHOD2(SetUlpfecConfig,
- void(int red_payload_type, int fec_payload_type));
- MOCK_METHOD2(SetFecParameters,
- bool(const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params));
MOCK_METHOD1(SetKeyFrameRequestMethod, int32_t(KeyFrameRequestMethod method));
MOCK_METHOD0(RequestKeyFrame, int32_t());
+ MOCK_METHOD3(SendLossNotification,
+ int32_t(uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag));
MOCK_METHOD0(Process, void());
MOCK_METHOD1(RegisterSendChannelRtpStatisticsCallback,
void(StreamDataCountersCallback*));
MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback,
StreamDataCountersCallback*(void));
MOCK_METHOD1(SetVideoBitrateAllocation, void(const VideoBitrateAllocation&));
+ MOCK_METHOD0(RtpSender, RTPSender*());
+ MOCK_CONST_METHOD0(RtpSender, const RTPSender*());
+
// Members.
unsigned int remote_ssrc_;
diff --git a/modules/rtp_rtcp/source/contributing_sources.h b/modules/rtp_rtcp/source/contributing_sources.h
index 5e34539..81bf725 100644
--- a/modules/rtp_rtcp/source/contributing_sources.h
+++ b/modules/rtp_rtcp/source/contributing_sources.h
@@ -18,8 +18,8 @@
#include "absl/types/optional.h"
#include "api/array_view.h"
-#include "api/rtpreceiverinterface.h" // For RtpSource
-#include "rtc_base/timeutils.h" // For kNumMillisecsPerSec
+#include "api/rtp_receiver_interface.h" // For RtpSource
+#include "rtc_base/time_utils.h" // For kNumMillisecsPerSec
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/contributing_sources_unittest.cc b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
index 5f1d8d3..38d25ce 100644
--- a/modules/rtp_rtcp/source/contributing_sources_unittest.cc
+++ b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
@@ -10,7 +10,7 @@
#include "modules/rtp_rtcp/source/contributing_sources.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "test/gmock.h"
#include "test/gtest.h"
diff --git a/modules/rtp_rtcp/source/dtmf_queue.h b/modules/rtp_rtcp/source/dtmf_queue.h
index e5955a1..28116bc 100644
--- a/modules/rtp_rtcp/source/dtmf_queue.h
+++ b/modules/rtp_rtcp/source/dtmf_queue.h
@@ -14,7 +14,7 @@
#include <stdint.h>
#include <list>
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
class DtmfQueue {
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
index b813340..e3cb0e9 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
@@ -12,11 +12,11 @@
#include <string.h>
+#include "api/scoped_refptr.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/scoped_ref_ptr.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
index 5da378c..3d19eda 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
@@ -13,13 +13,13 @@
#include <memory>
#include <utility>
+#include "api/scoped_refptr.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
#include "modules/rtp_rtcp/source/forward_error_correction.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "rtc_base/checks.h"
#include "rtc_base/random.h"
-#include "rtc_base/scoped_ref_ptr.h"
#include "test/gmock.h"
#include "test/gtest.h"
diff --git a/modules/rtp_rtcp/source/flexfec_receiver.cc b/modules/rtp_rtcp/source/flexfec_receiver.cc
index 1a62bce..1750927 100644
--- a/modules/rtp_rtcp/source/flexfec_receiver.cc
+++ b/modules/rtp_rtcp/source/flexfec_receiver.cc
@@ -13,9 +13,9 @@
#include <string.h>
#include "api/array_view.h"
+#include "api/scoped_refptr.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/scoped_ref_ptr.h"
namespace webrtc {
@@ -36,12 +36,22 @@
uint32_t ssrc,
uint32_t protected_media_ssrc,
RecoveredPacketReceiver* recovered_packet_receiver)
+ : FlexfecReceiver(Clock::GetRealTimeClock(),
+ ssrc,
+ protected_media_ssrc,
+ recovered_packet_receiver) {}
+
+FlexfecReceiver::FlexfecReceiver(
+ Clock* clock,
+ uint32_t ssrc,
+ uint32_t protected_media_ssrc,
+ RecoveredPacketReceiver* recovered_packet_receiver)
: ssrc_(ssrc),
protected_media_ssrc_(protected_media_ssrc),
erasure_code_(
ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
recovered_packet_receiver_(recovered_packet_receiver),
- clock_(Clock::GetRealTimeClock()),
+ clock_(clock),
last_recovered_packet_ms_(-1) {
// It's OK to create this object on a different thread/task queue than
// the one used during main operation.
diff --git a/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc b/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc
index 378cf7d..d19e575 100644
--- a/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc
@@ -49,8 +49,10 @@
FlexfecReceiverForTest(uint32_t ssrc,
uint32_t protected_media_ssrc,
RecoveredPacketReceiver* recovered_packet_receiver)
- : FlexfecReceiver(ssrc, protected_media_ssrc, recovered_packet_receiver) {
- }
+ : FlexfecReceiver(Clock::GetRealTimeClock(),
+ ssrc,
+ protected_media_ssrc,
+ recovered_packet_receiver) {}
// Expose methods for tests.
using FlexfecReceiver::AddReceivedPacket;
using FlexfecReceiver::ProcessReceivedPacket;
@@ -466,7 +468,7 @@
} loopback_recovered_packet_receiver;
// Feed recovered packets back into |receiver|.
- FlexfecReceiver receiver(kFlexfecSsrc, kMediaSsrc,
+ FlexfecReceiver receiver(Clock::GetRealTimeClock(), kFlexfecSsrc, kMediaSsrc,
&loopback_recovered_packet_receiver);
loopback_recovered_packet_receiver.SetReceiver(&receiver);
@@ -590,7 +592,7 @@
} loopback_recovered_packet_receiver;
// Feed recovered packets back into |receiver|.
- FlexfecReceiver receiver(kFlexfecSsrc, kMediaSsrc,
+ FlexfecReceiver receiver(Clock::GetRealTimeClock(), kFlexfecSsrc, kMediaSsrc,
&loopback_recovered_packet_receiver);
loopback_recovered_packet_receiver.SetReceiver(&receiver);
diff --git a/modules/rtp_rtcp/source/flexfec_sender.cc b/modules/rtp_rtcp/source/flexfec_sender.cc
index 1204b2d..02fee86 100644
--- a/modules/rtp_rtcp/source/flexfec_sender.cc
+++ b/modules/rtp_rtcp/source/flexfec_sender.cc
@@ -126,6 +126,7 @@
for (const auto* fec_packet : ulpfec_generator_.generated_fec_packets_) {
std::unique_ptr<RtpPacketToSend> fec_packet_to_send(
new RtpPacketToSend(&rtp_header_extension_map_));
+ fec_packet_to_send->set_is_fec(true);
// RTP header.
fec_packet_to_send->SetMarker(false);
diff --git a/modules/rtp_rtcp/source/flexfec_sender_unittest.cc b/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
index ddc2805..c561dbb 100644
--- a/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
@@ -10,7 +10,7 @@
#include <vector>
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/fec_test_helper.h"
diff --git a/modules/rtp_rtcp/source/forward_error_correction.h b/modules/rtp_rtcp/source/forward_error_correction.h
index adb7572..b442273 100644
--- a/modules/rtp_rtcp/source/forward_error_correction.h
+++ b/modules/rtp_rtcp/source/forward_error_correction.h
@@ -17,10 +17,10 @@
#include <memory>
#include <vector>
+#include "api/scoped_refptr.h"
#include "modules/include/module_fec_types.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
-#include "rtc_base/scoped_ref_ptr.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
index 7ecec76..864befe 100644
--- a/modules/rtp_rtcp/source/nack_rtx_unittest.cc
+++ b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -14,14 +14,18 @@
#include <memory>
#include <set>
+#include "absl/memory/memory.h"
#include "api/call/transport.h"
+#include "api/transport/field_trial_based_config.h"
#include "call/rtp_stream_receiver_controller.h"
#include "call/rtx_receive_stream.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
#include "rtc_base/rate_limiter.h"
#include "test/gtest.h"
@@ -132,8 +136,10 @@
configuration.receive_statistics = receive_statistics_.get();
configuration.outgoing_transport = &transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
- rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration);
-
+ rtp_rtcp_module_ = absl::WrapUnique(RtpRtcp::CreateRtpRtcp(configuration));
+ rtp_sender_video_ = absl::make_unique<RTPSenderVideo>(
+ &fake_clock, rtp_rtcp_module_->RtpSender(), nullptr,
+ &playout_delay_oracle_, nullptr, false, FieldTrialBasedConfig());
rtp_rtcp_module_->SetSSRC(kTestSsrc);
rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound);
rtp_rtcp_module_->SetStorePacketsStatus(true, 600);
@@ -146,9 +152,9 @@
// single rtp_rtcp module for both send and receive side.
rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc);
- rtp_rtcp_module_->RegisterVideoSendPayload(kPayloadType, "video");
+ rtp_sender_video_->RegisterPayloadType(kPayloadType, "video");
rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
- transport_.SetSendModule(rtp_rtcp_module_);
+ transport_.SetSendModule(rtp_rtcp_module_.get());
media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
kTestSsrc, &media_stream_);
@@ -203,9 +209,11 @@
uint16_t nack_list[kVideoNackListSize];
for (int frame = 0; frame < kNumFrames; ++frame) {
RTPVideoHeader video_header;
- EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
+ EXPECT_TRUE(rtp_rtcp_module_->OnSendingRtpFrame(timestamp, timestamp / 90,
+ kPayloadType, false));
+ EXPECT_TRUE(rtp_sender_video_->SendVideo(
webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
- payload_data, payload_data_length, nullptr, &video_header, nullptr));
+ payload_data, payload_data_length, nullptr, &video_header, 0));
// Min required delay until retransmit = 5 + RTT ms (RTT = 0).
fake_clock.AdvanceTimeMilliseconds(5);
int length = BuildNackList(nack_list);
@@ -219,10 +227,10 @@
media_stream_.sequence_numbers_.sort();
}
- void TearDown() override { delete rtp_rtcp_module_; }
-
std::unique_ptr<ReceiveStatistics> receive_statistics_;
- RtpRtcp* rtp_rtcp_module_;
+ std::unique_ptr<RtpRtcp> rtp_rtcp_module_;
+ PlayoutDelayOracle playout_delay_oracle_;
+ std::unique_ptr<RTPSenderVideo> rtp_sender_video_;
RtxLoopBackTransport transport_;
const std::map<int, int> rtx_associated_payload_types_ = {
{kRtxPayloadType, kPayloadType}};
@@ -252,9 +260,11 @@
// enough packets.
for (int frame = 0; frame < kNumFrames; ++frame) {
RTPVideoHeader video_header;
- EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
+ EXPECT_TRUE(rtp_rtcp_module_->OnSendingRtpFrame(timestamp, timestamp / 90,
+ kPayloadType, false));
+ EXPECT_TRUE(rtp_sender_video_->SendVideo(
webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
- payload_data, payload_data_length, nullptr, &video_header, nullptr));
+ payload_data, payload_data_length, nullptr, &video_header, 0));
// Prepare next frame.
timestamp += 3000;
fake_clock.AdvanceTimeMilliseconds(33);
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle.cc b/modules/rtp_rtcp/source/playout_delay_oracle.cc
index dc33fad..e3e13fd 100644
--- a/modules/rtp_rtcp/source/playout_delay_oracle.cc
+++ b/modules/rtp_rtcp/source/playout_delay_oracle.cc
@@ -8,57 +8,82 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <algorithm>
+
#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
-#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
namespace webrtc {
-PlayoutDelayOracle::PlayoutDelayOracle()
- : high_sequence_number_(0),
- send_playout_delay_(false),
- ssrc_(0),
- playout_delay_{-1, -1} {}
+PlayoutDelayOracle::PlayoutDelayOracle() = default;
-PlayoutDelayOracle::~PlayoutDelayOracle() {}
+PlayoutDelayOracle::~PlayoutDelayOracle() = default;
-void PlayoutDelayOracle::UpdateRequest(uint32_t ssrc,
- PlayoutDelay playout_delay,
- uint16_t seq_num) {
+absl::optional<PlayoutDelay> PlayoutDelayOracle::PlayoutDelayToSend(
+ PlayoutDelay requested_delay) const {
rtc::CritScope lock(&crit_sect_);
- RTC_DCHECK_LE(playout_delay.min_ms, PlayoutDelayLimits::kMaxMs);
- RTC_DCHECK_LE(playout_delay.max_ms, PlayoutDelayLimits::kMaxMs);
- RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
- int64_t unwrapped_seq_num = unwrapper_.Unwrap(seq_num);
- if (playout_delay.min_ms >= 0 &&
- playout_delay.min_ms != playout_delay_.min_ms) {
- send_playout_delay_ = true;
- playout_delay_.min_ms = playout_delay.min_ms;
- high_sequence_number_ = unwrapped_seq_num;
+ if (requested_delay.min_ms > PlayoutDelayLimits::kMaxMs ||
+ requested_delay.max_ms > PlayoutDelayLimits::kMaxMs) {
+ RTC_DLOG(LS_ERROR)
+ << "Requested playout delay values out of range, ignored";
+ return absl::nullopt;
+ }
+ if (requested_delay.max_ms != -1 &&
+ requested_delay.min_ms > requested_delay.max_ms) {
+ RTC_DLOG(LS_ERROR) << "Requested playout delay values out of order";
+ return absl::nullopt;
+ }
+ if ((requested_delay.min_ms == -1 ||
+ requested_delay.min_ms == latest_delay_.min_ms) &&
+ (requested_delay.max_ms == -1 ||
+ requested_delay.max_ms == latest_delay_.max_ms)) {
+ // Unchanged.
+ return unacked_sequence_number_ ? absl::make_optional(latest_delay_)
+ : absl::nullopt;
+ }
+ if (requested_delay.min_ms == -1) {
+ RTC_DCHECK_GE(requested_delay.max_ms, 0);
+ requested_delay.min_ms =
+ std::min(latest_delay_.min_ms, requested_delay.max_ms);
+ }
+ if (requested_delay.max_ms == -1) {
+ requested_delay.max_ms =
+ std::max(latest_delay_.max_ms, requested_delay.min_ms);
+ }
+ return requested_delay;
+}
+
+void PlayoutDelayOracle::OnSentPacket(uint16_t sequence_number,
+ absl::optional<PlayoutDelay> delay) {
+ rtc::CritScope lock(&crit_sect_);
+ int64_t unwrapped_sequence_number = unwrapper_.Unwrap(sequence_number);
+
+ if (!delay) {
+ return;
}
- if (playout_delay.max_ms >= 0 &&
- playout_delay.max_ms != playout_delay_.max_ms) {
- send_playout_delay_ = true;
- playout_delay_.max_ms = playout_delay.max_ms;
- high_sequence_number_ = unwrapped_seq_num;
+ RTC_DCHECK_LE(0, delay->min_ms);
+ RTC_DCHECK_LE(delay->max_ms, PlayoutDelayLimits::kMaxMs);
+ RTC_DCHECK_LE(delay->min_ms, delay->max_ms);
+
+ if (delay->min_ms != latest_delay_.min_ms ||
+ delay->max_ms != latest_delay_.max_ms) {
+ latest_delay_ = *delay;
+ unacked_sequence_number_ = unwrapped_sequence_number;
}
- ssrc_ = ssrc;
}
// If an ACK is received on the packet containing the playout delay extension,
// we stop sending the extension on future packets.
-void PlayoutDelayOracle::OnReceivedRtcpReportBlocks(
- const ReportBlockList& report_blocks) {
+void PlayoutDelayOracle::OnReceivedAck(
+ int64_t extended_highest_sequence_number) {
rtc::CritScope lock(&crit_sect_);
- for (const RTCPReportBlock& report_block : report_blocks) {
- if ((ssrc_ == report_block.source_ssrc) && send_playout_delay_ &&
- (report_block.extended_highest_sequence_number >
- high_sequence_number_)) {
- send_playout_delay_ = false;
- }
+ if (unacked_sequence_number_ &&
+ extended_highest_sequence_number > *unacked_sequence_number_) {
+ unacked_sequence_number_ = absl::nullopt;
}
}
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle.h b/modules/rtp_rtcp/source/playout_delay_oracle.h
index 0e3bd39..6451be4 100644
--- a/modules/rtp_rtcp/source/playout_delay_oracle.h
+++ b/modules/rtp_rtcp/source/playout_delay_oracle.h
@@ -13,11 +13,12 @@
#include <stdint.h>
+#include "absl/types/optional.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/include/module_common_types_public.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@@ -33,47 +34,39 @@
// The application specifies a minimum and maximum limit for the playout delay
// which are both communicated to the receiver and the receiver can adapt
// the playout delay within this range based on observed network jitter.
-class PlayoutDelayOracle {
+class PlayoutDelayOracle : public RtcpAckObserver {
public:
PlayoutDelayOracle();
- ~PlayoutDelayOracle();
+ ~PlayoutDelayOracle() override;
- // Returns true if the current frame should include the playout delay
- // extension
- bool send_playout_delay() const {
- rtc::CritScope lock(&crit_sect_);
- return send_playout_delay_;
- }
+ // The playout delay to be added to a packet. The input delays are provided by
+ // the application, with -1 meaning unchanged/unspecified. The output delay
+ // are the values to be attached to packets on the wire. Presence and value
+ // depends on the current input, previous inputs, and received acks from the
+ // remote end.
+ absl::optional<PlayoutDelay> PlayoutDelayToSend(
+ PlayoutDelay requested_delay) const;
- // Returns current playout delay.
- PlayoutDelay playout_delay() const {
- rtc::CritScope lock(&crit_sect_);
- return playout_delay_;
- }
+ void OnSentPacket(uint16_t sequence_number,
+ absl::optional<PlayoutDelay> playout_delay);
- // Updates the application requested playout delay, current ssrc
- // and the current sequence number.
- void UpdateRequest(uint32_t ssrc,
- PlayoutDelay playout_delay,
- uint16_t seq_num);
-
- void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks);
+ void OnReceivedAck(int64_t extended_highest_sequence_number) override;
private:
// The playout delay information is updated from the encoder thread(s).
// The sequence number feedback is updated from the worker thread.
// Guards access to data across multiple threads.
rtc::CriticalSection crit_sect_;
- // The current highest sequence number on which playout delay has been sent.
- int64_t high_sequence_number_ RTC_GUARDED_BY(crit_sect_);
- // Indicates whether the playout delay should go on the next frame.
- bool send_playout_delay_ RTC_GUARDED_BY(crit_sect_);
- // Sender ssrc.
- uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
- // Sequence number unwrapper.
+ // The oldest sequence number on which the current playout delay values have
+ // been sent. When set, it means we need to attach extension to sent packets.
+ absl::optional<int64_t> unacked_sequence_number_ RTC_GUARDED_BY(crit_sect_);
+ // Sequence number unwrapper for sent packets.
+
+ // TODO(nisse): Could potentially get out of sync with the unwrapper used by
+ // the caller of OnReceivedAck.
SequenceNumberUnwrapper unwrapper_ RTC_GUARDED_BY(crit_sect_);
// Playout delay values on the next frame if |send_playout_delay_| is set.
- PlayoutDelay playout_delay_ RTC_GUARDED_BY(crit_sect_);
+ PlayoutDelay latest_delay_ RTC_GUARDED_BY(crit_sect_) = {-1, -1};
RTC_DISALLOW_COPY_AND_ASSIGN(PlayoutDelayOracle);
};
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc b/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc
index 099339d..3857e9b 100644
--- a/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc
+++ b/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc
@@ -16,54 +16,37 @@
namespace webrtc {
namespace {
-constexpr int kSsrc = 100;
constexpr int kSequenceNumber = 100;
constexpr int kMinPlayoutDelay = 0;
constexpr int kMaxPlayoutDelay = 150;
} // namespace
-class PlayoutDelayOracleTest : public ::testing::Test {
- protected:
- void ReportRTCPFeedback(int ssrc, int seq_num) {
- RTCPReportBlock report_block;
- report_block.source_ssrc = ssrc;
- report_block.extended_highest_sequence_number = seq_num;
- report_blocks_.push_back(report_block);
- playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks_);
- }
-
- ReportBlockList report_blocks_;
- PlayoutDelayOracle playout_delay_oracle_;
-};
-
-TEST_F(PlayoutDelayOracleTest, DisabledByDefault) {
- EXPECT_FALSE(playout_delay_oracle_.send_playout_delay());
- EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().min_ms);
- EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().max_ms);
+TEST(PlayoutDelayOracleTest, DisabledByDefault) {
+ PlayoutDelayOracle playout_delay_oracle;
+ EXPECT_FALSE(playout_delay_oracle.PlayoutDelayToSend({-1, -1}));
}
-TEST_F(PlayoutDelayOracleTest, SendPlayoutDelayUntilSeqNumberExceeds) {
+TEST(PlayoutDelayOracleTest, SendPlayoutDelayUntilSeqNumberExceeds) {
+ PlayoutDelayOracle playout_delay_oracle;
PlayoutDelay playout_delay = {kMinPlayoutDelay, kMaxPlayoutDelay};
- playout_delay_oracle_.UpdateRequest(kSsrc, playout_delay, kSequenceNumber);
- EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
- EXPECT_EQ(kMinPlayoutDelay, playout_delay_oracle_.playout_delay().min_ms);
- EXPECT_EQ(kMaxPlayoutDelay, playout_delay_oracle_.playout_delay().max_ms);
+ playout_delay_oracle.OnSentPacket(kSequenceNumber, playout_delay);
+ absl::optional<PlayoutDelay> delay_to_send =
+ playout_delay_oracle.PlayoutDelayToSend({-1, -1});
+ ASSERT_TRUE(delay_to_send.has_value());
+ EXPECT_EQ(kMinPlayoutDelay, delay_to_send->min_ms);
+ EXPECT_EQ(kMaxPlayoutDelay, delay_to_send->max_ms);
// Oracle indicates playout delay should be sent if highest sequence number
// acked is lower than the sequence number of the first packet containing
// playout delay.
- ReportRTCPFeedback(kSsrc, kSequenceNumber - 1);
- EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
-
- // An invalid ssrc feedback report is dropped by the oracle.
- ReportRTCPFeedback(kSsrc + 1, kSequenceNumber + 1);
- EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
+ playout_delay_oracle.OnReceivedAck(kSequenceNumber - 1);
+ EXPECT_TRUE(playout_delay_oracle.PlayoutDelayToSend({-1, -1}));
// Oracle indicates playout delay should not be sent if sequence number
// acked on a matching ssrc indicates the receiver has received the playout
// delay values.
- ReportRTCPFeedback(kSsrc, kSequenceNumber + 1);
- EXPECT_FALSE(playout_delay_oracle_.send_playout_delay());
+ playout_delay_oracle.OnReceivedAck(kSequenceNumber + 1);
+ EXPECT_FALSE(playout_delay_oracle.PlayoutDelayToSend({-1, -1}));
}
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.cc b/modules/rtp_rtcp/source/receive_statistics_impl.cc
index bc742d1..066dc4b 100644
--- a/modules/rtp_rtcp/source/receive_statistics_impl.cc
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -48,11 +48,10 @@
last_receive_time_ms_(0),
last_received_timestamp_(0),
received_seq_first_(0),
- received_seq_max_(0),
- received_seq_wraps_(0),
+ received_seq_max_(-1),
last_report_inorder_packets_(0),
last_report_old_packets_(0),
- last_report_seq_max_(0),
+ last_report_seq_max_(-1),
rtcp_callback_(rtcp_callback),
rtp_callback_(rtp_callback) {}
@@ -64,54 +63,75 @@
rtp_callback_->DataCountersUpdated(counters, ssrc_);
}
+bool StreamStatisticianImpl::UpdateOutOfOrder(const RtpPacketReceived& packet,
+ int64_t sequence_number,
+ int64_t now_ms) {
+ RTC_DCHECK_EQ(sequence_number,
+ seq_unwrapper_.UnwrapWithoutUpdate(packet.SequenceNumber()));
+
+ // Check if |packet| is second packet of a stream restart.
+ if (received_seq_out_of_order_) {
+ uint16_t expected_sequence_number = *received_seq_out_of_order_ + 1;
+ received_seq_out_of_order_ = absl::nullopt;
+ if (packet.SequenceNumber() == expected_sequence_number) {
+ // Ignore sequence number gap caused by stream restart for next packet
+ // loss calculation.
+ last_report_seq_max_ = sequence_number;
+ last_report_inorder_packets_ = receive_counters_.transmitted.packets -
+ receive_counters_.retransmitted.packets;
+ // As final part of stream restart consider |packet| is not out of order.
+ return false;
+ }
+ }
+
+ if (std::abs(sequence_number - received_seq_max_) >
+ max_reordering_threshold_) {
+ // Sequence number gap looks too large, wait until next packet to check
+ // for a stream restart.
+ received_seq_out_of_order_ = packet.SequenceNumber();
+ return true;
+ }
+
+ if (sequence_number > received_seq_max_)
+ return false;
+
+ // Old out of order packet, may be retransmit.
+ if (enable_retransmit_detection_ && IsRetransmitOfOldPacket(packet, now_ms))
+ receive_counters_.retransmitted.AddPacket(packet);
+ return true;
+}
+
StreamDataCounters StreamStatisticianImpl::UpdateCounters(
const RtpPacketReceived& packet) {
rtc::CritScope cs(&stream_lock_);
RTC_DCHECK_EQ(ssrc_, packet.Ssrc());
- uint16_t sequence_number = packet.SequenceNumber();
- bool in_order =
- // First packet is always in order.
- last_receive_time_ms_ == 0 ||
- IsNewerSequenceNumber(sequence_number, received_seq_max_) ||
- // If we have a restart of the remote side this packet is still in order.
- !IsNewerSequenceNumber(sequence_number,
- received_seq_max_ - max_reordering_threshold_);
int64_t now_ms = clock_->TimeInMilliseconds();
incoming_bitrate_.Update(packet.size(), now_ms);
receive_counters_.transmitted.AddPacket(packet);
- if (!in_order && enable_retransmit_detection_ &&
- IsRetransmitOfOldPacket(packet, now_ms)) {
- receive_counters_.retransmitted.AddPacket(packet);
- }
- if (receive_counters_.transmitted.packets == 1) {
- received_seq_first_ = packet.SequenceNumber();
+ int64_t sequence_number =
+ seq_unwrapper_.UnwrapWithoutUpdate(packet.SequenceNumber());
+ if (!ReceivedRtpPacket()) {
+ received_seq_first_ = sequence_number;
+ last_report_seq_max_ = sequence_number - 1;
receive_counters_.first_packet_time_ms = now_ms;
+ } else if (UpdateOutOfOrder(packet, sequence_number, now_ms)) {
+ return receive_counters_;
}
+ // In order packet.
+ received_seq_max_ = sequence_number;
+ seq_unwrapper_.UpdateLast(sequence_number);
- // Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6
- // are received, 4 will be ignored.
- if (in_order) {
- // Wrong if we use RetransmitOfOldPacket.
- if (receive_counters_.transmitted.packets > 1 &&
- received_seq_max_ > packet.SequenceNumber()) {
- // Wrap around detected.
- received_seq_wraps_++;
- }
- // New max.
- received_seq_max_ = packet.SequenceNumber();
-
- // If new time stamp and more than one in-order packet received, calculate
- // new jitter statistics.
- if (packet.Timestamp() != last_received_timestamp_ &&
- (receive_counters_.transmitted.packets -
- receive_counters_.retransmitted.packets) > 1) {
- UpdateJitter(packet, now_ms);
- }
- last_received_timestamp_ = packet.Timestamp();
- last_receive_time_ms_ = now_ms;
+ // If new time stamp and more than one in-order packet received, calculate
+ // new jitter statistics.
+ if (packet.Timestamp() != last_received_timestamp_ &&
+ (receive_counters_.transmitted.packets -
+ receive_counters_.retransmitted.packets) > 1) {
+ UpdateJitter(packet, now_ms);
}
+ last_received_timestamp_ = packet.Timestamp();
+ last_receive_time_ms_ = now_ms;
return receive_counters_;
}
@@ -163,9 +183,7 @@
bool reset) {
{
rtc::CritScope cs(&stream_lock_);
- if (received_seq_first_ == 0 &&
- receive_counters_.transmitted.payload_bytes == 0) {
- // We have not received anything.
+ if (!ReceivedRtpPacket()) {
return false;
}
@@ -196,9 +214,7 @@
// Not active.
return false;
}
- if (received_seq_first_ == 0 &&
- receive_counters_.transmitted.payload_bytes == 0) {
- // We have not received anything.
+ if (!ReceivedRtpPacket()) {
return false;
}
@@ -212,19 +228,9 @@
RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() {
RtcpStatistics stats;
-
- if (last_report_inorder_packets_ == 0) {
- // First time we send a report.
- last_report_seq_max_ = received_seq_first_ - 1;
- }
-
// Calculate fraction lost.
- uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
-
- if (last_report_seq_max_ > received_seq_max_) {
- // Can we assume that the seq_num can't go decrease over a full RTCP period?
- exp_since_last = 0;
- }
+ int64_t exp_since_last = received_seq_max_ - last_report_seq_max_;
+ RTC_DCHECK_GE(exp_since_last, 0);
// Number of received RTP packets since last report, counts all packets but
// not re-transmissions.
@@ -261,7 +267,7 @@
cumulative_loss_ += missing;
stats.packets_lost = cumulative_loss_;
stats.extended_highest_sequence_number =
- (received_seq_wraps_ << 16) + received_seq_max_;
+ static_cast<uint32_t>(received_seq_max_);
// Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
stats.jitter = jitter_q4_ >> 4;
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.h b/modules/rtp_rtcp/source/receive_statistics_impl.h
index 8153c44..c153281 100644
--- a/modules/rtp_rtcp/source/receive_statistics_impl.h
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.h
@@ -17,7 +17,9 @@
#include <map>
#include <vector>
-#include "rtc_base/criticalsection.h"
+#include "absl/types/optional.h"
+#include "modules/include/module_common_types_public.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/rate_statistics.h"
#include "rtc_base/thread_annotations.h"
@@ -58,7 +60,18 @@
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
void UpdateJitter(const RtpPacketReceived& packet, int64_t receive_time_ms)
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
+ // Updates StreamStatistician for out of order packets.
+ // Returns true if packet considered to be out of order.
+ bool UpdateOutOfOrder(const RtpPacketReceived& packet,
+ int64_t sequence_number,
+ int64_t now_ms)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
+ // Updates StreamStatistician for incoming packets.
StreamDataCounters UpdateCounters(const RtpPacketReceived& packet);
+ // Checks if this StreamStatistician received any rtp packets.
+ bool ReceivedRtpPacket() const RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_) {
+ return received_seq_max_ >= 0;
+ }
const uint32_t ssrc_;
Clock* const clock_;
@@ -74,9 +87,13 @@
int64_t last_receive_time_ms_ RTC_GUARDED_BY(&stream_lock_);
uint32_t last_received_timestamp_ RTC_GUARDED_BY(&stream_lock_);
- uint16_t received_seq_first_ RTC_GUARDED_BY(&stream_lock_);
- uint16_t received_seq_max_ RTC_GUARDED_BY(&stream_lock_);
- uint16_t received_seq_wraps_ RTC_GUARDED_BY(&stream_lock_);
+ SequenceNumberUnwrapper seq_unwrapper_ RTC_GUARDED_BY(&stream_lock_);
+ int64_t received_seq_first_ RTC_GUARDED_BY(&stream_lock_);
+ int64_t received_seq_max_ RTC_GUARDED_BY(&stream_lock_);
+ // Assume that the other side restarted when there are two sequential packets
+ // with large jump from received_seq_max_.
+ absl::optional<uint16_t> received_seq_out_of_order_
+ RTC_GUARDED_BY(&stream_lock_);
// Current counter values.
StreamDataCounters receive_counters_ RTC_GUARDED_BY(&stream_lock_);
@@ -84,7 +101,7 @@
// Counter values when we sent the last report.
uint32_t last_report_inorder_packets_ RTC_GUARDED_BY(&stream_lock_);
uint32_t last_report_old_packets_ RTC_GUARDED_BY(&stream_lock_);
- uint16_t last_report_seq_max_ RTC_GUARDED_BY(&stream_lock_);
+ int64_t last_report_seq_max_ RTC_GUARDED_BY(&stream_lock_);
RtcpStatistics last_reported_statistics_ RTC_GUARDED_BY(&stream_lock_);
// stream_lock_ shouldn't be held when calling callbacks.
diff --git a/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
index 2539363..1703cee 100644
--- a/modules/rtp_rtcp/source/receive_statistics_unittest.cc
+++ b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
@@ -295,6 +295,217 @@
EXPECT_EQ(177u, statistics.jitter);
}
+TEST_F(ReceiveStatisticsTest, SimpleLossComputation) {
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(3);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(4);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(5);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ RtcpStatistics statistics;
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ // 20% = 51/255.
+ EXPECT_EQ(51u, statistics.fraction_lost);
+ EXPECT_EQ(1, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, LossComputationWithReordering) {
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(3);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(2);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(5);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ RtcpStatistics statistics;
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ // 20% = 51/255.
+ EXPECT_EQ(51u, statistics.fraction_lost);
+ EXPECT_EQ(1, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, LossComputationWithDuplicates) {
+ // Lose 2 packets, but also receive 1 duplicate. Should actually count as
+ // only 1 packet being lost.
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(4);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(4);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(5);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ RtcpStatistics statistics;
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ // 20% = 51/255.
+ EXPECT_EQ(51u, statistics.fraction_lost);
+ EXPECT_EQ(1, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, LossComputationWithSequenceNumberWrapping) {
+ // First, test loss computation over a period that included a sequence number
+ // rollover.
+ packet1_.SetSequenceNumber(0xfffd);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(0);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(0xfffe);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ // Only one packet was actually lost, 0xffff.
+ RtcpStatistics statistics;
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ // 20% = 51/255.
+ EXPECT_EQ(51u, statistics.fraction_lost);
+ EXPECT_EQ(1, statistics.packets_lost);
+
+ // Now test losing one packet *after* the rollover.
+ packet1_.SetSequenceNumber(3);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ // 50% = 127/255.
+ EXPECT_EQ(127u, statistics.fraction_lost);
+ EXPECT_EQ(2, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, StreamRestartDoesntCountAsLoss) {
+ RtcpStatistics statistics;
+ receive_statistics_->SetMaxReorderingThreshold(200);
+
+ packet1_.SetSequenceNumber(0);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ packet1_.SetSequenceNumber(400);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0, statistics.fraction_lost);
+ EXPECT_EQ(0, statistics.packets_lost);
+
+ packet1_.SetSequenceNumber(401);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0, statistics.fraction_lost);
+ EXPECT_EQ(0, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, CountsLossAfterStreamRestart) {
+ RtcpStatistics statistics;
+ receive_statistics_->SetMaxReorderingThreshold(200);
+
+ packet1_.SetSequenceNumber(0);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ packet1_.SetSequenceNumber(400);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(401);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(403);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(1, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, StreamCanRestartAtSequenceNumberWrapAround) {
+ RtcpStatistics statistics;
+ receive_statistics_->SetMaxReorderingThreshold(200);
+
+ packet1_.SetSequenceNumber(0xffff - 401);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(0xffff - 400);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ packet1_.SetSequenceNumber(0xffff);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(0);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(2);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(1, statistics.packets_lost);
+}
+
+TEST_F(ReceiveStatisticsTest, StreamRestartNeedsTwoConsecutivePackets) {
+ RtcpStatistics statistics;
+ receive_statistics_->SetMaxReorderingThreshold(200);
+
+ packet1_.SetSequenceNumber(400);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(401);
+ receive_statistics_->OnRtpPacket(packet1_);
+
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ packet1_.SetSequenceNumber(3);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(401u, statistics.extended_highest_sequence_number);
+
+ packet1_.SetSequenceNumber(4);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(4u, statistics.extended_highest_sequence_number);
+}
+
+TEST_F(ReceiveStatisticsTest, WrapsAroundExtendedHighestSequenceNumber) {
+ RtcpStatistics statistics;
+ packet1_.SetSequenceNumber(0xffff);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0xffffu, statistics.extended_highest_sequence_number);
+
+ // Wrap around.
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0x10001u, statistics.extended_highest_sequence_number);
+
+ // Should be treated as out of order; shouldn't increment highest extended
+ // sequence number.
+ packet1_.SetSequenceNumber(0x10000 - 6);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0x10001u, statistics.extended_highest_sequence_number);
+
+ // Receive a couple packets then wrap around again.
+ receive_statistics_->SetMaxReorderingThreshold(200);
+ for (int i = 10; i < 0xffff; i += 150) {
+ packet1_.SetSequenceNumber(i);
+ receive_statistics_->OnRtpPacket(packet1_);
+ }
+ packet1_.SetSequenceNumber(1);
+ receive_statistics_->OnRtpPacket(packet1_);
+ receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+ true);
+ EXPECT_EQ(0x20001u, statistics.extended_highest_sequence_number);
+}
+
class RtpTestCallback : public StreamDataCountersCallback {
public:
RtpTestCallback()
diff --git a/modules/rtp_rtcp/source/rtcp_packet.cc b/modules/rtp_rtcp/source/rtcp_packet.cc
index 194b992..bac03e7 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -52,7 +52,8 @@
size_t RtcpPacket::HeaderLength() const {
size_t length_in_bytes = BlockLength();
RTC_DCHECK_GT(length_in_bytes, 0);
- RTC_DCHECK_EQ(length_in_bytes % 4, 0) << "Padding not supported";
+ RTC_DCHECK_EQ(length_in_bytes % 4, 0)
+ << "Padding must be handled by each subclass.";
// Length in 32-bit words without common header.
return (length_in_bytes - kHeaderLength) / 4;
}
@@ -71,12 +72,23 @@
size_t length,
uint8_t* buffer,
size_t* pos) {
+ CreateHeader(count_or_format, packet_type, length, /*padding=*/false, buffer,
+ pos);
+}
+
+void RtcpPacket::CreateHeader(
+ size_t count_or_format, // Depends on packet type.
+ uint8_t packet_type,
+ size_t length,
+ bool padding,
+ uint8_t* buffer,
+ size_t* pos) {
RTC_DCHECK_LE(length, 0xffffU);
RTC_DCHECK_LE(count_or_format, 0x1f);
constexpr uint8_t kVersionBits = 2 << 6;
- constexpr uint8_t kNoPaddingBit = 0 << 5;
+ uint8_t padding_bit = padding ? 1 << 5 : 0;
buffer[*pos + 0] =
- kVersionBits | kNoPaddingBit | static_cast<uint8_t>(count_or_format);
+ kVersionBits | padding_bit | static_cast<uint8_t>(count_or_format);
buffer[*pos + 1] = packet_type;
buffer[*pos + 2] = (length >> 8) & 0xff;
buffer[*pos + 3] = length & 0xff;
diff --git a/modules/rtp_rtcp/source/rtcp_packet.h b/modules/rtp_rtcp/source/rtcp_packet.h
index 40e51e8..94bf9f0 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/modules/rtp_rtcp/source/rtcp_packet.h
@@ -87,6 +87,13 @@
uint8_t* buffer,
size_t* pos);
+ static void CreateHeader(size_t count_or_format,
+ uint8_t packet_type,
+ size_t block_length, // Payload size in 32bit words.
+ bool padding, // True if there are padding bytes.
+ uint8_t* buffer,
+ size_t* pos);
+
bool OnBufferFull(uint8_t* packet,
size_t* index,
PacketReadyCallback callback) const;
diff --git a/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
index 89b7814..f521c7f 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
@@ -15,7 +15,7 @@
#include <vector>
#include "modules/rtp_rtcp/source/rtcp_packet.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
namespace rtcp {
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
index 2b5f9ca..561503a 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
@@ -44,7 +44,8 @@
// : type-specific block contents :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ExtendedReports::ExtendedReports() : sender_ssrc_(0) {}
-ExtendedReports::~ExtendedReports() {}
+ExtendedReports::ExtendedReports(const ExtendedReports& xr) = default;
+ExtendedReports::~ExtendedReports() = default;
bool ExtendedReports::Parse(const CommonHeader& packet) {
RTC_DCHECK_EQ(packet.type(), kPacketType);
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
index fd96769..4ae652c 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
@@ -30,6 +30,7 @@
static constexpr size_t kMaxNumberOfDlrrItems = 50;
ExtendedReports();
+ ExtendedReports(const ExtendedReports& xr);
~ExtendedReports() override;
// Parse assumes header is already parsed and validated.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.cc b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
index 517e991..fd4a4c9 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/fir.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
@@ -46,6 +46,8 @@
Fir::Fir() = default;
+Fir::Fir(const Fir& fir) = default;
+
Fir::~Fir() = default;
bool Fir::Parse(const CommonHeader& packet) {
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.h b/modules/rtp_rtcp/source/rtcp_packet/fir.h
index 6fbc54c..383dc96 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/fir.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.h
@@ -30,6 +30,7 @@
};
Fir();
+ Fir(const Fir& fir);
~Fir() override;
// Parse assumes header is already parsed and validated.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/loss_notification.cc b/modules/rtp_rtcp/source/rtcp_packet/loss_notification.cc
new file mode 100644
index 0000000..08c75dd
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/loss_notification.cc
@@ -0,0 +1,133 @@
+/*
+ * 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/rtcp_packet/loss_notification.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// Loss Notification
+// -----------------
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P| FMT=15 | PT=206 | length |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// 0 | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 8 | Unique identifier 'L' 'N' 'T' 'F' |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 | Last Decoded Sequence Number | Last Received SeqNum Delta |D|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+LossNotification::LossNotification()
+ : last_decoded_(0), last_received_(0), decodability_flag_(false) {}
+
+LossNotification::LossNotification(uint16_t last_decoded,
+ uint16_t last_received,
+ bool decodability_flag)
+ : last_decoded_(last_decoded),
+ last_received_(last_received),
+ decodability_flag_(decodability_flag) {}
+
+LossNotification::LossNotification(const LossNotification& rhs) = default;
+
+LossNotification::~LossNotification() = default;
+
+size_t LossNotification::BlockLength() const {
+ return kHeaderLength + kCommonFeedbackLength + kLossNotificationPayloadLength;
+}
+
+bool LossNotification::Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ PacketReadyCallback callback) const {
+ while (*index + BlockLength() > max_length) {
+ if (!OnBufferFull(packet, index, callback))
+ return false;
+ }
+
+ const size_t index_end = *index + BlockLength();
+
+ // Note: |index| updated by the function below.
+ CreateHeader(Psfb::kAfbMessageType, kPacketType, HeaderLength(), packet,
+ index);
+
+ CreateCommonFeedback(packet + *index);
+ *index += kCommonFeedbackLength;
+
+ ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier);
+ *index += sizeof(uint32_t);
+
+ ByteWriter<uint16_t>::WriteBigEndian(packet + *index, last_decoded_);
+ *index += sizeof(uint16_t);
+
+ const uint16_t last_received_delta = last_received_ - last_decoded_;
+ RTC_DCHECK_LE(last_received_delta, 0x7fff);
+ const uint16_t last_received_delta_and_decodability =
+ (last_received_delta << 1) | (decodability_flag_ ? 0x0001 : 0x0000);
+
+ ByteWriter<uint16_t>::WriteBigEndian(packet + *index,
+ last_received_delta_and_decodability);
+ *index += sizeof(uint16_t);
+
+ RTC_DCHECK_EQ(index_end, *index);
+ return true;
+}
+
+bool LossNotification::Parse(const CommonHeader& packet) {
+ RTC_DCHECK_EQ(packet.type(), kPacketType);
+ RTC_DCHECK_EQ(packet.fmt(), Psfb::kAfbMessageType);
+
+ if (packet.payload_size_bytes() <
+ kCommonFeedbackLength + kLossNotificationPayloadLength) {
+ return false;
+ }
+
+ const uint8_t* const payload = packet.payload();
+
+ if (ByteReader<uint32_t>::ReadBigEndian(&payload[8]) != kUniqueIdentifier) {
+ return false;
+ }
+
+ ParseCommonFeedback(payload);
+
+ last_decoded_ = ByteReader<uint16_t>::ReadBigEndian(&payload[12]);
+
+ const uint16_t last_received_delta_and_decodability =
+ ByteReader<uint16_t>::ReadBigEndian(&payload[14]);
+ last_received_ = last_decoded_ + (last_received_delta_and_decodability >> 1);
+ decodability_flag_ = (last_received_delta_and_decodability & 0x0001);
+
+ return true;
+}
+
+bool LossNotification::Set(uint16_t last_decoded,
+ uint16_t last_received,
+ bool decodability_flag) {
+ const uint16_t delta = last_received - last_decoded;
+ if (delta > 0x7fff) {
+ return false;
+ }
+ last_received_ = last_received;
+ last_decoded_ = last_decoded;
+ decodability_flag_ = decodability_flag;
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/loss_notification.h b/modules/rtp_rtcp/source/rtcp_packet/loss_notification.h
new file mode 100644
index 0000000..2603a67
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/loss_notification.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_LOSS_NOTIFICATION_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_LOSS_NOTIFICATION_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+#include "rtc_base/system/unused.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class LossNotification : public Psfb {
+ public:
+ LossNotification();
+ LossNotification(uint16_t last_decoded,
+ uint16_t last_received,
+ bool decodability_flag);
+ LossNotification(const LossNotification& other);
+ ~LossNotification() override;
+
+ size_t BlockLength() const override;
+
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ PacketReadyCallback callback) const override
+ RTC_WARN_UNUSED_RESULT;
+
+ // Parse assumes header is already parsed and validated.
+ bool Parse(const CommonHeader& packet) RTC_WARN_UNUSED_RESULT;
+
+ // Set all of the values transmitted by the loss notification message.
+ // If the values may not be represented by a loss notification message,
+ // false is returned, and no change is made to the object; this happens
+ // when |last_recieved| is ahead of |last_decoded| by more than 0x7fff.
+ // This is because |last_recieved| is represented on the wire as a delta,
+ // and only 15 bits are available for that delta.
+ bool Set(uint16_t last_decoded,
+ uint16_t last_received,
+ bool decodability_flag) RTC_WARN_UNUSED_RESULT;
+
+ // RTP sequence number of the first packet belong to the last decoded
+ // non-discardable frame.
+ uint16_t last_decoded() const { return last_decoded_; }
+
+ // RTP sequence number of the last received packet.
+ uint16_t last_received() const { return last_received_; }
+
+ // A decodability flag, whose specific meaning depends on the last-received
+ // RTP sequence number. The decodability flag is true if and only if all of
+ // the frame's dependencies are known to be decodable, and the frame itself
+ // is not yet known to be unassemblable.
+ // * Clarification #1: In a multi-packet frame, the first packet's
+ // dependencies are known, but it is not yet known whether all parts
+ // of the current frame will be received.
+ // * Clarification #2: In a multi-packet frame, the dependencies would be
+ // unknown if the first packet was not received. Then, the packet will
+ // be known-unassemblable.
+ bool decodability_flag() const { return decodability_flag_; }
+
+ private:
+ static constexpr uint32_t kUniqueIdentifier = 0x4C4E5446; // 'L' 'N' 'T' 'F'.
+ static constexpr size_t kLossNotificationPayloadLength = 8;
+
+ uint16_t last_decoded_;
+ uint16_t last_received_;
+ bool decodability_flag_;
+};
+} // namespace rtcp
+} // namespace webrtc
+#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_LOSS_NOTIFICATION_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/loss_notification_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/loss_notification_unittest.cc
new file mode 100644
index 0000000..6d74225
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/loss_notification_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ * 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/rtcp_packet/loss_notification.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+namespace webrtc {
+
+using ::testing::ElementsAreArray;
+using ::testing::make_tuple;
+using ::webrtc::rtcp::LossNotification;
+
+TEST(RtcpPacketLossNotificationTest, SetWithIllegalValuesFails) {
+ constexpr uint16_t kLastDecoded = 0x3c7b;
+ constexpr uint16_t kLastReceived = kLastDecoded + 0x7fff + 1;
+ constexpr bool kDecodabilityFlag = true;
+ LossNotification loss_notification;
+ EXPECT_FALSE(
+ loss_notification.Set(kLastDecoded, kLastReceived, kDecodabilityFlag));
+}
+
+TEST(RtcpPacketLossNotificationTest, SetWithLegalValuesSucceeds) {
+ constexpr uint16_t kLastDecoded = 0x3c7b;
+ constexpr uint16_t kLastReceived = kLastDecoded + 0x7fff;
+ constexpr bool kDecodabilityFlag = true;
+ LossNotification loss_notification;
+ EXPECT_TRUE(
+ loss_notification.Set(kLastDecoded, kLastReceived, kDecodabilityFlag));
+}
+
+TEST(RtcpPacketLossNotificationTest, CreateProducesExpectedWireFormat) {
+ // Note that (0x6542 >> 1) is used just to make the pattern in kPacket
+ // more apparent; there's nothing truly special about the value,
+ // it's only an implementation detail that last-received is represented
+ // as a delta from last-decoded, and that this delta is shifted before
+ // it's put on the wire.
+ constexpr uint16_t kLastDecoded = 0x3c7b;
+ constexpr uint16_t kLastReceived = kLastDecoded + (0x6542 >> 1);
+ constexpr bool kDecodabilityFlag = true;
+
+ const uint8_t kPacket[] = {0x8f, 206, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, //
+ 0xab, 0xcd, 0xef, 0x01, 'L', 'N', 'T', 'F', //
+ 0x3c, 0x7b, 0x65, 0x43};
+
+ LossNotification loss_notification;
+ loss_notification.SetSenderSsrc(0x12345678);
+ loss_notification.SetMediaSsrc(0xabcdef01);
+ ASSERT_TRUE(
+ loss_notification.Set(kLastDecoded, kLastReceived, kDecodabilityFlag));
+
+ rtc::Buffer packet = loss_notification.Build();
+
+ EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+ ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketLossNotificationTest,
+ ParseFailsOnTooSmallPacketToBeLossNotification) {
+ uint8_t packet[] = {0x8f, 206, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, //
+ 0xab, 0xcd, 0xef, 0x01, 'L', 'N', 'T', 'F', //
+ 0x3c, 0x7b, 0x65, 0x43};
+ size_t packet_length_bytes = sizeof(packet);
+
+ LossNotification loss_notification;
+
+ // First, prove that the failure we're expecting to see happens because of
+ // the length, by showing that before the modification to the length,
+ // the packet was correctly parsed.
+ ASSERT_TRUE(
+ test::ParseSinglePacket(packet, packet_length_bytes, &loss_notification));
+
+ // Show that after shaving off a word, the packet is no longer parsable.
+ packet[3] -= 1; // Change the |length| field of the RTCP packet.
+ packet_length_bytes -= 4; // Effectively forget the last 32-bit word.
+ EXPECT_FALSE(
+ test::ParseSinglePacket(packet, packet_length_bytes, &loss_notification));
+}
+
+TEST(RtcpPacketLossNotificationTest,
+ ParseFailsWhenUniqueIdentifierIsNotLossNotification) {
+ uint8_t packet[] = {0x8f, 206, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, //
+ 0xab, 0xcd, 0xef, 0x01, 'L', 'N', 'T', 'F', //
+ 0x3c, 0x7b, 0x65, 0x43};
+
+ LossNotification loss_notification;
+
+ // First, prove that the failure we're expecting to see happens because of
+ // the identifier, by showing that before the modification to the identifier,
+ // the packet was correctly parsed.
+ ASSERT_TRUE(test::ParseSinglePacket(packet, &loss_notification));
+
+ // Show that after changing the identifier, the packet is no longer parsable.
+ RTC_DCHECK_EQ(packet[12], 'L');
+ RTC_DCHECK_EQ(packet[13], 'N');
+ RTC_DCHECK_EQ(packet[14], 'T');
+ RTC_DCHECK_EQ(packet[15], 'F');
+ packet[14] = 'x';
+ EXPECT_FALSE(test::ParseSinglePacket(packet, &loss_notification));
+}
+
+TEST(RtcpPacketLossNotificationTest,
+ ParseLegalLossNotificationMessagesCorrectly) {
+ // Note that (0x6542 >> 1) is used just to make the pattern in kPacket
+ // more apparent; there's nothing truly special about the value,
+ // it's only an implementation detail that last-received is represented
+ // as a delta from last-decoded, and that this delta is shifted before
+ // it's put on the wire.
+ constexpr uint16_t kLastDecoded = 0x3c7b;
+ constexpr uint16_t kLastReceived = kLastDecoded + (0x6542 >> 1);
+ constexpr bool kDecodabilityFlag = true;
+
+ const uint8_t kPacket[] = {0x8f, 206, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, //
+ 0xab, 0xcd, 0xef, 0x01, 'L', 'N', 'T', 'F', //
+ 0x3c, 0x7b, 0x65, 0x43};
+
+ LossNotification loss_notification;
+ EXPECT_TRUE(test::ParseSinglePacket(kPacket, &loss_notification));
+
+ EXPECT_EQ(loss_notification.sender_ssrc(), 0x12345678u);
+ EXPECT_EQ(loss_notification.media_ssrc(), 0xabcdef01u);
+ EXPECT_EQ(loss_notification.last_decoded(), kLastDecoded);
+ EXPECT_EQ(loss_notification.last_received(), kLastReceived);
+ EXPECT_EQ(loss_notification.decodability_flag(), kDecodabilityFlag);
+}
+
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.cc b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
index 274eb6b..5b41aa5 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/pli.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
@@ -33,6 +33,12 @@
// : Feedback Control Information (FCI) :
// : :
+Pli::Pli() = default;
+
+Pli::Pli(const Pli& pli) = default;
+
+Pli::~Pli() = default;
+
//
// Picture loss indication (PLI) (RFC 4585).
// FCI: no feedback control information.
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.h b/modules/rtp_rtcp/source/rtcp_packet/pli.h
index fc3c20a..b9b9c45 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/pli.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.h
@@ -20,8 +20,9 @@
public:
static constexpr uint8_t kFeedbackMessageType = 1;
- Pli() {}
- ~Pli() override {}
+ Pli();
+ Pli(const Pli& pli);
+ ~Pli() override;
bool Parse(const CommonHeader& packet);
diff --git a/modules/rtp_rtcp/source/rtcp_packet/psfb.cc b/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
index 074413a..bd2e7ce 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
@@ -15,6 +15,7 @@
namespace webrtc {
namespace rtcp {
constexpr uint8_t Psfb::kPacketType;
+constexpr uint8_t Psfb::kAfbMessageType;
constexpr size_t Psfb::kCommonFeedbackLength;
// RFC 4585: Feedback format.
//
diff --git a/modules/rtp_rtcp/source/rtcp_packet/psfb.h b/modules/rtp_rtcp/source/rtcp_packet/psfb.h
index 46ee291..dd870e3 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/psfb.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/psfb.h
@@ -25,6 +25,7 @@
class Psfb : public RtcpPacket {
public:
static constexpr uint8_t kPacketType = 206;
+ static constexpr uint8_t kAfbMessageType = 15;
Psfb() : sender_ssrc_(0), media_ssrc_(0) {}
~Psfb() override {}
diff --git a/modules/rtp_rtcp/source/rtcp_packet/remb.cc b/modules/rtp_rtcp/source/rtcp_packet/remb.cc
index 3ed1fbd..c4572d0 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/remb.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/remb.cc
@@ -20,6 +20,7 @@
namespace webrtc {
namespace rtcp {
+// TODO(bugs.webrtc.org/10353): Remove once dependencies are updated.
constexpr uint8_t Remb::kFeedbackMessageType;
// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
//
@@ -48,7 +49,7 @@
bool Remb::Parse(const CommonHeader& packet) {
RTC_DCHECK(packet.type() == kPacketType);
- RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+ RTC_DCHECK_EQ(packet.fmt(), Psfb::kAfbMessageType);
if (packet.payload_size_bytes() < 16) {
RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
@@ -57,7 +58,6 @@
}
const uint8_t* const payload = packet.payload();
if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) {
- RTC_LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet.";
return false;
}
uint8_t number_of_ssrcs = payload[12];
@@ -113,7 +113,7 @@
return false;
}
size_t index_end = *index + BlockLength();
- CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+ CreateHeader(Psfb::kAfbMessageType, kPacketType, HeaderLength(), packet,
index);
RTC_DCHECK_EQ(0, Psfb::media_ssrc());
CreateCommonFeedback(packet + *index);
diff --git a/modules/rtp_rtcp/source/rtcp_packet/remb.h b/modules/rtp_rtcp/source/rtcp_packet/remb.h
index 6570e59..bc19657 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/remb.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/remb.h
@@ -22,7 +22,7 @@
// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
class Remb : public Psfb {
public:
- static constexpr uint8_t kFeedbackMessageType = 15;
+ static constexpr uint8_t kFeedbackMessageType = Psfb::kAfbMessageType;
static constexpr size_t kMaxNumberOfSsrcs = 0xff;
Remb();
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
index 2816559..ee8b93a 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -262,10 +262,14 @@
}
TransportFeedback::TransportFeedback()
+ : TransportFeedback(/*include_timestamps=*/true) {}
+
+TransportFeedback::TransportFeedback(bool include_timestamps)
: base_seq_no_(0),
num_seq_no_(0),
base_time_ticks_(0),
feedback_seq_(0),
+ include_timestamps_(include_timestamps),
last_timestamp_us_(0),
size_bytes_(kTransportFeedbackHeaderSizeBytes) {}
@@ -276,6 +280,7 @@
num_seq_no_(other.num_seq_no_),
base_time_ticks_(other.base_time_ticks_),
feedback_seq_(other.feedback_seq_),
+ include_timestamps_(other.include_timestamps_),
last_timestamp_us_(other.last_timestamp_us_),
packets_(std::move(other.packets_)),
encoded_chunks_(std::move(other.encoded_chunks_)),
@@ -301,19 +306,25 @@
bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number,
int64_t timestamp_us) {
- // Convert to ticks and round.
- int64_t delta_full = (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs;
- if (delta_full > kTimeWrapPeriodUs / 2)
- delta_full -= kTimeWrapPeriodUs;
- delta_full +=
- delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2;
- delta_full /= kDeltaScaleFactor;
+ // Set delta to zero if timestamps are not included, this will simplify the
+ // encoding process.
+ int16_t delta = 0;
+ if (include_timestamps_) {
+ // Convert to ticks and round.
+ int64_t delta_full =
+ (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs;
+ if (delta_full > kTimeWrapPeriodUs / 2)
+ delta_full -= kTimeWrapPeriodUs;
+ delta_full +=
+ delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2;
+ delta_full /= kDeltaScaleFactor;
- int16_t delta = static_cast<int16_t>(delta_full);
- // If larger than 16bit signed, we can't represent it - need new fb packet.
- if (delta != delta_full) {
- RTC_LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )";
- return false;
+ delta = static_cast<int16_t>(delta_full);
+ // If larger than 16bit signed, we can't represent it - need new fb packet.
+ if (delta != delta_full) {
+ RTC_LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )";
+ return false;
+ }
}
uint16_t next_seq_no = base_seq_no_ + num_seq_no_;
@@ -332,7 +343,9 @@
packets_.emplace_back(sequence_number, delta);
last_timestamp_us_ += delta * kDeltaScaleFactor;
- size_bytes_ += delta_size;
+ if (include_timestamps_) {
+ size_bytes_ += delta_size;
+ }
return true;
}
@@ -400,38 +413,57 @@
num_seq_no_ = status_count;
uint16_t seq_no = base_seq_no_;
+ size_t recv_delta_size = 0;
for (size_t delta_size : delta_sizes) {
- if (index + delta_size > end_index) {
- RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
- Clear();
- return false;
- }
- switch (delta_size) {
- case 0:
- break;
- case 1: {
- int16_t delta = payload[index];
- packets_.emplace_back(seq_no, delta);
- last_timestamp_us_ += delta * kDeltaScaleFactor;
- index += delta_size;
- break;
- }
- case 2: {
- int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]);
- packets_.emplace_back(seq_no, delta);
- last_timestamp_us_ += delta * kDeltaScaleFactor;
- index += delta_size;
- break;
- }
- case 3:
+ recv_delta_size += delta_size;
+ }
+
+ // Determine if timestamps, that is, recv_delta are included in the packet.
+ if (end_index >= index + recv_delta_size) {
+ for (size_t delta_size : delta_sizes) {
+ if (index + delta_size > end_index) {
+ RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
Clear();
- RTC_LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no;
return false;
- default:
- RTC_NOTREACHED();
- break;
+ }
+ switch (delta_size) {
+ case 0:
+ break;
+ case 1: {
+ int16_t delta = payload[index];
+ packets_.emplace_back(seq_no, delta);
+ last_timestamp_us_ += delta * kDeltaScaleFactor;
+ index += delta_size;
+ break;
+ }
+ case 2: {
+ int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]);
+ packets_.emplace_back(seq_no, delta);
+ last_timestamp_us_ += delta * kDeltaScaleFactor;
+ index += delta_size;
+ break;
+ }
+ case 3:
+ Clear();
+ RTC_LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no;
+
+ return false;
+ default:
+ RTC_NOTREACHED();
+ break;
+ }
+ ++seq_no;
}
- ++seq_no;
+ } else {
+ // The packet does not contain receive deltas.
+ include_timestamps_ = false;
+ for (size_t delta_size : delta_sizes) {
+ // Use delta sizes to detect if packet was received.
+ if (delta_size > 0) {
+ packets_.emplace_back(seq_no, 0);
+ }
+ ++seq_no;
+ }
}
size_bytes_ = RtcpPacket::kHeaderLength + index;
RTC_DCHECK_LE(index, end_index);
@@ -495,7 +527,9 @@
timestamp_us += packet_it->delta_us();
++packet_it;
}
- packet_size += delta_size;
+ if (include_timestamps_) {
+ packet_size += delta_size;
+ }
++seq_no;
}
if (packet_it != packets_.end()) {
@@ -521,6 +555,10 @@
return (size_bytes_ + 3) & (~static_cast<size_t>(3));
}
+size_t TransportFeedback::PaddingLength() const {
+ return BlockLength() - size_bytes_;
+}
+
// Serialize packet.
bool TransportFeedback::Create(uint8_t* packet,
size_t* position,
@@ -534,9 +572,10 @@
return false;
}
const size_t position_end = *position + BlockLength();
-
- CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
- position);
+ const size_t padding_length = PaddingLength();
+ bool has_padding = padding_length > 0;
+ CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), has_padding,
+ packet, position);
CreateCommonFeedback(packet + *position);
*position += kCommonFeedbackLength;
@@ -561,19 +600,24 @@
*position += 2;
}
- for (const auto& received_packet : packets_) {
- int16_t delta = received_packet.delta_ticks();
- if (delta >= 0 && delta <= 0xFF) {
- packet[(*position)++] = delta;
- } else {
- ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
- *position += 2;
+ if (include_timestamps_) {
+ for (const auto& received_packet : packets_) {
+ int16_t delta = received_packet.delta_ticks();
+ if (delta >= 0 && delta <= 0xFF) {
+ packet[(*position)++] = delta;
+ } else {
+ ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
+ *position += 2;
+ }
}
}
- while ((*position % 4) != 0)
- packet[(*position)++] = 0;
-
+ if (padding_length > 0) {
+ for (size_t i = 0; i < padding_length - 1; ++i) {
+ packet[(*position)++] = 0;
+ }
+ packet[(*position)++] = padding_length;
+ }
RTC_DCHECK_EQ(*position, position_end);
return true;
}
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
index fbdc38e..174ef6b 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
@@ -45,6 +45,10 @@
static constexpr size_t kMaxReportedPackets = 0xffff;
TransportFeedback();
+ explicit TransportFeedback(
+ bool include_timestamps); // If |include_timestamps| is set to false, the
+ // created packet will not contain the receive
+ // delta block.
TransportFeedback(const TransportFeedback&);
TransportFeedback(TransportFeedback&&);
@@ -65,6 +69,9 @@
// Get the reference time in microseconds, including any precision loss.
int64_t GetBaseTimeUs() const;
+ // Does the feedback packet contain timestamp information?
+ bool IncludeTimestamps() const { return include_timestamps_; }
+
bool Parse(const CommonHeader& packet);
static std::unique_ptr<TransportFeedback> ParseFrom(const uint8_t* buffer,
size_t length);
@@ -73,6 +80,7 @@
bool IsConsistent() const;
size_t BlockLength() const override;
+ size_t PaddingLength() const;
bool Create(uint8_t* packet,
size_t* position,
@@ -140,6 +148,7 @@
uint16_t num_seq_no_;
int32_t base_time_ticks_;
uint8_t feedback_seq_;
+ bool include_timestamps_;
int64_t last_timestamp_us_;
std::vector<ReceivedPacket> packets_;
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
index 0496525..0bb2d47 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
@@ -33,9 +33,11 @@
class FeedbackTester {
public:
- FeedbackTester()
+ FeedbackTester() : FeedbackTester(true) {}
+ explicit FeedbackTester(bool include_timestamps)
: expected_size_(kAnySize),
- default_delta_(TransportFeedback::kDeltaScaleFactor * 4) {}
+ default_delta_(TransportFeedback::kDeltaScaleFactor * 4),
+ include_timestamps_(include_timestamps) {}
void WithExpectedSize(size_t expected_size) {
expected_size_ = expected_size;
@@ -46,16 +48,16 @@
void WithInput(const uint16_t received_seq[],
const int64_t received_ts[],
uint16_t length) {
- std::unique_ptr<int64_t[]> temp_deltas;
+ std::unique_ptr<int64_t[]> temp_timestamps;
if (received_ts == nullptr) {
- temp_deltas.reset(new int64_t[length]);
- GenerateDeltas(received_seq, length, temp_deltas.get());
- received_ts = temp_deltas.get();
+ temp_timestamps.reset(new int64_t[length]);
+ GenerateReceiveTimestamps(received_seq, length, temp_timestamps.get());
+ received_ts = temp_timestamps.get();
}
expected_seq_.clear();
expected_deltas_.clear();
- feedback_.reset(new TransportFeedback());
+ feedback_.reset(new TransportFeedback(include_timestamps_));
feedback_->SetBase(received_seq[0], received_ts[0]);
ASSERT_TRUE(feedback_->IsConsistent());
@@ -81,8 +83,9 @@
VerifyInternal();
feedback_ =
TransportFeedback::ParseFrom(serialized_.data(), serialized_.size());
+ ASSERT_NE(nullptr, feedback_);
ASSERT_TRUE(feedback_->IsConsistent());
- ASSERT_NE(nullptr, feedback_.get());
+ EXPECT_EQ(include_timestamps_, feedback_->IncludeTimestamps());
VerifyInternal();
}
@@ -104,12 +107,14 @@
actual_deltas_us.push_back(packet.delta_us());
}
EXPECT_THAT(actual_seq_nos, ElementsAreArray(expected_seq_));
- EXPECT_THAT(actual_deltas_us, ElementsAreArray(expected_deltas_));
+ if (include_timestamps_) {
+ EXPECT_THAT(actual_deltas_us, ElementsAreArray(expected_deltas_));
+ }
}
- void GenerateDeltas(const uint16_t seq[],
- const size_t length,
- int64_t* deltas) {
+ void GenerateReceiveTimestamps(const uint16_t seq[],
+ const size_t length,
+ int64_t* timestamps) {
uint16_t last_seq = seq[0];
int64_t offset = 0;
@@ -118,7 +123,7 @@
offset += 0x10000 * default_delta_;
last_seq = seq[i];
- deltas[i] = offset + (last_seq * default_delta_);
+ timestamps[i] = offset + (last_seq * default_delta_);
}
}
@@ -128,9 +133,18 @@
int64_t default_delta_;
std::unique_ptr<TransportFeedback> feedback_;
rtc::Buffer serialized_;
+ bool include_timestamps_;
};
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector) {
+// The following tests use FeedbackTester that simulates received packets as
+// specified by the parameters |received_seq[]| and |received_ts[]| (optional).
+// The following is verified in these tests:
+// - Expected size of serialized packet.
+// - Expected sequence numbers and receive deltas.
+// - Sequence numbers and receive deltas are persistent after serialization
+// followed by parsing.
+// - The internal state of a feedback packet is consistent.
+TEST(RtcpPacketTest, TransportFeedbackOneBitVector) {
const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
const size_t kExpectedSizeBytes =
@@ -142,7 +156,18 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVectorNoRecvDelta) {
+ const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
+ const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+ const size_t kExpectedSizeBytes = kHeaderSize + kStatusChunkSize;
+
+ FeedbackTester test(/*include_timestamps=*/false);
+ test.WithExpectedSize(kExpectedSizeBytes);
+ test.WithInput(kReceived, nullptr, kLength);
+ test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedbackFullOneBitVector) {
const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
const size_t kExpectedSizeBytes =
@@ -154,7 +179,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapReceived) {
const uint16_t kMax = 0xFFFF;
const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
@@ -167,7 +192,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapMissing) {
const uint16_t kMax = 0xFFFF;
const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
@@ -180,7 +205,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackTwoBitVector) {
const uint16_t kReceived[] = {1, 2, 6, 7};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
const size_t kExpectedSizeBytes =
@@ -193,7 +218,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) {
+TEST(RtcpPacketTest, TransportFeedbackTwoBitVectorFull) {
const uint16_t kReceived[] = {1, 2, 6, 7, 8};
const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
const size_t kExpectedSizeBytes =
@@ -206,7 +231,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) {
+TEST(RtcpPacketTest, TransportFeedbackLargeAndNegativeDeltas) {
const uint16_t kReceived[] = {1, 2, 6, 7, 8};
const int64_t kReceiveTimes[] = {
2000, 1000, 4000, 3000,
@@ -221,7 +246,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_MaxRle) {
+TEST(RtcpPacketTest, TransportFeedbackMaxRle) {
// Expected chunks created:
// * 1-bit vector chunk (1xreceived + 13xdropped)
// * RLE chunk of max length for dropped symbol
@@ -240,7 +265,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_MinRle) {
+TEST(RtcpPacketTest, TransportFeedbackMinRle) {
// Expected chunks created:
// * 1-bit vector chunk (1xreceived + 13xdropped)
// * RLE chunk of length 15 for dropped symbol
@@ -258,7 +283,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVector) {
const size_t kTwoBitVectorCapacity = 7;
const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1};
const int64_t kReceiveTimes[] = {
@@ -273,7 +298,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSimpleSplit) {
const size_t kTwoBitVectorCapacity = 7;
const uint16_t kReceived[] = {0, kTwoBitVectorCapacity};
const int64_t kReceiveTimes[] = {
@@ -288,7 +313,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSplit) {
// With received small delta = S, received large delta = L, use input
// SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L.
// After split there will be two symbols in symbol_vec: SL.
@@ -316,7 +341,7 @@
test.VerifyPacket();
}
-TEST(RtcpPacketTest, TransportFeedback_Aliasing) {
+TEST(RtcpPacketTest, TransportFeedbackAliasing) {
TransportFeedback feedback;
feedback.SetBase(0, 0);
@@ -340,7 +365,7 @@
}
}
-TEST(RtcpPacketTest, TransportFeedback_Limits) {
+TEST(RtcpPacketTest, TransportFeedbackLimits) {
// Sequence number wrap above 0x8000.
std::unique_ptr<TransportFeedback> packet(new TransportFeedback());
packet->SetBase(0, 0);
@@ -404,10 +429,12 @@
// add back test for max size in bytes.
}
-TEST(RtcpPacketTest, TransportFeedback_Padding) {
+TEST(RtcpPacketTest, TransportFeedbackPadding) {
const size_t kExpectedSizeBytes =
kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
+ const size_t kExpectedPaddingSizeBytes =
+ 4 * kExpectedSizeWords - kExpectedSizeBytes;
TransportFeedback feedback;
feedback.SetBase(0, 0);
@@ -416,8 +443,10 @@
rtc::Buffer packet = feedback.Build();
EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
- for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i)
- EXPECT_EQ(0u, packet.data()[i]);
+ for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
+ EXPECT_EQ(0u, packet[i]);
+
+ EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
// Modify packet by adding 4 bytes of padding at the end. Not currently used
// when we're sending, but need to be able to handle it when receiving.
@@ -428,7 +457,8 @@
uint8_t mod_buffer[kExpectedSizeWithPadding];
memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1);
- mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes;
+ mod_buffer[kExpectedSizeWithPadding - 1] =
+ kPaddingBytes + kExpectedPaddingSizeBytes;
const uint8_t padding_flag = 1 << 5;
mod_buffer[0] |= padding_flag;
ByteWriter<uint16_t>::WriteBigEndian(
@@ -437,11 +467,46 @@
std::unique_ptr<TransportFeedback> parsed_packet(
TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding));
- ASSERT_TRUE(parsed_packet.get() != nullptr);
+ ASSERT_TRUE(parsed_packet != nullptr);
EXPECT_EQ(kExpectedSizeWords * 4, packet.size()); // Padding not included.
}
-TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) {
+TEST(RtcpPacketTest, TransportFeedbackPaddingBackwardsCompatibility) {
+ const size_t kExpectedSizeBytes =
+ kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
+ const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
+ const size_t kExpectedPaddingSizeBytes =
+ 4 * kExpectedSizeWords - kExpectedSizeBytes;
+
+ TransportFeedback feedback;
+ feedback.SetBase(0, 0);
+ EXPECT_TRUE(feedback.AddReceivedPacket(0, 0));
+
+ rtc::Buffer packet = feedback.Build();
+ EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
+ ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
+ for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
+ EXPECT_EQ(0u, packet[i]);
+
+ EXPECT_GT(kExpectedPaddingSizeBytes, 0u);
+ EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
+
+ // Modify packet by removing padding bit and writing zero at the last padding
+ // byte to verify that we can parse packets from old clients, where zero
+ // padding of up to three bytes was used without the padding bit being set.
+ uint8_t mod_buffer[kExpectedSizeWords * 4];
+ memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
+ mod_buffer[kExpectedSizeWords * 4 - 1] = 0;
+ const uint8_t padding_flag = 1 << 5;
+ mod_buffer[0] &= ~padding_flag; // Unset padding flag.
+
+ std::unique_ptr<TransportFeedback> parsed_packet(
+ TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWords * 4));
+ ASSERT_TRUE(parsed_packet != nullptr);
+ EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
+}
+
+TEST(RtcpPacketTest, TransportFeedbackCorrectlySplitsVectorChunks) {
const int kOneBitVectorCapacity = 14;
const int64_t kLargeTimeDelta =
TransportFeedback::kDeltaScaleFactor * (1 << 8);
@@ -460,11 +525,11 @@
std::unique_ptr<TransportFeedback> deserialized_packet =
TransportFeedback::ParseFrom(serialized_packet.data(),
serialized_packet.size());
- EXPECT_TRUE(deserialized_packet.get() != nullptr);
+ EXPECT_TRUE(deserialized_packet != nullptr);
}
}
-TEST(RtcpPacketTest, TransportFeedback_MoveConstructor) {
+TEST(RtcpPacketTest, TransportFeedbackMoveConstructor) {
const int kSamples = 100;
const int64_t kDelta = TransportFeedback::kDeltaScaleFactor;
const uint16_t kBaseSeqNo = 7531;
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
index 383f785..22d6433 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -18,6 +18,7 @@
#include <utility>
#include <vector>
+#include "absl/memory/memory.h"
#include "api/video/video_bitrate_allocation.h"
#include "api/video/video_bitrate_allocator.h"
#include "common_types.h" // NOLINT(build/include)
@@ -26,6 +27,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
@@ -73,6 +75,7 @@
uint32_t receiver_estimated_max_bitrate_bps = 0;
std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
absl::optional<VideoBitrateAllocation> target_bitrate_allocation;
+ std::unique_ptr<rtcp::LossNotification> loss_notification;
};
// Structure for handing TMMBR and TMMBN rtcp messages (RFC5104, section 3.5.4).
@@ -376,7 +379,7 @@
case rtcp::Fir::kFeedbackMessageType:
HandleFir(rtcp_block, packet_information);
break;
- case rtcp::Remb::kFeedbackMessageType:
+ case rtcp::Psfb::kAfbMessageType:
HandlePsfbApp(rtcp_block, packet_information);
break;
default:
@@ -437,7 +440,7 @@
packet_information->packet_type_flags |= kRtcpRr;
}
- for (const rtcp::ReportBlock report_block : sender_report.report_blocks())
+ for (const rtcp::ReportBlock& report_block : sender_report.report_blocks())
HandleReportBlock(report_block, packet_information, remote_ssrc);
}
@@ -869,13 +872,27 @@
void RTCPReceiver::HandlePsfbApp(const CommonHeader& rtcp_block,
PacketInformation* packet_information) {
- rtcp::Remb remb;
- if (remb.Parse(rtcp_block)) {
- packet_information->packet_type_flags |= kRtcpRemb;
- packet_information->receiver_estimated_max_bitrate_bps = remb.bitrate_bps();
- return;
+ {
+ rtcp::Remb remb;
+ if (remb.Parse(rtcp_block)) {
+ packet_information->packet_type_flags |= kRtcpRemb;
+ packet_information->receiver_estimated_max_bitrate_bps =
+ remb.bitrate_bps();
+ return;
+ }
}
+ {
+ auto loss_notification = absl::make_unique<rtcp::LossNotification>();
+ if (loss_notification->Parse(rtcp_block)) {
+ packet_information->packet_type_flags |= kRtcpLossNotification;
+ packet_information->loss_notification = std::move(loss_notification);
+ return;
+ }
+ }
+
+ RTC_LOG(LS_WARNING) << "Unknown PSFB-APP packet.";
+
++num_skipped_packets_;
}
@@ -1012,6 +1029,16 @@
rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(
packet_information.receiver_estimated_max_bitrate_bps);
}
+ if (packet_information.packet_type_flags & kRtcpLossNotification) {
+ rtcp::LossNotification* loss_notification =
+ packet_information.loss_notification.get();
+ RTC_DCHECK(loss_notification);
+ RTC_LOG(LS_VERBOSE) << "Incoming Loss Notification: ("
+ << loss_notification->last_decoded() << ", "
+ << loss_notification->last_received() << ", "
+ << loss_notification->decodability_flag() << ").";
+ // TODO(eladalon): Notify observer.
+ }
if ((packet_information.packet_type_flags & kRtcpSr) ||
(packet_information.packet_type_flags & kRtcpRr)) {
int64_t now_ms = clock_->TimeInMilliseconds();
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h
index be4c70e..fe6ec4c 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -21,7 +21,7 @@
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
#include "system_wrappers/include/ntp_time.h"
diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc
index 2581487..b2fd8b7 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -24,6 +24,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
@@ -37,7 +38,7 @@
#include "modules/rtp_rtcp/source/time_util.h"
#include "modules/rtp_rtcp/source/tmmbr_help.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/trace_event.h"
@@ -163,6 +164,7 @@
builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
builders_[kRtcpBye] = &RTCPSender::BuildBYE;
builders_[kRtcpApp] = &RTCPSender::BuildAPP;
+ builders_[kRtcpLossNotification] = &RTCPSender::BuildLossNotification;
builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
builders_[kRtcpNack] = &RTCPSender::BuildNACK;
@@ -211,6 +213,23 @@
return 0;
}
+int32_t RTCPSender::SendLossNotification(const FeedbackState& feedback_state,
+ uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag) {
+ rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+ loss_notification_state_.last_decoded_seq_num = last_decoded_seq_num;
+ loss_notification_state_.last_received_seq_num = last_received_seq_num;
+ loss_notification_state_.decodability_flag = decodability_flag;
+
+ SetFlag(kRtcpLossNotification, /*is_volatile=*/true);
+
+ // Send immediately.
+ return SendCompoundRTCP(feedback_state,
+ {RTCPPacketType::kRtcpLossNotification});
+}
+
void RTCPSender::SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
RTC_CHECK_GE(bitrate_bps, 0);
rtc::CritScope lock(&critical_section_rtcp_sender_);
@@ -583,6 +602,17 @@
return std::unique_ptr<rtcp::RtcpPacket>(app);
}
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildLossNotification(
+ const RtcpContext& ctx) {
+ auto loss_notification = absl::make_unique<rtcp::LossNotification>(
+ loss_notification_state_.last_decoded_seq_num,
+ loss_notification_state_.last_received_seq_num,
+ loss_notification_state_.decodability_flag);
+ loss_notification->SetSenderSsrc(ssrc_);
+ loss_notification->SetMediaSsrc(remote_ssrc_);
+ return std::move(loss_notification);
+}
+
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
const RtcpContext& ctx) {
rtcp::Nack* nack = new rtcp::Nack();
diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h
index 0845397..7a9aeac 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/modules/rtp_rtcp/source/rtcp_sender.h
@@ -29,8 +29,8 @@
#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/random.h"
#include "rtc_base/thread_annotations.h"
@@ -114,6 +114,11 @@
int32_t nackSize = 0,
const uint16_t* nackList = 0);
+ int32_t SendLossNotification(const FeedbackState& feedback_state,
+ uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag);
+
void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs);
void UnsetRemb();
@@ -168,6 +173,9 @@
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context)
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+ std::unique_ptr<rtcp::RtcpPacket> BuildLossNotification(
+ const RtcpContext& context)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports(
const RtcpContext& context)
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
@@ -214,6 +222,15 @@
// Full intra request
uint8_t sequence_number_fir_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+ // Loss Notification
+ struct LossNotificationState {
+ uint16_t last_decoded_seq_num;
+ uint16_t last_received_seq_num;
+ bool decodability_flag;
+ };
+ LossNotificationState loss_notification_state_
+ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
// REMB
int64_t remb_bitrate_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
std::vector<uint32_t> remb_ssrcs_
diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
index e1a436b..d297f3d 100644
--- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -89,7 +89,7 @@
rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds(),
- /*paylpad_type=*/0);
+ /*payload_type=*/0);
}
void InsertIncomingPacket(uint32_t remote_ssrc, uint16_t seq_num) {
@@ -376,6 +376,19 @@
EXPECT_THAT(parser()->nack()->packet_ids(), ElementsAre(0, 1, 16));
}
+TEST_F(RtcpSenderTest, SendLossNotification) {
+ rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+ constexpr uint16_t kLastDecoded = 0x1234;
+ constexpr uint16_t kLastReceived = 0x4321;
+ constexpr bool kDecodabilityFlag = true;
+ const int32_t result = rtcp_sender_->SendLossNotification(
+ feedback_state(), kLastDecoded, kLastReceived, kDecodabilityFlag);
+ EXPECT_EQ(result, 0);
+ EXPECT_EQ(1, parser()->loss_notification()->num_packets());
+ EXPECT_EQ(kSenderSsrc, parser()->loss_notification()->sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, parser()->loss_notification()->media_ssrc());
+}
+
TEST_F(RtcpSenderTest, RembNotIncludedBeforeSet) {
rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
@@ -633,7 +646,7 @@
rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds(),
- /*paylpad_type=*/0);
+ /*payload_type=*/0);
// Set up REMB info to be included with BYE.
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc
index 57d2142..cec6da9 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc
@@ -16,7 +16,8 @@
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
@@ -41,8 +42,8 @@
void RtcpTransceiver::Stop(std::function<void()> on_destroyed) {
RTC_DCHECK(rtcp_transceiver_);
- task_queue_->PostTask(rtc::NewClosure(
- Destructor{std::move(rtcp_transceiver_)}, std::move(on_destroyed)));
+ task_queue_->PostTask(ToQueuedTask(Destructor{std::move(rtcp_transceiver_)},
+ std::move(on_destroyed)));
RTC_DCHECK(!rtcp_transceiver_);
}
@@ -65,8 +66,7 @@
auto remove = [ptr, remote_ssrc, observer] {
ptr->RemoveMediaReceiverRtcpObserver(remote_ssrc, observer);
};
- task_queue_->PostTask(
- rtc::NewClosure(std::move(remove), std::move(on_removed)));
+ task_queue_->PostTask(ToQueuedTask(std::move(remove), std::move(on_removed)));
}
void RtcpTransceiver::SetReadyToSend(bool ready) {
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h
index 9c96751..16fd5a7 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.h
@@ -18,7 +18,7 @@
#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
-#include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/task_queue.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
index 97c2ac0..5d2cd6e 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
@@ -29,11 +29,11 @@
#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
#include "modules/rtp_rtcp/source/time_util.h"
-#include "rtc_base/cancelable_periodic_task.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/task_queue.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
@@ -90,15 +90,18 @@
RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
: config_(config), ready_to_send_(config.initial_ready_to_send) {
RTC_CHECK(config_.Validate());
- if (ready_to_send_ && config_.schedule_periodic_compound_packets)
- SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
+ if (ready_to_send_ && config_.schedule_periodic_compound_packets) {
+ config_.task_queue->PostTask([this] {
+ SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
+ });
+ }
}
RtcpTransceiverImpl::~RtcpTransceiverImpl() {
// If RtcpTransceiverImpl is destroyed off task queue, assume it is destroyed
// after TaskQueue. In that case there is no need to Cancel periodic task.
if (config_.task_queue == rtc::TaskQueue::Current()) {
- periodic_task_handle_.Cancel();
+ periodic_task_handle_.Stop();
}
}
@@ -126,7 +129,7 @@
void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
if (config_.schedule_periodic_compound_packets) {
if (ready_to_send_ && !ready)
- periodic_task_handle_.Cancel();
+ periodic_task_handle_.Stop();
if (!ready_to_send_ && ready) // Restart periodic sending.
SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
@@ -323,24 +326,19 @@
void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
if (!config_.schedule_periodic_compound_packets)
return;
- periodic_task_handle_.Cancel();
+ periodic_task_handle_.Stop();
RTC_DCHECK(ready_to_send_);
SchedulePeriodicCompoundPackets(config_.report_period_ms);
}
void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
- auto task = rtc::CreateCancelablePeriodicTask([this] {
- RTC_DCHECK(config_.schedule_periodic_compound_packets);
- RTC_DCHECK(ready_to_send_);
- SendPeriodicCompoundPacket();
- return config_.report_period_ms;
- });
- periodic_task_handle_ = task->GetCancellationHandle();
-
- if (delay_ms > 0)
- config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
- else
- config_.task_queue->PostTask(std::move(task));
+ periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
+ config_.task_queue, TimeDelta::ms(delay_ms), [this] {
+ RTC_DCHECK(config_.schedule_periodic_compound_packets);
+ RTC_DCHECK(ready_to_send_);
+ SendPeriodicCompoundPacket();
+ return TimeDelta::ms(config_.report_period_ms);
+ });
}
void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
index eb9086f..b08dd56 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
@@ -24,7 +24,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
-#include "rtc_base/cancelable_task_handle.h"
+#include "rtc_base/task_utils/repeating_task.h"
#include "system_wrappers/include/ntp_time.h"
namespace webrtc {
@@ -96,7 +96,7 @@
// TODO(danilchap): Remove entries from remote_senders_ that are no longer
// needed.
std::map<uint32_t, RemoteSenderState> remote_senders_;
- rtc::CancelableTaskHandle periodic_task_handle_;
+ RepeatingTaskHandle periodic_task_handle_;
};
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
index e86d67f..fec2bb7 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
@@ -21,7 +21,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
#include "modules/rtp_rtcp/source/time_util.h"
#include "rtc_base/event.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/task_queue.h"
#include "test/gmock.h"
#include "test/gtest.h"
@@ -385,7 +385,7 @@
config.schedule_periodic_compound_packets = false;
RtcpTransceiverImpl rtcp_transceiver(config);
- rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+ rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrcs=*/{54321, 64321});
rtcp_transceiver.SendCompoundPacket();
EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1);
@@ -404,14 +404,14 @@
config.schedule_periodic_compound_packets = false;
RtcpTransceiverImpl rtcp_transceiver(config);
- rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+ rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrcs=*/{54321, 64321});
rtcp_transceiver.SendCompoundPacket();
EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1);
EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 10000u);
EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(54321, 64321));
- rtcp_transceiver.SetRemb(/*bitrate_bps=*/70000, /*ssrc=*/{67321});
+ rtcp_transceiver.SetRemb(/*bitrate_bps=*/70000, /*ssrcs=*/{67321});
rtcp_transceiver.SendCompoundPacket();
EXPECT_EQ(rtcp_parser.remb()->num_packets(), 2);
@@ -429,7 +429,7 @@
config.schedule_periodic_compound_packets = false;
RtcpTransceiverImpl rtcp_transceiver(config);
- rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+ rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrcs=*/{54321, 64321});
rtcp_transceiver.SendCompoundPacket();
rtcp_transceiver.SendCompoundPacket();
@@ -447,7 +447,7 @@
config.schedule_periodic_compound_packets = false;
RtcpTransceiverImpl rtcp_transceiver(config);
- rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+ rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrcs=*/{54321, 64321});
rtcp_transceiver.SendCompoundPacket();
EXPECT_EQ(transport.num_packets(), 1);
ASSERT_EQ(rtcp_parser.remb()->num_packets(), 1);
diff --git a/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
index cbad0ae..d260db4 100644
--- a/modules/rtp_rtcp/source/rtp_fec_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
@@ -216,7 +216,7 @@
using FecTypes =
Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>;
-TYPED_TEST_CASE(RtpFecTest, FecTypes);
+TYPED_TEST_SUITE(RtpFecTest, FecTypes);
TYPED_TEST(RtpFecTest, WillProtectMediaPacketsWithLargeSequenceNumberGap) {
constexpr int kNumImportantPackets = 0;
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.cc b/modules/rtp_rtcp/source/rtp_format_h264.cc
index 7a7bcdf..d10831f 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264.cc
+++ b/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -43,7 +43,6 @@
static const char* kSpsValidHistogramName = "WebRTC.Video.H264.SpsValid";
enum SpsValidEvent {
- kReceivedSpsPocOk = 0,
kReceivedSpsVuiOk = 1,
kReceivedSpsRewritten = 2,
kReceivedSpsParseFailure = 3,
@@ -135,11 +134,6 @@
SpsValidEvent::kSentSpsRewritten,
SpsValidEvent::kSpsRewrittenMax);
break;
- case SpsVuiRewriter::ParseResult::kPocOk:
- RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
- SpsValidEvent::kSentSpsPocOk,
- SpsValidEvent::kSpsRewrittenMax);
- break;
case SpsVuiRewriter::ParseResult::kVuiOk:
RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
SpsValidEvent::kSentSpsVuiOk,
@@ -219,10 +213,19 @@
PayloadSizeLimits limits = limits_;
// Leave room for the FU-A header.
limits.max_payload_len -= kFuAHeaderSize;
- // Ignore single/first/last packet reductions unless it is single/first/last
+ // Update single/first/last packet reductions unless it is single/first/last
// fragment.
- if (input_fragments_.size() != 1)
- limits.single_packet_reduction_len = 0;
+ if (input_fragments_.size() != 1) {
+ // if this fragment is put into a single packet, it might still be the
+ // first or the last packet in the whole sequence of packets.
+ if (fragment_index == input_fragments_.size() - 1) {
+ limits.single_packet_reduction_len = limits_.last_packet_reduction_len;
+ } else if (fragment_index == 0) {
+ limits.single_packet_reduction_len = limits_.first_packet_reduction_len;
+ } else {
+ limits.single_packet_reduction_len = 0;
+ }
+ }
if (fragment_index != 0)
limits.first_packet_reduction_len = 0;
if (fragment_index != input_fragments_.size() - 1)
@@ -550,11 +553,6 @@
SpsValidEvent::kReceivedSpsRewritten,
SpsValidEvent::kSpsRewrittenMax);
break;
- case SpsVuiRewriter::ParseResult::kPocOk:
- RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
- SpsValidEvent::kReceivedSpsPocOk,
- SpsValidEvent::kSpsRewrittenMax);
- break;
case SpsVuiRewriter::ParseResult::kVuiOk:
RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
SpsValidEvent::kReceivedSpsVuiOk,
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.h b/modules/rtp_rtcp/source/rtp_format_h264.h
index fbd4fd9..108156f 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264.h
+++ b/modules/rtp_rtcp/source/rtp_format_h264.h
@@ -23,7 +23,7 @@
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/video_coding/codecs/h264/include/h264_globals.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
index aeab813..7608de3 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
@@ -202,7 +202,7 @@
EXPECT_THAT(packets, SizeIs(1));
}
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
PacketMode,
RtpPacketizerH264ModeTest,
::testing::Values(H264PacketizationMode::SingleNalUnit,
@@ -379,6 +379,28 @@
ElementsAreArray(next_fragment, kStapANaluSize));
}
+TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
+ RtpPacketizer::PayloadSizeLimits limits;
+ limits.max_payload_len = 1178;
+ limits.first_packet_reduction_len = 0;
+ limits.last_packet_reduction_len = 20;
+ limits.single_packet_reduction_len = 20;
+ // Actual sizes, which triggered this bug.
+ size_t fragments[] = {20, 8, 18, 1161};
+ RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
+ rtc::Buffer frame = CreateFrame(fragmentation);
+
+ RtpPacketizerH264 packetizer(
+ frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+ std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
+
+ // Last packet has to be of correct size.
+ // Incorrect implementation might miss this constraint and not split the last
+ // fragment in two packets.
+ EXPECT_LE(static_cast<int>(packets.back().payload_size()),
+ limits.max_payload_len - limits.last_packet_reduction_len);
+}
+
// Splits frame with payload size |frame_payload_size| without fragmentation,
// Returns sizes of the payloads excluding fua headers.
std::vector<int> TestFua(size_t frame_payload_size,
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic.h b/modules/rtp_rtcp/source/rtp_format_video_generic.h
index 3458d49..982e35a 100644
--- a/modules/rtp_rtcp/source/rtp_format_video_generic.h
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/source/rtp_format.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.h b/modules/rtp_rtcp/source/rtp_format_vp8.h
index 444298f..0e0fa52 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp8.h
+++ b/modules/rtp_rtcp/source/rtp_format_vp8.h
@@ -34,7 +34,7 @@
#include "modules/rtp_rtcp/source/rtp_format.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h
index 07f5f64..03d4e58 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h
+++ b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h
@@ -22,7 +22,7 @@
#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9.cc b/modules/rtp_rtcp/source/rtp_format_vp9.cc
index 9cd7514..bbb8e29 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp9.cc
+++ b/modules/rtp_rtcp/source/rtp_format_vp9.cc
@@ -15,7 +15,7 @@
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/video_coding/codecs/interface/common_constants.h"
-#include "rtc_base/bitbuffer.h"
+#include "rtc_base/bit_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9.h b/modules/rtp_rtcp/source/rtp_format_vp9.h
index c3b8f17..2918b06 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp9.h
+++ b/modules/rtp_rtcp/source/rtp_format_vp9.h
@@ -29,7 +29,7 @@
#include "modules/rtp_rtcp/source/rtp_format.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc
index c27fb6e..7a8af09 100644
--- a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc
@@ -99,8 +99,15 @@
void RtpGenericFrameDescriptor::SetByteRepresentation(
rtc::ArrayView<const uint8_t> byte_representation) {
+ RTC_CHECK(!byte_representation.empty());
byte_representation_.assign(byte_representation.begin(),
byte_representation.end());
+ // Clear end_of_subframe bit.
+ // Because ByteRepresentation is used for frame authentication, bit describing
+ // position of the packet in the frame shouldn't be part of it.
+ // This match RtpVideoSender where descriptor is passed for authentication
+ // before end_of_subframe bit is decided and set, i.e. it is always 0.
+ byte_representation_[0] &= ~0x40;
}
rtc::ArrayView<const uint8_t>
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h
index 3a6c34d..47a2a74 100644
--- a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h
@@ -14,10 +14,13 @@
#include <stdint.h>
#include <vector>
+#include "absl/types/optional.h"
#include "api/array_view.h"
namespace webrtc {
+class RtpGenericFrameDescriptorExtension;
+
// Data to put on the wire for FrameDescriptor rtp header extension.
class RtpGenericFrameDescriptor {
public:
@@ -34,10 +37,14 @@
bool LastPacketInSubFrame() const { return end_of_subframe_; }
void SetLastPacketInSubFrame(bool last) { end_of_subframe_ = last; }
- bool FirstSubFrameInFrame() const { return beginning_of_frame_; }
- void SetFirstSubFrameInFrame(bool first) { beginning_of_frame_ = first; }
- bool LastSubFrameInFrame() const { return end_of_frame_; }
- void SetLastSubFrameInFrame(bool last) { end_of_frame_ = last; }
+ // Denotes whether the frame is discardable. That is, whether skipping it
+ // would have no effect on the decodability of subsequent frames.
+ // An absl::optional is used because version 0 of the extension did not
+ // support this flag. (The optional aspect is relevant only when parsing.)
+ // TODO(bugs.webrtc.org/10243): Make this into a plain bool when v00 of
+ // the extension is deprecated.
+ absl::optional<bool> Discardable() const { return discardable_; }
+ void SetDiscardable(bool discardable) { discardable_ = discardable; }
// Properties below undefined if !FirstPacketInSubFrame()
// Valid range for temporal layer: [0, 7]
@@ -68,8 +75,8 @@
private:
bool beginning_of_subframe_ = false;
bool end_of_subframe_ = false;
- bool beginning_of_frame_ = false;
- bool end_of_frame_ = false;
+
+ absl::optional<bool> discardable_;
uint16_t frame_id_ = 0;
uint8_t spatial_layers_ = 1;
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc
index 7cd120d..a705b5a 100644
--- a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc
@@ -17,15 +17,21 @@
constexpr uint8_t kFlagBeginOfSubframe = 0x80;
constexpr uint8_t kFlagEndOfSubframe = 0x40;
-constexpr uint8_t kFlagFirstSubframe = 0x20;
-constexpr uint8_t kFlagLastSubframe = 0x10;
+
+// In version 00, the flags F and L in the first byte correspond to
+// kFlagFirstSubframeV00 and kFlagLastSubframeV00. In practice, they were
+// always set to |true|. In version 01, these flags are deprecated, and we use
+// one of their bits for the discardability flag.
+constexpr uint8_t kFlagFirstSubframeV00 = 0x20;
+constexpr uint8_t kFlagLastSubframeV00 = 0x10;
+constexpr uint8_t kFlagDiscardableV01 = 0x10;
+
constexpr uint8_t kFlagDependencies = 0x08;
constexpr uint8_t kMaskTemporalLayer = 0x07;
constexpr uint8_t kFlagMoreDependencies = 0x01;
constexpr uint8_t kFlageXtendedOffset = 0x02;
-} // namespace
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |B|E|F|L|D| T |
@@ -52,10 +58,9 @@
// +---------------+
// | ... |
// +-+-+-+-+-+-+-+-+
-constexpr RTPExtensionType RtpGenericFrameDescriptorExtension::kId;
-constexpr char RtpGenericFrameDescriptorExtension::kUri[];
-bool RtpGenericFrameDescriptorExtension::Parse(
+bool RtpGenericFrameDescriptorExtensionParse(
+ size_t version,
rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) {
if (data.empty()) {
@@ -65,8 +70,10 @@
bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0;
descriptor->SetFirstPacketInSubFrame(begins_subframe);
descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0);
- descriptor->SetFirstSubFrameInFrame((data[0] & kFlagFirstSubframe) != 0);
- descriptor->SetLastSubFrameInFrame((data[0] & kFlagLastSubframe) != 0);
+
+ if (version >= 1) {
+ descriptor->SetDiscardable((data[0] & kFlagDiscardableV01) != 0);
+ }
// Parse Subframe details provided in 1st packet of subframe.
if (!begins_subframe) {
@@ -108,7 +115,7 @@
return true;
}
-size_t RtpGenericFrameDescriptorExtension::ValueSize(
+size_t RtpGenericFrameDescriptorExtensionValueSize(
const RtpGenericFrameDescriptor& descriptor) {
if (!descriptor.FirstPacketInSubFrame())
return 1;
@@ -125,15 +132,24 @@
return size;
}
-bool RtpGenericFrameDescriptorExtension::Write(
+bool RtpGenericFrameDescriptorExtensionWrite(
+ size_t version,
rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) {
- RTC_CHECK_EQ(data.size(), ValueSize(descriptor));
+ RTC_CHECK_EQ(data.size(),
+
+ RtpGenericFrameDescriptorExtensionValueSize(descriptor));
uint8_t base_header =
(descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) |
- (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0) |
- (descriptor.FirstSubFrameInFrame() ? kFlagFirstSubframe : 0) |
- (descriptor.LastSubFrameInFrame() ? kFlagLastSubframe : 0);
+ (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0);
+ if (version == 0) {
+ base_header |= kFlagFirstSubframeV00;
+ base_header |= kFlagLastSubframeV00;
+ } else if (version >= 1) {
+ const absl::optional<bool> discardable = descriptor.Discardable();
+ base_header |= (discardable.value_or(false) ? kFlagDiscardableV01 : 0);
+ }
+
if (!descriptor.FirstPacketInSubFrame()) {
data[0] = base_header;
return true;
@@ -168,4 +184,48 @@
return true;
}
+} // namespace
+
+constexpr RTPExtensionType RtpGenericFrameDescriptorExtension00::kId;
+constexpr char RtpGenericFrameDescriptorExtension00::kUri[];
+
+bool RtpGenericFrameDescriptorExtension00::Parse(
+ rtc::ArrayView<const uint8_t> data,
+ RtpGenericFrameDescriptor* descriptor) {
+ return RtpGenericFrameDescriptorExtensionParse(0, data, descriptor);
+}
+
+size_t RtpGenericFrameDescriptorExtension00::ValueSize(
+ const RtpGenericFrameDescriptor& descriptor) {
+ // No difference between existing versions.
+ return RtpGenericFrameDescriptorExtensionValueSize(descriptor);
+}
+
+bool RtpGenericFrameDescriptorExtension00::Write(
+ rtc::ArrayView<uint8_t> data,
+ const RtpGenericFrameDescriptor& descriptor) {
+ return RtpGenericFrameDescriptorExtensionWrite(0, data, descriptor);
+}
+
+constexpr RTPExtensionType RtpGenericFrameDescriptorExtension01::kId;
+constexpr char RtpGenericFrameDescriptorExtension01::kUri[];
+
+bool RtpGenericFrameDescriptorExtension01::Parse(
+ rtc::ArrayView<const uint8_t> data,
+ RtpGenericFrameDescriptor* descriptor) {
+ return RtpGenericFrameDescriptorExtensionParse(1, data, descriptor);
+}
+
+size_t RtpGenericFrameDescriptorExtension01::ValueSize(
+ const RtpGenericFrameDescriptor& descriptor) {
+ // No difference between existing versions.
+ return RtpGenericFrameDescriptorExtensionValueSize(descriptor);
+}
+
+bool RtpGenericFrameDescriptorExtension01::Write(
+ rtc::ArrayView<uint8_t> data,
+ const RtpGenericFrameDescriptor& descriptor) {
+ return RtpGenericFrameDescriptorExtensionWrite(1, data, descriptor);
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h
index 0d673e0..a52588e 100644
--- a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h
@@ -19,10 +19,10 @@
namespace webrtc {
-class RtpGenericFrameDescriptorExtension {
+class RtpGenericFrameDescriptorExtension00 {
public:
using value_type = RtpGenericFrameDescriptor;
- static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor;
+ static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor00;
static constexpr char kUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/"
"generic-frame-descriptor-00";
@@ -30,7 +30,23 @@
static bool Parse(rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor);
- static size_t ValueSize(const RtpGenericFrameDescriptor&);
+ static size_t ValueSize(const RtpGenericFrameDescriptor& descriptor);
+ static bool Write(rtc::ArrayView<uint8_t> data,
+ const RtpGenericFrameDescriptor& descriptor);
+};
+
+class RtpGenericFrameDescriptorExtension01 {
+ public:
+ using value_type = RtpGenericFrameDescriptor;
+ static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor01;
+ static constexpr char kUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/"
+ "generic-frame-descriptor-01";
+ static constexpr int kMaxSizeBytes = 16;
+
+ static bool Parse(rtc::ArrayView<const uint8_t> data,
+ RtpGenericFrameDescriptor* descriptor);
+ static size_t ValueSize(const RtpGenericFrameDescriptor& descriptor);
static bool Write(rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor);
};
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc
index 7f8fa2f..13cacb5 100644
--- a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2018 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
@@ -19,30 +19,91 @@
using ::testing::ElementsAreArray;
using ::testing::IsEmpty;
+constexpr uint8_t kDeprecatedFlags = 0x30;
+
// TODO(danilchap): Add fuzzer to test for various invalid inputs.
-TEST(RtpGenericFrameDescriptorExtensionTest,
- ParseFirstPacketOfIndependenSubFrame) {
+class RtpGenericFrameDescriptorExtensionTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<int> {
+ public:
+ RtpGenericFrameDescriptorExtensionTest() : version_(GetParam()) {}
+
+ bool Parse(rtc::ArrayView<const uint8_t> data,
+ RtpGenericFrameDescriptor* descriptor) const {
+ switch (version_) {
+ case 0:
+ return RtpGenericFrameDescriptorExtension00::Parse(data, descriptor);
+ case 1:
+ return RtpGenericFrameDescriptorExtension01::Parse(data, descriptor);
+ }
+ RTC_NOTREACHED();
+ return false;
+ }
+
+ size_t ValueSize(const RtpGenericFrameDescriptor& descriptor) const {
+ switch (version_) {
+ case 0:
+ return RtpGenericFrameDescriptorExtension00::ValueSize(descriptor);
+ case 1:
+ return RtpGenericFrameDescriptorExtension01::ValueSize(descriptor);
+ }
+ RTC_NOTREACHED();
+ return 0;
+ }
+
+ bool Write(rtc::ArrayView<uint8_t> data,
+ const RtpGenericFrameDescriptor& descriptor) const {
+ switch (version_) {
+ case 0:
+ return RtpGenericFrameDescriptorExtension00::Write(data, descriptor);
+ case 1:
+ return RtpGenericFrameDescriptorExtension01::Write(data, descriptor);
+ }
+ RTC_NOTREACHED();
+ return false;
+ }
+
+ protected:
+ const int version_;
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ RtpGenericFrameDescriptorExtensionTest,
+ ::testing::Values(0, 1));
+
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ ParseFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.LastPacketInSubFrame());
- EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
- EXPECT_FALSE(descriptor.LastSubFrameInFrame());
+
+ const absl::optional<bool> discardable = descriptor.Discardable();
+ if (version_ == 0) {
+ ASSERT_FALSE(discardable.has_value());
+ } else {
+ ASSERT_TRUE(discardable.has_value());
+ EXPECT_FALSE(discardable.value());
+ }
+
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), IsEmpty());
EXPECT_EQ(descriptor.TemporalLayer(), kTemporalLayer);
EXPECT_EQ(descriptor.SpatialLayersBitmask(), 0x49);
EXPECT_EQ(descriptor.FrameId(), 0x3412);
}
-TEST(RtpGenericFrameDescriptorExtensionTest,
- WriteFirstPacketOfIndependenSubFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ WriteFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
- constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
+ uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
@@ -50,260 +111,263 @@
descriptor.SetSpatialLayersBitmask(0x49);
descriptor.SetFrameId(0x3412);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
+
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
constexpr uint8_t kRaw[] = {0x40};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
+
+ const absl::optional<bool> discardable = descriptor.Discardable();
+ if (version_ == 0) {
+ ASSERT_FALSE(discardable.has_value());
+ } else {
+ ASSERT_TRUE(discardable.has_value());
+ EXPECT_FALSE(discardable.value());
+ }
+
EXPECT_TRUE(descriptor.LastPacketInSubFrame());
- EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
- EXPECT_FALSE(descriptor.LastSubFrameInFrame());
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
- constexpr uint8_t kRaw[] = {0x40};
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
+ uint8_t kRaw[] = {0x40};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
+
RtpGenericFrameDescriptor descriptor;
descriptor.SetLastPacketInSubFrame(true);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
- EXPECT_THAT(buffer, ElementsAreArray(kRaw));
-}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseFirstSubFrameInFrame) {
- constexpr uint8_t kRaw[] = {0x20};
- RtpGenericFrameDescriptor descriptor;
-
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
-
- EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
- EXPECT_FALSE(descriptor.LastPacketInSubFrame());
- EXPECT_TRUE(descriptor.FirstSubFrameInFrame());
- EXPECT_FALSE(descriptor.LastSubFrameInFrame());
-}
-
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteFirstSubFrameInFrame) {
- constexpr uint8_t kRaw[] = {0x20};
- RtpGenericFrameDescriptor descriptor;
- descriptor.SetFirstSubFrameInFrame(true);
-
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
- uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastSubFrameInFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseDiscardable) {
+ if (version_ == 0) {
+ return;
+ }
+
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
-
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
-
- EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
- EXPECT_FALSE(descriptor.LastPacketInSubFrame());
- EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
- EXPECT_TRUE(descriptor.LastSubFrameInFrame());
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
+ const absl::optional<bool> discardable = descriptor.Discardable();
+ ASSERT_TRUE(discardable.has_value());
+ EXPECT_TRUE(discardable.value());
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteLastSubFrameInFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteDiscardable) {
+ if (version_ == 0) {
+ return;
+ }
+
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
- descriptor.SetLastSubFrameInFrame(true);
-
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ descriptor.SetDiscardable(true);
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
+ constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfc};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
+ constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x02, 0x01};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest,
- ParseLongFrameDependenciesAsBigEndian) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ ParseLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
+ constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
-TEST(RtpGenericFrameDescriptorExtensionTest,
- WriteLongFrameDependenciesAsBigEndian) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ WriteLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
+ constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfe, 0xff};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
- constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
constexpr uint8_t kRaw[] = {
- 0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
+ 0xb8, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff1, kDiff2));
}
-TEST(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
- constexpr uint8_t kRaw[] = {
- 0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
+ uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff1);
descriptor.AddFrameDependencyDiff(kDiff2);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
-TEST(RtpGenericFrameDescriptorExtensionTest,
- ParseResolutionOnIndependentFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ ParseResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
- constexpr uint8_t kRaw[] = {0x80, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
+ constexpr uint8_t kRaw[] = {0xb0, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
RtpGenericFrameDescriptor descriptor;
- ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+ ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_EQ(descriptor.Width(), kWidth);
EXPECT_EQ(descriptor.Height(), kHeight);
}
-TEST(RtpGenericFrameDescriptorExtensionTest,
- WriteResolutionOnIndependentFrame) {
+TEST_P(RtpGenericFrameDescriptorExtensionTest,
+ WriteResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
- constexpr uint8_t kRaw[] = {0x80, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
+ uint8_t kRaw[] = {0x80, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
+ if (version_ == 0) {
+ kRaw[0] |= kDeprecatedFlags;
+ }
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.SetResolution(kWidth, kHeight);
- ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
- sizeof(kRaw));
+ ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
- EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+ EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
} // namespace
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
index 8e0a484..b4aaf3f 100644
--- a/modules/rtp_rtcp/source/rtp_header_extension_map.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
@@ -35,6 +35,7 @@
CreateExtensionInfo<AbsoluteSendTime>(),
CreateExtensionInfo<VideoOrientation>(),
CreateExtensionInfo<TransportSequenceNumber>(),
+ CreateExtensionInfo<TransportSequenceNumberV2>(),
CreateExtensionInfo<PlayoutDelayLimits>(),
CreateExtensionInfo<VideoContentTypeExtension>(),
CreateExtensionInfo<VideoTimingExtension>(),
@@ -42,7 +43,8 @@
CreateExtensionInfo<RtpStreamId>(),
CreateExtensionInfo<RepairedRtpStreamId>(),
CreateExtensionInfo<RtpMid>(),
- CreateExtensionInfo<RtpGenericFrameDescriptorExtension>(),
+ CreateExtensionInfo<RtpGenericFrameDescriptorExtension00>(),
+ CreateExtensionInfo<RtpGenericFrameDescriptorExtension01>(),
CreateExtensionInfo<ColorSpaceExtension>(),
};
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_size.cc b/modules/rtp_rtcp/source/rtp_header_extension_size.cc
index f20ca00..7719922 100644
--- a/modules/rtp_rtcp/source/rtp_header_extension_size.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extension_size.cc
@@ -10,7 +10,7 @@
#include "modules/rtp_rtcp/source/rtp_header_extension_size.h"
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc
index 92694cd..1d76ff3 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -12,6 +12,7 @@
#include <string.h>
#include <cmath>
+#include <limits>
#include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/source/byte_io.h"
@@ -125,27 +126,99 @@
return true;
}
+// TransportSequenceNumber
+//
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | ID | L=1 |transport wide sequence number |
+// | ID | L=1 |transport-wide sequence number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
constexpr RTPExtensionType TransportSequenceNumber::kId;
constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
constexpr const char TransportSequenceNumber::kUri[];
bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
- uint16_t* value) {
- if (data.size() != 2)
+ uint16_t* transport_sequence_number) {
+ if (data.size() != kValueSizeBytes)
return false;
- *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
+ *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
return true;
}
bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
- uint16_t value) {
- RTC_DCHECK_EQ(data.size(), 2);
- ByteWriter<uint16_t>::WriteBigEndian(data.data(), value);
+ uint16_t transport_sequence_number) {
+ RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
+ ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
+ return true;
+}
+
+// TransportSequenceNumberV2
+//
+// In addition to the format used for TransportSequencNumber, V2 also supports
+// the following packet format where two extra bytes are used to specify that
+// the sender requests immediate feedback.
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | L=3 |transport-wide sequence number |T| seq count |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |seq count cont.|
+// +-+-+-+-+-+-+-+-+
+//
+// The bit |T| determines whether the feedback should include timing information
+// or not and |seq_count| determines how many packets the feedback packet should
+// cover including the current packet. If |seq_count| is zero no feedback is
+// requested.
+constexpr RTPExtensionType TransportSequenceNumberV2::kId;
+constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
+constexpr uint8_t
+ TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
+constexpr const char TransportSequenceNumberV2::kUri[];
+constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
+
+bool TransportSequenceNumberV2::Parse(
+ rtc::ArrayView<const uint8_t> data,
+ uint16_t* transport_sequence_number,
+ absl::optional<FeedbackRequest>* feedback_request) {
+ if (data.size() != kValueSizeBytes &&
+ data.size() != kValueSizeBytesWithoutFeedbackRequest)
+ return false;
+
+ *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
+
+ *feedback_request = absl::nullopt;
+ if (data.size() == kValueSizeBytes) {
+ uint16_t feedback_request_raw =
+ ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
+ bool include_timestamps =
+ (feedback_request_raw & kIncludeTimestampsBit) != 0;
+ uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
+
+ // If |sequence_count| is zero no feedback is requested.
+ if (sequence_count != 0) {
+ *feedback_request = {include_timestamps, sequence_count};
+ }
+ }
+ return true;
+}
+
+bool TransportSequenceNumberV2::Write(
+ rtc::ArrayView<uint8_t> data,
+ uint16_t transport_sequence_number,
+ const absl::optional<FeedbackRequest>& feedback_request) {
+ RTC_DCHECK_EQ(data.size(),
+ ValueSize(transport_sequence_number, feedback_request));
+
+ ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
+
+ if (feedback_request) {
+ RTC_DCHECK_GE(feedback_request->sequence_count, 0);
+ RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
+ uint16_t feedback_request_raw =
+ feedback_request->sequence_count |
+ (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
+ ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
+ }
return true;
}
@@ -272,14 +345,14 @@
// 255 = Invalid. The whole timing frame extension should be ignored.
//
// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | ID | len=12| flags | encode start ms delta |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | encode finish ms delta | packetizer finish ms delta |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | pacer exit ms delta | network timestamp ms delta |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=12| flags | encode start ms delta |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | encode finish ms delta | packetizer finish ms delta |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | pacer exit ms delta | network timestamp ms delta |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | network2 timestamp ms delta |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -436,38 +509,39 @@
// Color space including HDR metadata as an optional field.
//
-// RTP header extension to carry HDR metadata.
-// Float values are upscaled by a static factor and transmitted as integers.
+// RTP header extension to carry color space information and optionally HDR
+// metadata. The float values in the HDR metadata struct are upscaled by a
+// static factor and transmitted as unsigned integers.
//
-// Data layout with HDR metadata
+// Data layout of color space with HDR metadata (two-byte RTP header extension)
// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | ID | length=30 | Primaries | Transfer |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | Matrix | Range | luminance_max |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | | luminance_min |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | mastering_metadata.primary_r.x and .y |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | mastering_metadata.primary_g.x and .y |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | mastering_metadata.primary_b.x and .y |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | mastering_metadata.white.x and .y |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | max_content_light_level | max_frame_average_light_level |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | length=28 | primaries | transfer |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | matrix |range+chr.sit. | luminance_max |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | luminance_min | mastering_metadata.|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |primary_r.x and .y | mastering_metadata.|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |primary_g.x and .y | mastering_metadata.|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |primary_b.x and .y | mastering_metadata.|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |white.x and .y | max_content_light_level |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | max_frame_average_light_level |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
-// Data layout without HDR metadata
+// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | ID | length=4 | Primaries | Transfer |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | Matrix | Range |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | L = 3 | primaries | transfer | matrix |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |range+chr.sit. |
+// +-+-+-+-+-+-+-+-+
constexpr RTPExtensionType ColorSpaceExtension::kId;
constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
@@ -482,13 +556,21 @@
size_t offset = 0;
// Read color space information.
- if (!color_space->set_primaries_from_uint8(data.data()[offset++]))
+ if (!color_space->set_primaries_from_uint8(data[offset++]))
return false;
- if (!color_space->set_transfer_from_uint8(data.data()[offset++]))
+ if (!color_space->set_transfer_from_uint8(data[offset++]))
return false;
- if (!color_space->set_matrix_from_uint8(data.data()[offset++]))
+ if (!color_space->set_matrix_from_uint8(data[offset++]))
return false;
- if (!color_space->set_range_from_uint8(data.data()[offset++]))
+
+ uint8_t range_and_chroma_siting = data[offset++];
+ if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
+ return false;
+ if (!color_space->set_chroma_siting_horizontal_from_uint8(
+ (range_and_chroma_siting >> 2) & 0x03))
+ return false;
+ if (!color_space->set_chroma_siting_vertical_from_uint8(
+ range_and_chroma_siting & 0x03))
return false;
// Read HDR metadata if it exists, otherwise clear it.
@@ -496,26 +578,9 @@
color_space->set_hdr_metadata(nullptr);
} else {
HdrMetadata hdr_metadata;
- offset += ParseLuminance(data.data() + offset,
- &hdr_metadata.mastering_metadata.luminance_max,
- kLuminanceMaxDenominator);
- offset += ParseLuminance(data.data() + offset,
- &hdr_metadata.mastering_metadata.luminance_min,
- kLuminanceMinDenominator);
- offset += ParseChromaticity(data.data() + offset,
- &hdr_metadata.mastering_metadata.primary_r);
- offset += ParseChromaticity(data.data() + offset,
- &hdr_metadata.mastering_metadata.primary_g);
- offset += ParseChromaticity(data.data() + offset,
- &hdr_metadata.mastering_metadata.primary_b);
- offset += ParseChromaticity(data.data() + offset,
- &hdr_metadata.mastering_metadata.white_point);
- hdr_metadata.max_content_light_level =
- ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
- offset += 2;
- hdr_metadata.max_frame_average_light_level =
- ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
- offset += 2;
+ offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
+ if (!hdr_metadata.Validate())
+ return false;
color_space->set_hdr_metadata(&hdr_metadata);
}
RTC_DCHECK_EQ(ValueSize(*color_space), offset);
@@ -524,43 +589,70 @@
bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
const ColorSpace& color_space) {
- RTC_DCHECK(data.size() >= ValueSize(color_space));
+ RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
size_t offset = 0;
// Write color space information.
- data.data()[offset++] = static_cast<uint8_t>(color_space.primaries());
- data.data()[offset++] = static_cast<uint8_t>(color_space.transfer());
- data.data()[offset++] = static_cast<uint8_t>(color_space.matrix());
- data.data()[offset++] = static_cast<uint8_t>(color_space.range());
+ data[offset++] = static_cast<uint8_t>(color_space.primaries());
+ data[offset++] = static_cast<uint8_t>(color_space.transfer());
+ data[offset++] = static_cast<uint8_t>(color_space.matrix());
+ data[offset++] = CombineRangeAndChromaSiting(
+ color_space.range(), color_space.chroma_siting_horizontal(),
+ color_space.chroma_siting_vertical());
// Write HDR metadata if it exists.
if (color_space.hdr_metadata()) {
- const HdrMetadata& hdr_metadata = *color_space.hdr_metadata();
- offset += WriteLuminance(data.data() + offset,
- hdr_metadata.mastering_metadata.luminance_max,
- kLuminanceMaxDenominator);
- offset += WriteLuminance(data.data() + offset,
- hdr_metadata.mastering_metadata.luminance_min,
- kLuminanceMinDenominator);
- offset += WriteChromaticity(data.data() + offset,
- hdr_metadata.mastering_metadata.primary_r);
- offset += WriteChromaticity(data.data() + offset,
- hdr_metadata.mastering_metadata.primary_g);
- offset += WriteChromaticity(data.data() + offset,
- hdr_metadata.mastering_metadata.primary_b);
- offset += WriteChromaticity(data.data() + offset,
- hdr_metadata.mastering_metadata.white_point);
-
- ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
- hdr_metadata.max_content_light_level);
- offset += 2;
- ByteWriter<uint16_t>::WriteBigEndian(
- data.data() + offset, hdr_metadata.max_frame_average_light_level);
- offset += 2;
+ offset +=
+ WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
}
RTC_DCHECK_EQ(ValueSize(color_space), offset);
return true;
}
+// Combines range and chroma siting into one byte with the following bit layout:
+// bits 0-1 Chroma siting vertical.
+// 2-3 Chroma siting horizontal.
+// 4-5 Range.
+// 6-7 Unused.
+uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
+ ColorSpace::RangeID range,
+ ColorSpace::ChromaSiting chroma_siting_horizontal,
+ ColorSpace::ChromaSiting chroma_siting_vertical) {
+ RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
+ RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
+ RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
+ return (static_cast<uint8_t>(range) << 4) |
+ (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
+ static_cast<uint8_t>(chroma_siting_vertical);
+}
+
+size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
+ HdrMetadata* hdr_metadata) {
+ RTC_DCHECK_EQ(data.size(),
+ kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
+ size_t offset = 0;
+ offset += ParseLuminance(data.data() + offset,
+ &hdr_metadata->mastering_metadata.luminance_max,
+ kLuminanceMaxDenominator);
+ offset += ParseLuminance(data.data() + offset,
+ &hdr_metadata->mastering_metadata.luminance_min,
+ kLuminanceMinDenominator);
+ offset += ParseChromaticity(data.data() + offset,
+ &hdr_metadata->mastering_metadata.primary_r);
+ offset += ParseChromaticity(data.data() + offset,
+ &hdr_metadata->mastering_metadata.primary_g);
+ offset += ParseChromaticity(data.data() + offset,
+ &hdr_metadata->mastering_metadata.primary_b);
+ offset += ParseChromaticity(data.data() + offset,
+ &hdr_metadata->mastering_metadata.white_point);
+ hdr_metadata->max_content_light_level =
+ ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
+ offset += 2;
+ hdr_metadata->max_frame_average_light_level =
+ ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
+ offset += 2;
+ return offset;
+}
+
size_t ColorSpaceExtension::ParseChromaticity(
const uint8_t* data,
HdrMasteringMetadata::Chromaticity* p) {
@@ -575,16 +667,48 @@
size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
float* f,
int denominator) {
- uint32_t luminance_scaled = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+ uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
*f = static_cast<float>(luminance_scaled) / denominator;
- return 3; // Return number of bytes read.
+ return 2; // Return number of bytes read.
+}
+
+size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
+ const HdrMetadata& hdr_metadata) {
+ RTC_DCHECK_EQ(data.size(),
+ kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
+ RTC_DCHECK(hdr_metadata.Validate());
+ size_t offset = 0;
+ offset += WriteLuminance(data.data() + offset,
+ hdr_metadata.mastering_metadata.luminance_max,
+ kLuminanceMaxDenominator);
+ offset += WriteLuminance(data.data() + offset,
+ hdr_metadata.mastering_metadata.luminance_min,
+ kLuminanceMinDenominator);
+ offset += WriteChromaticity(data.data() + offset,
+ hdr_metadata.mastering_metadata.primary_r);
+ offset += WriteChromaticity(data.data() + offset,
+ hdr_metadata.mastering_metadata.primary_g);
+ offset += WriteChromaticity(data.data() + offset,
+ hdr_metadata.mastering_metadata.primary_b);
+ offset += WriteChromaticity(data.data() + offset,
+ hdr_metadata.mastering_metadata.white_point);
+
+ ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
+ hdr_metadata.max_content_light_level);
+ offset += 2;
+ ByteWriter<uint16_t>::WriteBigEndian(
+ data.data() + offset, hdr_metadata.max_frame_average_light_level);
+ offset += 2;
+ return offset;
}
size_t ColorSpaceExtension::WriteChromaticity(
uint8_t* data,
const HdrMasteringMetadata::Chromaticity& p) {
RTC_DCHECK_GE(p.x, 0.0f);
+ RTC_DCHECK_LE(p.x, 1.0f);
RTC_DCHECK_GE(p.y, 0.0f);
+ RTC_DCHECK_LE(p.y, 1.0f);
ByteWriter<uint16_t>::WriteBigEndian(
data, std::round(p.x * kChromaticityDenominator));
ByteWriter<uint16_t>::WriteBigEndian(
@@ -596,8 +720,10 @@
float f,
int denominator) {
RTC_DCHECK_GE(f, 0.0f);
- ByteWriter<uint32_t, 3>::WriteBigEndian(data, std::round(f * denominator));
- return 3; // Return number of bytes written.
+ float upscaled_value = f * denominator;
+ RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
+ ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
+ return 2; // Return number of bytes written.
}
bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h
index 42a6216..8aacb9a 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -81,9 +81,38 @@
static constexpr const char kUri[] =
"http://www.ietf.org/id/"
"draft-holmer-rmcat-transport-wide-cc-extensions-01";
- static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value);
- static size_t ValueSize(uint16_t value) { return kValueSizeBytes; }
- static bool Write(rtc::ArrayView<uint8_t> data, uint16_t value);
+ static bool Parse(rtc::ArrayView<const uint8_t> data,
+ uint16_t* transport_sequence_number);
+ static size_t ValueSize(uint16_t /*transport_sequence_number*/) {
+ return kValueSizeBytes;
+ }
+ static bool Write(rtc::ArrayView<uint8_t> data,
+ uint16_t transport_sequence_number);
+};
+
+class TransportSequenceNumberV2 {
+ public:
+ static constexpr RTPExtensionType kId =
+ kRtpExtensionTransportSequenceNumber02;
+ static constexpr uint8_t kValueSizeBytes = 4;
+ static constexpr uint8_t kValueSizeBytesWithoutFeedbackRequest = 2;
+ static constexpr const char kUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02";
+ static bool Parse(rtc::ArrayView<const uint8_t> data,
+ uint16_t* transport_sequence_number,
+ absl::optional<FeedbackRequest>* feedback_request);
+ static size_t ValueSize(
+ uint16_t /*transport_sequence_number*/,
+ const absl::optional<FeedbackRequest>& feedback_request) {
+ return feedback_request ? kValueSizeBytes
+ : kValueSizeBytesWithoutFeedbackRequest;
+ }
+ static bool Write(rtc::ArrayView<uint8_t> data,
+ uint16_t transport_sequence_number,
+ const absl::optional<FeedbackRequest>& feedback_request);
+
+ private:
+ static constexpr uint16_t kIncludeTimestampsBit = 1 << 15;
};
class VideoOrientation {
@@ -186,10 +215,10 @@
public:
using value_type = ColorSpace;
static constexpr RTPExtensionType kId = kRtpExtensionColorSpace;
- static constexpr uint8_t kValueSizeBytes = 30;
+ static constexpr uint8_t kValueSizeBytes = 28;
static constexpr uint8_t kValueSizeBytesWithoutHdrMetadata = 4;
- // TODO(webrtc:8651): Change to a valid uri.
- static constexpr const char kUri[] = "rtp-colorspace-uri-placeholder";
+ static constexpr const char kUri[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/color-space";
static bool Parse(rtc::ArrayView<const uint8_t> data,
ColorSpace* color_space);
@@ -201,12 +230,21 @@
const ColorSpace& color_space);
private:
- static constexpr int kChromaticityDenominator = 10000; // 0.0001 resolution.
- static constexpr int kLuminanceMaxDenominator = 100; // 0.01 resolution.
+ static constexpr int kChromaticityDenominator = 50000; // 0.00002 resolution.
+ static constexpr int kLuminanceMaxDenominator = 1; // 1 resolution.
static constexpr int kLuminanceMinDenominator = 10000; // 0.0001 resolution.
+
+ static uint8_t CombineRangeAndChromaSiting(
+ ColorSpace::RangeID range,
+ ColorSpace::ChromaSiting chroma_siting_horizontal,
+ ColorSpace::ChromaSiting chroma_siting_vertical);
+ static size_t ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
+ HdrMetadata* hdr_metadata);
static size_t ParseChromaticity(const uint8_t* data,
HdrMasteringMetadata::Chromaticity* p);
static size_t ParseLuminance(const uint8_t* data, float* f, int denominator);
+ static size_t WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
+ const HdrMetadata& hdr_metadata);
static size_t WriteChromaticity(uint8_t* data,
const HdrMasteringMetadata::Chromaticity& p);
static size_t WriteLuminance(uint8_t* data, float f, int denominator);
diff --git a/modules/rtp_rtcp/source/rtp_header_parser.cc b/modules/rtp_rtcp/source/rtp_header_parser.cc
index 6481a40..4e4c723 100644
--- a/modules/rtp_rtcp/source/rtp_header_parser.cc
+++ b/modules/rtp_rtcp/source/rtp_header_parser.cc
@@ -13,7 +13,7 @@
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc
index 9d4dce4..91f0c59 100644
--- a/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/modules/rtp_rtcp/source/rtp_packet.cc
@@ -14,7 +14,7 @@
#include <cstring>
#include <utility>
-#include "api/rtpparameters.h"
+#include "api/rtp_parameters.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
@@ -61,12 +61,10 @@
RtpPacket::RtpPacket(const RtpPacket&) = default;
RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
- : buffer_(capacity) {
+ : extensions_(extensions ? *extensions : ExtensionManager()),
+ buffer_(capacity) {
RTC_DCHECK_GE(capacity, kFixedHeaderSize);
Clear();
- if (extensions) {
- extensions_ = *extensions;
- }
}
RtpPacket::~RtpPacket() {}
@@ -569,4 +567,9 @@
return AllocateRawExtension(id, length);
}
+bool RtpPacket::HasExtension(ExtensionType type) const {
+ // TODO(webrtc:7990): Add support for empty extensions (length==0).
+ return !FindExtension(type).empty();
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet.h b/modules/rtp_rtcp/source/rtp_packet.h
index 76666b7..c067580 100644
--- a/modules/rtp_rtcp/source/rtp_packet.h
+++ b/modules/rtp_rtcp/source/rtp_packet.h
@@ -16,7 +16,7 @@
#include "api/array_view.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/deprecation.h"
namespace webrtc {
@@ -95,6 +95,7 @@
// Header extensions.
template <typename Extension>
bool HasExtension() const;
+ bool HasExtension(ExtensionType type) const;
template <typename Extension, typename FirstValue, typename... Values>
bool GetExtension(FirstValue, Values...) const;
@@ -112,6 +113,14 @@
template <typename Extension>
bool ReserveExtension();
+ // Find or allocate an extension |type|. Returns view of size |length|
+ // to write raw extension to or an empty view on failure.
+ rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
+
+ // Find an extension |type|.
+ // Returns view of the raw extension or empty view on failure.
+ rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
+
// Reserve size_bytes for payload. Returns nullptr on failure.
uint8_t* SetPayloadSize(size_t size_bytes);
// Same as SetPayloadSize but doesn't guarantee to keep current payload.
@@ -145,10 +154,6 @@
// with the specified id if not found.
ExtensionInfo& FindOrCreateExtensionInfo(int id);
- // Find an extension |type|.
- // Returns view of the raw extension or empty view on failure.
- rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
-
// Allocates and returns place to store rtp header extension.
// Returns empty arrayview on failure.
rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length);
@@ -159,10 +164,6 @@
uint16_t SetExtensionLengthMaybeAddZeroPadding(size_t extensions_offset);
- // Find or allocate an extension |type|. Returns view of size |length|
- // to write raw extension to or an empty view on failure.
- rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
-
uint8_t* WriteAt(size_t offset) { return buffer_.data() + offset; }
void WriteAt(size_t offset, uint8_t byte) { buffer_.data()[offset] = byte; }
@@ -184,7 +185,7 @@
template <typename Extension>
bool RtpPacket::HasExtension() const {
- return !FindExtension(Extension::kId).empty();
+ return HasExtension(Extension::kId);
}
template <typename Extension, typename FirstValue, typename... Values>
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc
index 8c1c8eb..ac39e22 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_history.cc
@@ -315,7 +315,7 @@
state.send_time_ms = stored_packet.send_time_ms;
state.capture_time_ms = stored_packet.packet->capture_time_ms();
state.ssrc = stored_packet.packet->Ssrc();
- state.payload_size = stored_packet.packet->size();
+ state.packet_size = stored_packet.packet->size();
state.times_retransmitted = stored_packet.times_retransmitted;
return state;
}
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h
index 095424e..5e6463b 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history.h
+++ b/modules/rtp_rtcp/source/rtp_packet_history.h
@@ -16,8 +16,8 @@
#include <vector>
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@@ -44,7 +44,7 @@
absl::optional<int64_t> send_time_ms;
int64_t capture_time_ms = 0;
uint32_t ssrc = 0;
- size_t payload_size = 0;
+ size_t packet_size = 0;
// Number of times RE-transmitted, ie not including the first transmission.
size_t times_retransmitted = 0;
};
diff --git a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
index 140434c..afa158c 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
@@ -191,7 +191,7 @@
EXPECT_EQ(state->send_time_ms, fake_clock_.TimeInMilliseconds());
EXPECT_EQ(state->capture_time_ms, fake_clock_.TimeInMilliseconds());
EXPECT_EQ(state->ssrc, kSsrc);
- EXPECT_EQ(state->payload_size, packet_size);
+ EXPECT_EQ(state->packet_size, packet_size);
EXPECT_EQ(state->times_retransmitted, 0u);
fake_clock_.AdvanceTimeMilliseconds(1);
@@ -228,7 +228,7 @@
absl::optional<RtpPacketHistory::PacketState> packet_state =
hist_.GetPacketState(kStartSeqNum);
EXPECT_TRUE(packet_state);
- EXPECT_EQ(len, packet_state->payload_size);
+ EXPECT_EQ(len, packet_state->packet_size);
EXPECT_EQ(capture_time_ms, packet_state->capture_time_ms);
// Retransmission was allowed, next send it from pacer.
diff --git a/modules/rtp_rtcp/source/rtp_packet_received.cc b/modules/rtp_rtcp/source/rtp_packet_received.cc
index f80fad6..2a36b7b 100644
--- a/modules/rtp_rtcp/source/rtp_packet_received.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_received.cc
@@ -52,6 +52,9 @@
header->extension.hasAbsoluteSendTime =
GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
header->extension.hasTransportSequenceNumber =
+ GetExtension<TransportSequenceNumberV2>(
+ &header->extension.transportSequenceNumber,
+ &header->extension.feedback_request) ||
GetExtension<TransportSequenceNumber>(
&header->extension.transportSequenceNumber);
header->extension.hasAudioLevel = GetExtension<AudioLevel>(
diff --git a/modules/rtp_rtcp/source/rtp_packet_to_send.h b/modules/rtp_rtcp/source/rtp_packet_to_send.h
index 56b1024..21c9c86 100644
--- a/modules/rtp_rtcp/source/rtp_packet_to_send.h
+++ b/modules/rtp_rtcp/source/rtp_packet_to_send.h
@@ -38,6 +38,10 @@
void set_capture_time_ms(int64_t time) { capture_time_ms_ = time; }
+ bool is_fec() const { return is_fec_; }
+
+ void set_is_fec(bool fec) { is_fec_ = fec; }
+
// Additional data bound to the RTP packet for use in application code,
// outside of WebRTC.
rtc::ArrayView<const uint8_t> application_data() const {
@@ -74,6 +78,8 @@
private:
int64_t capture_time_ms_ = 0;
+ // Used for accounting purposes
+ bool is_fec_ = false;
std::vector<uint8_t> application_data_;
};
diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc
index b1c0e42..84f5020 100644
--- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -10,6 +10,7 @@
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "common_video/test/utilities.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "rtc_base/random.h"
@@ -186,35 +187,6 @@
0x00, 0x00, 0x00, 0x00};
// clang-format on
-HdrMetadata CreateTestHdrMetadata() {
- // Random but reasonable HDR metadata.
- HdrMetadata hdr_metadata;
- hdr_metadata.mastering_metadata.luminance_max = 2000.0;
- hdr_metadata.mastering_metadata.luminance_min = 2.0001;
- hdr_metadata.mastering_metadata.primary_r.x = 0.3003;
- hdr_metadata.mastering_metadata.primary_r.y = 0.4004;
- hdr_metadata.mastering_metadata.primary_g.x = 0.3201;
- hdr_metadata.mastering_metadata.primary_g.y = 0.4604;
- hdr_metadata.mastering_metadata.primary_b.x = 0.3409;
- hdr_metadata.mastering_metadata.primary_b.y = 0.4907;
- hdr_metadata.mastering_metadata.white_point.x = 0.4103;
- hdr_metadata.mastering_metadata.white_point.y = 0.4806;
- hdr_metadata.max_content_light_level = 2345;
- hdr_metadata.max_frame_average_light_level = 1789;
- return hdr_metadata;
-}
-
-ColorSpace CreateTestColorSpace(bool with_hdr_metadata) {
- ColorSpace color_space(
- ColorSpace::PrimaryID::kBT709, ColorSpace::TransferID::kGAMMA22,
- ColorSpace::MatrixID::kSMPTE2085, ColorSpace::RangeID::kFull);
- if (with_hdr_metadata) {
- HdrMetadata hdr_metadata = CreateTestHdrMetadata();
- color_space.set_hdr_metadata(&hdr_metadata);
- }
- return color_space;
-}
-
void TestCreateAndParseColorSpaceExtension(bool with_hdr_metadata) {
// Create packet with extension.
RtpPacket::ExtensionManager extensions(/*extmap-allow-mixed=*/true);
@@ -855,4 +827,129 @@
TestCreateAndParseColorSpaceExtension(/*with_hdr_metadata=*/false);
}
+TEST(RtpPacketTest, CreateAndParseTransportSequenceNumber) {
+ // Create a packet with transport sequence number extension populated.
+ RtpPacketToSend::ExtensionManager extensions;
+ constexpr int kExtensionId = 1;
+ extensions.Register<TransportSequenceNumber>(kExtensionId);
+ RtpPacketToSend send_packet(&extensions);
+ send_packet.SetPayloadType(kPayloadType);
+ send_packet.SetSequenceNumber(kSeqNum);
+ send_packet.SetTimestamp(kTimestamp);
+ send_packet.SetSsrc(kSsrc);
+
+ constexpr int kTransportSequenceNumber = 12345;
+ send_packet.SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
+
+ // Serialize the packet and then parse it again.
+ RtpPacketReceived receive_packet(&extensions);
+ EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer()));
+
+ uint16_t received_transport_sequeunce_number;
+ EXPECT_TRUE(receive_packet.GetExtension<TransportSequenceNumber>(
+ &received_transport_sequeunce_number));
+ EXPECT_EQ(received_transport_sequeunce_number, kTransportSequenceNumber);
+}
+
+TEST(RtpPacketTest, CreateAndParseTransportSequenceNumberV2) {
+ // Create a packet with transport sequence number V2 extension populated.
+ // No feedback request means that the extension will be two bytes unless it's
+ // pre-allocated.
+ RtpPacketToSend::ExtensionManager extensions;
+ constexpr int kExtensionId = 1;
+ extensions.Register<TransportSequenceNumberV2>(kExtensionId);
+ RtpPacketToSend send_packet(&extensions);
+ send_packet.SetPayloadType(kPayloadType);
+ send_packet.SetSequenceNumber(kSeqNum);
+ send_packet.SetTimestamp(kTimestamp);
+ send_packet.SetSsrc(kSsrc);
+
+ constexpr int kTransportSequenceNumber = 12345;
+ send_packet.SetExtension<TransportSequenceNumberV2>(kTransportSequenceNumber,
+ absl::nullopt);
+ EXPECT_EQ(send_packet.GetRawExtension<TransportSequenceNumberV2>().size(),
+ 2u);
+
+ // Serialize the packet and then parse it again.
+ RtpPacketReceived receive_packet(&extensions);
+ EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer()));
+
+ uint16_t received_transport_sequeunce_number;
+ absl::optional<FeedbackRequest> received_feedback_request;
+ EXPECT_TRUE(receive_packet.GetExtension<TransportSequenceNumberV2>(
+ &received_transport_sequeunce_number, &received_feedback_request));
+ EXPECT_EQ(received_transport_sequeunce_number, kTransportSequenceNumber);
+ EXPECT_FALSE(received_feedback_request);
+}
+
+TEST(RtpPacketTest, CreateAndParseTransportSequenceNumberV2Preallocated) {
+ // Create a packet with transport sequence number V2 extension populated.
+ // No feedback request means that the extension could be two bytes, but since
+ // it's pre-allocated we don't know if it is with or without feedback request
+ // therefore the size is four bytes.
+ RtpPacketToSend::ExtensionManager extensions;
+ constexpr int kExtensionId = 1;
+ extensions.Register<TransportSequenceNumberV2>(kExtensionId);
+ RtpPacketToSend send_packet(&extensions);
+ send_packet.SetPayloadType(kPayloadType);
+ send_packet.SetSequenceNumber(kSeqNum);
+ send_packet.SetTimestamp(kTimestamp);
+ send_packet.SetSsrc(kSsrc);
+
+ constexpr int kTransportSequenceNumber = 12345;
+ constexpr absl::optional<FeedbackRequest> kNoFeedbackRequest =
+ FeedbackRequest{/*include_timestamps=*/false, /*sequence_count=*/0};
+ send_packet.ReserveExtension<TransportSequenceNumberV2>();
+ send_packet.SetExtension<TransportSequenceNumberV2>(kTransportSequenceNumber,
+ kNoFeedbackRequest);
+ EXPECT_EQ(send_packet.GetRawExtension<TransportSequenceNumberV2>().size(),
+ 4u);
+
+ // Serialize the packet and then parse it again.
+ RtpPacketReceived receive_packet(&extensions);
+ EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer()));
+
+ uint16_t received_transport_sequeunce_number;
+ absl::optional<FeedbackRequest> received_feedback_request;
+ EXPECT_TRUE(receive_packet.GetExtension<TransportSequenceNumberV2>(
+ &received_transport_sequeunce_number, &received_feedback_request));
+ EXPECT_EQ(received_transport_sequeunce_number, kTransportSequenceNumber);
+ EXPECT_FALSE(received_feedback_request);
+}
+
+TEST(RtpPacketTest,
+ CreateAndParseTransportSequenceNumberV2WithFeedbackRequest) {
+ // Create a packet with TransportSequenceNumberV2 extension populated.
+ RtpPacketToSend::ExtensionManager extensions;
+ constexpr int kExtensionId = 1;
+ extensions.Register<TransportSequenceNumberV2>(kExtensionId);
+ RtpPacketToSend send_packet(&extensions);
+ send_packet.SetPayloadType(kPayloadType);
+ send_packet.SetSequenceNumber(kSeqNum);
+ send_packet.SetTimestamp(kTimestamp);
+ send_packet.SetSsrc(kSsrc);
+
+ constexpr int kTransportSequenceNumber = 12345;
+ constexpr absl::optional<FeedbackRequest> kFeedbackRequest =
+ FeedbackRequest{/*include_timestamps=*/true, /*sequence_count=*/3};
+ send_packet.SetExtension<TransportSequenceNumberV2>(kTransportSequenceNumber,
+ kFeedbackRequest);
+
+ // Serialize the packet and then parse it again.
+ RtpPacketReceived receive_packet(&extensions);
+ EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer()));
+
+ // Parse transport sequence number and feedback request.
+ uint16_t received_transport_sequeunce_number;
+ absl::optional<FeedbackRequest> received_feedback_request;
+ EXPECT_TRUE(receive_packet.GetExtension<TransportSequenceNumberV2>(
+ &received_transport_sequeunce_number, &received_feedback_request));
+ EXPECT_EQ(received_transport_sequeunce_number, kTransportSequenceNumber);
+ ASSERT_TRUE(received_feedback_request);
+ EXPECT_EQ(received_feedback_request->include_timestamps,
+ kFeedbackRequest->include_timestamps);
+ EXPECT_EQ(received_feedback_request->sequence_count,
+ kFeedbackRequest->sequence_count);
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 0d0ca96..2adddff 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -17,6 +17,8 @@
#include <string>
#include <utility>
+#include "absl/memory/memory.h"
+#include "api/transport/field_trial_based_config.h"
#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
#include "rtc_base/checks.h"
@@ -51,14 +53,6 @@
}
}
-// Deprecated.
-int32_t RtpRtcp::SetFecParameters(const FecProtectionParams* delta_params,
- const FecProtectionParams* key_params) {
- RTC_DCHECK(delta_params);
- RTC_DCHECK(key_params);
- return SetFecParameters(*delta_params, *key_params) ? 0 : -1;
-}
-
ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
: rtcp_sender_(configuration.audio,
configuration.clock,
@@ -83,7 +77,6 @@
: kDefaultVideoReportInterval),
this),
clock_(configuration.clock),
- audio_(configuration.audio),
keepalive_config_(configuration.keepalive_config),
last_bitrate_process_time_(clock_->TimeInMilliseconds()),
last_rtt_process_time_(clock_->TimeInMilliseconds()),
@@ -95,24 +88,32 @@
nack_last_seq_number_sent_(0),
key_frame_req_method_(kKeyFrameReqPliRtcp),
remote_bitrate_(configuration.remote_bitrate_estimator),
+ ack_observer_(configuration.ack_observer),
rtt_stats_(configuration.rtt_stats),
rtt_ms_(0) {
+ FieldTrialBasedConfig default_trials;
if (!configuration.receiver_only) {
rtp_sender_.reset(new RTPSender(
configuration.audio, configuration.clock,
configuration.outgoing_transport, configuration.paced_sender,
- configuration.flexfec_sender,
+ configuration.flexfec_sender
+ ? absl::make_optional(configuration.flexfec_sender->ssrc())
+ : absl::nullopt,
configuration.transport_sequence_number_allocator,
configuration.transport_feedback_callback,
configuration.send_bitrate_observer,
- configuration.send_frame_count_observer,
configuration.send_side_delay_observer, configuration.event_log,
configuration.send_packet_observer,
configuration.retransmission_rate_limiter,
configuration.overhead_observer,
configuration.populate_network2_timestamp,
configuration.frame_encryptor, configuration.require_frame_encryption,
- configuration.extmap_allow_mixed));
+ configuration.extmap_allow_mixed,
+ configuration.field_trials ? *configuration.field_trials
+ : default_trials));
+ if (configuration.audio) {
+ audio_ = absl::make_unique<RTPSenderAudio>(clock_, rtp_sender_.get());
+ }
// Make sure rtcp sender use same timestamp offset as rtp sender.
rtcp_sender_.SetTimestampOffset(rtp_sender_->TimestampOffset());
@@ -264,23 +265,24 @@
rtcp_receiver_.IncomingPacket(rtcp_packet, length);
}
-int32_t ModuleRtpRtcpImpl::RegisterSendPayload(const CodecInst& voice_codec) {
- rtcp_sender_.SetRtpClockRate(voice_codec.pltype, voice_codec.plfreq);
- return rtp_sender_->RegisterPayload(
- voice_codec.plname, voice_codec.pltype, voice_codec.plfreq,
- voice_codec.channels, (voice_codec.rate < 0) ? 0 : voice_codec.rate);
+void ModuleRtpRtcpImpl::RegisterAudioSendPayload(int payload_type,
+ absl::string_view payload_name,
+ int frequency,
+ int channels,
+ int rate) {
+ RTC_DCHECK(audio_);
+ rtcp_sender_.SetRtpClockRate(payload_type, frequency);
+ RTC_CHECK_EQ(0, audio_->RegisterAudioPayload(payload_name, payload_type,
+ frequency, channels, rate));
}
-void ModuleRtpRtcpImpl::RegisterVideoSendPayload(int payload_type,
- const char* payload_name) {
- rtcp_sender_.SetRtpClockRate(payload_type, kVideoPayloadTypeFrequency);
- RTC_CHECK_EQ(0,
- rtp_sender_->RegisterPayload(payload_name, payload_type,
- kVideoPayloadTypeFrequency, 0, 0));
+void ModuleRtpRtcpImpl::RegisterSendPayloadFrequency(int payload_type,
+ int payload_frequency) {
+ rtcp_sender_.SetRtpClockRate(payload_type, payload_frequency);
}
int32_t ModuleRtpRtcpImpl::DeRegisterSendPayload(const int8_t payload_type) {
- return rtp_sender_->DeRegisterSendPayload(payload_type);
+ return 0;
}
uint32_t ModuleRtpRtcpImpl::StartTimestamp() const {
@@ -331,6 +333,12 @@
SetRtcpReceiverSsrcs(ssrc);
}
+void ModuleRtpRtcpImpl::SetRid(const std::string& rid) {
+ if (rtp_sender_) {
+ rtp_sender_->SetRid(rid);
+ }
+}
+
void ModuleRtpRtcpImpl::SetMid(const std::string& mid) {
if (rtp_sender_) {
rtp_sender_->SetMid(mid);
@@ -422,25 +430,33 @@
const RTPFragmentationHeader* fragmentation,
const RTPVideoHeader* rtp_video_header,
uint32_t* transport_frame_id_out) {
- rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms, payload_type);
+ OnSendingRtpFrame(time_stamp, capture_time_ms, payload_type,
+ kVideoFrameKey == frame_type);
+
+ const uint32_t rtp_timestamp = time_stamp + rtp_sender_->TimestampOffset();
+ if (transport_frame_id_out)
+ *transport_frame_id_out = rtp_timestamp;
+
+ RTC_DCHECK(audio_);
+ RTC_DCHECK(fragmentation == nullptr);
+
+ return audio_->SendAudio(frame_type, payload_type, rtp_timestamp,
+ payload_data, payload_size);
+}
+
+bool ModuleRtpRtcpImpl::OnSendingRtpFrame(uint32_t timestamp,
+ int64_t capture_time_ms,
+ int payload_type,
+ bool force_sender_report) {
+ if (!Sending())
+ return false;
+
+ rtcp_sender_.SetLastRtpTime(timestamp, capture_time_ms, payload_type);
// Make sure an RTCP report isn't queued behind a key frame.
- if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
+ if (rtcp_sender_.TimeToSendRTCPReport(force_sender_report))
rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);
- }
- int64_t expected_retransmission_time_ms = rtt_ms();
- if (expected_retransmission_time_ms == 0) {
- // No rtt available (|kRtpRtcpRttProcessTimeMs| not yet passed?), so try to
- // poll avg_rtt_ms directly from rtcp receiver.
- if (rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), nullptr,
- &expected_retransmission_time_ms, nullptr,
- nullptr) == -1) {
- expected_retransmission_time_ms = kDefaultExpectedRetransmissionTimeMs;
- }
- }
- return rtp_sender_->SendOutgoingData(
- frame_type, payload_type, time_stamp, capture_time_ms, payload_data,
- payload_size, fragmentation, rtp_video_header, transport_frame_id_out,
- expected_retransmission_time_ms);
+
+ return true;
}
bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
@@ -525,6 +541,21 @@
return ret;
}
+int64_t ModuleRtpRtcpImpl::ExpectedRetransmissionTimeMs() const {
+ int64_t expected_retransmission_time_ms = rtt_ms();
+ if (expected_retransmission_time_ms > 0) {
+ return expected_retransmission_time_ms;
+ }
+ // No rtt available (|kRtpRtcpRttProcessTimeMs| not yet passed?), so try to
+ // poll avg_rtt_ms directly from rtcp receiver.
+ if (rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), nullptr,
+ &expected_retransmission_time_ms, nullptr,
+ nullptr) == 0) {
+ return expected_retransmission_time_ms;
+ }
+ return kDefaultExpectedRetransmissionTimeMs;
+}
+
// Force a send of an RTCP packet.
// Normal SR and RR are triggered via the process function.
int32_t ModuleRtpRtcpImpl::SendRTCP(RTCPPacketType packet_type) {
@@ -666,17 +697,6 @@
rtcp_sender_.SetTmmbn(std::move(bounding_set));
}
-// Returns the currently configured retransmission mode.
-int ModuleRtpRtcpImpl::SelectiveRetransmissions() const {
- return rtp_sender_->SelectiveRetransmissions();
-}
-
-// Enable or disable a retransmission mode, which decides which packets will
-// be retransmitted if NACKed.
-int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) {
- return rtp_sender_->SetSelectiveRetransmissions(settings);
-}
-
// Send a Negative acknowledgment packet.
int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
const uint16_t size) {
@@ -766,11 +786,11 @@
int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband(const uint8_t key,
const uint16_t time_ms,
const uint8_t level) {
- return rtp_sender_->SendTelephoneEvent(key, time_ms, level);
+ return audio_ ? audio_->SendTelephoneEvent(key, time_ms, level) : -1;
}
int32_t ModuleRtpRtcpImpl::SetAudioLevel(const uint8_t level_d_bov) {
- return rtp_sender_->SetAudioLevel(level_d_bov);
+ return audio_ ? audio_->SetAudioLevel(level_d_bov) : -1;
}
int32_t ModuleRtpRtcpImpl::SetKeyFrameRequestMethod(
@@ -789,15 +809,12 @@
return -1;
}
-void ModuleRtpRtcpImpl::SetUlpfecConfig(int red_payload_type,
- int ulpfec_payload_type) {
- rtp_sender_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
-}
-
-bool ModuleRtpRtcpImpl::SetFecParameters(
- const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params) {
- return rtp_sender_->SetFecParameters(delta_params, key_params);
+int32_t ModuleRtpRtcpImpl::SendLossNotification(uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag) {
+ return rtcp_sender_.SendLossNotification(
+ GetFeedbackState(), last_decoded_seq_num, last_received_seq_num,
+ decodability_flag);
}
void ModuleRtpRtcpImpl::SetRemoteSSRC(const uint32_t ssrc) {
@@ -806,13 +823,16 @@
rtcp_receiver_.SetRemoteSSRC(ssrc);
}
+// TODO(nisse): Delete video_rate amd fec_rate arguments.
void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate,
uint32_t* video_rate,
uint32_t* fec_rate,
uint32_t* nack_rate) const {
*total_rate = rtp_sender_->BitrateSent();
- *video_rate = rtp_sender_->VideoBitrateSent();
- *fec_rate = rtp_sender_->FecOverheadRate();
+ if (video_rate)
+ *video_rate = 0;
+ if (fec_rate)
+ *fec_rate = 0;
*nack_rate = rtp_sender_->NackOverheadRate();
}
@@ -841,8 +861,16 @@
void ModuleRtpRtcpImpl::OnReceivedRtcpReportBlocks(
const ReportBlockList& report_blocks) {
- if (rtp_sender_)
- rtp_sender_->OnReceivedRtcpReportBlocks(report_blocks);
+ if (ack_observer_) {
+ uint32_t ssrc = SSRC();
+
+ for (const RTCPReportBlock& report_block : report_blocks) {
+ if (ssrc == report_block.source_ssrc) {
+ ack_observer_->OnReceivedAck(
+ report_block.extended_highest_sequence_number);
+ }
+ }
+ }
}
bool ModuleRtpRtcpImpl::LastReceivedNTP(
@@ -904,4 +932,13 @@
const VideoBitrateAllocation& bitrate) {
rtcp_sender_.SetVideoBitrateAllocation(bitrate);
}
+
+RTPSender* ModuleRtpRtcpImpl::RtpSender() {
+ return rtp_sender_.get();
+}
+
+const RTPSender* ModuleRtpRtcpImpl::RtpSender() const {
+ return rtp_sender_.get();
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 8e9751d..20eb179 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -32,7 +32,9 @@
#include "modules/rtp_rtcp/source/rtcp_receiver.h"
#include "modules/rtp_rtcp/source/rtcp_sender.h"
#include "modules/rtp_rtcp/source/rtp_sender.h"
-#include "rtc_base/criticalsection.h"
+#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/gtest_prod_util.h"
namespace webrtc {
@@ -63,10 +65,13 @@
// Sender part.
- int32_t RegisterSendPayload(const CodecInst& voice_codec) override;
-
- void RegisterVideoSendPayload(int payload_type,
- const char* payload_name) override;
+ void RegisterAudioSendPayload(int payload_type,
+ absl::string_view payload_name,
+ int frequency,
+ int channels,
+ int rate) override;
+ void RegisterSendPayloadFrequency(int payload_type,
+ int payload_frequency) override;
int32_t DeRegisterSendPayload(int8_t payload_type) override;
@@ -102,6 +107,8 @@
// Configure SSRC, default is a random number.
void SetSSRC(uint32_t ssrc) override;
+ void SetRid(const std::string& rid) override;
+
void SetMid(const std::string& mid) override;
void SetCsrcs(const std::vector<uint32_t>& csrcs) override;
@@ -142,6 +149,11 @@
const RTPVideoHeader* rtp_video_header,
uint32_t* transport_frame_id_out) override;
+ bool OnSendingRtpFrame(uint32_t timestamp,
+ int64_t capture_time_ms,
+ int payload_type,
+ bool force_sender_report) override;
+
bool TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
int64_t capture_time_ms,
@@ -186,6 +198,8 @@
int64_t* min_rtt,
int64_t* max_rtt) const override;
+ int64_t ExpectedRetransmissionTimeMs() const override;
+
// Force a send of an RTCP packet.
// Normal SR and RR are triggered via the process function.
int32_t SendRTCP(RTCPPacketType rtcpPacketType) override;
@@ -227,10 +241,6 @@
// (NACK) Negative acknowledgment part.
- int SelectiveRetransmissions() const override;
-
- int SetSelectiveRetransmissions(uint8_t settings) override;
-
// Send a Negative acknowledgment packet.
// TODO(philipel): Deprecate SendNACK and use SendNack instead.
int32_t SendNACK(const uint16_t* nack_list, uint16_t size) override;
@@ -279,10 +289,9 @@
// Send a request for a keyframe.
int32_t RequestKeyFrame() override;
- void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) override;
-
- bool SetFecParameters(const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params) override;
+ int32_t SendLossNotification(uint16_t last_decoded_seq_num,
+ uint16_t last_received_seq_num,
+ bool decodability_flag) override;
bool LastReceivedNTP(uint32_t* NTPsecs,
uint32_t* NTPfrac,
@@ -309,6 +318,9 @@
void SetVideoBitrateAllocation(
const VideoBitrateAllocation& bitrate) override;
+ RTPSender* RtpSender() override;
+ const RTPSender* RtpSender() const override;
+
protected:
bool UpdateRTCPReceiveInformationTimers();
@@ -321,7 +333,7 @@
RTCPReceiver* rtcp_receiver() { return &rtcp_receiver_; }
const RTCPReceiver* rtcp_receiver() const { return &rtcp_receiver_; }
- const Clock* clock() const { return clock_; }
+ Clock* clock() const { return clock_; }
private:
FRIEND_TEST_ALL_PREFIXES(RtpRtcpImplTest, Rtt);
@@ -334,12 +346,11 @@
bool TimeToSendFullNackList(int64_t now) const;
std::unique_ptr<RTPSender> rtp_sender_;
+ std::unique_ptr<RTPSenderAudio> audio_;
RTCPSender rtcp_sender_;
RTCPReceiver rtcp_receiver_;
- const Clock* const clock_;
-
- const bool audio_;
+ Clock* const clock_;
const RtpKeepAliveConfig keepalive_config_;
int64_t last_bitrate_process_time_;
@@ -354,7 +365,9 @@
KeyFrameRequestMethod key_frame_req_method_;
- RemoteBitrateEstimator* remote_bitrate_;
+ RemoteBitrateEstimator* const remote_bitrate_;
+
+ RtcpAckObserver* const ack_observer_;
RtcpRttStats* const rtt_stats_;
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index 632a537..da541a5 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -12,9 +12,12 @@
#include <memory>
#include <set>
+#include "absl/memory/memory.h"
+#include "api/transport/field_trial_based_config.h"
#include "api/video_codecs/video_codec.h"
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
@@ -199,11 +202,15 @@
sender_.impl_->SetSequenceNumber(kSequenceNumber);
sender_.impl_->SetStorePacketsStatus(true, 100);
+ sender_video_ = absl::make_unique<RTPSenderVideo>(
+ &clock_, sender_.impl_->RtpSender(), nullptr, &playout_delay_oracle_,
+ nullptr, false, FieldTrialBasedConfig());
+
memset(&codec_, 0, sizeof(VideoCodec));
codec_.plType = 100;
codec_.width = 320;
codec_.height = 180;
- sender_.impl_->RegisterVideoSendPayload(codec_.plType, "VP8");
+ sender_video_->RegisterPayloadType(codec_.plType, "VP8");
// Receive module.
EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false));
@@ -217,10 +224,14 @@
SimulatedClock clock_;
RtpRtcpModule sender_;
+ PlayoutDelayOracle playout_delay_oracle_;
+ std::unique_ptr<RTPSenderVideo> sender_video_;
RtpRtcpModule receiver_;
VideoCodec codec_;
- void SendFrame(const RtpRtcpModule* module, uint8_t tid) {
+ void SendFrame(const RtpRtcpModule* module,
+ RTPSenderVideo* sender,
+ uint8_t tid) {
RTPVideoHeaderVP8 vp8_header = {};
vp8_header.temporalIdx = tid;
RTPVideoHeader rtp_video_header;
@@ -236,9 +247,10 @@
rtp_video_header.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false};
const uint8_t payload[100] = {0};
- EXPECT_EQ(true, module->impl_->SendOutgoingData(
- kVideoFrameKey, codec_.plType, 0, 0, payload,
- sizeof(payload), nullptr, &rtp_video_header, nullptr));
+ EXPECT_TRUE(module->impl_->OnSendingRtpFrame(0, 0, codec_.plType, true));
+ EXPECT_TRUE(sender->SendVideo(kVideoFrameKey, codec_.plType, 0, 0, payload,
+ sizeof(payload), nullptr, &rtp_video_header,
+ 0));
}
void IncomingRtcpNack(const RtpRtcpModule* module, uint16_t sequence_number) {
@@ -255,44 +267,14 @@
}
};
-TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_BaseLayer) {
- sender_.impl_->SetSelectiveRetransmissions(kRetransmitBaseLayer);
- EXPECT_EQ(kRetransmitBaseLayer, sender_.impl_->SelectiveRetransmissions());
-
+TEST_F(RtpRtcpImplTest, RetransmitsAllLayers) {
// Send frames.
EXPECT_EQ(0, sender_.RtpSent());
- SendFrame(&sender_, kBaseLayerTid); // kSequenceNumber
- SendFrame(&sender_, kHigherLayerTid); // kSequenceNumber + 1
- SendFrame(&sender_, kNoTemporalIdx); // kSequenceNumber + 2
- EXPECT_EQ(3, sender_.RtpSent());
- EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
-
- // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
- clock_.AdvanceTimeMilliseconds(5);
-
- // Frame with kBaseLayerTid re-sent.
- IncomingRtcpNack(&sender_, kSequenceNumber);
- EXPECT_EQ(4, sender_.RtpSent());
- EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber());
- // Frame with kHigherLayerTid not re-sent.
- IncomingRtcpNack(&sender_, kSequenceNumber + 1);
- EXPECT_EQ(4, sender_.RtpSent());
- // Frame with kNoTemporalIdx re-sent.
- IncomingRtcpNack(&sender_, kSequenceNumber + 2);
- EXPECT_EQ(5, sender_.RtpSent());
- EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
-}
-
-TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_HigherLayers) {
- const uint8_t kSetting = kRetransmitBaseLayer + kRetransmitHigherLayers;
- sender_.impl_->SetSelectiveRetransmissions(kSetting);
- EXPECT_EQ(kSetting, sender_.impl_->SelectiveRetransmissions());
-
- // Send frames.
- EXPECT_EQ(0, sender_.RtpSent());
- SendFrame(&sender_, kBaseLayerTid); // kSequenceNumber
- SendFrame(&sender_, kHigherLayerTid); // kSequenceNumber + 1
- SendFrame(&sender_, kNoTemporalIdx); // kSequenceNumber + 2
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); // kSequenceNumber
+ SendFrame(&sender_, sender_video_.get(),
+ kHigherLayerTid); // kSequenceNumber + 1
+ SendFrame(&sender_, sender_video_.get(),
+ kNoTemporalIdx); // kSequenceNumber + 2
EXPECT_EQ(3, sender_.RtpSent());
EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
@@ -322,7 +304,7 @@
receiver_.receive_statistics_->OnRtpPacket(packet);
// Send Frame before sending an SR.
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
// Sender module should send an SR.
EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
@@ -370,7 +352,7 @@
// Sender module should send a response to the last received RTRR (DLRR).
clock_.AdvanceTimeMilliseconds(1000);
// Send Frame before sending a SR.
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
// Verify RTT.
@@ -399,7 +381,7 @@
EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms);
EXPECT_EQ(receiver_.RtcpSent().first_packet_time_ms, current_time);
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, current_time);
}
@@ -491,7 +473,7 @@
uint16_t nack_list[kNackLength] = {123};
EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
// Send Frame before sending a compound RTCP that starts with SR.
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123));
@@ -503,7 +485,7 @@
uint16_t nack_list[kNackLength] = {123};
EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
// Send Frame before sending a compound RTCP that starts with SR.
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123));
@@ -528,7 +510,7 @@
uint16_t nack_list[kNackLength] = {123, 125};
EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
// Send Frame before sending a compound RTCP that starts with SR.
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125));
@@ -625,7 +607,7 @@
EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
// Send actual payload data, no keep-alive expected.
- SendFrame(&sender_, 0);
+ SendFrame(&sender_, sender_video_.get(), 0);
sender_.impl_->Process();
EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
@@ -647,7 +629,7 @@
sender_.SetRtcpReportIntervalAndReset(kVideoReportInterval);
SetUp();
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
// Initial state
sender_.impl_->Process();
@@ -666,7 +648,7 @@
EXPECT_GT(sender_.RtcpSent().first_packet_time_ms, -1);
EXPECT_EQ(sender_.transport_.NumRtcpSent(), 1u);
- SendFrame(&sender_, kBaseLayerTid);
+ SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
// Move ahead to the last possible second before second rtcp is expected.
clock_.AdvanceTimeMilliseconds(kVideoReportInterval * 1 / 2 - 1);
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index ddf91f5..197f52b 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -17,26 +17,21 @@
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
+#include "api/array_view.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
#include "logging/rtc_event_log/rtc_event_log.h"
-#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
-#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
-#include "modules/rtp_rtcp/source/rtp_sender_video.h"
#include "modules/rtp_rtcp/source/time_util.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_minmax.h"
#include "rtc_base/rate_limiter.h"
-#include "rtc_base/timeutils.h"
-#include "rtc_base/trace_event.h"
-#include "system_wrappers/include/field_trial.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
@@ -57,13 +52,18 @@
return {Extension::kId, Extension::kValueSizeBytes};
}
+template <typename Extension>
+constexpr RtpExtensionSize CreateMaxExtensionSize() {
+ return {Extension::kId, Extension::kMaxValueSizeBytes};
+}
+
// Size info for header extensions that might be used in padding or FEC packets.
constexpr RtpExtensionSize kFecOrPaddingExtensionSizes[] = {
CreateExtensionSize<AbsoluteSendTime>(),
CreateExtensionSize<TransmissionOffset>(),
CreateExtensionSize<TransportSequenceNumber>(),
CreateExtensionSize<PlayoutDelayLimits>(),
- {RtpMid::kId, RtpMid::kMaxValueSizeBytes},
+ CreateMaxExtensionSize<RtpMid>(),
};
// Size info for header extensions that might be used in video packets.
@@ -75,26 +75,15 @@
CreateExtensionSize<VideoOrientation>(),
CreateExtensionSize<VideoContentTypeExtension>(),
CreateExtensionSize<VideoTimingExtension>(),
- {RtpMid::kId, RtpMid::kMaxValueSizeBytes},
- {RtpGenericFrameDescriptorExtension::kId,
- RtpGenericFrameDescriptorExtension::kMaxSizeBytes},
+ CreateMaxExtensionSize<RtpStreamId>(),
+ CreateMaxExtensionSize<RepairedRtpStreamId>(),
+ CreateMaxExtensionSize<RtpMid>(),
+ {RtpGenericFrameDescriptorExtension00::kId,
+ RtpGenericFrameDescriptorExtension00::kMaxSizeBytes},
+ {RtpGenericFrameDescriptorExtension01::kId,
+ RtpGenericFrameDescriptorExtension01::kMaxSizeBytes},
};
-const char* FrameTypeToString(FrameType frame_type) {
- switch (frame_type) {
- case kEmptyFrame:
- return "empty";
- case kAudioFrameSpeech:
- return "audio_speech";
- case kAudioFrameCN:
- return "audio_cn";
- case kVideoFrameKey:
- return "video_key";
- case kVideoFrameDelta:
- return "video_delta";
- }
- return "";
-}
} // namespace
RTPSender::RTPSender(
@@ -102,11 +91,10 @@
Clock* clock,
Transport* transport,
RtpPacketSender* paced_sender,
- FlexfecSender* flexfec_sender,
+ absl::optional<uint32_t> flexfec_ssrc,
TransportSequenceNumberAllocator* sequence_number_allocator,
TransportFeedbackObserver* transport_feedback_observer,
BitrateStatisticsObserver* bitrate_callback,
- FrameCountObserver* frame_count_observer,
SendSideDelayObserver* send_side_delay_observer,
RtcEventLog* event_log,
SendPacketObserver* send_packet_observer,
@@ -115,29 +103,22 @@
bool populate_network2_timestamp,
FrameEncryptorInterface* frame_encryptor,
bool require_frame_encryption,
- bool extmap_allow_mixed)
+ bool extmap_allow_mixed,
+ const WebRtcKeyValueConfig& field_trials)
: clock_(clock),
// TODO(holmer): Remove this conversion?
clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
random_(clock_->TimeInMicroseconds()),
audio_configured_(audio),
- audio_(audio ? new RTPSenderAudio(clock, this) : nullptr),
- video_(audio ? nullptr
- : new RTPSenderVideo(clock,
- this,
- flexfec_sender,
- frame_encryptor,
- require_frame_encryption)),
+ flexfec_ssrc_(flexfec_ssrc),
paced_sender_(paced_sender),
transport_sequence_number_allocator_(sequence_number_allocator),
transport_feedback_observer_(transport_feedback_observer),
- last_capture_time_ms_sent_(0),
transport_(transport),
sending_media_(true), // Default to sending media.
force_part_of_allocation_(false),
max_packet_size_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
last_payload_type_(-1),
- payload_type_map_(),
rtp_header_extension_map_(extmap_allow_mixed),
packet_history_(clock),
flexfec_packet_history_(clock),
@@ -149,13 +130,11 @@
total_bitrate_sent_(kBitrateStatisticsWindowMs,
RateStatistics::kBpsScale),
nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
- frame_count_observer_(frame_count_observer),
send_side_delay_observer_(send_side_delay_observer),
event_log_(event_log),
send_packet_observer_(send_packet_observer),
bitrate_callback_(bitrate_callback),
// RTP variables
- remote_ssrc_(0),
sequence_number_forced_(false),
last_rtp_timestamp_(0),
capture_time_ms_(0),
@@ -169,7 +148,8 @@
overhead_observer_(overhead_observer),
populate_network2_timestamp_(populate_network2_timestamp),
send_side_bwe_with_overhead_(
- webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")) {
+ field_trials.Lookup("WebRTC-SendSideBwe-WithOverhead")
+ .find("Enabled") == 0) {
// This random initialization is not intended to be cryptographic strong.
timestamp_offset_ = random_.Rand<uint32_t>();
// Random start, 16 bits. Can't be 0.
@@ -178,7 +158,7 @@
// Store FlexFEC packets in the packet history data structure, so they can
// be found when paced.
- if (flexfec_sender) {
+ if (flexfec_ssrc_) {
flexfec_packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStore,
kMinFlexfecPacketsToStoreForPacing);
@@ -195,12 +175,6 @@
// variables but we grab them in all other methods. (what's the design?)
// Start documenting what thread we're on in what method so that it's easier
// to understand performance attributes and possibly remove locks.
- while (!payload_type_map_.empty()) {
- std::map<int8_t, RtpUtility::Payload*>::iterator it =
- payload_type_map_.begin();
- delete it->second;
- payload_type_map_.erase(it);
- }
}
rtc::ArrayView<const RtpExtensionSize> RTPSender::FecExtensionSizes() {
@@ -220,20 +194,6 @@
1000);
}
-uint32_t RTPSender::VideoBitrateSent() const {
- if (video_) {
- return video_->VideoBitrateSent();
- }
- return 0;
-}
-
-uint32_t RTPSender::FecOverheadRate() const {
- if (video_) {
- return video_->FecOverheadRate();
- }
- return 0;
-}
-
uint32_t RTPSender::NackOverheadRate() const {
rtc::CritScope cs(&statistics_crit_);
return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
@@ -265,69 +225,6 @@
return rtp_header_extension_map_.Deregister(type);
}
-int32_t RTPSender::RegisterPayload(absl::string_view payload_name,
- int8_t payload_number,
- uint32_t frequency,
- size_t channels,
- uint32_t rate) {
- RTC_DCHECK_LT(payload_name.size(), RTP_PAYLOAD_NAME_SIZE);
- rtc::CritScope lock(&send_critsect_);
-
- std::map<int8_t, RtpUtility::Payload*>::iterator it =
- payload_type_map_.find(payload_number);
-
- if (payload_type_map_.end() != it) {
- // We already use this payload type.
- RtpUtility::Payload* payload = it->second;
- RTC_DCHECK(payload);
-
- // Check if it's the same as we already have.
- if (absl::EqualsIgnoreCase(payload->name, payload_name)) {
- if (audio_configured_ && payload->typeSpecific.is_audio()) {
- auto& p = payload->typeSpecific.audio_payload();
- if (rtc::SafeEq(p.format.clockrate_hz, frequency) &&
- (p.rate == rate || p.rate == 0 || rate == 0)) {
- p.rate = rate;
- // Ensure that we update the rate if new or old is zero.
- return 0;
- }
- }
- if (!audio_configured_ && !payload->typeSpecific.is_audio()) {
- return 0;
- }
- }
- return -1;
- }
- int32_t ret_val = 0;
- RtpUtility::Payload* payload = nullptr;
- if (audio_configured_) {
- // TODO(mflodman): Change to CreateAudioPayload and make static.
- ret_val = audio_->RegisterAudioPayload(payload_name, payload_number,
- frequency, channels, rate, &payload);
- } else {
- payload = video_->CreateVideoPayload(payload_name, payload_number);
- }
- if (payload) {
- payload_type_map_[payload_number] = payload;
- }
- return ret_val;
-}
-
-int32_t RTPSender::DeRegisterSendPayload(int8_t payload_type) {
- rtc::CritScope lock(&send_critsect_);
-
- std::map<int8_t, RtpUtility::Payload*>::iterator it =
- payload_type_map_.find(payload_type);
-
- if (payload_type_map_.end() == it) {
- return -1;
- }
- RtpUtility::Payload* payload = it->second;
- delete payload;
- payload_type_map_.erase(it);
- return 0;
-}
-
void RTPSender::SetMaxRtpPacketSize(size_t max_packet_size) {
RTC_DCHECK_GE(max_packet_size, 100);
RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE);
@@ -373,123 +270,6 @@
rtx_payload_type_map_[associated_payload_type] = payload_type;
}
-int32_t RTPSender::CheckPayloadType(int8_t payload_type,
- VideoCodecType* video_type) {
- rtc::CritScope lock(&send_critsect_);
-
- if (payload_type < 0) {
- RTC_LOG(LS_ERROR) << "Invalid payload_type " << payload_type << ".";
- return -1;
- }
- if (last_payload_type_ == payload_type) {
- if (!audio_configured_) {
- *video_type = video_->VideoCodecType();
- }
- return 0;
- }
- std::map<int8_t, RtpUtility::Payload*>::iterator it =
- payload_type_map_.find(payload_type);
- if (it == payload_type_map_.end()) {
- RTC_LOG(LS_WARNING) << "Payload type " << static_cast<int>(payload_type)
- << " not registered.";
- return -1;
- }
- RtpUtility::Payload* payload = it->second;
- RTC_DCHECK(payload);
- if (payload->typeSpecific.is_video() && !audio_configured_) {
- video_->SetVideoCodecType(
- payload->typeSpecific.video_payload().videoCodecType);
- *video_type = payload->typeSpecific.video_payload().videoCodecType;
- }
- return 0;
-}
-
-bool RTPSender::SendOutgoingData(FrameType frame_type,
- int8_t payload_type,
- uint32_t capture_timestamp,
- int64_t capture_time_ms,
- const uint8_t* payload_data,
- size_t payload_size,
- const RTPFragmentationHeader* fragmentation,
- const RTPVideoHeader* rtp_header,
- uint32_t* transport_frame_id_out,
- int64_t expected_retransmission_time_ms) {
- uint32_t ssrc;
- uint16_t sequence_number;
- uint32_t rtp_timestamp;
- {
- // Drop this packet if we're not sending media packets.
- rtc::CritScope lock(&send_critsect_);
- RTC_DCHECK(ssrc_);
-
- ssrc = *ssrc_;
- sequence_number = sequence_number_;
- rtp_timestamp = timestamp_offset_ + capture_timestamp;
- if (transport_frame_id_out)
- *transport_frame_id_out = rtp_timestamp;
- if (!sending_media_)
- return true;
- }
- VideoCodecType video_type = kVideoCodecGeneric;
- if (CheckPayloadType(payload_type, &video_type) != 0) {
- RTC_LOG(LS_ERROR) << "Don't send data with unknown payload type: "
- << static_cast<int>(payload_type) << ".";
- return false;
- }
-
- switch (frame_type) {
- case kAudioFrameSpeech:
- case kAudioFrameCN:
- RTC_CHECK(audio_configured_);
- break;
- case kVideoFrameKey:
- case kVideoFrameDelta:
- RTC_CHECK(!audio_configured_);
- break;
- case kEmptyFrame:
- break;
- }
-
- bool result;
- if (audio_configured_) {
- TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", rtp_timestamp, "Send", "type",
- FrameTypeToString(frame_type));
- // The only known way to produce of RTPFragmentationHeader for audio is
- // to use the AudioCodingModule directly.
- RTC_DCHECK(fragmentation == nullptr);
- result = audio_->SendAudio(frame_type, payload_type, rtp_timestamp,
- payload_data, payload_size);
- } else {
- TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms, "Send", "type",
- FrameTypeToString(frame_type));
- if (frame_type == kEmptyFrame)
- return true;
-
- if (rtp_header) {
- playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
- sequence_number);
- }
-
- result = video_->SendVideo(video_type, frame_type, payload_type,
- rtp_timestamp, capture_time_ms, payload_data,
- payload_size, fragmentation, rtp_header,
- expected_retransmission_time_ms);
- }
-
- rtc::CritScope cs(&statistics_crit_);
- // Note: This is currently only counting for video.
- if (frame_type == kVideoFrameKey) {
- ++frame_counts_.key_frames;
- } else if (frame_type == kVideoFrameDelta) {
- ++frame_counts_.delta_frames;
- }
- if (frame_count_observer_) {
- frame_count_observer_->FrameCountUpdated(frame_counts_, ssrc);
- }
-
- return result;
-}
-
size_t RTPSender::TrySendRedundantPayloads(size_t bytes_to_send,
const PacedPacketInfo& pacing_info) {
{
@@ -664,7 +444,7 @@
return 0;
}
- const int32_t packet_size = static_cast<int32_t>(stored_packet->payload_size);
+ const int32_t packet_size = static_cast<int32_t>(stored_packet->packet_size);
// Skip retransmission rate check if not configured.
if (retransmission_rate_limiter_) {
@@ -683,7 +463,7 @@
paced_sender_->InsertPacket(
RtpPacketSender::kNormalPriority, stored_packet->ssrc,
stored_packet->rtp_sequence_number, corrected_capture_tims_ms,
- stored_packet->payload_size, true);
+ stored_packet->packet_size, true);
return packet_size;
}
@@ -724,19 +504,6 @@
return true;
}
-int RTPSender::SelectiveRetransmissions() const {
- if (!video_)
- return -1;
- return video_->SelectiveRetransmissions();
-}
-
-int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
- if (!video_)
- return -1;
- video_->SetSelectiveRetransmissions(settings);
- return 0;
-}
-
void RTPSender::OnReceivedNack(
const std::vector<uint16_t>& nack_sequence_numbers,
int64_t avg_rtt) {
@@ -752,11 +519,6 @@
}
}
-void RTPSender::OnReceivedRtcpReportBlocks(
- const ReportBlockList& report_blocks) {
- playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks);
-}
-
// Called from pacer when we can send the packet.
bool RTPSender::TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
@@ -874,7 +636,7 @@
if (counters->first_packet_time_ms == -1)
counters->first_packet_time_ms = now_ms;
- if (IsFecPacket(packet))
+ if (packet.is_fec())
counters->fec.AddPacket(packet);
if (is_retransmit) {
@@ -887,22 +649,6 @@
rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
}
-bool RTPSender::IsFecPacket(const RtpPacketToSend& packet) const {
- if (!video_)
- return false;
-
- // FlexFEC.
- if (packet.Ssrc() == FlexfecSsrc())
- return true;
-
- // RED+ULPFEC.
- int pt_red;
- int pt_fec;
- video_->GetUlpfecConfig(&pt_red, &pt_fec);
- return static_cast<int>(packet.PayloadType()) == pt_red &&
- static_cast<int>(packet.payload()[0]) == pt_fec;
-}
-
size_t RTPSender::TimeToSendPadding(size_t bytes,
const PacedPacketInfo& pacing_info) {
if (bytes == 0)
@@ -919,29 +665,15 @@
RTC_DCHECK(packet);
int64_t now_ms = clock_->TimeInMilliseconds();
- if (video_) {
- BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
- ActualSendBitrateKbit(), packet->Ssrc());
- BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
- FecOverheadRate() / 1000, packet->Ssrc());
- BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
- NackOverheadRate() / 1000, packet->Ssrc());
- } else {
- BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms,
- ActualSendBitrateKbit(), packet->Ssrc());
- BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms,
- NackOverheadRate() / 1000, packet->Ssrc());
- }
-
uint32_t ssrc = packet->Ssrc();
- absl::optional<uint32_t> flexfec_ssrc = FlexfecSsrc();
if (paced_sender_) {
uint16_t seq_no = packet->SequenceNumber();
// Correct offset between implementations of millisecond time stamps in
// TickTime and Clock.
int64_t corrected_time_ms = packet->capture_time_ms() + clock_delta_ms_;
- size_t payload_length = packet->payload_size();
- if (ssrc == flexfec_ssrc) {
+ size_t packet_size =
+ send_side_bwe_with_overhead_ ? packet->size() : packet->payload_size();
+ if (ssrc == FlexfecSsrc()) {
// Store FlexFEC packets in the history here, so they can be found
// when the pacer calls TimeToSendPacket.
flexfec_packet_history_.PutRtpPacket(std::move(packet), storage,
@@ -951,11 +683,7 @@
}
paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms,
- payload_length, false);
- if (last_capture_time_ms_sent_ == 0 ||
- corrected_time_ms > last_capture_time_ms_sent_) {
- last_capture_time_ms_sent_ = corrected_time_ms;
- }
+ packet_size, false);
return true;
}
@@ -1171,14 +899,15 @@
packet->ReserveExtension<AbsoluteSendTime>();
packet->ReserveExtension<TransmissionOffset>();
packet->ReserveExtension<TransportSequenceNumber>();
- if (playout_delay_oracle_.send_playout_delay()) {
- packet->SetExtension<PlayoutDelayLimits>(
- playout_delay_oracle_.playout_delay());
- }
+
if (!mid_.empty()) {
// This is a no-op if the MID header extension is not registered.
packet->SetExtension<RtpMid>(mid_);
}
+ if (!rid_.empty()) {
+ // This is a no-op if the RID header extension is not registered.
+ packet->SetExtension<RtpStreamId>(rid_);
+ }
return packet;
}
@@ -1263,6 +992,13 @@
return *ssrc_;
}
+void RTPSender::SetRid(const std::string& rid) {
+ // RID is used in simulcast scenario when multiple layers share the same mid.
+ rtc::CritScope lock(&send_critsect_);
+ RTC_DCHECK_LE(rid.length(), RtpStreamId::kMaxValueSizeBytes);
+ rid_ = rid;
+}
+
void RTPSender::SetMid(const std::string& mid) {
// This is configured via the API.
rtc::CritScope lock(&send_critsect_);
@@ -1270,10 +1006,7 @@
}
absl::optional<uint32_t> RTPSender::FlexfecSsrc() const {
- if (video_) {
- return video_->FlexfecSsrc();
- }
- return absl::nullopt;
+ return flexfec_ssrc_;
}
void RTPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
@@ -1293,42 +1026,58 @@
return sequence_number_;
}
-// Audio.
-int32_t RTPSender::SendTelephoneEvent(uint8_t key,
- uint16_t time_ms,
- uint8_t level) {
- if (!audio_configured_) {
- return -1;
+static void CopyHeaderAndExtensionsToRtxPacket(const RtpPacketToSend& packet,
+ RtpPacketToSend* rtx_packet) {
+ // Set the relevant fixed packet headers. The following are not set:
+ // * Payload type - it is replaced in rtx packets.
+ // * Sequence number - RTX has a separate sequence numbering.
+ // * SSRC - RTX stream has its own SSRC.
+ rtx_packet->SetMarker(packet.Marker());
+ rtx_packet->SetTimestamp(packet.Timestamp());
+
+ // Set the variable fields in the packet header:
+ // * CSRCs - must be set before header extensions.
+ // * Header extensions - replace Rid header with RepairedRid header.
+ const std::vector<uint32_t> csrcs = packet.Csrcs();
+ rtx_packet->SetCsrcs(csrcs);
+ for (int extension = kRtpExtensionNone + 1;
+ extension < kRtpExtensionNumberOfExtensions; ++extension) {
+ RTPExtensionType source_extension =
+ static_cast<RTPExtensionType>(extension);
+ // Rid header should be replaced with RepairedRid header
+ RTPExtensionType destination_extension =
+ source_extension == kRtpExtensionRtpStreamId
+ ? kRtpExtensionRepairedRtpStreamId
+ : source_extension;
+
+ // Empty extensions should be supported, so not checking |source.empty()|.
+ if (!packet.HasExtension(source_extension)) {
+ continue;
+ }
+
+ rtc::ArrayView<const uint8_t> source =
+ packet.FindExtension(source_extension);
+
+ rtc::ArrayView<uint8_t> destination =
+ rtx_packet->AllocateExtension(destination_extension, source.size());
+
+ // Could happen if any:
+ // 1. Extension has 0 length.
+ // 2. Extension is not registered in destination.
+ // 3. Allocating extension in destination failed.
+ if (destination.empty() || source.size() != destination.size()) {
+ continue;
+ }
+
+ std::memcpy(destination.begin(), source.begin(), destination.size());
}
- return audio_->SendTelephoneEvent(key, time_ms, level);
-}
-
-int32_t RTPSender::SetAudioLevel(uint8_t level_d_bov) {
- return audio_->SetAudioLevel(level_d_bov);
-}
-
-void RTPSender::SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) {
- RTC_DCHECK(!audio_configured_);
- video_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
-}
-
-bool RTPSender::SetFecParameters(const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params) {
- if (audio_configured_) {
- return false;
- }
- video_->SetFecParameters(delta_params, key_params);
- return true;
}
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
const RtpPacketToSend& packet) {
- // TODO(danilchap): Create rtx packet with extra capacity for SRTP
- // when transport interface would be updated to take buffer class.
- std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend(
- &rtp_header_extension_map_, packet.size() + kRtxHeaderSize));
+ std::unique_ptr<RtpPacketToSend> rtx_packet;
+
// Add original RTP header.
- rtx_packet->CopyHeaderFrom(packet);
{
rtc::CritScope lock(&send_critsect_);
if (!sending_media_)
@@ -1340,6 +1089,10 @@
auto kv = rtx_payload_type_map_.find(packet.PayloadType());
if (kv == rtx_payload_type_map_.end())
return nullptr;
+
+ rtx_packet = absl::make_unique<RtpPacketToSend>(&rtp_header_extension_map_,
+ max_packet_size_);
+
rtx_packet->SetPayloadType(kv->second);
// Replace sequence number.
@@ -1348,16 +1101,30 @@
// Replace SSRC.
rtx_packet->SetSsrc(*ssrc_rtx_);
- // Possibly include the MID header extension.
+ CopyHeaderAndExtensionsToRtxPacket(packet, rtx_packet.get());
+
+ // The spec indicates that it is possible for a sender to stop sending mids
+ // once the SSRCs have been bound on the receiver. As a result the source
+ // rtp packet might not have the MID header extension set.
+ // However, the SSRC of the RTX stream might not have been bound on the
+ // receiver. This means that we should include it here.
+ // The same argument goes for the Repaired RID extension.
if (!mid_.empty()) {
// This is a no-op if the MID header extension is not registered.
rtx_packet->SetExtension<RtpMid>(mid_);
}
+ if (!rid_.empty()) {
+ // This is a no-op if the Repaired-RID header extension is not registered.
+ // rtx_packet->SetExtension<RepairedRtpStreamId>(rid_);
+ }
}
+ RTC_DCHECK(rtx_packet);
uint8_t* rtx_payload =
rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize);
- RTC_DCHECK(rtx_payload);
+ if (rtx_payload == nullptr)
+ return nullptr;
+
// Add OSN (original sequence number).
ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber());
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index f9bbbdd..f08eb89 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -21,16 +21,15 @@
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/call/transport.h"
+#include "api/transport/webrtc_key_value_config.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "modules/rtp_rtcp/source/rtp_packet_history.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
-#include "modules/rtp_rtcp/source/rtp_utility.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/deprecation.h"
#include "rtc_base/random.h"
#include "rtc_base/rate_statistics.h"
@@ -43,8 +42,6 @@
class RateLimiter;
class RtcEventLog;
class RtpPacketToSend;
-class RTPSenderAudio;
-class RTPSenderVideo;
class RTPSender {
public:
@@ -52,13 +49,10 @@
Clock* clock,
Transport* transport,
RtpPacketSender* paced_sender,
- // TODO(brandtr): Remove |flexfec_sender| when that is hooked up
- // to PacedSender instead.
- FlexfecSender* flexfec_sender,
+ absl::optional<uint32_t> flexfec_ssrc,
TransportSequenceNumberAllocator* sequence_number_allocator,
TransportFeedbackObserver* transport_feedback_callback,
BitrateStatisticsObserver* bitrate_callback,
- FrameCountObserver* frame_count_observer,
SendSideDelayObserver* send_side_delay_observer,
RtcEventLog* event_log,
SendPacketObserver* send_packet_observer,
@@ -67,7 +61,8 @@
bool populate_network2_timestamp,
FrameEncryptorInterface* frame_encryptor,
bool require_frame_encryption,
- bool extmap_allow_mixed);
+ bool extmap_allow_mixed,
+ const WebRtcKeyValueConfig& field_trials);
~RTPSender();
@@ -75,18 +70,8 @@
uint16_t ActualSendBitrateKbit() const;
- uint32_t VideoBitrateSent() const;
- uint32_t FecOverheadRate() const;
uint32_t NackOverheadRate() const;
- int32_t RegisterPayload(absl::string_view payload_name,
- const int8_t payload_type,
- const uint32_t frequency,
- const size_t channels,
- const uint32_t rate);
-
- int32_t DeRegisterSendPayload(const int8_t payload_type);
-
void SetSendingMediaStatus(bool enabled);
bool SendingMedia() const;
@@ -100,6 +85,8 @@
void SetSSRC(uint32_t ssrc);
+ void SetRid(const std::string& rid);
+
void SetMid(const std::string& mid);
uint16_t SequenceNumber() const;
@@ -109,17 +96,6 @@
void SetMaxRtpPacketSize(size_t max_packet_size);
- bool SendOutgoingData(FrameType frame_type,
- int8_t payload_type,
- uint32_t timestamp,
- int64_t capture_time_ms,
- const uint8_t* payload_data,
- size_t payload_size,
- const RTPFragmentationHeader* fragmentation,
- const RTPVideoHeader* rtp_header,
- uint32_t* transport_frame_id_out,
- int64_t expected_retransmission_time_ms);
-
void SetExtmapAllowMixed(bool extmap_allow_mixed);
// RTP header extension
@@ -136,8 +112,6 @@
size_t TimeToSendPadding(size_t bytes, const PacedPacketInfo& pacing_info);
// NACK.
- int SelectiveRetransmissions() const;
- int SetSelectiveRetransmissions(uint8_t settings);
void OnReceivedNack(const std::vector<uint16_t>& nack_sequence_numbers,
int64_t avg_rtt);
@@ -147,10 +121,6 @@
int32_t ReSendPacket(uint16_t packet_id);
- // Feedback to decide when to stop sending the playout delay and MID header
- // extensions.
- void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks);
-
// RTX.
void SetRtxStatus(int mode);
int RtxStatus() const;
@@ -184,27 +154,11 @@
absl::optional<uint32_t> FlexfecSsrc() const;
+ // Sends packet to |transport_| or to the pacer, depending on configuration.
bool SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
StorageType storage,
RtpPacketSender::Priority priority);
- // Audio.
-
- // Send a DTMF tone using RFC 2833 (4733).
- int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level);
-
- // Store the audio level in d_bov for
- // header-extension-for-audio-level-indication.
- int32_t SetAudioLevel(uint8_t level_d_bov);
-
- uint32_t MaxConfiguredBitrateVideo() const;
-
- // ULPFEC.
- void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
-
- bool SetFecParameters(const FecProtectionParams& delta_params,
- const FecProtectionParams& key_params);
-
// Called on update of RTP statistics.
void RegisterRtpStatisticsCallback(StreamDataCountersCallback* callback);
StreamDataCountersCallback* GetRtpStatisticsCallback() const;
@@ -221,9 +175,6 @@
void SetRtt(int64_t rtt_ms);
- protected:
- int32_t CheckPayloadType(int8_t payload_type, VideoCodecType* video_type);
-
private:
// Maps capture time in milliseconds to send-side delay in milliseconds.
// Send-side delay is the difference between transmission time and capture
@@ -245,6 +196,7 @@
std::unique_ptr<RtpPacketToSend> BuildRtxPacket(
const RtpPacketToSend& packet);
+ // Sends packet on to |transport_|, leaving the RTP module.
bool SendPacketToNetwork(const RtpPacketToSend& packet,
const PacketOptions& options,
const PacedPacketInfo& pacing_info);
@@ -274,13 +226,12 @@
Random random_ RTC_GUARDED_BY(send_critsect_);
const bool audio_configured_;
- const std::unique_ptr<RTPSenderAudio> audio_;
- const std::unique_ptr<RTPSenderVideo> video_;
+
+ const absl::optional<uint32_t> flexfec_ssrc_;
RtpPacketSender* const paced_sender_;
TransportSequenceNumberAllocator* const transport_sequence_number_allocator_;
TransportFeedbackObserver* const transport_feedback_observer_;
- int64_t last_capture_time_ms_sent_;
rtc::CriticalSection send_critsect_;
Transport* transport_;
@@ -289,16 +240,10 @@
size_t max_packet_size_;
int8_t last_payload_type_ RTC_GUARDED_BY(send_critsect_);
- std::map<int8_t, RtpUtility::Payload*> payload_type_map_;
RtpHeaderExtensionMap rtp_header_extension_map_
RTC_GUARDED_BY(send_critsect_);
- // Tracks the current request for playout delay limits from application
- // and decides whether the current RTP frame should include the playout
- // delay extension on header.
- PlayoutDelayOracle playout_delay_oracle_;
-
RtpPacketHistory packet_history_;
// TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender
// is hooked up to the PacedSender.
@@ -309,14 +254,12 @@
SendDelayMap send_delays_ RTC_GUARDED_BY(statistics_crit_);
SendDelayMap::const_iterator max_delay_it_ RTC_GUARDED_BY(statistics_crit_);
int64_t sum_delays_ms_ RTC_GUARDED_BY(statistics_crit_);
- FrameCounts frame_counts_ RTC_GUARDED_BY(statistics_crit_);
StreamDataCounters rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
StreamDataCountersCallback* rtp_stats_callback_
RTC_GUARDED_BY(statistics_crit_);
RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
- FrameCountObserver* const frame_count_observer_;
SendSideDelayObserver* const send_side_delay_observer_;
RtcEventLog* const event_log_;
SendPacketObserver* const send_packet_observer_;
@@ -324,13 +267,14 @@
// RTP variables
uint32_t timestamp_offset_ RTC_GUARDED_BY(send_critsect_);
- uint32_t remote_ssrc_ RTC_GUARDED_BY(send_critsect_);
bool sequence_number_forced_ RTC_GUARDED_BY(send_critsect_);
uint16_t sequence_number_ RTC_GUARDED_BY(send_critsect_);
uint16_t sequence_number_rtx_ RTC_GUARDED_BY(send_critsect_);
// Must be explicitly set by the application, use of absl::optional
// only to keep track of correct use.
absl::optional<uint32_t> ssrc_ RTC_GUARDED_BY(send_critsect_);
+ // RID value to send in the RID or RepairedRID header extension.
+ std::string rid_ RTC_GUARDED_BY(send_critsect_);
// MID value to send in the MID header extension.
std::string mid_ RTC_GUARDED_BY(send_critsect_);
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(send_critsect_);
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.cc b/modules/rtp_rtcp/source/rtp_sender_audio.cc
index 636cccc..56d0884 100644
--- a/modules/rtp_rtcp/source/rtp_sender_audio.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.cc
@@ -16,6 +16,7 @@
#include "absl/strings/match.h"
#include "api/audio_codecs/audio_format.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
@@ -27,6 +28,24 @@
namespace webrtc {
+namespace {
+
+const char* FrameTypeToString(FrameType frame_type) {
+ switch (frame_type) {
+ case kEmptyFrame:
+ return "empty";
+ case kAudioFrameSpeech:
+ return "audio_speech";
+ case kAudioFrameCN:
+ return "audio_cn";
+ default:
+ RTC_NOTREACHED();
+ return "";
+ }
+}
+
+} // namespace
+
RTPSenderAudio::RTPSenderAudio(Clock* clock, RTPSender* rtp_sender)
: clock_(clock), rtp_sender_(rtp_sender) {}
@@ -36,8 +55,7 @@
const int8_t payload_type,
const uint32_t frequency,
const size_t channels,
- const uint32_t rate,
- RtpUtility::Payload** payload) {
+ const uint32_t rate) {
if (absl::EqualsIgnoreCase(payload_name, "cn")) {
rtc::CritScope cs(&send_audio_critsect_);
// we can have multiple CNG payload types
@@ -65,10 +83,6 @@
dtmf_payload_freq_ = frequency;
return 0;
}
- *payload = new RtpUtility::Payload(
- payload_name,
- PayloadUnion(AudioPayload{
- SdpAudioFormat(payload_name, frequency, channels), rate}));
return 0;
}
@@ -120,6 +134,12 @@
uint32_t rtp_timestamp,
const uint8_t* payload_data,
size_t payload_size) {
+ RTC_DCHECK(frame_type == kAudioFrameSpeech || frame_type == kAudioFrameCN ||
+ frame_type == kEmptyFrame);
+
+ TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", rtp_timestamp, "Send", "type",
+ FrameTypeToString(frame_type));
+
// From RFC 4733:
// A source has wide latitude as to how often it sends event updates. A
// natural interval is the spacing between non-event audio packets. [...]
@@ -238,7 +258,7 @@
TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp",
packet->Timestamp(), "seqnum",
packet->SequenceNumber());
- bool send_result = rtp_sender_->SendToNetwork(
+ bool send_result = LogAndSendToNetwork(
std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
if (first_packet_sent_()) {
RTC_LOG(LS_INFO) << "First audio RTP packet sent to pacer";
@@ -322,11 +342,29 @@
dtmfbuffer[1] = E | R | volume;
ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration);
- result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission,
- RtpPacketSender::kHighPriority);
+ result = LogAndSendToNetwork(std::move(packet), kAllowRetransmission,
+ RtpPacketSender::kHighPriority);
send_count--;
} while (send_count > 0 && result);
return result;
}
+
+bool RTPSenderAudio::LogAndSendToNetwork(
+ std::unique_ptr<RtpPacketToSend> packet,
+ StorageType storage,
+ RtpPacketSender::Priority priority) {
+#if BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
+ int64_t now_ms = clock_->TimeInMilliseconds();
+ BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms,
+ rtp_sender_->ActualSendBitrateKbit(),
+ packet->Ssrc());
+ BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms,
+ rtp_sender_->NackOverheadRate() / 1000,
+ packet->Ssrc());
+#endif
+
+ return rtp_sender_->SendToNetwork(std::move(packet), storage, priority);
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.h b/modules/rtp_rtcp/source/rtp_sender_audio.h
index 1dbe5b5..fa58943 100644
--- a/modules/rtp_rtcp/source/rtp_sender_audio.h
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.h
@@ -14,14 +14,15 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
+
#include "absl/strings/string_view.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/source/dtmf_queue.h"
#include "modules/rtp_rtcp/source/rtp_sender.h"
-#include "modules/rtp_rtcp/source/rtp_utility.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/onetimeevent.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/one_time_event.h"
#include "rtc_base/thread_annotations.h"
#include "system_wrappers/include/clock.h"
@@ -36,8 +37,7 @@
int8_t payload_type,
uint32_t frequency,
size_t channels,
- uint32_t rate,
- RtpUtility::Payload** payload);
+ uint32_t rate);
bool SendAudio(FrameType frame_type,
int8_t payload_type,
@@ -63,6 +63,10 @@
bool MarkerBit(FrameType frame_type, int8_t payload_type);
private:
+ bool LogAndSendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
+ StorageType storage,
+ RtpPacketSender::Priority priority);
+
Clock* const clock_ = nullptr;
RTPSender* const rtp_sender_ = nullptr;
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_audio_unittest.cc
new file mode 100644
index 0000000..31b0048
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_audio_unittest.cc
@@ -0,0 +1,178 @@
+/*
+ * 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 <vector>
+
+#include "api/transport/field_trial_based_config.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+enum : int { // The first valid value is 1.
+ kAudioLevelExtensionId = 1,
+};
+
+const uint16_t kSeqNum = 33;
+const uint32_t kSsrc = 725242;
+const uint8_t kAudioLevel = 0x5a;
+const uint64_t kStartTime = 123456789;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+
+class LoopbackTransportTest : public webrtc::Transport {
+ public:
+ LoopbackTransportTest() {
+ receivers_extensions_.Register(kRtpExtensionAudioLevel,
+ kAudioLevelExtensionId);
+ }
+
+ bool SendRtp(const uint8_t* data,
+ size_t len,
+ const PacketOptions& /*options*/) override {
+ sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_));
+ EXPECT_TRUE(sent_packets_.back().Parse(data, len));
+ return true;
+ }
+ bool SendRtcp(const uint8_t* data, size_t len) override { return false; }
+ const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); }
+ int packets_sent() { return sent_packets_.size(); }
+
+ private:
+ RtpHeaderExtensionMap receivers_extensions_;
+ std::vector<RtpPacketReceived> sent_packets_;
+};
+
+} // namespace
+
+class RtpSenderAudioTest : public ::testing::Test {
+ public:
+ RtpSenderAudioTest()
+ : fake_clock_(kStartTime),
+ rtp_sender_(true,
+ &fake_clock_,
+ &transport_,
+ nullptr,
+ absl::nullopt,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ false,
+ nullptr,
+ false,
+ false,
+ FieldTrialBasedConfig()),
+ rtp_sender_audio_(&fake_clock_, &rtp_sender_) {
+ rtp_sender_.SetSSRC(kSsrc);
+ rtp_sender_.SetSequenceNumber(kSeqNum);
+ }
+
+ SimulatedClock fake_clock_;
+ LoopbackTransportTest transport_;
+ RTPSender rtp_sender_;
+ RTPSenderAudio rtp_sender_audio_;
+};
+
+TEST_F(RtpSenderAudioTest, SendAudio) {
+ const char payload_name[] = "PAYLOAD_NAME";
+ const uint8_t payload_type = 127;
+ ASSERT_EQ(0, rtp_sender_audio_.RegisterAudioPayload(
+ payload_name, payload_type, 48000, 0, 1500));
+ uint8_t payload[] = {47, 11, 32, 93, 89};
+
+ ASSERT_TRUE(rtp_sender_audio_.SendAudio(kAudioFrameCN, payload_type, 4321,
+ payload, sizeof(payload)));
+
+ auto sent_payload = transport_.last_sent_packet().payload();
+ EXPECT_THAT(sent_payload, ElementsAreArray(payload));
+}
+
+TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
+ EXPECT_EQ(0, rtp_sender_audio_.SetAudioLevel(kAudioLevel));
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
+ kAudioLevelExtensionId));
+
+ const char payload_name[] = "PAYLOAD_NAME";
+ const uint8_t payload_type = 127;
+ ASSERT_EQ(0, rtp_sender_audio_.RegisterAudioPayload(
+ payload_name, payload_type, 48000, 0, 1500));
+
+ uint8_t payload[] = {47, 11, 32, 93, 89};
+
+ ASSERT_TRUE(rtp_sender_audio_.SendAudio(kAudioFrameCN, payload_type, 4321,
+ payload, sizeof(payload)));
+
+ auto sent_payload = transport_.last_sent_packet().payload();
+ EXPECT_THAT(sent_payload, ElementsAreArray(payload));
+ // Verify AudioLevel extension.
+ bool voice_activity;
+ uint8_t audio_level;
+ EXPECT_TRUE(transport_.last_sent_packet().GetExtension<AudioLevel>(
+ &voice_activity, &audio_level));
+ EXPECT_EQ(kAudioLevel, audio_level);
+ EXPECT_FALSE(voice_activity);
+}
+
+// As RFC4733, named telephone events are carried as part of the audio stream
+// and must use the same sequence number and timestamp base as the regular
+// audio channel.
+// This test checks the marker bit for the first packet and the consequent
+// packets of the same telephone event. Since it is specifically for DTMF
+// events, ignoring audio packets and sending kEmptyFrame instead of those.
+TEST_F(RtpSenderAudioTest, CheckMarkerBitForTelephoneEvents) {
+ const char* kDtmfPayloadName = "telephone-event";
+ const uint32_t kPayloadFrequency = 8000;
+ const uint8_t kPayloadType = 126;
+ ASSERT_EQ(0, rtp_sender_audio_.RegisterAudioPayload(
+ kDtmfPayloadName, kPayloadType, kPayloadFrequency, 0, 0));
+ // For Telephone events, payload is not added to the registered payload list,
+ // it will register only the payload used for audio stream.
+ // Registering the payload again for audio stream with different payload name.
+ const char* kPayloadName = "payload_name";
+ ASSERT_EQ(0, rtp_sender_audio_.RegisterAudioPayload(
+ kPayloadName, kPayloadType, kPayloadFrequency, 1, 0));
+ // Start time is arbitrary.
+ uint32_t capture_timestamp = fake_clock_.TimeInMilliseconds();
+ // DTMF event key=9, duration=500 and attenuationdB=10
+ rtp_sender_audio_.SendTelephoneEvent(9, 500, 10);
+ // During start, it takes the starting timestamp as last sent timestamp.
+ // The duration is calculated as the difference of current and last sent
+ // timestamp. So for first call it will skip since the duration is zero.
+ ASSERT_TRUE(rtp_sender_audio_.SendAudio(kEmptyFrame, kPayloadType,
+ capture_timestamp, nullptr, 0));
+ // DTMF Sample Length is (Frequency/1000) * Duration.
+ // So in this case, it is (8000/1000) * 500 = 4000.
+ // Sending it as two packets.
+ ASSERT_TRUE(rtp_sender_audio_.SendAudio(
+ kEmptyFrame, kPayloadType, capture_timestamp + 2000, nullptr, 0));
+
+ // Marker Bit should be set to 1 for first packet.
+ EXPECT_TRUE(transport_.last_sent_packet().Marker());
+
+ ASSERT_TRUE(rtp_sender_audio_.SendAudio(
+ kEmptyFrame, kPayloadType, capture_timestamp + 4000, nullptr, 0));
+ // Marker Bit should be set to 0 for rest of the packets.
+ EXPECT_FALSE(transport_.last_sent_packet().Marker());
+}
+
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index a687bcb..1c74e7e 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -12,6 +12,8 @@
#include <vector>
#include "absl/memory/memory.h"
+#include "api/transport/field_trial_based_config.h"
+#include "api/video/video_codec_constants.h"
#include "api/video/video_timing.h"
#include "logging/rtc_event_log/events/rtc_event.h"
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
@@ -30,7 +32,6 @@
#include "modules/rtp_rtcp/source/rtp_sender_video.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/arraysize.h"
-#include "rtc_base/buffer.h"
#include "rtc_base/rate_limiter.h"
#include "test/field_trial.h"
#include "test/gmock.h"
@@ -40,28 +41,32 @@
namespace webrtc {
namespace {
-const int kTransmissionTimeOffsetExtensionId = 1;
-const int kAbsoluteSendTimeExtensionId = 14;
-const int kTransportSequenceNumberExtensionId = 13;
-const int kVideoTimingExtensionId = 12;
-const int kMidExtensionId = 11;
+enum : int { // The first valid value is 1.
+ kAbsoluteSendTimeExtensionId = 1,
+ kAudioLevelExtensionId,
+ kGenericDescriptorId00,
+ kGenericDescriptorId01,
+ kMidExtensionId,
+ kRepairedRidExtensionId,
+ kRidExtensionId,
+ kTransmissionTimeOffsetExtensionId,
+ kTransportSequenceNumberExtensionId,
+ kVideoRotationExtensionId,
+ kVideoTimingExtensionId,
+};
+
const int kPayload = 100;
const int kRtxPayload = 98;
const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33;
const uint32_t kSsrc = 725242;
-const int kMaxPacketLength = 1500;
-const uint8_t kAudioLevel = 0x5a;
const uint16_t kTransportSequenceNumber = 0xaabbu;
-const uint8_t kAudioLevelExtensionId = 9;
-const int kAudioPayload = 103;
const uint64_t kStartTime = 123456789;
const size_t kMaxPaddingSize = 224u;
-const int kVideoRotationExtensionId = 5;
-const size_t kGenericHeaderLength = 1;
const uint8_t kPayloadData[] = {47, 11, 32, 93, 89};
const int64_t kDefaultExpectedRetransmissionTimeMs = 125;
-const int kGenericDescriptorId = 10;
+const char kNoRid[] = "";
+const char kNoMid[] = "";
using ::testing::_;
using ::testing::ElementsAre;
@@ -89,8 +94,13 @@
receivers_extensions_.Register(kRtpExtensionVideoTiming,
kVideoTimingExtensionId);
receivers_extensions_.Register(kRtpExtensionMid, kMidExtensionId);
- receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor,
- kGenericDescriptorId);
+ receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor00,
+ kGenericDescriptorId00);
+ receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor01,
+ kGenericDescriptorId01);
+ receivers_extensions_.Register(kRtpExtensionRtpStreamId, kRidExtensionId);
+ receivers_extensions_.Register(kRtpExtensionRepairedRtpStreamId,
+ kRepairedRidExtensionId);
}
bool SendRtp(const uint8_t* data,
@@ -171,7 +181,6 @@
mock_paced_sender_(),
retransmission_rate_limiter_(&fake_clock_, 1000),
rtp_sender_(),
- payload_(kPayload),
transport_(),
kMarkerBit(true),
field_trials_(GetParam() ? "WebRTC-SendSideBwe-WithOverhead/Enabled/"
@@ -182,10 +191,10 @@
void SetUpRtpSender(bool pacer, bool populate_network2) {
rtp_sender_.reset(new RTPSender(
false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
- nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+ absl::nullopt, &seq_num_allocator_, nullptr, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_,
&retransmission_rate_limiter_, nullptr, populate_network2, nullptr,
- false, false));
+ false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetTimestampOffset(0);
rtp_sender_->SetSSRC(kSsrc);
@@ -199,31 +208,10 @@
testing::StrictMock<MockTransportFeedbackObserver> feedback_observer_;
RateLimiter retransmission_rate_limiter_;
std::unique_ptr<RTPSender> rtp_sender_;
- int payload_;
LoopbackTransportTest transport_;
const bool kMarkerBit;
test::ScopedFieldTrials field_trials_;
- void VerifyRTPHeaderCommon(const RTPHeader& rtp_header) {
- VerifyRTPHeaderCommon(rtp_header, kMarkerBit, 0);
- }
-
- void VerifyRTPHeaderCommon(const RTPHeader& rtp_header, bool marker_bit) {
- VerifyRTPHeaderCommon(rtp_header, marker_bit, 0);
- }
-
- void VerifyRTPHeaderCommon(const RTPHeader& rtp_header,
- bool marker_bit,
- uint8_t number_of_csrcs) {
- EXPECT_EQ(marker_bit, rtp_header.markerBit);
- EXPECT_EQ(payload_, rtp_header.payloadType);
- EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber);
- EXPECT_EQ(kTimestamp, rtp_header.timestamp);
- EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.ssrc);
- EXPECT_EQ(number_of_csrcs, rtp_header.numCSRCs);
- EXPECT_EQ(0U, rtp_header.paddingLength);
- }
-
std::unique_ptr<RtpPacketToSend> BuildRtpPacket(int payload_type,
bool marker_bit,
uint32_t timestamp,
@@ -249,19 +237,9 @@
RtpPacketSender::kNormalPriority));
}
- void SendGenericPayload() {
- const uint32_t kTimestamp = 1234;
- const uint8_t kPayloadType = 127;
+ void SendGenericPacket() {
const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
- EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
- 0, 1500));
-
- RTPVideoHeader video_header;
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
- sizeof(kPayloadData), nullptr, &video_header, nullptr,
- kDefaultExpectedRetransmissionTimeMs));
+ SendPacket(kCaptureTimeMs, sizeof(kPayloadData));
}
};
@@ -272,34 +250,6 @@
void SetUp() override { SetUpRtpSender(false, false); }
};
-class TestRtpSenderVideo : public RTPSenderVideo {
- public:
- TestRtpSenderVideo(Clock* clock,
- RTPSender* rtp_sender,
- FlexfecSender* flexfec_sender)
- : RTPSenderVideo(clock, rtp_sender, flexfec_sender, nullptr, false) {}
- ~TestRtpSenderVideo() override {}
-
- StorageType GetStorageType(const RTPVideoHeader& header,
- int32_t retransmission_settings,
- int64_t expected_retransmission_time_ms) {
- return RTPSenderVideo::GetStorageType(GetTemporalId(header),
- retransmission_settings,
- expected_retransmission_time_ms);
- }
-};
-
-class RtpSenderVideoTest : public RtpSenderTest {
- protected:
- void SetUp() override {
- // TODO(pbos): Set up to use pacer.
- SetUpRtpSender(false, false);
- rtp_sender_video_.reset(
- new TestRtpSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr));
- }
- std::unique_ptr<TestRtpSenderVideo> rtp_sender_video_;
-};
-
TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) {
// Configure rtp_sender with csrc.
std::vector<uint32_t> csrcs;
@@ -381,10 +331,10 @@
MockTransport transport;
const bool kEnableAudio = true;
rtp_sender_.reset(new RTPSender(
- kEnableAudio, &fake_clock_, &transport, &mock_paced_sender_, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+ kEnableAudio, &fake_clock_, &transport, &mock_paced_sender_,
+ absl::nullopt, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
nullptr, &retransmission_rate_limiter_, nullptr, false, nullptr, false,
- false));
+ false, FieldTrialBasedConfig()));
rtp_sender_->SetTimestampOffset(0);
rtp_sender_->SetSSRC(kSsrc);
@@ -427,11 +377,12 @@
TransportFeedbackObserverGetsCorrectByteCount) {
constexpr int kRtpOverheadBytesPerPacket = 12 + 8;
testing::NiceMock<MockOverheadObserver> mock_overhead_observer;
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
- &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
- nullptr, &retransmission_rate_limiter_, &mock_overhead_observer, false,
- nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
+ &seq_num_allocator_, &feedback_observer_, nullptr, nullptr,
+ &mock_rtc_event_log_, nullptr,
+ &retransmission_rate_limiter_, &mock_overhead_observer,
+ false, nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber,
@@ -440,9 +391,8 @@
.WillOnce(testing::Return(kTransportSequenceNumber));
const size_t expected_bytes =
- GetParam() ? sizeof(kPayloadData) + kGenericHeaderLength +
- kRtpOverheadBytesPerPacket
- : sizeof(kPayloadData) + kGenericHeaderLength;
+ GetParam() ? sizeof(kPayloadData) + kRtpOverheadBytesPerPacket
+ : sizeof(kPayloadData);
EXPECT_CALL(feedback_observer_,
AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
@@ -451,15 +401,16 @@
EXPECT_CALL(mock_overhead_observer,
OnOverheadChanged(kRtpOverheadBytesPerPacket))
.Times(1);
- SendGenericPayload();
+ SendGenericPacket();
}
TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
- &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
- &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
- nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
+ &seq_num_allocator_, &feedback_observer_, nullptr, nullptr,
+ &mock_rtc_event_log_, &send_packet_observer_,
+ &retransmission_rate_limiter_, nullptr, false, nullptr,
+ false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber,
@@ -476,7 +427,7 @@
PacedPacketInfo()))
.Times(1);
- SendGenericPayload();
+ SendGenericPacket();
const auto& packet = transport_.last_sent_packet();
uint16_t transport_seq_no;
@@ -487,14 +438,15 @@
}
TEST_P(RtpSenderTestWithoutPacer, PacketOptionsNoRetransmission) {
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
- &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
- &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
- nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
+ &seq_num_allocator_, &feedback_observer_, nullptr, nullptr,
+ &mock_rtc_event_log_, &send_packet_observer_,
+ &retransmission_rate_limiter_, nullptr, false, nullptr,
+ false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
- SendGenericPayload();
+ SendGenericPacket();
EXPECT_FALSE(transport_.last_options_.is_retransmit);
}
@@ -507,7 +459,7 @@
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
.WillOnce(testing::Return(kTransportSequenceNumber));
EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1);
- SendGenericPayload();
+ SendGenericPacket();
EXPECT_TRUE(transport_.last_options_.included_in_feedback);
}
@@ -520,7 +472,7 @@
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
.WillOnce(testing::Return(kTransportSequenceNumber));
EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1);
- SendGenericPayload();
+ SendGenericPacket();
EXPECT_TRUE(transport_.last_options_.included_in_allocation);
}
@@ -528,33 +480,38 @@
SetsIncludedInAllocationWhenForcedAsPartOfAllocation) {
SetUpRtpSender(false, false);
rtp_sender_->SetAsPartOfAllocation(true);
- SendGenericPayload();
+ SendGenericPacket();
EXPECT_FALSE(transport_.last_options_.included_in_feedback);
EXPECT_TRUE(transport_.last_options_.included_in_allocation);
}
TEST_P(RtpSenderTestWithoutPacer, DoesnSetIncludedInAllocationByDefault) {
SetUpRtpSender(false, false);
- SendGenericPayload();
+ SendGenericPacket();
EXPECT_FALSE(transport_.last_options_.included_in_feedback);
EXPECT_FALSE(transport_.last_options_.included_in_allocation);
}
TEST_P(RtpSenderTestWithoutPacer, OnSendSideDelayUpdated) {
testing::StrictMock<MockSendSideDelayObserver> send_side_delay_observer_;
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, &send_side_delay_observer_, &mock_rtc_event_log_,
- nullptr, nullptr, nullptr, false, nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
+ nullptr, nullptr, nullptr, &send_side_delay_observer_,
+ &mock_rtc_event_log_, nullptr, nullptr, nullptr, false,
+ nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
+ &playout_delay_oracle, nullptr, false,
+ FieldTrialBasedConfig());
const uint8_t kPayloadType = 127;
+ const char payload_name[] = "GENERIC";
+
+ rtp_sender_video.RegisterPayloadType(kPayloadType, payload_name);
+
const uint32_t kCaptureTimeMsToRtpTimestamp = 90; // 90 kHz clock
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
RTPVideoHeader video_header;
- EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType,
- 1000 * kCaptureTimeMsToRtpTimestamp,
- 0, 1500));
// Send packet with 10 ms send-side delay. The average and max should be 10
// ms.
@@ -562,10 +519,10 @@
.Times(1);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
fake_clock_.AdvanceTimeMilliseconds(10);
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, kPayloadType,
capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms,
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
// Send another packet with 20 ms delay. The average
@@ -573,10 +530,10 @@
EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(15, 20, kSsrc))
.Times(1);
fake_clock_.AdvanceTimeMilliseconds(10);
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, kPayloadType,
capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms,
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
// Send another packet at the same time, which replaces the last packet.
@@ -585,10 +542,10 @@
EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(5, 10, kSsrc))
.Times(1);
capture_time_ms = fake_clock_.TimeInMilliseconds();
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, kPayloadType,
capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms,
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
// Send a packet 1 second later. The earlier packets should have timed
@@ -598,10 +555,10 @@
fake_clock_.AdvanceTimeMilliseconds(1);
EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(1, 1, kSsrc))
.Times(1);
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, kPayloadType,
capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms,
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
}
@@ -615,15 +572,16 @@
OnSendPacket(kTransportSequenceNumber, _, _))
.Times(1);
- SendGenericPayload();
+ SendGenericPacket();
}
TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
- &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr,
+ false, &fake_clock_, &transport_, &mock_paced_sender_, absl::nullopt,
+ &seq_num_allocator_, &feedback_observer_, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ &retransmission_rate_limiter_, nullptr, false, nullptr, false, false,
+ FieldTrialBasedConfig()));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc);
rtp_sender_->SetStorePacketsStatus(true, 10);
@@ -642,7 +600,7 @@
PacedPacketInfo()))
.Times(1);
- SendGenericPayload();
+ SendGenericPacket();
rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
fake_clock_.TimeInMilliseconds(), false,
PacedPacketInfo());
@@ -974,7 +932,7 @@
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
.Times(1);
- SendGenericPayload(); // Packet passed to pacer.
+ SendGenericPacket(); // Packet passed to pacer.
const bool kIsRetransmit = false;
rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -994,7 +952,7 @@
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
.Times(1);
- SendGenericPayload(); // Packet passed to pacer.
+ SendGenericPacket(); // Packet passed to pacer.
const bool kIsRetransmit = true;
rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -1005,10 +963,10 @@
TEST_P(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
+ false, &fake_clock_, &transport_, &mock_paced_sender_, absl::nullopt,
nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr,
- nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_,
- nullptr, false, nullptr, false, false));
+ nullptr, &send_packet_observer_, &retransmission_rate_limiter_, nullptr,
+ false, nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
@@ -1021,7 +979,7 @@
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
.Times(1);
- SendGenericPayload(); // Packet passed to pacer.
+ SendGenericPacket(); // Packet passed to pacer.
const bool kIsRetransmit = false;
rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -1032,9 +990,10 @@
TEST_P(RtpSenderTest, SendRedundantPayloads) {
MockTransport transport;
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
+ false, &fake_clock_, &transport, &mock_paced_sender_, absl::nullopt,
nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ &retransmission_rate_limiter_, nullptr, false, nullptr, false, false,
+ FieldTrialBasedConfig()));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc);
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
@@ -1107,17 +1066,20 @@
}
TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) {
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+ const char payload_name[] = "GENERIC";
const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
- 0, 1500));
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
+ &playout_delay_oracle, nullptr, false,
+ FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
uint8_t payload[] = {47, 11, 32, 93, 89};
// Send keyframe
RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+ ASSERT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
auto sent_payload = transport_.last_sent_packet().payload();
uint8_t generic_header = sent_payload[0];
@@ -1130,9 +1092,9 @@
payload[1] = 42;
payload[4] = 13;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+ ASSERT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
sent_payload = transport_.last_sent_packet().payload();
generic_header = sent_payload[0];
@@ -1142,11 +1104,11 @@
}
TEST_P(RtpSenderTest, SendFlexfecPackets) {
+ constexpr uint32_t kTimestamp = 1234;
constexpr int kMediaPayloadType = 127;
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
- const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
@@ -1155,20 +1117,26 @@
// Reset |rtp_sender_| to use FlexFEC.
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
- &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
- &mock_rtc_event_log_, &send_packet_observer_,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ false, &fake_clock_, &transport_, &mock_paced_sender_, kFlexfecSsrc,
+ &seq_num_allocator_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+ &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
+ nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetStorePacketsStatus(true, 10);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+ &flexfec_sender, &playout_delay_oracle,
+ nullptr, false, FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
// Parameters selected to generate a single FEC packet per media packet.
FecProtectionParams params;
params.fec_rate = 15;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
- rtp_sender_->SetFecParameters(params, params);
+ rtp_sender_video.SetFecParameters(params, params);
EXPECT_CALL(mock_paced_sender_,
InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
@@ -1177,7 +1145,13 @@
EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
kFlexfecSsrc, _, _, _, false))
.WillOnce(testing::SaveArg<2>(&flexfec_seq_num));
- SendGenericPayload();
+
+ RTPVideoHeader video_header;
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
.Times(2);
@@ -1201,11 +1175,12 @@
// TODO(ilnik): because of webrtc:7859. Once FEC moved below pacer, this test
// should be removed.
TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
+ constexpr uint32_t kTimestamp = 1234;
+ const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
constexpr int kMediaPayloadType = 127;
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
- const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
@@ -1215,14 +1190,21 @@
// Reset |rtp_sender_| to use FlexFEC.
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
- &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+ false, &fake_clock_, &transport_, &mock_paced_sender_,
+ flexfec_sender.ssrc(), &seq_num_allocator_, nullptr, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ &retransmission_rate_limiter_, nullptr, false, nullptr, false, false,
+ FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetStorePacketsStatus(true, 10);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+ &flexfec_sender, &playout_delay_oracle,
+ nullptr, false, FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
// Need extension to be registered for timing frames to be sent.
ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionVideoTiming, kVideoTimingExtensionId));
@@ -1232,7 +1214,7 @@
params.fec_rate = 15;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
- rtp_sender_->SetFecParameters(params, params);
+ rtp_sender_video.SetFecParameters(params, params);
EXPECT_CALL(mock_paced_sender_,
InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
@@ -1241,17 +1223,11 @@
kFlexfecSsrc, _, _, _, false))
.Times(0); // Not called because packet should not be protected.
- const uint32_t kTimestamp = 1234;
- const uint8_t kPayloadType = 127;
- const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
- EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
- 0, 1500));
RTPVideoHeader video_header;
video_header.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
- sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ kVideoFrameKey, kMediaPayloadType, kTimestamp, kCaptureTimeMs,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
EXPECT_CALL(mock_rtc_event_log_,
@@ -1275,9 +1251,9 @@
InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc,
kSeqNum + 1, _, _, false));
video_header.video_timing.flags = VideoSendTiming::kInvalid;
- EXPECT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameKey, kPayloadType, kTimestamp + 1, kCaptureTimeMs + 1,
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ kVideoFrameKey, kMediaPayloadType, kTimestamp + 1, kCaptureTimeMs + 1,
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
kDefaultExpectedRetransmissionTimeMs));
EXPECT_CALL(mock_rtc_event_log_,
@@ -1301,11 +1277,11 @@
}
TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
+ constexpr uint32_t kTimestamp = 1234;
constexpr int kMediaPayloadType = 127;
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
- const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
@@ -1314,24 +1290,35 @@
// Reset |rtp_sender_| to use FlexFEC.
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, &flexfec_sender,
- &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
- &mock_rtc_event_log_, &send_packet_observer_,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ false, &fake_clock_, &transport_, nullptr, flexfec_sender.ssrc(),
+ &seq_num_allocator_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+ &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
+ nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+ &flexfec_sender, &playout_delay_oracle,
+ nullptr, false, FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
// Parameters selected to generate a single FEC packet per media packet.
FecProtectionParams params;
params.fec_rate = 15;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
- rtp_sender_->SetFecParameters(params, params);
+ rtp_sender_video.SetFecParameters(params, params);
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
.Times(2);
- SendGenericPayload();
+ RTPVideoHeader video_header;
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
ASSERT_EQ(2, transport_.packets_sent());
const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
@@ -1353,8 +1340,8 @@
rtp_sender_->SetSendingMediaStatus(true);
// Send a couple packets.
- SendGenericPayload();
- SendGenericPayload();
+ SendGenericPacket();
+ SendGenericPacket();
// Expect both packets to have the MID set.
ASSERT_EQ(2u, transport_.sent_packets_.size());
@@ -1365,11 +1352,65 @@
}
}
+TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnSentPackets) {
+ const char kRid[] = "f";
+
+ rtp_sender_->SetSendingMediaStatus(false);
+ rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId,
+ kRidExtensionId);
+ rtp_sender_->SetRid(kRid);
+ rtp_sender_->SetSendingMediaStatus(true);
+
+ SendGenericPacket();
+
+ ASSERT_EQ(1u, transport_.sent_packets_.size());
+ const RtpPacketReceived& packet = transport_.sent_packets_[0];
+ std::string rid;
+ ASSERT_TRUE(packet.GetExtension<RtpStreamId>(&rid));
+ EXPECT_EQ(kRid, rid);
+}
+
+TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnRtxSentPackets) {
+ const char kRid[] = "f";
+
+ rtp_sender_->SetSendingMediaStatus(false);
+ rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId,
+ kRidExtensionId);
+ rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRepairedRtpStreamId,
+ kRepairedRidExtensionId);
+ rtp_sender_->SetRid(kRid);
+ rtp_sender_->SetSendingMediaStatus(true);
+
+ rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
+ rtp_sender_->SetRtxSsrc(1234);
+ rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
+
+ rtp_sender_->SetStorePacketsStatus(true, 10);
+
+ SendGenericPacket();
+ ASSERT_EQ(1u, transport_.sent_packets_.size());
+ const RtpPacketReceived& packet = transport_.sent_packets_[0];
+ std::string rid;
+ ASSERT_TRUE(packet.GetExtension<RtpStreamId>(&rid));
+ EXPECT_EQ(kRid, rid);
+ rid = kNoRid;
+ EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&rid));
+
+ uint16_t packet_id = packet.SequenceNumber();
+ rtp_sender_->ReSendPacket(packet_id);
+ ASSERT_EQ(2u, transport_.sent_packets_.size());
+ const RtpPacketReceived& rtx_packet = transport_.sent_packets_[1];
+ ASSERT_TRUE(rtx_packet.GetExtension<RepairedRtpStreamId>(&rid));
+ EXPECT_EQ(kRid, rid);
+ EXPECT_FALSE(rtx_packet.HasExtension<RtpStreamId>());
+}
+
TEST_P(RtpSenderTest, FecOverheadRate) {
+ constexpr uint32_t kTimestamp = 1234;
+ constexpr int kMediaPayloadType = 127;
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
- const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
@@ -1378,19 +1419,25 @@
// Reset |rtp_sender_| to use FlexFEC.
rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
- &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+ false, &fake_clock_, &transport_, &mock_paced_sender_,
+ flexfec_sender.ssrc(), &seq_num_allocator_, nullptr, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ &retransmission_rate_limiter_, nullptr, false, nullptr, false, false,
+ FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+ &flexfec_sender, &playout_delay_oracle,
+ nullptr, false, FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
// Parameters selected to generate a single FEC packet per media packet.
FecProtectionParams params;
params.fec_rate = 15;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
- rtp_sender_->SetFecParameters(params, params);
+ rtp_sender_video.SetFecParameters(params, params);
constexpr size_t kNumMediaPackets = 10;
constexpr size_t kNumFecPackets = kNumMediaPackets;
@@ -1398,7 +1445,13 @@
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false))
.Times(kNumMediaPackets + kNumFecPackets);
for (size_t i = 0; i < kNumMediaPackets; ++i) {
- SendGenericPayload();
+ RTPVideoHeader video_header;
+
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
fake_clock_.AdvanceTimeMilliseconds(kTimeBetweenPacketsMs);
}
constexpr size_t kRtpHeaderLength = 12;
@@ -1409,63 +1462,7 @@
kGenericCodecHeaderLength + kPayloadLength;
EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 /
(kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f),
- rtp_sender_->FecOverheadRate(), 500);
-}
-
-TEST_P(RtpSenderTest, FrameCountCallbacks) {
- class TestCallback : public FrameCountObserver {
- public:
- TestCallback() : FrameCountObserver(), num_calls_(0), ssrc_(0) {}
- ~TestCallback() override = default;
-
- void FrameCountUpdated(const FrameCounts& frame_counts,
- uint32_t ssrc) override {
- ++num_calls_;
- ssrc_ = ssrc;
- frame_counts_ = frame_counts;
- }
-
- uint32_t num_calls_;
- uint32_t ssrc_;
- FrameCounts frame_counts_;
- } callback;
-
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr,
- nullptr, nullptr, &callback, nullptr, nullptr, nullptr,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
- rtp_sender_->SetSSRC(kSsrc);
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
- const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
- 0, 1500));
- uint8_t payload[] = {47, 11, 32, 93, 89};
- rtp_sender_->SetStorePacketsStatus(true, 1);
- uint32_t ssrc = rtp_sender_->SSRC();
-
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _))
- .Times(::testing::AtLeast(2));
-
- RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
- EXPECT_EQ(1U, callback.num_calls_);
- EXPECT_EQ(ssrc, callback.ssrc_);
- EXPECT_EQ(1, callback.frame_counts_.key_frames);
- EXPECT_EQ(0, callback.frame_counts_.delta_frames);
-
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
- EXPECT_EQ(2U, callback.num_calls_);
- EXPECT_EQ(ssrc, callback.ssrc_);
- EXPECT_EQ(1, callback.frame_counts_.key_frames);
- EXPECT_EQ(1, callback.frame_counts_.delta_frames);
-
- rtp_sender_.reset();
+ rtp_sender_video.FecOverheadRate(), 500);
}
TEST_P(RtpSenderTest, BitrateCallbacks) {
@@ -1493,12 +1490,21 @@
uint32_t total_bitrate_;
uint32_t retransmit_bitrate_;
} callback;
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
- &callback, nullptr, nullptr, nullptr, nullptr,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
+ nullptr, nullptr, &callback, nullptr, nullptr, nullptr,
+ &retransmission_rate_limiter_, nullptr, false, nullptr,
+ false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
+ &playout_delay_oracle, nullptr, false,
+ FieldTrialBasedConfig());
+ const char payload_name[] = "GENERIC";
+ const uint8_t payload_type = 127;
+ rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
+
// Simulate kNumPackets sent with kPacketInterval ms intervals, with the
// number of packets selected so that we fill (but don't overflow) the one
// second averaging window.
@@ -1509,10 +1515,6 @@
// Overhead = 12 bytes RTP header + 1 byte generic header.
const uint32_t kPacketOverhead = 13;
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
- const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
- 0, 1500));
uint8_t payload[] = {47, 11, 32, 93, 89};
rtp_sender_->SetStorePacketsStatus(true, 1);
uint32_t ssrc = rtp_sender_->SSRC();
@@ -1523,9 +1525,9 @@
// Send a few frames.
RTPVideoHeader video_header;
for (uint32_t i = 0; i < kNumPackets; ++i) {
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+ ASSERT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
fake_clock_.AdvanceTimeMilliseconds(kPacketInterval);
}
@@ -1547,21 +1549,6 @@
rtp_sender_.reset();
}
-class RtpSenderAudioTest : public RtpSenderTest {
- protected:
- RtpSenderAudioTest() {}
-
- void SetUp() override {
- payload_ = kAudioPayload;
- rtp_sender_.reset(new RTPSender(
- true, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
- rtp_sender_->SetSSRC(kSsrc);
- rtp_sender_->SetSequenceNumber(kSeqNum);
- }
-};
-
TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) {
class TestCallback : public StreamDataCountersCallback {
public:
@@ -1595,10 +1582,13 @@
const uint8_t kRedPayloadType = 96;
const uint8_t kUlpfecPayloadType = 97;
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+ const char payload_name[] = "GENERIC";
const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
- 0, 1500));
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(), nullptr,
+ &playout_delay_oracle, nullptr, false,
+ FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(payload_type, payload_name);
uint8_t payload[] = {47, 11, 32, 93, 89};
rtp_sender_->SetStorePacketsStatus(true, 1);
uint32_t ssrc = rtp_sender_->SSRC();
@@ -1607,9 +1597,9 @@
// Send a frame.
RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+ ASSERT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
StreamDataCounters expected;
expected.transmitted.payload_bytes = 6;
expected.transmitted.header_bytes = 12;
@@ -1643,15 +1633,15 @@
callback.Matches(ssrc, expected);
// Send ULPFEC.
- rtp_sender_->SetUlpfecConfig(kRedPayloadType, kUlpfecPayloadType);
+ rtp_sender_video.SetUlpfecConfig(kRedPayloadType, kUlpfecPayloadType);
FecProtectionParams fec_params;
fec_params.fec_mask_type = kFecMaskRandom;
fec_params.fec_rate = 1;
fec_params.max_fec_frames = 1;
- rtp_sender_->SetFecParameters(fec_params, fec_params);
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+ rtp_sender_video.SetFecParameters(fec_params, fec_params);
+ ASSERT_TRUE(rtp_sender_video.SendVideo(
kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
expected.transmitted.payload_bytes = 40;
expected.transmitted.header_bytes = 60;
expected.transmitted.packets = 5;
@@ -1661,111 +1651,15 @@
rtp_sender_->RegisterRtpStatisticsCallback(nullptr);
}
-TEST_P(RtpSenderAudioTest, SendAudio) {
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
- const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000,
- 0, 1500));
- uint8_t payload[] = {47, 11, 32, 93, 89};
-
- RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
- auto sent_payload = transport_.last_sent_packet().payload();
- EXPECT_THAT(sent_payload, ElementsAreArray(payload));
-}
-
-TEST_P(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
- EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel));
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
- kAudioLevelExtensionId));
-
- char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
- const uint8_t payload_type = 127;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000,
- 0, 1500));
- uint8_t payload[] = {47, 11, 32, 93, 89};
-
- RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
- auto sent_payload = transport_.last_sent_packet().payload();
- EXPECT_THAT(sent_payload, ElementsAreArray(payload));
- // Verify AudioLevel extension.
- bool voice_activity;
- uint8_t audio_level;
- EXPECT_TRUE(transport_.last_sent_packet().GetExtension<AudioLevel>(
- &voice_activity, &audio_level));
- EXPECT_EQ(kAudioLevel, audio_level);
- EXPECT_FALSE(voice_activity);
-}
-
-// As RFC4733, named telephone events are carried as part of the audio stream
-// and must use the same sequence number and timestamp base as the regular
-// audio channel.
-// This test checks the marker bit for the first packet and the consequent
-// packets of the same telephone event. Since it is specifically for DTMF
-// events, ignoring audio packets and sending kEmptyFrame instead of those.
-TEST_P(RtpSenderAudioTest, CheckMarkerBitForTelephoneEvents) {
- const char* kDtmfPayloadName = "telephone-event";
- const uint32_t kPayloadFrequency = 8000;
- const uint8_t kPayloadType = 126;
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(kDtmfPayloadName, kPayloadType,
- kPayloadFrequency, 0, 0));
- // For Telephone events, payload is not added to the registered payload list,
- // it will register only the payload used for audio stream.
- // Registering the payload again for audio stream with different payload name.
- const char* kPayloadName = "payload_name";
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType,
- kPayloadFrequency, 1, 0));
- int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
- // DTMF event key=9, duration=500 and attenuationdB=10
- rtp_sender_->SendTelephoneEvent(9, 500, 10);
- // During start, it takes the starting timestamp as last sent timestamp.
- // The duration is calculated as the difference of current and last sent
- // timestamp. So for first call it will skip since the duration is zero.
- RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kEmptyFrame, kPayloadType, capture_time_ms, 0, nullptr, 0, nullptr,
- &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
- // DTMF Sample Length is (Frequency/1000) * Duration.
- // So in this case, it is (8000/1000) * 500 = 4000.
- // Sending it as two packets.
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kEmptyFrame, kPayloadType, capture_time_ms + 2000, 0, nullptr, 0, nullptr,
- &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
- // Marker Bit should be set to 1 for first packet.
- EXPECT_TRUE(transport_.last_sent_packet().Marker());
-
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kEmptyFrame, kPayloadType, capture_time_ms + 4000, 0, nullptr, 0, nullptr,
- &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
- // Marker Bit should be set to 0 for rest of the packets.
- EXPECT_FALSE(transport_.last_sent_packet().Marker());
-}
-
TEST_P(RtpSenderTestWithoutPacer, BytesReportedCorrectly) {
- const char* kPayloadName = "GENERIC";
+ // XXX const char* kPayloadName = "GENERIC";
const uint8_t kPayloadType = 127;
rtp_sender_->SetSSRC(1234);
rtp_sender_->SetRtxSsrc(4321);
rtp_sender_->SetRtxPayloadType(kPayloadType - 1, kPayloadType);
rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
- ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType, 90000,
- 0, 1500));
- uint8_t payload[] = {47, 11, 32, 93, 89};
-
- RTPVideoHeader video_header;
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(
- kVideoFrameKey, kPayloadType, 1234, 4321, payload, sizeof(payload),
- nullptr, &video_header, nullptr, kDefaultExpectedRetransmissionTimeMs));
-
+ SendGenericPacket();
// Will send 2 full-size padding packets.
rtp_sender_->TimeToSendPadding(1, PacedPacketInfo());
rtp_sender_->TimeToSendPadding(1, PacedPacketInfo());
@@ -1774,9 +1668,9 @@
StreamDataCounters rtx_stats;
rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats);
- // Payload + 1-byte generic header.
+ // Payload
EXPECT_GT(rtp_stats.first_packet_time_ms, -1);
- EXPECT_EQ(rtp_stats.transmitted.payload_bytes, sizeof(payload) + 1);
+ EXPECT_EQ(rtp_stats.transmitted.payload_bytes, sizeof(kPayloadData));
EXPECT_EQ(rtp_stats.transmitted.header_bytes, 12u);
EXPECT_EQ(rtp_stats.transmitted.padding_bytes, 0u);
EXPECT_EQ(rtx_stats.transmitted.payload_bytes, 0u);
@@ -1829,406 +1723,18 @@
EXPECT_EQ(kNumPackets * 2, transport_.packets_sent());
}
-TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) {
- uint8_t kFrame[kMaxPacketLength];
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
- kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
- RTPVideoHeader hdr;
- hdr.rotation = kVideoRotation_0;
- rtp_sender_video_->SendVideo(kVideoCodecGeneric, kVideoFrameKey, kPayload,
- kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
- &hdr, kDefaultExpectedRetransmissionTimeMs);
-
- VideoRotation rotation;
- EXPECT_TRUE(
- transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
- EXPECT_EQ(kVideoRotation_0, rotation);
-}
-
-TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
- uint8_t kFrame[kMaxPacketLength];
- const int64_t kPacketizationTimeMs = 100;
- const int64_t kEncodeStartDeltaMs = 10;
- const int64_t kEncodeFinishDeltaMs = 50;
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
- kRtpExtensionVideoTiming, kVideoTimingExtensionId));
-
- const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds();
-
- RTPVideoHeader hdr;
- hdr.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
- hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs;
- hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs;
-
- fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs);
- rtp_sender_video_->SendVideo(kVideoCodecGeneric, kVideoFrameKey, kPayload,
- kTimestamp, kCaptureTimestamp, kFrame,
- sizeof(kFrame), nullptr, &hdr,
- kDefaultExpectedRetransmissionTimeMs);
- VideoSendTiming timing;
- EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
- &timing));
- EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms);
- EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms);
- EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
-}
-
-TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
- uint8_t kFrame[kMaxPacketLength];
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
- kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
- RTPVideoHeader hdr;
- hdr.rotation = kVideoRotation_90;
- EXPECT_TRUE(rtp_sender_video_->SendVideo(
- kVideoCodecGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
- sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
- hdr.rotation = kVideoRotation_0;
- EXPECT_TRUE(rtp_sender_video_->SendVideo(
- kVideoCodecGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame,
- sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
- VideoRotation rotation;
- EXPECT_TRUE(
- transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
- EXPECT_EQ(kVideoRotation_0, rotation);
-}
-
-TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) {
- uint8_t kFrame[kMaxPacketLength];
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
- kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
- RTPVideoHeader hdr;
- hdr.rotation = kVideoRotation_90;
- EXPECT_TRUE(rtp_sender_video_->SendVideo(
- kVideoCodecGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
- sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
- EXPECT_TRUE(rtp_sender_video_->SendVideo(
- kVideoCodecGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame,
- sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
- VideoRotation rotation;
- EXPECT_TRUE(
- transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
- EXPECT_EQ(kVideoRotation_90, rotation);
-}
-
-// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits
-// are set in the CVO byte.
-TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
- // Test extracting rotation when Camera (C) and Flip (F) bits are zero.
- EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0));
- EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1));
- EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2));
- EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3));
- // Test extracting rotation when Camera (C) and Flip (F) bits are set.
- const int flip_bit = 1 << 2;
- const int camera_bit = 1 << 3;
- EXPECT_EQ(kVideoRotation_0,
- ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0));
- EXPECT_EQ(kVideoRotation_90,
- ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1));
- EXPECT_EQ(kVideoRotation_180,
- ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2));
- EXPECT_EQ(kVideoRotation_270,
- ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) {
- RTPVideoHeader header;
- header.codec = kVideoCodecGeneric;
-
- EXPECT_EQ(kDontRetransmit,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kConditionallyRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitAllPackets,
- kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) {
- RTPVideoHeader header;
- header.video_type_header.emplace<RTPVideoHeaderH264>().packetization_mode =
- H264PacketizationMode::NonInterleaved;
- header.codec = kVideoCodecH264;
-
- EXPECT_EQ(kDontRetransmit,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kConditionallyRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitAllPackets,
- kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) {
- RTPVideoHeader header;
- header.codec = kVideoCodecVP8;
- auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
- vp8_header.temporalIdx = 0;
-
- EXPECT_EQ(kDontRetransmit,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers | kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kConditionallyRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(
- kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitAllPackets,
- kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) {
- RTPVideoHeader header;
- header.codec = kVideoCodecVP8;
-
- auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
- for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
- vp8_header.temporalIdx = tid;
-
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kRetransmitOff,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers | kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitAllPackets,
- kDefaultExpectedRetransmissionTimeMs));
- }
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) {
- RTPVideoHeader header;
- header.codec = kVideoCodecVP9;
-
- auto& vp9_header = header.video_type_header.emplace<RTPVideoHeaderVP9>();
- for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
- vp9_header.temporal_idx = tid;
-
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kRetransmitOff,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
- header, kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission,
- rtp_sender_video_->GetStorageType(
- header, kRetransmitHigherLayers | kRetransmitBaseLayer,
- kDefaultExpectedRetransmissionTimeMs));
- EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
- header, kRetransmitAllPackets,
- kDefaultExpectedRetransmissionTimeMs));
- }
-}
-
-TEST_P(RtpSenderVideoTest, ConditionalRetransmit) {
- const int64_t kFrameIntervalMs = 33;
- const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
- const uint8_t kSettings =
- kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
-
- // Insert VP8 frames for all temporal layers, but stop before the final index.
- RTPVideoHeader header;
- header.codec = kVideoCodecVP8;
-
- // Fill averaging window to prevent rounding errors.
- constexpr int kNumRepetitions =
- (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
- kFrameIntervalMs;
- constexpr int kPattern[] = {0, 2, 1, 2};
- auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
- for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
- vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
- }
-
- // Since we're at the start of the pattern, the next expected frame in TL0 is
- // right now. We will wait at most one expected retransmission time before
- // acknowledging that it did not arrive, which means this frame and the next
- // will not be retransmitted.
- vp8_header.temporalIdx = 1;
- EXPECT_EQ(StorageType::kDontRetransmit,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
- EXPECT_EQ(StorageType::kDontRetransmit,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
- // The TL0 frame did not arrive. So allow retransmission.
- EXPECT_EQ(StorageType::kAllowRetransmission,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
- // Insert a frame for TL2. We just had frame in TL1, so the next one there is
- // in three frames away. TL0 is still too far in the past. So, allow
- // retransmission.
- vp8_header.temporalIdx = 2;
- EXPECT_EQ(StorageType::kAllowRetransmission,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
- // Another TL2, next in TL1 is two frames away. Allow again.
- EXPECT_EQ(StorageType::kAllowRetransmission,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
- // Yet another TL2, next in TL1 is now only one frame away, so don't store
- // for retransmission.
- EXPECT_EQ(StorageType::kDontRetransmit,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-}
-
-TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
- const int64_t kFrameIntervalMs = 200;
- const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
- const int32_t kSettings =
- kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
-
- // Insert VP8 frames for all temporal layers, but stop before the final index.
- RTPVideoHeader header;
- header.codec = kVideoCodecVP8;
-
- // Fill averaging window to prevent rounding errors.
- constexpr int kNumRepetitions =
- (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
- kFrameIntervalMs;
- constexpr int kPattern[] = {0, 2, 2, 2};
- auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
- for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
- vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
-
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
- fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
- }
-
- // Since we're at the start of the pattern, the next expected frame will be
- // right now in TL0. Put it in TL1 instead. Regular rules would dictate that
- // we don't store for retransmission because we expect a frame in a lower
- // layer, but that last frame in TL1 was a long time ago in absolute terms,
- // so allow retransmission anyway.
- vp8_header.temporalIdx = 1;
- EXPECT_EQ(StorageType::kAllowRetransmission,
- rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-}
-
-TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
- const int64_t kFrameId = 100000;
- uint8_t kFrame[100];
- EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
- kRtpExtensionGenericFrameDescriptor, kGenericDescriptorId));
-
- RTPVideoHeader hdr;
- RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
- generic.frame_id = kFrameId;
- generic.temporal_index = 3;
- generic.spatial_index = 2;
- generic.higher_spatial_layers.push_back(4);
- generic.dependencies.push_back(kFrameId - 1);
- generic.dependencies.push_back(kFrameId - 500);
- rtp_sender_video_->SendVideo(kVideoCodecGeneric, kVideoFrameDelta, kPayload,
- kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
- &hdr, kDefaultExpectedRetransmissionTimeMs);
-
- RtpGenericFrameDescriptor descriptor_wire;
- EXPECT_EQ(1U, transport_.sent_packets_.size());
- EXPECT_TRUE(
- transport_.last_sent_packet()
- .GetExtension<RtpGenericFrameDescriptorExtension>(&descriptor_wire));
- EXPECT_EQ(static_cast<uint16_t>(generic.frame_id), descriptor_wire.FrameId());
- EXPECT_EQ(generic.temporal_index, descriptor_wire.TemporalLayer());
- EXPECT_THAT(descriptor_wire.FrameDependenciesDiffs(), ElementsAre(1, 500));
- uint8_t spatial_bitmask = 0x14;
- EXPECT_EQ(spatial_bitmask, descriptor_wire.SpatialLayersBitmask());
-}
-
-TEST_P(RtpSenderVideoTest,
- UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed) {
- const int64_t kFrameId = 100000;
- const size_t kFrameSize = 100;
- uint8_t kFrame[kFrameSize];
- ASSERT_TRUE(rtp_sender_->RegisterRtpHeaderExtension(
- RtpGenericFrameDescriptorExtension::kUri, kGenericDescriptorId));
-
- RTPVideoHeader hdr;
- hdr.codec = kVideoCodecVP8;
- RTPVideoHeaderVP8& vp8 = hdr.video_type_header.emplace<RTPVideoHeaderVP8>();
- vp8.pictureId = kFrameId % 0X7FFF;
- vp8.tl0PicIdx = 13;
- vp8.temporalIdx = 1;
- vp8.keyIdx = 2;
- RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
- generic.frame_id = kFrameId;
- rtp_sender_video_->SendVideo(kVideoCodecVP8, kVideoFrameDelta, kPayload,
- kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
- &hdr, kDefaultExpectedRetransmissionTimeMs);
-
- ASSERT_THAT(transport_.sent_packets_, SizeIs(1));
- // Expect only minimal 1-byte vp8 descriptor was generated.
- EXPECT_THAT(transport_.sent_packets_[0].payload_size(), 1 + kFrameSize);
-}
-
TEST_P(RtpSenderTest, OnOverheadChanged) {
MockOverheadObserver mock_overhead_observer;
rtp_sender_.reset(
- new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_, &mock_overhead_observer,
- false, nullptr, false, false));
+ false, nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
// RTP overhead is 12B.
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(12)).Times(1);
- SendGenericPayload();
+ SendGenericPacket();
rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
@@ -2236,29 +1742,30 @@
// TransmissionTimeOffset extension has a size of 8B.
// 12B + 8B = 20B
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(20)).Times(1);
- SendGenericPayload();
+ SendGenericPacket();
}
TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
MockOverheadObserver mock_overhead_observer;
rtp_sender_.reset(
- new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
+ new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_, &mock_overhead_observer,
- false, nullptr, false, false));
+ false, nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSSRC(kSsrc);
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
- SendGenericPayload();
- SendGenericPayload();
+ SendGenericPacket();
+ SendGenericPacket();
}
TEST_P(RtpSenderTest, SendsKeepAlive) {
MockTransport transport;
- rtp_sender_.reset(new RTPSender(
- false, &fake_clock_, &transport, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
- &retransmission_rate_limiter_, nullptr, false, nullptr, false, false));
+ rtp_sender_.reset(
+ new RTPSender(false, &fake_clock_, &transport, nullptr, absl::nullopt,
+ nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+ nullptr, &retransmission_rate_limiter_, nullptr, false,
+ nullptr, false, false, FieldTrialBasedConfig()));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetTimestampOffset(0);
rtp_sender_->SetSSRC(kSsrc);
@@ -2286,16 +1793,11 @@
EXPECT_EQ(kSeqNum + 1, rtp_sender_->SequenceNumber());
}
-INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
- RtpSenderTest,
- ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
- RtpSenderTestWithoutPacer,
- ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
- RtpSenderVideoTest,
- ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
- RtpSenderAudioTest,
- ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
+ RtpSenderTest,
+ ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
+ RtpSenderTestWithoutPacer,
+ ::testing::Bool());
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
index cb0b665..8b835bd 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -20,7 +20,8 @@
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
-#include "api/crypto/frameencryptorinterface.h"
+#include "api/crypto/frame_encryptor_interface.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
@@ -52,11 +53,21 @@
}
void AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
+ const absl::optional<PlayoutDelay>& playout_delay,
FrameType frame_type,
bool set_video_rotation,
+ bool set_color_space,
+ bool set_frame_marking,
bool first_packet,
bool last_packet,
RtpPacketToSend* packet) {
+ // Color space requires two-byte header extensions if HDR metadata is
+ // included. Therefore, it's best to add this extension first so that the
+ // other extensions in the same packet are written as two-byte headers at
+ // once.
+ if (last_packet && set_color_space && video_header.color_space)
+ packet->SetExtension<ColorSpaceExtension>(video_header.color_space.value());
+
if (last_packet && set_video_rotation)
packet->SetExtension<VideoOrientation>(video_header.rotation);
@@ -69,12 +80,23 @@
video_header.video_timing.flags != VideoSendTiming::kInvalid)
packet->SetExtension<VideoTimingExtension>(video_header.video_timing);
+ // If transmitted, add to all packets; ack logic depends on this.
+ if (playout_delay) {
+ packet->SetExtension<PlayoutDelayLimits>(*playout_delay);
+ }
+
+ if (set_frame_marking) {
+ FrameMarking frame_marking = video_header.frame_marking;
+ frame_marking.start_of_frame = first_packet;
+ frame_marking.end_of_frame = last_packet;
+ packet->SetExtension<FrameMarkingExtension>(frame_marking);
+ }
+
if (video_header.generic) {
RtpGenericFrameDescriptor generic_descriptor;
generic_descriptor.SetFirstPacketInSubFrame(first_packet);
generic_descriptor.SetLastPacketInSubFrame(last_packet);
- generic_descriptor.SetFirstSubFrameInFrame(true);
- generic_descriptor.SetLastSubFrameInFrame(true);
+ generic_descriptor.SetDiscardable(video_header.generic->discardable);
if (first_packet) {
generic_descriptor.SetFrameId(
@@ -99,8 +121,13 @@
video_header.height);
}
}
- packet->SetExtension<RtpGenericFrameDescriptorExtension>(
- generic_descriptor);
+ if (!packet->SetExtension<RtpGenericFrameDescriptorExtension01>(
+ generic_descriptor) &&
+ !packet->SetExtension<RtpGenericFrameDescriptorExtension00>(
+ generic_descriptor)) {
+ RTC_LOG(LS_ERROR)
+ << "Could not set RTP extension - Generic Frame Descriptor";
+ }
}
}
@@ -118,19 +145,58 @@
return false;
}
+bool IsBaseLayer(const RTPVideoHeader& video_header) {
+ switch (video_header.codec) {
+ case kVideoCodecVP8: {
+ const auto& vp8 =
+ absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
+ return (vp8.temporalIdx == 0 || vp8.temporalIdx == kNoTemporalIdx);
+ }
+ case kVideoCodecVP9: {
+ const auto& vp9 =
+ absl::get<RTPVideoHeaderVP9>(video_header.video_type_header);
+ return (vp9.temporal_idx == 0 || vp9.temporal_idx == kNoTemporalIdx);
+ }
+ case kVideoCodecH264:
+ // TODO(kron): Implement logic for H264 once WebRTC supports temporal
+ // layers for H264.
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+const char* FrameTypeToString(FrameType frame_type) {
+ switch (frame_type) {
+ case kEmptyFrame:
+ return "empty";
+ case kVideoFrameKey:
+ return "video_key";
+ case kVideoFrameDelta:
+ return "video_delta";
+ default:
+ RTC_NOTREACHED();
+ return "";
+ }
+}
+
} // namespace
RTPSenderVideo::RTPSenderVideo(Clock* clock,
RTPSender* rtp_sender,
FlexfecSender* flexfec_sender,
+ PlayoutDelayOracle* playout_delay_oracle,
FrameEncryptorInterface* frame_encryptor,
- bool require_frame_encryption)
+ bool require_frame_encryption,
+ const WebRtcKeyValueConfig& field_trials)
: rtp_sender_(rtp_sender),
clock_(clock),
- video_type_(kVideoCodecGeneric),
retransmission_settings_(kRetransmitBaseLayer |
kConditionallyRetransmitHigherLayers),
last_rotation_(kVideoRotation_0),
+ transmit_color_space_next_frame_(false),
+ playout_delay_oracle_(playout_delay_oracle),
red_payload_type_(-1),
ulpfec_payload_type_(-1),
flexfec_sender_(flexfec_sender),
@@ -138,24 +204,21 @@
key_fec_params_{0, 1, kFecMaskRandom},
fec_bitrate_(1000, RateStatistics::kBpsScale),
video_bitrate_(1000, RateStatistics::kBpsScale),
+ packetization_overhead_bitrate_(1000, RateStatistics::kBpsScale),
frame_encryptor_(frame_encryptor),
- require_frame_encryption_(require_frame_encryption) {}
+ require_frame_encryption_(require_frame_encryption),
+ generic_descriptor_auth_experiment_(
+ field_trials.Lookup("WebRTC-GenericDescriptorAuth").find("Enabled") ==
+ 0) {
+ RTC_DCHECK(playout_delay_oracle_);
+}
RTPSenderVideo::~RTPSenderVideo() {}
-void RTPSenderVideo::SetVideoCodecType(enum VideoCodecType video_type) {
- video_type_ = video_type;
-}
+void RTPSenderVideo::RegisterPayloadType(int8_t payload_type,
+ absl::string_view payload_name) {
+ VideoCodecType video_type;
-VideoCodecType RTPSenderVideo::VideoCodecType() const {
- return video_type_;
-}
-
-// Static.
-RtpUtility::Payload* RTPSenderVideo::CreateVideoPayload(
- absl::string_view payload_name,
- int8_t payload_type) {
- enum VideoCodecType video_type = kVideoCodecGeneric;
if (absl::EqualsIgnoreCase(payload_name, "VP8")) {
video_type = kVideoCodecVP8;
} else if (absl::EqualsIgnoreCase(payload_name, "VP9")) {
@@ -169,9 +232,15 @@
} else {
video_type = kVideoCodecGeneric;
}
- VideoPayload vp;
- vp.videoCodecType = video_type;
- return new RtpUtility::Payload(payload_name, PayloadUnion(vp));
+
+ rtc::CritScope cs(&payload_type_crit_);
+ payload_type_map_[payload_type] = video_type;
+
+ // Backward compatibility for older receivers without temporal layer logic
+ if (video_type == kVideoCodecH264) {
+ rtc::CritScope cs(&crit_);
+ retransmission_settings_ = kRetransmitBaseLayer | kRetransmitHigherLayers;
+ }
}
void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,
@@ -179,8 +248,8 @@
// Remember some values about the packet before sending it away.
size_t packet_size = packet->size();
uint16_t seq_num = packet->SequenceNumber();
- if (!rtp_sender_->SendToNetwork(std::move(packet), storage,
- RtpPacketSender::kLowPriority)) {
+ if (!LogAndSendToNetwork(std::move(packet), storage,
+ RtpPacketSender::kLowPriority)) {
RTC_LOG(LS_WARNING) << "Failed to send video packet " << seq_num;
return;
}
@@ -199,7 +268,6 @@
BuildRedPayload(*media_packet, red_packet.get());
std::vector<std::unique_ptr<RedPacket>> fec_packets;
- StorageType fec_storage = kDontRetransmit;
{
// Only protect while creating RED and FEC packets, not when sending.
rtc::CritScope cs(&crit_);
@@ -217,15 +285,13 @@
fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed(
red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number);
RTC_DCHECK_EQ(num_fec_packets, fec_packets.size());
- if (retransmission_settings_ & kRetransmitFECPackets)
- fec_storage = kAllowRetransmission;
}
}
}
// Send |red_packet| instead of |packet| for allocated sequence number.
size_t red_packet_size = red_packet->size();
- if (rtp_sender_->SendToNetwork(std::move(red_packet), media_packet_storage,
- RtpPacketSender::kLowPriority)) {
+ if (LogAndSendToNetwork(std::move(red_packet), media_packet_storage,
+ RtpPacketSender::kLowPriority)) {
rtc::CritScope cs(&stats_crit_);
video_bitrate_.Update(red_packet_size, clock_->TimeInMilliseconds());
} else {
@@ -238,9 +304,10 @@
new RtpPacketToSend(*media_packet));
RTC_CHECK(rtp_packet->Parse(fec_packet->data(), fec_packet->length()));
rtp_packet->set_capture_time_ms(media_packet->capture_time_ms());
+ rtp_packet->set_is_fec(true);
uint16_t fec_sequence_number = rtp_packet->SequenceNumber();
- if (rtp_sender_->SendToNetwork(std::move(rtp_packet), fec_storage,
- RtpPacketSender::kLowPriority)) {
+ if (LogAndSendToNetwork(std::move(rtp_packet), kDontRetransmit,
+ RtpPacketSender::kLowPriority)) {
rtc::CritScope cs(&stats_crit_);
fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds());
} else {
@@ -267,8 +334,8 @@
for (auto& fec_packet : fec_packets) {
size_t packet_length = fec_packet->size();
uint16_t seq_num = fec_packet->SequenceNumber();
- if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit,
- RtpPacketSender::kLowPriority)) {
+ if (LogAndSendToNetwork(std::move(fec_packet), kDontRetransmit,
+ RtpPacketSender::kLowPriority)) {
rtc::CritScope cs(&stats_crit_);
fec_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
} else {
@@ -278,6 +345,24 @@
}
}
+bool RTPSenderVideo::LogAndSendToNetwork(
+ std::unique_ptr<RtpPacketToSend> packet,
+ StorageType storage,
+ RtpPacketSender::Priority priority) {
+#if BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
+ int64_t now_ms = clock_->TimeInMilliseconds();
+ BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
+ rtp_sender_->ActualSendBitrateKbit(),
+ packet->Ssrc());
+ BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
+ FecOverheadRate() / 1000, packet->Ssrc());
+ BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
+ rtp_sender_->NackOverheadRate() / 1000,
+ packet->Ssrc());
+#endif
+ return rtp_sender_->SendToNetwork(std::move(packet), storage, priority);
+}
+
void RTPSenderVideo::SetUlpfecConfig(int red_payload_type,
int ulpfec_payload_type) {
// Sanity check. Per the definition of UlpfecConfig (see config.h),
@@ -300,13 +385,6 @@
key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
}
-void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type,
- int* ulpfec_payload_type) const {
- rtc::CritScope cs(&crit_);
- *red_payload_type = red_payload_type_;
- *ulpfec_payload_type = ulpfec_payload_type_;
-}
-
size_t RTPSenderVideo::CalculateFecPacketOverhead() const {
if (flexfec_enabled())
return flexfec_sender_->MaxPacketOverhead();
@@ -343,8 +421,7 @@
return absl::nullopt;
}
-bool RTPSenderVideo::SendVideo(enum VideoCodecType video_type,
- FrameType frame_type,
+bool RTPSenderVideo::SendVideo(FrameType frame_type,
int8_t payload_type,
uint32_t rtp_timestamp,
int64_t capture_time_ms,
@@ -353,6 +430,15 @@
const RTPFragmentationHeader* fragmentation,
const RTPVideoHeader* video_header,
int64_t expected_retransmission_time_ms) {
+ RTC_DCHECK(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta ||
+ frame_type == kEmptyFrame);
+
+ TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms, "Send", "type",
+ FrameTypeToString(frame_type));
+
+ if (frame_type == kEmptyFrame)
+ return true;
+
if (payload_size == 0)
return false;
RTC_CHECK(video_header);
@@ -361,6 +447,12 @@
bool red_enabled;
int32_t retransmission_settings;
bool set_video_rotation;
+ bool set_color_space = false;
+ bool set_frame_marking = video_header->codec == kVideoCodecH264 &&
+ video_header->frame_marking.temporal_id != kNoTemporalIdx;
+
+ const absl::optional<PlayoutDelay> playout_delay =
+ playout_delay_oracle_->PlayoutDelayToSend(video_header->playout_delay);
{
rtc::CritScope cs(&crit_);
// According to
@@ -380,6 +472,21 @@
video_header->rotation != kVideoRotation_0;
last_rotation_ = video_header->rotation;
+ // Send color space when changed or if the frame is a key frame. Keep
+ // sending color space information until the first base layer frame to
+ // guarantee that the information is retrieved by the receiver.
+ if (video_header->color_space != last_color_space_) {
+ last_color_space_ = video_header->color_space;
+ set_color_space = true;
+ transmit_color_space_next_frame_ = !IsBaseLayer(*video_header);
+ } else {
+ set_color_space =
+ frame_type == kVideoFrameKey || transmit_color_space_next_frame_;
+ transmit_color_space_next_frame_ = transmit_color_space_next_frame_
+ ? !IsBaseLayer(*video_header)
+ : false;
+ }
+
// FEC settings.
const FecProtectionParams& fec_params =
frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
@@ -409,13 +516,17 @@
auto middle_packet = absl::make_unique<RtpPacketToSend>(*single_packet);
auto last_packet = absl::make_unique<RtpPacketToSend>(*single_packet);
// Simplest way to estimate how much extensions would occupy is to set them.
- AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ AddRtpHeaderExtensions(*video_header, playout_delay, frame_type,
+ set_video_rotation, set_color_space, set_frame_marking,
/*first=*/true, /*last=*/true, single_packet.get());
- AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ AddRtpHeaderExtensions(*video_header, playout_delay, frame_type,
+ set_video_rotation, set_color_space, set_frame_marking,
/*first=*/true, /*last=*/false, first_packet.get());
- AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ AddRtpHeaderExtensions(*video_header, playout_delay, frame_type,
+ set_video_rotation, set_color_space, set_frame_marking,
/*first=*/false, /*last=*/false, middle_packet.get());
- AddRtpHeaderExtensions(*video_header, frame_type, set_video_rotation,
+ AddRtpHeaderExtensions(*video_header, playout_delay, frame_type,
+ set_video_rotation, set_color_space, set_frame_marking,
/*first=*/false, /*last=*/true, last_packet.get());
RTC_DCHECK_GT(packet_capacity, single_packet->headers_size());
@@ -439,8 +550,21 @@
RTPVideoHeader minimized_video_header;
const RTPVideoHeader* packetize_video_header = video_header;
+
+ rtc::ArrayView<const uint8_t> generic_descriptor_raw_00 =
+ first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension00>();
+ rtc::ArrayView<const uint8_t> generic_descriptor_raw_01 =
+ first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension01>();
+
+ if (!generic_descriptor_raw_00.empty() &&
+ !generic_descriptor_raw_01.empty()) {
+ RTC_LOG(LS_WARNING) << "Two versions of GFD extension used.";
+ return false;
+ }
+
rtc::ArrayView<const uint8_t> generic_descriptor_raw =
- first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension>();
+ !generic_descriptor_raw_01.empty() ? generic_descriptor_raw_01
+ : generic_descriptor_raw_00;
if (!generic_descriptor_raw.empty()) {
if (MinimizeDescriptor(*video_header, &minimized_video_header)) {
packetize_video_header = &minimized_video_header;
@@ -460,9 +584,15 @@
encrypted_video_payload.SetSize(max_ciphertext_size);
size_t bytes_written = 0;
+
+ // Only enable header authentication if the field trial is enabled.
+ rtc::ArrayView<const uint8_t> additional_data;
+ if (generic_descriptor_auth_experiment_) {
+ additional_data = generic_descriptor_raw;
+ }
+
if (frame_encryptor_->Encrypt(
- cricket::MEDIA_TYPE_VIDEO, first_packet->Ssrc(),
- /*additional_data=*/nullptr,
+ cricket::MEDIA_TYPE_VIDEO, first_packet->Ssrc(), additional_data,
rtc::MakeArrayView(payload_data, payload_size),
encrypted_video_payload, &bytes_written) != 0) {
return false;
@@ -477,6 +607,17 @@
<< "one is required since require_frame_encryptor is set";
}
+ VideoCodecType video_type;
+ {
+ rtc::CritScope cs(&payload_type_crit_);
+ const auto it = payload_type_map_.find(payload_type);
+ if (it == payload_type_map_.end()) {
+ RTC_LOG(LS_ERROR) << "Payload type " << static_cast<int>(payload_type)
+ << " not registered.";
+ return false;
+ }
+ video_type = it->second;
+ }
std::unique_ptr<RtpPacketizer> packetizer = RtpPacketizer::Create(
video_type, rtc::MakeArrayView(payload_data, payload_size), limits,
*packetize_video_header, frame_type, fragmentation);
@@ -486,6 +627,17 @@
expected_retransmission_time_ms);
size_t num_packets = packetizer->NumPackets();
+ size_t unpacketized_payload_size;
+ if (fragmentation && fragmentation->fragmentationVectorSize > 0) {
+ unpacketized_payload_size = 0;
+ for (uint16_t i = 0; i < fragmentation->fragmentationVectorSize; ++i) {
+ unpacketized_payload_size += fragmentation->fragmentationLength[i];
+ }
+ } else {
+ unpacketized_payload_size = payload_size;
+ }
+ size_t packetized_payload_size = 0;
+
if (num_packets == 0)
return false;
@@ -516,7 +668,12 @@
RTC_DCHECK_LE(packet->payload_size(), expected_payload_capacity);
if (!rtp_sender_->AssignSequenceNumber(packet.get()))
return false;
+ packetized_payload_size += packet->payload_size();
+ if (i == 0) {
+ playout_delay_oracle_->OnSentPacket(packet->SequenceNumber(),
+ playout_delay);
+ }
// No FEC protection for upper temporal layers, if used.
bool protect_packet = temporal_id == 0 || temporal_id == kNoTemporalIdx;
@@ -555,6 +712,12 @@
}
}
+ rtc::CritScope cs(&stats_crit_);
+ RTC_DCHECK_GE(packetized_payload_size, unpacketized_payload_size);
+ packetization_overhead_bitrate_.Update(
+ packetized_payload_size - unpacketized_payload_size,
+ clock_->TimeInMilliseconds());
+
TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms, "timestamp",
rtp_timestamp);
return true;
@@ -570,14 +733,10 @@
return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
}
-int RTPSenderVideo::SelectiveRetransmissions() const {
- rtc::CritScope cs(&crit_);
- return retransmission_settings_;
-}
-
-void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
- rtc::CritScope cs(&crit_);
- retransmission_settings_ = settings;
+uint32_t RTPSenderVideo::PacketizationOverheadBps() const {
+ rtc::CritScope cs(&stats_crit_);
+ return packetization_overhead_bitrate_.Rate(clock_->TimeInMilliseconds())
+ .value_or(0);
}
StorageType RTPSenderVideo::GetStorageType(
@@ -586,8 +745,6 @@
int64_t expected_retransmission_time_ms) {
if (retransmission_settings == kRetransmitOff)
return StorageType::kDontRetransmit;
- if (retransmission_settings == kRetransmitAllPackets)
- return StorageType::kAllowRetransmission;
rtc::CritScope cs(&stats_crit_);
// Media packet storage.
@@ -618,7 +775,12 @@
uint8_t operator()(const RTPVideoHeaderH264&) { return kNoTemporalIdx; }
uint8_t operator()(const absl::monostate&) { return kNoTemporalIdx; }
};
- return absl::visit(TemporalIdGetter(), header.video_type_header);
+ switch (header.codec) {
+ case kVideoCodecH264:
+ return header.frame_marking.temporal_id;
+ default:
+ return absl::visit(TemporalIdGetter(), header.video_type_header);
+ }
}
bool RTPSenderVideo::UpdateConditionalRetransmit(
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h
index d3a898b..9772b86 100644
--- a/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -19,12 +19,12 @@
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
#include "modules/rtp_rtcp/source/rtp_sender.h"
-#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "modules/rtp_rtcp/source/ulpfec_generator.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/onetimeevent.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/one_time_event.h"
#include "rtc_base/rate_statistics.h"
#include "rtc_base/sequenced_task_checker.h"
#include "rtc_base/thread_annotations.h"
@@ -35,6 +35,17 @@
class RtpPacketizer;
class RtpPacketToSend;
+// kConditionallyRetransmitHigherLayers allows retransmission of video frames
+// in higher layers if either the last frame in that layer was too far back in
+// time, or if we estimate that a new frame will be available in a lower layer
+// in a shorter time than it would take to request and receive a retransmission.
+enum RetransmissionMode : uint8_t {
+ kRetransmitOff = 0x0,
+ kRetransmitBaseLayer = 0x2,
+ kRetransmitHigherLayers = 0x4,
+ kConditionallyRetransmitHigherLayers = 0x8,
+};
+
class RTPSenderVideo {
public:
static constexpr int64_t kTLRateWindowSizeMs = 2500;
@@ -42,17 +53,13 @@
RTPSenderVideo(Clock* clock,
RTPSender* rtpSender,
FlexfecSender* flexfec_sender,
+ PlayoutDelayOracle* playout_delay_oracle,
FrameEncryptorInterface* frame_encryptor,
- bool require_frame_encryption);
+ bool require_frame_encryption,
+ const WebRtcKeyValueConfig& field_trials);
virtual ~RTPSenderVideo();
- virtual enum VideoCodecType VideoCodecType() const;
-
- static RtpUtility::Payload* CreateVideoPayload(absl::string_view payload_name,
- int8_t payload_type);
-
- bool SendVideo(enum VideoCodecType video_type,
- FrameType frame_type,
+ bool SendVideo(FrameType frame_type,
int8_t payload_type,
uint32_t capture_timestamp,
int64_t capture_time_ms,
@@ -62,13 +69,17 @@
const RTPVideoHeader* video_header,
int64_t expected_retransmission_time_ms);
- void SetVideoCodecType(enum VideoCodecType type);
+ void RegisterPayloadType(int8_t payload_type, absl::string_view payload_name);
- // ULPFEC.
+ // Set RED and ULPFEC payload types. A payload type of -1 means that the
+ // corresponding feature is turned off. Note that we DO NOT support enabling
+ // ULPFEC without enabling RED, and RED is only ever used when ULPFEC is
+ // enabled.
void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
- void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const;
// FlexFEC/ULPFEC.
+ // Set FEC rates, max frames before FEC is sent, and type of FEC masks.
+ // Returns false on failure.
void SetFecParameters(const FecProtectionParams& delta_params,
const FecProtectionParams& key_params);
@@ -78,8 +89,10 @@
uint32_t VideoBitrateSent() const;
uint32_t FecOverheadRate() const;
- int SelectiveRetransmissions() const;
- void SetSelectiveRetransmissions(uint8_t settings);
+ // Returns the current packetization overhead rate, in bps. Note that this is
+ // the payload overhead, eg the VP8 payload headers, not the RTP headers
+ // or extension/
+ uint32_t PacketizationOverheadBps() const;
protected:
static uint8_t GetTemporalId(const RTPVideoHeader& header);
@@ -115,6 +128,10 @@
StorageType media_packet_storage,
bool protect_media_packet);
+ bool LogAndSendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
+ StorageType storage,
+ RtpPacketSender::Priority priority);
+
bool red_enabled() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) {
return red_payload_type_ >= 0;
}
@@ -132,12 +149,23 @@
RTPSender* const rtp_sender_;
Clock* const clock_;
+ // Maps payload type to codec type, for packetization.
+ // TODO(nisse): Set on construction, to avoid lock.
+ rtc::CriticalSection payload_type_crit_;
+ std::map<int8_t, VideoCodecType> payload_type_map_
+ RTC_GUARDED_BY(payload_type_crit_);
+
// Should never be held when calling out of this class.
rtc::CriticalSection crit_;
- enum VideoCodecType video_type_;
int32_t retransmission_settings_ RTC_GUARDED_BY(crit_);
VideoRotation last_rotation_ RTC_GUARDED_BY(crit_);
+ absl::optional<ColorSpace> last_color_space_ RTC_GUARDED_BY(crit_);
+ bool transmit_color_space_next_frame_ RTC_GUARDED_BY(crit_);
+ // Tracks the current request for playout delay limits from application
+ // and decides whether the current RTP frame should include the playout
+ // delay extension on header.
+ PlayoutDelayOracle* const playout_delay_oracle_;
// RED/ULPFEC.
int red_payload_type_ RTC_GUARDED_BY(crit_);
@@ -157,6 +185,7 @@
RateStatistics fec_bitrate_ RTC_GUARDED_BY(stats_crit_);
// Bitrate used for video payload and RTP headers.
RateStatistics video_bitrate_ RTC_GUARDED_BY(stats_crit_);
+ RateStatistics packetization_overhead_bitrate_ RTC_GUARDED_BY(stats_crit_);
std::map<int, TemporalLayerStats> frame_stats_by_temporal_layer_
RTC_GUARDED_BY(stats_crit_);
@@ -169,6 +198,8 @@
// initialized frame_encryptor_ before being sent out of the network.
// Otherwise these payloads will be dropped.
bool require_frame_encryption_;
+ // Set to true if the generic descriptor should be authenticated.
+ const bool generic_descriptor_auth_experiment_;
};
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
new file mode 100644
index 0000000..fbd15c6
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
@@ -0,0 +1,644 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include "api/video/video_codec_constants.h"
+#include "api/video/video_timing.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using ::testing::ElementsAre;
+
+enum : int { // The first valid value is 1.
+ kAbsoluteSendTimeExtensionId = 1,
+ kFrameMarkingExtensionId,
+ kGenericDescriptorId00,
+ kGenericDescriptorId01,
+ kTransmissionTimeOffsetExtensionId,
+ kTransportSequenceNumberExtensionId,
+ kVideoRotationExtensionId,
+ kVideoTimingExtensionId,
+};
+
+constexpr int kPayload = 100;
+constexpr uint32_t kTimestamp = 10;
+constexpr uint16_t kSeqNum = 33;
+constexpr uint32_t kSsrc = 725242;
+constexpr int kMaxPacketLength = 1500;
+constexpr uint64_t kStartTime = 123456789;
+constexpr int64_t kDefaultExpectedRetransmissionTimeMs = 125;
+
+class LoopbackTransportTest : public webrtc::Transport {
+ public:
+ LoopbackTransportTest() {
+ receivers_extensions_.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionTimeOffsetExtensionId);
+ receivers_extensions_.Register(kRtpExtensionAbsoluteSendTime,
+ kAbsoluteSendTimeExtensionId);
+ receivers_extensions_.Register(kRtpExtensionTransportSequenceNumber,
+ kTransportSequenceNumberExtensionId);
+ receivers_extensions_.Register(kRtpExtensionVideoRotation,
+ kVideoRotationExtensionId);
+ receivers_extensions_.Register(kRtpExtensionVideoTiming,
+ kVideoTimingExtensionId);
+ receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor00,
+ kGenericDescriptorId00);
+ receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor01,
+ kGenericDescriptorId01);
+ receivers_extensions_.Register(kRtpExtensionFrameMarking,
+ kFrameMarkingExtensionId);
+ }
+
+ bool SendRtp(const uint8_t* data,
+ size_t len,
+ const PacketOptions& options) override {
+ sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_));
+ EXPECT_TRUE(sent_packets_.back().Parse(data, len));
+ return true;
+ }
+ bool SendRtcp(const uint8_t* data, size_t len) override { return false; }
+ const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); }
+ int packets_sent() { return sent_packets_.size(); }
+
+ private:
+ RtpHeaderExtensionMap receivers_extensions_;
+ std::vector<RtpPacketReceived> sent_packets_;
+};
+
+} // namespace
+
+class TestRtpSenderVideo : public RTPSenderVideo {
+ public:
+ TestRtpSenderVideo(Clock* clock,
+ RTPSender* rtp_sender,
+ FlexfecSender* flexfec_sender,
+ const WebRtcKeyValueConfig& field_trials)
+ : RTPSenderVideo(clock,
+ rtp_sender,
+ flexfec_sender,
+ &playout_delay_oracle_,
+ nullptr,
+ false,
+ field_trials) {}
+ ~TestRtpSenderVideo() override {}
+
+ StorageType GetStorageType(const RTPVideoHeader& header,
+ int32_t retransmission_settings,
+ int64_t expected_retransmission_time_ms) {
+ return RTPSenderVideo::GetStorageType(GetTemporalId(header),
+ retransmission_settings,
+ expected_retransmission_time_ms);
+ }
+ PlayoutDelayOracle playout_delay_oracle_;
+};
+
+class FieldTrials : public WebRtcKeyValueConfig {
+ public:
+ explicit FieldTrials(bool use_send_side_bwe_with_overhead)
+ : use_send_side_bwe_with_overhead_(use_send_side_bwe_with_overhead) {}
+
+ std::string Lookup(absl::string_view key) const override {
+ return key == "WebRTC-SendSideBwe-WithOverhead" &&
+ use_send_side_bwe_with_overhead_
+ ? "Enabled"
+ : "";
+ }
+
+ private:
+ bool use_send_side_bwe_with_overhead_;
+};
+
+class RtpSenderVideoTest : public ::testing::TestWithParam<bool> {
+ public:
+ RtpSenderVideoTest()
+ : field_trials_(GetParam()),
+ fake_clock_(kStartTime),
+ retransmission_rate_limiter_(&fake_clock_, 1000),
+ // TODO(pbos): Set up to use pacer.
+ rtp_sender_(false,
+ &fake_clock_,
+ &transport_,
+ nullptr,
+ absl::nullopt,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &retransmission_rate_limiter_,
+ nullptr,
+ false,
+ nullptr,
+ false,
+ false,
+ field_trials_),
+ rtp_sender_video_(&fake_clock_, &rtp_sender_, nullptr, field_trials_) {
+ rtp_sender_.SetSequenceNumber(kSeqNum);
+ rtp_sender_.SetTimestampOffset(0);
+ rtp_sender_.SetSSRC(kSsrc);
+
+ rtp_sender_video_.RegisterPayloadType(kPayload, "generic");
+ }
+
+ void PopulateGenericFrameDescriptor(int version);
+
+ void UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(
+ int version);
+
+ protected:
+ FieldTrials field_trials_;
+ SimulatedClock fake_clock_;
+ LoopbackTransportTest transport_;
+ RateLimiter retransmission_rate_limiter_;
+
+ RTPSender rtp_sender_;
+ TestRtpSenderVideo rtp_sender_video_;
+};
+
+TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) {
+ uint8_t kFrame[kMaxPacketLength];
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+ kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+ RTPVideoHeader hdr;
+ hdr.rotation = kVideoRotation_0;
+ rtp_sender_video_.SendVideo(kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
+ sizeof(kFrame), nullptr, &hdr,
+ kDefaultExpectedRetransmissionTimeMs);
+
+ VideoRotation rotation;
+ EXPECT_TRUE(
+ transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+ EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
+ uint8_t kFrame[kMaxPacketLength];
+ const int64_t kPacketizationTimeMs = 100;
+ const int64_t kEncodeStartDeltaMs = 10;
+ const int64_t kEncodeFinishDeltaMs = 50;
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(kRtpExtensionVideoTiming,
+ kVideoTimingExtensionId));
+
+ const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds();
+
+ RTPVideoHeader hdr;
+ hdr.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
+ hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs;
+ hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs;
+
+ fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs);
+ rtp_sender_video_.SendVideo(
+ kVideoFrameKey, kPayload, kTimestamp, kCaptureTimestamp, kFrame,
+ sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs);
+ VideoSendTiming timing;
+ EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
+ &timing));
+ EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms);
+ EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms);
+ EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
+ uint8_t kFrame[kMaxPacketLength];
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+ kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+ RTPVideoHeader hdr;
+ hdr.rotation = kVideoRotation_90;
+ EXPECT_TRUE(rtp_sender_video_.SendVideo(
+ kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
+ &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+ hdr.rotation = kVideoRotation_0;
+ EXPECT_TRUE(rtp_sender_video_.SendVideo(
+ kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
+ nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+ VideoRotation rotation;
+ EXPECT_TRUE(
+ transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+ EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) {
+ uint8_t kFrame[kMaxPacketLength];
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+ kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+ RTPVideoHeader hdr;
+ hdr.rotation = kVideoRotation_90;
+ EXPECT_TRUE(rtp_sender_video_.SendVideo(
+ kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
+ &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+ EXPECT_TRUE(rtp_sender_video_.SendVideo(
+ kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
+ nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+ VideoRotation rotation;
+ EXPECT_TRUE(
+ transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+ EXPECT_EQ(kVideoRotation_90, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, CheckH264FrameMarking) {
+ uint8_t kFrame[kMaxPacketLength];
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+ kRtpExtensionFrameMarking, kFrameMarkingExtensionId));
+
+ RTPFragmentationHeader frag;
+ frag.VerifyAndAllocateFragmentationHeader(1);
+ frag.fragmentationOffset[0] = 0;
+ frag.fragmentationLength[0] = sizeof(kFrame);
+
+ RTPVideoHeader hdr;
+ hdr.video_type_header.emplace<RTPVideoHeaderH264>().packetization_mode =
+ H264PacketizationMode::NonInterleaved;
+ hdr.codec = kVideoCodecH264;
+ hdr.frame_marking.temporal_id = kNoTemporalIdx;
+ hdr.frame_marking.tl0_pic_idx = 99;
+ hdr.frame_marking.base_layer_sync = true;
+ rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload,
+ kTimestamp, 0, kFrame, sizeof(kFrame), &frag,
+ &hdr, kDefaultExpectedRetransmissionTimeMs);
+
+ FrameMarking fm;
+ EXPECT_FALSE(
+ transport_.last_sent_packet().GetExtension<FrameMarkingExtension>(&fm));
+
+ hdr.frame_marking.temporal_id = 0;
+ rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload,
+ kTimestamp + 1, 0, kFrame, sizeof(kFrame), &frag,
+ &hdr, kDefaultExpectedRetransmissionTimeMs);
+
+ EXPECT_TRUE(
+ transport_.last_sent_packet().GetExtension<FrameMarkingExtension>(&fm));
+ EXPECT_EQ(hdr.frame_marking.temporal_id, fm.temporal_id);
+ EXPECT_EQ(hdr.frame_marking.tl0_pic_idx, fm.tl0_pic_idx);
+ EXPECT_EQ(hdr.frame_marking.base_layer_sync, fm.base_layer_sync);
+}
+
+// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits
+// are set in the CVO byte.
+TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
+ // Test extracting rotation when Camera (C) and Flip (F) bits are zero.
+ EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0));
+ EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1));
+ EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2));
+ EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3));
+ // Test extracting rotation when Camera (C) and Flip (F) bits are set.
+ const int flip_bit = 1 << 2;
+ const int camera_bit = 1 << 3;
+ EXPECT_EQ(kVideoRotation_0,
+ ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0));
+ EXPECT_EQ(kVideoRotation_90,
+ ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1));
+ EXPECT_EQ(kVideoRotation_180,
+ ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2));
+ EXPECT_EQ(kVideoRotation_270,
+ ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) {
+ RTPVideoHeader header;
+ header.codec = kVideoCodecGeneric;
+
+ EXPECT_EQ(kDontRetransmit,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kConditionallyRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) {
+ RTPVideoHeader header;
+ header.video_type_header.emplace<RTPVideoHeaderH264>().packetization_mode =
+ H264PacketizationMode::NonInterleaved;
+ header.codec = kVideoCodecH264;
+ header.frame_marking.temporal_id = kNoTemporalIdx;
+
+ EXPECT_EQ(kDontRetransmit,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kConditionallyRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+
+ // Test higher level retransmit.
+ for (int tid = 0; tid <= kMaxTemporalStreams; ++tid) {
+ header.frame_marking.temporal_id = tid;
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ }
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) {
+ RTPVideoHeader header;
+ header.codec = kVideoCodecVP8;
+ auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+ vp8_header.temporalIdx = 0;
+
+ EXPECT_EQ(kDontRetransmit,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kConditionallyRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(
+ kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) {
+ RTPVideoHeader header;
+ header.codec = kVideoCodecVP8;
+
+ auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+ for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+ vp8_header.temporalIdx = tid;
+
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kRetransmitOff,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ }
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) {
+ RTPVideoHeader header;
+ header.codec = kVideoCodecVP9;
+
+ auto& vp9_header = header.video_type_header.emplace<RTPVideoHeaderVP9>();
+ for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+ vp9_header.temporal_idx = tid;
+
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kRetransmitOff,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+ header, kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers,
+ kDefaultExpectedRetransmissionTimeMs));
+ EXPECT_EQ(kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+ kDefaultExpectedRetransmissionTimeMs));
+ }
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmit) {
+ const int64_t kFrameIntervalMs = 33;
+ const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+ const uint8_t kSettings =
+ kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+ // Insert VP8 frames for all temporal layers, but stop before the final index.
+ RTPVideoHeader header;
+ header.codec = kVideoCodecVP8;
+
+ // Fill averaging window to prevent rounding errors.
+ constexpr int kNumRepetitions =
+ (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+ kFrameIntervalMs;
+ constexpr int kPattern[] = {0, 2, 1, 2};
+ auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+ for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+ vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs);
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+ }
+
+ // Since we're at the start of the pattern, the next expected frame in TL0 is
+ // right now. We will wait at most one expected retransmission time before
+ // acknowledging that it did not arrive, which means this frame and the next
+ // will not be retransmitted.
+ vp8_header.temporalIdx = 1;
+ EXPECT_EQ(StorageType::kDontRetransmit,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+ EXPECT_EQ(StorageType::kDontRetransmit,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+ // The TL0 frame did not arrive. So allow retransmission.
+ EXPECT_EQ(StorageType::kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+ // Insert a frame for TL2. We just had frame in TL1, so the next one there is
+ // in three frames away. TL0 is still too far in the past. So, allow
+ // retransmission.
+ vp8_header.temporalIdx = 2;
+ EXPECT_EQ(StorageType::kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+ // Another TL2, next in TL1 is two frames away. Allow again.
+ EXPECT_EQ(StorageType::kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+ // Yet another TL2, next in TL1 is now only one frame away, so don't store
+ // for retransmission.
+ EXPECT_EQ(StorageType::kDontRetransmit,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
+ const int64_t kFrameIntervalMs = 200;
+ const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+ const int32_t kSettings =
+ kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+ // Insert VP8 frames for all temporal layers, but stop before the final index.
+ RTPVideoHeader header;
+ header.codec = kVideoCodecVP8;
+
+ // Fill averaging window to prevent rounding errors.
+ constexpr int kNumRepetitions =
+ (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+ kFrameIntervalMs;
+ constexpr int kPattern[] = {0, 2, 2, 2};
+ auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+ for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+ vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
+
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs);
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+ }
+
+ // Since we're at the start of the pattern, the next expected frame will be
+ // right now in TL0. Put it in TL1 instead. Regular rules would dictate that
+ // we don't store for retransmission because we expect a frame in a lower
+ // layer, but that last frame in TL1 was a long time ago in absolute terms,
+ // so allow retransmission anyway.
+ vp8_header.temporalIdx = 1;
+ EXPECT_EQ(StorageType::kAllowRetransmission,
+ rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+}
+
+void RtpSenderVideoTest::PopulateGenericFrameDescriptor(int version) {
+ const RTPExtensionType ext_type =
+ (version == 0) ? RTPExtensionType::kRtpExtensionGenericFrameDescriptor00
+ : RTPExtensionType::kRtpExtensionGenericFrameDescriptor01;
+ const int ext_id =
+ (version == 0) ? kGenericDescriptorId00 : kGenericDescriptorId01;
+
+ const int64_t kFrameId = 100000;
+ uint8_t kFrame[100];
+ EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(ext_type, ext_id));
+
+ RTPVideoHeader hdr;
+ RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
+ generic.frame_id = kFrameId;
+ generic.temporal_index = 3;
+ generic.spatial_index = 2;
+ generic.higher_spatial_layers.push_back(4);
+ generic.dependencies.push_back(kFrameId - 1);
+ generic.dependencies.push_back(kFrameId - 500);
+ rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0, kFrame,
+ sizeof(kFrame), nullptr, &hdr,
+ kDefaultExpectedRetransmissionTimeMs);
+
+ RtpGenericFrameDescriptor descriptor_wire;
+ EXPECT_EQ(1, transport_.packets_sent());
+ if (version == 0) {
+ ASSERT_TRUE(transport_.last_sent_packet()
+ .GetExtension<RtpGenericFrameDescriptorExtension00>(
+ &descriptor_wire));
+ } else {
+ ASSERT_TRUE(transport_.last_sent_packet()
+ .GetExtension<RtpGenericFrameDescriptorExtension01>(
+ &descriptor_wire));
+ }
+ EXPECT_EQ(static_cast<uint16_t>(generic.frame_id), descriptor_wire.FrameId());
+ EXPECT_EQ(generic.temporal_index, descriptor_wire.TemporalLayer());
+ EXPECT_THAT(descriptor_wire.FrameDependenciesDiffs(), ElementsAre(1, 500));
+ uint8_t spatial_bitmask = 0x14;
+ EXPECT_EQ(spatial_bitmask, descriptor_wire.SpatialLayersBitmask());
+}
+
+TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor00) {
+ PopulateGenericFrameDescriptor(0);
+}
+
+TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor01) {
+ PopulateGenericFrameDescriptor(1);
+}
+
+void RtpSenderVideoTest::
+ UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(
+ int version) {
+ const int64_t kFrameId = 100000;
+ const size_t kFrameSize = 100;
+ uint8_t kFrame[kFrameSize];
+
+ if (version == 0) {
+ ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
+ RtpGenericFrameDescriptorExtension00::kUri, kGenericDescriptorId00));
+ } else {
+ ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
+ RtpGenericFrameDescriptorExtension01::kUri, kGenericDescriptorId01));
+ }
+
+ RTPVideoHeader hdr;
+ hdr.codec = kVideoCodecVP8;
+ RTPVideoHeaderVP8& vp8 = hdr.video_type_header.emplace<RTPVideoHeaderVP8>();
+ vp8.pictureId = kFrameId % 0X7FFF;
+ vp8.tl0PicIdx = 13;
+ vp8.temporalIdx = 1;
+ vp8.keyIdx = 2;
+ RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
+ generic.frame_id = kFrameId;
+ rtp_sender_video_.RegisterPayloadType(kPayload, "vp8");
+ rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0, kFrame,
+ sizeof(kFrame), nullptr, &hdr,
+ kDefaultExpectedRetransmissionTimeMs);
+
+ ASSERT_EQ(transport_.packets_sent(), 1);
+ // Expect only minimal 1-byte vp8 descriptor was generated.
+ EXPECT_EQ(transport_.last_sent_packet().payload_size(), 1 + kFrameSize);
+}
+
+TEST_P(RtpSenderVideoTest,
+ UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed00) {
+ UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(0);
+}
+
+TEST_P(RtpSenderVideoTest,
+ UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed01) {
+ UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(1);
+}
+
+INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
+ RtpSenderVideoTest,
+ ::testing::Bool());
+
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
index 44c671f..8811bf1 100644
--- a/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -24,7 +24,6 @@
#include "modules/video_coding/codecs/interface/common_constants.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/stringutils.h"
namespace webrtc {
@@ -434,6 +433,10 @@
header->extension.hasTransportSequenceNumber = true;
break;
}
+ case kRtpExtensionTransportSequenceNumber02:
+ RTC_LOG(WARNING) << "TransportSequenceNumberV2 unsupported by rtp "
+ "header parser.";
+ break;
case kRtpExtensionPlayoutDelay: {
if (len != 2) {
RTC_LOG(LS_WARNING) << "Incorrect playout delay len: " << len;
@@ -503,7 +506,8 @@
header->extension.mid.Set(rtc::MakeArrayView(ptr, len + 1));
break;
}
- case kRtpExtensionGenericFrameDescriptor:
+ case kRtpExtensionGenericFrameDescriptor00:
+ case kRtpExtensionGenericFrameDescriptor01:
RTC_LOG(WARNING)
<< "RtpGenericFrameDescriptor unsupported by rtp header parser.";
break;
diff --git a/modules/rtp_rtcp/source/rtp_utility.h b/modules/rtp_rtcp/source/rtp_utility.h
index 4085174..bbfb886 100644
--- a/modules/rtp_rtcp/source/rtp_utility.h
+++ b/modules/rtp_rtcp/source/rtp_utility.h
@@ -26,16 +26,6 @@
namespace RtpUtility {
-struct Payload {
- Payload(absl::string_view payload_name, const PayloadUnion& pu)
- : typeSpecific(pu) {
- size_t clipped_size = payload_name.copy(name, sizeof(name) - 1);
- name[clipped_size] = '\0';
- }
- char name[RTP_PAYLOAD_NAME_SIZE];
- PayloadUnion typeSpecific;
-};
-
// Round up to the nearest size that is a multiple of 4.
size_t Word32Align(size_t size);
diff --git a/modules/rtp_rtcp/source/rtp_video_header.h b/modules/rtp_rtcp/source/rtp_video_header.h
index 1c75f53..417c38c 100644
--- a/modules/rtp_rtcp/source/rtp_video_header.h
+++ b/modules/rtp_rtcp/source/rtp_video_header.h
@@ -15,6 +15,7 @@
#include "absl/container/inlined_vector.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
+#include "api/video/color_space.h"
#include "api/video/video_codec_type.h"
#include "api/video/video_content_type.h"
#include "api/video/video_frame_marking.h"
@@ -42,6 +43,7 @@
int temporal_index = 0;
absl::InlinedVector<int64_t, 5> dependencies;
absl::InlinedVector<int, 5> higher_spatial_layers;
+ bool discardable = false;
};
RTPVideoHeader();
@@ -62,7 +64,8 @@
PlayoutDelay playout_delay = {-1, -1};
VideoSendTiming video_timing;
- FrameMarking frame_marking;
+ FrameMarking frame_marking = {false, false, false, false, false, 0xFF, 0, 0};
+ absl::optional<ColorSpace> color_space;
RTPVideoTypeHeader video_type_header;
};
diff --git a/modules/rtp_rtcp/source/time_util.cc b/modules/rtp_rtcp/source/time_util.cc
index e65329d..806f9a9 100644
--- a/modules/rtp_rtcp/source/time_util.cc
+++ b/modules/rtp_rtcp/source/time_util.cc
@@ -13,7 +13,7 @@
#include <algorithm>
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
diff --git a/modules/rtp_rtcp/source/time_util_unittest.cc b/modules/rtp_rtcp/source/time_util_unittest.cc
index 0ff4f7b..f4315e5 100644
--- a/modules/rtp_rtcp/source/time_util_unittest.cc
+++ b/modules/rtp_rtcp/source/time_util_unittest.cc
@@ -9,8 +9,8 @@
*/
#include "modules/rtp_rtcp/source/time_util.h"
-#include "rtc_base/fakeclock.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/clock.h"
#include "test/gtest.h"
diff --git a/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc
index 22af7e7..7086b13 100644
--- a/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc
+++ b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc
@@ -12,10 +12,10 @@
#include <string.h>
+#include "api/scoped_refptr.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "rtc_base/checks.h"
-#include "rtc_base/scoped_ref_ptr.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc
index a1d1bd5..2ad1239 100644
--- a/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc
+++ b/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc
@@ -13,13 +13,13 @@
#include <memory>
#include <utility>
+#include "api/scoped_refptr.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/forward_error_correction.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
#include "rtc_base/checks.h"
#include "rtc_base/random.h"
-#include "rtc_base/scoped_ref_ptr.h"
#include "test/gtest.h"
namespace webrtc {
diff --git a/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc b/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc
index 7da6b88..614d4aa 100644
--- a/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc
+++ b/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc
@@ -14,10 +14,10 @@
#include <memory>
#include <utility>
+#include "api/scoped_refptr.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "rtc_base/logging.h"
-#include "rtc_base/scoped_ref_ptr.h"
-#include "system_wrappers/include/clock.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
@@ -141,8 +141,7 @@
}
++packet_counter_.num_packets;
if (packet_counter_.first_packet_time_ms == -1) {
- packet_counter_.first_packet_time_ms =
- Clock::GetRealTimeClock()->TimeInMilliseconds();
+ packet_counter_.first_packet_time_ms = rtc::TimeMillis();
}
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
diff --git a/modules/rtp_rtcp/source/ulpfec_receiver_impl.h b/modules/rtp_rtcp/source/ulpfec_receiver_impl.h
index 0943266..2821513 100644
--- a/modules/rtp_rtcp/source/ulpfec_receiver_impl.h
+++ b/modules/rtp_rtcp/source/ulpfec_receiver_impl.h
@@ -20,7 +20,7 @@
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
#include "modules/rtp_rtcp/source/forward_error_correction.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
diff --git a/modules/video_coding/codecs/h264/include/h264_globals.h b/modules/video_coding/codecs/h264/include/h264_globals.h
index e321500..321a6b7 100644
--- a/modules/video_coding/codecs/h264/include/h264_globals.h
+++ b/modules/video_coding/codecs/h264/include/h264_globals.h
@@ -15,6 +15,8 @@
#define MODULES_VIDEO_CODING_CODECS_H264_INCLUDE_H264_GLOBALS_H_
#include <string>
+#include "modules/video_coding/codecs/interface/common_constants.h"
+
#include "rtc_base/checks.h"
diff --git a/modules/video_coding/codecs/interface/common_constants.h b/modules/video_coding/codecs/interface/common_constants.h
index 2fdcb90..a8fc629 100644
--- a/modules/video_coding/codecs/interface/common_constants.h
+++ b/modules/video_coding/codecs/interface/common_constants.h
@@ -14,6 +14,8 @@
#ifndef MODULES_VIDEO_CODING_CODECS_INTERFACE_COMMON_CONSTANTS_H_
#define MODULES_VIDEO_CODING_CODECS_INTERFACE_COMMON_CONSTANTS_H_
+#include <stdint.h>
+
namespace webrtc {
const int16_t kNoPictureId = -1;
diff --git a/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h b/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h
index ae14f68..3d1671a 100644
--- a/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h
+++ b/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h
@@ -15,6 +15,7 @@
#include <memory>
+#include "api/video_codecs/vp8_frame_config.h"
#include "api/video_codecs/vp8_temporal_layers.h"
namespace webrtc {
@@ -27,9 +28,8 @@
explicit TemporalLayersChecker(int num_temporal_layers);
virtual ~TemporalLayersChecker() {}
- virtual bool CheckTemporalConfig(
- bool frame_is_keyframe,
- const Vp8TemporalLayers::FrameConfig& frame_config);
+ virtual bool CheckTemporalConfig(bool frame_is_keyframe,
+ const Vp8FrameConfig& frame_config);
static std::unique_ptr<TemporalLayersChecker> CreateTemporalLayersChecker(
Vp8TemporalLayersType type,
@@ -46,7 +46,7 @@
bool* need_sync,
bool frame_is_keyframe,
uint8_t temporal_layer,
- webrtc::Vp8TemporalLayers::BufferFlags flags,
+ Vp8FrameConfig::BufferFlags flags,
uint32_t sequence_number,
uint32_t* lowest_sequence_referenced);
BufferState last_;
diff --git a/modules/video_coding/codecs/vp9/include/vp9_globals.h b/modules/video_coding/codecs/vp9/include/vp9_globals.h
index aa532a6..895e2de 100644
--- a/modules/video_coding/codecs/vp9/include/vp9_globals.h
+++ b/modules/video_coding/codecs/vp9/include/vp9_globals.h
@@ -15,6 +15,7 @@
#define MODULES_VIDEO_CODING_CODECS_VP9_INCLUDE_VP9_GLOBALS_H_
#include <assert.h>
+#include <stdint.h>
#include "modules/video_coding/codecs/interface/common_constants.h"
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index c88815f..a79e690 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -79,33 +79,32 @@
":safe_minmax",
":type_traits",
"../api:array_view",
+ "../api:scoped_refptr",
"../system_wrappers:field_trial",
"experiments:field_trial_parser",
"system:arch",
"system:unused",
"third_party/base64",
- "//third_party/abseil-cpp/absl/memory:memory",
+ "//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
]
sources = [
"bind.h",
- "bitbuffer.cc",
- "bitbuffer.h",
- "bitrateallocationstrategy.cc",
- "bitrateallocationstrategy.h",
+ "bit_buffer.cc",
+ "bit_buffer.h",
+ "bitrate_allocation_strategy.cc",
+ "bitrate_allocation_strategy.h",
"buffer.h",
- "bufferqueue.cc",
- "bufferqueue.h",
- "bytebuffer.cc",
- "bytebuffer.h",
- "byteorder.h",
- "copyonwritebuffer.cc",
- "copyonwritebuffer.h",
+ "buffer_queue.cc",
+ "buffer_queue.h",
+ "byte_buffer.cc",
+ "byte_buffer.h",
+ "byte_order.h",
+ "copy_on_write_buffer.cc",
+ "copy_on_write_buffer.h",
"event_tracer.cc",
"event_tracer.h",
- "file.cc",
- "file.h",
"flags.cc",
"flags.h",
"function_view.h",
@@ -119,7 +118,7 @@
"numerics/moving_max_counter.h",
"numerics/sample_counter.cc",
"numerics/sample_counter.h",
- "onetimeevent.h",
+ "one_time_event.h",
"platform_file.cc",
"platform_file.h",
"race_checker.cc",
@@ -128,24 +127,19 @@
"random.h",
"rate_statistics.cc",
"rate_statistics.h",
- "ratetracker.cc",
- "ratetracker.h",
+ "rate_tracker.cc",
+ "rate_tracker.h",
"swap_queue.h",
"template_util.h",
- "timestampaligner.cc",
- "timestampaligner.h",
+ "timestamp_aligner.cc",
+ "timestamp_aligner.h",
"trace_event.h",
"zero_memory.cc",
"zero_memory.h",
]
- if (is_posix || is_fuchsia) {
- sources += [ "file_posix.cc" ]
- }
-
if (is_win) {
sources += [
- "file_win.cc",
"win/windows_version.cc",
"win/windows_version.h",
]
@@ -169,7 +163,6 @@
":macromagic",
":platform_thread",
":platform_thread_types",
- ":ptr_util",
":refcount",
":rtc_event",
":safe_conversions",
@@ -184,7 +177,7 @@
visibility = [ "*" ]
sources = [
"arraysize.h",
- "constructormagic.h",
+ "constructor_magic.h",
"format_macros.h",
"stringize_macros.h",
"thread_annotations.h",
@@ -201,22 +194,12 @@
]
}
-rtc_source_set("ptr_util") {
- visibility = [ "*" ]
- sources = [
- "scoped_ref_ptr.h",
- ]
- deps = [
- "../api:scoped_refptr",
- ]
-}
-
rtc_source_set("refcount") {
visibility = [ "*" ]
sources = [
- "refcount.h",
- "refcountedobject.h",
- "refcounter.h",
+ "ref_count.h",
+ "ref_counted_object.h",
+ "ref_counter.h",
]
deps = [
":atomicops",
@@ -226,8 +209,8 @@
rtc_source_set("criticalsection") {
sources = [
- "criticalsection.cc",
- "criticalsection.h",
+ "critical_section.cc",
+ "critical_section.h",
]
deps = [
":atomicops",
@@ -258,6 +241,7 @@
":rtc_event",
":thread_checker",
":timeutils",
+ "//third_party/abseil-cpp/absl/strings",
]
}
@@ -342,7 +326,7 @@
rtc_source_set("atomicops") {
sources = [
- "atomicops.h",
+ "atomic_ops.h",
]
}
@@ -417,8 +401,8 @@
rtc_source_set("timeutils") {
visibility = [ "*" ]
sources = [
- "timeutils.cc",
- "timeutils.h",
+ "time_utils.cc",
+ "time_utils.h",
]
deps = [
":checks",
@@ -429,14 +413,14 @@
rtc_source_set("stringutils") {
sources = [
+ "string_encode.cc",
+ "string_encode.h",
"string_to_number.cc",
"string_to_number.h",
- "stringencode.cc",
- "stringencode.h",
+ "string_utils.cc",
+ "string_utils.h",
"strings/string_builder.cc",
"strings/string_builder.h",
- "stringutils.cc",
- "stringutils.h",
]
deps = [
":checks",
@@ -484,69 +468,36 @@
rtc_source_set("rtc_task_queue") {
visibility = [ "*" ]
- deps = []
- public_deps = [
- ":rtc_task_queue_api",
- ]
-
- if (rtc_link_task_queue_impl) {
- deps += [ ":rtc_task_queue_impl" ]
- }
-}
-
-# WebRTC targets must not directly depend on rtc_task_queue_api or
-# rtc_task_queue_impl. Instead, depend on rtc_task_queue.
-# The build flag |rtc_link_task_queue_impl| decides if WebRTC targets will link
-# to the default implemenation in rtc_task_queue_impl or if an externally
-# provided implementation should be used. An external implementation should
-# depend on rtc_task_queue_api.
-rtc_source_set("rtc_task_queue_api") {
- # The visibility list is commented out so that we won't break external
- # implementations, but left here to manually test as well as for sake of what
- # targets we expect to depend on rtc_task_queue_api.
- # visibility = [
- # ":rtc_task_queue",
- # ":rtc_task_queue_impl",
- # ":sequenced_task_checker",
- # ]
sources = [
+ "task_queue.cc",
"task_queue.h",
]
deps = [
":macromagic",
- ":ptr_util",
+ "../api/task_queue",
+ "../api/task_queue:global_task_queue_factory",
"system:rtc_export",
+ "task_utils:to_queued_task",
"//third_party/abseil-cpp/absl/memory",
]
+
+ # TODO(danilchap): Move this conditional dependency to global_task_queue_factory
+ # after removing task_queue_impl -> global_task_queue_factory dependency in chromium.
+ if (build_with_chromium) {
+ deps += [ "../../webrtc_overrides:task_queue_impl" ]
+ }
}
-rtc_source_set("rtc_cancelable_task") {
- sources = [
- "cancelable_periodic_task.h",
- "cancelable_task_handle.cc",
- "cancelable_task_handle.h",
- ]
- deps = [
- ":checks",
- ":logging",
- ":macromagic",
- ":ptr_util",
- ":refcount",
- ":rtc_task_queue",
- ":safe_conversions",
- ":sequenced_task_checker",
- ":thread_checker",
- "//third_party/abseil-cpp/absl/memory",
- ]
+rtc_source_set("rtc_task_queue_api") {
+ visibility = [ "*" ]
}
if (rtc_enable_libevent) {
rtc_source_set("rtc_task_queue_libevent") {
- visibility = [ ":rtc_task_queue_impl" ]
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
sources = [
"task_queue_libevent.cc",
- "task_queue_posix.cc",
- "task_queue_posix.h",
+ "task_queue_libevent.h",
]
deps = [
":checks",
@@ -555,12 +506,11 @@
":macromagic",
":platform_thread",
":platform_thread_types",
- ":ptr_util",
- ":refcount",
- ":rtc_task_queue_api",
":safe_conversions",
":timeutils",
- "system:unused",
+ "../api/task_queue",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
]
if (rtc_build_libevent) {
deps += [ "//base/third_party/libevent" ]
@@ -570,27 +520,27 @@
if (is_mac || is_ios) {
rtc_source_set("rtc_task_queue_gcd") {
- visibility = [ ":rtc_task_queue_impl" ]
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
sources = [
"task_queue_gcd.cc",
- "task_queue_posix.cc",
- "task_queue_posix.h",
+ "task_queue_gcd.h",
]
deps = [
":checks",
":logging",
- ":ptr_util",
- ":refcount",
- ":rtc_task_queue_api",
+ "../api/task_queue",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
]
}
}
if (is_win) {
rtc_source_set("rtc_task_queue_win") {
- visibility = [ ":rtc_task_queue_impl" ]
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
sources = [
"task_queue_win.cc",
+ "task_queue_win.h",
]
deps = [
":checks",
@@ -598,20 +548,21 @@
":logging",
":macromagic",
":platform_thread",
- ":ptr_util",
- ":refcount",
":rtc_event",
- ":rtc_task_queue_api",
":safe_conversions",
":timeutils",
+ "../api/task_queue",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
]
}
}
rtc_source_set("rtc_task_queue_stdlib") {
- visibility = [ ":rtc_task_queue_impl" ]
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
sources = [
"task_queue_stdlib.cc",
+ "task_queue_stdlib.h",
]
deps = [
":checks",
@@ -619,41 +570,15 @@
":logging",
":macromagic",
":platform_thread",
- ":ptr_util",
- ":refcount",
":rtc_event",
- ":rtc_task_queue_api",
":safe_conversions",
":timeutils",
+ "../api/task_queue",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
]
}
-rtc_source_set("rtc_task_queue_impl") {
- visibility = [ "*" ]
- if (rtc_enable_libevent) {
- deps = [
- ":rtc_task_queue_libevent",
- ]
- } else {
- if (is_mac || is_ios) {
- deps = [
- ":rtc_task_queue_gcd",
- ]
- }
- if (is_win) {
- if (current_os == "winuwp") {
- deps = [
- ":rtc_task_queue_stdlib",
- ]
- } else {
- deps = [
- ":rtc_task_queue_win",
- ]
- }
- }
- }
-}
-
rtc_source_set("sequenced_task_checker") {
sources = [
"sequenced_task_checker.h",
@@ -664,8 +589,8 @@
":checks",
":criticalsection",
":macromagic",
- ":rtc_task_queue",
":thread_checker",
+ "../api/task_queue",
]
}
@@ -675,9 +600,9 @@
"weak_ptr.h",
]
deps = [
- ":ptr_util",
":refcount",
":sequenced_task_checker",
+ "../api:scoped_refptr",
]
}
@@ -689,6 +614,8 @@
"numerics/moving_average.h",
"numerics/moving_median_filter.h",
"numerics/percentile_filter.h",
+ "numerics/samples_stats_counter.cc",
+ "numerics/samples_stats_counter.h",
"numerics/sequence_number_util.h",
]
deps = [
@@ -722,6 +649,142 @@
}
}
+rtc_source_set("net_helpers") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "net_helpers.cc",
+ # "net_helpers.h",
+ # ]
+}
+
+rtc_source_set("async_resolver_interface") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "async_resolver_interface.cc",
+ # "async_resolver_interface.h",
+ # ]
+}
+
+rtc_source_set("ip_address") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "ip_address.cc",
+ # "ip_address.h",
+ # ]
+}
+
+rtc_source_set("socket_address") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_address.cc",
+ # "socket_address.h",
+ # ]
+}
+
+rtc_source_set("null_socket_server") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "null_socket_server.cc",
+ # "null_socket_server.h",
+ # ]
+}
+
+rtc_source_set("socket_server") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_server.h",
+ # ]
+}
+
+rtc_source_set("threading") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "asyncresolver.cc",
+ # "asyncresolver.h",
+ # "defaultsocketserver.cc",
+ # "defaultsocketserver.h",
+ # "message_handler.cc",
+ # "message_handler.h",
+ # "message_queue.cc",
+ # "message_queue.h",
+ # "network_monitor.cc",
+ # "network_monitor.h",
+ # "physical_socket_server.cc",
+ # "physical_socket_server.h",
+ # "signal_thread.cc",
+ # "signal_thread.h",
+ # "thread.cc",
+ # "thread.h",
+ # ]
+}
+
+rtc_source_set("socket_factory") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_factory.h",
+ # ]
+}
+
+rtc_source_set("async_socket") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "async_socket.cc",
+ # "async_socket.h",
+ # ]
+}
+
+rtc_source_set("socket") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket.cc",
+ # "socket.h",
+ # ]
+}
+
+rtc_source_set("network_constants") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "network_constants.h",
+ # ]
+}
+
+if (is_android) {
+ rtc_source_set("ifaddrs_android") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "ifaddrs_android.cc",
+ # "ifaddrs_android.h",
+ # ]
+ }
+}
+
+if (is_win) {
+ rtc_source_set("win32") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "win32.cc",
+ # "win32.h",
+ # ]
+ }
+}
+
rtc_static_library("rtc_base") {
visibility = [ "*" ]
cflags = []
@@ -730,13 +793,13 @@
defines = []
deps = [
":checks",
-
- # For deprecation of rtc::PacketTime, in asyncpacketsocket.h.
- ":deprecation",
":stringutils",
"..:webrtc_common",
"../api:array_view",
+ "../api:scoped_refptr",
+ "../system_wrappers:field_trial",
"network:sent_packet",
+ "system:file_wrapper",
"third_party/base64",
"third_party/sigslot",
"//third_party/abseil-cpp/absl/memory",
@@ -751,109 +814,111 @@
all_dependent_configs = [ ":rtc_base_all_dependent_config" ]
sources = [
- "asyncinvoker-inl.h",
- "asyncinvoker.cc",
- "asyncinvoker.h",
- "asyncpacketsocket.cc",
- "asyncpacketsocket.h",
- "asyncresolverinterface.cc",
- "asyncresolverinterface.h",
- "asyncsocket.cc",
- "asyncsocket.h",
- "asynctcpsocket.cc",
- "asynctcpsocket.h",
- "asyncudpsocket.cc",
- "asyncudpsocket.h",
+ "async_invoker.cc",
+ "async_invoker.h",
+ "async_invoker_inl.h",
+ "async_packet_socket.cc",
+ "async_packet_socket.h",
+ "async_resolver_interface.cc",
+ "async_resolver_interface.h",
+ "async_socket.cc",
+ "async_socket.h",
+ "async_tcp_socket.cc",
+ "async_tcp_socket.h",
+ "async_udp_socket.cc",
+ "async_udp_socket.h",
"crc32.cc",
"crc32.h",
- "cryptstring.cc",
- "cryptstring.h",
+ "crypt_string.cc",
+ "crypt_string.h",
"data_rate_limiter.cc",
"data_rate_limiter.h",
"dscp.h",
- "filerotatingstream.cc",
- "filerotatingstream.h",
+ "file_rotating_stream.cc",
+ "file_rotating_stream.h",
"gunit_prod.h",
"helpers.cc",
"helpers.h",
- "httpcommon.cc",
- "httpcommon.h",
- "ipaddress.cc",
- "ipaddress.h",
+ "http_common.cc",
+ "http_common.h",
+ "ip_address.cc",
+ "ip_address.h",
"keep_ref_until_done.h",
"key_derivation.cc",
"key_derivation.h",
"mdns_responder_interface.h",
- "messagedigest.cc",
- "messagedigest.h",
- "messagehandler.cc",
- "messagehandler.h",
- "messagequeue.cc",
- "messagequeue.h",
- "nethelper.cc",
- "nethelper.h",
- "nethelpers.cc",
- "nethelpers.h",
+ "message_digest.cc",
+ "message_digest.h",
+ "message_handler.cc",
+ "message_handler.h",
+ "message_queue.cc",
+ "message_queue.h",
+ "net_helper.cc",
+ "net_helper.h",
+ "net_helpers.cc",
+ "net_helpers.h",
"network.cc",
"network.h",
"network_constants.h",
- "networkmonitor.cc",
- "networkmonitor.h",
- "networkroute.h",
- "nullsocketserver.cc",
- "nullsocketserver.h",
+ "network_monitor.cc",
+ "network_monitor.h",
+ "network_route.h",
+ "null_socket_server.cc",
+ "null_socket_server.h",
"openssl.h",
+ "openssl_adapter.cc",
+ "openssl_adapter.h",
+ "openssl_certificate.cc",
+ "openssl_certificate.h",
+ "openssl_digest.cc",
+ "openssl_digest.h",
+ "openssl_identity.cc",
+ "openssl_identity.h",
"openssl_key_derivation_hkdf.cc",
"openssl_key_derivation_hkdf.h",
- "openssladapter.cc",
- "openssladapter.h",
- "opensslcertificate.cc",
- "opensslcertificate.h",
- "openssldigest.cc",
- "openssldigest.h",
- "opensslidentity.cc",
- "opensslidentity.h",
- "opensslsessioncache.cc",
- "opensslsessioncache.h",
- "opensslstreamadapter.cc",
- "opensslstreamadapter.h",
- "opensslutility.cc",
- "opensslutility.h",
- "physicalsocketserver.cc",
- "physicalsocketserver.h",
- "proxyinfo.cc",
- "proxyinfo.h",
- "rtccertificate.cc",
- "rtccertificate.h",
- "rtccertificategenerator.cc",
- "rtccertificategenerator.h",
- "signalthread.cc",
- "signalthread.h",
- "sigslotrepeater.h",
+ "openssl_session_cache.cc",
+ "openssl_session_cache.h",
+ "openssl_stream_adapter.cc",
+ "openssl_stream_adapter.h",
+ "openssl_utility.cc",
+ "openssl_utility.h",
+ "physical_socket_server.cc",
+ "physical_socket_server.h",
+ "proxy_info.cc",
+ "proxy_info.h",
+ "rtc_certificate.cc",
+ "rtc_certificate.h",
+ "rtc_certificate_generator.cc",
+ "rtc_certificate_generator.h",
+ "signal_thread.cc",
+ "signal_thread.h",
+ "sigslot_repeater.h",
"socket.cc",
"socket.h",
- "socketadapters.cc",
- "socketadapters.h",
- "socketaddress.cc",
- "socketaddress.h",
- "socketaddresspair.cc",
- "socketaddresspair.h",
- "socketfactory.h",
- "socketserver.h",
- "ssladapter.cc",
- "ssladapter.h",
- "sslcertificate.cc",
- "sslcertificate.h",
- "sslfingerprint.cc",
- "sslfingerprint.h",
- "sslidentity.cc",
- "sslidentity.h",
- "sslstreamadapter.cc",
- "sslstreamadapter.h",
+ "socket_adapters.cc",
+ "socket_adapters.h",
+ "socket_address.cc",
+ "socket_address.h",
+ "socket_address_pair.cc",
+ "socket_address_pair.h",
+ "socket_factory.h",
+ "socket_server.h",
+ "ssl_adapter.cc",
+ "ssl_adapter.h",
+ "ssl_certificate.cc",
+ "ssl_certificate.h",
+ "ssl_fingerprint.cc",
+ "ssl_fingerprint.h",
+ "ssl_identity.cc",
+ "ssl_identity.h",
+ "ssl_stream_adapter.cc",
+ "ssl_stream_adapter.h",
"stream.cc",
"stream.h",
"thread.cc",
"thread.h",
+ "unique_id_generator.cc",
+ "unique_id_generator.h",
]
if (build_with_chromium) {
@@ -862,19 +927,19 @@
} else {
sources += [
"callback.h",
- "logsinks.cc",
- "logsinks.h",
- "numerics/mathutils.h",
- "rollingaccumulator.h",
- "sslroots.h",
+ "log_sinks.cc",
+ "log_sinks.h",
+ "numerics/math_utils.h",
+ "rolling_accumulator.h",
+ "ssl_roots.h",
]
if (is_win) {
- sources += [ "win32socketinit.h" ]
+ sources += [ "win32_socket_init.h" ]
if (current_os != "winuwp") {
sources += [
- "win32socketserver.cc",
- "win32socketserver.h",
+ "win32_socket_server.cc",
+ "win32_socket_server.h",
]
}
}
@@ -888,8 +953,8 @@
if (is_android) {
sources += [
- "ifaddrs-android.cc",
- "ifaddrs-android.h",
+ "ifaddrs_android.cc",
+ "ifaddrs_android.h",
]
libs += [
@@ -899,7 +964,7 @@
}
if (is_ios || is_mac) {
- sources += [ "macifaddrs_converter.cc" ]
+ sources += [ "mac_ifaddrs_converter.cc" ]
deps += [ "system:cocoa_threading" ]
}
@@ -923,8 +988,8 @@
if (is_mac) {
sources += [
- "macutils.cc",
- "macutils.h",
+ "mac_utils.cc",
+ "mac_utils.h",
]
}
@@ -932,8 +997,8 @@
sources += [
"win32.cc",
"win32.h",
- "win32window.cc",
- "win32window.h",
+ "win32_window.cc",
+ "win32_window.h",
]
libs += [
@@ -978,14 +1043,15 @@
":rtc_base_tests_utils",
":stringutils",
"../test:test_support",
+ "//third_party/abseil-cpp/absl/strings",
]
}
rtc_source_set("testclient") {
testonly = true
sources = [
- "testclient.cc",
- "testclient.h",
+ "test_client.cc",
+ "test_client.h",
]
deps = [
":criticalsection",
@@ -994,7 +1060,7 @@
":rtc_base",
":rtc_base_tests_utils",
":timeutils",
- "//third_party/abseil-cpp/absl/memory:memory",
+ "//third_party/abseil-cpp/absl/memory",
]
}
@@ -1003,38 +1069,40 @@
sources = [
"cpu_time.cc",
"cpu_time.h",
+ "fake_clock.cc",
+ "fake_clock.h",
"fake_mdns_responder.h",
- "fakeclock.cc",
- "fakeclock.h",
- "fakenetwork.h",
- "fakesslidentity.cc",
- "fakesslidentity.h",
- "firewallsocketserver.cc",
- "firewallsocketserver.h",
+ "fake_network.h",
+ "fake_ssl_identity.cc",
+ "fake_ssl_identity.h",
+ "firewall_socket_server.cc",
+ "firewall_socket_server.h",
"memory_stream.cc",
"memory_stream.h",
"memory_usage.cc",
"memory_usage.h",
- "natserver.cc",
- "natserver.h",
- "natsocketfactory.cc",
- "natsocketfactory.h",
- "nattypes.cc",
- "nattypes.h",
- "proxyserver.cc",
- "proxyserver.h",
- "sigslottester.h",
+ "nat_server.cc",
+ "nat_server.h",
+ "nat_socket_factory.cc",
+ "nat_socket_factory.h",
+ "nat_types.cc",
+ "nat_types.h",
+ "proxy_server.cc",
+ "proxy_server.h",
+ "server_socket_adapters.cc",
+ "server_socket_adapters.h",
+ "sigslot_tester.h",
"sigslottester.h.pump",
- "socketstream.cc",
- "socketstream.h",
- "testbase64.h",
- "testcertificateverifier.h",
- "testechoserver.cc",
- "testechoserver.h",
- "testutils.cc",
- "testutils.h",
- "virtualsocketserver.cc",
- "virtualsocketserver.h",
+ "socket_stream.cc",
+ "socket_stream.h",
+ "test_base64.h",
+ "test_certificate_verifier.h",
+ "test_echo_server.cc",
+ "test_echo_server.h",
+ "test_utils.cc",
+ "test_utils.h",
+ "virtual_socket_server.cc",
+ "virtual_socket_server.h",
]
deps = [
":checks",
@@ -1057,6 +1125,7 @@
":checks",
":rtc_base_approved",
":rtc_task_queue",
+ "task_utils:to_queued_task",
]
}
@@ -1070,6 +1139,7 @@
":gunit_helpers",
":rtc_base",
":rtc_base_tests_utils",
+ "../test:test_support",
"third_party/sigslot",
]
}
@@ -1100,12 +1170,12 @@
sources = [
"cpu_time_unittest.cc",
- "filerotatingstream_unittest.cc",
- "nullsocketserver_unittest.cc",
- "physicalsocketserver_unittest.cc",
+ "file_rotating_stream_unittest.cc",
+ "null_socket_server_unittest.cc",
+ "physical_socket_server_unittest.cc",
+ "socket_address_unittest.cc",
"socket_unittest.cc",
"socket_unittest.h",
- "socketaddress_unittest.cc",
]
deps = [
":checks",
@@ -1117,34 +1187,31 @@
"../system_wrappers:system_wrappers",
"../test:fileutils",
"../test:test_support",
+ "third_party/sigslot:sigslot",
"//testing/gtest",
"//third_party/abseil-cpp/absl/memory",
]
if (is_win) {
- sources += [ "win32socketserver_unittest.cc" ]
+ sources += [ "win32_socket_server_unittest.cc" ]
}
}
rtc_source_set("rtc_base_approved_unittests") {
testonly = true
- if (is_msan) {
- cflags = [ "-fsanitize=memory" ]
- }
sources = [
- "atomicops_unittest.cc",
+ "atomic_ops_unittest.cc",
"base64_unittest.cc",
"bind_unittest.cc",
- "bitbuffer_unittest.cc",
- "bitrateallocationstrategy_unittest.cc",
+ "bit_buffer_unittest.cc",
+ "bitrate_allocation_strategy_unittest.cc",
+ "buffer_queue_unittest.cc",
"buffer_unittest.cc",
- "bufferqueue_unittest.cc",
- "bytebuffer_unittest.cc",
- "byteorder_unittest.cc",
- "copyonwritebuffer_unittest.cc",
- "criticalsection_unittest.cc",
+ "byte_buffer_unittest.cc",
+ "byte_order_unittest.cc",
+ "copy_on_write_buffer_unittest.cc",
+ "critical_section_unittest.cc",
"event_tracer_unittest.cc",
"event_unittest.cc",
- "file_unittest.cc",
"function_view_unittest.cc",
"logging_unittest.cc",
"numerics/histogram_percentile_counter_unittest.cc",
@@ -1153,26 +1220,26 @@
"numerics/safe_compare_unittest.cc",
"numerics/safe_minmax_unittest.cc",
"numerics/sample_counter_unittest.cc",
- "onetimeevent_unittest.cc",
+ "one_time_event_unittest.cc",
"platform_file_unittest.cc",
"platform_thread_unittest.cc",
"random_unittest.cc",
"rate_limiter_unittest.cc",
"rate_statistics_unittest.cc",
- "ratetracker_unittest.cc",
- "refcountedobject_unittest.cc",
+ "rate_tracker_unittest.cc",
+ "ref_counted_object_unittest.cc",
"sanitizer_unittest.cc",
+ "string_encode_unittest.cc",
"string_to_number_unittest.cc",
- "stringencode_unittest.cc",
+ "string_utils_unittest.cc",
"stringize_macros_unittest.cc",
"strings/string_builder_unittest.cc",
- "stringutils_unittest.cc",
"swap_queue_unittest.cc",
"thread_annotations_unittest.cc",
"thread_checker_unittest.cc",
- "timestampaligner_unittest.cc",
- "timeutils_unittest.cc",
- "virtualsocket_unittest.cc",
+ "time_utils_unittest.cc",
+ "timestamp_aligner_unittest.cc",
+ "virtual_socket_unittest.cc",
"zero_memory_unittest.cc",
]
if (is_win) {
@@ -1193,11 +1260,14 @@
":stringutils",
":testclient",
"../api:array_view",
+ "../api:scoped_refptr",
+ "../api/units:time_delta",
"../system_wrappers:system_wrappers",
"../test:fileutils",
"../test:test_support",
"memory:unittests",
"third_party/base64",
+ "third_party/sigslot:sigslot",
"//third_party/abseil-cpp/absl/memory",
]
}
@@ -1207,7 +1277,6 @@
testonly = true
sources = [
- "cancelable_periodic_task_unittest.cc",
"task_queue_unittest.cc",
]
deps = [
@@ -1215,10 +1284,9 @@
":rtc_base_approved",
":rtc_base_tests_main",
":rtc_base_tests_utils",
- ":rtc_cancelable_task",
":rtc_task_queue",
- ":rtc_task_queue_for_test",
"../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
]
}
@@ -1253,6 +1321,7 @@
":rtc_task_queue",
":weak_ptr",
"../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
]
}
@@ -1264,6 +1333,7 @@
"numerics/moving_average_unittest.cc",
"numerics/moving_median_filter_unittest.cc",
"numerics/percentile_filter_unittest.cc",
+ "numerics/samples_stats_counter_unittest.cc",
"numerics/sequence_number_util_unittest.cc",
]
deps = [
@@ -1298,37 +1368,38 @@
"crc32_unittest.cc",
"data_rate_limiter_unittest.cc",
"helpers_unittest.cc",
- "ipaddress_unittest.cc",
+ "ip_address_unittest.cc",
"memory_usage_unittest.cc",
- "messagedigest_unittest.cc",
- "messagequeue_unittest.cc",
+ "message_digest_unittest.cc",
+ "message_queue_unittest.cc",
"nat_unittest.cc",
"network_unittest.cc",
"proxy_unittest.cc",
- "rollingaccumulator_unittest.cc",
- "rtccertificate_unittest.cc",
- "rtccertificategenerator_unittest.cc",
- "signalthread_unittest.cc",
- "sigslottester_unittest.cc",
+ "rolling_accumulator_unittest.cc",
+ "rtc_certificate_generator_unittest.cc",
+ "rtc_certificate_unittest.cc",
+ "signal_thread_unittest.cc",
+ "sigslot_tester_unittest.cc",
"stream_unittest.cc",
- "testclient_unittest.cc",
+ "test_client_unittest.cc",
"thread_unittest.cc",
+ "unique_id_generator_unittest.cc",
]
if (is_win) {
sources += [
"win32_unittest.cc",
- "win32window_unittest.cc",
+ "win32_window_unittest.cc",
]
}
if (is_posix || is_fuchsia) {
sources += [
+ "openssl_adapter_unittest.cc",
"openssl_key_derivation_hkdf_unittest.cc",
- "openssladapter_unittest.cc",
- "opensslsessioncache_unittest.cc",
- "opensslutility_unittest.cc",
- "ssladapter_unittest.cc",
- "sslidentity_unittest.cc",
- "sslstreamadapter_unittest.cc",
+ "openssl_session_cache_unittest.cc",
+ "openssl_utility_unittest.cc",
+ "ssl_adapter_unittest.cc",
+ "ssl_identity_unittest.cc",
+ "ssl_stream_adapter_unittest.cc",
]
}
deps = [
@@ -1339,6 +1410,7 @@
":stringutils",
":testclient",
"../api:array_view",
+ "../test:field_trial",
"../test:fileutils",
"../test:test_support",
"third_party/sigslot",
@@ -1368,5 +1440,8 @@
"java/src/org/webrtc/Size.java",
"java/src/org/webrtc/ThreadUtils.java",
]
+ deps = [
+ "//third_party/android_deps:android_support_annotations_java",
+ ]
}
}
diff --git a/rtc_base/asyncinvoker.cc b/rtc_base/async_invoker.cc
similarity index 99%
rename from rtc_base/asyncinvoker.cc
rename to rtc_base/async_invoker.cc
index f0dd188..8584bda 100644
--- a/rtc_base/asyncinvoker.cc
+++ b/rtc_base/async_invoker.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asyncinvoker.h"
+#include "rtc_base/async_invoker.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
diff --git a/rtc_base/asyncinvoker.h b/rtc_base/async_invoker.h
similarity index 97%
rename from rtc_base/asyncinvoker.h
rename to rtc_base/async_invoker.h
index 474ec7c..f15955d 100644
--- a/rtc_base/asyncinvoker.h
+++ b/rtc_base/async_invoker.h
@@ -8,19 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCINVOKER_H_
-#define RTC_BASE_ASYNCINVOKER_H_
+#ifndef RTC_BASE_ASYNC_INVOKER_H_
+#define RTC_BASE_ASYNC_INVOKER_H_
#include <atomic>
#include <memory>
#include <utility>
-#include "rtc_base/asyncinvoker-inl.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/async_invoker_inl.h"
#include "rtc_base/bind.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/event.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
@@ -262,4 +262,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCINVOKER_H_
+#endif // RTC_BASE_ASYNC_INVOKER_H_
diff --git a/rtc_base/asyncinvoker-inl.h b/rtc_base/async_invoker_inl.h
similarity index 86%
rename from rtc_base/asyncinvoker-inl.h
rename to rtc_base/async_invoker_inl.h
index 0dadc0f..bd9b0d1 100644
--- a/rtc_base/asyncinvoker-inl.h
+++ b/rtc_base/async_invoker_inl.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCINVOKER_INL_H_
-#define RTC_BASE_ASYNCINVOKER_INL_H_
+#ifndef RTC_BASE_ASYNC_INVOKER_INL_H_
+#define RTC_BASE_ASYNC_INVOKER_INL_H_
+#include "api/scoped_refptr.h"
#include "rtc_base/bind.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
#include "rtc_base/thread_annotations.h"
@@ -58,4 +58,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCINVOKER_INL_H_
+#endif // RTC_BASE_ASYNC_INVOKER_INL_H_
diff --git a/rtc_base/asyncpacketsocket.cc b/rtc_base/async_packet_socket.cc
similarity index 94%
rename from rtc_base/asyncpacketsocket.cc
rename to rtc_base/async_packet_socket.cc
index 7e0cc8f..a708fae 100644
--- a/rtc_base/asyncpacketsocket.cc
+++ b/rtc_base/async_packet_socket.cc
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asyncpacketsocket.h"
-#include "rtc_base/nethelper.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/net_helper.h"
namespace rtc {
@@ -42,4 +42,4 @@
}
}
-}; // namespace rtc
+} // namespace rtc
diff --git a/rtc_base/asyncpacketsocket.h b/rtc_base/async_packet_socket.h
similarity index 93%
rename from rtc_base/asyncpacketsocket.h
rename to rtc_base/async_packet_socket.h
index 44d6c67..3afff3b 100644
--- a/rtc_base/asyncpacketsocket.h
+++ b/rtc_base/async_packet_socket.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCPACKETSOCKET_H_
-#define RTC_BASE_ASYNCPACKETSOCKET_H_
+#ifndef RTC_BASE_ASYNC_PACKET_SOCKET_H_
+#define RTC_BASE_ASYNC_PACKET_SOCKET_H_
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/deprecation.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/dscp.h"
+#include "rtc_base/network/sent_packet.h"
#include "rtc_base/socket.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
@@ -51,10 +51,6 @@
PacketInfo info_signaled_after_sent;
};
-// TODO(bugs.webrtc.org/9584): Compatibility alias, delete as soon as downstream
-// code is updated.
-typedef int64_t PacketTime;
-
// Provides the ability to receive packets asynchronously. Sends are not
// buffered since it is acceptable to drop packets under high load.
class AsyncPacketSocket : public sigslot::has_slots<> {
@@ -144,4 +140,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCPACKETSOCKET_H_
+#endif // RTC_BASE_ASYNC_PACKET_SOCKET_H_
diff --git a/rtc_base/asyncresolverinterface.cc b/rtc_base/async_resolver_interface.cc
similarity index 88%
rename from rtc_base/asyncresolverinterface.cc
rename to rtc_base/async_resolver_interface.cc
index b2880f2..ff8c87e 100644
--- a/rtc_base/asyncresolverinterface.cc
+++ b/rtc_base/async_resolver_interface.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asyncresolverinterface.h"
+#include "rtc_base/async_resolver_interface.h"
namespace rtc {
@@ -16,4 +16,4 @@
AsyncResolverInterface::~AsyncResolverInterface() = default;
-}; // namespace rtc
+} // namespace rtc
diff --git a/rtc_base/asyncresolverinterface.h b/rtc_base/async_resolver_interface.h
similarity index 92%
rename from rtc_base/asyncresolverinterface.h
rename to rtc_base/async_resolver_interface.h
index f3df884..0f5e989 100644
--- a/rtc_base/asyncresolverinterface.h
+++ b/rtc_base/async_resolver_interface.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCRESOLVERINTERFACE_H_
-#define RTC_BASE_ASYNCRESOLVERINTERFACE_H_
+#ifndef RTC_BASE_ASYNC_RESOLVER_INTERFACE_H_
+#define RTC_BASE_ASYNC_RESOLVER_INTERFACE_H_
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
diff --git a/rtc_base/asyncsocket.cc b/rtc_base/async_socket.cc
similarity index 98%
rename from rtc_base/asyncsocket.cc
rename to rtc_base/async_socket.cc
index acd5415..ab3f99e 100644
--- a/rtc_base/asyncsocket.cc
+++ b/rtc_base/async_socket.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/checks.h"
namespace rtc {
diff --git a/rtc_base/asyncsocket.h b/rtc_base/async_socket.h
similarity index 94%
rename from rtc_base/asyncsocket.h
rename to rtc_base/async_socket.h
index 0abdc27..7b2f0e0 100644
--- a/rtc_base/asyncsocket.h
+++ b/rtc_base/async_socket.h
@@ -8,10 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCSOCKET_H_
-#define RTC_BASE_ASYNCSOCKET_H_
+#ifndef RTC_BASE_ASYNC_SOCKET_H_
+#define RTC_BASE_ASYNC_SOCKET_H_
+
+#include <stddef.h>
+#include <stdint.h>
#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
@@ -79,4 +83,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCSOCKET_H_
+#endif // RTC_BASE_ASYNC_SOCKET_H_
diff --git a/rtc_base/asynctcpsocket.cc b/rtc_base/async_tcp_socket.cc
similarity index 97%
rename from rtc_base/asynctcpsocket.cc
rename to rtc_base/async_tcp_socket.cc
index 666b335..148e459 100644
--- a/rtc_base/asynctcpsocket.cc
+++ b/rtc_base/async_tcp_socket.cc
@@ -8,17 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asynctcpsocket.h"
+#include "rtc_base/async_tcp_socket.h"
+#include <stdint.h>
#include <string.h>
-
#include <algorithm>
#include <memory>
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/timeutils.h" // for TimeMillis
+#include "rtc_base/network/sent_packet.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
+#include "rtc_base/time_utils.h" // for TimeMillis
#if defined(WEBRTC_POSIX)
#include <errno.h>
diff --git a/rtc_base/asynctcpsocket.h b/rtc_base/async_tcp_socket.h
similarity index 92%
rename from rtc_base/asynctcpsocket.h
rename to rtc_base/async_tcp_socket.h
index 9567dd9..ae12a94 100644
--- a/rtc_base/asynctcpsocket.h
+++ b/rtc_base/async_tcp_socket.h
@@ -8,18 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCTCPSOCKET_H_
-#define RTC_BASE_ASYNCTCPSOCKET_H_
+#ifndef RTC_BASE_ASYNC_TCP_SOCKET_H_
+#define RTC_BASE_ASYNC_TCP_SOCKET_H_
#include <stddef.h>
#include <memory>
-#include "rtc_base/asyncpacketsocket.h"
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/socket.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/socket_address.h"
namespace rtc {
@@ -109,4 +109,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCTCPSOCKET_H_
+#endif // RTC_BASE_ASYNC_TCP_SOCKET_H_
diff --git a/rtc_base/asynctcpsocket_unittest.cc b/rtc_base/async_tcp_socket_unittest.cc
similarity index 93%
rename from rtc_base/asynctcpsocket_unittest.cc
rename to rtc_base/async_tcp_socket_unittest.cc
index e8fd96c..69b5392 100644
--- a/rtc_base/asynctcpsocket_unittest.cc
+++ b/rtc_base/async_tcp_socket_unittest.cc
@@ -11,9 +11,9 @@
#include <memory>
#include <string>
-#include "rtc_base/asynctcpsocket.h"
+#include "rtc_base/async_tcp_socket.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/virtual_socket_server.h"
namespace rtc {
diff --git a/rtc_base/asyncudpsocket.cc b/rtc_base/async_udp_socket.cc
similarity index 95%
rename from rtc_base/asyncudpsocket.cc
rename to rtc_base/async_udp_socket.cc
index 2f9011c..8521910 100644
--- a/rtc_base/asyncudpsocket.cc
+++ b/rtc_base/async_udp_socket.cc
@@ -8,9 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/asyncudpsocket.h"
+#include "rtc_base/async_udp_socket.h"
+
+#include <stdint.h>
+#include <string>
+
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
+#include "rtc_base/network/sent_packet.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/asyncudpsocket.h b/rtc_base/async_udp_socket.h
similarity index 89%
rename from rtc_base/asyncudpsocket.h
rename to rtc_base/async_udp_socket.h
index 030946d..237c88d 100644
--- a/rtc_base/asyncudpsocket.h
+++ b/rtc_base/async_udp_socket.h
@@ -8,17 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ASYNCUDPSOCKET_H_
-#define RTC_BASE_ASYNCUDPSOCKET_H_
+#ifndef RTC_BASE_ASYNC_UDP_SOCKET_H_
+#define RTC_BASE_ASYNC_UDP_SOCKET_H_
#include <stddef.h>
#include <memory>
-#include "rtc_base/asyncpacketsocket.h"
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/socket.h"
-#include "rtc_base/socketaddress.h"
-#include "rtc_base/socketfactory.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/socket_factory.h"
namespace rtc {
@@ -68,4 +68,4 @@
} // namespace rtc
-#endif // RTC_BASE_ASYNCUDPSOCKET_H_
+#endif // RTC_BASE_ASYNC_UDP_SOCKET_H_
diff --git a/rtc_base/asyncudpsocket_unittest.cc b/rtc_base/async_udp_socket_unittest.cc
similarity index 91%
rename from rtc_base/asyncudpsocket_unittest.cc
rename to rtc_base/async_udp_socket_unittest.cc
index 33b3d13..0484c3a 100644
--- a/rtc_base/asyncudpsocket_unittest.cc
+++ b/rtc_base/async_udp_socket_unittest.cc
@@ -11,10 +11,10 @@
#include <memory>
#include <string>
-#include "rtc_base/asyncudpsocket.h"
+#include "rtc_base/async_udp_socket.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/physical_socket_server.h"
+#include "rtc_base/virtual_socket_server.h"
namespace rtc {
diff --git a/rtc_base/atomicops.h b/rtc_base/atomic_ops.h
similarity index 96%
rename from rtc_base/atomicops.h
rename to rtc_base/atomic_ops.h
index 16fa603..18a24a8 100644
--- a/rtc_base/atomicops.h
+++ b/rtc_base/atomic_ops.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ATOMICOPS_H_
-#define RTC_BASE_ATOMICOPS_H_
+#ifndef RTC_BASE_ATOMIC_OPS_H_
+#define RTC_BASE_ATOMIC_OPS_H_
#if defined(WEBRTC_WIN)
// clang-format off
@@ -76,4 +76,4 @@
} // namespace rtc
-#endif // RTC_BASE_ATOMICOPS_H_
+#endif // RTC_BASE_ATOMIC_OPS_H_
diff --git a/rtc_base/atomicops_unittest.cc b/rtc_base/atomic_ops_unittest.cc
similarity index 100%
rename from rtc_base/atomicops_unittest.cc
rename to rtc_base/atomic_ops_unittest.cc
diff --git a/rtc_base/base64_unittest.cc b/rtc_base/base64_unittest.cc
index bdf8559..dcc4d1b 100644
--- a/rtc_base/base64_unittest.cc
+++ b/rtc_base/base64_unittest.cc
@@ -9,13 +9,17 @@
*/
#include "rtc_base/third_party/base64/base64.h"
-#include "rtc_base/gunit.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+
#include "rtc_base/logging.h"
+#include "rtc_base/test_base64.h"
+#include "test/gtest.h"
-#include "rtc_base/testbase64.h"
-
-using namespace std;
-using namespace rtc;
+namespace rtc {
+namespace {
static struct {
size_t plain_length;
@@ -333,7 +337,7 @@
size_t szdest) {
std::string escaped;
Base64::EncodeFromArray((const char*)src, szsrc, &escaped);
- memcpy(dest, escaped.data(), min(escaped.size(), szdest));
+ memcpy(dest, escaped.data(), std::min(escaped.size(), szdest));
return escaped.size();
}
@@ -344,7 +348,7 @@
std::string unescaped;
EXPECT_TRUE(
Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, &unescaped, nullptr));
- memcpy(dest, unescaped.data(), min(unescaped.size(), szdest));
+ memcpy(dest, unescaped.data(), std::min(unescaped.size(), szdest));
return unescaped.size();
}
@@ -1444,3 +1448,6 @@
EXPECT_FALSE(Base64::GetNextBase64Char('&', &next_char));
EXPECT_FALSE(Base64::GetNextBase64Char('Z', nullptr));
}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/bind.h b/rtc_base/bind.h
index 9f225f1..16ac556 100644
--- a/rtc_base/bind.h
+++ b/rtc_base/bind.h
@@ -64,7 +64,7 @@
#include <tuple>
#include <type_traits>
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
#include "rtc_base/template_util.h"
#define NONAME
diff --git a/rtc_base/bind_unittest.cc b/rtc_base/bind_unittest.cc
index ed0913f..a62e547 100644
--- a/rtc_base/bind_unittest.cc
+++ b/rtc_base/bind_unittest.cc
@@ -8,13 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <type_traits>
+#include <string>
#include "rtc_base/bind.h"
-#include "rtc_base/gunit.h"
-
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/bitbuffer.cc b/rtc_base/bit_buffer.cc
similarity index 99%
rename from rtc_base/bitbuffer.cc
rename to rtc_base/bit_buffer.cc
index be72d55..59b71fc 100644
--- a/rtc_base/bitbuffer.cc
+++ b/rtc_base/bit_buffer.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bitbuffer.h"
+#include "rtc_base/bit_buffer.h"
#include <algorithm>
#include <limits>
diff --git a/rtc_base/bitbuffer.h b/rtc_base/bit_buffer.h
similarity index 97%
rename from rtc_base/bitbuffer.h
rename to rtc_base/bit_buffer.h
index ba96a12..b03677c 100644
--- a/rtc_base/bitbuffer.h
+++ b/rtc_base/bit_buffer.h
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_BITBUFFER_H_
-#define RTC_BASE_BITBUFFER_H_
+#ifndef RTC_BASE_BIT_BUFFER_H_
+#define RTC_BASE_BIT_BUFFER_H_
#include <stddef.h> // For size_t.
#include <stdint.h> // For integer types.
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -123,4 +123,4 @@
} // namespace rtc
-#endif // RTC_BASE_BITBUFFER_H_
+#endif // RTC_BASE_BIT_BUFFER_H_
diff --git a/rtc_base/bitbuffer_unittest.cc b/rtc_base/bit_buffer_unittest.cc
similarity index 98%
rename from rtc_base/bitbuffer_unittest.cc
rename to rtc_base/bit_buffer_unittest.cc
index a3f140f..20c0049 100644
--- a/rtc_base/bitbuffer_unittest.cc
+++ b/rtc_base/bit_buffer_unittest.cc
@@ -8,10 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bitbuffer.h"
+#include "rtc_base/bit_buffer.h"
+
+#include <limits>
+
#include "rtc_base/arraysize.h"
-#include "rtc_base/bytebuffer.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/byte_buffer.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/bitrateallocationstrategy.cc b/rtc_base/bitrate_allocation_strategy.cc
similarity index 98%
rename from rtc_base/bitrateallocationstrategy.cc
rename to rtc_base/bitrate_allocation_strategy.cc
index 46e6674..34a61ef 100644
--- a/rtc_base/bitrateallocationstrategy.cc
+++ b/rtc_base/bitrate_allocation_strategy.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bitrateallocationstrategy.h"
+#include "rtc_base/bitrate_allocation_strategy.h"
#include <algorithm>
#include <cstddef>
@@ -45,6 +45,7 @@
std::vector<uint32_t> BitrateAllocationStrategy::SetAllBitratesToMinimum(
const std::vector<BitrateAllocationStrategy::TrackConfig>& track_configs) {
std::vector<uint32_t> track_allocations;
+ track_allocations.reserve(track_configs.size());
for (const auto& track_config : track_configs) {
track_allocations.push_back(track_config.min_bitrate_bps);
}
diff --git a/rtc_base/bitrateallocationstrategy.h b/rtc_base/bitrate_allocation_strategy.h
similarity index 96%
rename from rtc_base/bitrateallocationstrategy.h
rename to rtc_base/bitrate_allocation_strategy.h
index 13a4eee..fc54373 100644
--- a/rtc_base/bitrateallocationstrategy.h
+++ b/rtc_base/bitrate_allocation_strategy.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
-#define RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
+#ifndef RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_
+#define RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_
#include <stdint.h>
#include <string>
@@ -117,4 +117,4 @@
};
} // namespace rtc
-#endif // RTC_BASE_BITRATEALLOCATIONSTRATEGY_H_
+#endif // RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_
diff --git a/rtc_base/bitrateallocationstrategy_unittest.cc b/rtc_base/bitrate_allocation_strategy_unittest.cc
similarity index 98%
rename from rtc_base/bitrateallocationstrategy_unittest.cc
rename to rtc_base/bitrate_allocation_strategy_unittest.cc
index f4c7ee7..aea3966 100644
--- a/rtc_base/bitrateallocationstrategy_unittest.cc
+++ b/rtc_base/bitrate_allocation_strategy_unittest.cc
@@ -8,8 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bitrateallocationstrategy.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/bitrate_allocation_strategy.h"
+
+#include <cstdint>
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/buffer.h b/rtc_base/buffer.h
index f9291b9..e95636a 100644
--- a/rtc_base/buffer.h
+++ b/rtc_base/buffer.h
@@ -11,6 +11,7 @@
#ifndef RTC_BASE_BUFFER_H_
#define RTC_BASE_BUFFER_H_
+#include <stdint.h>
#include <algorithm>
#include <cstring>
#include <memory>
diff --git a/rtc_base/bufferqueue.cc b/rtc_base/buffer_queue.cc
similarity index 98%
rename from rtc_base/bufferqueue.cc
rename to rtc_base/buffer_queue.cc
index 74f7a50..8f3ead9 100644
--- a/rtc_base/bufferqueue.cc
+++ b/rtc_base/buffer_queue.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bufferqueue.h"
+#include "rtc_base/buffer_queue.h"
#include <stdint.h>
#include <string.h>
diff --git a/rtc_base/bufferqueue.h b/rtc_base/buffer_queue.h
similarity index 90%
rename from rtc_base/bufferqueue.h
rename to rtc_base/buffer_queue.h
index 63f5182..bce3c8a 100644
--- a/rtc_base/bufferqueue.h
+++ b/rtc_base/buffer_queue.h
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_BUFFERQUEUE_H_
-#define RTC_BASE_BUFFERQUEUE_H_
+#ifndef RTC_BASE_BUFFER_QUEUE_H_
+#define RTC_BASE_BUFFER_QUEUE_H_
#include <stddef.h>
#include <deque>
#include <vector>
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace rtc {
@@ -60,4 +60,4 @@
} // namespace rtc
-#endif // RTC_BASE_BUFFERQUEUE_H_
+#endif // RTC_BASE_BUFFER_QUEUE_H_
diff --git a/rtc_base/bufferqueue_unittest.cc b/rtc_base/buffer_queue_unittest.cc
similarity index 97%
rename from rtc_base/bufferqueue_unittest.cc
rename to rtc_base/buffer_queue_unittest.cc
index 11d115f..2a2f8cc 100644
--- a/rtc_base/bufferqueue_unittest.cc
+++ b/rtc_base/buffer_queue_unittest.cc
@@ -8,8 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bufferqueue.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/buffer_queue.h"
+
+#include <string.h>
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/buffer_unittest.cc b/rtc_base/buffer_unittest.cc
index b2f47c1..40d9edc 100644
--- a/rtc_base/buffer_unittest.cc
+++ b/rtc_base/buffer_unittest.cc
@@ -10,12 +10,12 @@
#include "rtc_base/buffer.h"
-#include "api/array_view.h"
-#include "rtc_base/gunit.h"
-
-#include <type_traits>
+#include <cstdint>
#include <utility>
+#include "api/array_view.h"
+#include "test/gtest.h"
+
namespace rtc {
namespace {
diff --git a/rtc_base/bytebuffer.cc b/rtc_base/byte_buffer.cc
similarity index 99%
rename from rtc_base/bytebuffer.cc
rename to rtc_base/byte_buffer.cc
index f8ce1a2..9f79120 100644
--- a/rtc_base/bytebuffer.cc
+++ b/rtc_base/byte_buffer.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bytebuffer.h"
+#include "rtc_base/byte_buffer.h"
#include <string.h>
diff --git a/rtc_base/bytebuffer.h b/rtc_base/byte_buffer.h
similarity index 97%
rename from rtc_base/bytebuffer.h
rename to rtc_base/byte_buffer.h
index 4d25c21..73e9040 100644
--- a/rtc_base/bytebuffer.h
+++ b/rtc_base/byte_buffer.h
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_BYTEBUFFER_H_
-#define RTC_BASE_BYTEBUFFER_H_
+#ifndef RTC_BASE_BYTE_BUFFER_H_
+#define RTC_BASE_BYTE_BUFFER_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
#include "rtc_base/buffer.h"
-#include "rtc_base/byteorder.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/byte_order.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -201,4 +201,4 @@
} // namespace rtc
-#endif // RTC_BASE_BYTEBUFFER_H_
+#endif // RTC_BASE_BYTE_BUFFER_H_
diff --git a/rtc_base/bytebuffer_unittest.cc b/rtc_base/byte_buffer_unittest.cc
similarity index 98%
rename from rtc_base/bytebuffer_unittest.cc
rename to rtc_base/byte_buffer_unittest.cc
index 718f35c..eafe670 100644
--- a/rtc_base/bytebuffer_unittest.cc
+++ b/rtc_base/byte_buffer_unittest.cc
@@ -8,10 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/bytebuffer.h"
+#include "rtc_base/byte_buffer.h"
+
+#include <string.h>
+
#include "rtc_base/arraysize.h"
-#include "rtc_base/byteorder.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/byte_order.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/byteorder.h b/rtc_base/byte_order.h
similarity index 97%
rename from rtc_base/byteorder.h
rename to rtc_base/byte_order.h
index 86546a5..2b50f0d 100644
--- a/rtc_base/byteorder.h
+++ b/rtc_base/byte_order.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_BYTEORDER_H_
-#define RTC_BASE_BYTEORDER_H_
+#ifndef RTC_BASE_BYTE_ORDER_H_
+#define RTC_BASE_BYTE_ORDER_H_
#include <stdint.h>
@@ -177,4 +177,4 @@
} // namespace rtc
-#endif // RTC_BASE_BYTEORDER_H_
+#endif // RTC_BASE_BYTE_ORDER_H_
diff --git a/rtc_base/byteorder_unittest.cc b/rtc_base/byte_order_unittest.cc
similarity index 97%
rename from rtc_base/byteorder_unittest.cc
rename to rtc_base/byte_order_unittest.cc
index 75509de..82b5fe9 100644
--- a/rtc_base/byteorder_unittest.cc
+++ b/rtc_base/byte_order_unittest.cc
@@ -10,8 +10,8 @@
#include <stdint.h>
-#include "rtc_base/byteorder.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/byte_order.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/callback.h b/rtc_base/callback.h
index 65b7c9c..4751221 100644
--- a/rtc_base/callback.h
+++ b/rtc_base/callback.h
@@ -62,9 +62,9 @@
#ifndef RTC_BASE_CALLBACK_H_
#define RTC_BASE_CALLBACK_H_
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
namespace rtc {
diff --git a/rtc_base/callback.h.pump b/rtc_base/callback.h.pump
index 2c40eab..dc5fb3a 100644
--- a/rtc_base/callback.h.pump
+++ b/rtc_base/callback.h.pump
@@ -57,9 +57,9 @@
#ifndef RTC_BASE_CALLBACK_H_
#define RTC_BASE_CALLBACK_H_
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
+#include "api/scoped_refptr.h"
namespace rtc {
diff --git a/rtc_base/callback_unittest.cc b/rtc_base/callback_unittest.cc
index ae86a4c..8767295 100644
--- a/rtc_base/callback_unittest.cc
+++ b/rtc_base/callback_unittest.cc
@@ -9,10 +9,11 @@
*/
#include "rtc_base/callback.h"
+
#include "rtc_base/bind.h"
-#include "rtc_base/gunit.h"
#include "rtc_base/keep_ref_until_done.h"
-#include "rtc_base/refcount.h"
+#include "rtc_base/ref_count.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/cancelable_periodic_task.h b/rtc_base/cancelable_periodic_task.h
deleted file mode 100644
index d113015..0000000
--- a/rtc_base/cancelable_periodic_task.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#ifndef RTC_BASE_CANCELABLE_PERIODIC_TASK_H_
-#define RTC_BASE_CANCELABLE_PERIODIC_TASK_H_
-
-#include <memory>
-#include <type_traits>
-#include <utility>
-
-#include "absl/memory/memory.h"
-#include "rtc_base/cancelable_task_handle.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/numerics/safe_conversions.h"
-
-namespace rtc {
-namespace cancelable_periodic_task_internal {
-// CancelablePeriodicTask runs a closure multiple times with delay decided
-// by the return value of the closure itself.
-// The task can be canceled with the handle returned by GetCancelationHandle().
-// Note that the task can only be canceled on the task queue where it runs.
-template <typename Closure>
-class CancelablePeriodicTask final : public BaseCancelableTask {
- public:
- // |closure| should return time in ms until next run.
- explicit CancelablePeriodicTask(Closure&& closure)
- : closure_(std::forward<Closure>(closure)) {}
- CancelablePeriodicTask(const CancelablePeriodicTask&) = delete;
- CancelablePeriodicTask& operator=(const CancelablePeriodicTask&) = delete;
- ~CancelablePeriodicTask() override = default;
-
- private:
- bool Run() override {
- // See QueuedTask::Run documentaion for return values meaning.
- if (BaseCancelableTask::Canceled())
- return true; // Caller retains ownership of `this`, and will destroy it.
- // Run the actual task.
- auto delay = closure_();
- // Convert closure_() return type into uint32_t.
- uint32_t delay_ms = 0;
- if (rtc::IsValueInRangeForNumericType<uint32_t>(delay)) {
- delay_ms = static_cast<uint32_t>(delay);
- } else {
- // Log and recover in production.
- RTC_LOG(LS_ERROR) << "Invalid delay until next run: " << delay;
- delay_ms = rtc::saturated_cast<uint32_t>(delay);
- // But crash in debug.
- RTC_DCHECK(false);
- }
- // Reschedule.
- auto owned_task = absl::WrapUnique(this);
- if (delay_ms == 0)
- TaskQueue::Current()->PostTask(std::move(owned_task));
- else
- TaskQueue::Current()->PostDelayedTask(std::move(owned_task), delay_ms);
- return false; // Caller will release ownership of `this`.
- }
-
- Closure closure_;
-};
-} // namespace cancelable_periodic_task_internal
-
-template <typename Closure>
-std::unique_ptr<BaseCancelableTask> CreateCancelablePeriodicTask(
- Closure&& closure) {
- using CleanedClosure = typename std::remove_cv<
- typename std::remove_reference<Closure>::type>::type;
- return absl::make_unique<cancelable_periodic_task_internal::
- CancelablePeriodicTask<CleanedClosure>>(
- std::forward<CleanedClosure>(closure));
-}
-
-} // namespace rtc
-
-#endif // RTC_BASE_CANCELABLE_PERIODIC_TASK_H_
diff --git a/rtc_base/cancelable_periodic_task_unittest.cc b/rtc_base/cancelable_periodic_task_unittest.cc
deleted file mode 100644
index badd623..0000000
--- a/rtc_base/cancelable_periodic_task_unittest.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2018 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 "rtc_base/cancelable_periodic_task.h"
-
-#include "rtc_base/event.h"
-#include "test/gmock.h"
-
-namespace {
-
-using ::testing::AtLeast;
-using ::testing::Invoke;
-using ::testing::NiceMock;
-using ::testing::MockFunction;
-using ::testing::Return;
-
-constexpr int kTimeoutMs = 1000;
-
-class MockClosure {
- public:
- MOCK_METHOD0(Call, int());
- MOCK_METHOD0(Delete, void());
-};
-
-class MoveOnlyClosure {
- public:
- explicit MoveOnlyClosure(MockClosure* mock) : mock_(mock) {}
- MoveOnlyClosure(const MoveOnlyClosure&) = delete;
- MoveOnlyClosure(MoveOnlyClosure&& other) : mock_(other.mock_) {
- other.mock_ = nullptr;
- }
- ~MoveOnlyClosure() {
- if (mock_)
- mock_->Delete();
- }
- int operator()() { return mock_->Call(); }
-
- private:
- MockClosure* mock_;
-};
-
-class CopyableClosure {
- public:
- explicit CopyableClosure(MockClosure* mock) : mock_(mock) {}
- CopyableClosure(const CopyableClosure& other) : mock_(other.mock_) {}
- ~CopyableClosure() {
- if (mock_) {
- mock_->Delete();
- mock_ = nullptr;
- }
- }
- int operator()() { return mock_->Call(); }
-
- private:
- MockClosure* mock_;
-};
-
-TEST(CancelablePeriodicTaskTest, CanCallCancelOnEmptyHandle) {
- rtc::CancelableTaskHandle handle;
- handle.Cancel();
-}
-
-TEST(CancelablePeriodicTaskTest, CancelTaskBeforeItRuns) {
- rtc::Event done;
- MockClosure mock;
- EXPECT_CALL(mock, Call).Times(0);
- EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
-
- rtc::TaskQueue task_queue("queue");
-
- auto task = rtc::CreateCancelablePeriodicTask(MoveOnlyClosure(&mock));
- rtc::CancelableTaskHandle handle = task->GetCancellationHandle();
- task_queue.PostTask([handle] { handle.Cancel(); });
- task_queue.PostTask(std::move(task));
-
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-TEST(CancelablePeriodicTaskTest, CancelDelayedTaskBeforeItRuns) {
- rtc::Event done;
- MockClosure mock;
- EXPECT_CALL(mock, Call).Times(0);
- EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
-
- rtc::TaskQueue task_queue("queue");
-
- auto task = rtc::CreateCancelablePeriodicTask(MoveOnlyClosure(&mock));
- rtc::CancelableTaskHandle handle = task->GetCancellationHandle();
- task_queue.PostDelayedTask(std::move(task), 100);
- task_queue.PostTask([handle] { handle.Cancel(); });
-
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-TEST(CancelablePeriodicTaskTest, CancelTaskAfterItRuns) {
- rtc::Event done;
- MockClosure mock;
- EXPECT_CALL(mock, Call).WillOnce(Return(100));
- EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
-
- rtc::TaskQueue task_queue("queue");
-
- auto task = rtc::CreateCancelablePeriodicTask(MoveOnlyClosure(&mock));
- rtc::CancelableTaskHandle handle = task->GetCancellationHandle();
- task_queue.PostTask(std::move(task));
- task_queue.PostTask([handle] { handle.Cancel(); });
-
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-TEST(CancelablePeriodicTaskTest, ZeroReturnValueRepostsTheTask) {
- NiceMock<MockClosure> closure;
- rtc::Event done;
- EXPECT_CALL(closure, Call()).WillOnce(Return(0)).WillOnce(Invoke([&done] {
- done.Set();
- return kTimeoutMs;
- }));
- rtc::TaskQueue task_queue("queue");
- task_queue.PostTask(
- rtc::CreateCancelablePeriodicTask(MoveOnlyClosure(&closure)));
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-TEST(CancelablePeriodicTaskTest, StartPeriodicTask) {
- MockFunction<int()> closure;
- rtc::Event done;
- EXPECT_CALL(closure, Call())
- .WillOnce(Return(20))
- .WillOnce(Return(20))
- .WillOnce(Invoke([&done] {
- done.Set();
- return kTimeoutMs;
- }));
- rtc::TaskQueue task_queue("queue");
- task_queue.PostTask(
- rtc::CreateCancelablePeriodicTask(closure.AsStdFunction()));
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-// Validates perfect forwarding doesn't keep reference to deleted copy.
-TEST(CancelablePeriodicTaskTest, CreateWithCopyOfAClosure) {
- rtc::Event done;
- MockClosure mock;
- EXPECT_CALL(mock, Call).WillOnce(Invoke([&done] {
- done.Set();
- return kTimeoutMs;
- }));
- EXPECT_CALL(mock, Delete).Times(AtLeast(2));
- CopyableClosure closure(&mock);
- std::unique_ptr<rtc::BaseCancelableTask> task;
- {
- CopyableClosure copy = closure;
- task = rtc::CreateCancelablePeriodicTask(copy);
- }
-
- rtc::TaskQueue task_queue("queue");
- task_queue.PostTask(std::move(task));
- EXPECT_TRUE(done.Wait(kTimeoutMs));
-}
-
-TEST(CancelablePeriodicTaskTest, DeletingHandleDoesntStopTheTask) {
- rtc::Event run;
- rtc::TaskQueue task_queue("queue");
- auto task = rtc::CreateCancelablePeriodicTask(([&] {
- run.Set();
- return kTimeoutMs;
- }));
- rtc::CancelableTaskHandle handle = task->GetCancellationHandle();
- handle = {}; // delete the handle.
- task_queue.PostTask(std::move(task));
- EXPECT_TRUE(run.Wait(kTimeoutMs));
-}
-
-// Example to test there are no thread races and use after free for suggested
-// typical usage of the CancelablePeriodicTask
-TEST(CancelablePeriodicTaskTest, Example) {
- class ObjectOnTaskQueue {
- public:
- void DoPeriodicTask() {}
- int TimeUntilNextRunMs() { return 100; }
-
- rtc::CancelableTaskHandle StartPeriodicTask(rtc::TaskQueue* task_queue) {
- auto periodic_task = rtc::CreateCancelablePeriodicTask([this] {
- DoPeriodicTask();
- return TimeUntilNextRunMs();
- });
- rtc::CancelableTaskHandle handle = periodic_task->GetCancellationHandle();
- task_queue->PostTask(std::move(periodic_task));
- return handle;
- }
- };
-
- rtc::TaskQueue task_queue("queue");
-
- auto object = absl::make_unique<ObjectOnTaskQueue>();
- // Create and start the periodic task.
- rtc::CancelableTaskHandle handle = object->StartPeriodicTask(&task_queue);
-
- // Restart the task
- task_queue.PostTask([handle] { handle.Cancel(); });
- handle = object->StartPeriodicTask(&task_queue);
-
- // Stop the task and destroy the object.
- struct Destructor {
- void operator()() {
- // Cancel must be run on the task_queue, but if task failed to start
- // because of task queue destruction, there is no need to run Cancel.
- handle.Cancel();
- }
- // Destruction will happen either on the task queue or because task
- // queue is destroyed.
-
- std::unique_ptr<ObjectOnTaskQueue> object;
- rtc::CancelableTaskHandle handle;
- };
- task_queue.PostTask(Destructor{std::move(object), std::move(handle)});
- // Do not wait for the Destructor closure in order to create a race between
- // task queue destruction and running the Desctructor closure.
-}
-
-} // namespace
diff --git a/rtc_base/cancelable_task_handle.cc b/rtc_base/cancelable_task_handle.cc
deleted file mode 100644
index 372e766..0000000
--- a/rtc_base/cancelable_task_handle.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018 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 "rtc_base/cancelable_task_handle.h"
-
-#include <utility>
-
-#include "rtc_base/refcounter.h"
-#include "rtc_base/sequenced_task_checker.h"
-#include "rtc_base/thread_annotations.h"
-#include "rtc_base/thread_checker.h"
-
-namespace rtc {
-
-class CancelableTaskHandle::CancellationToken {
- public:
- CancellationToken() : canceled_(false), ref_count_(0) { checker_.Detach(); }
- CancellationToken(const CancellationToken&) = delete;
- CancellationToken& operator=(const CancellationToken&) = delete;
-
- void Cancel() {
- RTC_DCHECK_RUN_ON(&checker_);
- canceled_ = true;
- }
-
- bool Canceled() {
- RTC_DCHECK_RUN_ON(&checker_);
- return canceled_;
- }
-
- void AddRef() { ref_count_.IncRef(); }
-
- void Release() {
- if (ref_count_.DecRef() == rtc::RefCountReleaseStatus::kDroppedLastRef)
- delete this;
- }
-
- private:
- ~CancellationToken() = default;
-
- rtc::SequencedTaskChecker checker_;
- bool canceled_ RTC_GUARDED_BY(checker_);
- webrtc::webrtc_impl::RefCounter ref_count_;
-};
-
-CancelableTaskHandle::CancelableTaskHandle() = default;
-CancelableTaskHandle::CancelableTaskHandle(const CancelableTaskHandle&) =
- default;
-CancelableTaskHandle::CancelableTaskHandle(CancelableTaskHandle&&) = default;
-CancelableTaskHandle& CancelableTaskHandle::operator=(
- const CancelableTaskHandle&) = default;
-CancelableTaskHandle& CancelableTaskHandle::operator=(CancelableTaskHandle&&) =
- default;
-CancelableTaskHandle::~CancelableTaskHandle() = default;
-
-void CancelableTaskHandle::Cancel() const {
- if (cancellation_token_.get() != nullptr)
- cancellation_token_->Cancel();
-}
-
-CancelableTaskHandle::CancelableTaskHandle(
- rtc::scoped_refptr<CancellationToken> cancellation_token)
- : cancellation_token_(std::move(cancellation_token)) {}
-
-BaseCancelableTask::~BaseCancelableTask() = default;
-
-CancelableTaskHandle BaseCancelableTask::GetCancellationHandle() const {
- return CancelableTaskHandle(cancellation_token_);
-}
-
-BaseCancelableTask::BaseCancelableTask()
- : cancellation_token_(new CancelableTaskHandle::CancellationToken) {}
-
-bool BaseCancelableTask::Canceled() const {
- return cancellation_token_->Canceled();
-}
-
-} // namespace rtc
diff --git a/rtc_base/cancelable_task_handle.h b/rtc_base/cancelable_task_handle.h
deleted file mode 100644
index 3b1f0d5..0000000
--- a/rtc_base/cancelable_task_handle.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#ifndef RTC_BASE_CANCELABLE_TASK_HANDLE_H_
-#define RTC_BASE_CANCELABLE_TASK_HANDLE_H_
-
-#include "rtc_base/scoped_ref_ptr.h"
-#include "rtc_base/task_queue.h"
-
-namespace rtc {
-
-class BaseCancelableTask;
-
-// Allows to cancel a cancelable task. Non-empty handle can be acquired by
-// calling GetCancellationHandle() on a cancelable task.
-class CancelableTaskHandle {
- public:
- // This class is copyable and cheaply movable.
- CancelableTaskHandle();
- CancelableTaskHandle(const CancelableTaskHandle&);
- CancelableTaskHandle(CancelableTaskHandle&&);
- CancelableTaskHandle& operator=(const CancelableTaskHandle&);
- CancelableTaskHandle& operator=(CancelableTaskHandle&&);
- // Deleting the handler doesn't Cancel the task.
- ~CancelableTaskHandle();
-
- // Prevents the cancelable task to run.
- // Must be executed on the same task queue as the task itself.
- void Cancel() const;
-
- private:
- friend class BaseCancelableTask;
- class CancellationToken;
- explicit CancelableTaskHandle(
- rtc::scoped_refptr<CancellationToken> cancelation_token);
-
- rtc::scoped_refptr<CancellationToken> cancellation_token_;
-};
-
-class BaseCancelableTask : public QueuedTask {
- public:
- ~BaseCancelableTask() override;
-
- CancelableTaskHandle GetCancellationHandle() const;
-
- protected:
- BaseCancelableTask();
-
- bool Canceled() const;
-
- private:
- rtc::scoped_refptr<CancelableTaskHandle::CancellationToken>
- cancellation_token_;
-};
-
-} // namespace rtc
-
-#endif // RTC_BASE_CANCELABLE_TASK_HANDLE_H_
diff --git a/rtc_base/constructormagic.h b/rtc_base/constructor_magic.h
similarity index 91%
rename from rtc_base/constructormagic.h
rename to rtc_base/constructor_magic.h
index 6b6e83c..e63c2ff 100644
--- a/rtc_base/constructormagic.h
+++ b/rtc_base/constructor_magic.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_CONSTRUCTORMAGIC_H_
-#define RTC_BASE_CONSTRUCTORMAGIC_H_
+#ifndef RTC_BASE_CONSTRUCTOR_MAGIC_H_
+#define RTC_BASE_CONSTRUCTOR_MAGIC_H_
// Put this in the declarations for a class to be unassignable.
#define RTC_DISALLOW_ASSIGN(TypeName) \
@@ -31,4 +31,4 @@
TypeName() = delete; \
RTC_DISALLOW_COPY_AND_ASSIGN(TypeName)
-#endif // RTC_BASE_CONSTRUCTORMAGIC_H_
+#endif // RTC_BASE_CONSTRUCTOR_MAGIC_H_
diff --git a/rtc_base/copyonwritebuffer.cc b/rtc_base/copy_on_write_buffer.cc
similarity index 98%
rename from rtc_base/copyonwritebuffer.cc
rename to rtc_base/copy_on_write_buffer.cc
index 8f5126a..de003f2 100644
--- a/rtc_base/copyonwritebuffer.cc
+++ b/rtc_base/copy_on_write_buffer.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/copy_on_write_buffer.h"
#include <stddef.h>
diff --git a/rtc_base/copyonwritebuffer.h b/rtc_base/copy_on_write_buffer.h
similarity index 97%
rename from rtc_base/copyonwritebuffer.h
rename to rtc_base/copy_on_write_buffer.h
index cc174df..d0954ad 100644
--- a/rtc_base/copyonwritebuffer.h
+++ b/rtc_base/copy_on_write_buffer.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_COPYONWRITEBUFFER_H_
-#define RTC_BASE_COPYONWRITEBUFFER_H_
+#ifndef RTC_BASE_COPY_ON_WRITE_BUFFER_H_
+#define RTC_BASE_COPY_ON_WRITE_BUFFER_H_
#include <stdint.h>
#include <algorithm>
@@ -18,10 +18,10 @@
#include <type_traits>
#include <utility>
+#include "api/scoped_refptr.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/ref_counted_object.h"
namespace rtc {
@@ -243,4 +243,4 @@
} // namespace rtc
-#endif // RTC_BASE_COPYONWRITEBUFFER_H_
+#endif // RTC_BASE_COPY_ON_WRITE_BUFFER_H_
diff --git a/rtc_base/copyonwritebuffer_unittest.cc b/rtc_base/copy_on_write_buffer_unittest.cc
similarity index 98%
rename from rtc_base/copyonwritebuffer_unittest.cc
rename to rtc_base/copy_on_write_buffer_unittest.cc
index 24a57d4..fc569bd 100644
--- a/rtc_base/copyonwritebuffer_unittest.cc
+++ b/rtc_base/copy_on_write_buffer_unittest.cc
@@ -8,8 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/copyonwritebuffer.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/copy_on_write_buffer.h"
+
+#include <cstdint>
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/cpu_time.cc b/rtc_base/cpu_time.cc
index ad91eca..b95bcb1 100644
--- a/rtc_base/cpu_time.cc
+++ b/rtc_base/cpu_time.cc
@@ -9,8 +9,9 @@
*/
#include "rtc_base/cpu_time.h"
+
#include "rtc_base/logging.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#if defined(WEBRTC_LINUX)
#include <time.h>
diff --git a/rtc_base/cpu_time_unittest.cc b/rtc_base/cpu_time_unittest.cc
index f473069..b5e0f67 100644
--- a/rtc_base/cpu_time_unittest.cc
+++ b/rtc_base/cpu_time_unittest.cc
@@ -9,11 +9,9 @@
*/
#include "rtc_base/cpu_time.h"
-#include <algorithm>
-#include <memory>
+
#include "rtc_base/platform_thread.h"
-#include "rtc_base/timeutils.h"
-#include "system_wrappers/include/cpu_info.h"
+#include "rtc_base/time_utils.h"
#include "system_wrappers/include/sleep.h"
#include "test/gtest.h"
diff --git a/rtc_base/crc32_unittest.cc b/rtc_base/crc32_unittest.cc
index 752bc9f..60997b2 100644
--- a/rtc_base/crc32_unittest.cc
+++ b/rtc_base/crc32_unittest.cc
@@ -9,10 +9,11 @@
*/
#include "rtc_base/crc32.h"
-#include "rtc_base/gunit.h"
#include <string>
+#include "test/gtest.h"
+
namespace rtc {
TEST(Crc32Test, TestBasic) {
diff --git a/rtc_base/criticalsection.cc b/rtc_base/critical_section.cc
similarity index 96%
rename from rtc_base/criticalsection.cc
rename to rtc_base/critical_section.cc
index 4e00be9..2100fe9 100644
--- a/rtc_base/criticalsection.cc
+++ b/rtc_base/critical_section.cc
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include <time.h>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/system/unused.h"
@@ -34,6 +34,10 @@
pthread_mutexattr_t mutex_attribute;
pthread_mutexattr_init(&mutex_attribute);
pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
+#if defined(WEBRTC_MAC)
+ pthread_mutexattr_setpolicy_np(&mutex_attribute,
+ _PTHREAD_MUTEX_POLICY_FAIRSHARE);
+#endif
pthread_mutex_init(&mutex_, &mutex_attribute);
pthread_mutexattr_destroy(&mutex_attribute);
#endif
diff --git a/rtc_base/criticalsection.h b/rtc_base/critical_section.h
similarity index 95%
rename from rtc_base/criticalsection.h
rename to rtc_base/critical_section.h
index f25e7d0..d575b97 100644
--- a/rtc_base/criticalsection.h
+++ b/rtc_base/critical_section.h
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_CRITICALSECTION_H_
-#define RTC_BASE_CRITICALSECTION_H_
+#ifndef RTC_BASE_CRITICAL_SECTION_H_
+#define RTC_BASE_CRITICAL_SECTION_H_
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/thread_annotations.h"
@@ -34,7 +34,7 @@
#endif
// See notes in the 'Performance' unit test for the effects of this flag.
-#define USE_NATIVE_MUTEX_ON_MAC 0
+#define USE_NATIVE_MUTEX_ON_MAC 1
#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
#include <dispatch/dispatch.h>
@@ -52,7 +52,7 @@
// Locking methods (Enter, TryEnter, Leave)are const to permit protecting
// members inside a const context without requiring mutable CriticalSections
-// everywhere.
+// everywhere. CriticalSection is reentrant lock.
class RTC_LOCKABLE CriticalSection {
public:
CriticalSection();
@@ -157,4 +157,4 @@
} // namespace rtc
-#endif // RTC_BASE_CRITICALSECTION_H_
+#endif // RTC_BASE_CRITICAL_SECTION_H_
diff --git a/rtc_base/criticalsection_unittest.cc b/rtc_base/critical_section_unittest.cc
similarity index 91%
rename from rtc_base/criticalsection_unittest.cc
rename to rtc_base/critical_section_unittest.cc
index 6016f85..5405c61 100644
--- a/rtc_base/criticalsection_unittest.cc
+++ b/rtc_base/critical_section_unittest.cc
@@ -8,18 +8,24 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <stddef.h>
+#include <stdint.h>
#include <memory>
#include <set>
+#include <utility>
#include <vector>
#include "rtc_base/arraysize.h"
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/location.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/thread.h"
+#include "test/gtest.h"
namespace rtc {
@@ -366,25 +372,33 @@
int my_id_ = 0;
};
-// Comparison of output of this test as tested on a MacBook Pro Retina, 15-inch,
-// Mid 2014, 2,8 GHz Intel Core i7, 16 GB 1600 MHz DDR3,
-// running OS X El Capitan, 10.11.2.
+// Comparison of output of this test as tested on a MacBook Pro, 13-inch,
+// 2017, 3,5 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3,
+// running macOS Mojave, 10.14.3.
//
-// Native mutex implementation:
+// Native mutex implementation using fair policy (previously macOS default):
// Approximate CPU usage:
-// System: ~16%
-// User mode: ~1.3%
-// Idle: ~82%
+// real 4m54.612s
+// user 1m20.575s
+// sys 3m48.872s
// Unit test output:
-// [ OK ] CriticalSectionTest.Performance (234545 ms)
+// [ OK ] CriticalSectionTest.Performance (294375 ms)
+//
+// Native mutex implementation using first fit policy (current macOS default):
+// Approximate CPU usage:
+// real 0m11.535s
+// user 0m12.738s
+// sys 0m31.207s
+// Unit test output:
+// [ OK ] CriticalSectionTest.Performance (11444 ms)
//
// Special partially spin lock based implementation:
// Approximate CPU usage:
-// System: ~75%
-// User mode: ~16%
-// Idle: ~8%
+// real 0m2.113s
+// user 0m3.014s
+// sys 0m4.495s
// Unit test output:
-// [ OK ] CriticalSectionTest.Performance (2107 ms)
+// [ OK ] CriticalSectionTest.Performance (1885 ms)
//
// The test is disabled by default to avoid unecessarily loading the bots.
TEST(CriticalSectionTest, DISABLED_Performance) {
diff --git a/rtc_base/cryptstring.cc b/rtc_base/crypt_string.cc
similarity index 96%
rename from rtc_base/cryptstring.cc
rename to rtc_base/crypt_string.cc
index 2c7c0c7..ed0ff16 100644
--- a/rtc_base/cryptstring.cc
+++ b/rtc_base/crypt_string.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/cryptstring.h"
+#include "rtc_base/crypt_string.h"
namespace rtc {
@@ -69,4 +69,4 @@
memcpy(&dest->front(), password_.data(), password_.size());
}
-}; // namespace rtc
+} // namespace rtc
diff --git a/rtc_base/cryptstring.h b/rtc_base/crypt_string.h
similarity index 95%
rename from rtc_base/cryptstring.h
rename to rtc_base/crypt_string.h
index d0e36cb..8aa757c 100644
--- a/rtc_base/cryptstring.h
+++ b/rtc_base/crypt_string.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_CRYPTSTRING_H_
-#define RTC_BASE_CRYPTSTRING_H_
+#ifndef RTC_BASE_CRYPT_STRING_H_
+#define RTC_BASE_CRYPT_STRING_H_
#include <string.h>
@@ -83,4 +83,4 @@
} // namespace rtc
-#endif // RTC_BASE_CRYPTSTRING_H_
+#endif // RTC_BASE_CRYPT_STRING_H_
diff --git a/rtc_base/data_rate_limiter_unittest.cc b/rtc_base/data_rate_limiter_unittest.cc
index 8c410fe..efd4728 100644
--- a/rtc_base/data_rate_limiter_unittest.cc
+++ b/rtc_base/data_rate_limiter_unittest.cc
@@ -9,7 +9,8 @@
*/
#include "rtc_base/data_rate_limiter.h"
-#include "rtc_base/gunit.h"
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/event_tracer.cc b/rtc_base/event_tracer.cc
index af88c9d..bcc8252 100644
--- a/rtc_base/event_tracer.cc
+++ b/rtc_base/event_tracer.cc
@@ -16,16 +16,16 @@
#include <string>
#include <vector>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/thread_checker.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
// This is a guesstimate that should be enough in most cases.
diff --git a/rtc_base/event_unittest.cc b/rtc_base/event_unittest.cc
index a65111b..3111887 100644
--- a/rtc_base/event_unittest.cc
+++ b/rtc_base/event_unittest.cc
@@ -9,8 +9,9 @@
*/
#include "rtc_base/event.h"
-#include "rtc_base/gunit.h"
+
#include "rtc_base/platform_thread.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn
index d36a43e..80fa70b 100644
--- a/rtc_base/experiments/BUILD.gn
+++ b/rtc_base/experiments/BUILD.gn
@@ -20,6 +20,24 @@
]
}
+rtc_static_library("audio_allocation_settings") {
+ sources = [
+ "audio_allocation_settings.cc",
+ "audio_allocation_settings.h",
+ ]
+ defines = []
+ if (rtc_opus_support_120ms_ptime) {
+ defines += [ "WEBRTC_OPUS_SUPPORT_120MS_PTIME=1" ]
+ } else {
+ defines += [ "WEBRTC_OPUS_SUPPORT_120MS_PTIME=0" ]
+ }
+ deps = [
+ ":field_trial_parser",
+ "../:rtc_base_approved",
+ "../../system_wrappers:field_trial",
+ ]
+}
+
rtc_static_library("field_trial_parser") {
sources = [
"field_trial_parser.cc",
@@ -37,18 +55,6 @@
]
}
-rtc_static_library("congestion_controller_experiment") {
- sources = [
- "congestion_controller_experiment.cc",
- "congestion_controller_experiment.h",
- ]
- deps = [
- "../:rtc_base_approved",
- "../../system_wrappers:field_trial",
- "//third_party/abseil-cpp/absl/types:optional",
- ]
-}
-
rtc_static_library("quality_scaling_experiment") {
sources = [
"quality_scaling_experiment.cc",
@@ -109,29 +115,47 @@
]
}
+rtc_static_library("rate_control_settings") {
+ sources = [
+ "rate_control_settings.cc",
+ "rate_control_settings.h",
+ ]
+ deps = [
+ ":field_trial_parser",
+ "../:rtc_base_approved",
+ "../../api/transport:field_trial_based_config",
+ "../../api/transport:webrtc_key_value_config",
+ "../../api/video_codecs:video_codecs_api",
+ "../../system_wrappers:field_trial",
+ "//third_party/abseil-cpp/absl/memory:memory",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
if (rtc_include_tests) {
rtc_source_set("experiments_unittests") {
testonly = true
sources = [
- "congestion_controller_experiment_unittest.cc",
"cpu_speed_experiment_unittest.cc",
"field_trial_parser_unittest.cc",
"field_trial_units_unittest.cc",
"normalize_simulcast_size_experiment_unittest.cc",
"quality_scaling_experiment_unittest.cc",
+ "rate_control_settings_unittest.cc",
"rtt_mult_experiment_unittest.cc",
]
deps = [
- ":congestion_controller_experiment",
":cpu_speed_experiment",
":field_trial_parser",
":normalize_simulcast_size_experiment",
":quality_scaling_experiment",
+ ":rate_control_settings",
":rtt_mult_experiment",
"..:gunit_helpers",
"../:rtc_base_tests_main",
"../:rtc_base_tests_utils",
+ "../../api/video_codecs:video_codecs_api",
"../../system_wrappers:field_trial",
"../../test:field_trial",
"../../test:test_support",
diff --git a/rtc_base/experiments/OWNERS b/rtc_base/experiments/OWNERS
index 9c55872..c31e020 100644
--- a/rtc_base/experiments/OWNERS
+++ b/rtc_base/experiments/OWNERS
@@ -1,4 +1,5 @@
per-file alr_experiment*=sprang@webrtc.org
+per-file audio_allocation_settings*=srte@webrtc.org
per-file congestion_controller_experiment*=srte@webrtc.org
per-file cpu_speed_experiment*=asapersson@webrtc.org
per-file field_trial*=srte@webrtc.org
@@ -6,3 +7,5 @@
per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org
per-file quality_scaling_experiment*=asapersson@webrtc.org
per-file rtt_mult_experiment*=mhoro@webrtc.org
+per-file rate_control_settings*=sprang@webrtc.org
+per-file rate_control_settings*=srte@webrtc.org
diff --git a/rtc_base/experiments/audio_allocation_settings.cc b/rtc_base/experiments/audio_allocation_settings.cc
new file mode 100644
index 0000000..a505357
--- /dev/null
+++ b/rtc_base/experiments/audio_allocation_settings.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright 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 "rtc_base/experiments/audio_allocation_settings.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+// For SendSideBwe, Opus bitrate should be in the range between 6000 and 32000.
+const int kOpusMinBitrateBps = 6000;
+const int kOpusBitrateFbBps = 32000;
+// OverheadPerPacket = Ipv4(20B) + UDP(8B) + SRTP(10B) + RTP(12)
+constexpr int kOverheadPerPacket = 20 + 8 + 10 + 12;
+} // namespace
+AudioAllocationSettings::AudioAllocationSettings()
+ : audio_send_side_bwe_("Enabled"),
+ allocate_audio_without_feedback_("Enabled"),
+ force_no_audio_feedback_("Enabled"),
+ audio_feedback_to_improve_video_bwe_("Enabled"),
+ send_side_bwe_with_overhead_("Enabled"),
+ default_min_bitrate_("min", DataRate::bps(kOpusMinBitrateBps)),
+ default_max_bitrate_("max", DataRate::bps(kOpusBitrateFbBps)),
+ priority_bitrate_("prio", DataRate::Zero()) {
+ ParseFieldTrial({&audio_send_side_bwe_},
+ field_trial::FindFullName("WebRTC-Audio-SendSideBwe"));
+ ParseFieldTrial({&allocate_audio_without_feedback_},
+ field_trial::FindFullName("WebRTC-Audio-ABWENoTWCC"));
+ ParseFieldTrial({&force_no_audio_feedback_},
+ field_trial::FindFullName("WebRTC-Audio-ForceNoTWCC"));
+ ParseFieldTrial(
+ {&audio_feedback_to_improve_video_bwe_},
+ field_trial::FindFullName("WebRTC-Audio-SendSideBwe-For-Video"));
+
+ ParseFieldTrial({&send_side_bwe_with_overhead_},
+ field_trial::FindFullName("WebRTC-SendSideBwe-WithOverhead"));
+ ParseFieldTrial(
+ {&default_min_bitrate_, &default_max_bitrate_, &priority_bitrate_},
+ field_trial::FindFullName("WebRTC-Audio-Allocation"));
+
+ // TODO(mflodman): Keep testing this and set proper values.
+ // Note: This is an early experiment currently only supported by Opus.
+ if (send_side_bwe_with_overhead_) {
+ constexpr int kMaxPacketSizeMs = WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60;
+ min_overhead_bps_ = kOverheadPerPacket * 8 * 1000 / kMaxPacketSizeMs;
+ }
+}
+
+AudioAllocationSettings::~AudioAllocationSettings() {}
+
+bool AudioAllocationSettings::ForceNoAudioFeedback() const {
+ return force_no_audio_feedback_;
+}
+
+bool AudioAllocationSettings::IgnoreSeqNumIdChange() const {
+ return !audio_send_side_bwe_;
+}
+
+bool AudioAllocationSettings::ConfigureRateAllocationRange() const {
+ return audio_send_side_bwe_;
+}
+
+bool AudioAllocationSettings::ShouldSendTransportSequenceNumber(
+ int transport_seq_num_extension_header_id) const {
+ if (force_no_audio_feedback_)
+ return false;
+ return audio_send_side_bwe_ && !allocate_audio_without_feedback_ &&
+ transport_seq_num_extension_header_id != 0;
+}
+
+bool AudioAllocationSettings::UpdateAudioTargetBitrate(
+ int transport_seq_num_extension_header_id) const {
+ // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is
+ // not enabled, do not update target audio bitrate if we are in
+ // WebRTC-Audio-SendSideBwe-For-Video experiment
+ if (allocate_audio_without_feedback_ ||
+ transport_seq_num_extension_header_id != 0)
+ return true;
+ if (audio_feedback_to_improve_video_bwe_)
+ return false;
+ return true;
+}
+
+bool AudioAllocationSettings::IncludeAudioInAllocationOnStart(
+ int min_bitrate_bps,
+ int max_bitrate_bps,
+ bool has_dscp,
+ int transport_seq_num_extension_header_id) const {
+ if (has_dscp || min_bitrate_bps == -1 || max_bitrate_bps == -1)
+ return false;
+ if (transport_seq_num_extension_header_id != 0 && !force_no_audio_feedback_)
+ return true;
+ if (allocate_audio_without_feedback_)
+ return true;
+ if (audio_send_side_bwe_)
+ return false;
+ return true;
+}
+
+bool AudioAllocationSettings::IncludeAudioInAllocationOnReconfigure(
+ int min_bitrate_bps,
+ int max_bitrate_bps,
+ bool has_dscp,
+ int transport_seq_num_extension_header_id) const {
+ // TODO(srte): Make this match include_audio_in_allocation_on_start.
+ if (has_dscp || min_bitrate_bps == -1 || max_bitrate_bps == -1)
+ return false;
+ if (transport_seq_num_extension_header_id != 0)
+ return true;
+ if (audio_send_side_bwe_)
+ return false;
+ return true;
+}
+
+int AudioAllocationSettings::MinBitrateBps() const {
+ return default_min_bitrate_->bps() + min_overhead_bps_;
+}
+
+int AudioAllocationSettings::MaxBitrateBps(
+ absl::optional<int> rtp_parameter_max_bitrate_bps) const {
+ // We assume that the max is a hard limit on the payload bitrate, so we add
+ // min_overhead_bps to it to ensure that, when overhead is deducted, the
+ // payload rate never goes beyond the limit. Note: this also means that if a
+ // higher overhead is forced, we cannot reach the limit.
+ // TODO(minyue): Reconsider this when the signaling to BWE is done
+ // through a dedicated API.
+
+ // This means that when RtpParameters is reset, we may change the
+ // encoder's bit rate immediately (through ReconfigureAudioSendStream()),
+ // meanwhile change the cap to the output of BWE.
+ if (rtp_parameter_max_bitrate_bps)
+ return *rtp_parameter_max_bitrate_bps + min_overhead_bps_;
+ return default_max_bitrate_->bps() + min_overhead_bps_;
+}
+DataRate AudioAllocationSettings::DefaultPriorityBitrate() const {
+ DataRate max_overhead = DataRate::Zero();
+ if (send_side_bwe_with_overhead_) {
+ const TimeDelta kMinPacketDuration = TimeDelta::ms(20);
+ max_overhead = DataSize::bytes(kOverheadPerPacket) / kMinPacketDuration;
+ }
+ return priority_bitrate_.Get() + max_overhead;
+}
+
+} // namespace webrtc
diff --git a/rtc_base/experiments/audio_allocation_settings.h b/rtc_base/experiments/audio_allocation_settings.h
new file mode 100644
index 0000000..f05b4a3
--- /dev/null
+++ b/rtc_base/experiments/audio_allocation_settings.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.
+ */
+#ifndef RTC_BASE_EXPERIMENTS_AUDIO_ALLOCATION_SETTINGS_H_
+#define RTC_BASE_EXPERIMENTS_AUDIO_ALLOCATION_SETTINGS_H_
+
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/experiments/field_trial_units.h"
+namespace webrtc {
+// This class encapsulates the logic that controls how allocation of audio
+// bitrate is done. This is primarily based on field trials, but also on the
+// values of audio parameters.
+class AudioAllocationSettings {
+ public:
+ AudioAllocationSettings();
+ ~AudioAllocationSettings();
+ // Returns true if audio feedback should be force disabled.
+ bool ForceNoAudioFeedback() const;
+ // Returns true if changes in transport sequence number id should be ignored
+ // as a trigger for reconfiguration.
+ bool IgnoreSeqNumIdChange() const;
+ // Returns true if the bitrate allocation range should be configured.
+ bool ConfigureRateAllocationRange() const;
+ // Returns true if sent audio packets should have transport wide sequence
+ // numbers.
+ // |transport_seq_num_extension_header_id| the extension header id for
+ // transport sequence numbers. Set to 0 if not the extension is not
+ // configured.
+ bool ShouldSendTransportSequenceNumber(
+ int transport_seq_num_extension_header_id) const;
+ // Returns true if target bitrate for audio streams should be updated.
+ // |transport_seq_num_extension_header_id| the extension header id for
+ // transport sequence numbers. Set to 0 if not the extension is not
+ // configured.
+ bool UpdateAudioTargetBitrate(
+ int transport_seq_num_extension_header_id) const;
+ // Returns true if audio should be added to rate allocation when the audio
+ // stream is started.
+ // |min_bitrate_bps| the configured min bitrate, set to -1 if unset.
+ // |max_bitrate_bps| the configured max bitrate, set to -1 if unset.
+ // |has_dscp| true is dscp is enabled.
+ // |transport_seq_num_extension_header_id| the extension header id for
+ // transport sequence numbers. Set to 0 if not the extension is not
+ // configured.
+ bool IncludeAudioInAllocationOnStart(
+ int min_bitrate_bps,
+ int max_bitrate_bps,
+ bool has_dscp,
+ int transport_seq_num_extension_header_id) const;
+ // Returns true if audio should be added to rate allocation when the audio
+ // stream is reconfigured.
+ // |min_bitrate_bps| the configured min bitrate, set to -1 if unset.
+ // |max_bitrate_bps| the configured max bitrate, set to -1 if unset.
+ // |has_dscp| true is dscp is enabled.
+ // |transport_seq_num_extension_header_id| the extension header id for
+ // transport sequence numbers. Set to 0 if not the extension is not
+ // configured.
+ bool IncludeAudioInAllocationOnReconfigure(
+ int min_bitrate_bps,
+ int max_bitrate_bps,
+ bool has_dscp,
+ int transport_seq_num_extension_header_id) const;
+
+ // Returns the min bitrate for audio rate allocation, potentially including
+ // overhead.
+ int MinBitrateBps() const;
+ // Returns the max bitrate for audio rate allocation, potentially including
+ // overhead. |rtp_parameter_max_bitrate_bps| max bitrate as configured in rtp
+ // parameters, excluding overhead.
+ int MaxBitrateBps(absl::optional<int> rtp_parameter_max_bitrate_bps) const;
+ // Indicates the default priority bitrate for audio streams. The bitrate
+ // allocator will prioritize audio until it reaches this bitrate and will
+ // divide bitrate evently between audio and video above this bitrate.
+ DataRate DefaultPriorityBitrate() const;
+
+ private:
+ FieldTrialFlag audio_send_side_bwe_;
+ FieldTrialFlag allocate_audio_without_feedback_;
+ FieldTrialFlag force_no_audio_feedback_;
+ FieldTrialFlag audio_feedback_to_improve_video_bwe_;
+ FieldTrialFlag send_side_bwe_with_overhead_;
+ int min_overhead_bps_ = 0;
+ // Default bitrates to use as range if there's no user configured
+ // bitrate range but audio bitrate allocation is enabled.
+ FieldTrialParameter<DataRate> default_min_bitrate_;
+ FieldTrialParameter<DataRate> default_max_bitrate_;
+ FieldTrialParameter<DataRate> priority_bitrate_;
+};
+} // namespace webrtc
+
+#endif // RTC_BASE_EXPERIMENTS_AUDIO_ALLOCATION_SETTINGS_H_
diff --git a/rtc_base/experiments/congestion_controller_experiment.cc b/rtc_base/experiments/congestion_controller_experiment.cc
deleted file mode 100644
index 2b7d776..0000000
--- a/rtc_base/experiments/congestion_controller_experiment.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2018 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 "rtc_base/experiments/congestion_controller_experiment.h"
-
-#include <string>
-
-#include "system_wrappers/include/field_trial.h"
-
-namespace webrtc {
-namespace {
-
-const char kControllerExperiment[] = "WebRTC-BweCongestionController";
-} // namespace
-
-bool CongestionControllerExperiment::BbrControllerEnabled() {
- std::string trial_string =
- webrtc::field_trial::FindFullName(kControllerExperiment);
- return trial_string.find("Enabled,BBR") == 0;
-}
-
-bool CongestionControllerExperiment::InjectedControllerEnabled() {
- std::string trial_string =
- webrtc::field_trial::FindFullName(kControllerExperiment);
- return trial_string.find("Enabled,Injected") == 0;
-}
-} // namespace webrtc
diff --git a/rtc_base/experiments/congestion_controller_experiment.h b/rtc_base/experiments/congestion_controller_experiment.h
deleted file mode 100644
index 1f2d8ae..0000000
--- a/rtc_base/experiments/congestion_controller_experiment.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-#ifndef RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
-#define RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
-
-namespace webrtc {
-class CongestionControllerExperiment {
- public:
- static bool BbrControllerEnabled();
- static bool InjectedControllerEnabled();
-};
-
-} // namespace webrtc
-
-#endif // RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
diff --git a/rtc_base/experiments/congestion_controller_experiment_unittest.cc b/rtc_base/experiments/congestion_controller_experiment_unittest.cc
deleted file mode 100644
index 7f929e6..0000000
--- a/rtc_base/experiments/congestion_controller_experiment_unittest.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2018 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 "rtc_base/experiments/congestion_controller_experiment.h"
-#include "rtc_base/gunit.h"
-#include "test/field_trial.h"
-
-namespace webrtc {
-TEST(CongestionControllerExperimentTest, BbrDisabledByDefault) {
- webrtc::test::ScopedFieldTrials field_trials("");
- EXPECT_FALSE(CongestionControllerExperiment::BbrControllerEnabled());
-}
-
-TEST(CongestionControllerExperimentTest, BbrEnabledByFieldTrial) {
- webrtc::test::ScopedFieldTrials field_trials(
- "WebRTC-BweCongestionController/Enabled,BBR/");
- EXPECT_TRUE(CongestionControllerExperiment::BbrControllerEnabled());
-}
-} // namespace webrtc
diff --git a/rtc_base/experiments/cpu_speed_experiment.cc b/rtc_base/experiments/cpu_speed_experiment.cc
index f39540c..114c27f 100644
--- a/rtc_base/experiments/cpu_speed_experiment.cc
+++ b/rtc_base/experiments/cpu_speed_experiment.cc
@@ -10,6 +10,7 @@
#include "rtc_base/experiments/cpu_speed_experiment.h"
+#include <stdio.h>
#include <string>
#include "rtc_base/logging.h"
diff --git a/rtc_base/experiments/field_trial_parser.cc b/rtc_base/experiments/field_trial_parser.cc
index 936487c..f823b48 100644
--- a/rtc_base/experiments/field_trial_parser.cc
+++ b/rtc_base/experiments/field_trial_parser.cc
@@ -41,9 +41,15 @@
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string trial_string) {
std::map<std::string, FieldTrialParameterInterface*> field_map;
+ FieldTrialParameterInterface* keyless_field = nullptr;
for (FieldTrialParameterInterface* field : fields) {
field->MarkAsUsed();
- field_map[field->Key()] = field;
+ if (field->Key().empty()) {
+ RTC_DCHECK(!keyless_field);
+ keyless_field = field;
+ } else {
+ field_map[field->Key()] = field;
+ }
}
size_t i = 0;
while (i < trial_string.length()) {
@@ -62,6 +68,11 @@
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
<< "' in trial: \"" << trial_string << "\"";
}
+ } else if (!opt_value && keyless_field && !key.empty()) {
+ if (!keyless_field->Parse(key)) {
+ RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
+ << key << "' in trial: \"" << trial_string << "\"";
+ }
} else {
RTC_LOG(LS_INFO) << "No field with key: '" << key
<< "' (found in trial: \"" << trial_string << "\")";
diff --git a/rtc_base/experiments/field_trial_parser.h b/rtc_base/experiments/field_trial_parser.h
index 8bdd9b5..0330f19 100644
--- a/rtc_base/experiments/field_trial_parser.h
+++ b/rtc_base/experiments/field_trial_parser.h
@@ -55,7 +55,7 @@
};
// ParseFieldTrial function parses the given string and fills the given fields
-// with extrated values if available.
+// with extracted values if available.
void ParseFieldTrial(
std::initializer_list<FieldTrialParameterInterface*> fields,
std::string raw_string);
diff --git a/rtc_base/experiments/field_trial_parser_unittest.cc b/rtc_base/experiments/field_trial_parser_unittest.cc
index 0d067f5..806b895 100644
--- a/rtc_base/experiments/field_trial_parser_unittest.cc
+++ b/rtc_base/experiments/field_trial_parser_unittest.cc
@@ -112,6 +112,14 @@
EXPECT_EQ(low.Get(), 20);
EXPECT_EQ(high.Get(), 20);
}
+TEST(FieldTrialParserTest, ReadsValuesFromFieldWithoutKey) {
+ FieldTrialFlag enabled("Enabled");
+ FieldTrialParameter<int> req("", 10);
+ ParseFieldTrial({&enabled, &req}, "Enabled,20");
+ EXPECT_EQ(req.Get(), 20);
+ ParseFieldTrial({&req}, "30");
+ EXPECT_EQ(req.Get(), 30);
+}
TEST(FieldTrialParserTest, ParsesOptionalParameters) {
FieldTrialOptional<int> max_count("c", absl::nullopt);
ParseFieldTrial({&max_count}, "");
diff --git a/rtc_base/experiments/field_trial_units_unittest.cc b/rtc_base/experiments/field_trial_units_unittest.cc
index 57022c2..94cbdb8 100644
--- a/rtc_base/experiments/field_trial_units_unittest.cc
+++ b/rtc_base/experiments/field_trial_units_unittest.cc
@@ -9,9 +9,10 @@
*/
#include <string>
+#include "absl/types/optional.h"
#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/experiments/field_trial_units.h"
-#include "rtc_base/gunit.h"
+#include "test/gtest.h"
namespace webrtc {
namespace {
diff --git a/rtc_base/experiments/jitter_upper_bound_experiment.cc b/rtc_base/experiments/jitter_upper_bound_experiment.cc
index b3e9230..84a17bf 100644
--- a/rtc_base/experiments/jitter_upper_bound_experiment.cc
+++ b/rtc_base/experiments/jitter_upper_bound_experiment.cc
@@ -10,7 +10,7 @@
#include "rtc_base/experiments/jitter_upper_bound_experiment.h"
-#include <algorithm>
+#include <stdio.h>
#include <string>
#include "rtc_base/logging.h"
diff --git a/rtc_base/experiments/normalize_simulcast_size_experiment.cc b/rtc_base/experiments/normalize_simulcast_size_experiment.cc
index 9ce5f57..ddf0683 100644
--- a/rtc_base/experiments/normalize_simulcast_size_experiment.cc
+++ b/rtc_base/experiments/normalize_simulcast_size_experiment.cc
@@ -10,6 +10,7 @@
#include "rtc_base/experiments/normalize_simulcast_size_experiment.h"
+#include <stdio.h>
#include <string>
#include "rtc_base/logging.h"
diff --git a/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc b/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc
index c37b809..34e0742 100644
--- a/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc
+++ b/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc
@@ -10,8 +10,8 @@
#include "rtc_base/experiments/normalize_simulcast_size_experiment.h"
-#include "rtc_base/gunit.h"
#include "test/field_trial.h"
+#include "test/gtest.h"
namespace webrtc {
diff --git a/rtc_base/experiments/quality_scaling_experiment.cc b/rtc_base/experiments/quality_scaling_experiment.cc
index c13de3f..4a50115 100644
--- a/rtc_base/experiments/quality_scaling_experiment.cc
+++ b/rtc_base/experiments/quality_scaling_experiment.cc
@@ -9,6 +9,7 @@
*/
#include "rtc_base/experiments/quality_scaling_experiment.h"
+#include <stdio.h>
#include <string>
#include "rtc_base/logging.h"
diff --git a/rtc_base/experiments/quality_scaling_experiment_unittest.cc b/rtc_base/experiments/quality_scaling_experiment_unittest.cc
index 15aadd6..7a345b6 100644
--- a/rtc_base/experiments/quality_scaling_experiment_unittest.cc
+++ b/rtc_base/experiments/quality_scaling_experiment_unittest.cc
@@ -10,8 +10,8 @@
#include "rtc_base/experiments/quality_scaling_experiment.h"
-#include "rtc_base/gunit.h"
#include "test/field_trial.h"
+#include "test/gtest.h"
namespace webrtc {
namespace {
diff --git a/rtc_base/experiments/rate_control_settings.cc b/rtc_base/experiments/rate_control_settings.cc
new file mode 100644
index 0000000..4e2d745
--- /dev/null
+++ b/rtc_base/experiments/rate_control_settings.cc
@@ -0,0 +1,219 @@
+/*
+ * 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 "rtc_base/experiments/rate_control_settings.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "api/transport/field_trial_based_config.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+namespace {
+
+const char* kCongestionWindowFieldTrialName = "WebRTC-CwndExperiment";
+const int kDefaultAcceptedQueueMs = 250;
+
+const char* kCongestionWindowPushbackFieldTrialName =
+ "WebRTC-CongestionWindowPushback";
+const int kDefaultMinPushbackTargetBitrateBps = 30000;
+
+const char kVp8TrustedRateControllerFieldTrialName[] =
+ "WebRTC-LibvpxVp8TrustedRateController";
+const char kVp9TrustedRateControllerFieldTrialName[] =
+ "WebRTC-LibvpxVp9TrustedRateController";
+
+const char* kVideoHysteresisFieldTrialname =
+ "WebRTC-SimulcastUpswitchHysteresisPercent";
+const double kDefaultVideoHysteresisFactor = 1.0;
+const char* kScreenshareHysteresisFieldTrialname =
+ "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent";
+// Default to 35% hysteresis for simulcast screenshare.
+const double kDefaultScreenshareHysteresisFactor = 1.35;
+
+absl::optional<int> MaybeReadCwndExperimentParameter(
+ const WebRtcKeyValueConfig* const key_value_config) {
+ int64_t accepted_queue_ms;
+ std::string experiment_string =
+ key_value_config->Lookup(kCongestionWindowFieldTrialName);
+ int parsed_values =
+ sscanf(experiment_string.c_str(), "Enabled-%" PRId64, &accepted_queue_ms);
+ if (parsed_values == 1) {
+ RTC_CHECK_GE(accepted_queue_ms, 0)
+ << "Accepted must be greater than or equal to 0.";
+ return rtc::checked_cast<int>(accepted_queue_ms);
+ } else if (experiment_string.find("Enabled") == 0) {
+ return kDefaultAcceptedQueueMs;
+ }
+ return absl::nullopt;
+}
+
+absl::optional<int> MaybeReadCongestionWindowPushbackExperimentParameter(
+ const WebRtcKeyValueConfig* const key_value_config) {
+ uint32_t min_pushback_target_bitrate_bps;
+ std::string experiment_string =
+ key_value_config->Lookup(kCongestionWindowPushbackFieldTrialName);
+ int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%" PRIu32,
+ &min_pushback_target_bitrate_bps);
+ if (parsed_values == 1) {
+ RTC_CHECK_GE(min_pushback_target_bitrate_bps, 0)
+ << "Min pushback target bitrate must be greater than or equal to 0.";
+ return rtc::checked_cast<int>(min_pushback_target_bitrate_bps);
+ } else if (experiment_string.find("Enabled") == 0) {
+ return kDefaultMinPushbackTargetBitrateBps;
+ }
+ return absl::nullopt;
+}
+
+bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config,
+ absl::string_view key) {
+ return key_value_config->Lookup(key).find("Enabled") == 0;
+}
+
+double ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config,
+ absl::string_view key,
+ double default_value) {
+ std::string group_name = key_value_config->Lookup(key);
+ int percent = 0;
+ if (!group_name.empty() && sscanf(group_name.c_str(), "%d", &percent) == 1 &&
+ percent >= 0) {
+ return 1.0 + (percent / 100.0);
+ }
+ return default_value;
+}
+
+} // namespace
+
+RateControlSettings::RateControlSettings(
+ const WebRtcKeyValueConfig* const key_value_config)
+ : congestion_window_("cwnd",
+ MaybeReadCwndExperimentParameter(key_value_config)),
+ congestion_window_pushback_(
+ "cwnd_pushback",
+ MaybeReadCongestionWindowPushbackExperimentParameter(
+ key_value_config)),
+ pacing_factor_("pacing_factor"),
+ alr_probing_("alr_probing", false),
+ trust_vp8_(
+ "trust_vp8",
+ IsEnabled(key_value_config, kVp8TrustedRateControllerFieldTrialName)),
+ trust_vp9_(
+ "trust_vp9",
+ IsEnabled(key_value_config, kVp9TrustedRateControllerFieldTrialName)),
+ video_hysteresis_("video_hysteresis",
+ ParseHysteresisFactor(key_value_config,
+ kVideoHysteresisFieldTrialname,
+ kDefaultVideoHysteresisFactor)),
+ screenshare_hysteresis_(
+ "screenshare_hysteresis",
+ ParseHysteresisFactor(key_value_config,
+ kScreenshareHysteresisFieldTrialname,
+ kDefaultScreenshareHysteresisFactor)),
+ probe_max_allocation_("probe_max_allocation", true),
+ bitrate_adjuster_("bitrate_adjuster", false),
+ vp8_s0_boost_("vp8_s0_boost", true) {
+ ParseFieldTrial({&congestion_window_, &congestion_window_pushback_,
+ &pacing_factor_, &alr_probing_, &trust_vp8_, &trust_vp9_,
+ &video_hysteresis_, &screenshare_hysteresis_,
+ &probe_max_allocation_, &bitrate_adjuster_, &vp8_s0_boost_},
+ key_value_config->Lookup("WebRTC-VideoRateControl"));
+}
+
+RateControlSettings::~RateControlSettings() = default;
+RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
+
+RateControlSettings RateControlSettings::ParseFromFieldTrials() {
+ FieldTrialBasedConfig field_trial_config;
+ return RateControlSettings(&field_trial_config);
+}
+
+RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
+ const WebRtcKeyValueConfig* const key_value_config) {
+ FieldTrialBasedConfig field_trial_config;
+ return RateControlSettings(key_value_config ? key_value_config
+ : &field_trial_config);
+}
+
+bool RateControlSettings::UseCongestionWindow() const {
+ return congestion_window_;
+}
+
+int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
+ return congestion_window_.GetOptional().value_or(kDefaultAcceptedQueueMs);
+}
+
+bool RateControlSettings::UseCongestionWindowPushback() const {
+ return congestion_window_ && congestion_window_pushback_;
+}
+
+uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
+ const {
+ return congestion_window_pushback_.GetOptional().value_or(
+ kDefaultMinPushbackTargetBitrateBps);
+}
+
+absl::optional<double> RateControlSettings::GetPacingFactor() const {
+ return pacing_factor_.GetOptional();
+}
+
+bool RateControlSettings::UseAlrProbing() const {
+ return alr_probing_.Get();
+}
+
+bool RateControlSettings::LibvpxVp8TrustedRateController() const {
+ return trust_vp8_.Get();
+}
+
+bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
+ return vp8_s0_boost_.Get();
+}
+
+bool RateControlSettings::LibvpxVp9TrustedRateController() const {
+ return trust_vp9_.Get();
+}
+
+double RateControlSettings::GetSimulcastHysteresisFactor(
+ VideoCodecMode mode) const {
+ if (mode == VideoCodecMode::kScreensharing) {
+ return GetSimulcastScreenshareHysteresisFactor();
+ }
+ return GetSimulcastVideoHysteresisFactor();
+}
+
+double RateControlSettings::GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType content_type) const {
+ if (content_type == VideoEncoderConfig::ContentType::kScreen) {
+ return GetSimulcastScreenshareHysteresisFactor();
+ }
+ return GetSimulcastVideoHysteresisFactor();
+}
+
+double RateControlSettings::GetSimulcastVideoHysteresisFactor() const {
+ return video_hysteresis_.Get();
+}
+
+double RateControlSettings::GetSimulcastScreenshareHysteresisFactor() const {
+ return screenshare_hysteresis_.Get();
+}
+
+bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const {
+ return probe_max_allocation_.Get();
+}
+
+bool RateControlSettings::UseEncoderBitrateAdjuster() const {
+ return bitrate_adjuster_.Get();
+}
+
+} // namespace webrtc
diff --git a/rtc_base/experiments/rate_control_settings.h b/rtc_base/experiments/rate_control_settings.h
new file mode 100644
index 0000000..0898f9b
--- /dev/null
+++ b/rtc_base/experiments/rate_control_settings.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#ifndef RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
+#define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
+
+#include "absl/types/optional.h"
+#include "api/transport/webrtc_key_value_config.h"
+#include "api/video_codecs/video_codec.h"
+#include "api/video_codecs/video_encoder_config.h"
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/experiments/field_trial_units.h"
+
+namespace webrtc {
+
+class RateControlSettings final {
+ public:
+ ~RateControlSettings();
+ RateControlSettings(RateControlSettings&&);
+
+ static RateControlSettings ParseFromFieldTrials();
+ static RateControlSettings ParseFromKeyValueConfig(
+ const WebRtcKeyValueConfig* const key_value_config);
+
+ // When CongestionWindowPushback is enabled, the pacer is oblivious to
+ // the congestion window. The relation between outstanding data and
+ // the congestion window affects encoder allocations directly.
+ bool UseCongestionWindow() const;
+ int64_t GetCongestionWindowAdditionalTimeMs() const;
+ bool UseCongestionWindowPushback() const;
+ uint32_t CongestionWindowMinPushbackTargetBitrateBps() const;
+
+ absl::optional<double> GetPacingFactor() const;
+ bool UseAlrProbing() const;
+
+ bool LibvpxVp8TrustedRateController() const;
+ bool Vp8BoostBaseLayerQuality() const;
+ bool LibvpxVp9TrustedRateController() const;
+
+ // TODO(bugs.webrtc.org/10272): Remove one of these when we have merged
+ // VideoCodecMode and VideoEncoderConfig::ContentType.
+ double GetSimulcastHysteresisFactor(VideoCodecMode mode) const;
+ double GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType content_type) const;
+
+ bool TriggerProbeOnMaxAllocatedBitrateChange() const;
+ bool UseEncoderBitrateAdjuster() const;
+
+ private:
+ explicit RateControlSettings(
+ const WebRtcKeyValueConfig* const key_value_config);
+
+ double GetSimulcastVideoHysteresisFactor() const;
+ double GetSimulcastScreenshareHysteresisFactor() const;
+
+ FieldTrialOptional<int> congestion_window_;
+ FieldTrialOptional<int> congestion_window_pushback_;
+ FieldTrialOptional<double> pacing_factor_;
+ FieldTrialParameter<bool> alr_probing_;
+ FieldTrialParameter<bool> trust_vp8_;
+ FieldTrialParameter<bool> trust_vp9_;
+ FieldTrialParameter<double> video_hysteresis_;
+ FieldTrialParameter<double> screenshare_hysteresis_;
+ FieldTrialParameter<bool> probe_max_allocation_;
+ FieldTrialParameter<bool> bitrate_adjuster_;
+ FieldTrialParameter<bool> vp8_s0_boost_;
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
diff --git a/rtc_base/experiments/rate_control_settings_unittest.cc b/rtc_base/experiments/rate_control_settings_unittest.cc
new file mode 100644
index 0000000..0d8c376
--- /dev/null
+++ b/rtc_base/experiments/rate_control_settings_unittest.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright 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 "rtc_base/experiments/rate_control_settings.h"
+
+#include "api/video_codecs/video_codec.h"
+#include "api/video_codecs/video_encoder_config.h"
+#include "test/field_trial.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+TEST(RateControlSettingsTest, CongestionWindow) {
+ EXPECT_FALSE(
+ RateControlSettings::ParseFromFieldTrials().UseCongestionWindow());
+
+ test::ScopedFieldTrials field_trials("WebRTC-VideoRateControl/cwnd:100/");
+ const RateControlSettings settings_after =
+ RateControlSettings::ParseFromFieldTrials();
+ EXPECT_TRUE(settings_after.UseCongestionWindow());
+ EXPECT_EQ(settings_after.GetCongestionWindowAdditionalTimeMs(), 100);
+}
+
+TEST(RateControlSettingsTest, CongestionWindowPushback) {
+ EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials()
+ .UseCongestionWindowPushback());
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/cwnd:100,cwnd_pushback:100000/");
+ const RateControlSettings settings_after =
+ RateControlSettings::ParseFromFieldTrials();
+ EXPECT_TRUE(settings_after.UseCongestionWindowPushback());
+ EXPECT_EQ(settings_after.CongestionWindowMinPushbackTargetBitrateBps(),
+ 100000u);
+}
+
+TEST(RateControlSettingsTest, PacingFactor) {
+ EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().GetPacingFactor());
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/pacing_factor:1.2/");
+ const RateControlSettings settings_after =
+ RateControlSettings::ParseFromFieldTrials();
+ // Need to explicitly dereference the absl::optional
+ // for the EXPECT_DOUBLE_EQ to compile.
+ ASSERT_TRUE(settings_after.GetPacingFactor());
+ EXPECT_DOUBLE_EQ(*settings_after.GetPacingFactor(), 1.2);
+}
+
+TEST(RateControlSettingsTest, AlrProbing) {
+ EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().UseAlrProbing());
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/alr_probing:1/");
+ EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials().UseAlrProbing());
+}
+
+TEST(RateControlSettingsTest, LibvpxTrustedRateController) {
+ const RateControlSettings settings_before =
+ RateControlSettings::ParseFromFieldTrials();
+ EXPECT_FALSE(settings_before.LibvpxVp8TrustedRateController());
+ EXPECT_FALSE(settings_before.LibvpxVp9TrustedRateController());
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/trust_vp8:1,trust_vp9:1/");
+ const RateControlSettings settings_after =
+ RateControlSettings::ParseFromFieldTrials();
+ EXPECT_TRUE(settings_after.LibvpxVp8TrustedRateController());
+ EXPECT_TRUE(settings_after.LibvpxVp9TrustedRateController());
+}
+
+TEST(RateControlSettingsTest, GetSimulcastHysteresisFactor) {
+ const RateControlSettings settings_before =
+ RateControlSettings::ParseFromFieldTrials();
+ EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor(
+ VideoCodecMode::kRealtimeVideo),
+ 1.0);
+ EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType::kRealtimeVideo),
+ 1.0);
+ EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor(
+ VideoCodecMode::kScreensharing),
+ 1.35);
+ EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType::kScreen),
+ 1.35);
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/"
+ "video_hysteresis:1.2,screenshare_hysteresis:1.4/");
+ const RateControlSettings settings_after =
+ RateControlSettings::ParseFromFieldTrials();
+
+ EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor(
+ VideoCodecMode::kRealtimeVideo),
+ 1.2);
+ EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType::kRealtimeVideo),
+ 1.2);
+ EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor(
+ VideoCodecMode::kScreensharing),
+ 1.4);
+ EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor(
+ VideoEncoderConfig::ContentType::kScreen),
+ 1.4);
+}
+
+TEST(RateControlSettingsTest, TriggerProbeOnMaxAllocatedBitrateChange) {
+ EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials()
+ .TriggerProbeOnMaxAllocatedBitrateChange());
+
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/probe_max_allocation:0/");
+ EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials()
+ .TriggerProbeOnMaxAllocatedBitrateChange());
+}
+
+TEST(RateControlSettingsTest, UseEncoderBitrateAdjuster) {
+ // Should be off by default.
+ EXPECT_FALSE(
+ RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster());
+
+ {
+ // Can be turned on via field trial.
+ test::ScopedFieldTrials field_trials(
+ "WebRTC-VideoRateControl/bitrate_adjuster:true/");
+ EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials()
+ .UseEncoderBitrateAdjuster());
+ }
+}
+
+} // namespace
+
+} // namespace webrtc
diff --git a/rtc_base/experiments/rtt_mult_experiment.cc b/rtc_base/experiments/rtt_mult_experiment.cc
index f8f7f2a..beb577c 100644
--- a/rtc_base/experiments/rtt_mult_experiment.cc
+++ b/rtc_base/experiments/rtt_mult_experiment.cc
@@ -9,6 +9,7 @@
*/
#include "rtc_base/experiments/rtt_mult_experiment.h"
+#include <stdio.h>
#include <algorithm>
#include <string>
diff --git a/rtc_base/experiments/rtt_mult_experiment_unittest.cc b/rtc_base/experiments/rtt_mult_experiment_unittest.cc
index 0cd86d1..9442cea 100644
--- a/rtc_base/experiments/rtt_mult_experiment_unittest.cc
+++ b/rtc_base/experiments/rtt_mult_experiment_unittest.cc
@@ -9,8 +9,9 @@
*/
#include "rtc_base/experiments/rtt_mult_experiment.h"
-#include "rtc_base/gunit.h"
+
#include "test/field_trial.h"
+#include "test/gtest.h"
namespace webrtc {
diff --git a/rtc_base/fakeclock.cc b/rtc_base/fake_clock.cc
similarity index 94%
rename from rtc_base/fakeclock.cc
rename to rtc_base/fake_clock.cc
index f63b85c..6b7d96b 100644
--- a/rtc_base/fakeclock.cc
+++ b/rtc_base/fake_clock.cc
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/checks.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_queue.h"
namespace rtc {
diff --git a/rtc_base/fakeclock.h b/rtc_base/fake_clock.h
similarity index 87%
rename from rtc_base/fakeclock.h
rename to rtc_base/fake_clock.h
index 2da8c61..5ccf370 100644
--- a/rtc_base/fakeclock.h
+++ b/rtc_base/fake_clock.h
@@ -8,12 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_FAKECLOCK_H_
-#define RTC_BASE_FAKECLOCK_H_
+#ifndef RTC_BASE_FAKE_CLOCK_H_
+#define RTC_BASE_FAKE_CLOCK_H_
+
+#include <stdint.h>
#include "api/units/time_delta.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/thread_annotations.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
@@ -69,4 +72,4 @@
} // namespace rtc
-#endif // RTC_BASE_FAKECLOCK_H_
+#endif // RTC_BASE_FAKE_CLOCK_H_
diff --git a/rtc_base/fake_mdns_responder.h b/rtc_base/fake_mdns_responder.h
index 1e60a5d..4290876 100644
--- a/rtc_base/fake_mdns_responder.h
+++ b/rtc_base/fake_mdns_responder.h
@@ -15,9 +15,11 @@
#include <memory>
#include <string>
+#include "rtc_base/async_invoker.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/location.h"
#include "rtc_base/mdns_responder_interface.h"
-
-#include "rtc_base/helpers.h"
+#include "rtc_base/thread.h"
namespace webrtc {
@@ -50,6 +52,15 @@
[callback, result]() { callback(result); });
}
+ rtc::IPAddress GetMappedAddressForName(const std::string& name) const {
+ for (const auto& addr_name_pair : addr_name_map_) {
+ if (addr_name_pair.second == name) {
+ return addr_name_pair.first;
+ }
+ }
+ return rtc::IPAddress();
+ }
+
private:
uint32_t next_available_id_ = 0;
std::map<rtc::IPAddress, std::string> addr_name_map_;
diff --git a/rtc_base/fakenetwork.h b/rtc_base/fake_network.h
similarity index 85%
rename from rtc_base/fakenetwork.h
rename to rtc_base/fake_network.h
index cb890ec..1da9814 100644
--- a/rtc_base/fakenetwork.h
+++ b/rtc_base/fake_network.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_FAKENETWORK_H_
-#define RTC_BASE_FAKENETWORK_H_
+#ifndef RTC_BASE_FAKE_NETWORK_H_
+#define RTC_BASE_FAKE_NETWORK_H_
#include <memory>
#include <string>
@@ -19,10 +19,10 @@
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
#include "rtc_base/fake_mdns_responder.h"
-#include "rtc_base/messagehandler.h"
+#include "rtc_base/message_handler.h"
#include "rtc_base/network.h"
-#include "rtc_base/socketaddress.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/string_encode.h"
#include "rtc_base/thread.h"
namespace rtc {
@@ -65,7 +65,7 @@
DoUpdateNetworks();
}
- virtual void StartUpdating() {
+ void StartUpdating() override {
++start_count_;
if (start_count_ == 1) {
sent_first_update_ = false;
@@ -77,25 +77,30 @@
}
}
- virtual void StopUpdating() { --start_count_; }
+ void StopUpdating() override { --start_count_; }
// MessageHandler interface.
- virtual void OnMessage(Message* msg) { DoUpdateNetworks(); }
+ void OnMessage(Message* msg) override { DoUpdateNetworks(); }
- void CreateMdnsResponder() {
+ void CreateMdnsResponder(rtc::Thread* network_thread) {
if (mdns_responder_ == nullptr) {
mdns_responder_ =
- absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current());
+ absl::make_unique<webrtc::FakeMdnsResponder>(network_thread);
}
}
using NetworkManagerBase::set_enumeration_permission;
using NetworkManagerBase::set_default_local_addresses;
+ // rtc::NetworkManager override.
webrtc::MdnsResponderInterface* GetMdnsResponder() const override {
return mdns_responder_.get();
}
+ webrtc::FakeMdnsResponder* GetMdnsResponderForTesting() const {
+ return mdns_responder_.get();
+ }
+
private:
void DoUpdateNetworks() {
if (start_count_ == 0)
@@ -129,12 +134,9 @@
int start_count_ = 0;
bool sent_first_update_ = false;
- IPAddress default_local_ipv4_address_;
- IPAddress default_local_ipv6_address_;
-
std::unique_ptr<webrtc::FakeMdnsResponder> mdns_responder_;
};
} // namespace rtc
-#endif // RTC_BASE_FAKENETWORK_H_
+#endif // RTC_BASE_FAKE_NETWORK_H_
diff --git a/rtc_base/fakesslidentity.cc b/rtc_base/fake_ssl_identity.cc
similarity index 96%
rename from rtc_base/fakesslidentity.cc
rename to rtc_base/fake_ssl_identity.cc
index 62ac9dd..480922c 100644
--- a/rtc_base/fakesslidentity.cc
+++ b/rtc_base/fake_ssl_identity.cc
@@ -8,15 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/fakesslidentity.h"
+#include "rtc_base/fake_ssl_identity.h"
-#include <algorithm>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
-#include "rtc_base/messagedigest.h"
+#include "rtc_base/message_digest.h"
namespace rtc {
@@ -76,6 +75,7 @@
FakeSSLIdentity::FakeSSLIdentity(const std::vector<std::string>& pem_strings) {
std::vector<std::unique_ptr<SSLCertificate>> certs;
+ certs.reserve(pem_strings.size());
for (const std::string& pem_string : pem_strings) {
certs.push_back(absl::make_unique<FakeSSLCertificate>(pem_string));
}
diff --git a/rtc_base/fakesslidentity.h b/rtc_base/fake_ssl_identity.h
similarity index 92%
rename from rtc_base/fakesslidentity.h
rename to rtc_base/fake_ssl_identity.h
index b19cbfb..c3a8d1f 100644
--- a/rtc_base/fakesslidentity.h
+++ b/rtc_base/fake_ssl_identity.h
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_FAKESSLIDENTITY_H_
-#define RTC_BASE_FAKESSLIDENTITY_H_
+#ifndef RTC_BASE_FAKE_SSL_IDENTITY_H_
+#define RTC_BASE_FAKE_SSL_IDENTITY_H_
#include <memory>
#include <vector>
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
namespace rtc {
@@ -78,4 +78,4 @@
} // namespace rtc
-#endif // RTC_BASE_FAKESSLIDENTITY_H_
+#endif // RTC_BASE_FAKE_SSL_IDENTITY_H_
diff --git a/rtc_base/file.cc b/rtc_base/file.cc
deleted file mode 100644
index a793500..0000000
--- a/rtc_base/file.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2016 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 "rtc_base/file.h"
-
-namespace rtc {
-
-File::File(PlatformFile file) : file_(file) {}
-
-File::File() : file_(kInvalidPlatformFileValue) {}
-
-File::~File() {
- Close();
-}
-
-// static
-File File::Open(const std::string& path) {
- return File(OpenPlatformFile(path));
-}
-
-// static
-File File::Create(const std::string& path) {
- return File(CreatePlatformFile(path));
-}
-
-// static
-bool File::Remove(const std::string& path) {
- return RemoveFile(path);
-}
-
-File::File(File&& other) : file_(other.file_) {
- other.file_ = kInvalidPlatformFileValue;
-}
-
-File& File::operator=(File&& other) {
- Close();
- file_ = other.file_;
- other.file_ = kInvalidPlatformFileValue;
- return *this;
-}
-
-bool File::IsOpen() {
- return file_ != kInvalidPlatformFileValue;
-}
-
-} // namespace rtc
diff --git a/rtc_base/file.h b/rtc_base/file.h
deleted file mode 100644
index bc0974a..0000000
--- a/rtc_base/file.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2016 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.
- */
-
-#ifndef RTC_BASE_FILE_H_
-#define RTC_BASE_FILE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <string>
-
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/platform_file.h"
-
-namespace rtc {
-
-// This class wraps the platform specific APIs for simple file interactions.
-//
-// The various read and write methods are best effort, i.e. if an underlying
-// call does not manage to read/write all the data more calls will be performed,
-// until an error is detected or all data is read/written.
-class File {
- public:
- // Wraps the given PlatformFile. This class is then responsible for closing
- // the file, which will be done in the destructor if Close is never called.
- explicit File(PlatformFile);
- // The default constructor produces a closed file.
- File();
- ~File();
-
- File(File&& other);
- File& operator=(File&& other);
-
- // Open and Create give files with both reading and writing enabled.
- static File Open(const std::string& path);
- // If the file already exists it will be overwritten.
- static File Create(const std::string& path);
-
- // Remove a file in the file system.
- static bool Remove(const std::string& path);
-
- size_t Write(const uint8_t* data, size_t length);
- size_t Read(uint8_t* buffer, size_t length);
-
- // The current position in the file after a call to these methods is platform
- // dependent (MSVC gives position offset+length, most other
- // compilers/platforms do not alter the position), i.e. do not depend on it,
- // do a Seek before any subsequent Read/Write.
- size_t WriteAt(const uint8_t* data, size_t length, size_t offset);
- size_t ReadAt(uint8_t* buffer, size_t length, size_t offset);
-
- // Attempt to position the file at the given offset from the start.
- // Returns true if successful, false otherwise.
- bool Seek(size_t offset);
-
- // Attempt to close the file. Returns true if successful, false otherwise,
- // most notably when the file is already closed.
- bool Close();
-
- bool IsOpen();
-
- private:
- PlatformFile file_;
- RTC_DISALLOW_COPY_AND_ASSIGN(File);
-};
-
-} // namespace rtc
-
-#endif // RTC_BASE_FILE_H_
diff --git a/rtc_base/file_posix.cc b/rtc_base/file_posix.cc
deleted file mode 100644
index 4920192..0000000
--- a/rtc_base/file_posix.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2016 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 <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <limits>
-
-#include "rtc_base/checks.h"
-#include "rtc_base/file.h"
-#include "rtc_base/platform_file.h"
-
-namespace rtc {
-
-size_t File::Write(const uint8_t* data, size_t length) {
- size_t total_written = 0;
- do {
- ssize_t written;
- do {
- written = ::write(file_, data + total_written, length - total_written);
- } while (written == -1 && errno == EINTR);
- if (written == -1)
- break;
- total_written += written;
- } while (total_written < length);
- return total_written;
-}
-
-size_t File::Read(uint8_t* buffer, size_t length) {
- size_t total_read = 0;
- do {
- ssize_t read;
- do {
- read = ::read(file_, buffer + total_read, length - total_read);
- } while (read == -1 && errno == EINTR);
- if (read == -1)
- break;
- total_read += read;
- } while (total_read < length);
- return total_read;
-}
-
-size_t File::WriteAt(const uint8_t* data, size_t length, size_t offset) {
- size_t total_written = 0;
- do {
- ssize_t written;
- do {
- written = ::pwrite(file_, data + total_written, length - total_written,
- offset + total_written);
- } while (written == -1 && errno == EINTR);
- if (written == -1)
- break;
- total_written += written;
- } while (total_written < length);
- return total_written;
-}
-
-size_t File::ReadAt(uint8_t* buffer, size_t length, size_t offset) {
- size_t total_read = 0;
- do {
- ssize_t read;
- do {
- read = ::pread(file_, buffer + total_read, length - total_read,
- offset + total_read);
- } while (read == -1 && errno == EINTR);
- if (read == -1)
- break;
- total_read += read;
- } while (total_read < length);
- return total_read;
-}
-
-bool File::Seek(size_t offset) {
- RTC_DCHECK_LE(offset, std::numeric_limits<off_t>::max());
- return lseek(file_, static_cast<off_t>(offset), SEEK_SET) != -1;
-}
-
-bool File::Close() {
- if (file_ == rtc::kInvalidPlatformFileValue)
- return false;
- bool ret = close(file_) == 0;
- file_ = rtc::kInvalidPlatformFileValue;
- return ret;
-}
-
-} // namespace rtc
diff --git a/rtc_base/filerotatingstream.cc b/rtc_base/file_rotating_stream.cc
similarity index 67%
rename from rtc_base/filerotatingstream.cc
rename to rtc_base/file_rotating_stream.cc
index b1dc5ff..86b852f 100644
--- a/rtc_base/filerotatingstream.cc
+++ b/rtc_base/file_rotating_stream.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/filerotatingstream.h"
+#include "rtc_base/file_rotating_stream.h"
#include <algorithm>
#include <cstdio>
@@ -17,7 +17,7 @@
#if defined(WEBRTC_WIN)
#include <windows.h>
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
#else
#include <dirent.h>
#include <sys/stat.h>
@@ -25,6 +25,7 @@
#endif // WEBRTC_WIN
#include "absl/strings/match.h"
+#include "absl/types/optional.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
@@ -35,6 +36,8 @@
namespace {
+const char kCallSessionLogPrefix[] = "webrtc_log";
+
std::string AddTrailingPathDelimiterIfNeeded(std::string directory);
// |dir| must have a trailing delimiter. |prefix| must not include wild card
@@ -167,68 +170,30 @@
} // namespace
FileRotatingStream::FileRotatingStream(const std::string& dir_path,
- const std::string& file_prefix)
- : FileRotatingStream(dir_path, file_prefix, 0, 0, kRead) {}
-
-FileRotatingStream::FileRotatingStream(const std::string& dir_path,
const std::string& file_prefix,
size_t max_file_size,
size_t num_files)
- : FileRotatingStream(dir_path,
- file_prefix,
- max_file_size,
- num_files,
- kWrite) {
- RTC_DCHECK_GT(max_file_size, 0);
- RTC_DCHECK_GT(num_files, 1);
-}
-
-FileRotatingStream::FileRotatingStream(const std::string& dir_path,
- const std::string& file_prefix,
- size_t max_file_size,
- size_t num_files,
- Mode mode)
: dir_path_(AddTrailingPathDelimiterIfNeeded(dir_path)),
file_prefix_(file_prefix),
- mode_(mode),
- file_stream_(nullptr),
max_file_size_(max_file_size),
current_file_index_(0),
rotation_index_(0),
current_bytes_written_(0),
disable_buffering_(false) {
+ RTC_DCHECK_GT(max_file_size, 0);
+ RTC_DCHECK_GT(num_files, 1);
RTC_DCHECK(IsFolder(dir_path));
- switch (mode) {
- case kWrite: {
- file_names_.clear();
- for (size_t i = 0; i < num_files; ++i) {
- file_names_.push_back(GetFilePath(i, num_files));
- }
- rotation_index_ = num_files - 1;
- break;
- }
- case kRead: {
- file_names_ = GetFilesWithPrefix(dir_path_, file_prefix_);
- std::sort(file_names_.begin(), file_names_.end());
- if (file_names_.size() > 0) {
- // |file_names_| is sorted newest first, so read from the end.
- current_file_index_ = file_names_.size() - 1;
- }
- break;
- }
+ file_names_.clear();
+ for (size_t i = 0; i < num_files; ++i) {
+ file_names_.push_back(GetFilePath(i, num_files));
}
+ rotation_index_ = num_files - 1;
}
FileRotatingStream::~FileRotatingStream() {}
StreamState FileRotatingStream::GetState() const {
- if (mode_ == kRead && current_file_index_ < file_names_.size()) {
- return SS_OPEN;
- }
- if (!file_stream_) {
- return SS_CLOSED;
- }
- return file_stream_->GetState();
+ return (file_.is_open() ? SS_OPEN : SS_CLOSED);
}
StreamResult FileRotatingStream::Read(void* buffer,
@@ -236,60 +201,15 @@
size_t* read,
int* error) {
RTC_DCHECK(buffer);
- if (mode_ != kRead) {
- return SR_EOS;
- }
- if (current_file_index_ >= file_names_.size()) {
- return SR_EOS;
- }
- // We will have no file stream initially, and when we are finished with the
- // previous file.
- if (!file_stream_) {
- if (!OpenCurrentFile()) {
- return SR_ERROR;
- }
- }
- int local_error = 0;
- if (!error) {
- error = &local_error;
- }
- StreamResult result = file_stream_->Read(buffer, buffer_len, read, error);
- if (result == SR_EOS || result == SR_ERROR) {
- if (result == SR_ERROR) {
- RTC_LOG(LS_ERROR) << "Failed to read from: "
- << file_names_[current_file_index_]
- << "Error: " << error;
- }
- // Reached the end of the file, read next file. If there is an error return
- // the error status but allow for a next read by reading next file.
- CloseCurrentFile();
- if (current_file_index_ == 0) {
- // Just finished reading the last file, signal EOS by setting index.
- current_file_index_ = file_names_.size();
- } else {
- --current_file_index_;
- }
- if (read) {
- *read = 0;
- }
- return result == SR_EOS ? SR_SUCCESS : result;
- } else if (result == SR_SUCCESS) {
- // Succeeded, continue reading from this file.
- return SR_SUCCESS;
- } else {
- RTC_NOTREACHED();
- }
- return result;
+ RTC_NOTREACHED();
+ return SR_EOS;
}
StreamResult FileRotatingStream::Write(const void* data,
size_t data_len,
size_t* written,
int* error) {
- if (mode_ != kWrite) {
- return SR_EOS;
- }
- if (!file_stream_) {
+ if (!file_.is_open()) {
std::fprintf(stderr, "Open() must be called before Write.\n");
return SR_ERROR;
}
@@ -297,42 +217,31 @@
RTC_DCHECK_LT(current_bytes_written_, max_file_size_);
size_t remaining_bytes = max_file_size_ - current_bytes_written_;
size_t write_length = std::min(data_len, remaining_bytes);
- size_t local_written = 0;
- if (!written) {
- written = &local_written;
- }
- StreamResult result = file_stream_->Write(data, write_length, written, error);
- current_bytes_written_ += *written;
+ if (!file_.Write(data, write_length)) {
+ return SR_ERROR;
+ }
+ if (disable_buffering_ && !file_.Flush()) {
+ return SR_ERROR;
+ }
+
+ current_bytes_written_ += write_length;
+ if (written) {
+ *written = write_length;
+ }
// If we're done with this file, rotate it out.
if (current_bytes_written_ >= max_file_size_) {
RTC_DCHECK_EQ(current_bytes_written_, max_file_size_);
RotateFiles();
}
- return result;
+ return SR_SUCCESS;
}
bool FileRotatingStream::Flush() {
- if (!file_stream_) {
+ if (!file_.is_open()) {
return false;
}
- return file_stream_->Flush();
-}
-
-bool FileRotatingStream::GetSize(size_t* size) const {
- if (mode_ != kRead) {
- // Not possible to get accurate size on disk when writing because of
- // potential buffering.
- return false;
- }
- RTC_DCHECK(size);
- *size = 0;
- size_t total_size = 0;
- for (auto file_name : file_names_) {
- total_size += GetFileSize(file_name).value_or(0);
- }
- *size = total_size;
- return true;
+ return file_.Flush();
}
void FileRotatingStream::Close() {
@@ -340,33 +249,20 @@
}
bool FileRotatingStream::Open() {
- switch (mode_) {
- case kRead:
- // Defer opening to when we first read since we want to return read error
- // if we fail to open next file.
- return true;
- case kWrite: {
- // Delete existing files when opening for write.
- std::vector<std::string> matching_files =
- GetFilesWithPrefix(dir_path_, file_prefix_);
- for (const auto& matching_file : matching_files) {
- if (!DeleteFile(matching_file)) {
- std::fprintf(stderr, "Failed to delete: %s\n", matching_file.c_str());
- }
- }
- return OpenCurrentFile();
+ // Delete existing files when opening for write.
+ std::vector<std::string> matching_files =
+ GetFilesWithPrefix(dir_path_, file_prefix_);
+ for (const auto& matching_file : matching_files) {
+ if (!DeleteFile(matching_file)) {
+ std::fprintf(stderr, "Failed to delete: %s\n", matching_file.c_str());
}
}
- return false;
+ return OpenCurrentFile();
}
bool FileRotatingStream::DisableBuffering() {
disable_buffering_ = true;
- if (!file_stream_) {
- std::fprintf(stderr, "Open() must be called before DisableBuffering().\n");
- return false;
- }
- return file_stream_->DisableBuffering();
+ return true;
}
std::string FileRotatingStream::GetFilePath(size_t index) const {
@@ -380,41 +276,28 @@
// Opens the appropriate file in the appropriate mode.
RTC_DCHECK_LT(current_file_index_, file_names_.size());
std::string file_path = file_names_[current_file_index_];
- file_stream_.reset(new FileStream());
- const char* mode = nullptr;
- switch (mode_) {
- case kWrite:
- mode = "w+";
- // We should always we writing to the zero-th file.
- RTC_DCHECK_EQ(current_file_index_, 0);
- break;
- case kRead:
- mode = "r";
- break;
- }
- int error = 0;
- if (!file_stream_->Open(file_path, mode, &error)) {
- std::fprintf(stderr, "Failed to open: %s Error: %i\n", file_path.c_str(),
+
+ // We should always be writing to the zero-th file.
+ RTC_DCHECK_EQ(current_file_index_, 0);
+ int error;
+ file_ = webrtc::FileWrapper::OpenWriteOnly(file_path, &error);
+ if (!file_.is_open()) {
+ std::fprintf(stderr, "Failed to open: %s Error: %d\n", file_path.c_str(),
error);
- file_stream_.reset();
return false;
}
- if (disable_buffering_) {
- file_stream_->DisableBuffering();
- }
return true;
}
void FileRotatingStream::CloseCurrentFile() {
- if (!file_stream_) {
+ if (!file_.is_open()) {
return;
}
current_bytes_written_ = 0;
- file_stream_.reset();
+ file_.Close();
}
void FileRotatingStream::RotateFiles() {
- RTC_DCHECK_EQ(mode_, kWrite);
CloseCurrentFile();
// Rotates the files by deleting the file at |rotation_index_|, which is the
// oldest file and then renaming the newer files to have an incremented index.
@@ -456,16 +339,10 @@
}
CallSessionFileRotatingStream::CallSessionFileRotatingStream(
- const std::string& dir_path)
- : FileRotatingStream(dir_path, kLogPrefix),
- max_total_log_size_(0),
- num_rotations_(0) {}
-
-CallSessionFileRotatingStream::CallSessionFileRotatingStream(
const std::string& dir_path,
size_t max_total_log_size)
: FileRotatingStream(dir_path,
- kLogPrefix,
+ kCallSessionLogPrefix,
max_total_log_size / 2,
GetNumRotatingLogFiles(max_total_log_size) + 1),
max_total_log_size_(max_total_log_size),
@@ -473,7 +350,6 @@
RTC_DCHECK_GE(max_total_log_size, 4);
}
-const char* CallSessionFileRotatingStream::kLogPrefix = "webrtc_log";
const size_t CallSessionFileRotatingStream::kRotatingLogFileDefaultSize =
1024 * 1024;
@@ -507,4 +383,46 @@
(max_total_log_size / 2) / kRotatingLogFileDefaultSize);
}
+FileRotatingStreamReader::FileRotatingStreamReader(
+ const std::string& dir_path,
+ const std::string& file_prefix) {
+ file_names_ = GetFilesWithPrefix(AddTrailingPathDelimiterIfNeeded(dir_path),
+ file_prefix);
+
+ // Plain sort of the file names would sort by age, i.e., oldest last. Using
+ // std::greater gives us the desired chronological older, oldest first.
+ std::sort(file_names_.begin(), file_names_.end(),
+ std::greater<std::string>());
+}
+
+FileRotatingStreamReader::~FileRotatingStreamReader() = default;
+
+size_t FileRotatingStreamReader::GetSize() const {
+ size_t total_size = 0;
+ for (const auto& file_name : file_names_) {
+ total_size += GetFileSize(file_name).value_or(0);
+ }
+ return total_size;
+}
+
+size_t FileRotatingStreamReader::ReadAll(void* buffer, size_t size) const {
+ size_t done = 0;
+ for (const auto& file_name : file_names_) {
+ if (done < size) {
+ webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(file_name);
+ if (!f.is_open()) {
+ break;
+ }
+ done += f.Read(static_cast<char*>(buffer) + done, size - done);
+ } else {
+ break;
+ }
+ }
+ return done;
+}
+
+CallSessionFileRotatingStreamReader::CallSessionFileRotatingStreamReader(
+ const std::string& dir_path)
+ : FileRotatingStreamReader(dir_path, kCallSessionLogPrefix) {}
+
} // namespace rtc
diff --git a/rtc_base/filerotatingstream.h b/rtc_base/file_rotating_stream.h
similarity index 81%
rename from rtc_base/filerotatingstream.h
rename to rtc_base/file_rotating_stream.h
index c75ee15..78e2983 100644
--- a/rtc_base/filerotatingstream.h
+++ b/rtc_base/file_rotating_stream.h
@@ -8,16 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_FILEROTATINGSTREAM_H_
-#define RTC_BASE_FILEROTATINGSTREAM_H_
+#ifndef RTC_BASE_FILE_ROTATING_STREAM_H_
+#define RTC_BASE_FILE_ROTATING_STREAM_H_
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/stream.h"
+#include "rtc_base/system/file_wrapper.h"
namespace rtc {
@@ -52,8 +53,6 @@
size_t* written,
int* error) override;
bool Flush() override;
- // Returns the total file size currently used on disk.
- bool GetSize(size_t* size) const override;
void Close() override;
// Opens the appropriate file(s). Call this before using the stream.
@@ -83,14 +82,6 @@
virtual void OnRotation() {}
private:
- enum Mode { kRead, kWrite };
-
- FileRotatingStream(const std::string& dir_path,
- const std::string& file_prefix,
- size_t max_file_size,
- size_t num_files,
- Mode mode);
-
bool OpenCurrentFile();
void CloseCurrentFile();
@@ -107,10 +98,9 @@
const std::string dir_path_;
const std::string file_prefix_;
- const Mode mode_;
- // FileStream is used to write to the current file.
- std::unique_ptr<FileStream> file_stream_;
+ // File we're currently writing to.
+ webrtc::FileWrapper file_;
// Convenience storage for file names so we don't generate them over and over.
std::vector<std::string> file_names_;
size_t max_file_size_;
@@ -127,7 +117,7 @@
};
// CallSessionFileRotatingStream is meant to be used in situations where we will
-// have limited disk space. Its purpose is to read and write logs up to a
+// have limited disk space. Its purpose is to write logs up to a
// maximum size. Once the maximum size is exceeded, logs from the middle are
// deleted whereas logs from the beginning and end are preserved. The reason for
// this is because we anticipate that in WebRTC the beginning and end of the
@@ -140,11 +130,11 @@
// (earliest) file on rotate, and that that file's size is bigger.
//
// Open() must be called before using this stream.
+
+// To read the logs produced by this class, one can use the companion class
+// CallSessionFileRotatingStreamReader.
class CallSessionFileRotatingStream : public FileRotatingStream {
public:
- // Use this constructor for reading a directory previously written to with
- // this stream.
- explicit CallSessionFileRotatingStream(const std::string& dir_path);
// Use this constructor for writing to a directory. Files in the directory
// matching what's used by the stream will be deleted. |max_total_log_size|
// must be at least 4.
@@ -158,7 +148,6 @@
private:
static size_t GetRotatingLogSize(size_t max_total_log_size);
static size_t GetNumRotatingLogFiles(size_t max_total_log_size);
- static const char* kLogPrefix;
static const size_t kRotatingLogFileDefaultSize;
const size_t max_total_log_size_;
@@ -167,6 +156,27 @@
RTC_DISALLOW_COPY_AND_ASSIGN(CallSessionFileRotatingStream);
};
+// This is a convenience class, to read all files produced by a
+// FileRotatingStream, all in one go. Typical use calls GetSize and ReadData
+// only once. The list of file names to read is based on the contents of the log
+// directory at construction time.
+class FileRotatingStreamReader {
+ public:
+ FileRotatingStreamReader(const std::string& dir_path,
+ const std::string& file_prefix);
+ ~FileRotatingStreamReader();
+ size_t GetSize() const;
+ size_t ReadAll(void* buffer, size_t size) const;
+
+ private:
+ std::vector<std::string> file_names_;
+};
+
+class CallSessionFileRotatingStreamReader : public FileRotatingStreamReader {
+ public:
+ CallSessionFileRotatingStreamReader(const std::string& dir_path);
+};
+
} // namespace rtc
-#endif // RTC_BASE_FILEROTATINGSTREAM_H_
+#endif // RTC_BASE_FILE_ROTATING_STREAM_H_
diff --git a/rtc_base/filerotatingstream_unittest.cc b/rtc_base/file_rotating_stream_unittest.cc
similarity index 82%
rename from rtc_base/filerotatingstream_unittest.cc
rename to rtc_base/file_rotating_stream_unittest.cc
index 172be57..22e247f 100644
--- a/rtc_base/filerotatingstream_unittest.cc
+++ b/rtc_base/file_rotating_stream_unittest.cc
@@ -8,13 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string.h>
+#include <cstdint>
#include <memory>
#include "rtc_base/arraysize.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/filerotatingstream.h"
-#include "rtc_base/gunit.h"
-#include "test/testsupport/fileutils.h"
+#include "rtc_base/file_rotating_stream.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
namespace rtc {
@@ -79,32 +80,24 @@
const size_t expected_length,
const std::string& dir_path,
const char* file_prefix) {
- std::unique_ptr<FileRotatingStream> stream;
- stream.reset(new FileRotatingStream(dir_path, file_prefix));
- ASSERT_TRUE(stream->Open());
- size_t read = 0;
- size_t stream_size = 0;
- EXPECT_TRUE(stream->GetSize(&stream_size));
+ FileRotatingStreamReader reader(dir_path, file_prefix);
+ EXPECT_EQ(reader.GetSize(), expected_length);
std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length]);
- EXPECT_EQ(SR_SUCCESS,
- stream->ReadAll(buffer.get(), expected_length, &read, nullptr));
+ memset(buffer.get(), 0, expected_length);
+ EXPECT_EQ(expected_length, reader.ReadAll(buffer.get(), expected_length));
EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length));
- EXPECT_EQ(SR_EOS, stream->ReadAll(buffer.get(), 1, nullptr, nullptr));
- EXPECT_EQ(stream_size, read);
}
void VerifyFileContents(const char* expected_contents,
const size_t expected_length,
const std::string& file_path) {
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length]);
- FileStream stream;
- ASSERT_TRUE(stream.Open(file_path, "r", nullptr));
- EXPECT_EQ(rtc::SR_SUCCESS,
- stream.ReadAll(buffer.get(), expected_length, nullptr, nullptr));
- EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length));
- size_t file_size = 0;
- EXPECT_TRUE(stream.GetSize(&file_size));
- EXPECT_EQ(file_size, expected_length);
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length + 1]);
+ webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(file_path);
+ ASSERT_TRUE(f.is_open());
+ size_t size_read = f.Read(buffer.get(), expected_length + 1);
+ EXPECT_EQ(size_read, expected_length);
+ EXPECT_EQ(0, memcmp(expected_contents, buffer.get(),
+ std::min(expected_length, size_read)));
}
std::unique_ptr<FileRotatingStream> stream_;
@@ -134,11 +127,10 @@
WriteAndFlush("a", 0);
std::string logfile_path = stream_->GetFilePath(0);
- FileStream stream;
- ASSERT_TRUE(stream.Open(logfile_path, "r", nullptr));
- size_t file_size = 0;
- EXPECT_TRUE(stream.GetSize(&file_size));
- EXPECT_EQ(0u, file_size);
+ webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(logfile_path);
+ ASSERT_TRUE(f.is_open());
+ char buf[1];
+ EXPECT_EQ(0u, f.Read(buf, sizeof(buf)));
}
// Tests that a write operation followed by a read returns the expected data
@@ -292,18 +284,12 @@
void VerifyStreamRead(const char* expected_contents,
const size_t expected_length,
const std::string& dir_path) {
- std::unique_ptr<CallSessionFileRotatingStream> stream(
- new CallSessionFileRotatingStream(dir_path));
- ASSERT_TRUE(stream->Open());
- size_t read = 0;
- size_t stream_size = 0;
- EXPECT_TRUE(stream->GetSize(&stream_size));
+ CallSessionFileRotatingStreamReader reader(dir_path);
+ EXPECT_EQ(reader.GetSize(), expected_length);
std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length]);
- EXPECT_EQ(SR_SUCCESS,
- stream->ReadAll(buffer.get(), expected_length, &read, nullptr));
+ memset(buffer.get(), 0, expected_length);
+ EXPECT_EQ(expected_length, reader.ReadAll(buffer.get(), expected_length));
EXPECT_EQ(0, memcmp(expected_contents, buffer.get(), expected_length));
- EXPECT_EQ(SR_EOS, stream->ReadAll(buffer.get(), 1, nullptr, nullptr));
- EXPECT_EQ(stream_size, read);
}
std::unique_ptr<CallSessionFileRotatingStream> stream_;
@@ -350,17 +336,25 @@
stream_->WriteAll(buffer.get(), buffer_size, nullptr, nullptr));
}
- stream_.reset(new CallSessionFileRotatingStream(dir_path_));
- ASSERT_TRUE(stream_->Open());
- std::unique_ptr<uint8_t[]> expected_buffer(new uint8_t[buffer_size]);
- int expected_vals[] = {0, 1, 2, 6, 7};
+ const int expected_vals[] = {0, 1, 2, 6, 7};
+ const size_t expected_size = buffer_size * arraysize(expected_vals);
+
+ CallSessionFileRotatingStreamReader reader(dir_path_);
+ EXPECT_EQ(reader.GetSize(), expected_size);
+ std::unique_ptr<uint8_t[]> contents(new uint8_t[expected_size + 1]);
+ EXPECT_EQ(reader.ReadAll(contents.get(), expected_size + 1), expected_size);
for (size_t i = 0; i < arraysize(expected_vals); ++i) {
- memset(expected_buffer.get(), expected_vals[i], buffer_size);
- EXPECT_EQ(SR_SUCCESS,
- stream_->ReadAll(buffer.get(), buffer_size, nullptr, nullptr));
- EXPECT_EQ(0, memcmp(buffer.get(), expected_buffer.get(), buffer_size));
+ const uint8_t* block = contents.get() + i * buffer_size;
+ bool match = true;
+ for (size_t j = 0; j < buffer_size; j++) {
+ if (block[j] != expected_vals[i]) {
+ match = false;
+ break;
+ }
+ }
+ // EXPECT call at end of loop, to limit the number of messages on failure.
+ EXPECT_TRUE(match);
}
- EXPECT_EQ(SR_EOS, stream_->ReadAll(buffer.get(), 1, nullptr, nullptr));
}
// Tests that writing and reading to a stream where only the first file is
@@ -377,17 +371,26 @@
stream_->WriteAll(buffer.get(), buffer_size, nullptr, nullptr));
}
- stream_.reset(new CallSessionFileRotatingStream(dir_path_));
- ASSERT_TRUE(stream_->Open());
- std::unique_ptr<uint8_t[]> expected_buffer(new uint8_t[buffer_size]);
- int expected_vals[] = {0, 1};
+ const int expected_vals[] = {0, 1};
+ const size_t expected_size = buffer_size * arraysize(expected_vals);
+
+ CallSessionFileRotatingStreamReader reader(dir_path_);
+ EXPECT_EQ(reader.GetSize(), expected_size);
+ std::unique_ptr<uint8_t[]> contents(new uint8_t[expected_size + 1]);
+ EXPECT_EQ(reader.ReadAll(contents.get(), expected_size + 1), expected_size);
+
for (size_t i = 0; i < arraysize(expected_vals); ++i) {
- memset(expected_buffer.get(), expected_vals[i], buffer_size);
- EXPECT_EQ(SR_SUCCESS,
- stream_->ReadAll(buffer.get(), buffer_size, nullptr, nullptr));
- EXPECT_EQ(0, memcmp(buffer.get(), expected_buffer.get(), buffer_size));
+ const uint8_t* block = contents.get() + i * buffer_size;
+ bool match = true;
+ for (size_t j = 0; j < buffer_size; j++) {
+ if (block[j] != expected_vals[i]) {
+ match = false;
+ break;
+ }
+ }
+ // EXPECT call at end of loop, to limit the number of messages on failure.
+ EXPECT_TRUE(match);
}
- EXPECT_EQ(SR_EOS, stream_->ReadAll(buffer.get(), 1, nullptr, nullptr));
}
} // namespace rtc
diff --git a/rtc_base/file_unittest.cc b/rtc_base/file_unittest.cc
deleted file mode 100644
index 5a72e5d..0000000
--- a/rtc_base/file_unittest.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2016 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 <limits>
-#include <memory>
-#include <string>
-
-#include "rtc_base/file.h"
-#include "rtc_base/gunit.h"
-#include "test/testsupport/fileutils.h"
-
-#if defined(WEBRTC_WIN)
-
-#include "rtc_base/win32.h"
-
-#else // if defined(WEBRTC_WIN)
-
-#include <errno.h>
-
-#endif
-
-namespace rtc {
-
-int LastError() {
-#if defined(WEBRTC_WIN)
- return ::GetLastError();
-#else
- return errno;
-#endif
-}
-
-bool VerifyBuffer(uint8_t* buffer, size_t length, uint8_t start_value) {
- for (size_t i = 0; i < length; ++i) {
- uint8_t val = start_value++;
- EXPECT_EQ(val, buffer[i]);
- if (buffer[i] != val)
- return false;
- }
- // Prevent the same buffer from being verified multiple times simply
- // because some operation that should have written to it failed
- memset(buffer, 0, length);
- return true;
-}
-
-class FileTest : public ::testing::Test {
- protected:
- std::string path_;
- void SetUp() override {
- path_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), "test_file");
- ASSERT_FALSE(path_.empty());
- }
- void TearDown() override { RemoveFile(path_); }
-};
-
-TEST_F(FileTest, DefaultConstructor) {
- File file;
- uint8_t buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-
- EXPECT_FALSE(file.IsOpen());
- EXPECT_EQ(0u, file.Write(buffer, 10));
- EXPECT_FALSE(file.Seek(0));
- EXPECT_EQ(0u, file.Read(buffer, 10));
- EXPECT_EQ(0u, file.WriteAt(buffer, 10, 0));
- EXPECT_EQ(0u, file.ReadAt(buffer, 10, 0));
- EXPECT_FALSE(file.Close());
-}
-
-TEST_F(FileTest, DoubleClose) {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-
- EXPECT_TRUE(file.Close());
- EXPECT_FALSE(file.Close());
-}
-
-TEST_F(FileTest, SimpleReadWrite) {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-
- uint8_t data[100] = {0};
- uint8_t out[100] = {0};
- for (int i = 0; i < 100; ++i) {
- data[i] = i;
- }
-
- EXPECT_EQ(10u, file.Write(data, 10));
-
- EXPECT_TRUE(file.Seek(0));
- EXPECT_EQ(10u, file.Read(out, 10));
- EXPECT_TRUE(VerifyBuffer(out, 10, 0));
-
- EXPECT_TRUE(file.Seek(0));
- EXPECT_EQ(100u, file.Write(data, 100));
-
- EXPECT_TRUE(file.Seek(0));
- EXPECT_EQ(100u, file.Read(out, 100));
- EXPECT_TRUE(VerifyBuffer(out, 100, 0));
-
- EXPECT_TRUE(file.Seek(1));
- EXPECT_EQ(50u, file.Write(data, 50));
- EXPECT_EQ(50u, file.Write(data + 50, 50));
-
- EXPECT_TRUE(file.Seek(1));
- EXPECT_EQ(100u, file.Read(out, 100));
- EXPECT_TRUE(VerifyBuffer(out, 100, 0));
-}
-
-TEST_F(FileTest, ReadWriteClose) {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-
- uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- uint8_t out[10] = {0};
- EXPECT_EQ(10u, file.Write(data, 10));
- EXPECT_TRUE(file.Close());
-
- File file2 = File::Open(path_);
- ASSERT_TRUE(file2.IsOpen()) << "Error: " << LastError();
- EXPECT_EQ(10u, file2.Read(out, 10));
- EXPECT_TRUE(VerifyBuffer(out, 10, 0));
-}
-
-TEST_F(FileTest, RandomAccessRead) {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-
- uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- uint8_t out[10] = {0};
- EXPECT_EQ(10u, file.Write(data, 10));
-
- EXPECT_EQ(4u, file.ReadAt(out, 4, 0));
- EXPECT_TRUE(VerifyBuffer(out, 4, 0));
-
- EXPECT_EQ(4u, file.ReadAt(out, 4, 4));
- EXPECT_TRUE(VerifyBuffer(out, 4, 4));
-
- EXPECT_EQ(5u, file.ReadAt(out, 5, 5));
- EXPECT_TRUE(VerifyBuffer(out, 5, 5));
-}
-
-TEST_F(FileTest, RandomAccessReadWrite) {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-
- uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- uint8_t out[10] = {0};
- EXPECT_EQ(10u, file.Write(data, 10));
- EXPECT_TRUE(file.Seek(4));
-
- EXPECT_EQ(4u, file.WriteAt(data, 4, 4));
- EXPECT_EQ(4u, file.ReadAt(out, 4, 4));
- EXPECT_TRUE(VerifyBuffer(out, 4, 0));
-
- EXPECT_EQ(2u, file.WriteAt(data, 2, 8));
- EXPECT_EQ(2u, file.ReadAt(out, 2, 8));
- EXPECT_TRUE(VerifyBuffer(out, 2, 0));
-}
-
-TEST_F(FileTest, ShouldBeAbleToRemoveFile) {
- {
- File file = File::Open(path_);
- ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
- }
-
- ASSERT_TRUE(File::Remove(path_)) << "Error: " << LastError();
-}
-
-} // namespace rtc
diff --git a/rtc_base/file_win.cc b/rtc_base/file_win.cc
deleted file mode 100644
index d7580aa..0000000
--- a/rtc_base/file_win.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2016 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 "rtc_base/file.h"
-
-#include <io.h>
-#include <windows.h>
-
-#include <limits>
-
-#include "rtc_base/checks.h"
-
-namespace rtc {
-
-size_t File::Write(const uint8_t* data, size_t length) {
- RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
- size_t total_written = 0;
- do {
- DWORD written;
- if (!::WriteFile(file_, data + total_written,
- static_cast<DWORD>(length - total_written), &written,
- nullptr)) {
- break;
- }
- total_written += written;
- } while (total_written < length);
- return total_written;
-}
-
-size_t File::Read(uint8_t* buffer, size_t length) {
- RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
- size_t total_read = 0;
- do {
- DWORD read;
- if (!::ReadFile(file_, buffer + total_read,
- static_cast<DWORD>(length - total_read), &read, nullptr)) {
- break;
- }
- total_read += read;
- } while (total_read < length);
- return total_read;
-}
-
-size_t File::WriteAt(const uint8_t* data, size_t length, size_t offset) {
- RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
- size_t total_written = 0;
- do {
- DWORD written;
-
- LARGE_INTEGER offset_li;
- offset_li.QuadPart = offset + total_written;
-
- OVERLAPPED overlapped = {0};
- overlapped.Offset = offset_li.LowPart;
- overlapped.OffsetHigh = offset_li.HighPart;
-
- if (!::WriteFile(file_, data + total_written,
- static_cast<DWORD>(length - total_written), &written,
- &overlapped)) {
- break;
- }
-
- total_written += written;
- } while (total_written < length);
- return total_written;
-}
-
-size_t File::ReadAt(uint8_t* buffer, size_t length, size_t offset) {
- RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
- size_t total_read = 0;
- do {
- DWORD read;
-
- LARGE_INTEGER offset_li;
- offset_li.QuadPart = offset + total_read;
-
- OVERLAPPED overlapped = {0};
- overlapped.Offset = offset_li.LowPart;
- overlapped.OffsetHigh = offset_li.HighPart;
-
- if (!::ReadFile(file_, buffer + total_read,
- static_cast<DWORD>(length - total_read), &read,
- &overlapped)) {
- break;
- }
-
- total_read += read;
- } while (total_read < length);
- return total_read;
-}
-
-bool File::Seek(size_t offset) {
- LARGE_INTEGER distance;
- distance.QuadPart = offset;
- return SetFilePointerEx(file_, distance, nullptr, FILE_BEGIN) != 0;
-}
-
-bool File::Close() {
- if (file_ == kInvalidPlatformFileValue)
- return false;
- bool ret = CloseHandle(file_) != 0;
- file_ = kInvalidPlatformFileValue;
- return ret;
-}
-
-} // namespace rtc
diff --git a/rtc_base/firewallsocketserver.cc b/rtc_base/firewall_socket_server.cc
similarity index 97%
rename from rtc_base/firewallsocketserver.cc
rename to rtc_base/firewall_socket_server.cc
index 2a28124..ec5a857 100644
--- a/rtc_base/firewallsocketserver.cc
+++ b/rtc_base/firewall_socket_server.cc
@@ -8,11 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/firewallsocketserver.h"
+#include "rtc_base/firewall_socket_server.h"
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
#include <algorithm>
+#include <string>
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
diff --git a/rtc_base/firewallsocketserver.h b/rtc_base/firewall_socket_server.h
similarity index 91%
rename from rtc_base/firewallsocketserver.h
rename to rtc_base/firewall_socket_server.h
index 0e96823..9536bd2 100644
--- a/rtc_base/firewallsocketserver.h
+++ b/rtc_base/firewall_socket_server.h
@@ -8,12 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_FIREWALLSOCKETSERVER_H_
-#define RTC_BASE_FIREWALLSOCKETSERVER_H_
+#ifndef RTC_BASE_FIREWALL_SOCKET_SERVER_H_
+#define RTC_BASE_FIREWALL_SOCKET_SERVER_H_
#include <vector>
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/socketserver.h"
+
+#include "rtc_base/async_socket.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/socket_server.h"
namespace rtc {
@@ -124,4 +129,4 @@
} // namespace rtc
-#endif // RTC_BASE_FIREWALLSOCKETSERVER_H_
+#endif // RTC_BASE_FIREWALL_SOCKET_SERVER_H_
diff --git a/rtc_base/flags.cc b/rtc_base/flags.cc
index bcce0da..6a87eb4 100644
--- a/rtc_base/flags.cc
+++ b/rtc_base/flags.cc
@@ -23,7 +23,7 @@
#include <shellapi.h> // must come after windows.h
// clang-format on
-#include "rtc_base/stringutils.h" // For ToUtf8
+#include "rtc_base/string_utils.h" // For ToUtf8
#endif
namespace {
diff --git a/rtc_base/flags.h b/rtc_base/flags.h
index a08bfd2..e152e2a 100644
--- a/rtc_base/flags.h
+++ b/rtc_base/flags.h
@@ -25,7 +25,7 @@
#include "rtc_base/checks.h"
#if defined(WEBRTC_WIN)
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#endif
namespace rtc {
diff --git a/rtc_base/function_view_unittest.cc b/rtc_base/function_view_unittest.cc
index d0cfeb3..d91bac0 100644
--- a/rtc_base/function_view_unittest.cc
+++ b/rtc_base/function_view_unittest.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "rtc_base/function_view.h"
-#include "rtc_base/gunit.h"
+#include "test/gtest.h"
namespace rtc {
@@ -97,6 +97,7 @@
TEST(FunctionViewTest, MoveConstructorIsCopy) {
auto f17 = [] { return 17; };
rtc::FunctionView<int()> fv1(f17);
+ // NOLINTNEXTLINE(performance-move-const-arg)
rtc::FunctionView<int()> fv2(std::move(fv1));
EXPECT_EQ(17, fv1());
EXPECT_EQ(17, fv2());
@@ -121,7 +122,7 @@
rtc::FunctionView<int()> fv2(f23);
EXPECT_EQ(17, fv1());
EXPECT_EQ(23, fv2());
- fv2 = std::move(fv1);
+ fv2 = std::move(fv1); // NOLINT(performance-move-const-arg)
EXPECT_EQ(17, fv1());
EXPECT_EQ(17, fv2());
}
diff --git a/rtc_base/gunit.cc b/rtc_base/gunit.cc
index 0dd8f12..83ee807 100644
--- a/rtc_base/gunit.cc
+++ b/rtc_base/gunit.cc
@@ -12,17 +12,18 @@
#include <string>
-#include "rtc_base/stringutils.h"
+#include "absl/strings/match.h"
-::testing::AssertionResult AssertStartsWith(const char* str_expr,
+::testing::AssertionResult AssertStartsWith(const char* text_expr,
const char* prefix_expr,
- const std::string& str,
- const std::string& prefix) {
- if (rtc::starts_with(str.c_str(), prefix.c_str())) {
+ absl::string_view text,
+ absl::string_view prefix) {
+ if (absl::StartsWith(text, prefix)) {
return ::testing::AssertionSuccess();
} else {
return ::testing::AssertionFailure()
- << str_expr << "\nwhich is\n\"" << str << "\"\ndoes not start with\n"
+ << text_expr << "\nwhich is\n\"" << text
+ << "\"\ndoes not start with\n"
<< prefix_expr << "\nwhich is\n\"" << prefix << "\"";
}
}
diff --git a/rtc_base/gunit.h b/rtc_base/gunit.h
index 910fbf3..d499125 100644
--- a/rtc_base/gunit.h
+++ b/rtc_base/gunit.h
@@ -11,7 +11,7 @@
#ifndef RTC_BASE_GUNIT_H_
#define RTC_BASE_GUNIT_H_
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/logging.h"
#include "rtc_base/thread.h"
#include "test/gtest.h"
@@ -153,11 +153,11 @@
} else \
GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_EQ(v1, v2)
-// Usage: EXPECT_PRED_FORMAT2(AssertStartsWith, str, "prefix");
-testing::AssertionResult AssertStartsWith(const char* str_expr,
+// Usage: EXPECT_PRED_FORMAT2(AssertStartsWith, text, "prefix");
+testing::AssertionResult AssertStartsWith(const char* text_expr,
const char* prefix_expr,
- const std::string& str,
- const std::string& prefix);
+ absl::string_view text,
+ absl::string_view prefix);
// Usage: EXPECT_PRED_FORMAT2(AssertStringContains, str, "substring");
testing::AssertionResult AssertStringContains(const char* str_expr,
diff --git a/rtc_base/helpers.cc b/rtc_base/helpers.cc
index b9372b9..d8ea89f 100644
--- a/rtc_base/helpers.cc
+++ b/rtc_base/helpers.cc
@@ -10,15 +10,13 @@
#include "rtc_base/helpers.h"
+#include <openssl/rand.h>
+#include <cstdint>
#include <limits>
#include <memory>
-#include <openssl/rand.h>
-
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/third_party/base64/base64.h"
-#include "rtc_base/timeutils.h"
// Protect against max macro inclusion.
#undef max
diff --git a/rtc_base/helpers_unittest.cc b/rtc_base/helpers_unittest.cc
index 3e8729c..1feb9de 100644
--- a/rtc_base/helpers_unittest.cc
+++ b/rtc_base/helpers_unittest.cc
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string.h>
#include <string>
#include "rtc_base/buffer.h"
-#include "rtc_base/gunit.h"
#include "rtc_base/helpers.h"
-#include "rtc_base/ssladapter.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/httpcommon.cc b/rtc_base/http_common.cc
similarity index 98%
rename from rtc_base/httpcommon.cc
rename to rtc_base/http_common.cc
index 4fa5f41..0456eea 100644
--- a/rtc_base/httpcommon.cc
+++ b/rtc_base/http_common.cc
@@ -14,24 +14,22 @@
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
+
#define SECURITY_WIN32
#include <security.h>
#endif
#include <ctype.h> // for isspace
#include <stdio.h> // for sprintf
-#include <algorithm>
#include <utility> // for pair
#include <vector>
#include "absl/strings/match.h"
-#include "rtc_base/arraysize.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/cryptstring.h" // for CryptString
-#include "rtc_base/httpcommon.h"
+#include "rtc_base/crypt_string.h" // for CryptString
+#include "rtc_base/http_common.h"
#include "rtc_base/logging.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/third_party/base64/base64.h" // for Base64
#include "rtc_base/zero_memory.h" // for ExplicitZeroMemory
diff --git a/rtc_base/httpcommon.h b/rtc_base/http_common.h
similarity index 94%
rename from rtc_base/httpcommon.h
rename to rtc_base/http_common.h
index fbad280..edf161f 100644
--- a/rtc_base/httpcommon.h
+++ b/rtc_base/http_common.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_HTTPCOMMON_H_
-#define RTC_BASE_HTTPCOMMON_H_
+#ifndef RTC_BASE_HTTP_COMMON_H_
+#define RTC_BASE_HTTP_COMMON_H_
#include <string>
@@ -49,4 +49,4 @@
} // namespace rtc
-#endif // RTC_BASE_HTTPCOMMON_H_
+#endif // RTC_BASE_HTTP_COMMON_H_
diff --git a/rtc_base/ifaddrs-android.cc b/rtc_base/ifaddrs_android.cc
similarity index 99%
rename from rtc_base/ifaddrs-android.cc
rename to rtc_base/ifaddrs_android.cc
index cc6cdab..94b8669 100644
--- a/rtc_base/ifaddrs-android.cc
+++ b/rtc_base/ifaddrs_android.cc
@@ -9,7 +9,7 @@
*/
#if defined(WEBRTC_ANDROID)
-#include "rtc_base/ifaddrs-android.h"
+#include "rtc_base/ifaddrs_android.h"
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
diff --git a/rtc_base/ifaddrs-android.h b/rtc_base/ifaddrs_android.h
similarity index 100%
rename from rtc_base/ifaddrs-android.h
rename to rtc_base/ifaddrs_android.h
diff --git a/rtc_base/ifaddrs_converter.h b/rtc_base/ifaddrs_converter.h
index 35bef5b..bd6957d 100644
--- a/rtc_base/ifaddrs_converter.h
+++ b/rtc_base/ifaddrs_converter.h
@@ -12,12 +12,12 @@
#define RTC_BASE_IFADDRS_CONVERTER_H_
#if defined(WEBRTC_ANDROID)
-#include "rtc_base/ifaddrs-android.h"
+#include "rtc_base/ifaddrs_android.h"
#else
#include <ifaddrs.h>
#endif // WEBRTC_ANDROID
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
namespace rtc {
diff --git a/rtc_base/ipaddress.cc b/rtc_base/ip_address.cc
similarity index 98%
rename from rtc_base/ipaddress.cc
rename to rtc_base/ip_address.cc
index 027a7b2..ff0be13 100644
--- a/rtc_base/ipaddress.cc
+++ b/rtc_base/ip_address.cc
@@ -20,10 +20,10 @@
#include <netdb.h>
#endif
-#include "rtc_base/byteorder.h"
-#include "rtc_base/ipaddress.h"
-#include "rtc_base/nethelpers.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/byte_order.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/string_utils.h"
#if defined(WEBRTC_WIN)
#include "rtc_base/win32.h"
diff --git a/rtc_base/ipaddress.h b/rtc_base/ip_address.h
similarity index 97%
rename from rtc_base/ipaddress.h
rename to rtc_base/ip_address.h
index 614fd8f..49dea68 100644
--- a/rtc_base/ipaddress.h
+++ b/rtc_base/ip_address.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_IPADDRESS_H_
-#define RTC_BASE_IPADDRESS_H_
+#ifndef RTC_BASE_IP_ADDRESS_H_
+#define RTC_BASE_IP_ADDRESS_H_
#if defined(WEBRTC_POSIX)
#include <arpa/inet.h>
@@ -23,9 +23,8 @@
#endif
#include <string.h>
#include <string>
-#include <vector>
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#if defined(WEBRTC_WIN)
#include "rtc_base/win32.h"
#endif
@@ -190,4 +189,4 @@
} // namespace rtc
-#endif // RTC_BASE_IPADDRESS_H_
+#endif // RTC_BASE_IP_ADDRESS_H_
diff --git a/rtc_base/ipaddress_unittest.cc b/rtc_base/ip_address_unittest.cc
similarity index 99%
rename from rtc_base/ipaddress_unittest.cc
rename to rtc_base/ip_address_unittest.cc
index 30312d0..c93244d 100644
--- a/rtc_base/ipaddress_unittest.cc
+++ b/rtc_base/ip_address_unittest.cc
@@ -8,8 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/ipaddress.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/ip_address.h"
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/java/src/org/webrtc/Logging.java b/rtc_base/java/src/org/webrtc/Logging.java
index aafdbe8..5dac688 100644
--- a/rtc_base/java/src/org/webrtc/Logging.java
+++ b/rtc_base/java/src/org/webrtc/Logging.java
@@ -10,12 +10,12 @@
package org.webrtc;
+import android.support.annotation.Nullable;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.EnumSet;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.annotation.Nullable;
import org.webrtc.Loggable;
/**
@@ -88,7 +88,7 @@
}
// Keep in sync with webrtc/rtc_base/logging.h:LoggingSeverity.
- public enum Severity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE }
+ public enum Severity { LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE }
public static void enableLogThreads() {
nativeEnableLogThreads();
diff --git a/rtc_base/java/src/org/webrtc/ThreadUtils.java b/rtc_base/java/src/org/webrtc/ThreadUtils.java
index a403870..d60230a 100644
--- a/rtc_base/java/src/org/webrtc/ThreadUtils.java
+++ b/rtc_base/java/src/org/webrtc/ThreadUtils.java
@@ -13,10 +13,10 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
+import android.support.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import javax.annotation.Nullable;
public class ThreadUtils {
/**
diff --git a/rtc_base/keep_ref_until_done.h b/rtc_base/keep_ref_until_done.h
index 9ba0e87..7bebd82 100644
--- a/rtc_base/keep_ref_until_done.h
+++ b/rtc_base/keep_ref_until_done.h
@@ -11,10 +11,10 @@
#ifndef RTC_BASE_KEEP_REF_UNTIL_DONE_H_
#define RTC_BASE_KEEP_REF_UNTIL_DONE_H_
+#include "api/scoped_refptr.h"
#include "rtc_base/bind.h"
#include "rtc_base/callback.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "rtc_base/ref_count.h"
namespace rtc {
diff --git a/rtc_base/key_derivation.cc b/rtc_base/key_derivation.cc
index 288e407..6c9a254 100644
--- a/rtc_base/key_derivation.cc
+++ b/rtc_base/key_derivation.cc
@@ -11,6 +11,7 @@
#include "rtc_base/key_derivation.h"
#include "absl/memory/memory.h"
+#include "rtc_base/checks.h"
#include "rtc_base/openssl_key_derivation_hkdf.h"
namespace rtc {
diff --git a/rtc_base/key_derivation.h b/rtc_base/key_derivation.h
index fa329ae..f35e7ff 100644
--- a/rtc_base/key_derivation.h
+++ b/rtc_base/key_derivation.h
@@ -11,12 +11,14 @@
#ifndef RTC_BASE_KEY_DERIVATION_H_
#define RTC_BASE_KEY_DERIVATION_H_
+#include <stddef.h>
+#include <stdint.h>
#include <memory>
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
diff --git a/rtc_base/location.cc b/rtc_base/location.cc
index c95ad9c..d3c911f 100644
--- a/rtc_base/location.cc
+++ b/rtc_base/location.cc
@@ -10,6 +10,8 @@
#include "rtc_base/location.h"
+#include <stdio.h>
+
namespace rtc {
Location::Location(const char* function_name, const char* file_and_line)
diff --git a/rtc_base/logsinks.cc b/rtc_base/log_sinks.cc
similarity index 98%
rename from rtc_base/logsinks.cc
rename to rtc_base/log_sinks.cc
index c01bafb..db12e9f 100644
--- a/rtc_base/logsinks.cc
+++ b/rtc_base/log_sinks.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/logsinks.h"
+#include "rtc_base/log_sinks.h"
#include <string.h>
#include <cstdio>
diff --git a/rtc_base/logsinks.h b/rtc_base/log_sinks.h
similarity index 92%
rename from rtc_base/logsinks.h
rename to rtc_base/log_sinks.h
index d0867a2..9e35748 100644
--- a/rtc_base/logsinks.h
+++ b/rtc_base/log_sinks.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_LOGSINKS_H_
-#define RTC_BASE_LOGSINKS_H_
+#ifndef RTC_BASE_LOG_SINKS_H_
+#define RTC_BASE_LOG_SINKS_H_
#include <stddef.h>
#include <memory>
#include <string>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/filerotatingstream.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/file_rotating_stream.h"
#include "rtc_base/logging.h"
namespace rtc {
@@ -69,4 +69,4 @@
} // namespace rtc
-#endif // RTC_BASE_LOGSINKS_H_
+#endif // RTC_BASE_LOG_SINKS_H_
diff --git a/rtc_base/logging.cc b/rtc_base/logging.cc
index 8d6afbc..f78cd88 100644
--- a/rtc_base/logging.cc
+++ b/rtc_base/logging.cc
@@ -35,14 +35,14 @@
#include <vector>
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/logging.h"
#include "rtc_base/platform_thread_types.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/string_utils.h"
#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/stringutils.h"
#include "rtc_base/thread_annotations.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
namespace {
@@ -308,8 +308,6 @@
LogThreads();
// Logging levels
- } else if (token == "sensitive") {
- current_level = LS_SENSITIVE;
} else if (token == "verbose") {
current_level = LS_VERBOSE;
} else if (token == "info") {
@@ -402,13 +400,6 @@
// from the shell.
int prio;
switch (severity) {
- case LS_SENSITIVE:
- __android_log_write(ANDROID_LOG_INFO, tag, "SENSITIVE");
- if (log_to_stderr) {
- fprintf(stderr, "SENSITIVE");
- fflush(stderr);
- }
- return;
case LS_VERBOSE:
prio = ANDROID_LOG_VERBOSE;
break;
@@ -540,9 +531,11 @@
case LogArgType::kLongDouble:
log_message.stream() << va_arg(args, long double);
break;
- case LogArgType::kCharP:
- log_message.stream() << va_arg(args, const char*);
+ case LogArgType::kCharP: {
+ const char* s = va_arg(args, const char*);
+ log_message.stream() << (s ? s : "(null)");
break;
+ }
case LogArgType::kStdString:
log_message.stream() << *va_arg(args, const std::string*);
break;
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index c7d083e..5cd4f72 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -52,7 +52,7 @@
#include <utility>
#include "absl/strings/string_view.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/deprecation.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/system/inline.h"
@@ -73,8 +73,6 @@
// Note that the non-standard LoggingSeverity aliases exist because they are
// still in broad use. The meanings of the levels are:
-// LS_SENSITIVE: Information which should only be logged with the consent
-// of the user, due to privacy concerns.
// LS_VERBOSE: This level is for data which we do not want to appear in the
// normal debug log, but should appear in diagnostic logs.
// LS_INFO: Chatty level used in debugging for all sorts of things, the default
@@ -83,7 +81,6 @@
// LS_ERROR: Something that should not have occurred.
// LS_NONE: Don't log.
enum LoggingSeverity {
- LS_SENSITIVE,
LS_VERBOSE,
LS_INFO,
LS_WARNING,
@@ -361,11 +358,6 @@
}
};
-// TODO(bugs.webrtc.org/9278): Remove this once it's no longer used.
-struct LogMessageVoidify {
- void operator&(std::ostream&) {} // no-presubmit-check TODO(webrtc:8982)
-};
-
} // namespace webrtc_logging_impl
// Direct use of this class is deprecated; please use the logging macros
@@ -512,13 +504,6 @@
// Logging Helpers
//////////////////////////////////////////////////////////////////////
-// DEPRECATED.
-// TODO(bugs.webrtc.org/9278): Remove once there are no more users.
-#define RTC_LOG_SEVERITY_PRECONDITION(sev) \
- (rtc::LogMessage::IsNoop(sev)) \
- ? static_cast<void>(0) \
- : rtc::webrtc_logging_impl::LogMessageVoidify()&
-
#define RTC_LOG_FILE_LINE(sev, file, line) \
rtc::webrtc_logging_impl::LogCall() & \
rtc::webrtc_logging_impl::LogStreamer<>() \
diff --git a/rtc_base/logging_unittest.cc b/rtc_base/logging_unittest.cc
index 4de1cf2..e49440d 100644
--- a/rtc_base/logging_unittest.cc
+++ b/rtc_base/logging_unittest.cc
@@ -9,13 +9,17 @@
*/
#include "rtc_base/logging.h"
+
+#include <string.h>
+#include <algorithm>
+
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
-#include "rtc_base/gunit.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/stream.h"
-#include "test/testsupport/fileutils.h"
+#include "rtc_base/time_utils.h"
+#include "test/gtest.h"
namespace rtc {
@@ -36,10 +40,6 @@
size_t* written,
int* error) override;
void Close() override;
- bool SetPosition(size_t position) override;
- bool GetPosition(size_t* position) const override;
- bool GetSize(size_t* size) const override;
- bool ReserveSize(size_t size) override;
private:
std::string& str_;
@@ -90,32 +90,6 @@
void StringStream::Close() {}
-bool StringStream::SetPosition(size_t position) {
- if (position > str_.size())
- return false;
- read_pos_ = position;
- return true;
-}
-
-bool StringStream::GetPosition(size_t* position) const {
- if (position)
- *position = read_pos_;
- return true;
-}
-
-bool StringStream::GetSize(size_t* size) const {
- if (size)
- *size = str_.size();
- return true;
-}
-
-bool StringStream::ReserveSize(size_t size) {
- if (read_only_)
- return false;
- str_.reserve(size);
- return true;
-}
-
} // namespace
template <typename Base>
@@ -188,13 +162,14 @@
std::string s1 = "char*";
std::string s2 = "std::string";
std::string s3 = "absl::stringview";
-
+ const char* null_string = nullptr;
void* p = reinterpret_cast<void*>(0xabcd);
// Log all suported types(except doubles/floats) as a sanity-check.
RTC_LOG(LS_INFO) << "|" << i << "|" << l << "|" << ll << "|" << u << "|" << ul
<< "|" << ull << "|" << s1.c_str() << "|" << s2 << "|"
- << absl::string_view(s3) << "|" << p << "|";
+ << absl::string_view(s3) << "|" << p << "|" << null_string
+ << "|";
// Signed integers
EXPECT_NE(std::string::npos, str.find("|1|"));
@@ -214,6 +189,9 @@
// void*
EXPECT_NE(std::string::npos, str.find("|abcd|"));
+ // null char*
+ EXPECT_NE(std::string::npos, str.find("|(null)|"));
+
LogMessage::RemoveLogToStream(&stream);
EXPECT_EQ(LS_NONE, LogMessage::GetLogToStream(&stream));
EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr));
@@ -284,10 +262,7 @@
void Start() { thread_.Start(); }
private:
- void Run() {
- // LS_SENSITIVE by default to avoid cluttering up any real logging going on.
- RTC_LOG(LS_SENSITIVE) << "RTC_LOG";
- }
+ void Run() { RTC_LOG(LS_VERBOSE) << "RTC_LOG"; }
static void ThreadEntry(void* p) { static_cast<LogThread*>(p)->Run(); }
@@ -308,9 +283,9 @@
std::string s1, s2, s3;
LogSinkImpl<StringStream> stream1(&s1), stream2(&s2), stream3(&s3);
for (int i = 0; i < 1000; ++i) {
- LogMessage::AddLogToStream(&stream1, LS_INFO);
- LogMessage::AddLogToStream(&stream2, LS_VERBOSE);
- LogMessage::AddLogToStream(&stream3, LS_SENSITIVE);
+ LogMessage::AddLogToStream(&stream1, LS_WARNING);
+ LogMessage::AddLogToStream(&stream2, LS_INFO);
+ LogMessage::AddLogToStream(&stream3, LS_VERBOSE);
LogMessage::RemoveLogToStream(&stream1);
LogMessage::RemoveLogToStream(&stream2);
LogMessage::RemoveLogToStream(&stream3);
@@ -367,12 +342,10 @@
TEST(LogTest, Perf) {
std::string str;
LogSinkImpl<StringStream> stream(&str);
- LogMessage::AddLogToStream(&stream, LS_SENSITIVE);
+ LogMessage::AddLogToStream(&stream, LS_VERBOSE);
const std::string message(80, 'X');
- {
- LogMessageForTesting sanity_check_msg(__FILE__, __LINE__, LS_SENSITIVE);
- }
+ { LogMessageForTesting sanity_check_msg(__FILE__, __LINE__, LS_VERBOSE); }
// We now know how many bytes the logging framework will tag onto every msg.
const size_t logging_overhead = str.size();
@@ -383,7 +356,7 @@
int64_t start = TimeMillis(), finish;
for (int i = 0; i < kRepetitions; ++i) {
- LogMessageForTesting(__FILE__, __LINE__, LS_SENSITIVE).stream() << message;
+ LogMessageForTesting(__FILE__, __LINE__, LS_VERBOSE).stream() << message;
}
finish = TimeMillis();
diff --git a/rtc_base/macifaddrs_converter.cc b/rtc_base/mac_ifaddrs_converter.cc
similarity index 100%
rename from rtc_base/macifaddrs_converter.cc
rename to rtc_base/mac_ifaddrs_converter.cc
diff --git a/rtc_base/macutils.cc b/rtc_base/mac_utils.cc
similarity index 95%
rename from rtc_base/macutils.cc
rename to rtc_base/mac_utils.cc
index 2b8700f..390f183 100644
--- a/rtc_base/macutils.cc
+++ b/rtc_base/mac_utils.cc
@@ -15,8 +15,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/macutils.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/mac_utils.h"
namespace rtc {
diff --git a/rtc_base/macutils.h b/rtc_base/mac_utils.h
similarity index 86%
rename from rtc_base/macutils.h
rename to rtc_base/mac_utils.h
index b22e5f9..ae97c3a 100644
--- a/rtc_base/macutils.h
+++ b/rtc_base/mac_utils.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_MACUTILS_H_
-#define RTC_BASE_MACUTILS_H_
+#ifndef RTC_BASE_MAC_UTILS_H_
+#define RTC_BASE_MAC_UTILS_H_
#include <CoreFoundation/CoreFoundation.h>
#include <string>
@@ -19,4 +19,4 @@
bool ToUtf16(const std::string& str8, CFStringRef* str16);
} // namespace rtc
-#endif // RTC_BASE_MACUTILS_H_
+#endif // RTC_BASE_MAC_UTILS_H_
diff --git a/rtc_base/mdns_responder_interface.h b/rtc_base/mdns_responder_interface.h
index 71938b2..96280a7 100644
--- a/rtc_base/mdns_responder_interface.h
+++ b/rtc_base/mdns_responder_interface.h
@@ -14,7 +14,7 @@
#include <functional>
#include <string>
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
namespace webrtc {
diff --git a/rtc_base/memory/aligned_array.h b/rtc_base/memory/aligned_array.h
index dcdef12..c67d87d 100644
--- a/rtc_base/memory/aligned_array.h
+++ b/rtc_base/memory/aligned_array.h
@@ -11,6 +11,8 @@
#ifndef RTC_BASE_MEMORY_ALIGNED_ARRAY_H_
#define RTC_BASE_MEMORY_ALIGNED_ARRAY_H_
+#include <stddef.h>
+
#include "rtc_base/checks.h"
#include "rtc_base/memory/aligned_malloc.h"
diff --git a/rtc_base/memory_stream.cc b/rtc_base/memory_stream.cc
index 541de07..a30aacd 100644
--- a/rtc_base/memory_stream.cc
+++ b/rtc_base/memory_stream.cc
@@ -8,8 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <errno.h>
+#include <string.h>
#include <algorithm>
+#include "rtc_base/checks.h"
#include "rtc_base/memory_stream.h"
namespace rtc {
@@ -88,6 +91,10 @@
return true;
}
+void MemoryStream::Rewind() {
+ seek_position_ = 0;
+}
+
bool MemoryStream::GetSize(size_t* size) const {
if (size)
*size = data_length_;
diff --git a/rtc_base/memory_stream.h b/rtc_base/memory_stream.h
index 936f71b..bdcc40d 100644
--- a/rtc_base/memory_stream.h
+++ b/rtc_base/memory_stream.h
@@ -11,6 +11,8 @@
#ifndef RTC_BASE_MEMORY_STREAM_H_
#define RTC_BASE_MEMORY_STREAM_H_
+#include <stddef.h>
+
#include "rtc_base/stream.h"
namespace rtc {
@@ -34,10 +36,12 @@
size_t* bytes_written,
int* error) override;
void Close() override;
- bool SetPosition(size_t position) override;
- bool GetPosition(size_t* position) const override;
- bool GetSize(size_t* size) const override;
- bool ReserveSize(size_t size) override;
+ bool GetSize(size_t* size) const;
+ bool ReserveSize(size_t size);
+
+ bool SetPosition(size_t position);
+ bool GetPosition(size_t* position) const;
+ void Rewind();
char* GetBuffer() { return buffer_; }
const char* GetBuffer() const { return buffer_; }
diff --git a/rtc_base/memory_usage.cc b/rtc_base/memory_usage.cc
index 9cd36d3..20db9f3 100644
--- a/rtc_base/memory_usage.cc
+++ b/rtc_base/memory_usage.cc
@@ -13,15 +13,13 @@
#if defined(WEBRTC_LINUX)
#include <unistd.h>
#include <cstdio>
-#include <cstdlib>
-#include <cstring>
#elif defined(WEBRTC_MAC)
#include <mach/mach.h>
#elif defined(WEBRTC_WIN)
// clang-format off
// clang formating would change include order.
#include <windows.h>
-#include <psapi.h> // must come after windows.h
+#include <psapi.h> // must come after windows.h
// clang-format on
#endif
diff --git a/rtc_base/memory_usage_unittest.cc b/rtc_base/memory_usage_unittest.cc
index 9c82f98..a928efb 100644
--- a/rtc_base/memory_usage_unittest.cc
+++ b/rtc_base/memory_usage_unittest.cc
@@ -9,7 +9,7 @@
*/
#include "rtc_base/memory_usage.h"
-#include <cstdio>
+
#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/message_buffer_reader.h b/rtc_base/message_buffer_reader.h
index baba89e..32b8f33 100644
--- a/rtc_base/message_buffer_reader.h
+++ b/rtc_base/message_buffer_reader.h
@@ -11,7 +11,7 @@
#ifndef RTC_BASE_MESSAGE_BUFFER_READER_H_
#define RTC_BASE_MESSAGE_BUFFER_READER_H_
-#include "rtc_base/bytebuffer.h"
+#include "rtc_base/byte_buffer.h"
namespace webrtc {
diff --git a/rtc_base/messagedigest.cc b/rtc_base/message_digest.cc
similarity index 98%
rename from rtc_base/messagedigest.cc
rename to rtc_base/message_digest.cc
index 5a0d16a..b1d4a48 100644
--- a/rtc_base/messagedigest.cc
+++ b/rtc_base/message_digest.cc
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/messagedigest.h"
+#include "rtc_base/message_digest.h"
#include <string.h>
#include <cstdint>
#include <memory>
-#include "rtc_base/openssldigest.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/openssl_digest.h"
+#include "rtc_base/string_encode.h"
namespace rtc {
diff --git a/rtc_base/messagedigest.h b/rtc_base/message_digest.h
similarity index 97%
rename from rtc_base/messagedigest.h
rename to rtc_base/message_digest.h
index 757f914..bbb22cf 100644
--- a/rtc_base/messagedigest.h
+++ b/rtc_base/message_digest.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_MESSAGEDIGEST_H_
-#define RTC_BASE_MESSAGEDIGEST_H_
+#ifndef RTC_BASE_MESSAGE_DIGEST_H_
+#define RTC_BASE_MESSAGE_DIGEST_H_
#include <stddef.h>
#include <string>
@@ -126,4 +126,4 @@
} // namespace rtc
-#endif // RTC_BASE_MESSAGEDIGEST_H_
+#endif // RTC_BASE_MESSAGE_DIGEST_H_
diff --git a/rtc_base/messagedigest_unittest.cc b/rtc_base/message_digest_unittest.cc
similarity index 98%
rename from rtc_base/messagedigest_unittest.cc
rename to rtc_base/message_digest_unittest.cc
index 5524b18..85e9bbd 100644
--- a/rtc_base/messagedigest_unittest.cc
+++ b/rtc_base/message_digest_unittest.cc
@@ -8,9 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/message_digest.h"
+
+#include "rtc_base/string_encode.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/messagehandler.cc b/rtc_base/message_handler.cc
similarity index 87%
rename from rtc_base/messagehandler.cc
rename to rtc_base/message_handler.cc
index 7376def..0e6c237 100644
--- a/rtc_base/messagehandler.cc
+++ b/rtc_base/message_handler.cc
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
namespace rtc {
diff --git a/rtc_base/messagehandler.h b/rtc_base/message_handler.h
similarity index 86%
rename from rtc_base/messagehandler.h
rename to rtc_base/message_handler.h
index 0c40853..015255e 100644
--- a/rtc_base/messagehandler.h
+++ b/rtc_base/message_handler.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_MESSAGEHANDLER_H_
-#define RTC_BASE_MESSAGEHANDLER_H_
+#ifndef RTC_BASE_MESSAGE_HANDLER_H_
+#define RTC_BASE_MESSAGE_HANDLER_H_
#include <utility>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -55,7 +55,8 @@
template <class FunctorT>
class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
public:
- explicit FunctorMessageHandler(const FunctorT& functor) : functor_(functor) {}
+ explicit FunctorMessageHandler(FunctorT&& functor)
+ : functor_(std::forward<FunctorT>(functor)) {}
virtual void OnMessage(Message* msg) { functor_(); }
void result() const {}
void MoveResult() {}
@@ -66,4 +67,4 @@
} // namespace rtc
-#endif // RTC_BASE_MESSAGEHANDLER_H_
+#endif // RTC_BASE_MESSAGE_HANDLER_H_
diff --git a/rtc_base/messagequeue.cc b/rtc_base/message_queue.cc
similarity index 99%
rename from rtc_base/messagequeue.cc
rename to rtc_base/message_queue.cc
index 204952a..abb01b3 100644
--- a/rtc_base/messagequeue.cc
+++ b/rtc_base/message_queue.cc
@@ -11,12 +11,12 @@
#include <string>
#include <utility>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
namespace rtc {
diff --git a/rtc_base/messagequeue.h b/rtc_base/message_queue.h
similarity index 97%
rename from rtc_base/messagequeue.h
rename to rtc_base/message_queue.h
index c1b9b5a..5a6bd0a 100644
--- a/rtc_base/messagequeue.h
+++ b/rtc_base/message_queue.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_MESSAGEQUEUE_H_
-#define RTC_BASE_MESSAGEQUEUE_H_
+#ifndef RTC_BASE_MESSAGE_QUEUE_H_
+#define RTC_BASE_MESSAGE_QUEUE_H_
#include <string.h>
@@ -19,12 +19,12 @@
#include <queue>
#include <vector>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/location.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/scoped_ref_ptr.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/socket_server.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread_annotations.h"
@@ -330,4 +330,4 @@
} // namespace rtc
-#endif // RTC_BASE_MESSAGEQUEUE_H_
+#endif // RTC_BASE_MESSAGE_QUEUE_H_
diff --git a/rtc_base/messagequeue_unittest.cc b/rtc_base/message_queue_unittest.cc
similarity index 96%
rename from rtc_base/messagequeue_unittest.cc
rename to rtc_base/message_queue_unittest.cc
index d8e8b11..657949c 100644
--- a/rtc_base/messagequeue_unittest.cc
+++ b/rtc_base/message_queue_unittest.cc
@@ -8,22 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_queue.h"
#include <functional>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/bind.h"
#include "rtc_base/event.h"
#include "rtc_base/gunit.h"
#include "rtc_base/logging.h"
-#include "rtc_base/nullsocketserver.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
-using namespace rtc;
+namespace rtc {
+namespace {
class MessageQueueTest : public testing::Test, public MessageQueue {
public:
@@ -231,3 +232,6 @@
t->Post(RTC_FROM_HERE, &handler, 0,
new ScopedRefMessageData<RefCountedHandler>(inner_handler));
}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/module.mk b/rtc_base/module.mk
index 8364fe5..61f2dd1 100644
--- a/rtc_base/module.mk
+++ b/rtc_base/module.mk
@@ -6,14 +6,13 @@
rtc_base_approved_generic_CXX_OBJECTS = \
rtc_base/third_party/base64/base64.o \
- rtc_base/bitbuffer.o \
- rtc_base/bitrateallocationstrategy.o \
- rtc_base/bufferqueue.o \
- rtc_base/bytebuffer.o \
- rtc_base/copyonwritebuffer.o \
- rtc_base/criticalsection.o \
+ rtc_base/bit_buffer.o \
+ rtc_base/bitrate_allocation_strategy.o \
+ rtc_base/buffer_queue.o \
+ rtc_base/byte_buffer.o \
+ rtc_base/copy_on_write_buffer.o \
+ rtc_base/critical_section.o \
rtc_base/event_tracer.o \
- rtc_base/file.o \
rtc_base/flags.o \
rtc_base/location.o \
rtc_base/numerics/histogram_percentile_counter.o \
@@ -23,21 +22,23 @@
rtc_base/race_checker.o \
rtc_base/random.o \
rtc_base/rate_statistics.o \
- rtc_base/ratetracker.o \
+ rtc_base/rate_tracker.o \
rtc_base/string_to_number.o \
- rtc_base/stringencode.o \
+ rtc_base/string_encode.o \
rtc_base/thread_checker_impl.o \
- rtc_base/timestampaligner.o \
- rtc_base/timeutils.o \
+ rtc_base/timestamp_aligner.o \
+ rtc_base/time_utils.o \
rtc_base/zero_memory.o \
- rtc_base/file_posix.o \
rtc_base/event.o \
rtc_base/logging.o \
# requires libevent at link
task_queue_impl_CXX_OBJECTS = \
- rtc_base/task_queue_libevent.o \
- rtc_base/task_queue_posix.o
+ api/task_queue/default_task_queue_factory_libevent.o \
+ api/task_queue/global_task_queue_factory.o \
+ api/task_queue/task_queue_base.o \
+ rtc_base/task_queue.o \
+ rtc_base/task_queue_libevent.o
rtc_base_CXX_OBJECTS = \
rtc_base/checks.o \
@@ -48,7 +49,7 @@
stringutils_CXX_OBJECTS = \
rtc_base/strings/string_builder.o \
- rtc_base/stringutils.o
+ rtc_base/string_utils.o
CXX_STATIC_LIBRARY(rtc_base/librtc_base.pic.a): \
CPPFLAGS+= -DWEBRTC_POSIX -DWEBRTC_LINUX
diff --git a/rtc_base/natserver.cc b/rtc_base/nat_server.cc
similarity index 98%
rename from rtc_base/natserver.cc
rename to rtc_base/nat_server.cc
index b005eca..2b614e8 100644
--- a/rtc_base/natserver.cc
+++ b/rtc_base/nat_server.cc
@@ -12,9 +12,9 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/natserver.h"
-#include "rtc_base/natsocketfactory.h"
-#include "rtc_base/socketadapters.h"
+#include "rtc_base/nat_server.h"
+#include "rtc_base/nat_socket_factory.h"
+#include "rtc_base/socket_adapters.h"
namespace rtc {
diff --git a/rtc_base/natserver.h b/rtc_base/nat_server.h
similarity index 92%
rename from rtc_base/natserver.h
rename to rtc_base/nat_server.h
index d16b537..46f01e9 100644
--- a/rtc_base/natserver.h
+++ b/rtc_base/nat_server.h
@@ -8,18 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NATSERVER_H_
-#define RTC_BASE_NATSERVER_H_
+#ifndef RTC_BASE_NAT_SERVER_H_
+#define RTC_BASE_NAT_SERVER_H_
#include <map>
#include <set>
-#include "rtc_base/asyncudpsocket.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/nattypes.h"
-#include "rtc_base/proxyserver.h"
-#include "rtc_base/socketaddresspair.h"
-#include "rtc_base/socketfactory.h"
+#include "rtc_base/async_udp_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/nat_types.h"
+#include "rtc_base/proxy_server.h"
+#include "rtc_base/socket_address_pair.h"
+#include "rtc_base/socket_factory.h"
#include "rtc_base/thread.h"
namespace rtc {
@@ -126,4 +126,4 @@
} // namespace rtc
-#endif // RTC_BASE_NATSERVER_H_
+#endif // RTC_BASE_NAT_SERVER_H_
diff --git a/rtc_base/natsocketfactory.cc b/rtc_base/nat_socket_factory.cc
similarity index 99%
rename from rtc_base/natsocketfactory.cc
rename to rtc_base/nat_socket_factory.cc
index a707ce0..6d44651 100644
--- a/rtc_base/natsocketfactory.cc
+++ b/rtc_base/nat_socket_factory.cc
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/natsocketfactory.h"
+#include "rtc_base/nat_socket_factory.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/natserver.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/nat_server.h"
+#include "rtc_base/virtual_socket_server.h"
namespace rtc {
diff --git a/rtc_base/natsocketfactory.h b/rtc_base/nat_socket_factory.h
similarity index 92%
rename from rtc_base/natsocketfactory.h
rename to rtc_base/nat_socket_factory.h
index 97961d4..9b5cb5a 100644
--- a/rtc_base/natsocketfactory.h
+++ b/rtc_base/nat_socket_factory.h
@@ -8,18 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NATSOCKETFACTORY_H_
-#define RTC_BASE_NATSOCKETFACTORY_H_
+#ifndef RTC_BASE_NAT_SOCKET_FACTORY_H_
+#define RTC_BASE_NAT_SOCKET_FACTORY_H_
+#include <stddef.h>
#include <map>
#include <memory>
#include <set>
-#include <string>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/natserver.h"
-#include "rtc_base/socketaddress.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/nat_server.h"
+#include "rtc_base/nat_types.h"
+#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/socket_factory.h"
+#include "rtc_base/socket_server.h"
namespace rtc {
@@ -80,6 +85,7 @@
class NATSocketServer : public SocketServer, public NATInternalSocketFactory {
public:
class Translator;
+
// holds a list of NATs
class TranslatorMap : private std::map<SocketAddress, Translator*> {
public:
@@ -169,4 +175,4 @@
SocketAddress* remote_addr);
} // namespace rtc
-#endif // RTC_BASE_NATSOCKETFACTORY_H_
+#endif // RTC_BASE_NAT_SOCKET_FACTORY_H_
diff --git a/rtc_base/nattypes.cc b/rtc_base/nat_types.cc
similarity index 97%
rename from rtc_base/nattypes.cc
rename to rtc_base/nat_types.cc
index a7af57d..50d7de0 100644
--- a/rtc_base/nattypes.cc
+++ b/rtc_base/nat_types.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/nattypes.h"
+#include "rtc_base/nat_types.h"
#include "rtc_base/checks.h"
diff --git a/rtc_base/nattypes.h b/rtc_base/nat_types.h
similarity index 92%
rename from rtc_base/nattypes.h
rename to rtc_base/nat_types.h
index 1d816ac..60e7fbd 100644
--- a/rtc_base/nattypes.h
+++ b/rtc_base/nat_types.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NATTYPES_H_
-#define RTC_BASE_NATTYPES_H_
+#ifndef RTC_BASE_NAT_TYPES_H_
+#define RTC_BASE_NAT_TYPES_H_
namespace rtc {
@@ -44,4 +44,4 @@
} // namespace rtc
-#endif // RTC_BASE_NATTYPES_H_
+#endif // RTC_BASE_NAT_TYPES_H_
diff --git a/rtc_base/nat_unittest.cc b/rtc_base/nat_unittest.cc
index ee94427..7a0761e 100644
--- a/rtc_base/nat_unittest.cc
+++ b/rtc_base/nat_unittest.cc
@@ -8,23 +8,37 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string.h>
#include <algorithm>
#include <memory>
#include <string>
+#include <vector>
#include "absl/memory/memory.h"
-#include "rtc_base/asynctcpsocket.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/async_tcp_socket.h"
+#include "rtc_base/async_udp_socket.h"
#include "rtc_base/gunit.h"
+#include "rtc_base/ip_address.h"
#include "rtc_base/logging.h"
-#include "rtc_base/natserver.h"
-#include "rtc_base/natsocketfactory.h"
-#include "rtc_base/nethelpers.h"
+#include "rtc_base/nat_server.h"
+#include "rtc_base/nat_socket_factory.h"
+#include "rtc_base/nat_types.h"
+#include "rtc_base/net_helpers.h"
#include "rtc_base/network.h"
-#include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/testclient.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/physical_socket_server.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/socket_factory.h"
+#include "rtc_base/socket_server.h"
+#include "rtc_base/test_client.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/virtual_socket_server.h"
+#include "test/gtest.h"
-using namespace rtc;
+namespace rtc {
+namespace {
bool CheckReceive(TestClient* client,
bool should_receive,
@@ -207,7 +221,6 @@
void TestPhysicalInternal(const SocketAddress& int_addr) {
BasicNetworkManager network_manager;
- network_manager.set_ipv6_enabled(true);
network_manager.StartUpdating();
// Process pending messages so the network list is updated.
Thread::Current()->ProcessMessages(0);
@@ -387,4 +400,6 @@
out->Send(buf, len);
EXPECT_TRUE(in->CheckNextPacket(buf, len, &trans_addr));
}
-// #endif
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/nethelper.cc b/rtc_base/net_helper.cc
similarity index 94%
rename from rtc_base/nethelper.cc
rename to rtc_base/net_helper.cc
index e654fe3..7dcb599 100644
--- a/rtc_base/nethelper.cc
+++ b/rtc_base/net_helper.cc
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/nethelper.h"
+#include "rtc_base/net_helper.h"
#include "rtc_base/checks.h"
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
namespace cricket {
diff --git a/rtc_base/nethelper.h b/rtc_base/net_helper.h
similarity index 90%
rename from rtc_base/nethelper.h
rename to rtc_base/net_helper.h
index f956138..e42502b 100644
--- a/rtc_base/nethelper.h
+++ b/rtc_base/net_helper.h
@@ -7,8 +7,8 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NETHELPER_H_
-#define RTC_BASE_NETHELPER_H_
+#ifndef RTC_BASE_NET_HELPER_H_
+#define RTC_BASE_NET_HELPER_H_
#include <string>
@@ -29,4 +29,4 @@
} // namespace cricket
-#endif // RTC_BASE_NETHELPER_H_
+#endif // RTC_BASE_NET_HELPER_H_
diff --git a/rtc_base/nethelpers.cc b/rtc_base/net_helpers.cc
similarity index 98%
rename from rtc_base/nethelpers.cc
rename to rtc_base/net_helpers.cc
index 1bba3b4..c662f1a 100644
--- a/rtc_base/nethelpers.cc
+++ b/rtc_base/net_helpers.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/nethelpers.h"
+#include "rtc_base/net_helpers.h"
#include <memory>
@@ -19,14 +19,14 @@
#endif
#if defined(WEBRTC_POSIX) && !defined(__native_client__)
#if defined(WEBRTC_ANDROID)
-#include "rtc_base/ifaddrs-android.h"
+#include "rtc_base/ifaddrs_android.h"
#else
#include <ifaddrs.h>
#endif
#endif // defined(WEBRTC_POSIX) && !defined(__native_client__)
#include "rtc_base/logging.h"
-#include "rtc_base/signalthread.h"
+#include "rtc_base/signal_thread.h"
#include "rtc_base/third_party/sigslot/sigslot.h" // for signal_with_thread...
namespace rtc {
diff --git a/rtc_base/nethelpers.h b/rtc_base/net_helpers.h
similarity index 86%
rename from rtc_base/nethelpers.h
rename to rtc_base/net_helpers.h
index 138f958..6f75318 100644
--- a/rtc_base/nethelpers.h
+++ b/rtc_base/net_helpers.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NETHELPERS_H_
-#define RTC_BASE_NETHELPERS_H_
+#ifndef RTC_BASE_NET_HELPERS_H_
+#define RTC_BASE_NET_HELPERS_H_
#if defined(WEBRTC_POSIX)
#include <sys/socket.h>
@@ -19,10 +19,10 @@
#include <vector>
-#include "rtc_base/asyncresolverinterface.h"
-#include "rtc_base/ipaddress.h"
-#include "rtc_base/signalthread.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/async_resolver_interface.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/signal_thread.h"
+#include "rtc_base/socket_address.h"
namespace rtc {
@@ -60,4 +60,4 @@
bool HasIPv6Enabled();
} // namespace rtc
-#endif // RTC_BASE_NETHELPERS_H_
+#endif // RTC_BASE_NET_HELPERS_H_
diff --git a/rtc_base/network.cc b/rtc_base/network.cc
index 5c7b019..9c9bc57 100644
--- a/rtc_base/network.cc
+++ b/rtc_base/network.cc
@@ -36,11 +36,11 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/networkmonitor.h"
+#include "rtc_base/network_monitor.h"
#include "rtc_base/socket.h" // includes something that makes windows happy
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/string_utils.h"
#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/stringutils.h"
#include "rtc_base/thread.h"
namespace rtc {
@@ -235,7 +235,8 @@
if (MatchTypeNameWithIndexPattern(network_name, "rmnet") ||
MatchTypeNameWithIndexPattern(network_name, "rmnet_data") ||
MatchTypeNameWithIndexPattern(network_name, "v4-rmnet") ||
- MatchTypeNameWithIndexPattern(network_name, "v4-rmnet_data")) {
+ MatchTypeNameWithIndexPattern(network_name, "v4-rmnet_data") ||
+ MatchTypeNameWithIndexPattern(network_name, "clat")) {
return ADAPTER_TYPE_CELLULAR;
}
if (MatchTypeNameWithIndexPattern(network_name, "wlan")) {
@@ -264,8 +265,7 @@
}
NetworkManagerBase::NetworkManagerBase()
- : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED),
- ipv6_enabled_(true) {}
+ : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED) {}
NetworkManagerBase::~NetworkManagerBase() {
for (const auto& kv : networks_map_) {
@@ -284,22 +284,20 @@
ipv4_any_address_network_.reset(
new rtc::Network("any", "any", ipv4_any_address, 0, ADAPTER_TYPE_ANY));
ipv4_any_address_network_->set_default_local_address_provider(this);
+ ipv4_any_address_network_->set_mdns_responder_provider(this);
ipv4_any_address_network_->AddIP(ipv4_any_address);
- ipv4_any_address_network_->SetMdnsResponder(GetMdnsResponder());
}
networks->push_back(ipv4_any_address_network_.get());
- if (ipv6_enabled()) {
- if (!ipv6_any_address_network_) {
- const rtc::IPAddress ipv6_any_address(in6addr_any);
- ipv6_any_address_network_.reset(new rtc::Network(
- "any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY));
- ipv6_any_address_network_->set_default_local_address_provider(this);
- ipv6_any_address_network_->AddIP(ipv6_any_address);
- ipv6_any_address_network_->SetMdnsResponder(GetMdnsResponder());
- }
- networks->push_back(ipv6_any_address_network_.get());
+ if (!ipv6_any_address_network_) {
+ const rtc::IPAddress ipv6_any_address(in6addr_any);
+ ipv6_any_address_network_.reset(
+ new rtc::Network("any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY));
+ ipv6_any_address_network_->set_default_local_address_provider(this);
+ ipv6_any_address_network_->set_mdns_responder_provider(this);
+ ipv6_any_address_network_->AddIP(ipv6_any_address);
}
+ networks->push_back(ipv6_any_address_network_.get());
}
void NetworkManagerBase::GetNetworks(NetworkList* result) const {
@@ -386,7 +384,7 @@
delete net;
}
}
- networks_map_[key]->SetMdnsResponder(GetMdnsResponder());
+ networks_map_[key]->set_mdns_responder_provider(this);
}
// It may still happen that the merged list is a subset of |networks_|.
// To detect this change, we compare their sizes.
@@ -520,10 +518,6 @@
cursor->ifa_addr->sa_family != AF_INET6) {
continue;
}
- // Skip IPv6 if not enabled.
- if (cursor->ifa_addr->sa_family == AF_INET6 && !ipv6_enabled()) {
- continue;
- }
// Convert to InterfaceAddress.
if (!ifaddrs_converter->ConvertIfAddrsToIPAddress(cursor, &ip, &mask)) {
continue;
@@ -699,22 +693,20 @@
break;
}
case AF_INET6: {
- if (ipv6_enabled()) {
- sockaddr_in6* v6_addr =
- reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
- scope_id = v6_addr->sin6_scope_id;
- ip = IPAddress(v6_addr->sin6_addr);
+ sockaddr_in6* v6_addr =
+ reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
+ scope_id = v6_addr->sin6_scope_id;
+ ip = IPAddress(v6_addr->sin6_addr);
- if (IsIgnoredIPv6(InterfaceAddress(ip))) {
- continue;
- }
-
- break;
- } else {
+ if (IsIgnoredIPv6(InterfaceAddress(ip))) {
continue;
}
+
+ break;
}
- default: { continue; }
+ default: {
+ continue;
+ }
}
IPAddress prefix;
@@ -750,6 +742,7 @@
std::unique_ptr<Network> network(new Network(
name, description, prefix, prefix_length, adapter_type));
network->set_default_local_address_provider(this);
+ network->set_mdns_responder_provider(this);
network->set_scope_id(scope_id);
network->AddIP(ip);
bool ignored = IsIgnoredNetwork(*network);
@@ -1060,6 +1053,13 @@
return static_cast<IPAddress>(selected_ip);
}
+webrtc::MdnsResponderInterface* Network::GetMdnsResponder() const {
+ if (mdns_responder_provider_ == nullptr) {
+ return nullptr;
+ }
+ return mdns_responder_provider_->GetMdnsResponder();
+}
+
uint16_t Network::GetCost() const {
AdapterType type = IsVpn() ? underlying_type_for_vpn_ : type_;
return ComputeNetworkCostByType(type);
diff --git a/rtc_base/network.h b/rtc_base/network.h
index 8b1a5fc..d202f6e 100644
--- a/rtc_base/network.h
+++ b/rtc_base/network.h
@@ -19,10 +19,10 @@
#include <string>
#include <vector>
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
#include "rtc_base/mdns_responder_interface.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/networkmonitor.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/network_monitor.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#if defined(WEBRTC_POSIX)
@@ -57,12 +57,24 @@
class DefaultLocalAddressProvider {
public:
virtual ~DefaultLocalAddressProvider() = default;
+
// The default local address is the local address used in multi-homed endpoint
// when the any address (0.0.0.0 or ::) is used as the local address. It's
// important to check the return value as a IP family may not be enabled.
virtual bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const = 0;
};
+class MdnsResponderProvider {
+ public:
+ virtual ~MdnsResponderProvider() = default;
+
+ // Returns the mDNS responder that can be used to obfuscate the local IP
+ // addresses of ICE host candidates by mDNS hostnames.
+ //
+ // The provider MUST outlive the mDNS responder.
+ virtual webrtc::MdnsResponderInterface* GetMdnsResponder() const = 0;
+};
+
// Generic network manager interface. It provides list of local
// networks.
//
@@ -72,7 +84,8 @@
//
// This allows constructing a NetworkManager subclass on one thread and
// passing it into an object that uses it on a different thread.
-class NetworkManager : public DefaultLocalAddressProvider {
+class NetworkManager : public DefaultLocalAddressProvider,
+ public MdnsResponderProvider {
public:
typedef std::vector<Network*> NetworkList;
@@ -139,9 +152,8 @@
}
};
- // Returns the mDNS responder that can be used to obfuscate the local IP
- // addresses of ICE host candidates by mDNS hostnames.
- virtual webrtc::MdnsResponderInterface* GetMdnsResponder() const;
+ // MdnsResponderProvider interface.
+ webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
};
// Base class for NetworkManager implementations.
@@ -153,12 +165,6 @@
void GetNetworks(NetworkList* networks) const override;
void GetAnyAddressNetworks(NetworkList* networks) override;
- // Defaults to true.
- // TODO(deadbeef): Remove this. Nothing but tests use this; IPv6 is enabled
- // by default everywhere else.
- bool ipv6_enabled() const { return ipv6_enabled_; }
- void set_ipv6_enabled(bool enabled) { ipv6_enabled_ = enabled; }
-
EnumerationPermission enumeration_permission() const override;
bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override;
@@ -194,7 +200,6 @@
NetworkList networks_;
NetworkMap networks_map_;
- bool ipv6_enabled_;
std::unique_ptr<rtc::Network> ipv4_any_address_network_;
std::unique_ptr<rtc::Network> ipv6_any_address_network_;
@@ -310,7 +315,11 @@
default_local_address_provider_ = provider;
}
- // Returns the name of the interface this network is associated wtih.
+ void set_mdns_responder_provider(const MdnsResponderProvider* provider) {
+ mdns_responder_provider_ = provider;
+ }
+
+ // Returns the name of the interface this network is associated with.
const std::string& name() const { return name_; }
// Returns the OS-assigned name for this network. This is useful for
@@ -329,7 +338,7 @@
// Returns the Network's current idea of the 'best' IP it has.
// Or return an unset IP if this network has no active addresses.
// Here is the rule on how we mark the IPv6 address as ignorable for WebRTC.
- // 1) return all global temporary dynamic and non-deprecrated ones.
+ // 1) return all global temporary dynamic and non-deprecated ones.
// 2) if #1 not available, return global ones.
// 3) if #2 not available, use ULA ipv6 as last resort. (ULA stands
// for unique local address, which is not route-able in open
@@ -361,19 +370,11 @@
const std::vector<InterfaceAddress>& GetIPs() const { return ips_; }
// Clear the network's list of addresses.
void ClearIPs() { ips_.clear(); }
- // Sets the mDNS responder that can be used to obfuscate the local IP
+ // Returns the mDNS responder that can be used to obfuscate the local IP
// addresses of host candidates by mDNS names in ICE gathering. After a
// name-address mapping is created by the mDNS responder, queries for the
// created name will be resolved by the responder.
- //
- // The mDNS responder, if not null, should outlive this rtc::Network.
- void SetMdnsResponder(webrtc::MdnsResponderInterface* mdns_responder) {
- mdns_responder_ = mdns_responder;
- }
- // Returns the mDNS responder, which is null by default.
- webrtc::MdnsResponderInterface* GetMdnsResponder() const {
- return mdns_responder_;
- }
+ webrtc::MdnsResponderInterface* GetMdnsResponder() const;
// Returns the scope-id of the network's address.
// Should only be relevant for link-local IPv6 addresses.
@@ -440,13 +441,13 @@
private:
const DefaultLocalAddressProvider* default_local_address_provider_ = nullptr;
+ const MdnsResponderProvider* mdns_responder_provider_ = nullptr;
std::string name_;
std::string description_;
IPAddress prefix_;
int prefix_length_;
std::string key_;
std::vector<InterfaceAddress> ips_;
- webrtc::MdnsResponderInterface* mdns_responder_ = nullptr;
int scope_id_;
bool ignored_;
AdapterType type_;
diff --git a/rtc_base/networkmonitor.cc b/rtc_base/network_monitor.cc
similarity index 98%
rename from rtc_base/networkmonitor.cc
rename to rtc_base/network_monitor.cc
index 0185eab..4eb5290 100644
--- a/rtc_base/networkmonitor.cc
+++ b/rtc_base/network_monitor.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/networkmonitor.h"
+#include "rtc_base/network_monitor.h"
#include <stdint.h>
diff --git a/rtc_base/networkmonitor.h b/rtc_base/network_monitor.h
similarity index 96%
rename from rtc_base/networkmonitor.h
rename to rtc_base/network_monitor.h
index 1ad7663..ed4464d 100644
--- a/rtc_base/networkmonitor.h
+++ b/rtc_base/network_monitor.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NETWORKMONITOR_H_
-#define RTC_BASE_NETWORKMONITOR_H_
+#ifndef RTC_BASE_NETWORK_MONITOR_H_
+#define RTC_BASE_NETWORK_MONITOR_H_
#include "rtc_base/network_constants.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
@@ -120,4 +120,4 @@
} // namespace rtc
-#endif // RTC_BASE_NETWORKMONITOR_H_
+#endif // RTC_BASE_NETWORK_MONITOR_H_
diff --git a/rtc_base/networkroute.h b/rtc_base/network_route.h
similarity index 67%
rename from rtc_base/networkroute.h
rename to rtc_base/network_route.h
index 31c0831..6a8f183 100644
--- a/rtc_base/networkroute.h
+++ b/rtc_base/network_route.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NETWORKROUTE_H_
-#define RTC_BASE_NETWORKROUTE_H_
+#ifndef RTC_BASE_NETWORK_ROUTE_H_
+#define RTC_BASE_NETWORK_ROUTE_H_
#include <stdint.h>
@@ -27,17 +27,7 @@
int last_sent_packet_id = -1;
// The overhead in bytes from IP layer and above.
int packet_overhead = 0;
-
- // |last_sent_packet_id| and |packet_overhead| do not affect the NetworkRoute
- // comparison.
- bool operator==(const NetworkRoute& nr) const {
- return connected == nr.connected &&
- local_network_id == nr.local_network_id &&
- remote_network_id == nr.remote_network_id;
- }
-
- bool operator!=(const NetworkRoute& nr) const { return !(*this == nr); }
};
} // namespace rtc
-#endif // RTC_BASE_NETWORKROUTE_H_
+#endif // RTC_BASE_NETWORK_ROUTE_H_
diff --git a/rtc_base/network_unittest.cc b/rtc_base/network_unittest.cc
index cf1cecc..1ba573e 100644
--- a/rtc_base/network_unittest.cc
+++ b/rtc_base/network_unittest.cc
@@ -16,8 +16,8 @@
#include <vector>
#include "rtc_base/checks.h"
-#include "rtc_base/nethelpers.h"
-#include "rtc_base/networkmonitor.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/network_monitor.h"
#if defined(WEBRTC_POSIX)
#include <net/if.h>
#include <sys/types.h>
@@ -179,6 +179,48 @@
return addr_list;
}
+ struct sockaddr_in* CreateIpv4Addr(const std::string& ip_string) {
+ struct sockaddr_in* ipv4_addr =
+ static_cast<struct sockaddr_in*>(malloc(sizeof(struct sockaddr_in)));
+ memset(ipv4_addr, 0, sizeof(struct sockaddr_in));
+ ipv4_addr->sin_family = AF_INET;
+ IPAddress ip;
+ IPFromString(ip_string, &ip);
+ ipv4_addr->sin_addr = ip.ipv4_address();
+ return ipv4_addr;
+ }
+
+ // Pointers created here need to be released via ReleaseIfAddrs.
+ struct ifaddrs* AddIpv4Address(struct ifaddrs* list,
+ char* if_name,
+ const std::string& ipv4_address,
+ const std::string& ipv4_netmask) {
+ struct ifaddrs* if_addr = new struct ifaddrs;
+ memset(if_addr, 0, sizeof(struct ifaddrs));
+ if_addr->ifa_name = if_name;
+ if_addr->ifa_addr =
+ reinterpret_cast<struct sockaddr*>(CreateIpv4Addr(ipv4_address));
+ if_addr->ifa_netmask =
+ reinterpret_cast<struct sockaddr*>(CreateIpv4Addr(ipv4_netmask));
+ if_addr->ifa_next = list;
+ if_addr->ifa_flags = IFF_RUNNING;
+ return if_addr;
+ }
+
+ struct ifaddrs* InstallIpv4Network(char* if_name,
+ const std::string& ipv4_address,
+ const std::string& ipv4_mask,
+ BasicNetworkManager& network_manager) {
+ ifaddrs* addr_list = nullptr;
+ addr_list = AddIpv4Address(addr_list, if_name, ipv4_address, ipv4_mask);
+ NetworkManager::NetworkList result;
+ bool changed;
+ NetworkManager::Stats stats;
+ CallConvertIfAddrs(network_manager, addr_list, true, &result);
+ network_manager.MergeNetworkList(result, &changed, &stats);
+ return addr_list;
+ }
+
void ReleaseIfAddrs(struct ifaddrs* list) {
struct ifaddrs* if_addr = list;
while (if_addr != nullptr) {
@@ -624,22 +666,10 @@
manager.DumpNetworks();
}
-// Test that we can toggle IPv6 on and off.
-// Crashes on Linux. See webrtc:4923.
-#if defined(WEBRTC_LINUX)
-#define MAYBE_TestIPv6Toggle DISABLED_TestIPv6Toggle
-#else
-#define MAYBE_TestIPv6Toggle TestIPv6Toggle
-#endif
-TEST_F(NetworkTest, MAYBE_TestIPv6Toggle) {
+TEST_F(NetworkTest, TestIPv6Toggle) {
BasicNetworkManager manager;
bool ipv6_found = false;
NetworkManager::NetworkList list;
-#if !defined(WEBRTC_WIN)
- // There should be at least one IPv6 network (fe80::/64 should be in there).
- // TODO(thaloun): Disabling this test on windows for the moment as the test
- // machines don't seem to have IPv6 installed on them at all.
- manager.set_ipv6_enabled(true);
list = GetNetworks(manager, true);
for (NetworkManager::NetworkList::iterator it = list.begin();
it != list.end(); ++it) {
@@ -653,22 +683,6 @@
it != list.end(); ++it) {
delete (*it);
}
-#endif
- ipv6_found = false;
- manager.set_ipv6_enabled(false);
- list = GetNetworks(manager, true);
- for (NetworkManager::NetworkList::iterator it = list.begin();
- it != list.end(); ++it) {
- if ((*it)->prefix().family() == AF_INET6) {
- ipv6_found = true;
- break;
- }
- }
- EXPECT_FALSE(ipv6_found);
- for (NetworkManager::NetworkList::iterator it = list.begin();
- it != list.end(); ++it) {
- delete (*it);
- }
}
// Test that when network interfaces are sorted and given preference values,
@@ -830,6 +844,8 @@
// a few cases. Note that UNKNOWN type for non-matching strings has been tested
// in the above test.
TEST_F(NetworkTest, TestGetAdapterTypeFromNameMatching) {
+ std::string ipv4_address1 = "192.0.0.121";
+ std::string ipv4_mask = "255.255.255.0";
std::string ipv6_address1 = "1000:2000:3000:4000:0:0:0:1";
std::string ipv6_address2 = "1000:2000:3000:8000:0:0:0:1";
std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF::";
@@ -850,7 +866,7 @@
ReleaseIfAddrs(addr_list);
strcpy(if_name, "eth0");
- addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager);
+ addr_list = InstallIpv4Network(if_name, ipv4_address1, ipv4_mask, manager);
EXPECT_EQ(ADAPTER_TYPE_ETHERNET, GetAdapterType(manager));
ClearNetworks(manager);
ReleaseIfAddrs(addr_list);
@@ -886,6 +902,12 @@
EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager));
ClearNetworks(manager);
ReleaseIfAddrs(addr_list);
+
+ strcpy(if_name, "clat4");
+ addr_list = InstallIpv4Network(if_name, ipv4_address1, ipv4_mask, manager);
+ EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager));
+ ClearNetworks(manager);
+ ReleaseIfAddrs(addr_list);
#else
// TODO(deadbeef): If not iOS or Android, "wlan0" should be treated as
// "unknown"? Why? This should be fixed if there's no good reason.
diff --git a/rtc_base/nullsocketserver.cc b/rtc_base/null_socket_server.cc
similarity index 95%
rename from rtc_base/nullsocketserver.cc
rename to rtc_base/null_socket_server.cc
index ec042dd..f446b3d 100644
--- a/rtc_base/nullsocketserver.cc
+++ b/rtc_base/null_socket_server.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/nullsocketserver.h"
+#include "rtc_base/null_socket_server.h"
#include "rtc_base/checks.h"
namespace rtc {
diff --git a/rtc_base/nullsocketserver.h b/rtc_base/null_socket_server.h
similarity index 81%
rename from rtc_base/nullsocketserver.h
rename to rtc_base/null_socket_server.h
index 47a7fa6..da22c79 100644
--- a/rtc_base/nullsocketserver.h
+++ b/rtc_base/null_socket_server.h
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NULLSOCKETSERVER_H_
-#define RTC_BASE_NULLSOCKETSERVER_H_
+#ifndef RTC_BASE_NULL_SOCKET_SERVER_H_
+#define RTC_BASE_NULL_SOCKET_SERVER_H_
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/event.h"
#include "rtc_base/socket.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/socket_server.h"
namespace rtc {
@@ -35,4 +35,4 @@
} // namespace rtc
-#endif // RTC_BASE_NULLSOCKETSERVER_H_
+#endif // RTC_BASE_NULL_SOCKET_SERVER_H_
diff --git a/rtc_base/nullsocketserver_unittest.cc b/rtc_base/null_socket_server_unittest.cc
similarity index 82%
rename from rtc_base/nullsocketserver_unittest.cc
rename to rtc_base/null_socket_server_unittest.cc
index f1d65ea..8268911 100644
--- a/rtc_base/nullsocketserver_unittest.cc
+++ b/rtc_base/null_socket_server_unittest.cc
@@ -8,8 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/nullsocketserver.h"
+#include "rtc_base/null_socket_server.h"
+
+#include <stdint.h>
+#include <memory>
+
#include "rtc_base/gunit.h"
+#include "rtc_base/location.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/time_utils.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/numerics/histogram_percentile_counter.h b/rtc_base/numerics/histogram_percentile_counter.h
index 7e5743f..f52513c 100644
--- a/rtc_base/numerics/histogram_percentile_counter.h
+++ b/rtc_base/numerics/histogram_percentile_counter.h
@@ -11,6 +11,7 @@
#ifndef RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_
#define RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_
+#include <stddef.h>
#include <stdint.h>
#include <map>
#include <vector>
diff --git a/rtc_base/numerics/histogram_percentile_counter_unittest.cc b/rtc_base/numerics/histogram_percentile_counter_unittest.cc
index a004dba..6fdaa36 100644
--- a/rtc_base/numerics/histogram_percentile_counter_unittest.cc
+++ b/rtc_base/numerics/histogram_percentile_counter_unittest.cc
@@ -10,6 +10,7 @@
#include "rtc_base/numerics/histogram_percentile_counter.h"
+#include <cstdint>
#include <utility>
#include <vector>
diff --git a/rtc_base/numerics/mathutils.h b/rtc_base/numerics/math_utils.h
similarity index 91%
rename from rtc_base/numerics/mathutils.h
rename to rtc_base/numerics/math_utils.h
index 5036c8f..8a91958 100644
--- a/rtc_base/numerics/mathutils.h
+++ b/rtc_base/numerics/math_utils.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_NUMERICS_MATHUTILS_H_
-#define RTC_BASE_NUMERICS_MATHUTILS_H_
+#ifndef RTC_BASE_NUMERICS_MATH_UTILS_H_
+#define RTC_BASE_NUMERICS_MATH_UTILS_H_
#include <math.h>
#include <type_traits>
@@ -36,4 +36,4 @@
return static_cast<unsigned_type>(x) - static_cast<unsigned_type>(y);
}
-#endif // RTC_BASE_NUMERICS_MATHUTILS_H_
+#endif // RTC_BASE_NUMERICS_MATH_UTILS_H_
diff --git a/rtc_base/numerics/mod_ops.h b/rtc_base/numerics/mod_ops.h
index 90d3ed8..65618b4 100644
--- a/rtc_base/numerics/mod_ops.h
+++ b/rtc_base/numerics/mod_ops.h
@@ -12,7 +12,6 @@
#define RTC_BASE_NUMERICS_MOD_OPS_H_
#include <algorithm>
-#include <limits>
#include <type_traits>
#include "rtc_base/checks.h"
diff --git a/rtc_base/numerics/mod_ops_unittest.cc b/rtc_base/numerics/mod_ops_unittest.cc
index 7b03e65..3bd2034 100644
--- a/rtc_base/numerics/mod_ops_unittest.cc
+++ b/rtc_base/numerics/mod_ops_unittest.cc
@@ -9,6 +9,9 @@
*/
#include "rtc_base/numerics/mod_ops.h"
+
+#include <stdint.h>
+
#include "test/gtest.h"
namespace webrtc {
diff --git a/rtc_base/numerics/moving_average.h b/rtc_base/numerics/moving_average.h
index 770e47d..1ae26ff 100644
--- a/rtc_base/numerics/moving_average.h
+++ b/rtc_base/numerics/moving_average.h
@@ -11,6 +11,8 @@
#ifndef RTC_BASE_NUMERICS_MOVING_AVERAGE_H_
#define RTC_BASE_NUMERICS_MOVING_AVERAGE_H_
+#include <stddef.h>
+#include <stdint.h>
#include <vector>
#include "absl/types/optional.h"
diff --git a/rtc_base/numerics/moving_max_counter.h b/rtc_base/numerics/moving_max_counter.h
index 6c6286d..ca956e9 100644
--- a/rtc_base/numerics/moving_max_counter.h
+++ b/rtc_base/numerics/moving_max_counter.h
@@ -19,7 +19,7 @@
#include "absl/types/optional.h"
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
diff --git a/rtc_base/numerics/moving_median_filter.h b/rtc_base/numerics/moving_median_filter.h
index b5c5fce..b4d8741 100644
--- a/rtc_base/numerics/moving_median_filter.h
+++ b/rtc_base/numerics/moving_median_filter.h
@@ -11,10 +11,11 @@
#ifndef RTC_BASE_NUMERICS_MOVING_MEDIAN_FILTER_H_
#define RTC_BASE_NUMERICS_MOVING_MEDIAN_FILTER_H_
+#include <stddef.h>
#include <list>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/numerics/percentile_filter.h"
namespace webrtc {
diff --git a/rtc_base/numerics/moving_median_filter_unittest.cc b/rtc_base/numerics/moving_median_filter_unittest.cc
index 5a6eb3d..41684b2 100644
--- a/rtc_base/numerics/moving_median_filter_unittest.cc
+++ b/rtc_base/numerics/moving_median_filter_unittest.cc
@@ -9,6 +9,9 @@
*/
#include "rtc_base/numerics/moving_median_filter.h"
+
+#include <stdint.h>
+
#include "test/gtest.h"
namespace webrtc {
diff --git a/rtc_base/numerics/percentile_filter.h b/rtc_base/numerics/percentile_filter.h
index cba4463..4781963 100644
--- a/rtc_base/numerics/percentile_filter.h
+++ b/rtc_base/numerics/percentile_filter.h
@@ -12,7 +12,6 @@
#define RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_
#include <stdint.h>
-
#include <iterator>
#include <set>
diff --git a/rtc_base/numerics/percentile_filter_unittest.cc b/rtc_base/numerics/percentile_filter_unittest.cc
index 11fb4a5..8ed6d67 100644
--- a/rtc_base/numerics/percentile_filter_unittest.cc
+++ b/rtc_base/numerics/percentile_filter_unittest.cc
@@ -8,11 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <stdlib.h>
#include <algorithm>
#include <climits>
+#include <cstdint>
#include <random>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/numerics/percentile_filter.h"
#include "test/gtest.h"
@@ -32,9 +34,9 @@
RTC_DISALLOW_COPY_AND_ASSIGN(PercentileFilterTest);
};
-INSTANTIATE_TEST_CASE_P(PercentileFilterTests,
- PercentileFilterTest,
- ::testing::Values(0.0f, 0.1f, 0.5f, 0.9f, 1.0f));
+INSTANTIATE_TEST_SUITE_P(PercentileFilterTests,
+ PercentileFilterTest,
+ ::testing::Values(0.0f, 0.1f, 0.5f, 0.9f, 1.0f));
TEST(PercentileFilterTest, MinFilter) {
PercentileFilter<int64_t> filter(0.0f);
diff --git a/rtc_base/numerics/safe_minmax.h b/rtc_base/numerics/safe_minmax.h
index 8d00afb..6c41dfd 100644
--- a/rtc_base/numerics/safe_minmax.h
+++ b/rtc_base/numerics/safe_minmax.h
@@ -42,7 +42,7 @@
//
// 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
+// 3. has the same signedness as the type of the first 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
diff --git a/rtc_base/numerics/sample_counter.cc b/rtc_base/numerics/sample_counter.cc
index bab47f1..7f76b74 100644
--- a/rtc_base/numerics/sample_counter.cc
+++ b/rtc_base/numerics/sample_counter.cc
@@ -57,6 +57,13 @@
return max_;
}
+absl::optional<int64_t> SampleCounter::Sum(int64_t min_required_samples) const {
+ RTC_DCHECK_GT(min_required_samples, 0);
+ if (num_samples_ < min_required_samples)
+ return absl::nullopt;
+ return sum_;
+}
+
int64_t SampleCounter::NumSamples() const {
return num_samples_;
}
diff --git a/rtc_base/numerics/sample_counter.h b/rtc_base/numerics/sample_counter.h
index 18bd36b..93d39c3 100644
--- a/rtc_base/numerics/sample_counter.h
+++ b/rtc_base/numerics/sample_counter.h
@@ -26,6 +26,7 @@
void Add(int sample);
absl::optional<int> Avg(int64_t min_required_samples) const;
absl::optional<int> Max() const;
+ absl::optional<int64_t> Sum(int64_t min_required_samples) const;
int64_t NumSamples() const;
void Reset();
// Adds all the samples from the |other| SampleCounter as if they were all
diff --git a/rtc_base/numerics/sample_counter_unittest.cc b/rtc_base/numerics/sample_counter_unittest.cc
index 4085370..e87c809 100644
--- a/rtc_base/numerics/sample_counter_unittest.cc
+++ b/rtc_base/numerics/sample_counter_unittest.cc
@@ -10,8 +10,7 @@
#include "rtc_base/numerics/sample_counter.h"
-#include <utility>
-#include <vector>
+#include <initializer_list>
#include "test/gmock.h"
#include "test/gtest.h"
@@ -34,6 +33,7 @@
counter.Add(value);
}
EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt));
+ EXPECT_THAT(counter.Sum(kMinSamples), Eq(absl::nullopt));
EXPECT_THAT(counter.Max(), Eq(5));
}
@@ -44,6 +44,7 @@
counter.Add(value);
}
EXPECT_THAT(counter.Avg(kMinSamples), Eq(3));
+ EXPECT_THAT(counter.Sum(kMinSamples), Eq(15));
EXPECT_THAT(counter.Max(), Eq(5));
}
diff --git a/rtc_base/numerics/samples_stats_counter.cc b/rtc_base/numerics/samples_stats_counter.cc
new file mode 100644
index 0000000..1348cba
--- /dev/null
+++ b/rtc_base/numerics/samples_stats_counter.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 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 "rtc_base/numerics/samples_stats_counter.h"
+
+#include <algorithm>
+#include <cmath>
+
+namespace webrtc {
+
+SamplesStatsCounter::SamplesStatsCounter() = default;
+SamplesStatsCounter::~SamplesStatsCounter() = default;
+SamplesStatsCounter::SamplesStatsCounter(const SamplesStatsCounter&) = default;
+SamplesStatsCounter& SamplesStatsCounter::operator=(
+ const SamplesStatsCounter&) = default;
+SamplesStatsCounter::SamplesStatsCounter(SamplesStatsCounter&&) = default;
+SamplesStatsCounter& SamplesStatsCounter::operator=(SamplesStatsCounter&&) =
+ default;
+
+void SamplesStatsCounter::AddSample(double value) {
+ samples_.push_back(value);
+ sorted_ = false;
+ if (value > max_) {
+ max_ = value;
+ }
+ if (value < min_) {
+ min_ = value;
+ }
+ sum_ += value;
+ sum_squared_ += value * value;
+}
+
+double SamplesStatsCounter::GetPercentile(double percentile) {
+ RTC_DCHECK(!IsEmpty());
+ RTC_CHECK_GE(percentile, 0);
+ RTC_CHECK_LE(percentile, 1);
+ if (!sorted_) {
+ std::sort(samples_.begin(), samples_.end());
+ sorted_ = true;
+ }
+ const double raw_rank = percentile * (samples_.size() - 1);
+ double int_part;
+ double fract_part = std::modf(raw_rank, &int_part);
+ size_t rank = static_cast<size_t>(int_part);
+ if (fract_part >= 1.0) {
+ // It can happen due to floating point calculation error.
+ rank++;
+ fract_part -= 1.0;
+ }
+
+ RTC_DCHECK_GE(rank, 0);
+ RTC_DCHECK_LT(rank, samples_.size());
+ RTC_DCHECK_GE(fract_part, 0);
+ RTC_DCHECK_LT(fract_part, 1);
+ RTC_DCHECK(rank + fract_part == raw_rank);
+
+ const double low = samples_[rank];
+ const double high = samples_[std::min(rank + 1, samples_.size() - 1)];
+ return low + fract_part * (high - low);
+}
+
+} // namespace webrtc
diff --git a/rtc_base/numerics/samples_stats_counter.h b/rtc_base/numerics/samples_stats_counter.h
new file mode 100644
index 0000000..a982b2e
--- /dev/null
+++ b/rtc_base/numerics/samples_stats_counter.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef RTC_BASE_NUMERICS_SAMPLES_STATS_COUNTER_H_
+#define RTC_BASE_NUMERICS_SAMPLES_STATS_COUNTER_H_
+
+#include <math.h>
+#include <limits>
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+class SamplesStatsCounter {
+ public:
+ SamplesStatsCounter();
+ ~SamplesStatsCounter();
+ SamplesStatsCounter(const SamplesStatsCounter&);
+ SamplesStatsCounter& operator=(const SamplesStatsCounter&);
+ SamplesStatsCounter(SamplesStatsCounter&&);
+ SamplesStatsCounter& operator=(SamplesStatsCounter&&);
+
+ // Adds sample to the stats in amortized O(1) time.
+ void AddSample(double value);
+
+ // Returns if there are any values in O(1) time.
+ bool IsEmpty() const { return samples_.empty(); }
+
+ // Returns min in O(1) time. This function may not be called if there are no
+ // samples.
+ double GetMin() const {
+ RTC_DCHECK(!IsEmpty());
+ return min_;
+ }
+ // Returns max in O(1) time. This function may not be called if there are no
+ // samples.
+ double GetMax() const {
+ RTC_DCHECK(!IsEmpty());
+ return max_;
+ }
+ // Returns average in O(1) time. This function may not be called if there are
+ // no samples.
+ double GetAverage() const {
+ RTC_DCHECK(!IsEmpty());
+ return sum_ / samples_.size();
+ }
+ // Returns variance in O(1) time. This function may not be called if there are
+ // no samples.
+ double GetVariance() const {
+ RTC_DCHECK(!IsEmpty());
+ return sum_squared_ / samples_.size() - GetAverage() * GetAverage();
+ }
+ // Returns standard deviation in O(1) time. This function may not be called if
+ // there are no samples.
+ double GetStandardDeviation() const {
+ RTC_DCHECK(!IsEmpty());
+ return sqrt(GetVariance());
+ }
+ // Returns percentile in O(nlogn) on first call and in O(1) after, if no
+ // additions were done. This function may not be called if there are no
+ // samples.
+ //
+ // |percentile| has to be in [0; 1]. 0 percentile is the min in the array and
+ // 1 percentile is the max in the array.
+ double GetPercentile(double percentile);
+
+ private:
+ std::vector<double> samples_;
+ double min_ = std::numeric_limits<double>::max();
+ double max_ = std::numeric_limits<double>::min();
+ double sum_ = 0;
+ double sum_squared_ = 0;
+ bool sorted_ = false;
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_NUMERICS_SAMPLES_STATS_COUNTER_H_
diff --git a/rtc_base/numerics/samples_stats_counter_unittest.cc b/rtc_base/numerics/samples_stats_counter_unittest.cc
new file mode 100644
index 0000000..e6d9f67
--- /dev/null
+++ b/rtc_base/numerics/samples_stats_counter_unittest.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 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 "rtc_base/numerics/samples_stats_counter.h"
+
+#include <math.h>
+#include <algorithm>
+#include <vector>
+
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+SamplesStatsCounter CreateStatsFilledWithIntsFrom1ToN(int n) {
+ std::vector<double> data;
+ for (int i = 1; i <= n; i++) {
+ data.push_back(i);
+ }
+ std::random_shuffle(data.begin(), data.end());
+
+ SamplesStatsCounter stats;
+ for (double v : data) {
+ stats.AddSample(v);
+ }
+ return stats;
+}
+
+} // namespace
+
+TEST(SamplesStatsCounter, FullSimpleTest) {
+ SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(100);
+
+ EXPECT_TRUE(!stats.IsEmpty());
+ EXPECT_DOUBLE_EQ(stats.GetMin(), 1.0);
+ EXPECT_DOUBLE_EQ(stats.GetMax(), 100.0);
+ EXPECT_DOUBLE_EQ(stats.GetAverage(), 50.5);
+ for (int i = 1; i <= 100; i++) {
+ double p = i / 100.0;
+ EXPECT_GE(stats.GetPercentile(p), i);
+ EXPECT_LT(stats.GetPercentile(p), i + 1);
+ }
+}
+
+TEST(SamplesStatsCounter, VarianceAndDeviation) {
+ SamplesStatsCounter stats;
+ stats.AddSample(2);
+ stats.AddSample(2);
+ stats.AddSample(-1);
+ stats.AddSample(5);
+
+ EXPECT_DOUBLE_EQ(stats.GetAverage(), 2.0);
+ EXPECT_DOUBLE_EQ(stats.GetVariance(), 4.5);
+ EXPECT_DOUBLE_EQ(stats.GetStandardDeviation(), sqrt(4.5));
+}
+
+TEST(SamplesStatsCounter, FractionPercentile) {
+ SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5);
+
+ EXPECT_DOUBLE_EQ(stats.GetPercentile(0.5), 3);
+}
+
+TEST(SamplesStatsCounter, TestBorderValues) {
+ SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5);
+
+ EXPECT_GE(stats.GetPercentile(0.01), 1);
+ EXPECT_LT(stats.GetPercentile(0.01), 2);
+ EXPECT_DOUBLE_EQ(stats.GetPercentile(1.0), 5);
+}
+
+} // namespace webrtc
diff --git a/rtc_base/numerics/sequence_number_util.h b/rtc_base/numerics/sequence_number_util.h
index c55513a..9a7361d 100644
--- a/rtc_base/numerics/sequence_number_util.h
+++ b/rtc_base/numerics/sequence_number_util.h
@@ -11,12 +11,13 @@
#ifndef RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_
#define RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_
+#include <stdint.h>
#include <limits>
#include <type_traits>
#include "absl/types/optional.h"
+#include "rtc_base/checks.h"
#include "rtc_base/numerics/mod_ops.h"
-#include "rtc_base/numerics/safe_compare.h"
namespace webrtc {
diff --git a/rtc_base/numerics/sequence_number_util_unittest.cc b/rtc_base/numerics/sequence_number_util_unittest.cc
index beb2b52..881e017 100644
--- a/rtc_base/numerics/sequence_number_util_unittest.cc
+++ b/rtc_base/numerics/sequence_number_util_unittest.cc
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <cstdint>
+#include <iterator>
#include <set>
#include "rtc_base/numerics/sequence_number_util.h"
diff --git a/rtc_base/onetimeevent.h b/rtc_base/one_time_event.h
similarity index 89%
rename from rtc_base/onetimeevent.h
rename to rtc_base/one_time_event.h
index f649f15..c5ccbf6 100644
--- a/rtc_base/onetimeevent.h
+++ b/rtc_base/one_time_event.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ONETIMEEVENT_H_
-#define RTC_BASE_ONETIMEEVENT_H_
+#ifndef RTC_BASE_ONE_TIME_EVENT_H_
+#define RTC_BASE_ONE_TIME_EVENT_H_
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
namespace webrtc {
// Provides a simple way to perform an operation (such as logging) one
@@ -57,4 +57,4 @@
} // namespace webrtc
-#endif // RTC_BASE_ONETIMEEVENT_H_
+#endif // RTC_BASE_ONE_TIME_EVENT_H_
diff --git a/rtc_base/onetimeevent_unittest.cc b/rtc_base/one_time_event_unittest.cc
similarity index 92%
rename from rtc_base/onetimeevent_unittest.cc
rename to rtc_base/one_time_event_unittest.cc
index 49cae07..39fd8f9 100644
--- a/rtc_base/onetimeevent_unittest.cc
+++ b/rtc_base/one_time_event_unittest.cc
@@ -8,8 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/onetimeevent.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/one_time_event.h"
+
+#include "test/gtest.h"
namespace webrtc {
diff --git a/rtc_base/openssladapter.cc b/rtc_base/openssl_adapter.cc
similarity index 94%
rename from rtc_base/openssladapter.cc
rename to rtc_base/openssl_adapter.cc
index fcfa53b..388b9a0 100644
--- a/rtc_base/openssladapter.cc
+++ b/rtc_base/openssl_adapter.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/openssladapter.h"
+#include "rtc_base/openssl_adapter.h"
#include <errno.h>
@@ -26,39 +26,11 @@
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/opensslcertificate.h"
-#include "rtc_base/opensslutility.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/openssl_certificate.h"
+#include "rtc_base/openssl_utility.h"
+#include "rtc_base/string_encode.h"
#include "rtc_base/thread.h"
-#ifndef OPENSSL_IS_BORINGSSL
-
-// TODO(benwright): Use a nicer abstraction for mutex.
-
-#if defined(WEBRTC_WIN)
-#define MUTEX_TYPE HANDLE
-#define MUTEX_SETUP(x) (x) = CreateMutex(nullptr, FALSE, nullptr)
-#define MUTEX_CLEANUP(x) CloseHandle(x)
-#define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
-#define MUTEX_UNLOCK(x) ReleaseMutex(x)
-#define THREAD_ID GetCurrentThreadId()
-#elif defined(WEBRTC_POSIX)
-#define MUTEX_TYPE pthread_mutex_t
-#define MUTEX_SETUP(x) pthread_mutex_init(&(x), nullptr)
-#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
-#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
-#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
-#define THREAD_ID pthread_self()
-#else
-#error You must define mutex operations appropriate for your platform!
-#endif
-
-struct CRYPTO_dynlock_value {
- MUTEX_TYPE mutex;
-};
-
-#endif // #ifndef OPENSSL_IS_BORINGSSL
-
//////////////////////////////////////////////////////////////////////
// SocketBIO
//////////////////////////////////////////////////////////////////////
@@ -881,17 +853,8 @@
}
SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) {
- // Use (D)TLS 1.2.
- // Note: BoringSSL supports a range of versions by setting max/min version
- // (Default V1.0 to V1.2). However (D)TLSv1_2_client_method functions used
- // below in OpenSSL only support V1.2.
- SSL_CTX* ctx = nullptr;
-#ifdef OPENSSL_IS_BORINGSSL
- ctx = SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
-#else
- ctx = SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLSv1_2_client_method()
- : TLSv1_2_client_method());
-#endif // OPENSSL_IS_BORINGSSL
+ SSL_CTX* ctx =
+ SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
if (ctx == nullptr) {
unsigned long error = ERR_get_error(); // NOLINT: type used by OpenSSL.
RTC_LOG(LS_WARNING) << "SSL_CTX creation failed: " << '"'
diff --git a/rtc_base/openssladapter.h b/rtc_base/openssl_adapter.h
similarity index 93%
rename from rtc_base/openssladapter.h
rename to rtc_base/openssl_adapter.h
index 2e3a355..7219671 100644
--- a/rtc_base/openssladapter.h
+++ b/rtc_base/openssl_adapter.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLADAPTER_H_
-#define RTC_BASE_OPENSSLADAPTER_H_
+#ifndef RTC_BASE_OPENSSL_ADAPTER_H_
+#define RTC_BASE_OPENSSL_ADAPTER_H_
#include <stddef.h>
#include <stdint.h>
@@ -17,18 +17,18 @@
#include <string>
#include <vector>
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
-#include "rtc_base/opensslidentity.h"
-#include "rtc_base/opensslsessioncache.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/openssl_identity.h"
+#include "rtc_base/openssl_session_cache.h"
#include "rtc_base/socket.h"
-#include "rtc_base/socketaddress.h"
-#include "rtc_base/ssladapter.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/ssl_adapter.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
namespace rtc {
@@ -189,4 +189,4 @@
} // namespace rtc
-#endif // RTC_BASE_OPENSSLADAPTER_H_
+#endif // RTC_BASE_OPENSSL_ADAPTER_H_
diff --git a/rtc_base/openssladapter_unittest.cc b/rtc_base/openssl_adapter_unittest.cc
similarity index 98%
rename from rtc_base/openssladapter_unittest.cc
rename to rtc_base/openssl_adapter_unittest.cc
index 4db00e5..2b171e6 100644
--- a/rtc_base/openssladapter_unittest.cc
+++ b/rtc_base/openssl_adapter_unittest.cc
@@ -13,9 +13,9 @@
#include <vector>
#include "absl/memory/memory.h"
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/openssladapter.h"
+#include "rtc_base/openssl_adapter.h"
#include "test/gmock.h"
namespace rtc {
diff --git a/rtc_base/opensslcertificate.cc b/rtc_base/openssl_certificate.cc
similarity index 97%
rename from rtc_base/opensslcertificate.cc
rename to rtc_base/openssl_certificate.cc
index 4e61b86..c22e5fb 100644
--- a/rtc_base/opensslcertificate.cc
+++ b/rtc_base/openssl_certificate.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/opensslcertificate.h"
+#include "rtc_base/openssl_certificate.h"
#if defined(WEBRTC_WIN)
// Must be included first before openssl headers.
@@ -24,10 +24,10 @@
#include "rtc_base/checks.h"
#include "rtc_base/helpers.h"
#include "rtc_base/logging.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/openssldigest.h"
-#include "rtc_base/opensslidentity.h"
-#include "rtc_base/opensslutility.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/openssl_digest.h"
+#include "rtc_base/openssl_identity.h"
+#include "rtc_base/openssl_utility.h"
namespace rtc {
namespace {
diff --git a/rtc_base/opensslcertificate.h b/rtc_base/openssl_certificate.h
similarity index 90%
rename from rtc_base/opensslcertificate.h
rename to rtc_base/openssl_certificate.h
index 088725c..9b61eee 100644
--- a/rtc_base/opensslcertificate.h
+++ b/rtc_base/openssl_certificate.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLCERTIFICATE_H_
-#define RTC_BASE_OPENSSLCERTIFICATE_H_
+#ifndef RTC_BASE_OPENSSL_CERTIFICATE_H_
+#define RTC_BASE_OPENSSL_CERTIFICATE_H_
#include <openssl/ossl_typ.h>
@@ -18,9 +18,9 @@
#include <string>
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
namespace rtc {
@@ -75,4 +75,4 @@
} // namespace rtc
-#endif // RTC_BASE_OPENSSLCERTIFICATE_H_
+#endif // RTC_BASE_OPENSSL_CERTIFICATE_H_
diff --git a/rtc_base/openssldigest.cc b/rtc_base/openssl_digest.cc
similarity index 98%
rename from rtc_base/openssldigest.cc
rename to rtc_base/openssl_digest.cc
index da90b65..1cf5bc0 100644
--- a/rtc_base/openssldigest.cc
+++ b/rtc_base/openssl_digest.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/openssldigest.h"
+#include "rtc_base/openssl_digest.h"
#include "rtc_base/checks.h" // RTC_DCHECK, RTC_CHECK
#include "rtc_base/openssl.h"
diff --git a/rtc_base/openssldigest.h b/rtc_base/openssl_digest.h
similarity index 89%
rename from rtc_base/openssldigest.h
rename to rtc_base/openssl_digest.h
index 82dc9a9..ee39eb8 100644
--- a/rtc_base/openssldigest.h
+++ b/rtc_base/openssl_digest.h
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLDIGEST_H_
-#define RTC_BASE_OPENSSLDIGEST_H_
+#ifndef RTC_BASE_OPENSSL_DIGEST_H_
+#define RTC_BASE_OPENSSL_DIGEST_H_
-#include <openssl/base.h>
+#include <openssl/ossl_typ.h>
#include <stddef.h>
#include <string>
-#include "rtc_base/messagedigest.h"
+#include "rtc_base/message_digest.h"
namespace rtc {
@@ -46,4 +46,4 @@
} // namespace rtc
-#endif // RTC_BASE_OPENSSLDIGEST_H_
+#endif // RTC_BASE_OPENSSL_DIGEST_H_
diff --git a/rtc_base/opensslidentity.cc b/rtc_base/openssl_identity.cc
similarity index 99%
rename from rtc_base/opensslidentity.cc
rename to rtc_base/openssl_identity.cc
index 9850c85..531c971 100644
--- a/rtc_base/opensslidentity.cc
+++ b/rtc_base/openssl_identity.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/opensslidentity.h"
+#include "rtc_base/openssl_identity.h"
#include <memory>
#include <utility>
@@ -32,7 +32,7 @@
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/openssl.h"
-#include "rtc_base/opensslutility.h"
+#include "rtc_base/openssl_utility.h"
namespace rtc {
diff --git a/rtc_base/opensslidentity.h b/rtc_base/openssl_identity.h
similarity index 92%
rename from rtc_base/opensslidentity.h
rename to rtc_base/openssl_identity.h
index fcf7deb..f0c4fb8 100644
--- a/rtc_base/opensslidentity.h
+++ b/rtc_base/openssl_identity.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLIDENTITY_H_
-#define RTC_BASE_OPENSSLIDENTITY_H_
+#ifndef RTC_BASE_OPENSSL_IDENTITY_H_
+#define RTC_BASE_OPENSSL_IDENTITY_H_
#include <openssl/ossl_typ.h>
@@ -18,10 +18,10 @@
#include <string>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/opensslcertificate.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/openssl_certificate.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
namespace rtc {
@@ -98,4 +98,4 @@
} // namespace rtc
-#endif // RTC_BASE_OPENSSLIDENTITY_H_
+#endif // RTC_BASE_OPENSSL_IDENTITY_H_
diff --git a/rtc_base/openssl_key_derivation_hkdf.cc b/rtc_base/openssl_key_derivation_hkdf.cc
index 52af667..6b75e62 100644
--- a/rtc_base/openssl_key_derivation_hkdf.cc
+++ b/rtc_base/openssl_key_derivation_hkdf.cc
@@ -10,19 +10,57 @@
#include "rtc_base/openssl_key_derivation_hkdf.h"
-#include <openssl/digest.h>
-#include <openssl/err.h>
-#include <openssl/hkdf.h>
-#include <openssl/sha.h>
-
#include <algorithm>
#include <utility>
+#include <openssl/ossl_typ.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#else
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#endif
+#include <openssl/err.h>
+#include <openssl/sha.h>
+
#include "rtc_base/buffer.h"
#include "rtc_base/openssl.h"
namespace rtc {
+#ifndef OPENSSL_IS_BORINGSSL
+namespace {
+
+// HKDF is static within OpenSSL and hence not accessible to the caller.
+// This internal implementation allows for compatibility with BoringSSL.
+static int HKDF(uint8_t* out_key,
+ size_t out_len,
+ const EVP_MD* digest,
+ const uint8_t* secret,
+ size_t secret_len,
+ const uint8_t* salt,
+ size_t salt_len,
+ const uint8_t* info,
+ size_t info_len) {
+ EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+
+ if (EVP_PKEY_derive_init(pctx) <= 0 ||
+ EVP_PKEY_CTX_set_hkdf_md(pctx, digest) <= 0 ||
+ EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_len) <= 0 ||
+ EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len) <= 0 ||
+ EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len) <= 0 ||
+ EVP_PKEY_derive(pctx, out_key, &out_len) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ return 0;
+ }
+ EVP_PKEY_CTX_free(pctx);
+ return 1;
+}
+
+} // namespace
+#endif
+
OpenSSLKeyDerivationHKDF::OpenSSLKeyDerivationHKDF() = default;
OpenSSLKeyDerivationHKDF::~OpenSSLKeyDerivationHKDF() = default;
diff --git a/rtc_base/openssl_key_derivation_hkdf.h b/rtc_base/openssl_key_derivation_hkdf.h
index ebf43cf..7f88252 100644
--- a/rtc_base/openssl_key_derivation_hkdf.h
+++ b/rtc_base/openssl_key_derivation_hkdf.h
@@ -11,7 +11,7 @@
#ifndef RTC_BASE_OPENSSL_KEY_DERIVATION_HKDF_H_
#define RTC_BASE_OPENSSL_KEY_DERIVATION_HKDF_H_
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/key_derivation.h"
namespace rtc {
diff --git a/rtc_base/opensslsessioncache.cc b/rtc_base/openssl_session_cache.cc
similarity index 94%
rename from rtc_base/opensslsessioncache.cc
rename to rtc_base/openssl_session_cache.cc
index 2e37d55..270abe8 100644
--- a/rtc_base/opensslsessioncache.cc
+++ b/rtc_base/openssl_session_cache.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/opensslsessioncache.h"
+#include "rtc_base/openssl_session_cache.h"
#include "rtc_base/checks.h"
#include "rtc_base/openssl.h"
@@ -22,7 +22,7 @@
}
OpenSSLSessionCache::~OpenSSLSessionCache() {
- for (auto it : sessions_) {
+ for (const auto& it : sessions_) {
SSL_SESSION_free(it.second);
}
SSL_CTX_free(ssl_ctx_);
diff --git a/rtc_base/opensslsessioncache.h b/rtc_base/openssl_session_cache.h
similarity index 92%
rename from rtc_base/opensslsessioncache.h
rename to rtc_base/openssl_session_cache.h
index c74b7bf..e53e41a 100644
--- a/rtc_base/opensslsessioncache.h
+++ b/rtc_base/openssl_session_cache.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLSESSIONCACHE_H_
-#define RTC_BASE_OPENSSLSESSIONCACHE_H_
+#ifndef RTC_BASE_OPENSSL_SESSION_CACHE_H_
+#define RTC_BASE_OPENSSL_SESSION_CACHE_H_
#include <openssl/ossl_typ.h>
#include <map>
#include <string>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ssl_stream_adapter.h"
#ifndef OPENSSL_IS_BORINGSSL
typedef struct ssl_session_st SSL_SESSION;
@@ -64,4 +64,4 @@
} // namespace rtc
-#endif // RTC_BASE_OPENSSLSESSIONCACHE_H_
+#endif // RTC_BASE_OPENSSL_SESSION_CACHE_H_
diff --git a/rtc_base/opensslsessioncache_unittest.cc b/rtc_base/openssl_session_cache_unittest.cc
similarity index 98%
rename from rtc_base/opensslsessioncache_unittest.cc
rename to rtc_base/openssl_session_cache_unittest.cc
index 6489b2b..366fc26 100644
--- a/rtc_base/opensslsessioncache_unittest.cc
+++ b/rtc_base/openssl_session_cache_unittest.cc
@@ -16,7 +16,7 @@
#include "rtc_base/gunit.h"
#include "rtc_base/openssl.h"
-#include "rtc_base/opensslsessioncache.h"
+#include "rtc_base/openssl_session_cache.h"
namespace rtc {
diff --git a/rtc_base/opensslstreamadapter.cc b/rtc_base/openssl_stream_adapter.cc
similarity index 88%
rename from rtc_base/opensslstreamadapter.cc
rename to rtc_base/openssl_stream_adapter.cc
index 727cb84..5131b30 100644
--- a/rtc_base/opensslstreamadapter.cc
+++ b/rtc_base/openssl_stream_adapter.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/opensslstreamadapter.h"
+#include "rtc_base/openssl_stream_adapter.h"
#include <openssl/bio.h>
#include <openssl/crypto.h>
@@ -25,29 +25,33 @@
#include <utility>
#include <vector>
+#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/openssl.h"
-#include "rtc_base/openssladapter.h"
-#include "rtc_base/openssldigest.h"
-#include "rtc_base/opensslidentity.h"
-#include "rtc_base/sslcertificate.h"
+#include "rtc_base/openssl_adapter.h"
+#include "rtc_base/openssl_digest.h"
+#include "rtc_base/openssl_identity.h"
+#include "rtc_base/ssl_certificate.h"
#include "rtc_base/stream.h"
-#include "rtc_base/stringutils.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
-
-namespace {
-bool g_use_time_callback_for_testing = false;
-}
-
-namespace rtc {
+#include "rtc_base/time_utils.h"
+#include "system_wrappers/include/field_trial.h"
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#error "webrtc requires at least OpenSSL version 1.1.0, to support DTLS-SRTP"
#endif
+// Defines for the TLS Cipher Suite Map.
+#define DEFINE_CIPHER_ENTRY_SSL3(name) \
+ { SSL3_CK_##name, "TLS_" #name }
+#define DEFINE_CIPHER_ENTRY_TLS1(name) \
+ { TLS1_CK_##name, "TLS_" #name }
+
+namespace rtc {
+namespace {
+
// SRTP cipher suite table. |internal_name| is used to construct a
// colon-separated profile strings which is needed by
// SSL_CTX_set_tlsext_use_srtp().
@@ -56,37 +60,23 @@
const int id;
};
-// This isn't elegant, but it's better than an external reference
-static SrtpCipherMapEntry SrtpCipherMap[] = {
- {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80},
- {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32},
- {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM},
- {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM},
- {nullptr, 0}};
-
-#ifdef OPENSSL_IS_BORINGSSL
-// Not used in production code. Actual time should be relative to Jan 1, 1970.
-static void TimeCallbackForTesting(const SSL* ssl, struct timeval* out_clock) {
- int64_t time = TimeNanos();
- out_clock->tv_sec = time / kNumNanosecsPerSec;
- out_clock->tv_usec = (time % kNumNanosecsPerSec) / kNumNanosecsPerMicrosec;
-}
-#else // #ifdef OPENSSL_IS_BORINGSSL
-
// Cipher name table. Maps internal OpenSSL cipher ids to the RFC name.
struct SslCipherMapEntry {
uint32_t openssl_id;
const char* rfc_name;
};
-#define DEFINE_CIPHER_ENTRY_SSL3(name) \
- { SSL3_CK_##name, "TLS_" #name }
-#define DEFINE_CIPHER_ENTRY_TLS1(name) \
- { TLS1_CK_##name, "TLS_" #name }
+// This isn't elegant, but it's better than an external reference
+constexpr SrtpCipherMapEntry kSrtpCipherMap[] = {
+ {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80},
+ {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32},
+ {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM},
+ {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM}};
+#ifndef OPENSSL_IS_BORINGSSL
// The "SSL_CIPHER_standard_name" function is only available in OpenSSL when
// compiled with tracing, so we need to define the mapping manually here.
-static const SslCipherMapEntry kSslCipherMap[] = {
+constexpr SslCipherMapEntry kSslCipherMap[] = {
// TLS v1.0 ciphersuites from RFC2246.
DEFINE_CIPHER_ENTRY_SSL3(RSA_RC4_128_SHA),
{SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
@@ -145,15 +135,19 @@
{0, nullptr}};
#endif // #ifndef OPENSSL_IS_BORINGSSL
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable : 4309)
-#pragma warning(disable : 4310)
-#endif // defined(_MSC_VER)
+#ifdef OPENSSL_IS_BORINGSSL
+// Enabled by EnableTimeCallbackForTesting. Should never be set in production
+// code.
+bool g_use_time_callback_for_testing = false;
+// Not used in production code. Actual time should be relative to Jan 1, 1970.
+void TimeCallbackForTesting(const SSL* ssl, struct timeval* out_clock) {
+ int64_t time = TimeNanos();
+ out_clock->tv_sec = time / kNumNanosecsPerSec;
+ out_clock->tv_usec = (time % kNumNanosecsPerSec) / kNumNanosecsPerMicrosec;
+}
+#endif
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif // defined(_MSC_VER)
+} // namespace
//////////////////////////////////////////////////////////////////////
// StreamBIO
@@ -281,7 +275,9 @@
ssl_(nullptr),
ssl_ctx_(nullptr),
ssl_mode_(SSL_MODE_TLS),
- ssl_max_version_(SSL_PROTOCOL_TLS_12) {}
+ ssl_max_version_(SSL_PROTOCOL_TLS_12),
+ support_legacy_tls_protocols_flag_(
+ webrtc::field_trial::IsEnabled("WebRTC-LegacyTlsProtocols")) {}
OpenSSLStreamAdapter::~OpenSSLStreamAdapter() {
Cleanup(0);
@@ -382,8 +378,9 @@
}
int OpenSSLStreamAdapter::GetSslVersion() const {
- if (state_ != SSL_CONNECTED)
+ if (state_ != SSL_CONNECTED) {
return -1;
+ }
int ssl_version = SSL_version(ssl_);
if (ssl_mode_ == SSL_MODE_DTLS) {
@@ -422,29 +419,26 @@
bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites(
const std::vector<int>& ciphers) {
- std::string internal_ciphers;
-
if (state_ != SSL_NONE) {
return false;
}
- for (std::vector<int>::const_iterator cipher = ciphers.begin();
- cipher != ciphers.end(); ++cipher) {
+ std::string internal_ciphers;
+ for (const int cipher : ciphers) {
bool found = false;
- for (SrtpCipherMapEntry* entry = SrtpCipherMap; entry->internal_name;
- ++entry) {
- if (*cipher == entry->id) {
+ for (const auto& entry : kSrtpCipherMap) {
+ if (cipher == entry.id) {
found = true;
if (!internal_ciphers.empty()) {
internal_ciphers += ":";
}
- internal_ciphers += entry->internal_name;
+ internal_ciphers += entry.internal_name;
break;
}
}
if (!found) {
- RTC_LOG(LS_ERROR) << "Could not find cipher: " << *cipher;
+ RTC_LOG(LS_ERROR) << "Could not find cipher: " << cipher;
return false;
}
}
@@ -624,8 +618,9 @@
ssl_read_needs_write_ = false;
- int code = SSL_read(ssl_, data, checked_cast<int>(data_len));
- int ssl_error = SSL_get_error(ssl_, code);
+ const int code = SSL_read(ssl_, data, checked_cast<int>(data_len));
+ const int ssl_error = SSL_get_error(ssl_, code);
+
switch (ssl_error) {
case SSL_ERROR_NONE:
RTC_LOG(LS_VERBOSE) << " -- success";
@@ -676,10 +671,10 @@
while (left) {
// This should always succeed
- int toread = (sizeof(buf) < left) ? sizeof(buf) : left;
- int code = SSL_read(ssl_, buf, toread);
+ const int toread = (sizeof(buf) < left) ? sizeof(buf) : left;
+ const int code = SSL_read(ssl_, buf, toread);
- int ssl_error = SSL_get_error(ssl_, code);
+ const int ssl_error = SSL_get_error(ssl_, code);
RTC_DCHECK(ssl_error == SSL_ERROR_NONE);
if (ssl_error != SSL_ERROR_NONE) {
@@ -820,20 +815,6 @@
SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-#if !defined(OPENSSL_IS_BORINGSSL)
- // Specify an ECDH group for ECDHE ciphers, otherwise OpenSSL cannot
- // negotiate them when acting as the server. Use NIST's P-256 which is
- // commonly supported. BoringSSL doesn't need explicit configuration and has
- // a reasonable default set.
- EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- if (ecdh == nullptr) {
- return -1;
- }
- SSL_set_options(ssl_, SSL_OP_SINGLE_ECDH_USE);
- SSL_set_tmp_ecdh(ssl_, ecdh);
- EC_KEY_free(ecdh);
-#endif
-
// Do the connect
return ContinueSSL();
}
@@ -845,9 +826,10 @@
// Clear the DTLS timer
Thread::Current()->Clear(this, MSG_TIMEOUT);
- int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_);
- int ssl_error;
- switch (ssl_error = SSL_get_error(ssl_, code)) {
+ const int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_);
+ const int ssl_error = SSL_get_error(ssl_, code);
+
+ switch (ssl_error) {
case SSL_ERROR_NONE:
RTC_LOG(LS_VERBOSE) << " -- success";
// By this point, OpenSSL should have given us a certificate, or errored
@@ -967,74 +949,42 @@
}
SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
- SSL_CTX* ctx = nullptr;
-
-#ifdef OPENSSL_IS_BORINGSSL
- ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
-// Version limiting for BoringSSL will be done below.
-#else
- const SSL_METHOD* method;
- switch (ssl_max_version_) {
- case SSL_PROTOCOL_TLS_10:
- case SSL_PROTOCOL_TLS_11:
- // OpenSSL doesn't support setting min/max versions, so we always use
- // (D)TLS 1.0 if a max. version below the max. available is requested.
- if (ssl_mode_ == SSL_MODE_DTLS) {
- if (role_ == SSL_CLIENT) {
- method = DTLSv1_client_method();
- } else {
- method = DTLSv1_server_method();
- }
- } else {
- if (role_ == SSL_CLIENT) {
- method = TLSv1_client_method();
- } else {
- method = TLSv1_server_method();
- }
- }
- break;
- case SSL_PROTOCOL_TLS_12:
- default:
- if (ssl_mode_ == SSL_MODE_DTLS) {
- if (role_ == SSL_CLIENT) {
- method = DTLS_client_method();
- } else {
- method = DTLS_server_method();
- }
- } else {
- if (role_ == SSL_CLIENT) {
- method = TLS_client_method();
- } else {
- method = TLS_server_method();
- }
- }
- break;
- }
- ctx = SSL_CTX_new(method);
-#endif // OPENSSL_IS_BORINGSSL
-
+ SSL_CTX* ctx =
+ SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
if (ctx == nullptr) {
return nullptr;
}
-#ifdef OPENSSL_IS_BORINGSSL
- SSL_CTX_set_min_proto_version(
- ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
- switch (ssl_max_version_) {
- case SSL_PROTOCOL_TLS_10:
- SSL_CTX_set_max_proto_version(
- ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
- break;
- case SSL_PROTOCOL_TLS_11:
- SSL_CTX_set_max_proto_version(
- ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_1_VERSION);
- break;
- case SSL_PROTOCOL_TLS_12:
- default:
- SSL_CTX_set_max_proto_version(
- ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION);
- break;
+ if (support_legacy_tls_protocols_flag_) {
+ // TODO(https://bugs.webrtc.org/10261): Completely remove this branch in
+ // M75.
+ SSL_CTX_set_min_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
+ switch (ssl_max_version_) {
+ case SSL_PROTOCOL_TLS_10:
+ SSL_CTX_set_max_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
+ break;
+ case SSL_PROTOCOL_TLS_11:
+ SSL_CTX_set_max_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_1_VERSION);
+ break;
+ case SSL_PROTOCOL_TLS_12:
+ default:
+ SSL_CTX_set_max_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION);
+ break;
+ }
+ } else {
+ // TODO(https://bugs.webrtc.org/10261): Make this the default in M75.
+ SSL_CTX_set_min_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION);
+ SSL_CTX_set_max_proto_version(
+ ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION);
}
+
+#ifdef OPENSSL_IS_BORINGSSL
+ // SSL_CTX_set_current_time_cb is only supported in BoringSSL.
if (g_use_time_callback_for_testing) {
SSL_CTX_set_current_time_cb(ctx, &TimeCallbackForTesting);
}
@@ -1137,7 +1087,7 @@
// Record the peer's certificate.
X509* cert = X509_STORE_CTX_get0_cert(store);
stream->peer_cert_chain_.reset(
- new SSLCertChain(new OpenSSLCertificate(cert)));
+ new SSLCertChain(absl::make_unique<OpenSSLCertificate>(cert)));
#endif
// If the peer certificate digest isn't known yet, we'll wait to verify
diff --git a/rtc_base/opensslstreamadapter.h b/rtc_base/openssl_stream_adapter.h
similarity index 94%
rename from rtc_base/opensslstreamadapter.h
rename to rtc_base/openssl_stream_adapter.h
index e012d17..bca2fde 100644
--- a/rtc_base/opensslstreamadapter.h
+++ b/rtc_base/openssl_stream_adapter.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLSTREAMADAPTER_H_
-#define RTC_BASE_OPENSSLSTREAMADAPTER_H_
+#ifndef RTC_BASE_OPENSSL_STREAM_ADAPTER_H_
+#define RTC_BASE_OPENSSL_STREAM_ADAPTER_H_
#include <openssl/ossl_typ.h>
@@ -20,10 +20,10 @@
#include <vector>
#include "rtc_base/buffer.h"
-#include "rtc_base/messagequeue.h"
-#include "rtc_base/opensslidentity.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/openssl_identity.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
namespace rtc {
@@ -217,10 +217,13 @@
// A 50-ms initial timeout ensures rapid setup on fast connections, but may
// be too aggressive for low bandwidth links.
int dtls_handshake_timeout_ms_ = 50;
+
+ // TODO(https://bugs.webrtc.org/10261): Completely remove this option in M75.
+ const bool support_legacy_tls_protocols_flag_;
};
/////////////////////////////////////////////////////////////////////////////
} // namespace rtc
-#endif // RTC_BASE_OPENSSLSTREAMADAPTER_H_
+#endif // RTC_BASE_OPENSSL_STREAM_ADAPTER_H_
diff --git a/rtc_base/opensslutility.cc b/rtc_base/openssl_utility.cc
similarity index 96%
rename from rtc_base/opensslutility.cc
rename to rtc_base/openssl_utility.cc
index a3f3347..9749912 100644
--- a/rtc_base/opensslutility.cc
+++ b/rtc_base/openssl_utility.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/opensslutility.h"
+#include "rtc_base/openssl_utility.h"
#if defined(WEBRTC_WIN)
// Must be included first before openssl headers.
#include "rtc_base/win32.h" // NOLINT
@@ -24,9 +24,9 @@
#include "rtc_base/arraysize.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/opensslcertificate.h"
+#include "rtc_base/openssl_certificate.h"
#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
-#include "rtc_base/sslroots.h"
+#include "rtc_base/ssl_roots.h"
#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS
namespace rtc {
diff --git a/rtc_base/opensslutility.h b/rtc_base/openssl_utility.h
similarity index 92%
rename from rtc_base/opensslutility.h
rename to rtc_base/openssl_utility.h
index 77ed0b1..a2e49df 100644
--- a/rtc_base/opensslutility.h
+++ b/rtc_base/openssl_utility.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_OPENSSLUTILITY_H_
-#define RTC_BASE_OPENSSLUTILITY_H_
+#ifndef RTC_BASE_OPENSSL_UTILITY_H_
+#define RTC_BASE_OPENSSL_UTILITY_H_
#include <openssl/ossl_typ.h>
#include <string>
@@ -37,4 +37,4 @@
} // namespace openssl
} // namespace rtc
-#endif // RTC_BASE_OPENSSLUTILITY_H_
+#endif // RTC_BASE_OPENSSL_UTILITY_H_
diff --git a/rtc_base/opensslutility_unittest.cc b/rtc_base/openssl_utility_unittest.cc
similarity index 99%
rename from rtc_base/opensslutility_unittest.cc
rename to rtc_base/openssl_utility_unittest.cc
index 2f952ae..9c9b971 100644
--- a/rtc_base/opensslutility_unittest.cc
+++ b/rtc_base/openssl_utility_unittest.cc
@@ -32,8 +32,8 @@
#include "rtc_base/gunit.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/openssl.h"
-#include "rtc_base/opensslutility.h"
-#include "rtc_base/sslroots.h"
+#include "rtc_base/openssl_utility.h"
+#include "rtc_base/ssl_roots.h"
#include "test/gmock.h"
namespace rtc {
diff --git a/rtc_base/physicalsocketserver.cc b/rtc_base/physical_socket_server.cc
similarity index 99%
rename from rtc_base/physicalsocketserver.cc
rename to rtc_base/physical_socket_server.cc
index 4ad2857..4845a73 100644
--- a/rtc_base/physicalsocketserver.cc
+++ b/rtc_base/physical_socket_server.cc
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/physicalsocketserver.h"
+#include "rtc_base/physical_socket_server.h"
#if defined(_MSC_VER) && _MSC_VER < 1300
#pragma warning(disable : 4786)
@@ -44,12 +44,12 @@
#include <map>
#include "rtc_base/arraysize.h"
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/networkmonitor.h"
-#include "rtc_base/nullsocketserver.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/network_monitor.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/time_utils.h"
#if defined(WEBRTC_WIN)
#define LAST_SYSTEM_ERROR (::GetLastError())
diff --git a/rtc_base/physicalsocketserver.h b/rtc_base/physical_socket_server.h
similarity index 96%
rename from rtc_base/physicalsocketserver.h
rename to rtc_base/physical_socket_server.h
index ee4f936..b2dfb3f 100644
--- a/rtc_base/physicalsocketserver.h
+++ b/rtc_base/physical_socket_server.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_PHYSICALSOCKETSERVER_H_
-#define RTC_BASE_PHYSICALSOCKETSERVER_H_
+#ifndef RTC_BASE_PHYSICAL_SOCKET_SERVER_H_
+#define RTC_BASE_PHYSICAL_SOCKET_SERVER_H_
#if defined(WEBRTC_POSIX) && defined(WEBRTC_LINUX)
#include <sys/epoll.h>
@@ -20,9 +20,9 @@
#include <set>
#include <vector>
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/nethelpers.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/socket_server.h"
#if defined(WEBRTC_POSIX)
typedef int SOCKET;
@@ -268,4 +268,4 @@
} // namespace rtc
-#endif // RTC_BASE_PHYSICALSOCKETSERVER_H_
+#endif // RTC_BASE_PHYSICAL_SOCKET_SERVER_H_
diff --git a/rtc_base/physicalsocketserver_unittest.cc b/rtc_base/physical_socket_server_unittest.cc
similarity index 98%
rename from rtc_base/physicalsocketserver_unittest.cc
rename to rtc_base/physical_socket_server_unittest.cc
index 4b36cd5..aed8bf3 100644
--- a/rtc_base/physicalsocketserver_unittest.cc
+++ b/rtc_base/physical_socket_server_unittest.cc
@@ -9,16 +9,18 @@
*/
#include <signal.h>
-#include <stdarg.h>
+#include <algorithm>
#include <memory>
#include "rtc_base/gunit.h"
+#include "rtc_base/ip_address.h"
#include "rtc_base/logging.h"
-#include "rtc_base/networkmonitor.h"
-#include "rtc_base/physicalsocketserver.h"
+#include "rtc_base/network_monitor.h"
+#include "rtc_base/physical_socket_server.h"
#include "rtc_base/socket_unittest.h"
-#include "rtc_base/testutils.h"
+#include "rtc_base/test_utils.h"
#include "rtc_base/thread.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/platform_file.cc b/rtc_base/platform_file.cc
index baefb22..f9317d3 100644
--- a/rtc_base/platform_file.cc
+++ b/rtc_base/platform_file.cc
@@ -13,7 +13,7 @@
#if defined(WEBRTC_WIN)
#include <io.h>
-#include "rtc_base/stringutils.h" // For ToUtf16
+#include "rtc_base/string_utils.h" // For ToUtf16
#else
#include <fcntl.h>
#include <sys/stat.h>
diff --git a/rtc_base/platform_file_unittest.cc b/rtc_base/platform_file_unittest.cc
index 4e72400..396286a 100644
--- a/rtc_base/platform_file_unittest.cc
+++ b/rtc_base/platform_file_unittest.cc
@@ -10,7 +10,7 @@
#include "rtc_base/platform_file.h"
#include "test/gtest.h"
-#include "test/testsupport/fileutils.h"
+#include "test/testsupport/file_utils.h"
namespace rtc {
diff --git a/rtc_base/platform_thread.cc b/rtc_base/platform_thread.cc
index ba84b6a..19da912 100644
--- a/rtc_base/platform_thread.cc
+++ b/rtc_base/platform_thread.cc
@@ -17,9 +17,9 @@
#include <time.h>
#include <algorithm>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
namespace {
@@ -39,10 +39,8 @@
PlatformThread::PlatformThread(ThreadRunFunctionDeprecated func,
void* obj,
- const char* thread_name)
- : run_function_deprecated_(func),
- obj_(obj),
- name_(thread_name ? thread_name : "webrtc") {
+ absl::string_view thread_name)
+ : run_function_deprecated_(func), obj_(obj), name_(thread_name) {
RTC_DCHECK(func);
RTC_DCHECK(name_.length() < 64);
spawned_thread_checker_.DetachFromThread();
@@ -50,7 +48,7 @@
PlatformThread::PlatformThread(ThreadRunFunction func,
void* obj,
- const char* thread_name,
+ absl::string_view thread_name,
ThreadPriority priority /*= kNormalPriority*/)
: run_function_(func), priority_(priority), obj_(obj), name_(thread_name) {
RTC_DCHECK(func);
@@ -240,11 +238,7 @@
// thread priorities.
return true;
#else
-#ifdef WEBRTC_THREAD_RR
- const int policy = SCHED_RR;
-#else
const int policy = SCHED_FIFO;
-#endif
const int min_prio = sched_get_priority_min(policy);
const int max_prio = sched_get_priority_max(policy);
if (min_prio == -1 || max_prio == -1) {
diff --git a/rtc_base/platform_thread.h b/rtc_base/platform_thread.h
index 47c23dc..99c5f90 100644
--- a/rtc_base/platform_thread.h
+++ b/rtc_base/platform_thread.h
@@ -16,7 +16,8 @@
#endif
#include <string>
-#include "rtc_base/constructormagic.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/thread_checker.h"
@@ -51,10 +52,10 @@
public:
PlatformThread(ThreadRunFunctionDeprecated func,
void* obj,
- const char* thread_name);
+ absl::string_view thread_name);
PlatformThread(ThreadRunFunction func,
void* obj,
- const char* thread_name,
+ absl::string_view thread_name,
ThreadPriority priority = kNormalPriority);
virtual ~PlatformThread();
diff --git a/rtc_base/platform_thread_types.h b/rtc_base/platform_thread_types.h
index 0bc42eb..6b9101e 100644
--- a/rtc_base/platform_thread_types.h
+++ b/rtc_base/platform_thread_types.h
@@ -25,6 +25,9 @@
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#include <unistd.h>
+#if defined(WEBRTC_MAC)
+#include <pthread_spis.h>
+#endif
#endif
// clang-format on
diff --git a/rtc_base/protobuf_utils.h b/rtc_base/protobuf_utils.h
index 8fbc060..786365d 100644
--- a/rtc_base/protobuf_utils.h
+++ b/rtc_base/protobuf_utils.h
@@ -13,12 +13,6 @@
#ifndef RTC_BASE_PROTOBUF_UTILS_H_
#define RTC_BASE_PROTOBUF_UTILS_H_
-namespace webrtc {
-
-using ProtoString = std::string;
-
-} // namespace webrtc
-
#if WEBRTC_ENABLE_PROTOBUF
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
diff --git a/rtc_base/proxyinfo.cc b/rtc_base/proxy_info.cc
similarity index 95%
rename from rtc_base/proxyinfo.cc
rename to rtc_base/proxy_info.cc
index c394487..23d60af 100644
--- a/rtc_base/proxyinfo.cc
+++ b/rtc_base/proxy_info.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/proxyinfo.h"
+#include "rtc_base/proxy_info.h"
namespace rtc {
diff --git a/rtc_base/proxyinfo.h b/rtc_base/proxy_info.h
similarity index 82%
rename from rtc_base/proxyinfo.h
rename to rtc_base/proxy_info.h
index 1947669..6fded09 100644
--- a/rtc_base/proxyinfo.h
+++ b/rtc_base/proxy_info.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_PROXYINFO_H_
-#define RTC_BASE_PROXYINFO_H_
+#ifndef RTC_BASE_PROXY_INFO_H_
+#define RTC_BASE_PROXY_INFO_H_
#include <string>
-#include "rtc_base/cryptstring.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/crypt_string.h"
+#include "rtc_base/socket_address.h"
namespace rtc {
@@ -35,4 +35,4 @@
} // namespace rtc
-#endif // RTC_BASE_PROXYINFO_H_
+#endif // RTC_BASE_PROXY_INFO_H_
diff --git a/rtc_base/proxyserver.cc b/rtc_base/proxy_server.cc
similarity index 98%
rename from rtc_base/proxyserver.cc
rename to rtc_base/proxy_server.cc
index 71c4879..3420404 100644
--- a/rtc_base/proxyserver.cc
+++ b/rtc_base/proxy_server.cc
@@ -8,13 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/proxyserver.h"
+#include "rtc_base/proxy_server.h"
+#include <stddef.h>
#include <algorithm>
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/socketfactory.h"
+#include "rtc_base/socket_factory.h"
namespace rtc {
diff --git a/rtc_base/proxyserver.h b/rtc_base/proxy_server.h
similarity index 92%
rename from rtc_base/proxyserver.h
rename to rtc_base/proxy_server.h
index 37cadd0..ef4a3c7 100644
--- a/rtc_base/proxyserver.h
+++ b/rtc_base/proxy_server.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_PROXYSERVER_H_
-#define RTC_BASE_PROXYSERVER_H_
+#ifndef RTC_BASE_PROXY_SERVER_H_
+#define RTC_BASE_PROXY_SERVER_H_
#include <list>
#include <memory>
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/socketadapters.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/server_socket_adapters.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/stream.h"
namespace rtc {
@@ -101,4 +101,4 @@
} // namespace rtc
-#endif // RTC_BASE_PROXYSERVER_H_
+#endif // RTC_BASE_PROXY_SERVER_H_
diff --git a/rtc_base/proxy_unittest.cc b/rtc_base/proxy_unittest.cc
index 0101893..229891d 100644
--- a/rtc_base/proxy_unittest.cc
+++ b/rtc_base/proxy_unittest.cc
@@ -11,11 +11,11 @@
#include <memory>
#include <string>
#include "rtc_base/gunit.h"
-#include "rtc_base/proxyserver.h"
-#include "rtc_base/socketadapters.h"
-#include "rtc_base/testclient.h"
-#include "rtc_base/testechoserver.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/proxy_server.h"
+#include "rtc_base/socket_adapters.h"
+#include "rtc_base/test_client.h"
+#include "rtc_base/test_echo_server.h"
+#include "rtc_base/virtual_socket_server.h"
using rtc::Socket;
using rtc::SocketAddress;
diff --git a/rtc_base/random.h b/rtc_base/random.h
index e1c3bb7..31de6e1 100644
--- a/rtc_base/random.h
+++ b/rtc_base/random.h
@@ -15,7 +15,7 @@
#include <limits>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
diff --git a/rtc_base/random_unittest.cc b/rtc_base/random_unittest.cc
index d05a16b..8f32657 100644
--- a/rtc_base/random_unittest.cc
+++ b/rtc_base/random_unittest.cc
@@ -13,7 +13,7 @@
#include <limits>
#include <vector>
-#include "rtc_base/numerics/mathutils.h" // unsigned difference
+#include "rtc_base/numerics/math_utils.h" // unsigned difference
#include "rtc_base/random.h"
#include "test/gtest.h"
diff --git a/rtc_base/rate_limiter.cc b/rtc_base/rate_limiter.cc
index 5c7bdef..7394c3e 100644
--- a/rtc_base/rate_limiter.cc
+++ b/rtc_base/rate_limiter.cc
@@ -17,7 +17,7 @@
namespace webrtc {
-RateLimiter::RateLimiter(const Clock* clock, int64_t max_window_ms)
+RateLimiter::RateLimiter(Clock* clock, int64_t max_window_ms)
: clock_(clock),
current_rate_(max_window_ms, RateStatistics::kBpsScale),
window_size_ms_(max_window_ms),
diff --git a/rtc_base/rate_limiter.h b/rtc_base/rate_limiter.h
index 43ef88d..1c956d7 100644
--- a/rtc_base/rate_limiter.h
+++ b/rtc_base/rate_limiter.h
@@ -14,8 +14,8 @@
#include <stddef.h>
#include <stdint.h>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/rate_statistics.h"
#include "rtc_base/thread_annotations.h"
@@ -28,7 +28,7 @@
// methods will acquire (the same) lock befeore executing.
class RateLimiter {
public:
- RateLimiter(const Clock* clock, int64_t max_window_ms);
+ RateLimiter(Clock* clock, int64_t max_window_ms);
~RateLimiter();
// Try to use rate to send bytes. Returns true on success and if so updates
@@ -44,7 +44,7 @@
bool SetWindowSize(int64_t window_size_ms);
private:
- const Clock* const clock_;
+ Clock* const clock_;
rtc::CriticalSection lock_;
RateStatistics current_rate_ RTC_GUARDED_BY(lock_);
int64_t window_size_ms_ RTC_GUARDED_BY(lock_);
diff --git a/rtc_base/rate_limiter_unittest.cc b/rtc_base/rate_limiter_unittest.cc
index ac0625f..cb9b5b4 100644
--- a/rtc_base/rate_limiter_unittest.cc
+++ b/rtc_base/rate_limiter_unittest.cc
@@ -8,13 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <algorithm>
#include <memory>
#include "rtc_base/event.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/rate_limiter.h"
-#include "rtc_base/task_queue.h"
#include "system_wrappers/include/clock.h"
#include "test/gtest.h"
diff --git a/rtc_base/rate_statistics_unittest.cc b/rtc_base/rate_statistics_unittest.cc
index 62f1486..822767e 100644
--- a/rtc_base/rate_statistics_unittest.cc
+++ b/rtc_base/rate_statistics_unittest.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <algorithm>
+#include <cstdlib>
#include "rtc_base/rate_statistics.h"
#include "test/gtest.h"
diff --git a/rtc_base/ratetracker.cc b/rtc_base/rate_tracker.cc
similarity index 98%
rename from rtc_base/ratetracker.cc
rename to rtc_base/rate_tracker.cc
index 7c96ca9..771dc6c 100644
--- a/rtc_base/ratetracker.cc
+++ b/rtc_base/rate_tracker.cc
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/ratetracker.h"
+#include "rtc_base/rate_tracker.h"
#include <algorithm>
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/ratetracker.h b/rtc_base/rate_tracker.h
similarity index 95%
rename from rtc_base/ratetracker.h
rename to rtc_base/rate_tracker.h
index ac9b88a..e9be522 100644
--- a/rtc_base/ratetracker.h
+++ b/rtc_base/rate_tracker.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_RATETRACKER_H_
-#define RTC_BASE_RATETRACKER_H_
+#ifndef RTC_BASE_RATE_TRACKER_H_
+#define RTC_BASE_RATE_TRACKER_H_
#include <stdint.h>
#include <stdlib.h>
@@ -66,4 +66,4 @@
} // namespace rtc
-#endif // RTC_BASE_RATETRACKER_H_
+#endif // RTC_BASE_RATE_TRACKER_H_
diff --git a/rtc_base/ratetracker_unittest.cc b/rtc_base/rate_tracker_unittest.cc
similarity index 98%
rename from rtc_base/ratetracker_unittest.cc
rename to rtc_base/rate_tracker_unittest.cc
index 58102df..7a2c1ad 100644
--- a/rtc_base/ratetracker_unittest.cc
+++ b/rtc_base/rate_tracker_unittest.cc
@@ -8,8 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/ratetracker.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/rate_tracker.h"
+
+#include "test/gtest.h"
namespace rtc {
namespace {
diff --git a/rtc_base/refcount.h b/rtc_base/ref_count.h
similarity index 96%
rename from rtc_base/refcount.h
rename to rtc_base/ref_count.h
index fb0971c..d8d652a 100644
--- a/rtc_base/refcount.h
+++ b/rtc_base/ref_count.h
@@ -7,8 +7,8 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_REFCOUNT_H_
-#define RTC_BASE_REFCOUNT_H_
+#ifndef RTC_BASE_REF_COUNT_H_
+#define RTC_BASE_REF_COUNT_H_
namespace rtc {
@@ -64,4 +64,4 @@
} // namespace rtc
-#endif // RTC_BASE_REFCOUNT_H_
+#endif // RTC_BASE_REF_COUNT_H_
diff --git a/rtc_base/refcountedobject.h b/rtc_base/ref_counted_object.h
similarity index 87%
rename from rtc_base/refcountedobject.h
rename to rtc_base/ref_counted_object.h
index da3ed9f..ce18379 100644
--- a/rtc_base/refcountedobject.h
+++ b/rtc_base/ref_counted_object.h
@@ -7,14 +7,15 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_REFCOUNTEDOBJECT_H_
-#define RTC_BASE_REFCOUNTEDOBJECT_H_
+#ifndef RTC_BASE_REF_COUNTED_OBJECT_H_
+#define RTC_BASE_REF_COUNTED_OBJECT_H_
+#include <type_traits>
#include <utility>
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcounter.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counter.h"
namespace rtc {
@@ -60,4 +61,4 @@
} // namespace rtc
-#endif // RTC_BASE_REFCOUNTEDOBJECT_H_
+#endif // RTC_BASE_REF_COUNTED_OBJECT_H_
diff --git a/rtc_base/refcountedobject_unittest.cc b/rtc_base/ref_counted_object_unittest.cc
similarity index 92%
rename from rtc_base/refcountedobject_unittest.cc
rename to rtc_base/ref_counted_object_unittest.cc
index 4744525..00a9295 100644
--- a/rtc_base/refcountedobject_unittest.cc
+++ b/rtc_base/ref_counted_object_unittest.cc
@@ -8,11 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <memory>
#include <string>
+#include <utility>
-#include "rtc_base/gunit.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/refcounter.h b/rtc_base/ref_counter.h
similarity index 73%
rename from rtc_base/refcounter.h
rename to rtc_base/ref_counter.h
index 3906529..600dda8 100644
--- a/rtc_base/refcounter.h
+++ b/rtc_base/ref_counter.h
@@ -7,11 +7,11 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_REFCOUNTER_H_
-#define RTC_BASE_REFCOUNTER_H_
+#ifndef RTC_BASE_REF_COUNTER_H_
+#define RTC_BASE_REF_COUNTER_H_
-#include "rtc_base/atomicops.h"
-#include "rtc_base/refcount.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/ref_count.h"
namespace webrtc {
namespace webrtc_impl {
@@ -23,9 +23,11 @@
void IncRef() { rtc::AtomicOps::Increment(&ref_count_); }
- // TODO(nisse): Switch return type to RefCountReleaseStatus?
- // Returns true if this was the last reference, and the resource protected by
- // the reference counter can be deleted.
+ // Returns kDroppedLastRef if this call dropped the last reference; the caller
+ // should therefore free the resource protected by the reference counter.
+ // Otherwise, returns kOtherRefsRemained (note that in case of multithreading,
+ // some other caller may have dropped the last reference by the time this call
+ // returns; all we know is that we didn't do it).
rtc::RefCountReleaseStatus DecRef() {
return (rtc::AtomicOps::Decrement(&ref_count_) == 0)
? rtc::RefCountReleaseStatus::kDroppedLastRef
@@ -49,4 +51,4 @@
} // namespace webrtc_impl
} // namespace webrtc
-#endif // RTC_BASE_REFCOUNTER_H_
+#endif // RTC_BASE_REF_COUNTER_H_
diff --git a/rtc_base/rollingaccumulator.h b/rtc_base/rolling_accumulator.h
similarity index 95%
rename from rtc_base/rollingaccumulator.h
rename to rtc_base/rolling_accumulator.h
index f6215c5..dacceff 100644
--- a/rtc_base/rollingaccumulator.h
+++ b/rtc_base/rolling_accumulator.h
@@ -8,14 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_ROLLINGACCUMULATOR_H_
-#define RTC_BASE_ROLLINGACCUMULATOR_H_
+#ifndef RTC_BASE_ROLLING_ACCUMULATOR_H_
+#define RTC_BASE_ROLLING_ACCUMULATOR_H_
+#include <stddef.h>
#include <algorithm>
#include <vector>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -163,4 +164,4 @@
} // namespace rtc
-#endif // RTC_BASE_ROLLINGACCUMULATOR_H_
+#endif // RTC_BASE_ROLLING_ACCUMULATOR_H_
diff --git a/rtc_base/rollingaccumulator_unittest.cc b/rtc_base/rolling_accumulator_unittest.cc
similarity index 97%
rename from rtc_base/rollingaccumulator_unittest.cc
rename to rtc_base/rolling_accumulator_unittest.cc
index 91ed853..7d5e70d 100644
--- a/rtc_base/rollingaccumulator_unittest.cc
+++ b/rtc_base/rolling_accumulator_unittest.cc
@@ -8,8 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/rollingaccumulator.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/rolling_accumulator.h"
+
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/rtccertificate.cc b/rtc_base/rtc_certificate.cc
similarity index 92%
rename from rtc_base/rtccertificate.cc
rename to rtc_base/rtc_certificate.cc
index 875068f..46f6c31 100644
--- a/rtc_base/rtccertificate.cc
+++ b/rtc_base/rtc_certificate.cc
@@ -10,13 +10,13 @@
#include <memory>
-#include "rtc_base/rtccertificate.h"
+#include "rtc_base/rtc_certificate.h"
#include "rtc_base/checks.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/rtccertificate.h b/rtc_base/rtc_certificate.h
similarity index 94%
rename from rtc_base/rtccertificate.h
rename to rtc_base/rtc_certificate.h
index 561ea0f..d98c4ea 100644
--- a/rtc_base/rtccertificate.h
+++ b/rtc_base/rtc_certificate.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_RTCCERTIFICATE_H_
-#define RTC_BASE_RTCCERTIFICATE_H_
+#ifndef RTC_BASE_RTC_CERTIFICATE_H_
+#define RTC_BASE_RTC_CERTIFICATE_H_
#include <stdint.h>
#include <memory>
#include <string>
-#include "rtc_base/refcount.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
namespace rtc {
@@ -90,4 +90,4 @@
} // namespace rtc
-#endif // RTC_BASE_RTCCERTIFICATE_H_
+#endif // RTC_BASE_RTC_CERTIFICATE_H_
diff --git a/rtc_base/rtccertificategenerator.cc b/rtc_base/rtc_certificate_generator.cc
similarity index 96%
rename from rtc_base/rtccertificategenerator.cc
rename to rtc_base/rtc_certificate_generator.cc
index 114b35c..08cd199 100644
--- a/rtc_base/rtccertificategenerator.cc
+++ b/rtc_base/rtc_certificate_generator.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/rtccertificategenerator.h"
+#include "rtc_base/rtc_certificate_generator.h"
#include <time.h>
#include <algorithm>
@@ -17,10 +17,10 @@
#include "rtc_base/checks.h"
#include "rtc_base/location.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/ssl_identity.h"
namespace rtc {
diff --git a/rtc_base/rtccertificategenerator.h b/rtc_base/rtc_certificate_generator.h
similarity index 91%
rename from rtc_base/rtccertificategenerator.h
rename to rtc_base/rtc_certificate_generator.h
index fed075e..8cabca4 100644
--- a/rtc_base/rtccertificategenerator.h
+++ b/rtc_base/rtc_certificate_generator.h
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_RTCCERTIFICATEGENERATOR_H_
-#define RTC_BASE_RTCCERTIFICATEGENERATOR_H_
+#ifndef RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_
+#define RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_
#include <stdint.h>
#include "absl/types/optional.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/rtccertificate.h"
-#include "rtc_base/scoped_ref_ptr.h"
-#include "rtc_base/sslidentity.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/rtc_certificate.h"
+#include "rtc_base/ssl_identity.h"
#include "rtc_base/thread.h"
namespace rtc {
@@ -84,4 +84,4 @@
} // namespace rtc
-#endif // RTC_BASE_RTCCERTIFICATEGENERATOR_H_
+#endif // RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_
diff --git a/rtc_base/rtccertificategenerator_unittest.cc b/rtc_base/rtc_certificate_generator_unittest.cc
similarity index 97%
rename from rtc_base/rtccertificategenerator_unittest.cc
rename to rtc_base/rtc_certificate_generator_unittest.cc
index 3929128..69c8597 100644
--- a/rtc_base/rtccertificategenerator_unittest.cc
+++ b/rtc_base/rtc_certificate_generator_unittest.cc
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/rtccertificategenerator.h"
+#include "rtc_base/rtc_certificate_generator.h"
#include <memory>
#include "absl/types/optional.h"
#include "rtc_base/checks.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/refcountedobject.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/thread.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/rtccertificate_unittest.cc b/rtc_base/rtc_certificate_unittest.cc
similarity index 95%
rename from rtc_base/rtccertificate_unittest.cc
rename to rtc_base/rtc_certificate_unittest.cc
index bb88d8a..ab242bb 100644
--- a/rtc_base/rtccertificate_unittest.cc
+++ b/rtc_base/rtc_certificate_unittest.cc
@@ -8,18 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <time.h>
#include <memory>
#include <utility>
#include "rtc_base/checks.h"
-#include "rtc_base/fakesslidentity.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/rtccertificate.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/rtc_certificate.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/time_utils.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/sanitizer_unittest.cc b/rtc_base/sanitizer_unittest.cc
index 8dc6068..ffbfed7 100644
--- a/rtc_base/sanitizer_unittest.cc
+++ b/rtc_base/sanitizer_unittest.cc
@@ -10,8 +10,10 @@
#include "rtc_base/sanitizer.h"
-#include "rtc_base/gunit.h"
+#include <stdint.h>
+
#include "rtc_base/logging.h"
+#include "test/gtest.h"
#if RTC_HAS_MSAN
#include <sanitizer/msan_interface.h>
diff --git a/rtc_base/scoped_ref_ptr.h b/rtc_base/scoped_ref_ptr.h
deleted file mode 100644
index b961ff5..0000000
--- a/rtc_base/scoped_ref_ptr.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 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.
- */
-
-#ifndef RTC_BASE_SCOPED_REF_PTR_H_
-#define RTC_BASE_SCOPED_REF_PTR_H_
-
-// TODO(bugs.webrtc.org/9887): This is a forward header for backwards
-// compatibility. Remove when downstream clients are updated.
-
-#include "api/scoped_refptr.h"
-
-#endif // RTC_BASE_SCOPED_REF_PTR_H_
diff --git a/rtc_base/sequenced_task_checker.h b/rtc_base/sequenced_task_checker.h
index eb15198..e5443af 100644
--- a/rtc_base/sequenced_task_checker.h
+++ b/rtc_base/sequenced_task_checker.h
@@ -17,7 +17,7 @@
#define ENABLE_SEQUENCED_TASK_CHECKER RTC_DCHECK_IS_ON
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/sequenced_task_checker_impl.h"
#include "rtc_base/thread_annotations.h"
diff --git a/rtc_base/sequenced_task_checker_impl.cc b/rtc_base/sequenced_task_checker_impl.cc
index 717cb95..678f91d 100644
--- a/rtc_base/sequenced_task_checker_impl.cc
+++ b/rtc_base/sequenced_task_checker_impl.cc
@@ -14,19 +14,19 @@
#include <dispatch/dispatch.h>
#endif
+#include "api/task_queue/task_queue_base.h"
#include "rtc_base/checks.h"
#include "rtc_base/sequenced_task_checker.h"
-#include "rtc_base/task_queue.h"
namespace rtc {
SequencedTaskCheckerImpl::SequencedTaskCheckerImpl()
- : attached_(true), valid_queue_(TaskQueue::Current()) {}
+ : attached_(true), valid_queue_(webrtc::TaskQueueBase::Current()) {}
SequencedTaskCheckerImpl::~SequencedTaskCheckerImpl() {}
bool SequencedTaskCheckerImpl::CalledSequentially() const {
- QueueId current_queue = TaskQueue::Current();
+ QueueId current_queue = webrtc::TaskQueueBase::Current();
#if defined(WEBRTC_MAC)
// If we're not running on a TaskQueue, use the system dispatch queue
// label as an identifier.
diff --git a/rtc_base/sequenced_task_checker_impl.h b/rtc_base/sequenced_task_checker_impl.h
index 293b1ac..bd53961 100644
--- a/rtc_base/sequenced_task_checker_impl.h
+++ b/rtc_base/sequenced_task_checker_impl.h
@@ -11,12 +11,11 @@
#ifndef RTC_BASE_SEQUENCED_TASK_CHECKER_IMPL_H_
#define RTC_BASE_SEQUENCED_TASK_CHECKER_IMPL_H_
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_checker.h"
namespace rtc {
-class TaskQueue;
// Real implementation of SequencedTaskChecker, for use in debug mode, or
// for temporary use in release mode.
//
diff --git a/rtc_base/sequenced_task_checker_unittest.cc b/rtc_base/sequenced_task_checker_unittest.cc
index 7b7247c..b3df2fa 100644
--- a/rtc_base/sequenced_task_checker_unittest.cc
+++ b/rtc_base/sequenced_task_checker_unittest.cc
@@ -10,8 +10,11 @@
#include "rtc_base/sequenced_task_checker.h"
+#include <memory>
+#include <utility>
+
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/event.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/task_queue.h"
diff --git a/rtc_base/server_socket_adapters.cc b/rtc_base/server_socket_adapters.cc
new file mode 100644
index 0000000..887ca87
--- /dev/null
+++ b/rtc_base/server_socket_adapters.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2004 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 <string>
+
+#include "rtc_base/byte_buffer.h"
+#include "rtc_base/server_socket_adapters.h"
+
+namespace rtc {
+
+AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
+ size_t buffer_size)
+ : BufferedReadAdapter(socket, buffer_size) {}
+
+AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
+
+AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
+ : BufferedReadAdapter(socket, 1024) {
+ BufferInput(true);
+}
+
+void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
+ // We only accept client hello messages.
+ const ArrayView<const uint8_t> client_hello =
+ AsyncSSLSocket::SslClientHello();
+ if (*len < client_hello.size()) {
+ return;
+ }
+
+ if (memcmp(client_hello.data(), data, client_hello.size()) != 0) {
+ Close();
+ SignalCloseEvent(this, 0);
+ return;
+ }
+
+ *len -= client_hello.size();
+
+ // Clients should not send more data until the handshake is completed.
+ RTC_DCHECK(*len == 0);
+
+ const ArrayView<const uint8_t> server_hello =
+ AsyncSSLSocket::SslServerHello();
+ // Send a server hello back to the client.
+ DirectSend(server_hello.data(), server_hello.size());
+
+ // Handshake completed for us, redirect input to our parent.
+ BufferInput(false);
+}
+
+AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
+ : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
+ BufferInput(true);
+}
+
+void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
+ RTC_DCHECK(state_ < SS_CONNECT_PENDING);
+
+ ByteBufferReader response(data, *len);
+ if (state_ == SS_HELLO) {
+ HandleHello(&response);
+ } else if (state_ == SS_AUTH) {
+ HandleAuth(&response);
+ } else if (state_ == SS_CONNECT) {
+ HandleConnect(&response);
+ }
+
+ // Consume parsed data
+ *len = response.Length();
+ memmove(data, response.Data(), *len);
+}
+
+void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
+ BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
+}
+
+void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
+ uint8_t ver, num_methods;
+ if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
+ Error(0);
+ return;
+ }
+
+ if (ver != 5) {
+ Error(0);
+ return;
+ }
+
+ // Handle either no-auth (0) or user/pass auth (2)
+ uint8_t method = 0xFF;
+ if (num_methods > 0 && !request->ReadUInt8(&method)) {
+ Error(0);
+ return;
+ }
+
+ SendHelloReply(method);
+ if (method == 0) {
+ state_ = SS_CONNECT;
+ } else if (method == 2) {
+ state_ = SS_AUTH;
+ } else {
+ state_ = SS_ERROR;
+ }
+}
+
+void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
+ ByteBufferWriter response;
+ response.WriteUInt8(5); // Socks Version
+ response.WriteUInt8(method); // Auth method
+ DirectSend(response);
+}
+
+void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
+ uint8_t ver, user_len, pass_len;
+ std::string user, pass;
+ if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
+ !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
+ !request->ReadString(&pass, pass_len)) {
+ Error(0);
+ return;
+ }
+
+ SendAuthReply(0);
+ state_ = SS_CONNECT;
+}
+
+void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
+ ByteBufferWriter response;
+ response.WriteUInt8(1); // Negotiation Version
+ response.WriteUInt8(result);
+ DirectSend(response);
+}
+
+void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
+ uint8_t ver, command, reserved, addr_type;
+ uint32_t ip;
+ uint16_t port;
+ if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
+ !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
+ !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
+ Error(0);
+ return;
+ }
+
+ if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
+ Error(0);
+ return;
+ }
+
+ SignalConnectRequest(this, SocketAddress(ip, port));
+ state_ = SS_CONNECT_PENDING;
+}
+
+void AsyncSocksProxyServerSocket::SendConnectResult(int result,
+ const SocketAddress& addr) {
+ if (state_ != SS_CONNECT_PENDING)
+ return;
+
+ ByteBufferWriter response;
+ response.WriteUInt8(5); // Socks version
+ response.WriteUInt8((result != 0)); // 0x01 is generic error
+ response.WriteUInt8(0); // reserved
+ response.WriteUInt8(1); // IPv4 address
+ response.WriteUInt32(addr.ip());
+ response.WriteUInt16(addr.port());
+ DirectSend(response);
+ BufferInput(false);
+ state_ = SS_TUNNEL;
+}
+
+void AsyncSocksProxyServerSocket::Error(int error) {
+ state_ = SS_ERROR;
+ BufferInput(false);
+ Close();
+ SetError(SOCKET_EACCES);
+ SignalCloseEvent(this, error);
+}
+
+} // namespace rtc
diff --git a/rtc_base/server_socket_adapters.h b/rtc_base/server_socket_adapters.h
new file mode 100644
index 0000000..a534eea
--- /dev/null
+++ b/rtc_base/server_socket_adapters.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2004 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.
+ */
+
+#ifndef RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
+#define RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
+
+#include "rtc_base/socket_adapters.h"
+
+namespace rtc {
+
+// Interface for implementing proxy server sockets.
+class AsyncProxyServerSocket : public BufferedReadAdapter {
+ public:
+ AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size);
+ ~AsyncProxyServerSocket() override;
+ sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&>
+ SignalConnectRequest;
+ virtual void SendConnectResult(int err, const SocketAddress& addr) = 0;
+};
+
+// Implements a socket adapter that performs the server side of a
+// fake SSL handshake. Used when implementing a relay server that does "ssltcp".
+class AsyncSSLServerSocket : public BufferedReadAdapter {
+ public:
+ explicit AsyncSSLServerSocket(AsyncSocket* socket);
+
+ protected:
+ void ProcessInput(char* data, size_t* len) override;
+ RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLServerSocket);
+};
+
+// Implements a proxy server socket for the SOCKS protocol.
+class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket {
+ public:
+ explicit AsyncSocksProxyServerSocket(AsyncSocket* socket);
+
+ private:
+ void ProcessInput(char* data, size_t* len) override;
+ void DirectSend(const ByteBufferWriter& buf);
+
+ void HandleHello(ByteBufferReader* request);
+ void SendHelloReply(uint8_t method);
+ void HandleAuth(ByteBufferReader* request);
+ void SendAuthReply(uint8_t result);
+ void HandleConnect(ByteBufferReader* request);
+ void SendConnectResult(int result, const SocketAddress& addr) override;
+
+ void Error(int error);
+
+ static const int kBufferSize = 1024;
+ enum State {
+ SS_HELLO,
+ SS_AUTH,
+ SS_CONNECT,
+ SS_CONNECT_PENDING,
+ SS_TUNNEL,
+ SS_ERROR
+ };
+ State state_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxyServerSocket);
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
diff --git a/rtc_base/signalthread.cc b/rtc_base/signal_thread.cc
similarity index 97%
rename from rtc_base/signalthread.cc
rename to rtc_base/signal_thread.cc
index 5dd9387..84613db 100644
--- a/rtc_base/signalthread.cc
+++ b/rtc_base/signal_thread.cc
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/signalthread.h"
+#include "rtc_base/signal_thread.h"
#include <memory>
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
#include "rtc_base/location.h"
-#include "rtc_base/nullsocketserver.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/socket_server.h"
namespace rtc {
diff --git a/rtc_base/signalthread.h b/rtc_base/signal_thread.h
similarity index 95%
rename from rtc_base/signalthread.h
rename to rtc_base/signal_thread.h
index 9208e2c..9a20ad2 100644
--- a/rtc_base/signalthread.h
+++ b/rtc_base/signal_thread.h
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SIGNALTHREAD_H_
-#define RTC_BASE_SIGNALTHREAD_H_
+#ifndef RTC_BASE_SIGNAL_THREAD_H_
+#define RTC_BASE_SIGNAL_THREAD_H_
#include <string>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
#include "rtc_base/thread_annotations.h"
@@ -155,4 +155,4 @@
} // namespace rtc
-#endif // RTC_BASE_SIGNALTHREAD_H_
+#endif // RTC_BASE_SIGNAL_THREAD_H_
diff --git a/rtc_base/signalthread_unittest.cc b/rtc_base/signal_thread_unittest.cc
similarity index 96%
rename from rtc_base/signalthread_unittest.cc
rename to rtc_base/signal_thread_unittest.cc
index 078710b..2bc0dda 100644
--- a/rtc_base/signalthread_unittest.cc
+++ b/rtc_base/signal_thread_unittest.cc
@@ -10,12 +10,15 @@
#include <memory>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/signalthread.h"
+#include "rtc_base/signal_thread.h"
+#include "rtc_base/socket_server.h"
#include "rtc_base/thread.h"
+#include "test/gtest.h"
-using namespace rtc;
+namespace rtc {
+namespace {
// 10 seconds.
static const int kTimeout = 10000;
@@ -206,3 +209,6 @@
ExpectState(1, 0, 0, 1, 0);
ExpectStateWait(1, 1, 0, 1, 1, kTimeout);
}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/sigslotrepeater.h b/rtc_base/sigslot_repeater.h
similarity index 94%
rename from rtc_base/sigslotrepeater.h
rename to rtc_base/sigslot_repeater.h
index 724e624..f562c5a 100644
--- a/rtc_base/sigslotrepeater.h
+++ b/rtc_base/sigslot_repeater.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SIGSLOTREPEATER_H__
-#define RTC_BASE_SIGSLOTREPEATER_H__
+#ifndef RTC_BASE_SIGSLOT_REPEATER_H__
+#define RTC_BASE_SIGSLOT_REPEATER_H__
// repeaters are both signals and slots, which are designed as intermediate
// pass-throughs for signals and slots which don't know about each other (for
@@ -53,4 +53,4 @@
} // namespace sigslot
-#endif // RTC_BASE_SIGSLOTREPEATER_H__
+#endif // RTC_BASE_SIGSLOT_REPEATER_H__
diff --git a/rtc_base/sigslottester.h b/rtc_base/sigslot_tester.h
similarity index 97%
rename from rtc_base/sigslottester.h
rename to rtc_base/sigslot_tester.h
index 73f4365..58be511 100644
--- a/rtc_base/sigslottester.h
+++ b/rtc_base/sigslot_tester.h
@@ -12,8 +12,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SIGSLOTTESTER_H_
-#define RTC_BASE_SIGSLOTTESTER_H_
+#ifndef RTC_BASE_SIGSLOT_TESTER_H_
+#define RTC_BASE_SIGSLOT_TESTER_H_
// To generate sigslottester.h from sigslottester.h.pump, execute:
// /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump
@@ -38,7 +38,7 @@
// EXPECT_EQ("hello", capture);
// /* See unit-tests for more examples */
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
@@ -237,4 +237,4 @@
};
} // namespace rtc
-#endif // RTC_BASE_SIGSLOTTESTER_H_
+#endif // RTC_BASE_SIGSLOT_TESTER_H_
diff --git a/rtc_base/sigslottester_unittest.cc b/rtc_base/sigslot_tester_unittest.cc
similarity index 97%
rename from rtc_base/sigslottester_unittest.cc
rename to rtc_base/sigslot_tester_unittest.cc
index 8fde268..6c5b12e 100644
--- a/rtc_base/sigslottester_unittest.cc
+++ b/rtc_base/sigslot_tester_unittest.cc
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/sigslottester.h"
+#include "rtc_base/sigslot_tester.h"
#include <string>
-#include "rtc_base/gunit.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/sigslot_unittest.cc b/rtc_base/sigslot_unittest.cc
index 2f3de40..8edab7c 100644
--- a/rtc_base/sigslot_unittest.cc
+++ b/rtc_base/sigslot_unittest.cc
@@ -9,8 +9,9 @@
*/
#include "rtc_base/third_party/sigslot/sigslot.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/sigslotrepeater.h"
+
+#include "rtc_base/sigslot_repeater.h"
+#include "test/gtest.h"
// This function, when passed a has_slots or signalx, will break the build if
// its threading requirement is not single threaded
diff --git a/rtc_base/sigslottester.h.pump b/rtc_base/sigslottester.h.pump
index 0c7c693..0a1f411 100755
--- a/rtc_base/sigslottester.h.pump
+++ b/rtc_base/sigslottester.h.pump
@@ -35,7 +35,7 @@
// EXPECT_EQ("hello", capture);
// /* See unit-tests for more examples */
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
diff --git a/rtc_base/socket.h b/rtc_base/socket.h
index e7e8210..a2b65d1 100644
--- a/rtc_base/socket.h
+++ b/rtc_base/socket.h
@@ -25,9 +25,8 @@
#include "rtc_base/win32.h"
#endif
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/network/sent_packet.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/socket_address.h"
// Rather than converting errors into a private namespace,
// Reuse the POSIX socket api errors. Note this depends on
diff --git a/rtc_base/socketadapters.cc b/rtc_base/socket_adapters.cc
similarity index 80%
rename from rtc_base/socketadapters.cc
rename to rtc_base/socket_adapters.cc
index 3bac17b..2bcdcd8 100644
--- a/rtc_base/socketadapters.cc
+++ b/rtc_base/socket_adapters.cc
@@ -31,13 +31,12 @@
#include "absl/strings/match.h"
#include "rtc_base/buffer.h"
-#include "rtc_base/bytebuffer.h"
+#include "rtc_base/byte_buffer.h"
#include "rtc_base/checks.h"
-#include "rtc_base/httpcommon.h"
+#include "rtc_base/http_common.h"
#include "rtc_base/logging.h"
-#include "rtc_base/socketadapters.h"
+#include "rtc_base/socket_adapters.h"
#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/stringutils.h"
#include "rtc_base/zero_memory.h"
namespace rtc {
@@ -130,12 +129,6 @@
ProcessInput(buffer_, &data_len_);
}
-AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
- size_t buffer_size)
- : BufferedReadAdapter(socket, buffer_size) {}
-
-AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
-
///////////////////////////////////////////////////////////////////////////////
// This is a SSL v2 CLIENT_HELLO message.
@@ -157,6 +150,13 @@
0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
};
+// static
+ArrayView<const uint8_t> AsyncSSLSocket::SslClientHello() {
+ // Implicit conversion directly from kSslClientHello to ArrayView fails when
+ // built with gcc.
+ return {kSslClientHello, sizeof(kSslClientHello)};
+}
+
// This is a TLSv1 SERVER_HELLO message.
static const uint8_t kSslServerHello[] = {
0x16, // handshake message
@@ -178,6 +178,11 @@
0x00 // null compression
};
+// static
+ArrayView<const uint8_t> AsyncSSLSocket::SslServerHello() {
+ return {kSslServerHello, sizeof(kSslServerHello)};
+}
+
AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
: BufferedReadAdapter(socket, 1024) {}
@@ -219,35 +224,6 @@
SignalReadEvent(this);
}
-AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
- : BufferedReadAdapter(socket, 1024) {
- BufferInput(true);
-}
-
-void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
- // We only accept client hello messages.
- if (*len < sizeof(kSslClientHello)) {
- return;
- }
-
- if (memcmp(kSslClientHello, data, sizeof(kSslClientHello)) != 0) {
- Close();
- SignalCloseEvent(this, 0);
- return;
- }
-
- *len -= sizeof(kSslClientHello);
-
- // Clients should not send more data until the handshake is completed.
- RTC_DCHECK(*len == 0);
-
- // Send a server hello back to the client.
- DirectSend(kSslServerHello, sizeof(kSslServerHello));
-
- // Handshake completed for us, redirect input to our parent.
- BufferInput(false);
-}
-
///////////////////////////////////////////////////////////////////////////////
AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
@@ -714,135 +690,4 @@
SignalCloseEvent(this, error);
}
-AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
- : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
- BufferInput(true);
-}
-
-void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
- // TODO: See if the whole message has arrived
- RTC_DCHECK(state_ < SS_CONNECT_PENDING);
-
- ByteBufferReader response(data, *len);
- if (state_ == SS_HELLO) {
- HandleHello(&response);
- } else if (state_ == SS_AUTH) {
- HandleAuth(&response);
- } else if (state_ == SS_CONNECT) {
- HandleConnect(&response);
- }
-
- // Consume parsed data
- *len = response.Length();
- memmove(data, response.Data(), *len);
-}
-
-void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
- BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
-}
-
-void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
- uint8_t ver, num_methods;
- if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
- Error(0);
- return;
- }
-
- if (ver != 5) {
- Error(0);
- return;
- }
-
- // Handle either no-auth (0) or user/pass auth (2)
- uint8_t method = 0xFF;
- if (num_methods > 0 && !request->ReadUInt8(&method)) {
- Error(0);
- return;
- }
-
- // TODO: Ask the server which method to use.
- SendHelloReply(method);
- if (method == 0) {
- state_ = SS_CONNECT;
- } else if (method == 2) {
- state_ = SS_AUTH;
- } else {
- state_ = SS_ERROR;
- }
-}
-
-void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
- ByteBufferWriter response;
- response.WriteUInt8(5); // Socks Version
- response.WriteUInt8(method); // Auth method
- DirectSend(response);
-}
-
-void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
- uint8_t ver, user_len, pass_len;
- std::string user, pass;
- if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
- !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
- !request->ReadString(&pass, pass_len)) {
- Error(0);
- return;
- }
-
- // TODO: Allow for checking of credentials.
- SendAuthReply(0);
- state_ = SS_CONNECT;
-}
-
-void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
- ByteBufferWriter response;
- response.WriteUInt8(1); // Negotiation Version
- response.WriteUInt8(result);
- DirectSend(response);
-}
-
-void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
- uint8_t ver, command, reserved, addr_type;
- uint32_t ip;
- uint16_t port;
- if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
- !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
- !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
- Error(0);
- return;
- }
-
- if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
- Error(0);
- return;
- }
-
- SignalConnectRequest(this, SocketAddress(ip, port));
- state_ = SS_CONNECT_PENDING;
-}
-
-void AsyncSocksProxyServerSocket::SendConnectResult(int result,
- const SocketAddress& addr) {
- if (state_ != SS_CONNECT_PENDING)
- return;
-
- ByteBufferWriter response;
- response.WriteUInt8(5); // Socks version
- response.WriteUInt8((result != 0)); // 0x01 is generic error
- response.WriteUInt8(0); // reserved
- response.WriteUInt8(1); // IPv4 address
- response.WriteUInt32(addr.ip());
- response.WriteUInt16(addr.port());
- DirectSend(response);
- BufferInput(false);
- state_ = SS_TUNNEL;
-}
-
-void AsyncSocksProxyServerSocket::Error(int error) {
- state_ = SS_ERROR;
- BufferInput(false);
- Close();
- SetError(SOCKET_EACCES);
- SignalCloseEvent(this, error);
-}
-
} // namespace rtc
diff --git a/rtc_base/socketadapters.h b/rtc_base/socket_adapters.h
similarity index 71%
rename from rtc_base/socketadapters.h
rename to rtc_base/socket_adapters.h
index 062f75c..99c9109 100644
--- a/rtc_base/socketadapters.h
+++ b/rtc_base/socket_adapters.h
@@ -8,14 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETADAPTERS_H_
-#define RTC_BASE_SOCKETADAPTERS_H_
+#ifndef RTC_BASE_SOCKET_ADAPTERS_H_
+#define RTC_BASE_SOCKET_ADAPTERS_H_
#include <string>
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/cryptstring.h"
+#include "api/array_view.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/crypt_string.h"
namespace rtc {
@@ -55,22 +56,13 @@
///////////////////////////////////////////////////////////////////////////////
-// Interface for implementing proxy server sockets.
-class AsyncProxyServerSocket : public BufferedReadAdapter {
- public:
- AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size);
- ~AsyncProxyServerSocket() override;
- sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&>
- SignalConnectRequest;
- virtual void SendConnectResult(int err, const SocketAddress& addr) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
// Implements a socket adapter that performs the client side of a
// fake SSL handshake. Used for "ssltcp" P2P functionality.
class AsyncSSLSocket : public BufferedReadAdapter {
public:
+ static ArrayView<const uint8_t> SslClientHello();
+ static ArrayView<const uint8_t> SslServerHello();
+
explicit AsyncSSLSocket(AsyncSocket* socket);
int Connect(const SocketAddress& addr) override;
@@ -81,17 +73,6 @@
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLSocket);
};
-// Implements a socket adapter that performs the server side of a
-// fake SSL handshake. Used when implementing a relay server that does "ssltcp".
-class AsyncSSLServerSocket : public BufferedReadAdapter {
- public:
- explicit AsyncSSLServerSocket(AsyncSocket* socket);
-
- protected:
- void ProcessInput(char* data, size_t* len) override;
- RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSSLServerSocket);
-};
-
///////////////////////////////////////////////////////////////////////////////
// Implements a socket adapter that speaks the HTTP/S proxy protocol.
@@ -184,37 +165,6 @@
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxySocket);
};
-// Implements a proxy server socket for the SOCKS protocol.
-class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket {
- public:
- explicit AsyncSocksProxyServerSocket(AsyncSocket* socket);
-
- private:
- void ProcessInput(char* data, size_t* len) override;
- void DirectSend(const ByteBufferWriter& buf);
-
- void HandleHello(ByteBufferReader* request);
- void SendHelloReply(uint8_t method);
- void HandleAuth(ByteBufferReader* request);
- void SendAuthReply(uint8_t result);
- void HandleConnect(ByteBufferReader* request);
- void SendConnectResult(int result, const SocketAddress& addr) override;
-
- void Error(int error);
-
- static const int kBufferSize = 1024;
- enum State {
- SS_HELLO,
- SS_AUTH,
- SS_CONNECT,
- SS_CONNECT_PENDING,
- SS_TUNNEL,
- SS_ERROR
- };
- State state_;
- RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxyServerSocket);
-};
-
} // namespace rtc
-#endif // RTC_BASE_SOCKETADAPTERS_H_
+#endif // RTC_BASE_SOCKET_ADAPTERS_H_
diff --git a/rtc_base/socketaddress.cc b/rtc_base/socket_address.cc
similarity index 98%
rename from rtc_base/socketaddress.cc
rename to rtc_base/socket_address.cc
index c91846d..3b22a05 100644
--- a/rtc_base/socketaddress.cc
+++ b/rtc_base/socket_address.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/numerics/safe_conversions.h"
#if defined(WEBRTC_POSIX)
@@ -26,10 +26,10 @@
#include <unistd.h>
#endif
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/nethelpers.h"
+#include "rtc_base/net_helpers.h"
#include "rtc_base/strings/string_builder.h"
#if defined(WEBRTC_WIN)
diff --git a/rtc_base/socketaddress.h b/rtc_base/socket_address.h
similarity index 97%
rename from rtc_base/socketaddress.h
rename to rtc_base/socket_address.h
index b1a52b9..342f5de 100644
--- a/rtc_base/socketaddress.h
+++ b/rtc_base/socket_address.h
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETADDRESS_H_
-#define RTC_BASE_SOCKETADDRESS_H_
+#ifndef RTC_BASE_SOCKET_ADDRESS_H_
+#define RTC_BASE_SOCKET_ADDRESS_H_
#include <string>
#ifdef UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
-#include "rtc_base/ipaddress.h"
+#include "rtc_base/ip_address.h"
#undef SetPort
@@ -199,4 +199,4 @@
} // namespace rtc
-#endif // RTC_BASE_SOCKETADDRESS_H_
+#endif // RTC_BASE_SOCKET_ADDRESS_H_
diff --git a/rtc_base/socketaddresspair.cc b/rtc_base/socket_address_pair.cc
similarity index 95%
rename from rtc_base/socketaddresspair.cc
rename to rtc_base/socket_address_pair.cc
index 914ffd9..54f70ff 100644
--- a/rtc_base/socketaddresspair.cc
+++ b/rtc_base/socket_address_pair.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/socketaddresspair.h"
+#include "rtc_base/socket_address_pair.h"
namespace rtc {
diff --git a/rtc_base/socketaddresspair.h b/rtc_base/socket_address_pair.h
similarity index 87%
rename from rtc_base/socketaddresspair.h
rename to rtc_base/socket_address_pair.h
index 6691386..f315e64 100644
--- a/rtc_base/socketaddresspair.h
+++ b/rtc_base/socket_address_pair.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETADDRESSPAIR_H_
-#define RTC_BASE_SOCKETADDRESSPAIR_H_
+#ifndef RTC_BASE_SOCKET_ADDRESS_PAIR_H_
+#define RTC_BASE_SOCKET_ADDRESS_PAIR_H_
#include <stddef.h>
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/socket_address.h"
namespace rtc {
@@ -40,4 +40,4 @@
} // namespace rtc
-#endif // RTC_BASE_SOCKETADDRESSPAIR_H_
+#endif // RTC_BASE_SOCKET_ADDRESS_PAIR_H_
diff --git a/rtc_base/socketaddress_unittest.cc b/rtc_base/socket_address_unittest.cc
similarity index 98%
rename from rtc_base/socketaddress_unittest.cc
rename to rtc_base/socket_address_unittest.cc
index b7a2d92..14da8cb 100644
--- a/rtc_base/socketaddress_unittest.cc
+++ b/rtc_base/socket_address_unittest.cc
@@ -12,9 +12,11 @@
#include <netinet/in.h> // for sockaddr_in
#endif
-#include "rtc_base/gunit.h"
-#include "rtc_base/ipaddress.h"
-#include "rtc_base/socketaddress.h"
+#include <string.h>
+
+#include "rtc_base/ip_address.h"
+#include "rtc_base/socket_address.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/socketfactory.h b/rtc_base/socket_factory.h
similarity index 85%
rename from rtc_base/socketfactory.h
rename to rtc_base/socket_factory.h
index 5a5cd04..7356745 100644
--- a/rtc_base/socketfactory.h
+++ b/rtc_base/socket_factory.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETFACTORY_H_
-#define RTC_BASE_SOCKETFACTORY_H_
+#ifndef RTC_BASE_SOCKET_FACTORY_H_
+#define RTC_BASE_SOCKET_FACTORY_H_
-#include "rtc_base/asyncsocket.h"
+#include "rtc_base/async_socket.h"
#include "rtc_base/socket.h"
namespace rtc {
@@ -30,4 +30,4 @@
} // namespace rtc
-#endif // RTC_BASE_SOCKETFACTORY_H_
+#endif // RTC_BASE_SOCKET_FACTORY_H_
diff --git a/rtc_base/socketserver.h b/rtc_base/socket_server.h
similarity index 93%
rename from rtc_base/socketserver.h
rename to rtc_base/socket_server.h
index e29884e..348d099 100644
--- a/rtc_base/socketserver.h
+++ b/rtc_base/socket_server.h
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETSERVER_H_
-#define RTC_BASE_SOCKETSERVER_H_
+#ifndef RTC_BASE_SOCKET_SERVER_H_
+#define RTC_BASE_SOCKET_SERVER_H_
#include <memory>
-#include "rtc_base/socketfactory.h"
+#include "rtc_base/socket_factory.h"
namespace rtc {
@@ -59,4 +59,4 @@
} // namespace rtc
-#endif // RTC_BASE_SOCKETSERVER_H_
+#endif // RTC_BASE_SOCKET_SERVER_H_
diff --git a/rtc_base/socketstream.cc b/rtc_base/socket_stream.cc
similarity index 98%
rename from rtc_base/socketstream.cc
rename to rtc_base/socket_stream.cc
index 8978404..e93d6aa 100644
--- a/rtc_base/socketstream.cc
+++ b/rtc_base/socket_stream.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/socketstream.h"
+#include "rtc_base/socket_stream.h"
#include "rtc_base/checks.h"
#include "rtc_base/socket.h"
diff --git a/rtc_base/socketstream.h b/rtc_base/socket_stream.h
similarity index 85%
rename from rtc_base/socketstream.h
rename to rtc_base/socket_stream.h
index f781af1..f9875fe 100644
--- a/rtc_base/socketstream.h
+++ b/rtc_base/socket_stream.h
@@ -8,12 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SOCKETSTREAM_H_
-#define RTC_BASE_SOCKETSTREAM_H_
+#ifndef RTC_BASE_SOCKET_STREAM_H_
+#define RTC_BASE_SOCKET_STREAM_H_
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/constructormagic.h"
+#include <stddef.h>
+
+#include "rtc_base/async_socket.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/stream.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
@@ -58,4 +61,4 @@
} // namespace rtc
-#endif // RTC_BASE_SOCKETSTREAM_H_
+#endif // RTC_BASE_SOCKET_STREAM_H_
diff --git a/rtc_base/socket_unittest.cc b/rtc_base/socket_unittest.cc
index cbc5eb5..3166ec7 100644
--- a/rtc_base/socket_unittest.cc
+++ b/rtc_base/socket_unittest.cc
@@ -8,20 +8,32 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
#include <memory>
-#include "rtc_base/socket_unittest.h"
-
#include "absl/memory/memory.h"
#include "rtc_base/arraysize.h"
-#include "rtc_base/asyncudpsocket.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/async_udp_socket.h"
#include "rtc_base/buffer.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/nethelpers.h"
-#include "rtc_base/socketserver.h"
-#include "rtc_base/testclient.h"
-#include "rtc_base/testutils.h"
+#include "rtc_base/location.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/socket_server.h"
+#include "rtc_base/socket_unittest.h"
+#include "rtc_base/test_client.h"
+#include "rtc_base/test_utils.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/ssladapter.cc b/rtc_base/ssl_adapter.cc
similarity index 93%
rename from rtc_base/ssladapter.cc
rename to rtc_base/ssl_adapter.cc
index e091f00..9d414ea 100644
--- a/rtc_base/ssladapter.cc
+++ b/rtc_base/ssl_adapter.cc
@@ -8,9 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/ssladapter.h"
+#include "rtc_base/ssl_adapter.h"
-#include "rtc_base/openssladapter.h"
+#include "rtc_base/openssl_adapter.h"
///////////////////////////////////////////////////////////////////////////////
diff --git a/rtc_base/ssladapter.h b/rtc_base/ssl_adapter.h
similarity index 93%
rename from rtc_base/ssladapter.h
rename to rtc_base/ssl_adapter.h
index 7ebedca..240899f 100644
--- a/rtc_base/ssladapter.h
+++ b/rtc_base/ssl_adapter.h
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SSLADAPTER_H_
-#define RTC_BASE_SSLADAPTER_H_
+#ifndef RTC_BASE_SSL_ADAPTER_H_
+#define RTC_BASE_SSL_ADAPTER_H_
#include <string>
#include <vector>
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
namespace rtc {
@@ -103,4 +103,4 @@
} // namespace rtc
-#endif // RTC_BASE_SSLADAPTER_H_
+#endif // RTC_BASE_SSL_ADAPTER_H_
diff --git a/rtc_base/ssladapter_unittest.cc b/rtc_base/ssl_adapter_unittest.cc
similarity index 98%
rename from rtc_base/ssladapter_unittest.cc
rename to rtc_base/ssl_adapter_unittest.cc
index c84c668..b459496 100644
--- a/rtc_base/ssladapter_unittest.cc
+++ b/rtc_base/ssl_adapter_unittest.cc
@@ -14,15 +14,15 @@
#include "absl/memory/memory.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/ipaddress.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/socketstream.h"
-#include "rtc_base/ssladapter.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/socket_stream.h"
+#include "rtc_base/ssl_adapter.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
-#include "rtc_base/stringencode.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/virtual_socket_server.h"
#include "test/gmock.h"
using ::testing::_;
@@ -53,7 +53,7 @@
MOCK_METHOD1(Verify, bool(const rtc::SSLCertificate&));
};
-// TODO(benwright) - Move to using INSTANTIATE_TEST_CASE_P instead of using
+// TODO(benwright) - Move to using INSTANTIATE_TEST_SUITE_P instead of using
// duplicate test cases for simple parameter changes.
class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
public:
diff --git a/rtc_base/sslcertificate.cc b/rtc_base/ssl_certificate.cc
similarity index 97%
rename from rtc_base/sslcertificate.cc
rename to rtc_base/ssl_certificate.cc
index 934848f..8f6cfa2 100644
--- a/rtc_base/sslcertificate.cc
+++ b/rtc_base/ssl_certificate.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/sslcertificate.h"
+#include "rtc_base/ssl_certificate.h"
#include <algorithm>
#include <string>
@@ -16,8 +16,8 @@
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
-#include "rtc_base/opensslcertificate.h"
-#include "rtc_base/sslfingerprint.h"
+#include "rtc_base/openssl_certificate.h"
+#include "rtc_base/ssl_fingerprint.h"
#include "rtc_base/third_party/base64/base64.h"
namespace rtc {
diff --git a/rtc_base/sslcertificate.h b/rtc_base/ssl_certificate.h
similarity index 97%
rename from rtc_base/sslcertificate.h
rename to rtc_base/ssl_certificate.h
index eb81c20..fad1404 100644
--- a/rtc_base/sslcertificate.h
+++ b/rtc_base/ssl_certificate.h
@@ -12,8 +12,8 @@
// for TLS TURN connections and the SSLStreamAdapter for DTLS Peer to Peer
// Connections for SRTP Key negotiation and SCTP encryption.
-#ifndef RTC_BASE_SSLCERTIFICATE_H_
-#define RTC_BASE_SSLCERTIFICATE_H_
+#ifndef RTC_BASE_SSL_CERTIFICATE_H_
+#define RTC_BASE_SSL_CERTIFICATE_H_
#include <stddef.h>
#include <stdint.h>
@@ -22,7 +22,7 @@
#include <vector>
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -134,4 +134,4 @@
} // namespace rtc
-#endif // RTC_BASE_SSLCERTIFICATE_H_
+#endif // RTC_BASE_SSL_CERTIFICATE_H_
diff --git a/rtc_base/sslfingerprint.cc b/rtc_base/ssl_fingerprint.cc
similarity index 94%
rename from rtc_base/sslfingerprint.cc
rename to rtc_base/ssl_fingerprint.cc
index b296d33..77b6149 100644
--- a/rtc_base/sslfingerprint.cc
+++ b/rtc_base/ssl_fingerprint.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/sslfingerprint.h"
+#include "rtc_base/ssl_fingerprint.h"
#include <ctype.h>
#include <algorithm>
@@ -17,11 +17,11 @@
#include "absl/memory/memory.h"
#include "rtc_base/logging.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/rtccertificate.h"
-#include "rtc_base/sslcertificate.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/stringencode.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/rtc_certificate.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/string_encode.h"
namespace rtc {
diff --git a/rtc_base/sslfingerprint.h b/rtc_base/ssl_fingerprint.h
similarity index 93%
rename from rtc_base/sslfingerprint.h
rename to rtc_base/ssl_fingerprint.h
index ea10ede..f4037f7 100644
--- a/rtc_base/sslfingerprint.h
+++ b/rtc_base/ssl_fingerprint.h
@@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SSLFINGERPRINT_H_
-#define RTC_BASE_SSLFINGERPRINT_H_
+#ifndef RTC_BASE_SSL_FINGERPRINT_H_
+#define RTC_BASE_SSL_FINGERPRINT_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
-#include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/copy_on_write_buffer.h"
namespace rtc {
@@ -70,4 +70,4 @@
} // namespace rtc
-#endif // RTC_BASE_SSLFINGERPRINT_H_
+#endif // RTC_BASE_SSL_FINGERPRINT_H_
diff --git a/rtc_base/sslidentity.cc b/rtc_base/ssl_identity.cc
similarity index 97%
rename from rtc_base/sslidentity.cc
rename to rtc_base/ssl_identity.cc
index 41eb35d..64c0f67 100644
--- a/rtc_base/sslidentity.cc
+++ b/rtc_base/ssl_identity.cc
@@ -9,18 +9,18 @@
*/
// Handling of certificates and keypairs for SSLStreamAdapter's peer mode.
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/ssl_identity.h"
#include <string.h>
#include <time.h>
#include <string>
#include "rtc_base/checks.h"
-#include "rtc_base/opensslidentity.h"
-#include "rtc_base/sslcertificate.h"
+#include "rtc_base/openssl_identity.h"
+#include "rtc_base/ssl_certificate.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/third_party/base64/base64.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
@@ -174,7 +174,7 @@
if (header == std::string::npos) {
return false;
}
- size_t body = pem_string.find("\n", header);
+ size_t body = pem_string.find('\n', header);
if (body == std::string::npos) {
return false;
}
diff --git a/rtc_base/sslidentity.h b/rtc_base/ssl_identity.h
similarity index 98%
rename from rtc_base/sslidentity.h
rename to rtc_base/ssl_identity.h
index 39feeab..c013a89 100644
--- a/rtc_base/sslidentity.h
+++ b/rtc_base/ssl_identity.h
@@ -10,8 +10,8 @@
// Handling of certificates and keypairs for SSLStreamAdapter's peer mode.
-#ifndef RTC_BASE_SSLIDENTITY_H_
-#define RTC_BASE_SSLIDENTITY_H_
+#ifndef RTC_BASE_SSL_IDENTITY_H_
+#define RTC_BASE_SSL_IDENTITY_H_
#include <stdint.h>
#include <ctime>
@@ -164,4 +164,4 @@
} // namespace rtc
-#endif // RTC_BASE_SSLIDENTITY_H_
+#endif // RTC_BASE_SSL_IDENTITY_H_
diff --git a/rtc_base/sslidentity_unittest.cc b/rtc_base/ssl_identity_unittest.cc
similarity index 97%
rename from rtc_base/sslidentity_unittest.cc
rename to rtc_base/ssl_identity_unittest.cc
index ba53d17..748041e 100644
--- a/rtc_base/sslidentity_unittest.cc
+++ b/rtc_base/ssl_identity_unittest.cc
@@ -8,17 +8,20 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <string.h>
#include <memory>
#include <string>
+#include <vector>
-#include "rtc_base/fakesslidentity.h"
-#include "rtc_base/gunit.h"
+#include "absl/strings/str_replace.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/fake_ssl_identity.h"
#include "rtc_base/helpers.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/ssladapter.h"
-#include "rtc_base/sslfingerprint.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/ssl_fingerprint.h"
+#include "rtc_base/ssl_identity.h"
+#include "test/gtest.h"
using rtc::SSLIdentity;
@@ -170,10 +173,10 @@
info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
// Strip header/footer and newline characters of PEM strings.
for (size_t i = 0; i < info.pems.size(); ++i) {
- rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, "", 0,
- &info.pems[i]);
- rtc::replace_substrs("-----END CERTIFICATE-----", 25, "", 0, &info.pems[i]);
- rtc::replace_substrs("\n", 1, "", 0, &info.pems[i]);
+ absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
+ {"-----END CERTIFICATE-----", ""},
+ {"\n", ""}},
+ &info.pems[i]);
}
// Fingerprints for the whole certificate chain, starting with leaf
// certificate.
diff --git a/rtc_base/sslroots.h b/rtc_base/ssl_roots.h
similarity index 99%
rename from rtc_base/sslroots.h
rename to rtc_base/ssl_roots.h
index 0dbd19b..69f6e39 100644
--- a/rtc_base/sslroots.h
+++ b/rtc_base/ssl_roots.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SSLROOTS_H_
-#define RTC_BASE_SSLROOTS_H_
+#ifndef RTC_BASE_SSL_ROOTS_H_
+#define RTC_BASE_SSL_ROOTS_H_
// This file is the root certificates in C form that are needed to connect to
// Google.
@@ -4283,4 +4283,4 @@
// clang-format on
-#endif // RTC_BASE_SSLROOTS_H_
+#endif // RTC_BASE_SSL_ROOTS_H_
diff --git a/rtc_base/sslstreamadapter.cc b/rtc_base/ssl_stream_adapter.cc
similarity index 98%
rename from rtc_base/sslstreamadapter.cc
rename to rtc_base/ssl_stream_adapter.cc
index 9c33a9c..372c37f 100644
--- a/rtc_base/sslstreamadapter.cc
+++ b/rtc_base/ssl_stream_adapter.cc
@@ -8,9 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/ssl_stream_adapter.h"
-#include "rtc_base/opensslstreamadapter.h"
+#include "rtc_base/openssl_stream_adapter.h"
///////////////////////////////////////////////////////////////////////////////
diff --git a/rtc_base/sslstreamadapter.h b/rtc_base/ssl_stream_adapter.h
similarity index 94%
rename from rtc_base/sslstreamadapter.h
rename to rtc_base/ssl_stream_adapter.h
index 25f4f33..99345ac 100644
--- a/rtc_base/sslstreamadapter.h
+++ b/rtc_base/ssl_stream_adapter.h
@@ -8,15 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_SSLSTREAMADAPTER_H_
-#define RTC_BASE_SSLSTREAMADAPTER_H_
+#ifndef RTC_BASE_SSL_STREAM_ADAPTER_H_
+#define RTC_BASE_SSL_STREAM_ADAPTER_H_
+#include <stddef.h>
+#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
-#include "rtc_base/sslidentity.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_identity.h"
#include "rtc_base/stream.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
@@ -86,6 +90,11 @@
enum SSLRole { SSL_CLIENT, SSL_SERVER };
enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS };
+
+// Note: By default TLS_10, TLS_11, and DTLS_10 will all be upgraded to DTLS1_2
+// unless the trial flag WebRTC-LegacyTlsProtocols/Enabled/ is passed in. These
+// protocol versions will be completely removed in M75
+// TODO(https://bugs.webrtc.org/10261).
enum SSLProtocolVersion {
SSL_PROTOCOL_TLS_10,
SSL_PROTOCOL_TLS_11,
@@ -259,4 +268,4 @@
} // namespace rtc
-#endif // RTC_BASE_SSLSTREAMADAPTER_H_
+#endif // RTC_BASE_SSL_STREAM_ADAPTER_H_
diff --git a/rtc_base/sslstreamadapter_unittest.cc b/rtc_base/ssl_stream_adapter_unittest.cc
similarity index 94%
rename from rtc_base/sslstreamadapter_unittest.cc
rename to rtc_base/ssl_stream_adapter_unittest.cc
index 6fbb1d7..abf9880 100644
--- a/rtc_base/sslstreamadapter_unittest.cc
+++ b/rtc_base/ssl_stream_adapter_unittest.cc
@@ -13,21 +13,22 @@
#include <set>
#include <string>
-#include "rtc_base/bufferqueue.h"
+#include "rtc_base/buffer_queue.h"
#include "rtc_base/checks.h"
#include "rtc_base/gunit.h"
#include "rtc_base/helpers.h"
#include "rtc_base/memory_stream.h"
-#include "rtc_base/messagedigest.h"
-#include "rtc_base/ssladapter.h"
-#include "rtc_base/sslidentity.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/message_digest.h"
+#include "rtc_base/ssl_adapter.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
+#include "test/field_trial.h"
-using ::testing::WithParamInterface;
-using ::testing::Values;
using ::testing::Combine;
using ::testing::tuple;
+using ::testing::Values;
+using ::testing::WithParamInterface;
static const int kBlockSize = 4096;
static const char kExporterLabel[] = "label";
@@ -283,6 +284,7 @@
const std::string& client_cert_pem,
const std::string& client_private_key_pem,
bool dtls,
+ bool legacy_tls_protocols = false,
rtc::KeyParams client_key_type = rtc::KeyParams(rtc::KT_DEFAULT),
rtc::KeyParams server_key_type = rtc::KeyParams(rtc::KT_DEFAULT))
: client_cert_pem_(client_cert_pem),
@@ -300,7 +302,8 @@
damage_(false),
dtls_(dtls),
handshake_wait_(5000),
- identities_set_(false) {
+ identities_set_(false),
+ legacy_tls_protocols_(legacy_tls_protocols) {
// Set use of the test RNG to get predictable loss patterns.
rtc::SetRandomTestMode(true);
}
@@ -313,6 +316,10 @@
void SetUp() override {
CreateStreams();
+ // Enable legacy protocols if required
+ webrtc::test::ScopedFieldTrials trial(
+ legacy_tls_protocols_ ? "WebRTC-LegacyTlsProtocols/Enabled/" : "");
+
client_ssl_.reset(rtc::SSLStreamAdapter::Create(client_stream_));
server_ssl_.reset(rtc::SSLStreamAdapter::Create(server_stream_));
@@ -645,6 +652,7 @@
bool dtls_;
int handshake_wait_;
bool identities_set_;
+ bool legacy_tls_protocols_;
};
class SSLStreamAdapterTestTLS
@@ -655,6 +663,7 @@
: SSLStreamAdapterTestBase("",
"",
false,
+ false,
::testing::get<0>(GetParam()),
::testing::get<1>(GetParam())),
client_buffer_(kFifoBufferSize),
@@ -731,7 +740,7 @@
break;
}
}
- };
+ }
void ReadData(rtc::StreamInterface* stream) override {
char buffer[1600];
@@ -771,9 +780,13 @@
public WithParamInterface<tuple<rtc::KeyParams, rtc::KeyParams>> {
public:
SSLStreamAdapterTestDTLS()
+ : SSLStreamAdapterTestDTLS(/*legacy_tls_protocols=*/false) {}
+
+ SSLStreamAdapterTestDTLS(bool legacy_tls_protocols)
: SSLStreamAdapterTestBase("",
"",
true,
+ legacy_tls_protocols,
::testing::get<0>(GetParam()),
::testing::get<1>(GetParam())),
client_buffer_(kBufferCapacity, kDefaultBufferSize),
@@ -880,7 +893,7 @@
RTC_LOG(LS_INFO) << "Sent " << sent_ << " packets; received "
<< received_.size();
}
- };
+ }
private:
BufferQueueStream client_buffer_;
@@ -907,7 +920,7 @@
}
return test_base_->DataWritten(this, data, data_len, written, error);
-};
+}
class SSLStreamAdapterTestDTLSFromPEMStrings : public SSLStreamAdapterTestDTLS {
public:
@@ -919,7 +932,7 @@
// certificate.
class SSLStreamAdapterTestDTLSCertChain : public SSLStreamAdapterTestDTLS {
public:
- SSLStreamAdapterTestDTLSCertChain() : SSLStreamAdapterTestDTLS("", ""){};
+ SSLStreamAdapterTestDTLSCertChain() : SSLStreamAdapterTestDTLS("", "") {}
void SetUp() override {
CreateStreams();
@@ -945,12 +958,19 @@
}
};
+// Enable legacy TLS protocols in DTLS.
+class SSLStreamAdapterTestDTLSLegacyProtocols
+ : public SSLStreamAdapterTestDTLS {
+ public:
+ SSLStreamAdapterTestDTLSLegacyProtocols()
+ : SSLStreamAdapterTestDTLS(/*legacy_tls_protocols=*/true) {}
+};
// Basic tests: TLS
// Test that we can make a handshake work
TEST_P(SSLStreamAdapterTestTLS, TestTLSConnect) {
TestHandshake();
-};
+}
TEST_P(SSLStreamAdapterTestTLS, GetPeerCertChainWithOneCertificate) {
TestHandshake();
@@ -1009,13 +1029,13 @@
TestHandshake();
client_ssl_->Close();
EXPECT_EQ_WAIT(rtc::SS_CLOSED, server_ssl_->GetState(), handshake_wait_);
-};
+}
// Test transfer -- trivial
TEST_P(SSLStreamAdapterTestTLS, TestTLSTransfer) {
TestHandshake();
TestTransfer(100000);
-};
+}
// Test read-write after close.
TEST_P(SSLStreamAdapterTestTLS, ReadWriteAfterClose) {
@@ -1034,21 +1054,21 @@
// But after closed read gives you EOS.
rv = client_ssl_->Read(block, sizeof(block), &dummy, nullptr);
ASSERT_EQ(rtc::SR_EOS, rv);
-};
+}
// Test a handshake with a bogus peer digest
TEST_P(SSLStreamAdapterTestTLS, TestTLSBogusDigest) {
SetPeerIdentitiesByDigest(false, true);
TestHandshake(false);
-};
+}
TEST_P(SSLStreamAdapterTestTLS, TestTLSDelayedIdentity) {
TestHandshakeWithDelayedIdentity(true);
-};
+}
TEST_P(SSLStreamAdapterTestTLS, TestTLSDelayedIdentityWithBogusDigest) {
TestHandshakeWithDelayedIdentity(false);
-};
+}
// Test that the correct error is returned when SetPeerCertificateDigest is
// called with an unknown algorithm.
@@ -1093,7 +1113,7 @@
// Test that we can make a handshake work
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnect) {
TestHandshake();
-};
+}
// Test that we can make a handshake work if the first packet in
// each direction is lost. This gives us predictable loss
@@ -1101,7 +1121,7 @@
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacket) {
SetLoseFirstPacket(true);
TestHandshake();
-};
+}
// Test a handshake with loss and delay
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacketDelay2s) {
@@ -1109,7 +1129,7 @@
SetDelay(2000);
SetHandshakeWait(20000);
TestHandshake();
-};
+}
// Test a handshake with small MTU
// Disabled due to https://code.google.com/p/webrtc/issues/detail?id=3910
@@ -1117,34 +1137,34 @@
SetMtu(700);
SetHandshakeWait(20000);
TestHandshake();
-};
+}
// Test transfer -- trivial
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransfer) {
TestHandshake();
TestTransfer(100);
-};
+}
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithLoss) {
TestHandshake();
SetLoss(10);
TestTransfer(100);
-};
+}
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithDamage) {
SetDamage(); // Must be called first because first packet
// write happens at end of handshake.
TestHandshake();
TestTransfer(100);
-};
+}
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSDelayedIdentity) {
TestHandshakeWithDelayedIdentity(true);
-};
+}
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSDelayedIdentityWithBogusDigest) {
TestHandshakeWithDelayedIdentity(false);
-};
+}
// Test DTLS-SRTP with all high ciphers
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHigh) {
@@ -1161,7 +1181,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_80);
-};
+}
// Test DTLS-SRTP with all low ciphers
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpLow) {
@@ -1178,7 +1198,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_32);
-};
+}
// Test DTLS-SRTP with a mismatch -- should not converge
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHighLow) {
@@ -1194,7 +1214,7 @@
ASSERT_FALSE(GetDtlsSrtpCryptoSuite(true, &client_cipher));
int server_cipher;
ASSERT_FALSE(GetDtlsSrtpCryptoSuite(false, &server_cipher));
-};
+}
// Test DTLS-SRTP with each side being mixed -- should select high
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpMixed) {
@@ -1212,7 +1232,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AES128_CM_SHA1_80);
-};
+}
// Test DTLS-SRTP with all GCM-128 ciphers.
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCM128) {
@@ -1229,7 +1249,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AEAD_AES_128_GCM);
-};
+}
// Test DTLS-SRTP with all GCM-256 ciphers.
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCM256) {
@@ -1246,7 +1266,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AEAD_AES_256_GCM);
-};
+}
// Test DTLS-SRTP with mixed GCM-128/-256 ciphers -- should not converge.
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCMMismatch) {
@@ -1262,7 +1282,7 @@
ASSERT_FALSE(GetDtlsSrtpCryptoSuite(true, &client_cipher));
int server_cipher;
ASSERT_FALSE(GetDtlsSrtpCryptoSuite(false, &server_cipher));
-};
+}
// Test DTLS-SRTP with both GCM-128/-256 ciphers -- should select GCM-256.
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCMMixed) {
@@ -1280,7 +1300,7 @@
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_EQ(client_cipher, rtc::SRTP_AEAD_AES_256_GCM);
-};
+}
// Test SRTP cipher suite lengths.
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpKeyAndSaltLengths) {
@@ -1309,7 +1329,7 @@
&key_len, &salt_len));
ASSERT_EQ(256 / 8, key_len);
ASSERT_EQ(96 / 8, salt_len);
-};
+}
// Test an exporter
TEST_P(SSLStreamAdapterTestDTLS, TestDTLSExporter) {
@@ -1381,7 +1401,7 @@
// Test getting the used DTLS ciphers.
// DTLS 1.2 enabled for neither client nor server -> DTLS 1.0 will be used.
-TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuite) {
+TEST_P(SSLStreamAdapterTestDTLSLegacyProtocols, TestGetSslCipherSuite) {
SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10);
TestHandshake();
@@ -1400,6 +1420,64 @@
// Test getting the used DTLS 1.2 ciphers.
// DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used.
+TEST_P(SSLStreamAdapterTestDTLSLegacyProtocols,
+ TestGetSslCipherSuiteDtls12Both) {
+ SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12);
+ TestHandshake();
+
+ int client_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher));
+ int server_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher));
+
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(true));
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(false));
+
+ ASSERT_EQ(client_cipher, server_cipher);
+ ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher(
+ server_cipher, ::testing::get<1>(GetParam()).type()));
+}
+
+// DTLS 1.2 enabled for client only -> DTLS 1.0 will be used.
+TEST_P(SSLStreamAdapterTestDTLSLegacyProtocols,
+ TestGetSslCipherSuiteDtls12Client) {
+ SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12);
+ TestHandshake();
+
+ int client_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher));
+ int server_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher));
+
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true));
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false));
+
+ ASSERT_EQ(client_cipher, server_cipher);
+ ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher(
+ server_cipher, ::testing::get<1>(GetParam()).type()));
+}
+
+// DTLS 1.2 enabled for server only -> DTLS 1.0 will be used.
+TEST_P(SSLStreamAdapterTestDTLSLegacyProtocols,
+ TestGetSslCipherSuiteDtls12Server) {
+ SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10);
+ TestHandshake();
+
+ int client_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher));
+ int server_cipher;
+ ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher));
+
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true));
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false));
+
+ ASSERT_EQ(client_cipher, server_cipher);
+ ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher(
+ server_cipher, ::testing::get<1>(GetParam()).type()));
+}
+
+// Test getting the used DTLS 1.2 ciphers.
+// DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used.
TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuiteDtls12Both) {
SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12);
TestHandshake();
@@ -1417,9 +1495,10 @@
server_cipher, ::testing::get<1>(GetParam()).type()));
}
-// DTLS 1.2 enabled for client only -> DTLS 1.0 will be used.
-TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuiteDtls12Client) {
- SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12);
+// Test getting the used DTLS ciphers.
+// DTLS 1.0 enabled for client and server, both will be upgraded to DTLS 1.2
+TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuite) {
+ SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10);
TestHandshake();
int client_cipher;
@@ -1427,26 +1506,8 @@
int server_cipher;
ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher));
- ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true));
- ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false));
-
- ASSERT_EQ(client_cipher, server_cipher);
- ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher(
- server_cipher, ::testing::get<1>(GetParam()).type()));
-}
-
-// DTLS 1.2 enabled for server only -> DTLS 1.0 will be used.
-TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuiteDtls12Server) {
- SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10);
- TestHandshake();
-
- int client_cipher;
- ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher));
- int server_cipher;
- ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher));
-
- ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true));
- ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false));
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(true));
+ ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(false));
ASSERT_EQ(client_cipher, server_cipher);
ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher(
@@ -1456,7 +1517,7 @@
// The RSA keysizes here might look strange, why not include the RFC's size
// 2048?. The reason is test case slowness; testing two sizes to exercise
// parametrization is sufficient.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
SSLStreamAdapterTestsTLS,
SSLStreamAdapterTestTLS,
Combine(Values(rtc::KeyParams::RSA(1024, 65537),
@@ -1465,7 +1526,7 @@
Values(rtc::KeyParams::RSA(1024, 65537),
rtc::KeyParams::RSA(1152, 65537),
rtc::KeyParams::ECDSA(rtc::EC_NIST_P256))));
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
SSLStreamAdapterTestsDTLS,
SSLStreamAdapterTestDTLS,
Combine(Values(rtc::KeyParams::RSA(1024, 65537),
diff --git a/rtc_base/stream.cc b/rtc_base/stream.cc
index 783625c..01f1504 100644
--- a/rtc_base/stream.cc
+++ b/rtc_base/stream.cc
@@ -9,13 +9,12 @@
*/
#include <errno.h>
#include <string.h>
-#include <sys/stat.h>
#include <algorithm>
#include <string>
#include "rtc_base/checks.h"
#include "rtc_base/location.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/stream.h"
#include "rtc_base/thread.h"
@@ -23,7 +22,7 @@
#include <windows.h>
#define fileno _fileno
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
#endif
namespace rtc {
@@ -78,26 +77,10 @@
PostEvent(Thread::Current(), events, err);
}
-bool StreamInterface::SetPosition(size_t position) {
- return false;
-}
-
-bool StreamInterface::GetPosition(size_t* position) const {
- return false;
-}
-
-bool StreamInterface::GetSize(size_t* size) const {
- return false;
-}
-
bool StreamInterface::Flush() {
return false;
}
-bool StreamInterface::ReserveSize(size_t size) {
- return true;
-}
-
StreamInterface::StreamInterface() {}
void StreamInterface::OnMessage(Message* msg) {
@@ -138,22 +121,6 @@
stream_->Close();
}
-bool StreamAdapterInterface::SetPosition(size_t position) {
- return stream_->SetPosition(position);
-}
-
-bool StreamAdapterInterface::GetPosition(size_t* position) const {
- return stream_->GetPosition(position);
-}
-
-bool StreamAdapterInterface::GetSize(size_t* size) const {
- return stream_->GetSize(size);
-}
-
-bool StreamAdapterInterface::ReserveSize(size_t size) {
- return stream_->ReserveSize(size);
-}
-
bool StreamAdapterInterface::Flush() {
return stream_->Flush();
}
@@ -305,35 +272,6 @@
return (fseek(file_, static_cast<int>(position), SEEK_SET) == 0);
}
-bool FileStream::GetPosition(size_t* position) const {
- RTC_DCHECK(nullptr != position);
- if (!file_)
- return false;
- long result = ftell(file_);
- if (result < 0)
- return false;
- if (position)
- *position = result;
- return true;
-}
-
-bool FileStream::GetSize(size_t* size) const {
- RTC_DCHECK(nullptr != size);
- if (!file_)
- return false;
- struct stat file_stats;
- if (fstat(fileno(file_), &file_stats) != 0)
- return false;
- if (size)
- *size = file_stats.st_size;
- return true;
-}
-
-bool FileStream::ReserveSize(size_t size) {
- // TODO: extend the file to the proper length
- return true;
-}
-
bool FileStream::Flush() {
if (file_) {
return (0 == fflush(file_));
diff --git a/rtc_base/stream.h b/rtc_base/stream.h
index 43e7f58..a7c6266 100644
--- a/rtc_base/stream.h
+++ b/rtc_base/stream.h
@@ -16,10 +16,10 @@
#include <memory>
#include "rtc_base/buffer.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace rtc {
@@ -107,38 +107,15 @@
// Like the aforementioned method, but posts to the current thread.
void PostEvent(int events, int err);
- // Seek to a byte offset from the beginning of the stream. Returns false if
- // the stream does not support seeking, or cannot seek to the specified
- // position.
- virtual bool SetPosition(size_t position);
-
- // Get the byte offset of the current position from the start of the stream.
- // Returns false if the position is not known.
- virtual bool GetPosition(size_t* position) const;
-
- // Get the byte length of the entire stream. Returns false if the length
- // is not known.
- virtual bool GetSize(size_t* size) const;
-
// Return true if flush is successful.
virtual bool Flush();
- // Communicates the amount of data which will be written to the stream. The
- // stream may choose to preallocate memory to accomodate this data. The
- // stream may return false to indicate that there is not enough room (ie,
- // Write will return SR_EOS/SR_ERROR at some point). Note that calling this
- // function should not affect the existing state of data in the stream.
- virtual bool ReserveSize(size_t size);
-
//
// CONVENIENCE METHODS
//
// These methods are implemented in terms of other methods, for convenience.
//
- // Seek to the start of the stream.
- inline bool Rewind() { return SetPosition(0); }
-
// WriteAll is a helper function which repeatedly calls Write until all the
// data is written, or something other than SR_SUCCESS is returned. Note that
// unlike Write, the argument 'written' is always set, and may be non-zero
@@ -191,10 +168,6 @@
int* error) override;
void Close() override;
- bool SetPosition(size_t position) override;
- bool GetPosition(size_t* position) const override;
- bool GetSize(size_t* size) const override;
- bool ReserveSize(size_t size) override;
bool Flush() override;
void Attach(StreamInterface* stream, bool owned = true);
@@ -219,6 +192,7 @@
// support asynchronous notification.
///////////////////////////////////////////////////////////////////////////////
+// TODO(bugs.webrtc.org/6463): Delete this class.
class FileStream : public StreamInterface {
public:
FileStream();
@@ -245,10 +219,7 @@
size_t* written,
int* error) override;
void Close() override;
- bool SetPosition(size_t position) override;
- bool GetPosition(size_t* position) const override;
- bool GetSize(size_t* size) const override;
- bool ReserveSize(size_t size) override;
+ virtual bool SetPosition(size_t position);
bool Flush() override;
@@ -306,6 +277,19 @@
size_t* bytes_written,
int* error) override;
void Close() override;
+
+ // Seek to a byte offset from the beginning of the stream. Returns false if
+ // the stream does not support seeking, or cannot seek to the specified
+ // position.
+ bool SetPosition(size_t position);
+
+ // Get the byte offset of the current position from the start of the stream.
+ // Returns false if the position is not known.
+ bool GetPosition(size_t* position) const;
+
+ // Seek to the start of the stream.
+ bool Rewind() { return SetPosition(0); }
+
// GetReadData returns a pointer to a buffer which is owned by the stream.
// The buffer contains data_len bytes. null is returned if no data is
// available, or if the method fails. If the caller processes the data, it
diff --git a/rtc_base/stream_unittest.cc b/rtc_base/stream_unittest.cc
index 2ca2526..bd6e84f 100644
--- a/rtc_base/stream_unittest.cc
+++ b/rtc_base/stream_unittest.cc
@@ -9,7 +9,10 @@
*/
#include "rtc_base/stream.h"
-#include "rtc_base/gunit.h"
+
+#include <string.h>
+
+#include "test/gtest.h"
namespace rtc {
@@ -47,19 +50,6 @@
void Close() override {}
- bool SetPosition(size_t position) override {
- pos_ = position;
- return true;
- }
-
- bool GetPosition(size_t* position) const override {
- if (position)
- *position = pos_;
- return true;
- }
-
- bool GetSize(size_t* size) const override { return false; }
-
private:
size_t pos_;
};
@@ -77,26 +67,6 @@
return passed;
}
-void SeekTest(StreamInterface* stream, const unsigned char value) {
- size_t bytes;
- unsigned char buffer[13] = {0};
- const size_t kBufSize = sizeof(buffer);
-
- EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, nullptr), SR_SUCCESS);
- EXPECT_EQ(bytes, kBufSize);
- EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value));
- EXPECT_TRUE(stream->GetPosition(&bytes));
- EXPECT_EQ(13U, bytes);
-
- EXPECT_TRUE(stream->SetPosition(7));
-
- EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, nullptr), SR_SUCCESS);
- EXPECT_EQ(bytes, kBufSize);
- EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value + 7));
- EXPECT_TRUE(stream->GetPosition(&bytes));
- EXPECT_EQ(20U, bytes);
-}
-
TEST(FifoBufferTest, TestAll) {
const size_t kSize = 16;
const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
diff --git a/rtc_base/stringencode.cc b/rtc_base/string_encode.cc
similarity index 99%
rename from rtc_base/stringencode.cc
rename to rtc_base/string_encode.cc
index fc4e3bc..45ea586 100644
--- a/rtc_base/stringencode.cc
+++ b/rtc_base/string_encode.cc
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
#include <cstdio>
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
namespace rtc {
diff --git a/rtc_base/stringencode.h b/rtc_base/string_encode.h
similarity index 98%
rename from rtc_base/stringencode.h
rename to rtc_base/string_encode.h
index 09bf77f..d3338d9 100644
--- a/rtc_base/stringencode.h
+++ b/rtc_base/string_encode.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_STRINGENCODE_H_
-#define RTC_BASE_STRINGENCODE_H_
+#ifndef RTC_BASE_STRING_ENCODE_H_
+#define RTC_BASE_STRING_ENCODE_H_
#include <stddef.h>
#include <string>
@@ -197,4 +197,4 @@
} // namespace rtc
-#endif // RTC_BASE_STRINGENCODE_H__
+#endif // RTC_BASE_STRING_ENCODE_H__
diff --git a/rtc_base/stringencode_unittest.cc b/rtc_base/string_encode_unittest.cc
similarity index 98%
rename from rtc_base/stringencode_unittest.cc
rename to rtc_base/string_encode_unittest.cc
index f21c4cb..cc72e43 100644
--- a/rtc_base/stringencode_unittest.cc
+++ b/rtc_base/string_encode_unittest.cc
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/stringencode.h"
-#include "rtc_base/arraysize.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_encode.h"
+#include <string.h>
#include <sstream> // no-presubmit-check TODO(webrtc:8982)
+#include "test/gtest.h"
+
namespace rtc {
class HexEncodeTest : public testing::Test {
diff --git a/rtc_base/string_to_number_unittest.cc b/rtc_base/string_to_number_unittest.cc
index f7bf484..2c2dfcc 100644
--- a/rtc_base/string_to_number_unittest.cc
+++ b/rtc_base/string_to_number_unittest.cc
@@ -10,11 +10,11 @@
#include "rtc_base/string_to_number.h"
+#include <stdint.h>
#include <limits>
#include <string>
-#include <type_traits>
-#include "rtc_base/gunit.h"
+#include "test/gtest.h"
namespace rtc {
@@ -36,7 +36,7 @@
template <typename T>
class BasicNumberTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(BasicNumberTest);
+TYPED_TEST_SUITE_P(BasicNumberTest);
TYPED_TEST_P(BasicNumberTest, TestValidNumbers) {
using T = TypeParam;
@@ -93,16 +93,16 @@
EXPECT_EQ(absl::nullopt, StringToNumber<T>("5 "));
}
-REGISTER_TYPED_TEST_CASE_P(BasicNumberTest,
- TestValidNumbers,
- TestInvalidNumbers,
- TestInvalidInputs);
+REGISTER_TYPED_TEST_SUITE_P(BasicNumberTest,
+ TestValidNumbers,
+ TestInvalidNumbers,
+ TestInvalidInputs);
} // namespace
-INSTANTIATE_TYPED_TEST_CASE_P(StringToNumberTest_Integers,
- BasicNumberTest,
- IntegerTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(StringToNumberTest_Integers,
+ BasicNumberTest,
+ IntegerTypes);
TEST(StringToNumberTest, TestSpecificValues) {
EXPECT_EQ(absl::nullopt, StringToNumber<uint8_t>("256"));
diff --git a/rtc_base/stringutils.cc b/rtc_base/string_utils.cc
similarity index 65%
rename from rtc_base/stringutils.cc
rename to rtc_base/string_utils.cc
index c808eb2..dfbb548 100644
--- a/rtc_base/stringutils.cc
+++ b/rtc_base/string_utils.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
namespace rtc {
@@ -30,34 +30,6 @@
return srclen;
}
-void replace_substrs(const char* search,
- size_t search_len,
- const char* replace,
- size_t replace_len,
- std::string* s) {
- size_t pos = 0;
- while ((pos = s->find(search, pos, search_len)) != std::string::npos) {
- s->replace(pos, search_len, replace, replace_len);
- pos += replace_len;
- }
-}
-
-bool starts_with(const char* s1, const char* s2) {
- return strncmp(s1, s2, strlen(s2)) == 0;
-}
-
-bool ends_with(const char* s1, const char* s2) {
- size_t s1_length = strlen(s1);
- size_t s2_length = strlen(s2);
-
- if (s2_length > s1_length) {
- return false;
- }
-
- const char* start = s1 + (s1_length - s2_length);
- return strncmp(start, s2, s2_length) == 0;
-}
-
static const char kWhitespace[] = " \n\r\t";
std::string string_trim(const std::string& s) {
diff --git a/rtc_base/stringutils.h b/rtc_base/string_utils.h
similarity index 85%
rename from rtc_base/stringutils.h
rename to rtc_base/string_utils.h
index 702bc67..bc33284 100644
--- a/rtc_base/stringutils.h
+++ b/rtc_base/string_utils.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_STRINGUTILS_H_
-#define RTC_BASE_STRINGUTILS_H_
+#ifndef RTC_BASE_STRING_UTILS_H_
+#define RTC_BASE_STRING_UTILS_H_
#include <ctype.h>
#include <stdarg.h>
@@ -93,19 +93,6 @@
#endif // WEBRTC_WIN
-// Replaces all occurrences of "search" with "replace".
-void replace_substrs(const char* search,
- size_t search_len,
- const char* replace,
- size_t replace_len,
- std::string* s);
-
-// True iff s1 starts with s2.
-bool starts_with(const char* s1, const char* s2);
-
-// True iff s1 ends with s2.
-bool ends_with(const char* s1, const char* s2);
-
// Remove leading and trailing whitespaces.
std::string string_trim(const std::string& s);
@@ -116,4 +103,4 @@
} // namespace rtc
-#endif // RTC_BASE_STRINGUTILS_H_
+#endif // RTC_BASE_STRING_UTILS_H_
diff --git a/rtc_base/string_utils_unittest.cc b/rtc_base/string_utils_unittest.cc
new file mode 100644
index 0000000..b4396f1
--- /dev/null
+++ b/rtc_base/string_utils_unittest.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004 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 "rtc_base/string_utils.h"
+
+#include "test/gtest.h"
+
+namespace rtc {
+
+TEST(string_trim_Test, Trimming) {
+ EXPECT_EQ("temp", string_trim("\n\r\t temp \n\r\t"));
+ EXPECT_EQ("temp\n\r\t temp", string_trim(" temp\n\r\t temp "));
+ EXPECT_EQ("temp temp", string_trim("temp temp"));
+ EXPECT_EQ("", string_trim(" \r\n\t"));
+ EXPECT_EQ("", string_trim(""));
+}
+
+TEST(string_toHexTest, ToHex) {
+ EXPECT_EQ(ToHex(0), "0");
+ EXPECT_EQ(ToHex(0X1243E), "1243e");
+ EXPECT_EQ(ToHex(-20), "ffffffec");
+}
+
+} // namespace rtc
diff --git a/rtc_base/strings/json.cc b/rtc_base/strings/json.cc
index efcb97a..8a544a0 100644
--- a/rtc_base/strings/json.cc
+++ b/rtc_base/strings/json.cc
@@ -14,7 +14,7 @@
#include <limits.h>
#include <stdlib.h>
-#include "rtc_base/stringencode.h"
+#include "rtc_base/string_encode.h"
namespace rtc {
diff --git a/rtc_base/strings/json_unittest.cc b/rtc_base/strings/json_unittest.cc
index 2215769..82d26f1 100644
--- a/rtc_base/strings/json_unittest.cc
+++ b/rtc_base/strings/json_unittest.cc
@@ -12,7 +12,7 @@
#include <vector>
-#include "rtc_base/gunit.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/strings/string_builder.h b/rtc_base/strings/string_builder.h
index 27001d1..7c45ac4 100644
--- a/rtc_base/strings/string_builder.h
+++ b/rtc_base/strings/string_builder.h
@@ -17,8 +17,8 @@
#include "absl/strings/string_view.h"
#include "api/array_view.h"
-#include "rtc_base/stringencode.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/string_utils.h"
namespace rtc {
diff --git a/rtc_base/strings/string_builder_unittest.cc b/rtc_base/strings/string_builder_unittest.cc
index 878e128..6d8b9f2 100644
--- a/rtc_base/strings/string_builder_unittest.cc
+++ b/rtc_base/strings/string_builder_unittest.cc
@@ -10,8 +10,9 @@
#include "rtc_base/strings/string_builder.h"
+#include <string.h>
+
#include "rtc_base/checks.h"
-#include "rtc_base/stringutils.h"
#include "test/gmock.h"
#include "test/gtest.h"
diff --git a/rtc_base/stringutils_unittest.cc b/rtc_base/stringutils_unittest.cc
deleted file mode 100644
index 663e976..0000000
--- a/rtc_base/stringutils_unittest.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2004 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 "rtc_base/stringutils.h"
-#include "rtc_base/gunit.h"
-
-namespace rtc {
-
-TEST(string_trim_Test, Trimming) {
- EXPECT_EQ("temp", string_trim("\n\r\t temp \n\r\t"));
- EXPECT_EQ("temp\n\r\t temp", string_trim(" temp\n\r\t temp "));
- EXPECT_EQ("temp temp", string_trim("temp temp"));
- EXPECT_EQ("", string_trim(" \r\n\t"));
- EXPECT_EQ("", string_trim(""));
-}
-
-TEST(string_startsTest, StartsWith) {
- EXPECT_TRUE(starts_with("foobar", "foo"));
- EXPECT_TRUE(starts_with("foobar", "foobar"));
- EXPECT_TRUE(starts_with("foobar", ""));
- EXPECT_TRUE(starts_with("", ""));
- EXPECT_FALSE(starts_with("foobar", "bar"));
- EXPECT_FALSE(starts_with("foobar", "foobarbaz"));
- EXPECT_FALSE(starts_with("", "f"));
-}
-
-TEST(string_endsTest, EndsWith) {
- EXPECT_TRUE(ends_with("foobar", "bar"));
- EXPECT_TRUE(ends_with("foobar", "foobar"));
- EXPECT_TRUE(ends_with("foobar", ""));
- EXPECT_TRUE(ends_with("", ""));
- EXPECT_FALSE(ends_with("foobar", "foo"));
- EXPECT_FALSE(ends_with("foobar", "foobarbaz"));
- EXPECT_FALSE(ends_with("", "f"));
-}
-
-TEST(string_toHexTest, ToHex) {
- EXPECT_EQ(ToHex(0), "0");
- EXPECT_EQ(ToHex(0X1243E), "1243e");
- EXPECT_EQ(ToHex(-20), "ffffffec");
-}
-
-} // namespace rtc
diff --git a/rtc_base/swap_queue.h b/rtc_base/swap_queue.h
index 172f2f5..c3246db 100644
--- a/rtc_base/swap_queue.h
+++ b/rtc_base/swap_queue.h
@@ -11,14 +11,15 @@
#ifndef RTC_BASE_SWAP_QUEUE_H_
#define RTC_BASE_SWAP_QUEUE_H_
-#include <algorithm>
+#include <stddef.h>
#include <utility>
#include <vector>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/system/unused.h"
+#include "rtc_base/thread_annotations.h"
namespace webrtc {
diff --git a/rtc_base/swap_queue_unittest.cc b/rtc_base/swap_queue_unittest.cc
index 28f870b..199ac6b 100644
--- a/rtc_base/swap_queue_unittest.cc
+++ b/rtc_base/swap_queue_unittest.cc
@@ -10,6 +10,7 @@
#include "rtc_base/swap_queue.h"
+#include <cstdint>
#include <vector>
#include "test/gtest.h"
diff --git a/rtc_base/system/BUILD.gn b/rtc_base/system/BUILD.gn
index e5aa32b..8b83d04 100644
--- a/rtc_base/system/BUILD.gn
+++ b/rtc_base/system/BUILD.gn
@@ -75,5 +75,6 @@
deps = [
"..:checks",
]
+ libs = [ "Foundation.framework" ]
}
}
diff --git a/rtc_base/system/file_wrapper.cc b/rtc_base/system/file_wrapper.cc
index c033a79..9d99cef 100644
--- a/rtc_base/system/file_wrapper.cc
+++ b/rtc_base/system/file_wrapper.cc
@@ -10,6 +10,8 @@
#include "rtc_base/system/file_wrapper.h"
+#include <cerrno>
+
#ifdef _WIN32
#include <Windows.h>
#else
@@ -20,7 +22,7 @@
namespace webrtc {
namespace {
-FILE* FileOpen(const char* file_name_utf8, bool read_only) {
+FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) {
#if defined(_WIN32)
int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0);
std::wstring wstr(len, 0);
@@ -29,27 +31,40 @@
#else
FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb");
#endif
+ if (!file && error) {
+ *error = errno;
+ }
return file;
}
+
+const char* GetCstrCheckNoEmbeddedNul(const std::string& s) {
+ const char* p = s.c_str();
+ RTC_CHECK_EQ(strlen(p), s.size())
+ << "Invalid filename, containing NUL character";
+ return p;
+}
} // namespace
// static
-FileWrapper* FileWrapper::Create() {
- return new FileWrapper();
+FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) {
+ return FileWrapper(FileOpen(file_name_utf8, true, nullptr));
}
// static
-FileWrapper FileWrapper::Open(const char* file_name_utf8, bool read_only) {
- return FileWrapper(FileOpen(file_name_utf8, read_only), 0);
+FileWrapper FileWrapper::OpenReadOnly(const std::string& file_name_utf8) {
+ return OpenReadOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8));
}
-FileWrapper::FileWrapper() {}
+// static
+FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8,
+ int* error /*=nullptr*/) {
+ return FileWrapper(FileOpen(file_name_utf8, false, error));
+}
-FileWrapper::FileWrapper(FILE* file, size_t max_size)
- : file_(file), max_size_in_bytes_(max_size) {}
-
-FileWrapper::~FileWrapper() {
- CloseFileImpl();
+// static
+FileWrapper FileWrapper::OpenWriteOnly(const std::string& file_name_utf8,
+ int* error /*=nullptr*/) {
+ return OpenWriteOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8), error);
}
FileWrapper::FileWrapper(FileWrapper&& other) {
@@ -57,95 +72,39 @@
}
FileWrapper& FileWrapper::operator=(FileWrapper&& other) {
+ Close();
file_ = other.file_;
- max_size_in_bytes_ = other.max_size_in_bytes_;
- position_ = other.position_;
other.file_ = nullptr;
return *this;
}
-void FileWrapper::CloseFile() {
- rtc::CritScope lock(&lock_);
- CloseFileImpl();
+bool FileWrapper::Rewind() {
+ RTC_DCHECK(file_);
+ return fseek(file_, 0, SEEK_SET) == 0;
}
-int FileWrapper::Rewind() {
- rtc::CritScope lock(&lock_);
- if (file_ != nullptr) {
- position_ = 0;
- return fseek(file_, 0, SEEK_SET);
- }
- return -1;
+bool FileWrapper::Flush() {
+ RTC_DCHECK(file_);
+ return fflush(file_) == 0;
}
-void FileWrapper::SetMaxFileSize(size_t bytes) {
- rtc::CritScope lock(&lock_);
- max_size_in_bytes_ = bytes;
-}
-
-int FileWrapper::Flush() {
- rtc::CritScope lock(&lock_);
- return FlushImpl();
-}
-
-bool FileWrapper::OpenFile(const char* file_name_utf8, bool read_only) {
- size_t length = strlen(file_name_utf8);
- if (length > kMaxFileNameSize - 1)
- return false;
-
- rtc::CritScope lock(&lock_);
- if (file_ != nullptr)
- return false;
-
- file_ = FileOpen(file_name_utf8, read_only);
- return file_ != nullptr;
-}
-
-bool FileWrapper::OpenFromFileHandle(FILE* handle) {
- if (!handle)
- return false;
- rtc::CritScope lock(&lock_);
- CloseFileImpl();
- file_ = handle;
- return true;
-}
-
-int FileWrapper::Read(void* buf, size_t length) {
- rtc::CritScope lock(&lock_);
- if (file_ == nullptr)
- return -1;
-
- size_t bytes_read = fread(buf, 1, length, file_);
- return static_cast<int>(bytes_read);
+size_t FileWrapper::Read(void* buf, size_t length) {
+ RTC_DCHECK(file_);
+ return fread(buf, 1, length, file_);
}
bool FileWrapper::Write(const void* buf, size_t length) {
- if (buf == nullptr)
- return false;
+ RTC_DCHECK(file_);
+ return fwrite(buf, 1, length, file_) == length;
+}
- rtc::CritScope lock(&lock_);
-
+bool FileWrapper::Close() {
if (file_ == nullptr)
- return false;
+ return true;
- // Check if it's time to stop writing.
- if (max_size_in_bytes_ > 0 && (position_ + length) > max_size_in_bytes_)
- return false;
-
- size_t num_bytes = fwrite(buf, 1, length, file_);
- position_ += num_bytes;
-
- return num_bytes == length;
-}
-
-void FileWrapper::CloseFileImpl() {
- if (file_ != nullptr)
- fclose(file_);
+ bool success = fclose(file_) == 0;
file_ = nullptr;
-}
-
-int FileWrapper::FlushImpl() {
- return (file_ != nullptr) ? fflush(file_) : -1;
+ return success;
}
} // namespace webrtc
diff --git a/rtc_base/system/file_wrapper.h b/rtc_base/system/file_wrapper.h
index 0bb86a3..4f5d511 100644
--- a/rtc_base/system/file_wrapper.h
+++ b/rtc_base/system/file_wrapper.h
@@ -14,70 +14,75 @@
#include <stddef.h>
#include <stdio.h>
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
// Implementation that can read (exclusive) or write from/to a file.
namespace webrtc {
-// TODO(tommi): Rename to rtc::File and move to base.
+// This class is a thin wrapper around FILE*. It's main features are that it
+// owns the FILE*, calling fclose on destruction, and that on windows, file
+// names passed to the open methods are always treated as utf-8, regardless of
+// system code page.
+
+// Most of the methods return only a success/fail indication. When needed, an
+// optional argument |int* error| should be added to all methods, in the same
+// way as for the OpenWriteOnly methods.
class FileWrapper final {
public:
- static const size_t kMaxFileNameSize = 1024;
+ // Opens a file, in read or write mode. Use the is_open() method on the
+ // returned object to check if the open operation was successful. On failure,
+ // and if |error| is non-null, the system errno value is stored at |*error|.
+ // The file is closed by the destructor.
+ static FileWrapper OpenReadOnly(const char* file_name_utf8);
+ static FileWrapper OpenReadOnly(const std::string& file_name_utf8);
+ static FileWrapper OpenWriteOnly(const char* file_name_utf8,
+ int* error = nullptr);
- // Factory methods.
- // TODO(tommi): Remove Create().
- static FileWrapper* Create();
- static FileWrapper Open(const char* file_name_utf8, bool read_only);
+ static FileWrapper OpenWriteOnly(const std::string& file_name_utf8,
+ int* error = nullptr);
- FileWrapper(FILE* file, size_t max_size);
- ~FileWrapper();
+ FileWrapper() = default;
- // Support for move semantics.
- FileWrapper(FileWrapper&& other);
- FileWrapper& operator=(FileWrapper&& other);
-
- // Returns true if a file has been opened.
- bool is_open() const { return file_ != nullptr; }
-
- // Opens a file in read or write mode, decided by the read_only parameter.
- bool OpenFile(const char* file_name_utf8, bool read_only);
-
- // Initializes the wrapper from an existing handle. The wrapper
- // takes ownership of |handle| and closes it in CloseFile().
- bool OpenFromFileHandle(FILE* handle);
-
- void CloseFile();
-
- // Limits the file size to |bytes|. Writing will fail after the cap
- // is hit. Pass zero to use an unlimited size.
- // TODO(tommi): Could we move this out into a separate class?
- void SetMaxFileSize(size_t bytes);
-
- // Flush any pending writes. Note: Flushing when closing, is not required.
- int Flush();
-
- // Rewinds the file to the start.
- int Rewind();
- int Read(void* buf, size_t length);
- bool Write(const void* buf, size_t length);
-
- private:
- FileWrapper();
-
- void CloseFileImpl();
- int FlushImpl();
-
- // TODO(tommi): Remove the lock.
- rtc::CriticalSection lock_;
-
- FILE* file_ = nullptr;
- size_t position_ = 0;
- size_t max_size_in_bytes_ = 0;
+ // Takes over ownership of |file|, closing it on destruction.
+ explicit FileWrapper(FILE* file) : file_(file) {}
+ ~FileWrapper() { Close(); }
// Copying is not supported.
FileWrapper(const FileWrapper&) = delete;
FileWrapper& operator=(const FileWrapper&) = delete;
+
+ // Support for move semantics.
+ FileWrapper(FileWrapper&&);
+ FileWrapper& operator=(FileWrapper&&);
+
+ // Returns true if a file has been opened. If the file is not open, no methods
+ // but is_open and Close may be called.
+ bool is_open() const { return file_ != nullptr; }
+
+ // Closes the file, and implies Flush. Returns true on success, false if
+ // writing buffered data fails. On failure, the file is nevertheless closed.
+ // Calling Close on an already closed file does nothing and returns success.
+ bool Close();
+
+ // Write any buffered data to the underlying file. Returns true on success,
+ // false on write error. Note: Flushing when closing, is not required.
+ bool Flush();
+
+ // Seeks to the beginning of file. Returns true on success, false on failure,
+ // e.g., if the underlying file isn't seekable.
+ bool Rewind();
+
+ // Returns number of bytes read. Short count indicates EOF or error.
+ size_t Read(void* buf, size_t length);
+
+ // Returns true if all data was successfully written (or buffered), or false
+ // if there was an error. Writing buffered data can fail later, and is
+ // reported with return value from Flush or Close.
+ bool Write(const void* buf, size_t length);
+
+ private:
+ FILE* file_ = nullptr;
};
} // namespace webrtc
diff --git a/rtc_base/task_queue.cc b/rtc_base/task_queue.cc
new file mode 100644
index 0000000..ed489eb
--- /dev/null
+++ b/rtc_base/task_queue.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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 "rtc_base/task_queue.h"
+
+#include "api/task_queue/global_task_queue_factory.h"
+#include "api/task_queue/task_queue_base.h"
+
+namespace rtc {
+
+TaskQueue::TaskQueue(
+ std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> task_queue)
+ : impl_(task_queue.release()) {
+ impl_->task_queue_ = this;
+}
+
+TaskQueue::TaskQueue(const char* queue_name, Priority priority)
+ : TaskQueue(webrtc::GlobalTaskQueueFactory().CreateTaskQueue(queue_name,
+ priority)) {}
+
+TaskQueue::~TaskQueue() {
+ // There might running task that tries to rescheduler itself to the TaskQueue
+ // and not yet aware TaskQueue destructor is called.
+ // Calling back to TaskQueue::PostTask need impl_ pointer still be valid, so
+ // do not invalidate impl_ pointer until Delete returns.
+ impl_->Delete();
+}
+
+// static
+TaskQueue* TaskQueue::Current() {
+ webrtc::TaskQueueBase* impl = webrtc::TaskQueueBase::Current();
+ if (impl == nullptr) {
+ return nullptr;
+ }
+ return impl->task_queue_;
+}
+
+bool TaskQueue::IsCurrent() const {
+ return Current() == this;
+}
+
+void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
+ return impl_->PostTask(std::move(task));
+}
+
+void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) {
+ return impl_->PostDelayedTask(std::move(task), milliseconds);
+}
+
+} // namespace rtc
diff --git a/rtc_base/task_queue.h b/rtc_base/task_queue.h
index 888e203..1c0ae29 100644
--- a/rtc_base/task_queue.h
+++ b/rtc_base/task_queue.h
@@ -11,85 +11,24 @@
#ifndef RTC_BASE_TASK_QUEUE_H_
#define RTC_BASE_TASK_QUEUE_H_
+#include <stdint.h>
#include <memory>
-#include <type_traits>
#include <utility>
#include "absl/memory/memory.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/task_queue/queued_task.h"
+#include "api/task_queue/task_queue_base.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/system/rtc_export.h"
+#include "rtc_base/task_utils/to_queued_task.h"
#include "rtc_base/thread_annotations.h"
namespace rtc {
-// Base interface for asynchronously executed tasks.
-// The interface basically consists of a single function, Run(), that executes
-// on the target queue. For more details see the Run() method and TaskQueue.
-class QueuedTask {
- public:
- QueuedTask() {}
- virtual ~QueuedTask() {}
-
- // Main routine that will run when the task is executed on the desired queue.
- // The task should return |true| to indicate that it should be deleted or
- // |false| to indicate that the queue should consider ownership of the task
- // having been transferred. Returning |false| can be useful if a task has
- // re-posted itself to a different queue or is otherwise being re-used.
- virtual bool Run() = 0;
-
- private:
- RTC_DISALLOW_COPY_AND_ASSIGN(QueuedTask);
-};
-
-// Simple implementation of QueuedTask for use with rtc::Bind and lambdas.
-template <class Closure>
-class ClosureTask : public QueuedTask {
- public:
- explicit ClosureTask(Closure&& closure)
- : closure_(std::forward<Closure>(closure)) {}
-
- private:
- bool Run() override {
- closure_();
- return true;
- }
-
- typename std::remove_const<
- typename std::remove_reference<Closure>::type>::type closure_;
-};
-
-// Extends ClosureTask to also allow specifying cleanup code.
-// This is useful when using lambdas if guaranteeing cleanup, even if a task
-// was dropped (queue is too full), is required.
-template <class Closure, class Cleanup>
-class ClosureTaskWithCleanup : public ClosureTask<Closure> {
- public:
- ClosureTaskWithCleanup(Closure&& closure, Cleanup&& cleanup)
- : ClosureTask<Closure>(std::forward<Closure>(closure)),
- cleanup_(std::forward<Cleanup>(cleanup)) {}
- ~ClosureTaskWithCleanup() { cleanup_(); }
-
- private:
- typename std::remove_const<
- typename std::remove_reference<Cleanup>::type>::type cleanup_;
-};
-
-// Convenience function to construct closures that can be passed directly
-// to methods that support std::unique_ptr<QueuedTask> but not template
-// based parameters.
-template <class Closure>
-static std::unique_ptr<QueuedTask> NewClosure(Closure&& closure) {
- return absl::make_unique<ClosureTask<Closure>>(
- std::forward<Closure>(closure));
-}
-
-template <class Closure, class Cleanup>
-static std::unique_ptr<QueuedTask> NewClosure(Closure&& closure,
- Cleanup&& cleanup) {
- return absl::make_unique<ClosureTaskWithCleanup<Closure, Cleanup>>(
- std::forward<Closure>(closure), std::forward<Cleanup>(cleanup));
-}
+// TODO(danilchap): Remove the alias when all of webrtc is updated to use
+// webrtc::QueuedTask directly.
+using ::webrtc::QueuedTask;
// Implements a task queue that asynchronously executes tasks in a way that
// guarantees that they're executed in FIFO order and that tasks never overlap.
@@ -109,19 +48,7 @@
// queue_.PostTask([]() { Work(); });
// ...
//
-// 2) Doing work asynchronously on a worker queue and providing a notification
-// callback on the current queue, when the work has been done:
-//
-// void MyClass::StartWorkAndLetMeKnowWhenDone(
-// std::unique_ptr<QueuedTask> callback) {
-// DCHECK(TaskQueue::Current()) << "Need to be running on a queue";
-// queue_.PostTaskAndReply([]() { Work(); }, std::move(callback));
-// }
-// ...
-// my_class->StartWorkAndLetMeKnowWhenDone(
-// NewClosure([]() { RTC_LOG(INFO) << "The work is done!";}));
-//
-// 3) Posting a custom task on a timer. The task posts itself again after
+// 2) Posting a custom task on a timer. The task posts itself again after
// every running:
//
// class TimerTask : public QueuedTask {
@@ -155,12 +82,10 @@
public:
// TaskQueue priority levels. On some platforms these will map to thread
// priorities, on others such as Mac and iOS, GCD queue priorities.
- enum class Priority {
- NORMAL = 0,
- HIGH,
- LOW,
- };
+ using Priority = ::webrtc::TaskQueueFactory::Priority;
+ explicit TaskQueue(std::unique_ptr<webrtc::TaskQueueBase,
+ webrtc::TaskQueueDeleter> task_queue);
explicit TaskQueue(const char* queue_name,
Priority priority = Priority::NORMAL);
~TaskQueue();
@@ -170,15 +95,13 @@
// Used for DCHECKing the current queue.
bool IsCurrent() const;
+ // Returns non-owning pointer to the task queue implementation.
+ webrtc::TaskQueueBase* Get() { return impl_; }
+
// TODO(tommi): For better debuggability, implement RTC_FROM_HERE.
// Ownership of the task is passed to PostTask.
void PostTask(std::unique_ptr<QueuedTask> task);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue* reply_queue);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply);
// Schedules a task to execute a specified number of milliseconds from when
// the call is made. The precision should be considered as "best effort"
@@ -195,7 +118,7 @@
Closure,
std::unique_ptr<QueuedTask>>::value>::type* = nullptr>
void PostTask(Closure&& closure) {
- PostTask(NewClosure(std::forward<Closure>(closure)));
+ PostTask(webrtc::ToQueuedTask(std::forward<Closure>(closure)));
}
// See documentation above for performance expectations.
@@ -204,36 +127,12 @@
Closure,
std::unique_ptr<QueuedTask>>::value>::type* = nullptr>
void PostDelayedTask(Closure&& closure, uint32_t milliseconds) {
- PostDelayedTask(NewClosure(std::forward<Closure>(closure)), milliseconds);
- }
-
- template <class Closure1, class Closure2>
- void PostTaskAndReply(Closure1&& task,
- Closure2&& reply,
- TaskQueue* reply_queue) {
- PostTaskAndReply(NewClosure(std::forward<Closure1>(task)),
- NewClosure(std::forward<Closure2>(reply)), reply_queue);
- }
-
- template <class Closure>
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task, Closure&& reply) {
- PostTaskAndReply(std::move(task), NewClosure(std::forward<Closure>(reply)));
- }
-
- template <class Closure>
- void PostTaskAndReply(Closure&& task, std::unique_ptr<QueuedTask> reply) {
- PostTaskAndReply(NewClosure(std::forward<Closure>(task)), std::move(reply));
- }
-
- template <class Closure1, class Closure2>
- void PostTaskAndReply(Closure1&& task, Closure2&& reply) {
- PostTaskAndReply(NewClosure(std::forward(task)),
- NewClosure(std::forward(reply)));
+ PostDelayedTask(webrtc::ToQueuedTask(std::forward<Closure>(closure)),
+ milliseconds);
}
private:
- class Impl;
- const scoped_refptr<Impl> impl_;
+ webrtc::TaskQueueBase* const impl_;
RTC_DISALLOW_COPY_AND_ASSIGN(TaskQueue);
};
diff --git a/rtc_base/task_queue_for_test.h b/rtc_base/task_queue_for_test.h
index 9162e81..0becc80 100644
--- a/rtc_base/task_queue_for_test.h
+++ b/rtc_base/task_queue_for_test.h
@@ -11,11 +11,12 @@
#ifndef RTC_BASE_TASK_QUEUE_FOR_TEST_H_
#define RTC_BASE_TASK_QUEUE_FOR_TEST_H_
-#include <utility>
-
#include "rtc_base/checks.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "rtc_base/thread_annotations.h"
namespace rtc {
namespace test {
@@ -34,7 +35,7 @@
void SendTask(Closure* task) {
RTC_DCHECK(!IsCurrent());
rtc::Event event;
- PostTask(rtc::NewClosure(
+ PostTask(webrtc::ToQueuedTask(
[&task]() {
RTC_CHECK_EQ(false, static_cast<QueuedTask*>(task)->Run());
},
@@ -48,7 +49,8 @@
void SendTask(Closure&& task) {
RTC_DCHECK(!IsCurrent());
rtc::Event event;
- PostTask(rtc::NewClosure(std::move(task), [&event]() { event.Set(); }));
+ PostTask(webrtc::ToQueuedTask(std::forward<Closure>(task),
+ [&event] { event.Set(); }));
event.Wait(rtc::Event::kForever);
}
diff --git a/rtc_base/task_queue_gcd.cc b/rtc_base/task_queue_gcd.cc
index c7731dd..c131d82 100644
--- a/rtc_base/task_queue_gcd.cc
+++ b/rtc_base/task_queue_gcd.cc
@@ -12,231 +12,142 @@
// The implementation uses Grand Central Dispatch queues (GCD) to
// do the actual task queuing.
-#include "rtc_base/task_queue.h"
+#include "rtc_base/task_queue_gcd.h"
#include <string.h>
#include <dispatch/dispatch.h>
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/task_queue/queued_task.h"
+#include "api/task_queue/task_queue_base.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/task_queue_posix.h"
-namespace rtc {
+namespace webrtc {
namespace {
-using Priority = TaskQueue::Priority;
-
-int TaskQueuePriorityToGCD(Priority priority) {
+int TaskQueuePriorityToGCD(TaskQueueFactory::Priority priority) {
switch (priority) {
- case Priority::NORMAL:
+ case TaskQueueFactory::Priority::NORMAL:
return DISPATCH_QUEUE_PRIORITY_DEFAULT;
- case Priority::HIGH:
+ case TaskQueueFactory::Priority::HIGH:
return DISPATCH_QUEUE_PRIORITY_HIGH;
- case Priority::LOW:
+ case TaskQueueFactory::Priority::LOW:
return DISPATCH_QUEUE_PRIORITY_LOW;
}
}
-} // namespace
-using internal::GetQueuePtrTls;
-using internal::AutoSetCurrentQueuePtr;
-
-class TaskQueue::Impl : public RefCountInterface {
+class TaskQueueGcd : public TaskQueueBase {
public:
- Impl(const char* queue_name, TaskQueue* task_queue, Priority priority);
- ~Impl() override;
+ TaskQueueGcd(absl::string_view queue_name, int gcd_priority);
- static TaskQueue* Current();
-
- // Used for DCHECKing the current queue.
- bool IsCurrent() const;
-
- void PostTask(std::unique_ptr<QueuedTask> task);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue);
-
- void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds);
+ void Delete() override;
+ void PostTask(std::unique_ptr<QueuedTask> task) override;
+ void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) override;
private:
- struct QueueContext {
- explicit QueueContext(TaskQueue* q) : queue(q), is_active(true) {}
-
- static void SetNotActive(void* context) {
- QueueContext* qc = static_cast<QueueContext*>(context);
- qc->is_active = false;
- }
-
- static void DeleteContext(void* context) {
- QueueContext* qc = static_cast<QueueContext*>(context);
- delete qc;
- }
-
- TaskQueue* const queue;
- bool is_active;
- };
-
struct TaskContext {
- TaskContext(QueueContext* queue_ctx, std::unique_ptr<QueuedTask> task)
- : queue_ctx(queue_ctx), task(std::move(task)) {}
- virtual ~TaskContext() {}
+ TaskContext(TaskQueueGcd* queue, std::unique_ptr<QueuedTask> task)
+ : queue(queue), task(std::move(task)) {}
- static void RunTask(void* context) {
- std::unique_ptr<TaskContext> tc(static_cast<TaskContext*>(context));
- if (tc->queue_ctx->is_active) {
- AutoSetCurrentQueuePtr set_current(tc->queue_ctx->queue);
- if (!tc->task->Run())
- tc->task.release();
- }
- }
-
- QueueContext* const queue_ctx;
+ TaskQueueGcd* const queue;
std::unique_ptr<QueuedTask> task;
};
- // Special case context for holding two tasks, a |first_task| + the task
- // that's owned by the parent struct, TaskContext, that then becomes the
- // second (i.e. 'reply') task.
- struct PostTaskAndReplyContext : public TaskContext {
- explicit PostTaskAndReplyContext(QueueContext* first_queue_ctx,
- std::unique_ptr<QueuedTask> first_task,
- QueueContext* second_queue_ctx,
- std::unique_ptr<QueuedTask> second_task)
- : TaskContext(second_queue_ctx, std::move(second_task)),
- first_queue_ctx(first_queue_ctx),
- first_task(std::move(first_task)),
- reply_queue_(second_queue_ctx->queue->impl_->queue_) {
- // Retain the reply queue for as long as this object lives.
- // If we don't, we may have memory leaks and/or failures.
- dispatch_retain(reply_queue_);
- }
- ~PostTaskAndReplyContext() override { dispatch_release(reply_queue_); }
-
- static void RunTask(void* context) {
- auto* rc = static_cast<PostTaskAndReplyContext*>(context);
- if (rc->first_queue_ctx->is_active) {
- AutoSetCurrentQueuePtr set_current(rc->first_queue_ctx->queue);
- if (!rc->first_task->Run())
- rc->first_task.release();
- }
- // Post the reply task. This hands the work over to the parent struct.
- // This task will eventually delete |this|.
- dispatch_async_f(rc->reply_queue_, rc, &TaskContext::RunTask);
- }
-
- QueueContext* const first_queue_ctx;
- std::unique_ptr<QueuedTask> first_task;
- dispatch_queue_t reply_queue_;
- };
+ ~TaskQueueGcd() override;
+ static void RunTask(void* task_context);
+ static void SetNotActive(void* task_queue);
+ static void DeleteQueue(void* task_queue);
dispatch_queue_t queue_;
- QueueContext* const context_;
+ bool is_active_;
};
-TaskQueue::Impl::Impl(const char* queue_name,
- TaskQueue* task_queue,
- Priority priority)
- : queue_(dispatch_queue_create(queue_name, DISPATCH_QUEUE_SERIAL)),
- context_(new QueueContext(task_queue)) {
- RTC_DCHECK(queue_name);
+TaskQueueGcd::TaskQueueGcd(absl::string_view queue_name, int gcd_priority)
+ : queue_(dispatch_queue_create(std::string(queue_name).c_str(),
+ DISPATCH_QUEUE_SERIAL)),
+ is_active_(true) {
RTC_CHECK(queue_);
- dispatch_set_context(queue_, context_);
- // Assign a finalizer that will delete the context when the last reference
- // to the queue is released. This may run after the TaskQueue object has
- // been deleted.
- dispatch_set_finalizer_f(queue_, &QueueContext::DeleteContext);
+ dispatch_set_context(queue_, this);
+ // Assign a finalizer that will delete the queue when the last reference
+ // is released. This may run after the TaskQueue::Delete.
+ dispatch_set_finalizer_f(queue_, &DeleteQueue);
- dispatch_set_target_queue(
- queue_, dispatch_get_global_queue(TaskQueuePriorityToGCD(priority), 0));
+ dispatch_set_target_queue(queue_, dispatch_get_global_queue(gcd_priority, 0));
}
-TaskQueue::Impl::~Impl() {
+TaskQueueGcd::~TaskQueueGcd() = default;
+
+void TaskQueueGcd::Delete() {
RTC_DCHECK(!IsCurrent());
// Implementation/behavioral note:
// Dispatch queues are reference counted via calls to dispatch_retain and
// dispatch_release. Pending blocks submitted to a queue also hold a
// reference to the queue until they have finished. Once all references to a
// queue have been released, the queue will be deallocated by the system.
- // This is why we check the context before running tasks.
+ // This is why we check the is_active_ before running tasks.
- // Use dispatch_sync to set the context to null to guarantee that there's not
- // a race between checking the context and using it from a task.
- dispatch_sync_f(queue_, context_, &QueueContext::SetNotActive);
+ // Use dispatch_sync to set the is_active_ to guarantee that there's not a
+ // race with checking it from a task.
+ dispatch_sync_f(queue_, this, &SetNotActive);
dispatch_release(queue_);
}
-// static
-TaskQueue* TaskQueue::Impl::Current() {
- return static_cast<TaskQueue*>(pthread_getspecific(GetQueuePtrTls()));
+void TaskQueueGcd::PostTask(std::unique_ptr<QueuedTask> task) {
+ auto* context = new TaskContext(this, std::move(task));
+ dispatch_async_f(queue_, context, &RunTask);
}
-bool TaskQueue::Impl::IsCurrent() const {
- RTC_DCHECK(queue_);
- const TaskQueue* current = Current();
- return current && this == current->impl_.get();
-}
-
-void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) {
- auto* context = new TaskContext(context_, std::move(task));
- dispatch_async_f(queue_, context, &TaskContext::RunTask);
-}
-
-void TaskQueue::Impl::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
- auto* context = new TaskContext(context_, std::move(task));
+void TaskQueueGcd::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) {
+ auto* context = new TaskContext(this, std::move(task));
dispatch_after_f(
dispatch_time(DISPATCH_TIME_NOW, milliseconds * NSEC_PER_MSEC), queue_,
- context, &TaskContext::RunTask);
+ context, &RunTask);
}
-void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue) {
- auto* context = new PostTaskAndReplyContext(
- context_, std::move(task), reply_queue->context_, std::move(reply));
- dispatch_async_f(queue_, context, &PostTaskAndReplyContext::RunTask);
-}
-
-// Boilerplate for the PIMPL pattern.
-TaskQueue::TaskQueue(const char* queue_name, Priority priority)
- : impl_(new RefCountedObject<TaskQueue::Impl>(queue_name, this, priority)) {
-}
-
-TaskQueue::~TaskQueue() {}
-
// static
-TaskQueue* TaskQueue::Current() {
- return TaskQueue::Impl::Current();
+void TaskQueueGcd::RunTask(void* task_context) {
+ std::unique_ptr<TaskContext> tc(static_cast<TaskContext*>(task_context));
+ if (!tc->queue->is_active_)
+ return;
+
+ CurrentTaskQueueSetter set_current(tc->queue);
+ auto* task = tc->task.release();
+ if (task->Run()) {
+ // Delete the task before CurrentTaskQueueSetter clears state that this code
+ // is running on the task queue.
+ delete task;
+ }
}
-// Used for DCHECKing the current queue.
-bool TaskQueue::IsCurrent() const {
- return impl_->IsCurrent();
+// static
+void TaskQueueGcd::SetNotActive(void* task_queue) {
+ static_cast<TaskQueueGcd*>(task_queue)->is_active_ = false;
}
-void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
- return TaskQueue::impl_->PostTask(std::move(task));
+// static
+void TaskQueueGcd::DeleteQueue(void* task_queue) {
+ delete static_cast<TaskQueueGcd*>(task_queue);
}
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue* reply_queue) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- reply_queue->impl_.get());
+class TaskQueueGcdFactory final : public TaskQueueFactory {
+ public:
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const override {
+ return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
+ new TaskQueueGcd(name, TaskQueuePriorityToGCD(priority)));
+ }
+};
+
+} // namespace
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory() {
+ return absl::make_unique<TaskQueueGcdFactory>();
}
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- impl_.get());
-}
-
-void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
- return TaskQueue::impl_->PostDelayedTask(std::move(task), milliseconds);
-}
-
-} // namespace rtc
+} // namespace webrtc
diff --git a/rtc_base/task_queue_gcd.h b/rtc_base/task_queue_gcd.h
new file mode 100644
index 0000000..dc6039e
--- /dev/null
+++ b/rtc_base/task_queue_gcd.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_QUEUE_GCD_H_
+#define RTC_BASE_TASK_QUEUE_GCD_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory();
+
+} // namespace webrtc
+
+#endif // RTC_BASE_TASK_QUEUE_GCD_H_
diff --git a/rtc_base/task_queue_libevent.cc b/rtc_base/task_queue_libevent.cc
index 7588569..7d93267 100644
--- a/rtc_base/task_queue_libevent.cc
+++ b/rtc_base/task_queue_libevent.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/task_queue.h"
+#include "rtc_base/task_queue_libevent.h"
#include <errno.h>
#include <fcntl.h>
@@ -22,38 +22,32 @@
#include <type_traits>
#include <utility>
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/task_queue/queued_task.h"
+#include "api/task_queue/task_queue_base.h"
#include <event.h>
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/platform_thread_types.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
-#include "rtc_base/system/unused.h"
-#include "rtc_base/task_queue_posix.h"
#include "rtc_base/thread_annotations.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
-namespace rtc {
-using internal::GetQueuePtrTls;
-using internal::AutoSetCurrentQueuePtr;
-
+namespace webrtc {
namespace {
-static const char kQuit = 1;
-static const char kRunTask = 2;
-static const char kRunReplyTask = 3;
+constexpr char kQuit = 1;
+constexpr char kRunTask = 2;
-using Priority = TaskQueue::Priority;
+using Priority = TaskQueueFactory::Priority;
// This ignores the SIGPIPE signal on the calling thread.
// This signal can be fired when trying to write() to a pipe that's being
// closed or while closing a pipe that's being written to.
-// We can run into that situation (e.g. reply tasks that don't get a chance to
-// run because the task queue is being deleted) so we ignore this signal and
-// continue as normal.
+// We can run into that situation so we ignore this signal and continue as
+// normal.
// As a side note for this implementation, it would be great if we could safely
// restore the sigmask, but unfortunately the operation of restoring it, can
// itself actually cause SIGPIPE to be signaled :-| (e.g. on MacOS)
@@ -69,14 +63,6 @@
pthread_sigmask(SIG_BLOCK, &sigpipe_mask, nullptr);
}
-struct TimerEvent {
- explicit TimerEvent(std::unique_ptr<QueuedTask> task)
- : task(std::move(task)) {}
- ~TimerEvent() { event_del(&ev); }
- event ev;
- std::unique_ptr<QueuedTask> task;
-};
-
bool SetNonBlocking(int fd) {
const int flags = fcntl(fd, F_GETFL);
RTC_CHECK(flags != -1);
@@ -103,174 +89,76 @@
#endif
}
-ThreadPriority TaskQueuePriorityToThreadPriority(Priority priority) {
+rtc::ThreadPriority TaskQueuePriorityToThreadPriority(Priority priority) {
switch (priority) {
case Priority::HIGH:
- return kRealtimePriority;
+ return rtc::kRealtimePriority;
case Priority::LOW:
- return kLowPriority;
+ return rtc::kLowPriority;
case Priority::NORMAL:
- return kNormalPriority;
+ return rtc::kNormalPriority;
default:
RTC_NOTREACHED();
break;
}
- return kNormalPriority;
+ return rtc::kNormalPriority;
}
-} // namespace
-class TaskQueue::Impl : public RefCountInterface {
+class TaskQueueLibevent final : public TaskQueueBase {
public:
- explicit Impl(const char* queue_name,
- TaskQueue* queue,
- Priority priority = Priority::NORMAL);
- ~Impl() override;
+ TaskQueueLibevent(absl::string_view queue_name, rtc::ThreadPriority priority);
- static TaskQueue::Impl* Current();
- static TaskQueue* CurrentQueue();
-
- // Used for DCHECKing the current queue.
- bool IsCurrent() const;
-
- void PostTask(std::unique_ptr<QueuedTask> task);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue);
-
- void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds);
+ void Delete() override;
+ void PostTask(std::unique_ptr<QueuedTask> task) override;
+ void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) override;
private:
+ class SetTimerTask;
+ struct TimerEvent;
+
+ ~TaskQueueLibevent() override = default;
+
static void ThreadMain(void* context);
static void OnWakeup(int socket, short flags, void* context); // NOLINT
static void RunTask(int fd, short flags, void* context); // NOLINT
static void RunTimer(int fd, short flags, void* context); // NOLINT
- class ReplyTaskOwner;
- class PostAndReplyTask;
- class SetTimerTask;
-
- typedef RefCountedObject<ReplyTaskOwner> ReplyTaskOwnerRef;
-
- void PrepareReplyTask(scoped_refptr<ReplyTaskOwnerRef> reply_task);
-
- struct QueueContext;
- TaskQueue* const queue_;
+ bool is_active_ = true;
int wakeup_pipe_in_ = -1;
int wakeup_pipe_out_ = -1;
event_base* event_base_;
- std::unique_ptr<event> wakeup_event_;
- PlatformThread thread_;
+ event wakeup_event_;
+ rtc::PlatformThread thread_;
rtc::CriticalSection pending_lock_;
std::list<std::unique_ptr<QueuedTask>> pending_ RTC_GUARDED_BY(pending_lock_);
- std::list<scoped_refptr<ReplyTaskOwnerRef>> pending_replies_
- RTC_GUARDED_BY(pending_lock_);
-};
-
-struct TaskQueue::Impl::QueueContext {
- explicit QueueContext(TaskQueue::Impl* q) : queue(q), is_active(true) {}
- TaskQueue::Impl* queue;
- bool is_active;
// Holds a list of events pending timers for cleanup when the loop exits.
std::list<TimerEvent*> pending_timers_;
};
-// Posting a reply task is tricky business. This class owns the reply task
-// and a reference to it is held by both the reply queue and the first task.
-// Here's an outline of what happens when dealing with a reply task.
-// * The ReplyTaskOwner owns the |reply_| task.
-// * One ref owned by PostAndReplyTask
-// * One ref owned by the reply TaskQueue
-// * ReplyTaskOwner has a flag |run_task_| initially set to false.
-// * ReplyTaskOwner has a method: HasOneRef() (provided by RefCountedObject).
-// * After successfully running the original |task_|, PostAndReplyTask() calls
-// set_should_run_task(). This sets |run_task_| to true.
-// * In PostAndReplyTask's dtor:
-// * It releases its reference to ReplyTaskOwner (important to do this first).
-// * Sends (write()) a kRunReplyTask message to the reply queue's pipe.
-// * PostAndReplyTask doesn't care if write() fails, but when it does:
-// * The reply queue is gone.
-// * ReplyTaskOwner has already been deleted and the reply task too.
-// * If write() succeeds:
-// * ReplyQueue receives the kRunReplyTask message
-// * Goes through all pending tasks, finding the first that HasOneRef()
-// * Calls ReplyTaskOwner::Run()
-// * if set_should_run_task() was called, the reply task will be run
-// * Release the reference to ReplyTaskOwner
-// * ReplyTaskOwner and associated |reply_| are deleted.
-class TaskQueue::Impl::ReplyTaskOwner {
- public:
- ReplyTaskOwner(std::unique_ptr<QueuedTask> reply)
- : reply_(std::move(reply)) {}
+struct TaskQueueLibevent::TimerEvent {
+ TimerEvent(TaskQueueLibevent* task_queue, std::unique_ptr<QueuedTask> task)
+ : task_queue(task_queue), task(std::move(task)) {}
+ ~TimerEvent() { event_del(&ev); }
- void Run() {
- RTC_DCHECK(reply_);
- if (run_task_) {
- if (!reply_->Run())
- reply_.release();
- }
- reply_.reset();
- }
-
- void set_should_run_task() {
- RTC_DCHECK(!run_task_);
- run_task_ = true;
- }
-
- private:
- std::unique_ptr<QueuedTask> reply_;
- bool run_task_ = false;
+ event ev;
+ TaskQueueLibevent* task_queue;
+ std::unique_ptr<QueuedTask> task;
};
-class TaskQueue::Impl::PostAndReplyTask : public QueuedTask {
- public:
- PostAndReplyTask(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue,
- int reply_pipe)
- : task_(std::move(task)),
- reply_pipe_(reply_pipe),
- reply_task_owner_(
- new RefCountedObject<ReplyTaskOwner>(std::move(reply))) {
- reply_queue->PrepareReplyTask(reply_task_owner_);
- }
-
- ~PostAndReplyTask() override {
- reply_task_owner_ = nullptr;
- IgnoreSigPipeSignalOnCurrentThread();
- // Send a signal to the reply queue that the reply task can run now.
- // Depending on whether |set_should_run_task()| was called by the
- // PostAndReplyTask(), the reply task may or may not actually run.
- // In either case, it will be deleted.
- char message = kRunReplyTask;
- RTC_UNUSED(write(reply_pipe_, &message, sizeof(message)));
- }
-
- private:
- bool Run() override {
- if (!task_->Run())
- task_.release();
- reply_task_owner_->set_should_run_task();
- return true;
- }
-
- std::unique_ptr<QueuedTask> task_;
- int reply_pipe_;
- scoped_refptr<RefCountedObject<ReplyTaskOwner>> reply_task_owner_;
-};
-
-class TaskQueue::Impl::SetTimerTask : public QueuedTask {
+class TaskQueueLibevent::SetTimerTask : public QueuedTask {
public:
SetTimerTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds)
: task_(std::move(task)),
milliseconds_(milliseconds),
- posted_(Time32()) {}
+ posted_(rtc::Time32()) {}
private:
bool Run() override {
// Compensate for the time that has passed since construction
// and until we got here.
- uint32_t post_time = Time32() - posted_;
- TaskQueue::Impl::Current()->PostDelayedTask(
+ uint32_t post_time = rtc::Time32() - posted_;
+ TaskQueueLibevent::Current()->PostDelayedTask(
std::move(task_),
post_time > milliseconds_ ? 0 : milliseconds_ - post_time);
return true;
@@ -281,17 +169,10 @@
const uint32_t posted_;
};
-TaskQueue::Impl::Impl(const char* queue_name,
- TaskQueue* queue,
- Priority priority /*= NORMAL*/)
- : queue_(queue),
- event_base_(event_base_new()),
- wakeup_event_(new event()),
- thread_(&TaskQueue::Impl::ThreadMain,
- this,
- queue_name,
- TaskQueuePriorityToThreadPriority(priority)) {
- RTC_DCHECK(queue_name);
+TaskQueueLibevent::TaskQueueLibevent(absl::string_view queue_name,
+ rtc::ThreadPriority priority)
+ : event_base_(event_base_new()),
+ thread_(&TaskQueueLibevent::ThreadMain, this, queue_name, priority) {
int fds[2];
RTC_CHECK(pipe(fds) == 0);
SetNonBlocking(fds[0]);
@@ -299,13 +180,13 @@
wakeup_pipe_out_ = fds[0];
wakeup_pipe_in_ = fds[1];
- EventAssign(wakeup_event_.get(), event_base_, wakeup_pipe_out_,
+ EventAssign(&wakeup_event_, event_base_, wakeup_pipe_out_,
EV_READ | EV_PERSIST, OnWakeup, this);
- event_add(wakeup_event_.get(), 0);
+ event_add(&wakeup_event_, 0);
thread_.Start();
}
-TaskQueue::Impl::~Impl() {
+void TaskQueueLibevent::Delete() {
RTC_DCHECK(!IsCurrent());
struct timespec ts;
char message = kQuit;
@@ -319,7 +200,7 @@
thread_.Stop();
- event_del(wakeup_event_.get());
+ event_del(&wakeup_event_);
IgnoreSigPipeSignalOnCurrentThread();
@@ -329,48 +210,30 @@
wakeup_pipe_out_ = -1;
event_base_free(event_base_);
+ delete this;
}
-// static
-TaskQueue::Impl* TaskQueue::Impl::Current() {
- QueueContext* ctx =
- static_cast<QueueContext*>(pthread_getspecific(GetQueuePtrTls()));
- return ctx ? ctx->queue : nullptr;
-}
-
-// static
-TaskQueue* TaskQueue::Impl::CurrentQueue() {
- TaskQueue::Impl* current = Current();
- if (current) {
- return current->queue_;
- }
- return nullptr;
-}
-
-bool TaskQueue::Impl::IsCurrent() const {
- return IsThreadRefEqual(thread_.GetThreadRef(), CurrentThreadRef());
-}
-
-void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) {
+void TaskQueueLibevent::PostTask(std::unique_ptr<QueuedTask> task) {
RTC_DCHECK(task.get());
// libevent isn't thread safe. This means that we can't use methods such
// as event_base_once to post tasks to the worker thread from a different
// thread. However, we can use it when posting from the worker thread itself.
if (IsCurrent()) {
- if (event_base_once(event_base_, -1, EV_TIMEOUT, &TaskQueue::Impl::RunTask,
- task.get(), nullptr) == 0) {
+ if (event_base_once(event_base_, -1, EV_TIMEOUT,
+ &TaskQueueLibevent::RunTask, task.get(),
+ nullptr) == 0) {
task.release();
}
} else {
QueuedTask* task_id = task.get(); // Only used for comparison.
{
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
pending_.push_back(std::move(task));
}
char message = kRunTask;
if (write(wakeup_pipe_in_, &message, sizeof(message)) != sizeof(message)) {
RTC_LOG(WARNING) << "Failed to queue task.";
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
pending_.remove_if([task_id](std::unique_ptr<QueuedTask>& t) {
return t.get() == task_id;
});
@@ -378,92 +241,61 @@
}
}
-void TaskQueue::Impl::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
+void TaskQueueLibevent::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) {
if (IsCurrent()) {
- TimerEvent* timer = new TimerEvent(std::move(task));
- EventAssign(&timer->ev, event_base_, -1, 0, &TaskQueue::Impl::RunTimer,
+ TimerEvent* timer = new TimerEvent(this, std::move(task));
+ EventAssign(&timer->ev, event_base_, -1, 0, &TaskQueueLibevent::RunTimer,
timer);
- QueueContext* ctx =
- static_cast<QueueContext*>(pthread_getspecific(GetQueuePtrTls()));
- ctx->pending_timers_.push_back(timer);
+ pending_timers_.push_back(timer);
timeval tv = {rtc::dchecked_cast<int>(milliseconds / 1000),
rtc::dchecked_cast<int>(milliseconds % 1000) * 1000};
event_add(&timer->ev, &tv);
} else {
- PostTask(std::unique_ptr<QueuedTask>(
- new SetTimerTask(std::move(task), milliseconds)));
+ PostTask(absl::make_unique<SetTimerTask>(std::move(task), milliseconds));
}
}
-void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue) {
- std::unique_ptr<QueuedTask> wrapper_task(
- new PostAndReplyTask(std::move(task), std::move(reply), reply_queue,
- reply_queue->wakeup_pipe_in_));
- PostTask(std::move(wrapper_task));
-}
-
// static
-void TaskQueue::Impl::ThreadMain(void* context) {
- TaskQueue::Impl* me = static_cast<TaskQueue::Impl*>(context);
+void TaskQueueLibevent::ThreadMain(void* context) {
+ TaskQueueLibevent* me = static_cast<TaskQueueLibevent*>(context);
- QueueContext queue_context(me);
- pthread_setspecific(GetQueuePtrTls(), &queue_context);
+ {
+ CurrentTaskQueueSetter set_current(me);
+ while (me->is_active_)
+ event_base_loop(me->event_base_, 0);
+ }
- while (queue_context.is_active)
- event_base_loop(me->event_base_, 0);
-
- pthread_setspecific(GetQueuePtrTls(), nullptr);
-
- for (TimerEvent* timer : queue_context.pending_timers_)
+ for (TimerEvent* timer : me->pending_timers_)
delete timer;
}
// static
-void TaskQueue::Impl::OnWakeup(int socket,
- short flags,
- void* context) { // NOLINT
- QueueContext* ctx =
- static_cast<QueueContext*>(pthread_getspecific(GetQueuePtrTls()));
- RTC_DCHECK(ctx->queue->wakeup_pipe_out_ == socket);
+void TaskQueueLibevent::OnWakeup(int socket,
+ short flags, // NOLINT
+ void* context) {
+ TaskQueueLibevent* me = static_cast<TaskQueueLibevent*>(context);
+ RTC_DCHECK(me->wakeup_pipe_out_ == socket);
char buf;
RTC_CHECK(sizeof(buf) == read(socket, &buf, sizeof(buf)));
switch (buf) {
case kQuit:
- ctx->is_active = false;
- event_base_loopbreak(ctx->queue->event_base_);
+ me->is_active_ = false;
+ event_base_loopbreak(me->event_base_);
break;
case kRunTask: {
std::unique_ptr<QueuedTask> task;
{
- CritScope lock(&ctx->queue->pending_lock_);
- RTC_DCHECK(!ctx->queue->pending_.empty());
- task = std::move(ctx->queue->pending_.front());
- ctx->queue->pending_.pop_front();
+ rtc::CritScope lock(&me->pending_lock_);
+ RTC_DCHECK(!me->pending_.empty());
+ task = std::move(me->pending_.front());
+ me->pending_.pop_front();
RTC_DCHECK(task.get());
}
if (!task->Run())
task.release();
break;
}
- case kRunReplyTask: {
- scoped_refptr<ReplyTaskOwnerRef> reply_task;
- {
- CritScope lock(&ctx->queue->pending_lock_);
- for (auto it = ctx->queue->pending_replies_.begin();
- it != ctx->queue->pending_replies_.end(); ++it) {
- if ((*it)->HasOneRef()) {
- reply_task = std::move(*it);
- ctx->queue->pending_replies_.erase(it);
- break;
- }
- }
- }
- reply_task->Run();
- break;
- }
default:
RTC_NOTREACHED();
break;
@@ -471,66 +303,38 @@
}
// static
-void TaskQueue::Impl::RunTask(int fd, short flags, void* context) { // NOLINT
+void TaskQueueLibevent::RunTask(int fd, short flags, void* context) { // NOLINT
auto* task = static_cast<QueuedTask*>(context);
if (task->Run())
delete task;
}
// static
-void TaskQueue::Impl::RunTimer(int fd, short flags, void* context) { // NOLINT
+void TaskQueueLibevent::RunTimer(int fd,
+ short flags, // NOLINT
+ void* context) {
TimerEvent* timer = static_cast<TimerEvent*>(context);
if (!timer->task->Run())
timer->task.release();
- QueueContext* ctx =
- static_cast<QueueContext*>(pthread_getspecific(GetQueuePtrTls()));
- ctx->pending_timers_.remove(timer);
+ timer->task_queue->pending_timers_.remove(timer);
delete timer;
}
-void TaskQueue::Impl::PrepareReplyTask(
- scoped_refptr<ReplyTaskOwnerRef> reply_task) {
- RTC_DCHECK(reply_task);
- CritScope lock(&pending_lock_);
- pending_replies_.push_back(std::move(reply_task));
+class TaskQueueLibeventFactory final : public TaskQueueFactory {
+ public:
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const override {
+ return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
+ new TaskQueueLibevent(name,
+ TaskQueuePriorityToThreadPriority(priority)));
+ }
+};
+
+} // namespace
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueLibeventFactory() {
+ return absl::make_unique<TaskQueueLibeventFactory>();
}
-TaskQueue::TaskQueue(const char* queue_name, Priority priority)
- : impl_(new RefCountedObject<TaskQueue::Impl>(queue_name, this, priority)) {
-}
-
-TaskQueue::~TaskQueue() {}
-
-// static
-TaskQueue* TaskQueue::Current() {
- return TaskQueue::Impl::CurrentQueue();
-}
-
-// Used for DCHECKing the current queue.
-bool TaskQueue::IsCurrent() const {
- return impl_->IsCurrent();
-}
-
-void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
- return TaskQueue::impl_->PostTask(std::move(task));
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue* reply_queue) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- reply_queue->impl_.get());
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- impl_.get());
-}
-
-void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
- return TaskQueue::impl_->PostDelayedTask(std::move(task), milliseconds);
-}
-
-} // namespace rtc
+} // namespace webrtc
diff --git a/rtc_base/task_queue_libevent.h b/rtc_base/task_queue_libevent.h
new file mode 100644
index 0000000..aaa72d4
--- /dev/null
+++ b/rtc_base/task_queue_libevent.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_QUEUE_LIBEVENT_H_
+#define RTC_BASE_TASK_QUEUE_LIBEVENT_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueLibeventFactory();
+
+} // namespace webrtc
+
+#endif // RTC_BASE_TASK_QUEUE_LIBEVENT_H_
diff --git a/rtc_base/task_queue_posix.cc b/rtc_base/task_queue_posix.cc
deleted file mode 100644
index 520b8e9..0000000
--- a/rtc_base/task_queue_posix.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 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 "rtc_base/task_queue_posix.h"
-
-#include "rtc_base/checks.h"
-#include "rtc_base/task_queue.h"
-
-namespace rtc {
-namespace internal {
-pthread_key_t g_queue_ptr_tls = 0;
-
-void InitializeTls() {
- RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0);
-}
-
-pthread_key_t GetQueuePtrTls() {
- static pthread_once_t init_once = PTHREAD_ONCE_INIT;
- RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0);
- return g_queue_ptr_tls;
-}
-
-AutoSetCurrentQueuePtr::AutoSetCurrentQueuePtr(TaskQueue* q)
- : prev_(TaskQueue::Current()) {
- pthread_setspecific(GetQueuePtrTls(), q);
-}
-
-AutoSetCurrentQueuePtr::~AutoSetCurrentQueuePtr() {
- pthread_setspecific(GetQueuePtrTls(), prev_);
-}
-
-} // namespace internal
-} // namespace rtc
diff --git a/rtc_base/task_queue_posix.h b/rtc_base/task_queue_posix.h
deleted file mode 100644
index 3014e20..0000000
--- a/rtc_base/task_queue_posix.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#ifndef RTC_BASE_TASK_QUEUE_POSIX_H_
-#define RTC_BASE_TASK_QUEUE_POSIX_H_
-
-#include <pthread.h>
-
-namespace rtc {
-
-class TaskQueue;
-
-namespace internal {
-
-class AutoSetCurrentQueuePtr {
- public:
- explicit AutoSetCurrentQueuePtr(TaskQueue* q);
- ~AutoSetCurrentQueuePtr();
-
- private:
- TaskQueue* const prev_;
-};
-
-pthread_key_t GetQueuePtrTls();
-
-} // namespace internal
-} // namespace rtc
-
-#endif // RTC_BASE_TASK_QUEUE_POSIX_H_
diff --git a/rtc_base/task_queue_stdlib.cc b/rtc_base/task_queue_stdlib.cc
index 0fb0ed2..88128b5 100644
--- a/rtc_base/task_queue_stdlib.cc
+++ b/rtc_base/task_queue_stdlib.cc
@@ -8,83 +8,55 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/task_queue.h"
+#include "rtc_base/task_queue_stdlib.h"
#include <string.h>
#include <algorithm>
-#include <atomic>
-#include <condition_variable>
#include <map>
#include <queue>
#include <utility>
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/task_queue/queued_task.h"
+#include "api/task_queue/task_queue_base.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/platform_thread.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
#include "rtc_base/thread_annotations.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
-namespace rtc {
+namespace webrtc {
namespace {
-using Priority = TaskQueue::Priority;
-
-ThreadPriority TaskQueuePriorityToThreadPriority(Priority priority) {
+rtc::ThreadPriority TaskQueuePriorityToThreadPriority(
+ TaskQueueFactory::Priority priority) {
switch (priority) {
- case Priority::HIGH:
- return kRealtimePriority;
- case Priority::LOW:
- return kLowPriority;
- case Priority::NORMAL:
- return kNormalPriority;
+ case TaskQueueFactory::Priority::HIGH:
+ return rtc::kRealtimePriority;
+ case TaskQueueFactory::Priority::LOW:
+ return rtc::kLowPriority;
+ case TaskQueueFactory::Priority::NORMAL:
+ return rtc::kNormalPriority;
default:
RTC_NOTREACHED();
- return kNormalPriority;
+ return rtc::kNormalPriority;
}
- return kNormalPriority;
}
-} // namespace
-
-class TaskQueue::Impl : public RefCountInterface {
+class TaskQueueStdlib final : public TaskQueueBase {
public:
- Impl(const char* queue_name, TaskQueue* queue, Priority priority);
- ~Impl() override;
+ TaskQueueStdlib(absl::string_view queue_name, rtc::ThreadPriority priority);
+ ~TaskQueueStdlib() override = default;
- static TaskQueue::Impl* Current();
- static TaskQueue* CurrentQueue();
+ void Delete() override;
+ void PostTask(std::unique_ptr<QueuedTask> task) override;
+ void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) override;
- // Used for DCHECKing the current queue.
- bool IsCurrent() const;
-
- template <class Closure,
- typename std::enable_if<!std::is_convertible<
- Closure,
- std::unique_ptr<QueuedTask>>::value>::type* = nullptr>
- void PostTask(Closure&& closure) {
- PostTask(NewClosure(std::forward<Closure>(closure)));
- }
-
- void PostTask(std::unique_ptr<QueuedTask> task);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue);
-
- void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds);
-
- class WorkerThread : public PlatformThread {
- public:
- WorkerThread(ThreadRunFunction func,
- void* obj,
- const char* thread_name,
- ThreadPriority priority)
- : PlatformThread(func, obj, thread_name, priority) {}
- };
-
+ private:
using OrderId = uint64_t;
struct DelayedEntryTimeout {
@@ -103,38 +75,26 @@
int64_t sleep_time_ms_{};
};
- protected:
NextTask GetNextTask();
- private:
- // The ThreadQueue::Current() method requires that the current thread
- // returns the task queue if the current thread is the active task
- // queue and this variable holds the value needed in thread_local to
- // on the initialized worker thread holding the queue.
- static thread_local TaskQueue::Impl* thread_context_;
-
static void ThreadMain(void* context);
void ProcessTasks();
void NotifyWake();
- // The back pointer from the owner task queue object
- // from this implementation detail.
- TaskQueue* const queue_;
-
// Indicates if the thread has started.
- Event started_;
+ rtc::Event started_;
// Indicates if the thread has stopped.
- Event stopped_;
+ rtc::Event stopped_;
// Signaled whenever a new task is pending.
- Event flag_notify_;
+ rtc::Event flag_notify_;
// Contains the active worker thread assigned to processing
// tasks (including delayed tasks).
- WorkerThread thread_;
+ rtc::PlatformThread thread_;
rtc::CriticalSection pending_lock_;
@@ -160,57 +120,34 @@
RTC_GUARDED_BY(pending_lock_);
};
-// static
-thread_local TaskQueue::Impl* TaskQueue::Impl::thread_context_ = nullptr;
-
-TaskQueue::Impl::Impl(const char* queue_name,
- TaskQueue* queue,
- Priority priority)
- : queue_(queue),
- started_(/*manual_reset=*/false, /*initially_signaled=*/false),
+TaskQueueStdlib::TaskQueueStdlib(absl::string_view queue_name,
+ rtc::ThreadPriority priority)
+ : started_(/*manual_reset=*/false, /*initially_signaled=*/false),
stopped_(/*manual_reset=*/false, /*initially_signaled=*/false),
flag_notify_(/*manual_reset=*/false, /*initially_signaled=*/false),
- thread_(&TaskQueue::Impl::ThreadMain,
- this,
- queue_name,
- TaskQueuePriorityToThreadPriority(priority)) {
- RTC_DCHECK(queue_name);
+ thread_(&TaskQueueStdlib::ThreadMain, this, queue_name, priority) {
thread_.Start();
- started_.Wait(Event::kForever);
+ started_.Wait(rtc::Event::kForever);
}
-TaskQueue::Impl::~Impl() {
+void TaskQueueStdlib::Delete() {
RTC_DCHECK(!IsCurrent());
{
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
thread_should_quit_ = true;
}
NotifyWake();
- stopped_.Wait(Event::kForever);
+ stopped_.Wait(rtc::Event::kForever);
thread_.Stop();
+ delete this;
}
-// static
-TaskQueue::Impl* TaskQueue::Impl::Current() {
- return thread_context_;
-}
-
-// static
-TaskQueue* TaskQueue::Impl::CurrentQueue() {
- TaskQueue::Impl* current = Current();
- return current ? current->queue_ : nullptr;
-}
-
-bool TaskQueue::Impl::IsCurrent() const {
- return IsThreadRefEqual(thread_.GetThreadRef(), CurrentThreadRef());
-}
-
-void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) {
+void TaskQueueStdlib::PostTask(std::unique_ptr<QueuedTask> task) {
{
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
OrderId order = thread_posting_order_++;
pending_queue_.push(std::pair<OrderId, std::unique_ptr<QueuedTask>>(
@@ -220,7 +157,7 @@
NotifyWake();
}
-void TaskQueue::Impl::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+void TaskQueueStdlib::PostDelayedTask(std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) {
auto fire_at = rtc::TimeMillis() + milliseconds;
@@ -228,7 +165,7 @@
delay.next_fire_at_ms_ = fire_at;
{
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
delay.order_ = ++thread_posting_order_;
delayed_queue_[delay] = std::move(task);
}
@@ -236,25 +173,12 @@
NotifyWake();
}
-void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue) {
- QueuedTask* task_ptr = task.release();
- QueuedTask* reply_task_ptr = reply.release();
- PostTask([task_ptr, reply_task_ptr, reply_queue]() {
- if (task_ptr->Run())
- delete task_ptr;
-
- reply_queue->PostTask(std::unique_ptr<QueuedTask>(reply_task_ptr));
- });
-}
-
-TaskQueue::Impl::NextTask TaskQueue::Impl::GetNextTask() {
+TaskQueueStdlib::NextTask TaskQueueStdlib::GetNextTask() {
NextTask result{};
auto tick = rtc::TimeMillis();
- CritScope lock(&pending_lock_);
+ rtc::CritScope lock(&pending_lock_);
if (thread_should_quit_) {
result.final_task_ = true;
@@ -295,13 +219,13 @@
}
// static
-void TaskQueue::Impl::ThreadMain(void* context) {
- TaskQueue::Impl* me = static_cast<TaskQueue::Impl*>(context);
+void TaskQueueStdlib::ThreadMain(void* context) {
+ TaskQueueStdlib* me = static_cast<TaskQueueStdlib*>(context);
+ CurrentTaskQueueSetter set_current(me);
me->ProcessTasks();
}
-void TaskQueue::Impl::ProcessTasks() {
- thread_context_ = this;
+void TaskQueueStdlib::ProcessTasks() {
started_.Set();
while (true) {
@@ -321,7 +245,7 @@
}
if (0 == task.sleep_time_ms_)
- flag_notify_.Wait(Event::kForever);
+ flag_notify_.Wait(rtc::Event::kForever);
else
flag_notify_.Wait(task.sleep_time_ms_);
}
@@ -329,7 +253,7 @@
stopped_.Set();
}
-void TaskQueue::Impl::NotifyWake() {
+void TaskQueueStdlib::NotifyWake() {
// The queue holds pending tasks to complete. Either tasks are to be
// executed immediately or tasks are to be run at some future delayed time.
// For immediate tasks the task queue's thread is busy running the task and
@@ -357,43 +281,20 @@
flag_notify_.Set();
}
-// Boilerplate for the PIMPL pattern.
-TaskQueue::TaskQueue(const char* queue_name, Priority priority)
- : impl_(new RefCountedObject<TaskQueue::Impl>(queue_name, this, priority)) {
+class TaskQueueStdlibFactory final : public TaskQueueFactory {
+ public:
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const override {
+ return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
+ new TaskQueueStdlib(name, TaskQueuePriorityToThreadPriority(priority)));
+ }
+};
+
+} // namespace
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueStdlibFactory() {
+ return absl::make_unique<TaskQueueStdlibFactory>();
}
-TaskQueue::~TaskQueue() {}
-
-// static
-TaskQueue* TaskQueue::Current() {
- return TaskQueue::Impl::CurrentQueue();
-}
-
-// Used for DCHECKing the current queue.
-bool TaskQueue::IsCurrent() const {
- return impl_->IsCurrent();
-}
-
-void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
- return TaskQueue::impl_->PostTask(std::move(task));
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue* reply_queue) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- reply_queue->impl_.get());
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- impl_.get());
-}
-
-void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
- return TaskQueue::impl_->PostDelayedTask(std::move(task), milliseconds);
-}
-
-} // namespace rtc
+} // namespace webrtc
diff --git a/rtc_base/task_queue_stdlib.h b/rtc_base/task_queue_stdlib.h
new file mode 100644
index 0000000..fb03dff
--- /dev/null
+++ b/rtc_base/task_queue_stdlib.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_QUEUE_STDLIB_H_
+#define RTC_BASE_TASK_QUEUE_STDLIB_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueStdlibFactory();
+
+} // namespace webrtc
+
+#endif // RTC_BASE_TASK_QUEUE_STDLIB_H_
diff --git a/rtc_base/task_queue_unittest.cc b/rtc_base/task_queue_unittest.cc
index 0af39a5..5c80c4f 100644
--- a/rtc_base/task_queue_unittest.cc
+++ b/rtc_base/task_queue_unittest.cc
@@ -15,16 +15,17 @@
// clang-format on
#endif
+#include <stdint.h>
#include <memory>
+#include <utility>
#include <vector>
+#include "absl/memory/memory.h"
#include "rtc_base/bind.h"
#include "rtc_base/event.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/task_queue_for_test.h"
-#include "rtc_base/timeutils.h"
-
-using rtc::test::TaskQueueForTest;
+#include "rtc_base/task_queue.h"
+#include "rtc_base/time_utils.h"
+#include "test/gtest.h"
namespace rtc {
@@ -56,89 +57,6 @@
} // namespace
-TEST(TaskQueueTest, Construct) {
- static const char kQueueName[] = "Construct";
- TaskQueue queue(kQueueName);
- EXPECT_FALSE(queue.IsCurrent());
-}
-
-TEST(TaskQueueTest, PostAndCheckCurrent) {
- static const char kQueueName[] = "PostAndCheckCurrent";
- Event event;
- TaskQueue queue(kQueueName);
-
- // We're not running a task, so there shouldn't be a current queue.
- EXPECT_FALSE(queue.IsCurrent());
- EXPECT_FALSE(TaskQueue::Current());
-
- queue.PostTask(Bind(&CheckCurrent, &event, &queue));
- EXPECT_TRUE(event.Wait(1000));
-}
-
-TEST(TaskQueueTest, PostCustomTask) {
- static const char kQueueName[] = "PostCustomImplementation";
- TaskQueueForTest queue(kQueueName);
-
- class CustomTask : public QueuedTask {
- public:
- CustomTask() {}
- bool ran() const { return ran_; }
-
- private:
- bool Run() override {
- ran_ = true;
- return false; // Never allow the task to be deleted by the queue.
- }
-
- bool ran_ = false;
- } my_task;
-
- queue.SendTask(&my_task);
- EXPECT_TRUE(my_task.ran());
-}
-
-TEST(TaskQueueTest, PostLambda) {
- TaskQueueForTest queue("PostLambda");
- bool ran = false;
- queue.SendTask([&ran]() { ran = true; });
- EXPECT_TRUE(ran);
-}
-
-TEST(TaskQueueTest, PostDelayedZero) {
- static const char kQueueName[] = "PostDelayedZero";
- Event event;
- TaskQueue queue(kQueueName);
-
- queue.PostDelayedTask([&event]() { event.Set(); }, 0);
- EXPECT_TRUE(event.Wait(1000));
-}
-
-TEST(TaskQueueTest, PostFromQueue) {
- static const char kQueueName[] = "PostFromQueue";
- Event event;
- TaskQueue queue(kQueueName);
-
- queue.PostTask(
- [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); });
- EXPECT_TRUE(event.Wait(1000));
-}
-
-TEST(TaskQueueTest, PostDelayed) {
- static const char kQueueName[] = "PostDelayed";
- Event event;
- TaskQueue queue(kQueueName, TaskQueue::Priority::HIGH);
-
- uint32_t start = Time();
- queue.PostDelayedTask(Bind(&CheckCurrent, &event, &queue), 100);
- EXPECT_TRUE(event.Wait(1000));
- uint32_t end = Time();
- // These tests are a little relaxed due to how "powerful" our test bots can
- // be. Most recently we've seen windows bots fire the callback after 94-99ms,
- // which is why we have a little bit of leeway backwards as well.
- EXPECT_GE(end - start, 90u);
- EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290.
-}
-
// This task needs to be run manually due to the slowness of some of our bots.
// TODO(tommi): Can we run this on the perf bots?
TEST(TaskQueueTest, DISABLED_PostDelayedHighRes) {
@@ -159,295 +77,4 @@
EXPECT_NEAR(end - start, 3, 3u);
}
-TEST(TaskQueueTest, PostMultipleDelayed) {
- static const char kQueueName[] = "PostMultipleDelayed";
- TaskQueue queue(kQueueName);
-
- std::vector<std::unique_ptr<Event>> events;
- for (int i = 0; i < 100; ++i) {
- events.push_back(absl::make_unique<Event>());
- queue.PostDelayedTask(Bind(&CheckCurrent, events.back().get(), &queue), i);
- }
-
- for (const auto& e : events)
- EXPECT_TRUE(e->Wait(1000));
-}
-
-TEST(TaskQueueTest, PostDelayedAfterDestruct) {
- static const char kQueueName[] = "PostDelayedAfterDestruct";
- Event run;
- Event deleted;
- {
- TaskQueue queue(kQueueName);
- queue.PostDelayedTask(
- rtc::NewClosure([&run] { run.Set(); }, [&deleted] { deleted.Set(); }),
- 100);
- }
- // Task might outlive the TaskQueue, but still should be deleted.
- EXPECT_TRUE(deleted.Wait(200));
- EXPECT_FALSE(run.Wait(0)); // and should not run.
-}
-
-TEST(TaskQueueTest, PostAndReply) {
- static const char kPostQueue[] = "PostQueue";
- static const char kReplyQueue[] = "ReplyQueue";
- Event event;
- TaskQueue post_queue(kPostQueue);
- TaskQueue reply_queue(kReplyQueue);
-
- post_queue.PostTaskAndReply(Bind(&CheckCurrent, nullptr, &post_queue),
- Bind(&CheckCurrent, &event, &reply_queue),
- &reply_queue);
- EXPECT_TRUE(event.Wait(1000));
-}
-
-TEST(TaskQueueTest, PostAndReuse) {
- static const char kPostQueue[] = "PostQueue";
- static const char kReplyQueue[] = "ReplyQueue";
- Event event;
- TaskQueue post_queue(kPostQueue);
- TaskQueue reply_queue(kReplyQueue);
-
- int call_count = 0;
-
- class ReusedTask : public QueuedTask {
- public:
- ReusedTask(int* counter, TaskQueue* reply_queue, Event* event)
- : counter_(counter), reply_queue_(reply_queue), event_(event) {
- EXPECT_EQ(0, *counter_);
- }
-
- private:
- bool Run() override {
- if (++(*counter_) == 1) {
- std::unique_ptr<QueuedTask> myself(this);
- reply_queue_->PostTask(std::move(myself));
- // At this point, the object is owned by reply_queue_ and it's
- // theoratically possible that the object has been deleted (e.g. if
- // posting wasn't possible). So, don't touch any member variables here.
-
- // Indicate to the current queue that ownership has been transferred.
- return false;
- } else {
- EXPECT_EQ(2, *counter_);
- EXPECT_TRUE(reply_queue_->IsCurrent());
- event_->Set();
- return true; // Indicate that the object should be deleted.
- }
- }
-
- int* const counter_;
- TaskQueue* const reply_queue_;
- Event* const event_;
- };
-
- std::unique_ptr<ReusedTask> task(
- new ReusedTask(&call_count, &reply_queue, &event));
-
- post_queue.PostTask(std::move(task));
- EXPECT_TRUE(event.Wait(1000));
-}
-
-TEST(TaskQueueTest, PostAndReplyLambda) {
- static const char kPostQueue[] = "PostQueue";
- static const char kReplyQueue[] = "ReplyQueue";
- Event event;
- TaskQueue post_queue(kPostQueue);
- TaskQueue reply_queue(kReplyQueue);
-
- bool my_flag = false;
- post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; },
- [&event]() { event.Set(); }, &reply_queue);
- EXPECT_TRUE(event.Wait(1000));
- EXPECT_TRUE(my_flag);
-}
-
-TEST(TaskQueueTest, PostCopyableClosure) {
- struct CopyableClosure {
- CopyableClosure(int* num_copies, int* num_moves, Event* event)
- : num_copies(num_copies), num_moves(num_moves), event(event) {}
- CopyableClosure(const CopyableClosure& other)
- : num_copies(other.num_copies),
- num_moves(other.num_moves),
- event(other.event) {
- ++*num_copies;
- }
- CopyableClosure(CopyableClosure&& other)
- : num_copies(other.num_copies),
- num_moves(other.num_moves),
- event(other.event) {
- ++*num_moves;
- }
- void operator()() { event->Set(); }
-
- int* num_copies;
- int* num_moves;
- Event* event;
- };
-
- int num_copies = 0;
- int num_moves = 0;
- Event event;
-
- static const char kPostQueue[] = "PostCopyableClosure";
- TaskQueue post_queue(kPostQueue);
- {
- CopyableClosure closure(&num_copies, &num_moves, &event);
- post_queue.PostTask(closure);
- // Destroy closure to check with msan and tsan posted task has own copy.
- }
-
- EXPECT_TRUE(event.Wait(1000));
- EXPECT_EQ(num_copies, 1);
- EXPECT_EQ(num_moves, 0);
-}
-
-TEST(TaskQueueTest, PostMoveOnlyClosure) {
- struct SomeState {
- explicit SomeState(Event* event) : event(event) {}
- ~SomeState() { event->Set(); }
- Event* event;
- };
- struct MoveOnlyClosure {
- MoveOnlyClosure(int* num_moves, std::unique_ptr<SomeState> state)
- : num_moves(num_moves), state(std::move(state)) {}
- MoveOnlyClosure(const MoveOnlyClosure&) = delete;
- MoveOnlyClosure(MoveOnlyClosure&& other)
- : num_moves(other.num_moves), state(std::move(other.state)) {
- ++*num_moves;
- }
- void operator()() { state.reset(); }
-
- int* num_moves;
- std::unique_ptr<SomeState> state;
- };
-
- int num_moves = 0;
- Event event;
- std::unique_ptr<SomeState> state(new SomeState(&event));
-
- static const char kPostQueue[] = "PostMoveOnlyClosure";
- TaskQueue post_queue(kPostQueue);
- post_queue.PostTask(MoveOnlyClosure(&num_moves, std::move(state)));
-
- EXPECT_TRUE(event.Wait(1000));
- EXPECT_EQ(num_moves, 1);
-}
-
-TEST(TaskQueueTest, PostMoveOnlyCleanup) {
- struct SomeState {
- explicit SomeState(Event* event) : event(event) {}
- ~SomeState() { event->Set(); }
- Event* event;
- };
- struct MoveOnlyClosure {
- void operator()() { state.reset(); }
-
- std::unique_ptr<SomeState> state;
- };
-
- Event event_run;
- Event event_cleanup;
- std::unique_ptr<SomeState> state_run(new SomeState(&event_run));
- std::unique_ptr<SomeState> state_cleanup(new SomeState(&event_cleanup));
-
- static const char kPostQueue[] = "PostMoveOnlyCleanup";
- TaskQueue post_queue(kPostQueue);
- post_queue.PostTask(NewClosure(MoveOnlyClosure{std::move(state_run)},
- MoveOnlyClosure{std::move(state_cleanup)}));
-
- EXPECT_TRUE(event_cleanup.Wait(1000));
- // Expect run closure to complete before cleanup closure.
- EXPECT_TRUE(event_run.Wait(0));
-}
-
-// This test covers a particular bug that we had in the libevent implementation
-// where we could hit a deadlock while trying to post a reply task to a queue
-// that was being deleted. The test isn't guaranteed to hit that case but it's
-// written in a way that makes it likely and by running with --gtest_repeat=1000
-// the bug would occur. Alas, now it should be fixed.
-TEST(TaskQueueTest, PostAndReplyDeadlock) {
- Event event;
- TaskQueue post_queue("PostQueue");
- TaskQueue reply_queue("ReplyQueue");
-
- post_queue.PostTaskAndReply([&event]() { event.Set(); }, []() {},
- &reply_queue);
- EXPECT_TRUE(event.Wait(1000));
-}
-
-// http://bugs.webrtc.org/9728
-#if defined(WEBRTC_WIN)
-#define MAYBE_DeleteTaskQueueAfterPostAndReply \
- DISABLED_DeleteTaskQueueAfterPostAndReply
-#else
-#define MAYBE_DeleteTaskQueueAfterPostAndReply DeleteTaskQueueAfterPostAndReply
-#endif
-TEST(TaskQueueTest, MAYBE_DeleteTaskQueueAfterPostAndReply) {
- Event task_deleted;
- Event reply_deleted;
- auto* task_queue = new TaskQueue("Queue");
-
- task_queue->PostTaskAndReply(
- /*task=*/rtc::NewClosure(
- /*closure=*/[] {},
- /*cleanup=*/[&task_deleted] { task_deleted.Set(); }),
- /*reply=*/rtc::NewClosure(
- /*closure=*/[] {},
- /*cleanup=*/[&reply_deleted] { reply_deleted.Set(); }));
-
- delete task_queue;
-
- EXPECT_TRUE(task_deleted.Wait(1000));
- EXPECT_TRUE(reply_deleted.Wait(1000));
-}
-
-void TestPostTaskAndReply(TaskQueue* work_queue, Event* event) {
- ASSERT_FALSE(work_queue->IsCurrent());
- work_queue->PostTaskAndReply(Bind(&CheckCurrent, nullptr, work_queue),
- NewClosure([event]() { event->Set(); }));
-}
-
-// Does a PostTaskAndReply from within a task to post and reply to the current
-// queue. All in all there will be 3 tasks posted and run.
-TEST(TaskQueueTest, PostAndReply2) {
- static const char kQueueName[] = "PostAndReply2";
- static const char kWorkQueueName[] = "PostAndReply2_Worker";
- Event event;
- TaskQueue queue(kQueueName);
- TaskQueue work_queue(kWorkQueueName);
-
- queue.PostTask(Bind(&TestPostTaskAndReply, &work_queue, &event));
- EXPECT_TRUE(event.Wait(1000));
-}
-
-// Tests posting more messages than a queue can queue up.
-// In situations like that, tasks will get dropped.
-TEST(TaskQueueTest, PostALot) {
- // To destruct the event after the queue has gone out of scope.
- Event event;
-
- int tasks_executed = 0;
- int tasks_cleaned_up = 0;
- static const int kTaskCount = 0xffff;
-
- {
- static const char kQueueName[] = "PostALot";
- TaskQueue queue(kQueueName);
-
- // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
- // So here we post a total of 0xffff+1 messages, which triggers a failure
- // case inside of the libevent queue implementation.
-
- queue.PostTask([&event]() { event.Wait(Event::kForever); });
- for (int i = 0; i < kTaskCount; ++i)
- queue.PostTask(NewClosure([&tasks_executed]() { ++tasks_executed; },
- [&tasks_cleaned_up]() { ++tasks_cleaned_up; }));
- event.Set(); // Unblock the first task.
- }
-
- EXPECT_GE(tasks_cleaned_up, tasks_executed);
- EXPECT_EQ(kTaskCount, tasks_cleaned_up);
-}
-
} // namespace rtc
diff --git a/rtc_base/task_queue_win.cc b/rtc_base/task_queue_win.cc
index c1e7c46..696eda3 100644
--- a/rtc_base/task_queue_win.cc
+++ b/rtc_base/task_queue_win.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/task_queue.h"
+#include "rtc_base/task_queue_win.h"
// clang-format off
// clang formating would change include order.
@@ -27,69 +27,51 @@
#include <queue>
#include <utility>
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "api/task_queue/queued_task.h"
+#include "api/task_queue/task_queue_base.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
-namespace rtc {
+namespace webrtc {
namespace {
#define WM_RUN_TASK WM_USER + 1
#define WM_QUEUE_DELAYED_TASK WM_USER + 2
-using Priority = TaskQueue::Priority;
-
-DWORD g_queue_ptr_tls = 0;
-
-BOOL CALLBACK InitializeTls(PINIT_ONCE init_once, void* param, void** context) {
- g_queue_ptr_tls = TlsAlloc();
- return TRUE;
-}
-
-DWORD GetQueuePtrTls() {
- static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
- ::InitOnceExecuteOnce(&init_once, InitializeTls, nullptr, nullptr);
- return g_queue_ptr_tls;
-}
-
-struct ThreadStartupData {
- Event* started;
- void* thread_context;
-};
-
void CALLBACK InitializeQueueThread(ULONG_PTR param) {
MSG msg;
::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
- ThreadStartupData* data = reinterpret_cast<ThreadStartupData*>(param);
- ::TlsSetValue(GetQueuePtrTls(), data->thread_context);
- data->started->Set();
+ rtc::Event* data = reinterpret_cast<rtc::Event*>(param);
+ data->Set();
}
-ThreadPriority TaskQueuePriorityToThreadPriority(Priority priority) {
+rtc::ThreadPriority TaskQueuePriorityToThreadPriority(
+ TaskQueueFactory::Priority priority) {
switch (priority) {
- case Priority::HIGH:
- return kRealtimePriority;
- case Priority::LOW:
- return kLowPriority;
- case Priority::NORMAL:
- return kNormalPriority;
+ case TaskQueueFactory::Priority::HIGH:
+ return rtc::kRealtimePriority;
+ case TaskQueueFactory::Priority::LOW:
+ return rtc::kLowPriority;
+ case TaskQueueFactory::Priority::NORMAL:
+ return rtc::kNormalPriority;
default:
RTC_NOTREACHED();
break;
}
- return kNormalPriority;
+ return rtc::kNormalPriority;
}
int64_t GetTick() {
static const UINT kPeriod = 1;
bool high_res = (timeBeginPeriod(kPeriod) == TIMERR_NOERROR);
- int64_t ret = TimeMillis();
+ int64_t ret = rtc::TimeMillis();
if (high_res)
timeEndPeriod(kPeriod);
return ret;
@@ -168,85 +150,56 @@
RTC_DISALLOW_COPY_AND_ASSIGN(MultimediaTimer);
};
-} // namespace
-
-class TaskQueue::Impl : public RefCountInterface {
+class TaskQueueWin : public TaskQueueBase {
public:
- Impl(const char* queue_name, TaskQueue* queue, Priority priority);
- ~Impl() override;
+ TaskQueueWin(absl::string_view queue_name, rtc::ThreadPriority priority);
+ ~TaskQueueWin() override = default;
- static TaskQueue::Impl* Current();
- static TaskQueue* CurrentQueue();
-
- // Used for DCHECKing the current queue.
- bool IsCurrent() const;
-
- template <class Closure,
- typename std::enable_if<!std::is_convertible<
- Closure,
- std::unique_ptr<QueuedTask>>::value>::type* = nullptr>
- void PostTask(Closure&& closure) {
- PostTask(NewClosure(std::forward<Closure>(closure)));
- }
-
- void PostTask(std::unique_ptr<QueuedTask> task);
- void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue);
-
- void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds);
+ void Delete() override;
+ void PostTask(std::unique_ptr<QueuedTask> task) override;
+ void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) override;
void RunPendingTasks();
private:
static void ThreadMain(void* context);
- class WorkerThread : public PlatformThread {
+ class WorkerThread : public rtc::PlatformThread {
public:
- WorkerThread(ThreadRunFunction func,
+ WorkerThread(rtc::ThreadRunFunction func,
void* obj,
- const char* thread_name,
- ThreadPriority priority)
+ absl::string_view thread_name,
+ rtc::ThreadPriority priority)
: PlatformThread(func, obj, thread_name, priority) {}
bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data) {
- return PlatformThread::QueueAPC(apc_function, data);
+ return rtc::PlatformThread::QueueAPC(apc_function, data);
}
};
- class ThreadState {
- public:
- explicit ThreadState(HANDLE in_queue) : in_queue_(in_queue) {}
- ~ThreadState() {}
+ void RunThreadMain();
+ bool ProcessQueuedMessages();
+ void RunDueTasks();
+ void ScheduleNextTimer();
+ void CancelTimers();
- void RunThreadMain();
-
- private:
- bool ProcessQueuedMessages();
- void RunDueTasks();
- void ScheduleNextTimer();
- void CancelTimers();
-
- // Since priority_queue<> by defult orders items in terms of
- // largest->smallest, using std::less<>, and we want smallest->largest,
- // we would like to use std::greater<> here. Alas it's only available in
- // C++14 and later, so we roll our own compare template that that relies on
- // operator<().
- template <typename T>
- struct greater {
- bool operator()(const T& l, const T& r) { return l > r; }
- };
-
- MultimediaTimer timer_;
- std::priority_queue<DelayedTaskInfo,
- std::vector<DelayedTaskInfo>,
- greater<DelayedTaskInfo>>
- timer_tasks_;
- UINT_PTR timer_id_ = 0;
- HANDLE in_queue_;
+ // Since priority_queue<> by defult orders items in terms of
+ // largest->smallest, using std::less<>, and we want smallest->largest,
+ // we would like to use std::greater<> here. Alas it's only available in
+ // C++14 and later, so we roll our own compare template that that relies on
+ // operator<().
+ template <typename T>
+ struct greater {
+ bool operator()(const T& l, const T& r) { return l > r; }
};
- TaskQueue* const queue_;
+ MultimediaTimer timer_;
+ std::priority_queue<DelayedTaskInfo,
+ std::vector<DelayedTaskInfo>,
+ greater<DelayedTaskInfo>>
+ timer_tasks_;
+ UINT_PTR timer_id_ = 0;
WorkerThread thread_;
rtc::CriticalSection pending_lock_;
std::queue<std::unique_ptr<QueuedTask>> pending_
@@ -254,26 +207,19 @@
HANDLE in_queue_;
};
-TaskQueue::Impl::Impl(const char* queue_name,
- TaskQueue* queue,
- Priority priority)
- : queue_(queue),
- thread_(&TaskQueue::Impl::ThreadMain,
- this,
- queue_name,
- TaskQueuePriorityToThreadPriority(priority)),
+TaskQueueWin::TaskQueueWin(absl::string_view queue_name,
+ rtc::ThreadPriority priority)
+ : thread_(&TaskQueueWin::ThreadMain, this, queue_name, priority),
in_queue_(::CreateEvent(nullptr, true, false, nullptr)) {
- RTC_DCHECK(queue_name);
RTC_DCHECK(in_queue_);
thread_.Start();
- Event event(false, false);
- ThreadStartupData startup = {&event, this};
+ rtc::Event event(false, false);
RTC_CHECK(thread_.QueueAPC(&InitializeQueueThread,
- reinterpret_cast<ULONG_PTR>(&startup)));
- event.Wait(Event::kForever);
+ reinterpret_cast<ULONG_PTR>(&event)));
+ event.Wait(rtc::Event::kForever);
}
-TaskQueue::Impl::~Impl() {
+void TaskQueueWin::Delete() {
RTC_DCHECK(!IsCurrent());
while (!::PostThreadMessage(thread_.GetThreadRef(), WM_QUIT, 0, 0)) {
RTC_CHECK_EQ(ERROR_NOT_ENOUGH_QUOTA, ::GetLastError());
@@ -281,31 +227,17 @@
}
thread_.Stop();
::CloseHandle(in_queue_);
+ delete this;
}
-// static
-TaskQueue::Impl* TaskQueue::Impl::Current() {
- return static_cast<TaskQueue::Impl*>(::TlsGetValue(GetQueuePtrTls()));
-}
-
-// static
-TaskQueue* TaskQueue::Impl::CurrentQueue() {
- TaskQueue::Impl* current = Current();
- return current ? current->queue_ : nullptr;
-}
-
-bool TaskQueue::Impl::IsCurrent() const {
- return IsThreadRefEqual(thread_.GetThreadRef(), CurrentThreadRef());
-}
-
-void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) {
+void TaskQueueWin::PostTask(std::unique_ptr<QueuedTask> task) {
rtc::CritScope lock(&pending_lock_);
pending_.push(std::move(task));
::SetEvent(in_queue_);
}
-void TaskQueue::Impl::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
+void TaskQueueWin::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) {
if (!milliseconds) {
PostTask(std::move(task));
return;
@@ -322,25 +254,7 @@
}
}
-void TaskQueue::Impl::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue::Impl* reply_queue) {
- QueuedTask* task_ptr = task.release();
- QueuedTask* reply_task_ptr = reply.release();
- DWORD reply_thread_id = reply_queue->thread_.GetThreadRef();
- PostTask([task_ptr, reply_task_ptr, reply_thread_id]() {
- if (task_ptr->Run())
- delete task_ptr;
- // If the thread's message queue is full, we can't queue the task and will
- // have to drop it (i.e. delete).
- if (!::PostThreadMessage(reply_thread_id, WM_RUN_TASK, 0,
- reinterpret_cast<LPARAM>(reply_task_ptr))) {
- delete reply_task_ptr;
- }
- });
-}
-
-void TaskQueue::Impl::RunPendingTasks() {
+void TaskQueueWin::RunPendingTasks() {
while (true) {
std::unique_ptr<QueuedTask> task;
{
@@ -357,12 +271,12 @@
}
// static
-void TaskQueue::Impl::ThreadMain(void* context) {
- ThreadState state(static_cast<TaskQueue::Impl*>(context)->in_queue_);
- state.RunThreadMain();
+void TaskQueueWin::ThreadMain(void* context) {
+ static_cast<TaskQueueWin*>(context)->RunThreadMain();
}
-void TaskQueue::Impl::ThreadState::RunThreadMain() {
+void TaskQueueWin::RunThreadMain() {
+ CurrentTaskQueueSetter set_current(this);
HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_};
while (true) {
// Make sure we do an alertable wait as that's required to allow APCs to run
@@ -388,12 +302,12 @@
if (result == (WAIT_OBJECT_0 + 1)) {
::ResetEvent(in_queue_);
- TaskQueue::Impl::Current()->RunPendingTasks();
+ RunPendingTasks();
}
}
}
-bool TaskQueue::Impl::ThreadState::ProcessQueuedMessages() {
+bool TaskQueueWin::ProcessQueuedMessages() {
MSG msg = {};
// To protect against overly busy message queues, we limit the time
// we process tasks to a few milliseconds. If we don't do that, there's
@@ -447,7 +361,7 @@
return msg.message != WM_QUIT;
}
-void TaskQueue::Impl::ThreadState::RunDueTasks() {
+void TaskQueueWin::RunDueTasks() {
RTC_DCHECK(!timer_tasks_.empty());
auto now = GetTick();
do {
@@ -459,7 +373,7 @@
} while (!timer_tasks_.empty());
}
-void TaskQueue::Impl::ThreadState::ScheduleNextTimer() {
+void TaskQueueWin::ScheduleNextTimer() {
RTC_DCHECK_EQ(timer_id_, 0);
if (timer_tasks_.empty())
return;
@@ -471,7 +385,7 @@
timer_id_ = ::SetTimer(nullptr, 0, milliseconds, nullptr);
}
-void TaskQueue::Impl::ThreadState::CancelTimers() {
+void TaskQueueWin::CancelTimers() {
timer_.Cancel();
if (timer_id_) {
::KillTimer(nullptr, timer_id_);
@@ -479,43 +393,20 @@
}
}
-// Boilerplate for the PIMPL pattern.
-TaskQueue::TaskQueue(const char* queue_name, Priority priority)
- : impl_(new RefCountedObject<TaskQueue::Impl>(queue_name, this, priority)) {
+class TaskQueueWinFactory : public TaskQueueFactory {
+ public:
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const override {
+ return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
+ new TaskQueueWin(name, TaskQueuePriorityToThreadPriority(priority)));
+ }
+};
+
+} // namespace
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory() {
+ return absl::make_unique<TaskQueueWinFactory>();
}
-TaskQueue::~TaskQueue() {}
-
-// static
-TaskQueue* TaskQueue::Current() {
- return TaskQueue::Impl::CurrentQueue();
-}
-
-// Used for DCHECKing the current queue.
-bool TaskQueue::IsCurrent() const {
- return impl_->IsCurrent();
-}
-
-void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
- return TaskQueue::impl_->PostTask(std::move(task));
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply,
- TaskQueue* reply_queue) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- reply_queue->impl_.get());
-}
-
-void TaskQueue::PostTaskAndReply(std::unique_ptr<QueuedTask> task,
- std::unique_ptr<QueuedTask> reply) {
- return TaskQueue::impl_->PostTaskAndReply(std::move(task), std::move(reply),
- impl_.get());
-}
-
-void TaskQueue::PostDelayedTask(std::unique_ptr<QueuedTask> task,
- uint32_t milliseconds) {
- return TaskQueue::impl_->PostDelayedTask(std::move(task), milliseconds);
-}
-
-} // namespace rtc
+} // namespace webrtc
diff --git a/rtc_base/task_queue_win.h b/rtc_base/task_queue_win.h
new file mode 100644
index 0000000..972611a
--- /dev/null
+++ b/rtc_base/task_queue_win.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_QUEUE_WIN_H_
+#define RTC_BASE_TASK_QUEUE_WIN_H_
+
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+
+namespace webrtc {
+
+std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory();
+
+}
+
+#endif // RTC_BASE_TASK_QUEUE_WIN_H_
diff --git a/rtc_base/task_utils/BUILD.gn b/rtc_base/task_utils/BUILD.gn
new file mode 100644
index 0000000..0ec6739
--- /dev/null
+++ b/rtc_base/task_utils/BUILD.gn
@@ -0,0 +1,64 @@
+# 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.
+
+import("../../webrtc.gni")
+
+rtc_source_set("repeating_task") {
+ sources = [
+ "repeating_task.cc",
+ "repeating_task.h",
+ ]
+ deps = [
+ "..:logging",
+ "..:rtc_task_queue",
+ "..:sequenced_task_checker",
+ "..:thread_checker",
+ "..:timeutils",
+ "../../api/units:time_delta",
+ "../../api/units:timestamp",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+}
+
+rtc_source_set("to_queued_task") {
+ sources = [
+ "to_queued_task.h",
+ ]
+ deps = [
+ "../../api/task_queue",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("repeating_task_unittests") {
+ testonly = true
+ sources = [
+ "repeating_task_unittest.cc",
+ ]
+ deps = [
+ ":repeating_task",
+ "..:rtc_base_approved",
+ "../../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+ }
+
+ rtc_source_set("to_queued_task_unittests") {
+ testonly = true
+ sources = [
+ "to_queued_task_unittest.cc",
+ ]
+ deps = [
+ ":to_queued_task",
+ "../../api/task_queue",
+ "../../test:test_support",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+ }
+}
diff --git a/rtc_base/task_utils/repeating_task.cc b/rtc_base/task_utils/repeating_task.cc
new file mode 100644
index 0000000..5f366cb
--- /dev/null
+++ b/rtc_base/task_utils/repeating_task.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright 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 "rtc_base/task_utils/repeating_task.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+namespace webrtc_repeating_task_impl {
+RepeatingTaskBase::RepeatingTaskBase(rtc::TaskQueue* task_queue,
+ TimeDelta first_delay)
+ : task_queue_(task_queue),
+ next_run_time_(Timestamp::us(rtc::TimeMicros()) + first_delay) {}
+
+RepeatingTaskBase::~RepeatingTaskBase() = default;
+
+bool RepeatingTaskBase::Run() {
+ RTC_DCHECK_RUN_ON(task_queue_);
+ // Return true to tell the TaskQueue to destruct this object.
+ if (next_run_time_.IsPlusInfinity())
+ return true;
+
+ TimeDelta delay = RunClosure();
+ RTC_DCHECK(delay.IsFinite());
+
+ // The closure might have stopped this task, in which case we return true to
+ // destruct this object.
+ if (next_run_time_.IsPlusInfinity())
+ return true;
+
+ TimeDelta lost_time = Timestamp::us(rtc::TimeMicros()) - next_run_time_;
+ next_run_time_ += delay;
+ delay -= lost_time;
+ delay = std::max(delay, TimeDelta::Zero());
+
+ task_queue_->PostDelayedTask(absl::WrapUnique(this), delay.ms());
+
+ // Return false to tell the TaskQueue to not destruct this object since we
+ // have taken ownership with absl::WrapUnique.
+ return false;
+}
+
+void RepeatingTaskBase::Stop() {
+ RTC_DCHECK(next_run_time_.IsFinite());
+ next_run_time_ = Timestamp::PlusInfinity();
+}
+
+void RepeatingTaskBase::PostStop() {
+ if (task_queue_->IsCurrent()) {
+ RTC_DLOG(LS_INFO) << "Using PostStop() from the task queue running the "
+ "repeated task. Consider calling Stop() instead.";
+ }
+ task_queue_->PostTask([this] {
+ RTC_DCHECK_RUN_ON(task_queue_);
+ Stop();
+ });
+}
+
+} // namespace webrtc_repeating_task_impl
+RepeatingTaskHandle::RepeatingTaskHandle() {
+ sequence_checker_.Detach();
+}
+RepeatingTaskHandle::~RepeatingTaskHandle() {
+ sequence_checker_.Detach();
+}
+
+RepeatingTaskHandle::RepeatingTaskHandle(RepeatingTaskHandle&& other)
+ : repeating_task_(other.repeating_task_) {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ other.repeating_task_ = nullptr;
+}
+
+RepeatingTaskHandle& RepeatingTaskHandle::operator=(
+ RepeatingTaskHandle&& other) {
+ RTC_DCHECK_RUN_ON(&other.sequence_checker_);
+ {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ repeating_task_ = other.repeating_task_;
+ }
+ other.repeating_task_ = nullptr;
+ return *this;
+}
+
+RepeatingTaskHandle::RepeatingTaskHandle(
+ webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task)
+ : repeating_task_(repeating_task) {}
+
+void RepeatingTaskHandle::Stop() {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ if (repeating_task_) {
+ RTC_DCHECK_RUN_ON(repeating_task_->task_queue_);
+ repeating_task_->Stop();
+ repeating_task_ = nullptr;
+ }
+}
+
+void RepeatingTaskHandle::PostStop() {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ if (repeating_task_) {
+ repeating_task_->PostStop();
+ repeating_task_ = nullptr;
+ }
+}
+
+bool RepeatingTaskHandle::Running() const {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ return repeating_task_ != nullptr;
+}
+
+} // namespace webrtc
diff --git a/rtc_base/task_utils/repeating_task.h b/rtc_base/task_utils/repeating_task.h
new file mode 100644
index 0000000..c4e760a
--- /dev/null
+++ b/rtc_base/task_utils/repeating_task.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
+#define RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/sequenced_task_checker.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/thread_checker.h"
+
+namespace webrtc {
+
+class RepeatingTaskHandle;
+
+namespace webrtc_repeating_task_impl {
+class RepeatingTaskBase : public rtc::QueuedTask {
+ public:
+ RepeatingTaskBase(rtc::TaskQueue* task_queue, TimeDelta first_delay);
+ ~RepeatingTaskBase() override;
+ virtual TimeDelta RunClosure() = 0;
+
+ private:
+ friend class ::webrtc::RepeatingTaskHandle;
+
+ bool Run() final;
+ void Stop() RTC_RUN_ON(task_queue_);
+ void PostStop();
+
+ rtc::TaskQueue* const task_queue_;
+ // This is always finite, except for the special case where it's PlusInfinity
+ // to signal that the task should stop.
+ Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_);
+};
+
+// The template closure pattern is based on rtc::ClosureTask.
+template <class Closure>
+class RepeatingTaskImpl final : public RepeatingTaskBase {
+ public:
+ RepeatingTaskImpl(rtc::TaskQueue* task_queue,
+ TimeDelta first_delay,
+ Closure&& closure)
+ : RepeatingTaskBase(task_queue, first_delay),
+ closure_(std::forward<Closure>(closure)) {
+ static_assert(
+ std::is_same<TimeDelta,
+ typename std::result_of<decltype (&Closure::operator())(
+ Closure)>::type>::value,
+ "");
+ }
+
+ TimeDelta RunClosure() override { return closure_(); }
+
+ private:
+ typename std::remove_const<
+ typename std::remove_reference<Closure>::type>::type closure_;
+};
+} // namespace webrtc_repeating_task_impl
+
+// Allows starting tasks that repeat themselves on a TaskQueue indefinately
+// until they are stopped or the TaskQueue is destroyed. It allows starting and
+// stopping multiple times, but you must stop one task before starting another
+// and it can only be stopped when in the running state. The public interface is
+// not thread safe.
+class RepeatingTaskHandle {
+ public:
+ RepeatingTaskHandle();
+ ~RepeatingTaskHandle();
+ RepeatingTaskHandle(RepeatingTaskHandle&& other);
+ RepeatingTaskHandle& operator=(RepeatingTaskHandle&& other);
+ RepeatingTaskHandle(const RepeatingTaskHandle&) = delete;
+ RepeatingTaskHandle& operator=(const RepeatingTaskHandle&) = delete;
+
+ // Start can be used to start a task that will be reposted with a delay
+ // determined by the return value of the provided closure. The actual task is
+ // owned by the TaskQueue and will live until it has been stopped or the
+ // TaskQueue is destroyed. Note that this means that trying to stop the
+ // repeating task after the TaskQueue is destroyed is an error. However, it's
+ // perfectly fine to destroy the handle while the task is running, since the
+ // repeated task is owned by the TaskQueue.
+ template <class Closure>
+ static RepeatingTaskHandle Start(rtc::TaskQueue* task_queue,
+ Closure&& closure) {
+ auto repeating_task = absl::make_unique<
+ webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
+ task_queue, TimeDelta::Zero(), std::forward<Closure>(closure));
+ auto* repeating_task_ptr = repeating_task.get();
+ task_queue->PostTask(std::move(repeating_task));
+ return RepeatingTaskHandle(repeating_task_ptr);
+ }
+ template <class Closure>
+ static RepeatingTaskHandle Start(Closure&& closure) {
+ return Start(rtc::TaskQueue::Current(), std::forward<Closure>(closure));
+ }
+
+ // DelayedStart is equivalent to Start except that the first invocation of the
+ // closure will be delayed by the given amount.
+ template <class Closure>
+ static RepeatingTaskHandle DelayedStart(rtc::TaskQueue* task_queue,
+ TimeDelta first_delay,
+ Closure&& closure) {
+ auto repeating_task = absl::make_unique<
+ webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
+ task_queue, first_delay, std::forward<Closure>(closure));
+ auto* repeating_task_ptr = repeating_task.get();
+ task_queue->PostDelayedTask(std::move(repeating_task), first_delay.ms());
+ return RepeatingTaskHandle(repeating_task_ptr);
+ }
+ template <class Closure>
+ static RepeatingTaskHandle DelayedStart(TimeDelta first_delay,
+ Closure&& closure) {
+ return DelayedStart(rtc::TaskQueue::Current(), first_delay,
+ std::forward<Closure>(closure));
+ }
+
+ // Stops future invocations of the repeating task closure. Can only be called
+ // from the TaskQueue where the task is running. The closure is guaranteed to
+ // not be running after Stop() returns unless Stop() is called from the
+ // closure itself.
+ void Stop();
+
+ // Stops future invocations of the repeating task closure. The closure might
+ // still be running when PostStop() returns, but there will be no future
+ // invocation.
+ void PostStop();
+
+ // Returns true if Start() or DelayedStart() was called most recently. Returns
+ // false initially and if Stop() or PostStop() was called most recently.
+ bool Running() const;
+
+ private:
+ explicit RepeatingTaskHandle(
+ webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task);
+ rtc::SequencedTaskChecker sequence_checker_;
+ // Owned by the task queue.
+ webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task_
+ RTC_GUARDED_BY(sequence_checker_) = nullptr;
+};
+
+} // namespace webrtc
+#endif // RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
diff --git a/rtc_base/task_utils/repeating_task_unittest.cc b/rtc_base/task_utils/repeating_task_unittest.cc
new file mode 100644
index 0000000..52683e3
--- /dev/null
+++ b/rtc_base/task_utils/repeating_task_unittest.cc
@@ -0,0 +1,224 @@
+/*
+ * Copyright 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 <atomic>
+#include <chrono> // Not allowed in production per Chromium style guide.
+#include <memory>
+#include <thread> // Not allowed in production per Chromium style guide.
+
+#include "absl/memory/memory.h"
+#include "rtc_base/event.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+// NOTE: Since these tests rely on real time behavior, they will be flaky
+// if run on heavily loaded systems.
+namespace webrtc {
+namespace {
+using ::testing::AtLeast;
+using ::testing::Invoke;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+constexpr TimeDelta kTimeout = TimeDelta::Millis<1000>();
+
+void Sleep(TimeDelta time_delta) {
+ // Note that Chromium style guide prohibits use of <thread> and <chrono> in
+ // production code, used here since webrtc::SleepMs may return early.
+ std::this_thread::sleep_for(std::chrono::microseconds(time_delta.us()));
+}
+
+class MockClosure {
+ public:
+ MOCK_METHOD0(Call, TimeDelta());
+ MOCK_METHOD0(Delete, void());
+};
+
+class MoveOnlyClosure {
+ public:
+ explicit MoveOnlyClosure(MockClosure* mock) : mock_(mock) {}
+ MoveOnlyClosure(const MoveOnlyClosure&) = delete;
+ MoveOnlyClosure(MoveOnlyClosure&& other) : mock_(other.mock_) {
+ other.mock_ = nullptr;
+ }
+ ~MoveOnlyClosure() {
+ if (mock_)
+ mock_->Delete();
+ }
+ TimeDelta operator()() { return mock_->Call(); }
+
+ private:
+ MockClosure* mock_;
+};
+} // namespace
+
+TEST(RepeatingTaskTest, TaskIsStoppedOnStop) {
+ const TimeDelta kShortInterval = TimeDelta::ms(5);
+ const TimeDelta kLongInterval = TimeDelta::ms(20);
+ const int kShortIntervalCount = 4;
+ const int kMargin = 1;
+
+ rtc::TaskQueue task_queue("TestQueue");
+ std::atomic_int counter(0);
+ auto handle = RepeatingTaskHandle::Start(&task_queue, [&] {
+ if (++counter >= kShortIntervalCount)
+ return kLongInterval;
+ return kShortInterval;
+ });
+ // Sleep long enough to go through the initial phase.
+ Sleep(kShortInterval * (kShortIntervalCount + kMargin));
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+
+ handle.PostStop();
+ // Sleep long enough that the task would run at least once more if not
+ // stopped.
+ Sleep(kLongInterval * 2);
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+}
+
+TEST(RepeatingTaskTest, CompensatesForLongRunTime) {
+ const int kTargetCount = 20;
+ const int kTargetCountMargin = 2;
+ const TimeDelta kRepeatInterval = TimeDelta::ms(2);
+ // Sleeping inside the task for longer than the repeat interval once, should
+ // be compensated for by repeating the task faster to catch up.
+ const TimeDelta kSleepDuration = TimeDelta::ms(20);
+ const int kSleepAtCount = 3;
+
+ std::atomic_int counter(0);
+ rtc::TaskQueue task_queue("TestQueue");
+ RepeatingTaskHandle::Start(&task_queue, [&] {
+ if (++counter == kSleepAtCount)
+ Sleep(kSleepDuration);
+ return kRepeatInterval;
+ });
+ Sleep(kRepeatInterval * kTargetCount);
+ // Execution time should not have affected the run count,
+ // but we allow some margin to reduce flakiness.
+ EXPECT_GE(counter.load(), kTargetCount - kTargetCountMargin);
+}
+
+TEST(RepeatingTaskTest, CompensatesForShortRunTime) {
+ std::atomic_int counter(0);
+ rtc::TaskQueue task_queue("TestQueue");
+ RepeatingTaskHandle::Start(&task_queue, [&] {
+ ++counter;
+ // Sleeping for the 10 ms should be compensated.
+ Sleep(TimeDelta::ms(10));
+ return TimeDelta::ms(30);
+ });
+ Sleep(TimeDelta::ms(40));
+
+ // We expect that the task have been called twice, once directly at Start and
+ // once after 30 ms has passed.
+ EXPECT_EQ(counter.load(), 2);
+}
+
+TEST(RepeatingTaskTest, CancelDelayedTaskBeforeItRuns) {
+ rtc::Event done;
+ MockClosure mock;
+ EXPECT_CALL(mock, Call).Times(0);
+ EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
+ rtc::TaskQueue task_queue("queue");
+ auto handle = RepeatingTaskHandle::DelayedStart(
+ &task_queue, TimeDelta::ms(100), MoveOnlyClosure(&mock));
+ handle.PostStop();
+ EXPECT_TRUE(done.Wait(kTimeout.ms()));
+}
+
+TEST(RepeatingTaskTest, CancelTaskAfterItRuns) {
+ rtc::Event done;
+ MockClosure mock;
+ EXPECT_CALL(mock, Call).WillOnce(Return(TimeDelta::ms(100)));
+ EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
+ rtc::TaskQueue task_queue("queue");
+ auto handle = RepeatingTaskHandle::Start(&task_queue, MoveOnlyClosure(&mock));
+ handle.PostStop();
+ EXPECT_TRUE(done.Wait(kTimeout.ms()));
+}
+
+TEST(RepeatingTaskTest, TaskCanStopItself) {
+ std::atomic_int counter(0);
+ rtc::TaskQueue task_queue("TestQueue");
+ RepeatingTaskHandle handle;
+ task_queue.PostTask([&] {
+ handle = RepeatingTaskHandle::Start(&task_queue, [&] {
+ ++counter;
+ handle.Stop();
+ return TimeDelta::ms(2);
+ });
+ });
+ Sleep(TimeDelta::ms(10));
+ EXPECT_EQ(counter.load(), 1);
+}
+
+TEST(RepeatingTaskTest, ZeroReturnValueRepostsTheTask) {
+ NiceMock<MockClosure> closure;
+ rtc::Event done;
+ EXPECT_CALL(closure, Call())
+ .WillOnce(Return(TimeDelta::Zero()))
+ .WillOnce(Invoke([&done] {
+ done.Set();
+ return kTimeout;
+ }));
+ rtc::TaskQueue task_queue("queue");
+ RepeatingTaskHandle::Start(&task_queue, MoveOnlyClosure(&closure));
+ EXPECT_TRUE(done.Wait(kTimeout.ms()));
+}
+
+TEST(RepeatingTaskTest, StartPeriodicTask) {
+ MockFunction<TimeDelta()> closure;
+ rtc::Event done;
+ EXPECT_CALL(closure, Call())
+ .WillOnce(Return(TimeDelta::ms(20)))
+ .WillOnce(Return(TimeDelta::ms(20)))
+ .WillOnce(Invoke([&done] {
+ done.Set();
+ return kTimeout;
+ }));
+ rtc::TaskQueue task_queue("queue");
+ RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction());
+ EXPECT_TRUE(done.Wait(kTimeout.ms()));
+}
+
+TEST(RepeatingTaskTest, Example) {
+ class ObjectOnTaskQueue {
+ public:
+ void DoPeriodicTask() {}
+ TimeDelta TimeUntilNextRun() { return TimeDelta::ms(100); }
+ void StartPeriodicTask(RepeatingTaskHandle* handle,
+ rtc::TaskQueue* task_queue) {
+ *handle = RepeatingTaskHandle::Start(task_queue, [this] {
+ DoPeriodicTask();
+ return TimeUntilNextRun();
+ });
+ }
+ };
+ rtc::TaskQueue task_queue("queue");
+ auto object = absl::make_unique<ObjectOnTaskQueue>();
+ // Create and start the periodic task.
+ RepeatingTaskHandle handle;
+ object->StartPeriodicTask(&handle, &task_queue);
+ // Restart the task
+ handle.PostStop();
+ object->StartPeriodicTask(&handle, &task_queue);
+ handle.PostStop();
+ struct Destructor {
+ void operator()() { object.reset(); }
+ std::unique_ptr<ObjectOnTaskQueue> object;
+ };
+ task_queue.PostTask(Destructor{std::move(object)});
+ // Do not wait for the destructor closure in order to create a race between
+ // task queue destruction and running the desctructor closure.
+}
+
+} // namespace webrtc
diff --git a/rtc_base/task_utils/to_queued_task.h b/rtc_base/task_utils/to_queued_task.h
new file mode 100644
index 0000000..5088af9
--- /dev/null
+++ b/rtc_base/task_utils/to_queued_task.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef RTC_BASE_TASK_UTILS_TO_QUEUED_TASK_H_
+#define RTC_BASE_TASK_UTILS_TO_QUEUED_TASK_H_
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "api/task_queue/queued_task.h"
+
+namespace webrtc {
+namespace webrtc_new_closure_impl {
+// Simple implementation of QueuedTask for use with rtc::Bind and lambdas.
+template <typename Closure>
+class ClosureTask : public QueuedTask {
+ public:
+ explicit ClosureTask(Closure&& closure)
+ : closure_(std::forward<Closure>(closure)) {}
+
+ private:
+ bool Run() override {
+ closure_();
+ return true;
+ }
+
+ typename std::decay<Closure>::type closure_;
+};
+
+// Extends ClosureTask to also allow specifying cleanup code.
+// This is useful when using lambdas if guaranteeing cleanup, even if a task
+// was dropped (queue is too full), is required.
+template <typename Closure, typename Cleanup>
+class ClosureTaskWithCleanup : public ClosureTask<Closure> {
+ public:
+ ClosureTaskWithCleanup(Closure&& closure, Cleanup&& cleanup)
+ : ClosureTask<Closure>(std::forward<Closure>(closure)),
+ cleanup_(std::forward<Cleanup>(cleanup)) {}
+ ~ClosureTaskWithCleanup() override { cleanup_(); }
+
+ private:
+ typename std::decay<Cleanup>::type cleanup_;
+};
+} // namespace webrtc_new_closure_impl
+
+// Convenience function to construct closures that can be passed directly
+// to methods that support std::unique_ptr<QueuedTask> but not template
+// based parameters.
+template <typename Closure>
+std::unique_ptr<QueuedTask> ToQueuedTask(Closure&& closure) {
+ return absl::make_unique<webrtc_new_closure_impl::ClosureTask<Closure>>(
+ std::forward<Closure>(closure));
+}
+
+template <typename Closure, typename Cleanup>
+std::unique_ptr<QueuedTask> ToQueuedTask(Closure&& closure, Cleanup&& cleanup) {
+ return absl::make_unique<
+ webrtc_new_closure_impl::ClosureTaskWithCleanup<Closure, Cleanup>>(
+ std::forward<Closure>(closure), std::forward<Cleanup>(cleanup));
+}
+
+} // namespace webrtc
+
+#endif // RTC_BASE_TASK_UTILS_TO_QUEUED_TASK_H_
diff --git a/rtc_base/task_utils/to_queued_task_unittest.cc b/rtc_base/task_utils/to_queued_task_unittest.cc
new file mode 100644
index 0000000..45dec77
--- /dev/null
+++ b/rtc_base/task_utils/to_queued_task_unittest.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 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 "rtc_base/task_utils/to_queued_task.h"
+
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "api/task_queue/queued_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::InSequence;
+using ::testing::MockFunction;
+
+void RunTask(std::unique_ptr<QueuedTask> task) {
+ // Simulate how task queue suppose to run tasks.
+ QueuedTask* raw = task.release();
+ if (raw->Run())
+ delete raw;
+}
+
+TEST(ToQueuedTaskTest, AcceptsLambda) {
+ bool run = false;
+ std::unique_ptr<QueuedTask> task = ToQueuedTask([&run] { run = true; });
+ EXPECT_FALSE(run);
+ RunTask(std::move(task));
+ EXPECT_TRUE(run);
+}
+
+TEST(ToQueuedTaskTest, AcceptsCopyableClosure) {
+ struct CopyableClosure {
+ CopyableClosure(int* num_copies, int* num_moves, int* num_runs)
+ : num_copies(num_copies), num_moves(num_moves), num_runs(num_runs) {}
+ CopyableClosure(const CopyableClosure& other)
+ : num_copies(other.num_copies),
+ num_moves(other.num_moves),
+ num_runs(other.num_runs) {
+ ++*num_copies;
+ }
+ CopyableClosure(CopyableClosure&& other)
+ : num_copies(other.num_copies),
+ num_moves(other.num_moves),
+ num_runs(other.num_runs) {
+ ++*num_moves;
+ }
+ void operator()() { ++*num_runs; }
+
+ int* num_copies;
+ int* num_moves;
+ int* num_runs;
+ };
+
+ int num_copies = 0;
+ int num_moves = 0;
+ int num_runs = 0;
+
+ std::unique_ptr<QueuedTask> task;
+ {
+ CopyableClosure closure(&num_copies, &num_moves, &num_runs);
+ task = ToQueuedTask(closure);
+ // Destroy closure to check with msan task has own copy.
+ }
+ EXPECT_EQ(num_copies, 1);
+ EXPECT_EQ(num_runs, 0);
+ RunTask(std::move(task));
+ EXPECT_EQ(num_copies, 1);
+ EXPECT_EQ(num_moves, 0);
+ EXPECT_EQ(num_runs, 1);
+}
+
+TEST(ToQueuedTaskTest, AcceptsMoveOnlyClosure) {
+ struct MoveOnlyClosure {
+ MoveOnlyClosure(int* num_moves, std::function<void()> trigger)
+ : num_moves(num_moves), trigger(std::move(trigger)) {}
+ MoveOnlyClosure(const MoveOnlyClosure&) = delete;
+ MoveOnlyClosure(MoveOnlyClosure&& other)
+ : num_moves(other.num_moves), trigger(std::move(other.trigger)) {
+ ++*num_moves;
+ }
+ void operator()() { trigger(); }
+
+ int* num_moves;
+ std::function<void()> trigger;
+ };
+
+ int num_moves = 0;
+ MockFunction<void()> run;
+
+ auto task = ToQueuedTask(MoveOnlyClosure(&num_moves, run.AsStdFunction()));
+ EXPECT_EQ(num_moves, 1);
+ EXPECT_CALL(run, Call);
+ RunTask(std::move(task));
+ EXPECT_EQ(num_moves, 1);
+}
+
+TEST(ToQueuedTaskTest, AcceptsMoveOnlyCleanup) {
+ struct MoveOnlyClosure {
+ MoveOnlyClosure(const MoveOnlyClosure&) = delete;
+ MoveOnlyClosure(MoveOnlyClosure&&) = default;
+ void operator()() { trigger(); }
+
+ std::function<void()> trigger;
+ };
+
+ MockFunction<void()> run;
+ MockFunction<void()> cleanup;
+
+ auto task = ToQueuedTask(MoveOnlyClosure{run.AsStdFunction()},
+ MoveOnlyClosure{cleanup.AsStdFunction()});
+
+ // Expect run closure to complete before cleanup closure.
+ InSequence in_sequence;
+ EXPECT_CALL(run, Call);
+ EXPECT_CALL(cleanup, Call);
+ RunTask(std::move(task));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/rtc_base/testbase64.h b/rtc_base/test_base64.h
similarity index 99%
rename from rtc_base/testbase64.h
rename to rtc_base/test_base64.h
index 5dc94b6..51d8c58 100644
--- a/rtc_base/testbase64.h
+++ b/rtc_base/test_base64.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TESTBASE64_H_
-#define RTC_BASE_TESTBASE64_H_
+#ifndef RTC_BASE_TEST_BASE64_H_
+#define RTC_BASE_TEST_BASE64_H_
/* This file was generated by googleclient/talk/binary2header.sh */
@@ -2108,4 +2108,4 @@
0xba, 0x5b, 0xfe, 0x97, 0xfa, 0x4b, 0xfc, 0xba, 0x7f, 0xb1, 0xc7, 0xab,
0x1e, 0x8f, 0xff, 0xd9};
-#endif // RTC_BASE_TESTBASE64_H_
+#endif // RTC_BASE_TEST_BASE64_H_
diff --git a/rtc_base/testcertificateverifier.h b/rtc_base/test_certificate_verifier.h
similarity index 81%
rename from rtc_base/testcertificateverifier.h
rename to rtc_base/test_certificate_verifier.h
index 8ad6e4d..9775615 100644
--- a/rtc_base/testcertificateverifier.h
+++ b/rtc_base/test_certificate_verifier.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TESTCERTIFICATEVERIFIER_H_
-#define RTC_BASE_TESTCERTIFICATEVERIFIER_H_
+#ifndef RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_
+#define RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_
-#include "rtc_base/sslcertificate.h"
+#include "rtc_base/ssl_certificate.h"
namespace rtc {
@@ -31,4 +31,4 @@
} // namespace rtc
-#endif // RTC_BASE_TESTCERTIFICATEVERIFIER_H_
+#endif // RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_
diff --git a/rtc_base/testclient.cc b/rtc_base/test_client.cc
similarity index 97%
rename from rtc_base/testclient.cc
rename to rtc_base/test_client.cc
index a5b90dd..274b6ca 100644
--- a/rtc_base/testclient.cc
+++ b/rtc_base/test_client.cc
@@ -8,12 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/testclient.h"
+#include "rtc_base/test_client.h"
+
+#include <string.h>
+#include <utility>
#include "absl/memory/memory.h"
#include "rtc_base/gunit.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/testclient.h b/rtc_base/test_client.h
similarity index 93%
rename from rtc_base/testclient.h
rename to rtc_base/test_client.h
index 16fb6ba..fb8a2f9 100644
--- a/rtc_base/testclient.h
+++ b/rtc_base/test_client.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TESTCLIENT_H_
-#define RTC_BASE_TESTCLIENT_H_
+#ifndef RTC_BASE_TEST_CLIENT_H_
+#define RTC_BASE_TEST_CLIENT_H_
#include <memory>
#include <vector>
-#include "rtc_base/asyncudpsocket.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/async_udp_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/fake_clock.h"
namespace rtc {
@@ -113,4 +113,4 @@
} // namespace rtc
-#endif // RTC_BASE_TESTCLIENT_H_
+#endif // RTC_BASE_TEST_CLIENT_H_
diff --git a/rtc_base/testclient_unittest.cc b/rtc_base/test_client_unittest.cc
similarity index 87%
rename from rtc_base/testclient_unittest.cc
rename to rtc_base/test_client_unittest.cc
index b3a6c80..382aaaf 100644
--- a/rtc_base/testclient_unittest.cc
+++ b/rtc_base/test_client_unittest.cc
@@ -8,15 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/testclient.h"
-#include "absl/memory/memory.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/nethelpers.h"
-#include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/testechoserver.h"
-#include "rtc_base/thread.h"
+#include "rtc_base/test_client.h"
-using namespace rtc;
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/async_tcp_socket.h"
+#include "rtc_base/async_udp_socket.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/socket_server.h"
+#include "rtc_base/test_echo_server.h"
+#include "rtc_base/thread.h"
+#include "test/gtest.h"
+
+namespace rtc {
+namespace {
#define MAYBE_SKIP_IPV4 \
if (!HasIPv4Enabled()) { \
@@ -94,3 +102,6 @@
MAYBE_SKIP_IPV6;
TestTcpInternal(SocketAddress("::1", 0));
}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/testechoserver.cc b/rtc_base/test_echo_server.cc
similarity index 92%
rename from rtc_base/testechoserver.cc
rename to rtc_base/test_echo_server.cc
index a5eb7de..d2e11d6 100644
--- a/rtc_base/testechoserver.cc
+++ b/rtc_base/test_echo_server.cc
@@ -8,7 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/testechoserver.h"
+#include "rtc_base/test_echo_server.h"
+
+#include "rtc_base/socket_server.h"
namespace rtc {
diff --git a/rtc_base/testechoserver.h b/rtc_base/test_echo_server.h
similarity index 82%
rename from rtc_base/testechoserver.h
rename to rtc_base/test_echo_server.h
index 9ffd786..4710560 100644
--- a/rtc_base/testechoserver.h
+++ b/rtc_base/test_echo_server.h
@@ -8,15 +8,21 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TESTECHOSERVER_H_
-#define RTC_BASE_TESTECHOSERVER_H_
+#ifndef RTC_BASE_TEST_ECHO_SERVER_H_
+#define RTC_BASE_TEST_ECHO_SERVER_H_
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
#include <list>
#include <memory>
-#include "rtc_base/asynctcpsocket.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/async_tcp_socket.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
namespace rtc {
@@ -63,4 +69,4 @@
} // namespace rtc
-#endif // RTC_BASE_TESTECHOSERVER_H_
+#endif // RTC_BASE_TEST_ECHO_SERVER_H_
diff --git a/rtc_base/testutils.cc b/rtc_base/test_utils.cc
similarity index 94%
rename from rtc_base/testutils.cc
rename to rtc_base/test_utils.cc
index f3292fd..ecf2cfa 100644
--- a/rtc_base/testutils.cc
+++ b/rtc_base/test_utils.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/testutils.h"
+#include "rtc_base/test_utils.h"
namespace webrtc {
namespace testing {
diff --git a/rtc_base/testutils.h b/rtc_base/test_utils.h
similarity index 73%
rename from rtc_base/testutils.h
rename to rtc_base/test_utils.h
index ac74203..4746e96 100644
--- a/rtc_base/testutils.h
+++ b/rtc_base/test_utils.h
@@ -8,24 +8,21 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TESTUTILS_H_
-#define RTC_BASE_TESTUTILS_H_
+#ifndef RTC_BASE_TEST_UTILS_H_
+#define RTC_BASE_TEST_UTILS_H_
// Utilities for testing rtc infrastructure in unittests
-#include <algorithm>
#include <map>
-#include <memory>
-#include <vector>
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/checks.h"
+#include <utility>
+
+#include "rtc_base/async_socket.h"
#include "rtc_base/stream.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
namespace webrtc {
namespace testing {
-using namespace rtc;
-
///////////////////////////////////////////////////////////////////////////////
// StreamSink - Monitor asynchronously signalled events from StreamInterface
// or AsyncSocket (which should probably be a StreamInterface.
@@ -35,10 +32,10 @@
// event.
enum StreamSinkEvent {
- SSE_OPEN = SE_OPEN,
- SSE_READ = SE_READ,
- SSE_WRITE = SE_WRITE,
- SSE_CLOSE = SE_CLOSE,
+ SSE_OPEN = rtc::SE_OPEN,
+ SSE_READ = rtc::SE_READ,
+ SSE_WRITE = rtc::SE_WRITE,
+ SSE_CLOSE = rtc::SE_CLOSE,
SSE_ERROR = 16
};
@@ -47,25 +44,25 @@
StreamSink();
~StreamSink() override;
- void Monitor(StreamInterface* stream) {
+ void Monitor(rtc::StreamInterface* stream) {
stream->SignalEvent.connect(this, &StreamSink::OnEvent);
events_.erase(stream);
}
- void Unmonitor(StreamInterface* stream) {
+ void Unmonitor(rtc::StreamInterface* stream) {
stream->SignalEvent.disconnect(this);
// In case you forgot to unmonitor a previous object with this address
events_.erase(stream);
}
- bool Check(StreamInterface* stream,
+ bool Check(rtc::StreamInterface* stream,
StreamSinkEvent event,
bool reset = true) {
return DoCheck(stream, event, reset);
}
- int Events(StreamInterface* stream, bool reset = true) {
+ int Events(rtc::StreamInterface* stream, bool reset = true) {
return DoEvents(stream, reset);
}
- void Monitor(AsyncSocket* socket) {
+ void Monitor(rtc::AsyncSocket* socket) {
socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
@@ -73,33 +70,35 @@
// In case you forgot to unmonitor a previous object with this address
events_.erase(socket);
}
- void Unmonitor(AsyncSocket* socket) {
+ void Unmonitor(rtc::AsyncSocket* socket) {
socket->SignalConnectEvent.disconnect(this);
socket->SignalReadEvent.disconnect(this);
socket->SignalWriteEvent.disconnect(this);
socket->SignalCloseEvent.disconnect(this);
events_.erase(socket);
}
- bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) {
+ bool Check(rtc::AsyncSocket* socket,
+ StreamSinkEvent event,
+ bool reset = true) {
return DoCheck(socket, event, reset);
}
- int Events(AsyncSocket* socket, bool reset = true) {
+ int Events(rtc::AsyncSocket* socket, bool reset = true) {
return DoEvents(socket, reset);
}
private:
typedef std::map<void*, int> EventMap;
- void OnEvent(StreamInterface* stream, int events, int error) {
+ void OnEvent(rtc::StreamInterface* stream, int events, int error) {
if (error) {
events = SSE_ERROR;
}
AddEvents(stream, events);
}
- void OnConnectEvent(AsyncSocket* socket) { AddEvents(socket, SSE_OPEN); }
- void OnReadEvent(AsyncSocket* socket) { AddEvents(socket, SSE_READ); }
- void OnWriteEvent(AsyncSocket* socket) { AddEvents(socket, SSE_WRITE); }
- void OnCloseEvent(AsyncSocket* socket, int error) {
+ void OnConnectEvent(rtc::AsyncSocket* socket) { AddEvents(socket, SSE_OPEN); }
+ void OnReadEvent(rtc::AsyncSocket* socket) { AddEvents(socket, SSE_READ); }
+ void OnWriteEvent(rtc::AsyncSocket* socket) { AddEvents(socket, SSE_WRITE); }
+ void OnCloseEvent(rtc::AsyncSocket* socket, int error) {
AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR);
}
@@ -138,4 +137,4 @@
} // namespace testing
} // namespace webrtc
-#endif // RTC_BASE_TESTUTILS_H_
+#endif // RTC_BASE_TEST_UTILS_H_
diff --git a/rtc_base/thread.cc b/rtc_base/thread.cc
index 4dd5fd2..936871c 100644
--- a/rtc_base/thread.cc
+++ b/rtc_base/thread.cc
@@ -28,10 +28,10 @@
#include <utility>
#include "rtc_base/checks.h"
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/logging.h"
-#include "rtc_base/nullsocketserver.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/time_utils.h"
#include "rtc_base/trace_event.h"
#if defined(WEBRTC_MAC)
diff --git a/rtc_base/thread.h b/rtc_base/thread.h
index 039192c..7bb7a3c 100644
--- a/rtc_base/thread.h
+++ b/rtc_base/thread.h
@@ -20,12 +20,12 @@
#if defined(WEBRTC_POSIX)
#include <pthread.h>
#endif
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/location.h"
-#include "rtc_base/messagehandler.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/platform_thread_types.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/socket_server.h"
#include "rtc_base/thread_annotations.h"
#if defined(WEBRTC_WIN)
@@ -36,6 +36,29 @@
class Thread;
+namespace rtc_thread_internal {
+
+template <class FunctorT>
+class SingleMessageHandlerWithFunctor final : public MessageHandler {
+ public:
+ explicit SingleMessageHandlerWithFunctor(FunctorT&& functor)
+ : functor_(std::forward<FunctorT>(functor)) {}
+
+ void OnMessage(Message* msg) override {
+ functor_();
+ delete this;
+ }
+
+ private:
+ ~SingleMessageHandlerWithFunctor() override {}
+
+ typename std::remove_reference<FunctorT>::type functor_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SingleMessageHandlerWithFunctor);
+};
+
+} // namespace rtc_thread_internal
+
class ThreadManager {
public:
static const int kForever = -1;
@@ -183,6 +206,8 @@
// &MyFunctionReturningBool);
// NOTE: This function can only be called when synchronous calls are allowed.
// See ScopedDisallowBlockingCalls for details.
+ // NOTE: Blocking invokes are DISCOURAGED, consider if what you're doing can
+ // be achieved with PostTask() and callbacks instead.
template <class ReturnT, class FunctorT>
ReturnT Invoke(const Location& posted_from, FunctorT&& functor) {
FunctorMessageHandler<ReturnT, FunctorT> handler(
@@ -191,6 +216,44 @@
return handler.MoveResult();
}
+ // Posts a task to invoke the functor on |this| thread asynchronously, i.e.
+ // without blocking the thread that invoked PostTask(). Ownership of |functor|
+ // is passed and destroyed on |this| thread after it is invoked.
+ // Requirements of FunctorT:
+ // - FunctorT is movable.
+ // - FunctorT implements "T operator()()" or "T operator()() const" for some T
+ // (if T is not void, the return value is discarded on |this| thread).
+ // - FunctorT has a public destructor that can be invoked from |this| thread
+ // after operation() has been invoked.
+ // - The functor must not cause the thread to quit before PostTask() is done.
+ //
+ // Example - Calling a class method:
+ // class Foo {
+ // public:
+ // void DoTheThing();
+ // };
+ // Foo foo;
+ // thread->PostTask(RTC_FROM_HERE, Bind(&Foo::DoTheThing, &foo));
+ //
+ // Example - Calling a lambda function:
+ // thread->PostTask(RTC_FROM_HERE,
+ // [&x, &y] { x.TrackComputations(y.Compute()); });
+ template <class FunctorT>
+ void PostTask(const Location& posted_from, FunctorT&& functor) {
+ Post(posted_from,
+ new rtc_thread_internal::SingleMessageHandlerWithFunctor<FunctorT>(
+ std::forward<FunctorT>(functor)));
+ // This DCHECK guarantees that the post was successful.
+ // Post() doesn't say whether it succeeded, but it will only fail if the
+ // thread is quitting. DCHECKing that the thread is not quitting *after*
+ // posting might yield some false positives (where the thread did in fact
+ // quit, but only after posting), but if we have false positives here then
+ // we have a race condition anyway.
+ // TODO(https://crbug.com/webrtc/10364): When Post() returns a bool we can
+ // DCHECK the result instead of inferring success from IsQuitting().
+ RTC_DCHECK(!IsQuitting());
+ }
+
// From MessageQueue
bool IsProcessingMessagesForTesting() override;
void Clear(MessageHandler* phandler,
@@ -219,10 +282,6 @@
// of whatever code is conditionally executing because of the return value!
bool RunningForTest() { return IsRunning(); }
- // Sets the per-thread allow-blocking-calls flag and returns the previous
- // value. Must be called on this thread.
- bool SetAllowBlockingCalls(bool allow);
-
// These functions are public to avoid injecting test hooks. Don't call them
// outside of tests.
// This method should be called when thread is created using non standard
@@ -232,6 +291,17 @@
bool WrapCurrent();
void UnwrapCurrent();
+ // Sets the per-thread allow-blocking-calls flag to false; this is
+ // irrevocable. Must be called on this thread.
+ void DisallowBlockingCalls() { SetAllowBlockingCalls(false); }
+
+#ifdef WEBRTC_ANDROID
+ // Sets the per-thread allow-blocking-calls flag to true, sidestepping the
+ // invariants upheld by DisallowBlockingCalls() and
+ // ScopedDisallowBlockingCalls. Must be called on this thread.
+ void DEPRECATED_AllowBlockingCalls() { SetAllowBlockingCalls(true); }
+#endif
+
protected:
// Same as WrapCurrent except that it never fails as it does not try to
// acquire the synchronization access of the thread. The caller should never
@@ -251,6 +321,10 @@
Runnable* runnable;
};
+ // Sets the per-thread allow-blocking-calls flag and returns the previous
+ // value. Must be called on this thread.
+ bool SetAllowBlockingCalls(bool allow);
+
#if defined(WEBRTC_WIN)
static DWORD WINAPI PreRun(LPVOID context);
#else
diff --git a/rtc_base/thread_checker.h b/rtc_base/thread_checker.h
index ad04508..43f7320 100644
--- a/rtc_base/thread_checker.h
+++ b/rtc_base/thread_checker.h
@@ -20,7 +20,7 @@
#define RTC_ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/thread_checker_impl.h"
@@ -152,12 +152,12 @@
// // Will fail at runtime when DCHECK is enabled:
// // encoder_->Encode();
// // Will work:
-// rtc::scoped_ref_ptr<Encoder> encoder = encoder_;
+// rtc::scoped_refptr<Encoder> encoder = encoder_;
// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
// }
//
// private:
-// rtc::scoped_ref_ptr<Encoder> encoder_;
+// rtc::scoped_refptr<Encoder> encoder_;
// }
// Document if a function expected to be called from same thread/task queue.
diff --git a/rtc_base/thread_checker_impl.h b/rtc_base/thread_checker_impl.h
index c82fe1d..c39e10f 100644
--- a/rtc_base/thread_checker_impl.h
+++ b/rtc_base/thread_checker_impl.h
@@ -13,7 +13,7 @@
#ifndef RTC_BASE_THREAD_CHECKER_IMPL_H_
#define RTC_BASE_THREAD_CHECKER_IMPL_H_
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/platform_thread_types.h"
namespace rtc {
diff --git a/rtc_base/thread_checker_unittest.cc b/rtc_base/thread_checker_unittest.cc
index 9c0942f..a40196f 100644
--- a/rtc_base/thread_checker_unittest.cc
+++ b/rtc_base/thread_checker_unittest.cc
@@ -11,10 +11,12 @@
// Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc.
#include <memory>
+#include <utility>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-#include "rtc_base/nullsocketserver.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/socket_server.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread.h"
#include "rtc_base/thread_checker.h"
diff --git a/rtc_base/thread_unittest.cc b/rtc_base/thread_unittest.cc
index 7e392af..63edcf8 100644
--- a/rtc_base/thread_unittest.cc
+++ b/rtc_base/thread_unittest.cc
@@ -10,13 +10,13 @@
#include <memory>
-#include "rtc_base/asyncinvoker.h"
-#include "rtc_base/asyncudpsocket.h"
+#include "rtc_base/async_invoker.h"
+#include "rtc_base/async_udp_socket.h"
#include "rtc_base/event.h"
#include "rtc_base/gunit.h"
-#include "rtc_base/nullsocketserver.h"
-#include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/socketaddress.h"
+#include "rtc_base/null_socket_server.h"
+#include "rtc_base/physical_socket_server.h"
+#include "rtc_base/socket_address.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
@@ -24,7 +24,8 @@
#include <comdef.h> // NOLINT
#endif
-using namespace rtc;
+namespace rtc {
+namespace {
// Generates a sequence of numbers (collaboratively).
class TestGenerator {
@@ -669,3 +670,231 @@
EXPECT_FALSE(flag1.get());
EXPECT_TRUE(flag2.get());
}
+
+void ThreadIsCurrent(Thread* thread, bool* result, Event* event) {
+ *result = thread->IsCurrent();
+ event->Set();
+}
+
+void WaitAndSetEvent(Event* wait_event, Event* set_event) {
+ wait_event->Wait(Event::kForever);
+ set_event->Set();
+}
+
+// A functor that keeps track of the number of copies and moves.
+class LifeCycleFunctor {
+ public:
+ struct Stats {
+ size_t copy_count = 0;
+ size_t move_count = 0;
+ };
+
+ LifeCycleFunctor(Stats* stats, Event* event) : stats_(stats), event_(event) {}
+ LifeCycleFunctor(const LifeCycleFunctor& other) { *this = other; }
+ LifeCycleFunctor(LifeCycleFunctor&& other) { *this = std::move(other); }
+
+ LifeCycleFunctor& operator=(const LifeCycleFunctor& other) {
+ stats_ = other.stats_;
+ event_ = other.event_;
+ ++stats_->copy_count;
+ return *this;
+ }
+
+ LifeCycleFunctor& operator=(LifeCycleFunctor&& other) {
+ stats_ = other.stats_;
+ event_ = other.event_;
+ ++stats_->move_count;
+ return *this;
+ }
+
+ void operator()() { event_->Set(); }
+
+ private:
+ Stats* stats_;
+ Event* event_;
+};
+
+// A functor that verifies the thread it was destroyed on.
+class DestructionFunctor {
+ public:
+ DestructionFunctor(Thread* thread, bool* thread_was_current, Event* event)
+ : thread_(thread),
+ thread_was_current_(thread_was_current),
+ event_(event) {}
+ ~DestructionFunctor() {
+ // Only signal the event if this was the functor that was invoked to avoid
+ // the event being signaled due to the destruction of temporary/moved
+ // versions of this object.
+ if (was_invoked_) {
+ *thread_was_current_ = thread_->IsCurrent();
+ event_->Set();
+ }
+ }
+
+ void operator()() { was_invoked_ = true; }
+
+ private:
+ Thread* thread_;
+ bool* thread_was_current_;
+ Event* event_;
+ bool was_invoked_ = false;
+};
+
+TEST(ThreadPostTaskTest, InvokesWithBind) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ background_thread->PostTask(RTC_FROM_HERE, Bind(&Event::Set, &event));
+ event.Wait(Event::kForever);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithLambda) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ background_thread->PostTask(RTC_FROM_HERE, [&event] { event.Set(); });
+ event.Wait(Event::kForever);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithCopiedFunctor) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ LifeCycleFunctor::Stats stats;
+ Event event;
+ LifeCycleFunctor functor(&stats, &event);
+ background_thread->PostTask(RTC_FROM_HERE, functor);
+ event.Wait(Event::kForever);
+
+ EXPECT_EQ(1u, stats.copy_count);
+ EXPECT_EQ(0u, stats.move_count);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithMovedFunctor) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ LifeCycleFunctor::Stats stats;
+ Event event;
+ LifeCycleFunctor functor(&stats, &event);
+ background_thread->PostTask(RTC_FROM_HERE, std::move(functor));
+ event.Wait(Event::kForever);
+
+ EXPECT_EQ(0u, stats.copy_count);
+ EXPECT_EQ(1u, stats.move_count);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithReferencedFunctorShouldCopy) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ LifeCycleFunctor::Stats stats;
+ Event event;
+ LifeCycleFunctor functor(&stats, &event);
+ LifeCycleFunctor& functor_ref = functor;
+ background_thread->PostTask(RTC_FROM_HERE, functor_ref);
+ event.Wait(Event::kForever);
+
+ EXPECT_EQ(1u, stats.copy_count);
+ EXPECT_EQ(0u, stats.move_count);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithCopiedFunctorDestroyedOnTargetThread) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ bool was_invoked_on_background_thread = false;
+ DestructionFunctor functor(background_thread.get(),
+ &was_invoked_on_background_thread, &event);
+ background_thread->PostTask(RTC_FROM_HERE, functor);
+ event.Wait(Event::kForever);
+
+ EXPECT_TRUE(was_invoked_on_background_thread);
+}
+
+TEST(ThreadPostTaskTest, InvokesWithMovedFunctorDestroyedOnTargetThread) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ bool was_invoked_on_background_thread = false;
+ DestructionFunctor functor(background_thread.get(),
+ &was_invoked_on_background_thread, &event);
+ background_thread->PostTask(RTC_FROM_HERE, std::move(functor));
+ event.Wait(Event::kForever);
+
+ EXPECT_TRUE(was_invoked_on_background_thread);
+}
+
+TEST(ThreadPostTaskTest,
+ InvokesWithReferencedFunctorShouldCopyAndDestroyedOnTargetThread) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ bool was_invoked_on_background_thread = false;
+ DestructionFunctor functor(background_thread.get(),
+ &was_invoked_on_background_thread, &event);
+ DestructionFunctor& functor_ref = functor;
+ background_thread->PostTask(RTC_FROM_HERE, functor_ref);
+ event.Wait(Event::kForever);
+
+ EXPECT_TRUE(was_invoked_on_background_thread);
+}
+
+TEST(ThreadPostTaskTest, InvokesOnBackgroundThread) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event event;
+ bool was_invoked_on_background_thread = false;
+ background_thread->PostTask(RTC_FROM_HERE,
+ Bind(&ThreadIsCurrent, background_thread.get(),
+ &was_invoked_on_background_thread, &event));
+ event.Wait(Event::kForever);
+
+ EXPECT_TRUE(was_invoked_on_background_thread);
+}
+
+TEST(ThreadPostTaskTest, InvokesAsynchronously) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ // The first event ensures that SendSingleMessage() is not blocking this
+ // thread. The second event ensures that the message is processed.
+ Event event_set_by_test_thread;
+ Event event_set_by_background_thread;
+ background_thread->PostTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &event_set_by_test_thread,
+ &event_set_by_background_thread));
+ event_set_by_test_thread.Set();
+ event_set_by_background_thread.Wait(Event::kForever);
+}
+
+TEST(ThreadPostTaskTest, InvokesInPostedOrder) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event first;
+ Event second;
+ Event third;
+ Event fourth;
+
+ background_thread->PostTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &first, &second));
+ background_thread->PostTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &second, &third));
+ background_thread->PostTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &third, &fourth));
+
+ // All tasks have been posted before the first one is unblocked.
+ first.Set();
+ // Only if the chain is invoked in posted order will the last event be set.
+ fourth.Wait(Event::kForever);
+}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/timeutils.cc b/rtc_base/time_utils.cc
similarity index 99%
rename from rtc_base/timeutils.cc
rename to rtc_base/time_utils.cc
index 0f79a87..53f8b36 100644
--- a/rtc_base/timeutils.cc
+++ b/rtc_base/time_utils.cc
@@ -29,7 +29,7 @@
#endif
#include "rtc_base/checks.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
diff --git a/rtc_base/timeutils.h b/rtc_base/time_utils.h
similarity index 97%
rename from rtc_base/timeutils.h
rename to rtc_base/time_utils.h
index c6ddd73..d1d8b05 100644
--- a/rtc_base/timeutils.h
+++ b/rtc_base/time_utils.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TIMEUTILS_H_
-#define RTC_BASE_TIMEUTILS_H_
+#ifndef RTC_BASE_TIME_UTILS_H_
+#define RTC_BASE_TIME_UTILS_H_
#include <stdint.h>
#include <time.h>
@@ -165,4 +165,4 @@
} // namespace rtc
-#endif // RTC_BASE_TIMEUTILS_H_
+#endif // RTC_BASE_TIME_UTILS_H_
diff --git a/rtc_base/timeutils_unittest.cc b/rtc_base/time_utils_unittest.cc
similarity index 96%
rename from rtc_base/timeutils_unittest.cc
rename to rtc_base/time_utils_unittest.cc
index 577efda..b4cefb7 100644
--- a/rtc_base/timeutils_unittest.cc
+++ b/rtc_base/time_utils_unittest.cc
@@ -8,12 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
+
+#include <memory>
+
+#include "api/units/time_delta.h"
#include "rtc_base/event.h"
-#include "rtc_base/fakeclock.h"
-#include "rtc_base/gunit.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/helpers.h"
+#include "rtc_base/location.h"
+#include "rtc_base/message_handler.h"
#include "rtc_base/thread.h"
+#include "test/gtest.h"
namespace rtc {
@@ -266,7 +272,7 @@
auto functor = [&message_handler_dispatched] {
message_handler_dispatched.Set();
};
- FunctorMessageHandler<void, decltype(functor)> handler(functor);
+ FunctorMessageHandler<void, decltype(functor)> handler(std::move(functor));
worker->PostDelayed(RTC_FROM_HERE, 60000, &handler);
// Wait for a bit for the worker thread to be started and enter its socket
diff --git a/rtc_base/timestampaligner.cc b/rtc_base/timestamp_aligner.cc
similarity index 98%
rename from rtc_base/timestampaligner.cc
rename to rtc_base/timestamp_aligner.cc
index f2da101..3d92dd8 100644
--- a/rtc_base/timestampaligner.cc
+++ b/rtc_base/timestamp_aligner.cc
@@ -13,8 +13,8 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/timestampaligner.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/timestamp_aligner.h"
namespace rtc {
diff --git a/rtc_base/timestampaligner.h b/rtc_base/timestamp_aligner.h
similarity index 94%
rename from rtc_base/timestampaligner.h
rename to rtc_base/timestamp_aligner.h
index 6fa8d69..2146880 100644
--- a/rtc_base/timestampaligner.h
+++ b/rtc_base/timestamp_aligner.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_TIMESTAMPALIGNER_H_
-#define RTC_BASE_TIMESTAMPALIGNER_H_
+#ifndef RTC_BASE_TIMESTAMP_ALIGNER_H_
+#define RTC_BASE_TIMESTAMP_ALIGNER_H_
#include <stdint.h>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
namespace rtc {
@@ -71,4 +71,4 @@
} // namespace rtc
-#endif // RTC_BASE_TIMESTAMPALIGNER_H_
+#endif // RTC_BASE_TIMESTAMP_ALIGNER_H_
diff --git a/rtc_base/timestampaligner_unittest.cc b/rtc_base/timestamp_aligner_unittest.cc
similarity index 98%
rename from rtc_base/timestampaligner_unittest.cc
rename to rtc_base/timestamp_aligner_unittest.cc
index 8ba5be9..f92cd96 100644
--- a/rtc_base/timestampaligner_unittest.cc
+++ b/rtc_base/timestamp_aligner_unittest.cc
@@ -9,13 +9,13 @@
*/
#include <math.h>
-
#include <algorithm>
#include <limits>
-#include "rtc_base/gunit.h"
#include "rtc_base/random.h"
-#include "rtc_base/timestampaligner.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/timestamp_aligner.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/unique_id_generator.cc b/rtc_base/unique_id_generator.cc
new file mode 100644
index 0000000..d41fa8d
--- /dev/null
+++ b/rtc_base/unique_id_generator.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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 "rtc_base/unique_id_generator.h"
+
+#include <limits>
+#include <vector>
+
+#include "rtc_base/helpers.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/string_to_number.h"
+
+namespace rtc {
+
+UniqueRandomIdGenerator::UniqueRandomIdGenerator() : known_ids_() {}
+UniqueRandomIdGenerator::UniqueRandomIdGenerator(ArrayView<uint32_t> known_ids)
+ : known_ids_(known_ids.begin(), known_ids.end()) {}
+
+UniqueRandomIdGenerator::~UniqueRandomIdGenerator() = default;
+
+uint32_t UniqueRandomIdGenerator::GenerateId() {
+ RTC_CHECK_LT(known_ids_.size(), std::numeric_limits<uint32_t>::max() - 1);
+ while (true) {
+ auto pair = known_ids_.insert(CreateRandomNonZeroId());
+ if (pair.second) {
+ return *pair.first;
+ }
+ }
+}
+
+bool UniqueRandomIdGenerator::AddKnownId(uint32_t value) {
+ return known_ids_.insert(value).second;
+}
+
+UniqueStringGenerator::UniqueStringGenerator() : unique_number_generator_() {}
+UniqueStringGenerator::UniqueStringGenerator(ArrayView<std::string> known_ids) {
+ for (const std::string& str : known_ids) {
+ AddKnownId(str);
+ }
+}
+
+UniqueStringGenerator::~UniqueStringGenerator() = default;
+
+std::string UniqueStringGenerator::GenerateString() {
+ return ToString(unique_number_generator_.GenerateNumber());
+}
+
+bool UniqueStringGenerator::AddKnownId(const std::string& value) {
+ absl::optional<uint32_t> int_value = StringToNumber<uint32_t>(value);
+ // The underlying generator works for uint32_t values, so if the provided
+ // value is not a uint32_t it will never be generated anyway.
+ if (int_value.has_value()) {
+ return unique_number_generator_.AddKnownId(int_value.value());
+ }
+ return false;
+}
+
+} // namespace rtc
diff --git a/rtc_base/unique_id_generator.h b/rtc_base/unique_id_generator.h
new file mode 100644
index 0000000..836dc70
--- /dev/null
+++ b/rtc_base/unique_id_generator.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef RTC_BASE_UNIQUE_ID_GENERATOR_H_
+#define RTC_BASE_UNIQUE_ID_GENERATOR_H_
+
+#include <limits>
+#include <set>
+#include <string>
+
+#include "api/array_view.h"
+
+namespace rtc {
+
+// This class will generate numbers. A common use case is for identifiers.
+// The generated numbers will be unique, in the local scope of the generator.
+// This means that a generator will never generate the same number twice.
+// The generator can also be initialized with a sequence of known ids.
+// In such a case, it will never generate an id from that list.
+// Recommendedations:
+// * Prefer unsigned types.
+// * Prefer larger types (uint8_t will run out quickly).
+template <typename TIntegral>
+class UniqueNumberGenerator {
+ public:
+ typedef TIntegral value_type;
+ UniqueNumberGenerator();
+ // Creates a generator that will never return any value from the given list.
+ explicit UniqueNumberGenerator(ArrayView<TIntegral> known_ids);
+ ~UniqueNumberGenerator();
+
+ // Generates a number that this generator has never produced before.
+ // If there are no available numbers to generate, this method will fail
+ // with an |RTC_CHECK|.
+ TIntegral GenerateNumber();
+ TIntegral operator()() { return GenerateNumber(); }
+
+ // Adds an id that this generator should no longer generate.
+ // Return value indicates whether the ID was hitherto unknown.
+ bool AddKnownId(TIntegral value);
+
+ private:
+ static_assert(std::is_integral<TIntegral>::value, "Must be integral type.");
+ TIntegral counter_;
+ std::set<TIntegral> known_ids_;
+};
+
+// This class will generate unique ids. Ids are 32 bit unsigned integers.
+// The generated ids will be unique, in the local scope of the generator.
+// This means that a generator will never generate the same id twice.
+// The generator can also be initialized with a sequence of known ids.
+// In such a case, it will never generate an id from that list.
+class UniqueRandomIdGenerator {
+ public:
+ typedef uint32_t value_type;
+ UniqueRandomIdGenerator();
+ // Create a generator that will never return any value from the given list.
+ explicit UniqueRandomIdGenerator(ArrayView<uint32_t> known_ids);
+ ~UniqueRandomIdGenerator();
+
+ // Generates a random id that this generator has never produced before.
+ // This method becomes more expensive with each use, as the probability of
+ // collision for the randomly generated numbers increases.
+ uint32_t GenerateId();
+ uint32_t operator()() { return GenerateId(); }
+
+ // Adds an id that this generator should no longer generate.
+ // Return value indicates whether the ID was hitherto unknown.
+ bool AddKnownId(uint32_t value);
+
+ private:
+ std::set<uint32_t> known_ids_;
+};
+
+// This class will generate strings. A common use case is for identifiers.
+// The generated strings will be unique, in the local scope of the generator.
+// This means that a generator will never generate the same string twice.
+// The generator can also be initialized with a sequence of known ids.
+// In such a case, it will never generate an id from that list.
+class UniqueStringGenerator {
+ public:
+ typedef std::string value_type;
+ UniqueStringGenerator();
+ explicit UniqueStringGenerator(ArrayView<std::string> known_ids);
+ ~UniqueStringGenerator();
+
+ std::string GenerateString();
+ std::string operator()() { return GenerateString(); }
+
+ // Adds an id that this generator should no longer generate.
+ // Return value indicates whether the ID was hitherto unknown.
+ bool AddKnownId(const std::string& value);
+
+ private:
+ // This implementation will be simple and will generate "0", "1", ...
+ UniqueNumberGenerator<uint32_t> unique_number_generator_;
+};
+
+template <typename TIntegral>
+UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator() : counter_(0) {}
+
+template <typename TIntegral>
+UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator(
+ ArrayView<TIntegral> known_ids)
+ : counter_(0), known_ids_(known_ids.begin(), known_ids.end()) {}
+
+template <typename TIntegral>
+UniqueNumberGenerator<TIntegral>::~UniqueNumberGenerator() {}
+
+template <typename TIntegral>
+TIntegral UniqueNumberGenerator<TIntegral>::GenerateNumber() {
+ while (true) {
+ RTC_CHECK_LT(counter_, std::numeric_limits<TIntegral>::max());
+ auto pair = known_ids_.insert(counter_++);
+ if (pair.second) {
+ return *pair.first;
+ }
+ }
+}
+
+template <typename TIntegral>
+bool UniqueNumberGenerator<TIntegral>::AddKnownId(TIntegral value) {
+ return known_ids_.insert(value).second;
+}
+} // namespace rtc
+
+#endif // RTC_BASE_UNIQUE_ID_GENERATOR_H_
diff --git a/rtc_base/unique_id_generator_unittest.cc b/rtc_base/unique_id_generator_unittest.cc
new file mode 100644
index 0000000..7ce192c
--- /dev/null
+++ b/rtc_base/unique_id_generator_unittest.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018 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 "algorithm"
+#include "string"
+#include "vector"
+
+#include "api/array_view.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/helpers.h"
+#include "rtc_base/unique_id_generator.h"
+#include "test/gmock.h"
+
+using ::testing::IsEmpty;
+using ::testing::Test;
+
+namespace rtc {
+
+template <typename Generator>
+class UniqueIdGeneratorTest : public Test {};
+
+using test_types = ::testing::Types<UniqueNumberGenerator<uint8_t>,
+ UniqueNumberGenerator<uint16_t>,
+ UniqueNumberGenerator<uint32_t>,
+ UniqueNumberGenerator<int>,
+ UniqueRandomIdGenerator,
+ UniqueStringGenerator>;
+
+TYPED_TEST_SUITE(UniqueIdGeneratorTest, test_types);
+
+TYPED_TEST(UniqueIdGeneratorTest, ElementsDoNotRepeat) {
+ typedef TypeParam Generator;
+ const size_t num_elements = 255;
+ Generator generator;
+ std::vector<typename Generator::value_type> values;
+ for (size_t i = 0; i < num_elements; i++) {
+ values.push_back(generator());
+ }
+
+ EXPECT_EQ(num_elements, values.size());
+ // Use a set to check uniqueness.
+ std::set<typename Generator::value_type> set(values.begin(), values.end());
+ EXPECT_EQ(values.size(), set.size()) << "Returned values were not unique.";
+}
+
+TYPED_TEST(UniqueIdGeneratorTest, KnownElementsAreNotGenerated) {
+ typedef TypeParam Generator;
+ const size_t num_elements = 100;
+ rtc::InitRandom(0);
+ Generator generator1;
+ std::vector<typename Generator::value_type> known_values;
+ for (size_t i = 0; i < num_elements; i++) {
+ known_values.push_back(generator1());
+ }
+ EXPECT_EQ(num_elements, known_values.size());
+
+ rtc::InitRandom(0);
+ Generator generator2(known_values);
+
+ std::vector<typename Generator::value_type> values;
+ for (size_t i = 0; i < num_elements; i++) {
+ values.push_back(generator2());
+ }
+ EXPECT_THAT(values, ::testing::SizeIs(num_elements));
+ std::sort(values.begin(), values.end());
+ std::sort(known_values.begin(), known_values.end());
+ std::vector<typename Generator::value_type> intersection;
+ std::set_intersection(values.begin(), values.end(), known_values.begin(),
+ known_values.end(), std::back_inserter(intersection));
+ EXPECT_THAT(intersection, IsEmpty());
+}
+
+TYPED_TEST(UniqueIdGeneratorTest, AddedElementsAreNotGenerated) {
+ typedef TypeParam Generator;
+ const size_t num_elements = 100;
+ rtc::InitRandom(0);
+ Generator generator1;
+ std::vector<typename Generator::value_type> known_values;
+ for (size_t i = 0; i < num_elements; i++) {
+ known_values.push_back(generator1());
+ }
+ EXPECT_EQ(num_elements, known_values.size());
+
+ rtc::InitRandom(0);
+ Generator generator2;
+
+ for (const typename Generator::value_type& value : known_values) {
+ generator2.AddKnownId(value);
+ }
+
+ std::vector<typename Generator::value_type> values;
+ for (size_t i = 0; i < num_elements; i++) {
+ values.push_back(generator2());
+ }
+ EXPECT_THAT(values, ::testing::SizeIs(num_elements));
+ std::sort(values.begin(), values.end());
+ std::sort(known_values.begin(), known_values.end());
+ std::vector<typename Generator::value_type> intersection;
+ std::set_intersection(values.begin(), values.end(), known_values.begin(),
+ known_values.end(), std::back_inserter(intersection));
+ EXPECT_THAT(intersection, IsEmpty());
+}
+
+TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdOnNewIdReturnsTrue) {
+ typedef TypeParam Generator;
+
+ rtc::InitRandom(0);
+ Generator generator1;
+ const typename Generator::value_type id = generator1();
+
+ rtc::InitRandom(0);
+ Generator generator2;
+ EXPECT_TRUE(generator2.AddKnownId(id));
+}
+
+TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdCalledAgainForSameIdReturnsFalse) {
+ typedef TypeParam Generator;
+
+ rtc::InitRandom(0);
+ Generator generator1;
+ const typename Generator::value_type id = generator1();
+
+ rtc::InitRandom(0);
+ Generator generator2;
+ ASSERT_TRUE(generator2.AddKnownId(id));
+ EXPECT_FALSE(generator2.AddKnownId(id));
+}
+
+TYPED_TEST(UniqueIdGeneratorTest,
+ AddKnownIdOnIdProvidedAsKnownToCtorReturnsFalse) {
+ typedef TypeParam Generator;
+
+ rtc::InitRandom(0);
+ Generator generator1;
+ const typename Generator::value_type id = generator1();
+ std::vector<typename Generator::value_type> known_values = {id};
+
+ rtc::InitRandom(0);
+ Generator generator2(known_values);
+ EXPECT_FALSE(generator2.AddKnownId(id));
+}
+
+} // namespace rtc
diff --git a/rtc_base/units/unit_base.h b/rtc_base/units/unit_base.h
index 5503a32..37b60a0 100644
--- a/rtc_base/units/unit_base.h
+++ b/rtc_base/units/unit_base.h
@@ -23,7 +23,7 @@
namespace rtc_units_impl {
// UnitBase is a base class for implementing custom value types with a specific
-// unit. It provides type safety and sommonly useful operations. The undelying
+// unit. It provides type safety and commonly useful operations. The underlying
// storage is always an int64_t, it's up to the unit implementation to choose
// what scale it represents.
//
diff --git a/rtc_base/unittest_main.cc b/rtc_base/unittest_main.cc
index 5fd3a99..def0104 100644
--- a/rtc_base/unittest_main.cc
+++ b/rtc_base/unittest_main.cc
@@ -15,16 +15,16 @@
#endif
#include "rtc_base/flags.h"
-#include "rtc_base/gunit.h"
#include "rtc_base/logging.h"
-#include "rtc_base/ssladapter.h"
-#include "rtc_base/sslstreamadapter.h"
+#include "rtc_base/ssl_adapter.h"
+#include "rtc_base/ssl_stream_adapter.h"
#include "system_wrappers/include/field_trial.h"
#include "system_wrappers/include/metrics.h"
#include "test/field_trial.h"
+#include "test/gtest.h"
#if defined(WEBRTC_WIN)
-#include "rtc_base/win32socketinit.h"
+#include "rtc_base/win32_socket_init.h"
#endif
#if defined(WEBRTC_IOS)
diff --git a/rtc_base/virtualsocketserver.cc b/rtc_base/virtual_socket_server.cc
similarity index 99%
rename from rtc_base/virtualsocketserver.cc
rename to rtc_base/virtual_socket_server.cc
index 7969411..3255124 100644
--- a/rtc_base/virtualsocketserver.cc
+++ b/rtc_base/virtual_socket_server.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/virtual_socket_server.h"
#include <errno.h>
#include <math.h>
@@ -19,12 +19,12 @@
#include <vector>
#include "rtc_base/checks.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/logging.h"
-#include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/socketaddresspair.h"
+#include "rtc_base/physical_socket_server.h"
+#include "rtc_base/socket_address_pair.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace rtc {
#if defined(WEBRTC_WIN)
diff --git a/rtc_base/virtualsocketserver.h b/rtc_base/virtual_socket_server.h
similarity index 97%
rename from rtc_base/virtualsocketserver.h
rename to rtc_base/virtual_socket_server.h
index 4fa7d77..610c0fb 100644
--- a/rtc_base/virtualsocketserver.h
+++ b/rtc_base/virtual_socket_server.h
@@ -8,18 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_VIRTUALSOCKETSERVER_H_
-#define RTC_BASE_VIRTUALSOCKETSERVER_H_
+#ifndef RTC_BASE_VIRTUAL_SOCKET_SERVER_H_
+#define RTC_BASE_VIRTUAL_SOCKET_SERVER_H_
#include <deque>
#include <map>
#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
#include "rtc_base/event.h"
-#include "rtc_base/fakeclock.h"
-#include "rtc_base/messagequeue.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/socket_server.h"
namespace rtc {
@@ -409,4 +409,4 @@
} // namespace rtc
-#endif // RTC_BASE_VIRTUALSOCKETSERVER_H_
+#endif // RTC_BASE_VIRTUAL_SOCKET_SERVER_H_
diff --git a/rtc_base/virtualsocket_unittest.cc b/rtc_base/virtual_socket_unittest.cc
similarity index 98%
rename from rtc_base/virtualsocket_unittest.cc
rename to rtc_base/virtual_socket_unittest.cc
index d44f46a..ac0af08 100644
--- a/rtc_base/virtualsocket_unittest.cc
+++ b/rtc_base/virtual_socket_unittest.cc
@@ -9,25 +9,42 @@
*/
#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
#if defined(WEBRTC_POSIX)
#include <netinet/in.h>
#endif
+#include <algorithm>
#include <memory>
+#include <utility>
#include "absl/memory/memory.h"
#include "rtc_base/arraysize.h"
-#include "rtc_base/fakeclock.h"
+#include "rtc_base/async_packet_socket.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/async_udp_socket.h"
+#include "rtc_base/fake_clock.h"
#include "rtc_base/gunit.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/location.h"
#include "rtc_base/logging.h"
-#include "rtc_base/testclient.h"
-#include "rtc_base/testutils.h"
+#include "rtc_base/message_handler.h"
+#include "rtc_base/message_queue.h"
+#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/test_client.h"
+#include "rtc_base/test_utils.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
-#include "rtc_base/timeutils.h"
-#include "rtc_base/virtualsocketserver.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/virtual_socket_server.h"
+#include "test/gtest.h"
-using namespace rtc;
+namespace rtc {
+namespace {
using webrtc::testing::SSE_CLOSE;
using webrtc::testing::SSE_ERROR;
@@ -1127,3 +1144,6 @@
}
}
}
+
+} // namespace
+} // namespace rtc
diff --git a/rtc_base/weak_ptr.h b/rtc_base/weak_ptr.h
index 8acfab0..89969d6 100644
--- a/rtc_base/weak_ptr.h
+++ b/rtc_base/weak_ptr.h
@@ -15,9 +15,9 @@
#include <utility>
-#include "rtc_base/refcount.h"
-#include "rtc_base/refcountedobject.h"
-#include "rtc_base/scoped_ref_ptr.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counted_object.h"
#include "rtc_base/sequenced_task_checker.h"
// The implementation is borrowed from chromium except that it does not
diff --git a/rtc_base/weak_ptr_unittest.cc b/rtc_base/weak_ptr_unittest.cc
index 66f2b4d..8f09a33 100644
--- a/rtc_base/weak_ptr_unittest.cc
+++ b/rtc_base/weak_ptr_unittest.cc
@@ -8,12 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <memory>
#include <string>
+#include "absl/memory/memory.h"
#include "rtc_base/event.h"
-#include "rtc_base/gunit.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/weak_ptr.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/rtc_base/win/windows_version.cc b/rtc_base/win/windows_version.cc
index 65ef4fd..72aa5c6 100644
--- a/rtc_base/win/windows_version.cc
+++ b/rtc_base/win/windows_version.cc
@@ -14,7 +14,7 @@
#include <memory>
#include "rtc_base/checks.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
#if !defined(__clang__) && _MSC_FULL_VER < 191125507
#error VS 2017 Update 3.2 or higher is required
diff --git a/rtc_base/win/windows_version.h b/rtc_base/win/windows_version.h
index 39d333e..fa0a767 100644
--- a/rtc_base/win/windows_version.h
+++ b/rtc_base/win/windows_version.h
@@ -14,7 +14,7 @@
#include <stddef.h>
#include <string>
-#include "rtc_base/constructormagic.h"
+#include "rtc_base/constructor_magic.h"
typedef void* HANDLE;
diff --git a/rtc_base/win32.cc b/rtc_base/win32.cc
index 480d97b..b5a2611 100644
--- a/rtc_base/win32.cc
+++ b/rtc_base/win32.cc
@@ -15,10 +15,10 @@
#include <algorithm>
#include "rtc_base/arraysize.h"
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/stringutils.h"
+#include "rtc_base/string_utils.h"
namespace rtc {
diff --git a/rtc_base/win32socketinit.h b/rtc_base/win32_socket_init.h
similarity index 87%
rename from rtc_base/win32socketinit.h
rename to rtc_base/win32_socket_init.h
index 7f9bdcc..4a90e14 100644
--- a/rtc_base/win32socketinit.h
+++ b/rtc_base/win32_socket_init.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_WIN32SOCKETINIT_H_
-#define RTC_BASE_WIN32SOCKETINIT_H_
+#ifndef RTC_BASE_WIN32_SOCKET_INIT_H_
+#define RTC_BASE_WIN32_SOCKET_INIT_H_
#ifndef WEBRTC_WIN
#error "Only #include this header in Windows builds"
@@ -38,4 +38,4 @@
} // namespace rtc
-#endif // RTC_BASE_WIN32SOCKETINIT_H_
+#endif // RTC_BASE_WIN32_SOCKET_INIT_H_
diff --git a/rtc_base/win32socketserver.cc b/rtc_base/win32_socket_server.cc
similarity index 98%
rename from rtc_base/win32socketserver.cc
rename to rtc_base/win32_socket_server.cc
index 230f3ed..389b76b 100644
--- a/rtc_base/win32socketserver.cc
+++ b/rtc_base/win32_socket_server.cc
@@ -8,16 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/win32socketserver.h"
+#include "rtc_base/win32_socket_server.h"
#include <ws2tcpip.h> // NOLINT
#include <algorithm>
-#include "rtc_base/byteorder.h"
+#include "rtc_base/byte_order.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
-#include "rtc_base/timeutils.h" // For Time, TimeSince
-#include "rtc_base/win32window.h"
+#include "rtc_base/time_utils.h" // For Time, TimeSince
+#include "rtc_base/win32_window.h"
namespace rtc {
diff --git a/rtc_base/win32socketserver.h b/rtc_base/win32_socket_server.h
similarity index 92%
rename from rtc_base/win32socketserver.h
rename to rtc_base/win32_socket_server.h
index 0b11d64..37515d9 100644
--- a/rtc_base/win32socketserver.h
+++ b/rtc_base/win32_socket_server.h
@@ -8,18 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_WIN32SOCKETSERVER_H_
-#define RTC_BASE_WIN32SOCKETSERVER_H_
+#ifndef RTC_BASE_WIN32_SOCKET_SERVER_H_
+#define RTC_BASE_WIN32_SOCKET_SERVER_H_
#if defined(WEBRTC_WIN)
-#include "rtc_base/asyncsocket.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/messagequeue.h"
+#include "rtc_base/async_socket.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/message_queue.h"
#include "rtc_base/socket.h"
-#include "rtc_base/socketfactory.h"
-#include "rtc_base/socketserver.h"
+#include "rtc_base/socket_factory.h"
+#include "rtc_base/socket_server.h"
#include "rtc_base/thread.h"
-#include "rtc_base/win32window.h"
+#include "rtc_base/win32_window.h"
namespace rtc {
@@ -151,4 +151,4 @@
#endif // WEBRTC_WIN
-#endif // RTC_BASE_WIN32SOCKETSERVER_H_
+#endif // RTC_BASE_WIN32_SOCKET_SERVER_H_
diff --git a/rtc_base/win32socketserver_unittest.cc b/rtc_base/win32_socket_server_unittest.cc
similarity index 98%
rename from rtc_base/win32socketserver_unittest.cc
rename to rtc_base/win32_socket_server_unittest.cc
index 60295f1..d8484d1 100644
--- a/rtc_base/win32socketserver_unittest.cc
+++ b/rtc_base/win32_socket_server_unittest.cc
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/win32socketserver.h"
+#include "rtc_base/win32_socket_server.h"
#include "rtc_base/gunit.h"
#include "rtc_base/socket_unittest.h"
#include "rtc_base/thread.h"
diff --git a/rtc_base/win32_unittest.cc b/rtc_base/win32_unittest.cc
index 5691be4..913aa01 100644
--- a/rtc_base/win32_unittest.cc
+++ b/rtc_base/win32_unittest.cc
@@ -11,7 +11,7 @@
#include <string>
#include "rtc_base/gunit.h"
-#include "rtc_base/nethelpers.h"
+#include "rtc_base/net_helpers.h"
#include "rtc_base/win32.h"
#if !defined(WEBRTC_WIN)
diff --git a/rtc_base/win32window.cc b/rtc_base/win32_window.cc
similarity index 98%
rename from rtc_base/win32window.cc
rename to rtc_base/win32_window.cc
index 4290894..fc7b4c3 100644
--- a/rtc_base/win32window.cc
+++ b/rtc_base/win32_window.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/win32window.h"
+#include "rtc_base/win32_window.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
diff --git a/rtc_base/win32window.h b/rtc_base/win32_window.h
similarity index 94%
rename from rtc_base/win32window.h
rename to rtc_base/win32_window.h
index e96aa35..5256a85 100644
--- a/rtc_base/win32window.h
+++ b/rtc_base/win32_window.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef RTC_BASE_WIN32WINDOW_H_
-#define RTC_BASE_WIN32WINDOW_H_
+#ifndef RTC_BASE_WIN32_WINDOW_H_
+#define RTC_BASE_WIN32_WINDOW_H_
#if defined(WEBRTC_WIN)
@@ -67,4 +67,4 @@
#endif // WEBRTC_WIN
-#endif // RTC_BASE_WIN32WINDOW_H_
+#endif // RTC_BASE_WIN32_WINDOW_H_
diff --git a/rtc_base/win32window_unittest.cc b/rtc_base/win32_window_unittest.cc
similarity index 98%
rename from rtc_base/win32window_unittest.cc
rename to rtc_base/win32_window_unittest.cc
index c659349..62430bb 100644
--- a/rtc_base/win32window_unittest.cc
+++ b/rtc_base/win32_window_unittest.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "rtc_base/win32window.h"
+#include "rtc_base/win32_window.h"
#include "rtc_base/gunit.h"
#include "rtc_base/logging.h"
diff --git a/rtc_base/zero_memory_unittest.cc b/rtc_base/zero_memory_unittest.cc
index 0f49670..74d95f4 100644
--- a/rtc_base/zero_memory_unittest.cc
+++ b/rtc_base/zero_memory_unittest.cc
@@ -10,9 +10,10 @@
#include "rtc_base/zero_memory.h"
+#include <stdint.h>
+
#include "api/array_view.h"
-#include "rtc_base/buffer.h"
-#include "rtc_base/gunit.h"
+#include "test/gtest.h"
namespace rtc {
diff --git a/script/sync-apm.sh b/script/sync-apm.sh
index 47eccdd..c88a656 100755
--- a/script/sync-apm.sh
+++ b/script/sync-apm.sh
@@ -48,7 +48,7 @@
rsync "${OPTIONS[@]}" --include="*.cc" --include="*.h" --include="audio" \
--include="video" --include="transport" --include="units" \
- --exclude="*" ${FROM}/api/* ${TO}/api
+ --include="task_queue" --exclude="*" ${FROM}/api/* ${TO}/api
# Adjust include path to use libevent header on chroot
sed -i 's/include "base\/third_party\/libevent\/event\.h"/include <event.h>/' \
diff --git a/system_wrappers/BUILD.gn b/system_wrappers/BUILD.gn
index da83d12..ee24c8b 100644
--- a/system_wrappers/BUILD.gn
+++ b/system_wrappers/BUILD.gn
@@ -42,8 +42,6 @@
]
if (is_android) {
- defines += [ "WEBRTC_THREAD_RR" ]
-
if (build_with_mozilla) {
include_dirs = [
"/config/external/nspr",
@@ -58,8 +56,6 @@
}
if (is_linux) {
- defines += [ "WEBRTC_THREAD_RR" ]
-
if (!build_with_chromium) {
deps += [ ":cpu_features_linux" ]
}
@@ -67,10 +63,6 @@
libs += [ "rt" ]
}
- if (is_ios || is_mac) {
- defines += [ "WEBRTC_THREAD_RR" ]
- }
-
if (is_win) {
libs += [ "winmm.lib" ]
@@ -174,6 +166,7 @@
":metrics",
":system_wrappers",
"..:webrtc_common",
+ "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../test:test_main",
"../test:test_support",
diff --git a/system_wrappers/include/clock.h b/system_wrappers/include/clock.h
index f1fc11f..b2c6c5f 100644
--- a/system_wrappers/include/clock.h
+++ b/system_wrappers/include/clock.h
@@ -32,17 +32,17 @@
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
- virtual int64_t TimeInMilliseconds() const = 0;
+ virtual int64_t TimeInMilliseconds() = 0;
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
- virtual int64_t TimeInMicroseconds() const = 0;
+ virtual int64_t TimeInMicroseconds() = 0;
// Retrieve an NTP absolute timestamp.
- virtual NtpTime CurrentNtpTime() const = 0;
+ virtual NtpTime CurrentNtpTime() = 0;
// Retrieve an NTP absolute timestamp in milliseconds.
- virtual int64_t CurrentNtpInMilliseconds() const = 0;
+ virtual int64_t CurrentNtpInMilliseconds() = 0;
// Converts an NTP timestamp to a millisecond timestamp.
static int64_t NtpToMs(uint32_t seconds, uint32_t fractions) {
@@ -61,17 +61,17 @@
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
- int64_t TimeInMilliseconds() const override;
+ int64_t TimeInMilliseconds() override;
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
- int64_t TimeInMicroseconds() const override;
+ int64_t TimeInMicroseconds() override;
// Retrieve an NTP absolute timestamp.
- NtpTime CurrentNtpTime() const override;
+ NtpTime CurrentNtpTime() override;
// Converts an NTP timestamp to a millisecond timestamp.
- int64_t CurrentNtpInMilliseconds() const override;
+ int64_t CurrentNtpInMilliseconds() override;
// Advance the simulated clock with a given number of milliseconds or
// microseconds.
@@ -83,6 +83,6 @@
std::unique_ptr<RWLockWrapper> lock_;
};
-}; // namespace webrtc
+} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INCLUDE_CLOCK_H_
diff --git a/system_wrappers/include/metrics.h b/system_wrappers/include/metrics.h
index f00ecf2..62dc6c6 100644
--- a/system_wrappers/include/metrics.h
+++ b/system_wrappers/include/metrics.h
@@ -11,11 +11,12 @@
#ifndef SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
#define SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+#include <stddef.h>
#include <map>
#include <memory>
#include <string>
-#include "rtc_base/atomicops.h"
+#include "rtc_base/atomic_ops.h"
#include "rtc_base/checks.h"
// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
@@ -133,7 +134,7 @@
// TODO(qingsi): Refactor the default implementation given by RtcHistogram,
// which is already sparse, and remove the boundary argument from the macro.
#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
- RTC_HISTOGRAM_COMMON_BLOCK( \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
name, sample, \
webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary))
@@ -148,7 +149,7 @@
// Histogram for enumerators (evenly spaced buckets).
// |boundary| should be above the max enumerator sample.
#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
- RTC_HISTOGRAM_COMMON_BLOCK( \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
name, sample, \
webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
@@ -175,7 +176,6 @@
} \
} while (0)
-// Deprecated.
// The histogram is constructed/found for each call.
// May be used for histograms with infrequent updates.`
#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
@@ -309,6 +309,10 @@
// Returns the minimum sample value (or -1 if the histogram has no samples).
int MinSample(const std::string& name);
+// Returns a map with keys the samples with at least one event and values the
+// number of events for that sample.
+std::map<int, int> Samples(const std::string& name);
+
} // namespace metrics
} // namespace webrtc
diff --git a/system_wrappers/source/clock.cc b/system_wrappers/source/clock.cc
index 32cf1de..f69d13c 100644
--- a/system_wrappers/source/clock.cc
+++ b/system_wrappers/source/clock.cc
@@ -17,7 +17,7 @@
#include <mmsystem.h>
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#elif defined(WEBRTC_POSIX)
@@ -27,21 +27,21 @@
#endif // defined(WEBRTC_POSIX)
#include "rtc_base/synchronization/rw_lock_wrapper.h"
-#include "rtc_base/timeutils.h"
+#include "rtc_base/time_utils.h"
namespace webrtc {
class RealTimeClock : public Clock {
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
- int64_t TimeInMilliseconds() const override { return rtc::TimeMillis(); }
+ int64_t TimeInMilliseconds() override { return rtc::TimeMillis(); }
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
- int64_t TimeInMicroseconds() const override { return rtc::TimeMicros(); }
+ int64_t TimeInMicroseconds() override { return rtc::TimeMicros(); }
// Retrieve an NTP absolute timestamp.
- NtpTime CurrentNtpTime() const override {
+ NtpTime CurrentNtpTime() override {
timeval tv = CurrentTimeVal();
double microseconds_in_seconds;
uint32_t seconds;
@@ -52,7 +52,7 @@
}
// Retrieve an NTP absolute timestamp in milliseconds.
- int64_t CurrentNtpInMilliseconds() const override {
+ int64_t CurrentNtpInMilliseconds() override {
timeval tv = CurrentTimeVal();
uint32_t seconds;
double microseconds_in_seconds;
@@ -62,7 +62,7 @@
}
protected:
- virtual timeval CurrentTimeVal() const = 0;
+ virtual timeval CurrentTimeVal() = 0;
static void Adjust(const timeval& tv,
uint32_t* adjusted_s,
@@ -87,7 +87,7 @@
~WinUwpRealTimeClock() override {}
protected:
- timeval CurrentTimeVal() const override {
+ timeval CurrentTimeVal() override {
// The rtc::SystemTimeNanos() method is already time offset from a base
// epoch value and might as be synchronized against an NTP time server as
// an added bonus.
@@ -104,7 +104,7 @@
#elif defined(WEBRTC_WIN)
// TODO(pbos): Consider modifying the implementation to synchronize itself
-// against system time (update ref_point_, make it non-const) periodically to
+// against system time (update ref_point_) periodically to
// prevent clock drift.
class WindowsRealTimeClock : public RealTimeClock {
public:
@@ -121,7 +121,7 @@
LARGE_INTEGER counter_ms;
};
- timeval CurrentTimeVal() const override {
+ timeval CurrentTimeVal() override {
const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
FILETIME StartTime;
@@ -143,7 +143,7 @@
return tv;
}
- void GetTime(FILETIME* current_time) const {
+ void GetTime(FILETIME* current_time) {
DWORD t;
LARGE_INTEGER elapsed_ms;
{
@@ -197,10 +197,9 @@
return ref;
}
- // mutable as time-accessing functions are const.
rtc::CriticalSection crit_;
- mutable DWORD last_time_ms_;
- mutable LONG num_timer_wraps_;
+ DWORD last_time_ms_;
+ LONG num_timer_wraps_;
const ReferencePoint ref_point_;
};
@@ -212,7 +211,7 @@
~UnixRealTimeClock() override {}
protected:
- timeval CurrentTimeVal() const override {
+ timeval CurrentTimeVal() override {
struct timeval tv;
struct timezone tz;
tz.tz_minuteswest = 0;
@@ -241,17 +240,17 @@
SimulatedClock::~SimulatedClock() {}
-int64_t SimulatedClock::TimeInMilliseconds() const {
+int64_t SimulatedClock::TimeInMilliseconds() {
ReadLockScoped synchronize(*lock_);
return (time_us_ + 500) / 1000;
}
-int64_t SimulatedClock::TimeInMicroseconds() const {
+int64_t SimulatedClock::TimeInMicroseconds() {
ReadLockScoped synchronize(*lock_);
return time_us_;
}
-NtpTime SimulatedClock::CurrentNtpTime() const {
+NtpTime SimulatedClock::CurrentNtpTime() {
int64_t now_ms = TimeInMilliseconds();
uint32_t seconds = (now_ms / 1000) + kNtpJan1970;
uint32_t fractions =
@@ -259,7 +258,7 @@
return NtpTime(seconds, fractions);
}
-int64_t SimulatedClock::CurrentNtpInMilliseconds() const {
+int64_t SimulatedClock::CurrentNtpInMilliseconds() {
return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
}
@@ -272,4 +271,4 @@
time_us_ += microseconds;
}
-}; // namespace webrtc
+} // namespace webrtc
diff --git a/system_wrappers/source/cpu_info.cc b/system_wrappers/source/cpu_info.cc
index c17d59d..6bcdd5f 100644
--- a/system_wrappers/source/cpu_info.cc
+++ b/system_wrappers/source/cpu_info.cc
@@ -14,9 +14,10 @@
#include <windows.h>
#elif defined(WEBRTC_LINUX)
#include <unistd.h>
-#endif
-#if defined(WEBRTC_MAC)
+#elif defined(WEBRTC_MAC)
#include <sys/sysctl.h>
+#elif defined(WEBRTC_FUCHSIA)
+#include <zircon/syscalls.h>
#endif
#include "rtc_base/logging.h"
@@ -32,13 +33,15 @@
number_of_cores = static_cast<int>(si.dwNumberOfProcessors);
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
number_of_cores = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
-#elif defined(WEBRTC_MAC)
+#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
int name[] = {CTL_HW, HW_AVAILCPU};
size_t size = sizeof(number_of_cores);
if (0 != sysctl(name, 2, &number_of_cores, &size, NULL, 0)) {
RTC_LOG(LS_ERROR) << "Failed to get number of cores";
number_of_cores = 1;
}
+#elif defined(WEBRTC_FUCHSIA)
+ number_of_cores = zx_system_get_num_cpus();
#else
RTC_LOG(LS_ERROR) << "No function to get number of cores";
#endif
diff --git a/system_wrappers/source/metrics.cc b/system_wrappers/source/metrics.cc
index 4aa8770..2383272 100644
--- a/system_wrappers/source/metrics.cc
+++ b/system_wrappers/source/metrics.cc
@@ -11,7 +11,7 @@
#include <algorithm>
-#include "rtc_base/criticalsection.h"
+#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
// Default implementation of histogram methods for WebRTC clients that do not
@@ -88,6 +88,11 @@
return (info_.samples.empty()) ? -1 : info_.samples.begin()->first;
}
+ std::map<int, int> Samples() const {
+ rtc::CritScope cs(&crit_);
+ return info_.samples;
+ }
+
private:
rtc::CriticalSection crit_;
const int min_;
@@ -162,6 +167,12 @@
return (it == map_.end()) ? -1 : it->second->MinSample();
}
+ std::map<int, int> Samples(const std::string& name) const {
+ rtc::CritScope cs(&crit_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? std::map<int, int>() : it->second->Samples();
+ }
+
private:
rtc::CriticalSection crit_;
std::map<std::string, std::unique_ptr<RtcHistogram>> map_
@@ -307,5 +318,10 @@
return map ? map->MinSample(name) : -1;
}
+std::map<int, int> Samples(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->Samples(name) : std::map<int, int>();
+}
+
} // namespace metrics
} // namespace webrtc
diff --git a/system_wrappers/source/metrics_default_unittest.cc b/system_wrappers/source/metrics_default_unittest.cc
index b2d2023..cb427c2 100644
--- a/system_wrappers/source/metrics_default_unittest.cc
+++ b/system_wrappers/source/metrics_default_unittest.cc
@@ -8,6 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "rtc_base/checks.h"
#include "system_wrappers/include/metrics.h"
#include "test/gtest.h"
diff --git a/system_wrappers/source/metrics_unittest.cc b/system_wrappers/source/metrics_unittest.cc
index dac8177..9c96ba0 100644
--- a/system_wrappers/source/metrics_unittest.cc
+++ b/system_wrappers/source/metrics_unittest.cc
@@ -9,8 +9,13 @@
*/
#include "system_wrappers/include/metrics.h"
+#include "test/gmock.h"
#include "test/gtest.h"
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+
namespace webrtc {
namespace {
const int kSample = 22;
@@ -34,6 +39,7 @@
TEST_F(MetricsTest, InitiallyNoSamples) {
EXPECT_EQ(0, metrics::NumSamples("NonExisting"));
EXPECT_EQ(0, metrics::NumEvents("NonExisting", kSample));
+ EXPECT_THAT(metrics::Samples("NonExisting"), IsEmpty());
}
TEST_F(MetricsTest, RtcHistogramPercent_AddSample) {
@@ -41,6 +47,7 @@
RTC_HISTOGRAM_PERCENTAGE(kName, kSample);
EXPECT_EQ(1, metrics::NumSamples(kName));
EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
}
TEST_F(MetricsTest, RtcHistogramEnumeration_AddSample) {
@@ -48,6 +55,7 @@
RTC_HISTOGRAM_ENUMERATION(kName, kSample, kSample + 1);
EXPECT_EQ(1, metrics::NumSamples(kName));
EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
}
TEST_F(MetricsTest, RtcHistogramBoolean_AddSample) {
@@ -56,6 +64,7 @@
RTC_HISTOGRAM_BOOLEAN(kName, kSample);
EXPECT_EQ(1, metrics::NumSamples(kName));
EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
}
TEST_F(MetricsTest, RtcHistogramCountsSparse_AddSample) {
@@ -63,6 +72,7 @@
RTC_HISTOGRAM_COUNTS_SPARSE_100(kName, kSample);
EXPECT_EQ(1, metrics::NumSamples(kName));
EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
}
TEST_F(MetricsTest, RtcHistogramCounts_AddSample) {
@@ -70,16 +80,20 @@
RTC_HISTOGRAM_COUNTS_100(kName, kSample);
EXPECT_EQ(1, metrics::NumSamples(kName));
EXPECT_EQ(1, metrics::NumEvents(kName, kSample));
+ EXPECT_THAT(metrics::Samples(kName), ElementsAre(Pair(kSample, 1)));
}
TEST_F(MetricsTest, RtcHistogramCounts_AddMultipleSamples) {
const std::string kName = "Counts200";
const int kNumSamples = 10;
+ std::map<int, int> samples;
for (int i = 1; i <= kNumSamples; ++i) {
RTC_HISTOGRAM_COUNTS_200(kName, i);
EXPECT_EQ(1, metrics::NumEvents(kName, i));
EXPECT_EQ(i, metrics::NumSamples(kName));
+ samples[i] = 1;
}
+ EXPECT_EQ(samples, metrics::Samples(kName));
}
TEST_F(MetricsTest, RtcHistogramsCounts_AddSample) {
@@ -92,6 +106,9 @@
EXPECT_EQ(1, metrics::NumEvents("Name1", kSample + 0));
EXPECT_EQ(1, metrics::NumEvents("Name2", kSample + 1));
EXPECT_EQ(1, metrics::NumEvents("Name3", kSample + 2));
+ EXPECT_THAT(metrics::Samples("Name1"), ElementsAre(Pair(kSample + 0, 1)));
+ EXPECT_THAT(metrics::Samples("Name2"), ElementsAre(Pair(kSample + 1, 1)));
+ EXPECT_THAT(metrics::Samples("Name3"), ElementsAre(Pair(kSample + 2, 1)));
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
@@ -107,6 +124,8 @@
AddSparseSample("Sparse2", kSample);
EXPECT_EQ(1, metrics::NumSamples("Sparse1"));
EXPECT_EQ(1, metrics::NumSamples("Sparse2"));
+ EXPECT_THAT(metrics::Samples("Sparse1"), ElementsAre(Pair(kSample, 1)));
+ EXPECT_THAT(metrics::Samples("Sparse2"), ElementsAre(Pair(kSample, 1)));
}
} // namespace webrtc
diff --git a/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc b/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
index b0b83bb..14bc6e0 100644
--- a/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
+++ b/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
@@ -9,6 +9,9 @@
*/
#include "system_wrappers/include/rtp_to_ntp_estimator.h"
+
+#include <stddef.h>
+
#include "rtc_base/random.h"
#include "test/gtest.h"
@@ -343,4 +346,4 @@
}
}
-}; // namespace webrtc
+} // namespace webrtc
diff --git a/third_party/rnnoise/src/kiss_fft_unittest.cc b/third_party/rnnoise/src/kiss_fft_unittest.cc
index 3132445..f7d1bb0 100644
--- a/third_party/rnnoise/src/kiss_fft_unittest.cc
+++ b/third_party/rnnoise/src/kiss_fft_unittest.cc
@@ -77,20 +77,20 @@
tolerance);
}
-INSTANTIATE_TEST_CASE_P(FftPoints,
- RnnVadTest,
- ::testing::Values(std::make_tuple(1.f, 240, 3e-7f),
- std::make_tuple(1.f, 256, 3e-7f),
- std::make_tuple(1.f, 480, 3e-7f),
- std::make_tuple(1.f, 512, 3e-7f),
- std::make_tuple(1.f, 960, 4e-7f),
- std::make_tuple(1.f, 1024, 3e-7f),
- std::make_tuple(30.f, 240, 5e-6f),
- std::make_tuple(30.f, 256, 5e-6f),
- std::make_tuple(30.f, 480, 6e-6f),
- std::make_tuple(30.f, 512, 6e-6f),
- std::make_tuple(30.f, 960, 8e-6f),
- std::make_tuple(30.f, 1024, 6e-6f)));
+INSTANTIATE_TEST_SUITE_P(FftPoints,
+ RnnVadTest,
+ ::testing::Values(std::make_tuple(1.f, 240, 3e-7f),
+ std::make_tuple(1.f, 256, 3e-7f),
+ std::make_tuple(1.f, 480, 3e-7f),
+ std::make_tuple(1.f, 512, 3e-7f),
+ std::make_tuple(1.f, 960, 4e-7f),
+ std::make_tuple(1.f, 1024, 3e-7f),
+ std::make_tuple(30.f, 240, 5e-6f),
+ std::make_tuple(30.f, 256, 5e-6f),
+ std::make_tuple(30.f, 480, 6e-6f),
+ std::make_tuple(30.f, 512, 6e-6f),
+ std::make_tuple(30.f, 960, 8e-6f),
+ std::make_tuple(30.f, 1024, 6e-6f)));
TEST(RnnVadTest, KissFftBitExactness) {
constexpr std::array<float, 32> samples = {
diff --git a/webrtc_apm.cc b/webrtc_apm.cc
index ce8f8ee..e3e6fe0 100644
--- a/webrtc_apm.cc
+++ b/webrtc_apm.cc
@@ -4,6 +4,7 @@
*/
#include "api/audio/echo_canceller3_factory.h"
+#include "api/task_queue/default_task_queue_factory.h"
#include "cras-config/aec_config.h"
#include "cras-config/apm_config.h"
#include "modules/audio_processing/aec_dump/aec_dump_factory.h"