diff --git a/.style.yapf b/.style.yapf index c34341d425..557fa7bf84 100644 --- a/.style.yapf +++ b/.style.yapf @@ -1,4 +1,2 @@ [style] based_on_style = pep8 -indent_width = 2 -column_limit = 80 \ No newline at end of file diff --git a/AUTHORS b/AUTHORS index eb393ef057..6e922401d0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -104,6 +104,7 @@ Raman Budny Ramprakash Jelari Riku Voipio Robert Bares +Robert Mader Robert Mader Robert Nagy Ryan Yoakum @@ -132,6 +133,7 @@ Xiaohong Xu Xiaolei Yu Xinchao Tian Yaowen Guo +Youfa Yura Yaroshevich Yuriy Pavlyshak Yusuke Suzuki diff --git a/BUILD.gn b/BUILD.gn index 3480a932e0..8b6898f7bf 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -30,6 +30,7 @@ if (rtc_enable_protobuf) { if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") + import("//third_party/jni_zero/jni_zero.gni") } if (!build_with_chromium) { @@ -301,6 +302,10 @@ config("common_config") { defines += [ "RTC_ENABLE_VP9" ] } + if (rtc_use_h265) { + defines += [ "RTC_ENABLE_H265" ] + } + if (rtc_include_dav1d_in_internal_decoder_factory) { defines += [ "RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY" ] } @@ -462,7 +467,7 @@ config("common_config") { ] } - if (use_fuzzing_engine && optimize_for_fuzzing) { + if (use_fuzzing_engine) { # Used in Chromium's overrides to disable logging defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ] } @@ -808,8 +813,5 @@ group("poison_default_task_queue") { group("poison_default_echo_detector") { } -group("poison_rtc_json") { -} - group("poison_software_video_codecs") { } diff --git a/DEPS b/DEPS index 98cf94d80e..eb20d9ef73 100644 --- a/DEPS +++ b/DEPS @@ -10,7 +10,7 @@ vars = { # chromium waterfalls. More info at: crbug.com/570091. 'checkout_configuration': 'default', 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"', - 'chromium_revision': '6ac79291669656814b2c66e66ea296caac6652fd', + 'chromium_revision': 'c89d7a6d7f77a1afc1e3759f0e66a49eca1ee1d7', # Fetch the prebuilt binaries for llvm-cov and llvm-profdata. Needed to # process the raw profiles produced by instrumented targets (built with @@ -25,14 +25,14 @@ vars = { # By default, download the fuchsia sdk from the public sdk directory. 'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/core/', - 'fuchsia_version': 'version:14.20230826.1.1', + 'fuchsia_version': 'version:15.20231022.3.1', # By default, download the fuchsia images from the fuchsia GCS bucket. 'fuchsia_images_bucket': 'fuchsia', 'checkout_fuchsia': False, # Since the images are hundreds of MB, default to only downloading the image # most commonly useful for developers. Bots and developers that need to use # other images can override this with additional images. - 'checkout_fuchsia_boot_images': "terminal.qemu-x64", + 'checkout_fuchsia_boot_images': "terminal.qemu-x64,terminal.x64", 'checkout_fuchsia_product_bundles': '"{checkout_fuchsia_boot_images}" != ""', # Fetch configuration files required for the 'use_remoteexec' gn arg @@ -40,7 +40,7 @@ vars = { # RBE instance to use for running remote builds 'rbe_instance': 'projects/rbe-webrtc-developer/instances/default_instance', # reclient CIPD package version - 'reclient_version': 're_client_version:0.113.0.8b45b89-gomaip', + 'reclient_version': 're_client_version:0.117.1.21520c6-gomaip', # ninja CIPD package version # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja @@ -54,30 +54,30 @@ deps = { # TODO(kjellander): Move this to be Android-only. 'src/base': - 'https://chromium.googlesource.com/chromium/src/base@609cafa975c8a29d3b2f686c9a42530a556835fe', + 'https://chromium.googlesource.com/chromium/src/base@1546e3adb67bb711ca2fd39c3913cb56bd889748', 'src/build': - 'https://chromium.googlesource.com/chromium/src/build@115a7079919c25462a7fd8c1d22900378bbc6585', + 'https://chromium.googlesource.com/chromium/src/build@a21fc6065131d0442e8a54c3ca2638e393b69438', 'src/buildtools': - 'https://chromium.googlesource.com/chromium/src/buildtools@b2043d4f435131d0a1bdd5342c17753ef9236572', + 'https://chromium.googlesource.com/chromium/src/buildtools@6f834e2039daedfc68a2749c217922b26d5e8497', # Gradle 6.6.1. Used for testing Android Studio project generation for WebRTC. 'src/examples/androidtests/third_party/gradle': { 'url': 'https://chromium.googlesource.com/external/github.com/gradle/gradle.git@f2d1fb54a951d8b11d25748e4711bec8d128d7e3', 'condition': 'checkout_android', }, 'src/ios': { - 'url': 'https://chromium.googlesource.com/chromium/src/ios@17864bdc8fb2f78060ea4109d61a9144f64f4d67', + 'url': 'https://chromium.googlesource.com/chromium/src/ios@5139a7efd464e4514a6df1054e44e0e4fac67536', 'condition': 'checkout_ios', }, 'src/testing': - 'https://chromium.googlesource.com/chromium/src/testing@ff8dee88bc0b49f8337cee6e82151c245a63b98c', + 'https://chromium.googlesource.com/chromium/src/testing@46366a7e4d08bf9fceeb3c1c3b5eab8a6a5024b5', 'src/third_party': - 'https://chromium.googlesource.com/chromium/src/third_party@ee6367daea550c5845a6079cec5fd6555f39144f', + 'https://chromium.googlesource.com/chromium/src/third_party@64d9ec3158b4629163f88b779a53e16f1cc24f81', 'src/buildtools/linux64': { 'packages': [ { 'package': 'gn/gn/linux-${{arch}}', - 'version': 'git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4', + 'version': 'git_revision:e4702d7409069c4f12d45ea7b7f0890717ca3f4b', } ], 'dep_type': 'cipd', @@ -87,7 +87,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/mac-${{arch}}', - 'version': 'git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4', + 'version': 'git_revision:e4702d7409069c4f12d45ea7b7f0890717ca3f4b', } ], 'dep_type': 'cipd', @@ -97,7 +97,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/windows-amd64', - 'version': 'git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4', + 'version': 'git_revision:e4702d7409069c4f12d45ea7b7f0890717ca3f4b', } ], 'dep_type': 'cipd', @@ -119,11 +119,11 @@ deps = { 'src/third_party/clang-format/script': 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@e5337933f2951cacd3aeacd238ce4578163ca0b9', 'src/third_party/libc++/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git@84fb809dd6dae36d556dc0bb702c6cc2ce9d4b80', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git@a429c26ae25c26a569ff12390d5f9be70c5e286b', 'src/third_party/libc++abi/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@3d83ca7bd2ab81f042bafe6996da08c9cd57c119', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@2ca9f38714b1465b9f55b5fbd0da5e4342811e2b', 'src/third_party/libunwind/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@76e621a89787516da745489245d8b65a48ad60d8', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@7686b5d38c69d14932abfb1c1a66ba56c78791ad', 'src/third_party/ninja': { 'packages': [ @@ -159,7 +159,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/aapt2', - 'version': 'STY0BXlZxsEhudnlXQFed-B5UpwehcoM0sYqor6qRqsC', + 'version': 'y1G4s2RWI63L9ZLgzS3RzFdWdeblpCmYyAUzMphcQawC', }, ], 'condition': 'checkout_android', @@ -170,7 +170,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/bundletool', - 'version': '2RPwohwtc6on0_96oFxokeEvnC1LbLrGuyCAw00k62AC', + 'version': 'xOeKyLIaK_RRHU0Qv0EdxTrRlq_22HAwoOr1xn5yoOcC', }, ], 'condition': 'checkout_android', @@ -178,11 +178,11 @@ deps = { }, 'src/third_party/boringssl/src': - 'https://boringssl.googlesource.com/boringssl.git@b8e012e1ff736cc794273af4a7db521e6b18bcd5', + 'https://boringssl.googlesource.com/boringssl.git@c38dc29860a72540eb2c4fdb8a8bfb27ef94ddf3', 'src/third_party/breakpad/breakpad': 'https://chromium.googlesource.com/breakpad/breakpad.git@8988364bcddd9b194b0bf931c10bc125987330ed', 'src/third_party/catapult': - 'https://chromium.googlesource.com/catapult.git@b8c4f2d99ac66fe47cb8cceec0dd1a1da5d1b51e', + 'https://chromium.googlesource.com/catapult.git@47efdb4b1428e549c58a6d6c2fa79c4a8ceaf9b4', 'src/third_party/ced/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/compact_enc_det.git@ba412eaaacd3186085babcd901679a48863c7dd5', }, @@ -195,11 +195,11 @@ deps = { 'src/third_party/crc32c/src': 'https://chromium.googlesource.com/external/github.com/google/crc32c.git@fa5ade41ee480003d9c5af6f43567ba22e4e17e6', 'src/third_party/depot_tools': - 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@427f0f43ad0ceb08399561ab9cc60e45931059d3', + 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@9f3b33a275e7a5b19d8ce4aba7960d2a38858681', 'src/third_party/ffmpeg': - 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@0ba37733400593b162e5ae9ff26b384cff49c250', + 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@e1ca3f06adec15150a171bc38f550058b4bbb23b', 'src/third_party/flatbuffers/src': - 'https://chromium.googlesource.com/external/github.com/google/flatbuffers.git@28861d1d7d5ec6ce34d4bbdc10bec4aace341167', + 'https://chromium.googlesource.com/external/github.com/google/flatbuffers.git@bcb9ef187628fe07514e57756d05e6a6296f7dc5', 'src/third_party/grpc/src': { 'url': 'https://chromium.googlesource.com/external/github.com/grpc/grpc.git@822dab21d9995c5cf942476b35ca12a1aa9d2737', }, @@ -209,35 +209,29 @@ deps = { 'condition': 'checkout_linux', }, 'src/third_party/freetype/src': - 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@dd1ced4ee37b375686a1e0fb6e3a6966b195f4ab', + 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@55d0287cfc31115760cb13caa346b407ef0c0ceb', 'src/third_party/harfbuzz-ng/src': - 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@db700b5670d9475cc8ed4880cc9447b232c5e432', + 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@f26fd69d858642d76413b8f4068eaf9b57c40a5f', 'src/third_party/google_benchmark/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/benchmark.git@b177433f3ee2513b1075140c723d73ab8901790f', }, # WebRTC-only dependency (not present in Chromium). 'src/third_party/gtest-parallel': 'https://chromium.googlesource.com/external/github.com/google/gtest-parallel@f4d65b555894b301699c7c3c52906f72ea052e83', - 'src/third_party/google-truth': { - 'packages': [ - { - 'package': 'chromium/third_party/google-truth', - 'version': 'u8oovXxp24lStqX4d54htRovta-75Sy2w7ijg1TL07gC', - }, - ], + 'src/third_party/google-truth/src': { + 'url': 'https://chromium.googlesource.com/external/github.com/google/truth.git@33387149b465f82712a817e6744847fe136949b3', 'condition': 'checkout_android', - 'dep_type': 'cipd', }, 'src/third_party/googletest/src': 'https://chromium.googlesource.com/external/github.com/google/googletest.git@af29db7ec28d6df1c7f0f745186884091e602e07', 'src/third_party/icu': { - 'url': 'https://chromium.googlesource.com/chromium/deps/icu.git@985b9a6f70e13f3db741fed121e4dcc3046ad494', + 'url': 'https://chromium.googlesource.com/chromium/deps/icu.git@a622de35ac311c5ad390a7af80724634e5dc61ed', }, 'src/third_party/jdk': { 'packages': [ { 'package': 'chromium/third_party/jdk', - 'version': '0yjD6s5XYtcGAQoObIys7xs2ThkudwxJwS-2ZNP0SFEC', + 'version': 'tUJrCBvDNDE9jFvgkuOwX8tU6oCWT8CtI2_JxpGlTJIC', }, ], 'condition': 'host_os == "linux" and checkout_android', @@ -259,14 +253,14 @@ deps = { 'src/third_party/jsoncpp/source': 'https://chromium.googlesource.com/external/github.com/open-source-parsers/jsoncpp.git@42e892d96e47b1f6e29844cc705e148ec4856448', # from svn 248 'src/third_party/junit/src': { - 'url': 'https://chromium.googlesource.com/external/junit.git@05fe2a64f59127c02135be22f416e91260d6ede6', + 'url': 'https://chromium.googlesource.com/external/junit.git@0eb5ce72848d730da5bd6d42902fdd6a8a42055d', 'condition': 'checkout_android', }, 'src/third_party/kotlin_stdlib': { 'packages': [ { 'package': 'chromium/third_party/kotlin_stdlib', - 'version': '6cGkpHi3fSRhpRfq2b1mjmzfFmShvtQe6gy4g2nFQd0C', + 'version': 'ZwEhbBOU3zJ8iFzea34zthR0d1a1LlfSPjfsblxKbSgC', }, ], 'condition': 'checkout_android', @@ -285,23 +279,23 @@ deps = { }, # Used for building libFuzzers (only supports Linux). 'src/third_party/libFuzzer/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/compiler-rt/lib/fuzzer.git@26cc39e59b2bf5cbc20486296248a842c536878d', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/compiler-rt/lib/fuzzer.git@758bd21f103a501b362b1ca46fa8fcb692eaa303', 'src/third_party/libjpeg_turbo': - 'https://chromium.googlesource.com/chromium/deps/libjpeg_turbo.git@30bdb85e302ecfc52593636b2f44af438e05e784', + 'https://chromium.googlesource.com/chromium/deps/libjpeg_turbo.git@9b894306ec3b28cea46e84c32b56773a98c483da', 'src/third_party/libsrtp': 'https://chromium.googlesource.com/chromium/deps/libsrtp.git@5b7c744eb8310250ccc534f3f86a2015b3887a0a', 'src/third_party/dav1d/libdav1d': - 'https://chromium.googlesource.com/external/github.com/videolan/dav1d.git@f8ae94eca0f53502a2cddd29a263c1edea4822a0', + 'https://chromium.googlesource.com/external/github.com/videolan/dav1d.git@47107e384bd1dc25674acf04d000a8cdc6195234', 'src/third_party/libaom/source/libaom': - 'https://aomedia.googlesource.com/aom.git@5f8db64abce68a3698fb732697ae50880bc9cac4', + 'https://aomedia.googlesource.com/aom.git@1dbe1c7fae2456f91ccc79fecb919e9ffea0727a', 'src/third_party/libunwindstack': { 'url': 'https://chromium.googlesource.com/chromium/src/third_party/libunwindstack.git@4dbfa0e8c844c8e243b297bc185e54a99ff94f9e', 'condition': 'checkout_android', }, 'src/third_party/perfetto': - 'https://android.googlesource.com/platform/external/perfetto.git@00427277dd1728c836d92f78006c60430c04d6bc', + 'https://android.googlesource.com/platform/external/perfetto.git@cefa83de08a0851cc0b0edee8801cf860a3bc1ed', 'src/third_party/libvpx/source/libvpx': - 'https://chromium.googlesource.com/webm/libvpx.git@38a707faef72eeff89d669c553e7bfe9e08dba8f', + 'https://chromium.googlesource.com/webm/libvpx.git@424723dc025ce451dab9568239a46b18d0919b4d', 'src/third_party/libyuv': 'https://chromium.googlesource.com/libyuv/libyuv.git@04821d1e7d60845525e8db55c7bcd41ef5be9406', 'src/third_party/lss': { @@ -324,7 +318,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'TBaeKaSTY2ttKx2JSFuWiQ8Na80KHZwLEgSAvT1DBJ0C', + 'version': 'jj098_uPn3EKB7YisD1VAQXkZWNtSa6Qxz3vpMQkPR4C', }, ], 'condition': 'checkout_android', @@ -348,7 +342,7 @@ deps = { 'condition': 'checkout_android', }, 'src/tools': - 'https://chromium.googlesource.com/chromium/src/tools@3e78ed797e9e5308cb90f319c7330a6d44dac2c7', + 'https://chromium.googlesource.com/chromium/src/tools@d7f60c3fd236aee6695f04187b6c128536a2bc9f', 'src/third_party/accessibility_test_framework': { 'packages': [ @@ -409,7 +403,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_toolchain/android_toolchain', - 'version': 'R_8suM8m0oHbZ1awdxGXvKEFpAOETscbfZxkkMthyk8C', + 'version': 'NSOM616pOQCfRfDAhC72ltgjyUQp9lAWCMzlmgB18dAC', }, ], 'condition': 'checkout_android', @@ -420,7 +414,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '2n47PFweHFzGxPWjh9RANTrGhmSDWowZ-YhkOV4j11MC', + 'version': 'F-habe4EUUBiRQmzyGAB5oOUtnTNQkhvpoUe4vVZuegC', }, ], 'condition': 'checkout_android', @@ -431,7 +425,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/manifest_merger', - 'version': 'kkbYOGsVRXhtxBiXuTufY0puTnG5QAfyxvFTBHFWL08C', + 'version': 'V90mMwKNdDvQaZ-2eMjmdkHQdGrDn3w4DxA-fGMA8y0C', }, ], 'condition': 'checkout_android', @@ -503,7 +497,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/robolectric', - 'version': 'hzetqh1qFI32FOgQroZvGcGdomrgVBJ6WKRnl1KFw6EC', + 'version': 'UmWqaevXYVw3D8VySDJcqj3aU9zMDFwt1RySUuU0vI8C', }, ], 'condition': 'checkout_android', @@ -525,7 +519,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/turbine', - 'version': 'ZlMS4BOYyYmbU8BuBDGyW7QrkvZ_-pTkm4lH4jKjTi4C', + 'version': 'VRQ9UNP0lvjDXJ4DhORCj66go0TLg5uuGnHWkNN_hgUC', }, ], 'condition': 'checkout_android', @@ -536,11 +530,11 @@ deps = { 'packages': [ { 'package': 'infra/tools/luci/isolate/${{platform}}', - 'version': 'git_revision:fe3cfd422b1012c2c8cf00d65cdb11aa2c26cd66', + 'version': 'git_revision:924cfd2323a9192361b765f81fffc135026c1fee', }, { 'package': 'infra/tools/luci/swarming/${{platform}}', - 'version': 'git_revision:fe3cfd422b1012c2c8cf00d65cdb11aa2c26cd66', + 'version': 'git_revision:924cfd2323a9192361b765f81fffc135026c1fee', }, ], 'dep_type': 'cipd', @@ -597,17 +591,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/android_arch_lifecycle_common_java8': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_common_java8', - 'version': 'version:2@1.1.1.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/android_arch_lifecycle_livedata': { 'packages': [ { @@ -652,28 +635,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_animated_vector_drawable': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_animated_vector_drawable', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - - 'src/third_party/android_deps/libs/com_android_support_appcompat_v7': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_appcompat_v7', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_asynclayoutinflater': { 'packages': [ { @@ -685,17 +646,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_cardview_v7': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_cardview_v7', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_collections': { 'packages': [ { @@ -740,17 +690,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_design': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_design', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_documentfile': { 'packages': [ { @@ -806,17 +745,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_multidex': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_multidex', - 'version': 'version:2@1.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_print': { 'packages': [ { @@ -828,17 +756,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_recyclerview_v7': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_recyclerview_v7', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_slidingpanelayout': { 'packages': [ { @@ -894,50 +811,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_support_fragment': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_fragment', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - - 'src/third_party/android_deps/libs/com_android_support_support_media_compat': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_media_compat', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - - 'src/third_party/android_deps/libs/com_android_support_support_v4': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_v4', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - - 'src/third_party/android_deps/libs/com_android_support_support_vector_drawable': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_vector_drawable', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_swiperefreshlayout': { 'packages': [ { @@ -949,17 +822,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/com_android_support_transition': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_android_support_transition', - 'version': 'version:2@28.0.0.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/com_android_support_versionedparcelable': { 'packages': [ { @@ -1448,7 +1310,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations', - 'version': 'version:2@2.18.0.cr1', + 'version': 'version:2@2.23.0.cr1', }, ], 'condition': 'checkout_android', @@ -2346,17 +2208,6 @@ deps = { 'dep_type': 'cipd', }, - 'src/third_party/android_deps/libs/org_robolectric_shadows_playservices': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_playservices', - 'version': 'version:2@4.10.3.cr1', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/libs/org_robolectric_utils': { 'packages': [ { @@ -2703,11 +2554,11 @@ hooks = [ }, # Download remote exec cfg files { - 'name': 'fetch_reclient_cfgs', + 'name': 'configure_reclient_cfgs', 'pattern': '.', 'condition': 'download_remoteexec_cfg', 'action': ['python3', - 'src/buildtools/reclient_cfgs/fetch_reclient_cfgs.py', + 'src/buildtools/reclient_cfgs/configure_reclient_cfgs.py', '--rbe_instance', Var('rbe_instance'), '--reproxy_cfg_template', @@ -2744,6 +2595,7 @@ include_rules = [ "+absl/base/attributes.h", "+absl/base/config.h", "+absl/base/const_init.h", + "+absl/base/nullability.h", "+absl/base/macros.h", "+absl/cleanup/cleanup.h", "+absl/container/inlined_vector.h", diff --git a/OWNERS_INFRA b/OWNERS_INFRA index 7172570152..eb3bb3ef92 100644 --- a/OWNERS_INFRA +++ b/OWNERS_INFRA @@ -10,6 +10,7 @@ per-file .vpython3=mbonadei@webrtc.org,jansson@webrtc.org,jleconte@webrtc.org per-file AUTHORS=* per-file DEPS=* per-file pylintrc=mbonadei@webrtc.org,jansson@webrtc.org,jleconte@webrtc.org +per-file pylintrc_old_style=mbonadei@webrtc.org,jansson@webrtc.org,jleconte@webrtc.org per-file WATCHLISTS=* per-file native-api.md=mbonadei@webrtc.org per-file ....lua=titovartem@webrtc.org diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 4fbee0e32d..2d9768f86a 100755 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py @@ -47,6 +47,11 @@ CPPLINT_EXCEPTIONS = [ 'voice_engine', ] +PYLINT_OLD_STYLE = [ + "PRESUBMIT.py", + "tools_webrtc/autoroller/roll_deps.py", +] + # These filters will always be removed, even if the caller specifies a filter # set, as they are problematic or broken in some way. # @@ -122,42 +127,42 @@ FILE_PATH_RE = re.compile(r'"(?P(\w|\/)+)(?P\.\w+)"') def FindSrcDirPath(starting_dir): - """Returns the abs path to the src/ dir of the project.""" - src_dir = starting_dir - while os.path.basename(src_dir) != 'src': - src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) - return src_dir + """Returns the abs path to the src/ dir of the project.""" + src_dir = starting_dir + while os.path.basename(src_dir) != 'src': + src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) + return src_dir @contextmanager def _AddToPath(*paths): - original_sys_path = sys.path - sys.path.extend(paths) - try: - yield - finally: - # Restore sys.path to what it was before. - sys.path = original_sys_path + original_sys_path = sys.path + sys.path.extend(paths) + try: + yield + finally: + # Restore sys.path to what it was before. + sys.path = original_sys_path def VerifyNativeApiHeadersListIsValid(input_api, output_api): - """Ensures the list of native API header directories is up to date.""" - non_existing_paths = [] - native_api_full_paths = [ - input_api.os_path.join(input_api.PresubmitLocalPath(), *path.split('/')) - for path in API_DIRS - ] - for path in native_api_full_paths: - if not os.path.isdir(path): - non_existing_paths.append(path) - if non_existing_paths: - return [ - output_api.PresubmitError( - 'Directories to native API headers have changed which has made ' - 'the list in PRESUBMIT.py outdated.\nPlease update it to the ' - 'current location of our native APIs.', non_existing_paths) + """Ensures the list of native API header directories is up to date.""" + non_existing_paths = [] + native_api_full_paths = [ + input_api.os_path.join(input_api.PresubmitLocalPath(), + *path.split('/')) for path in API_DIRS ] - return [] + for path in native_api_full_paths: + if not os.path.isdir(path): + non_existing_paths.append(path) + if non_existing_paths: + return [ + output_api.PresubmitError( + 'Directories to native API headers have changed which has made ' + 'the list in PRESUBMIT.py outdated.\nPlease update it to the ' + 'current location of our native APIs.', non_existing_paths) + ] + return [] API_CHANGE_MSG = """ @@ -181,592 +186,613 @@ Related files: def CheckNativeApiHeaderChanges(input_api, output_api): - """Checks to remind proper changing of native APIs.""" - files = [] - source_file_filter = lambda x: input_api.FilterSourceFile( - x, files_to_check=[r'.+\.(gn|gni|h)$']) - for f in input_api.AffectedSourceFiles(source_file_filter): - for path in API_DIRS: - dn = os.path.dirname(f.LocalPath()) - if path == 'api': - # Special case: Subdirectories included. - if dn == 'api' or dn.startswith('api/'): - files.append(f.LocalPath()) - else: - # Normal case: Subdirectories not included. - if dn == path: - files.append(f.LocalPath()) + """Checks to remind proper changing of native APIs.""" + files = [] + source_file_filter = lambda x: input_api.FilterSourceFile( + x, files_to_check=[r'.+\.(gn|gni|h)$']) + for f in input_api.AffectedSourceFiles(source_file_filter): + for path in API_DIRS: + dn = os.path.dirname(f.LocalPath()) + if path == 'api': + # Special case: Subdirectories included. + if dn == 'api' or dn.startswith('api/'): + files.append(f.LocalPath()) + else: + # Normal case: Subdirectories not included. + if dn == path: + files.append(f.LocalPath()) - if files: - return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)] - return [] + if files: + return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)] + return [] def CheckNoIOStreamInHeaders(input_api, output_api, source_file_filter): - """Checks to make sure no .h files include .""" - files = [] - pattern = input_api.re.compile(r'^#include\s*', - input_api.re.MULTILINE) - file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter( - x)) - for f in input_api.AffectedSourceFiles(file_filter): - if not f.LocalPath().endswith('.h'): - continue - contents = input_api.ReadFile(f) - if pattern.search(contents): - files.append(f) + """Checks to make sure no .h files include .""" + files = [] + pattern = input_api.re.compile(r'^#include\s*', + input_api.re.MULTILINE) + file_filter = lambda x: (input_api.FilterSourceFile(x) and + source_file_filter(x)) + for f in input_api.AffectedSourceFiles(file_filter): + if not f.LocalPath().endswith('.h'): + continue + contents = input_api.ReadFile(f) + if pattern.search(contents): + files.append(f) - if len(files) > 0: - return [ - output_api.PresubmitError( - 'Do not #include in header files, since it inserts ' - 'static initialization into every file including the header. ' - 'Instead, #include . See http://crbug.com/94794', files) - ] - return [] + if len(files) > 0: + return [ + output_api.PresubmitError( + 'Do not #include in header files, since it inserts ' + 'static initialization into every file including the header. ' + 'Instead, #include . See http://crbug.com/94794', + files) + ] + return [] def CheckNoPragmaOnce(input_api, output_api, source_file_filter): - """Make sure that banned functions are not used.""" - files = [] - pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE) - file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter( - x)) - for f in input_api.AffectedSourceFiles(file_filter): - if not f.LocalPath().endswith('.h'): - continue - contents = input_api.ReadFile(f) - if pattern.search(contents): - files.append(f) + """Make sure that banned functions are not used.""" + files = [] + pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE) + file_filter = lambda x: (input_api.FilterSourceFile(x) and + source_file_filter(x)) + for f in input_api.AffectedSourceFiles(file_filter): + if not f.LocalPath().endswith('.h'): + continue + contents = input_api.ReadFile(f) + if pattern.search(contents): + files.append(f) - if files: - return [ - output_api.PresubmitError( - 'Do not use #pragma once in header files.\n' - 'See http://www.chromium.org/developers/coding-style' - '#TOC-File-headers', files) - ] - return [] + if files: + return [ + output_api.PresubmitError( + 'Do not use #pragma once in header files.\n' + 'See http://www.chromium.org/developers/coding-style' + '#TOC-File-headers', files) + ] + return [] def CheckNoFRIEND_TEST(# pylint: disable=invalid-name input_api, output_api, source_file_filter): - """Make sure that gtest's FRIEND_TEST() macro is not used, the + """Make sure that gtest's FRIEND_TEST() macro is not used, the FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes.""" - problems = [] + problems = [] - file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and - source_file_filter(f)) - for f in input_api.AffectedFiles(file_filter=file_filter): - for line_num, line in f.ChangedContents(): - if 'FRIEND_TEST(' in line: - problems.append(' %s:%d' % (f.LocalPath(), line_num)) + file_filter = lambda f: (f.LocalPath().endswith( + ('.cc', '.h')) and source_file_filter(f)) + for f in input_api.AffectedFiles(file_filter=file_filter): + for line_num, line in f.ChangedContents(): + if 'FRIEND_TEST(' in line: + problems.append(' %s:%d' % (f.LocalPath(), line_num)) - if not problems: - return [] - return [ - output_api.PresubmitPromptWarning( - 'WebRTC\'s code should not use gtest\'s FRIEND_TEST() macro. ' - 'Include testsupport/gtest_prod_util.h and use ' - 'FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems)) - ] + if not problems: + return [] + return [ + output_api.PresubmitPromptWarning( + 'WebRTC\'s code should not use gtest\'s FRIEND_TEST() macro. ' + 'Include testsupport/gtest_prod_util.h and use ' + 'FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems)) + ] def IsLintDisabled(disabled_paths, file_path): - """ Checks if a file is disabled for lint check.""" - for path in disabled_paths: - if file_path == path or os.path.dirname(file_path).startswith(path): - return True - return False + """ Checks if a file is disabled for lint check.""" + for path in disabled_paths: + if file_path == path or os.path.dirname(file_path).startswith(path): + return True + return False def CheckApprovedFilesLintClean(input_api, output_api, source_file_filter=None): - """Checks that all new or non-exempt .cc and .h files pass cpplint.py. + """Checks that all new or non-exempt .cc and .h files pass cpplint.py. This check is based on CheckChangeLintsClean in depot_tools/presubmit_canned_checks.py but has less filters and only checks added files.""" - result = [] + result = [] - # Initialize cpplint. - import cpplint - # Access to a protected member _XX of a client class - # pylint: disable=W0212 - cpplint._cpplint_state.ResetErrorCounts() + # Initialize cpplint. + import cpplint + # Access to a protected member _XX of a client class + # pylint: disable=W0212 + cpplint._cpplint_state.ResetErrorCounts() - lint_filters = cpplint._Filters() - lint_filters.extend(DISABLED_LINT_FILTERS) - cpplint._SetFilters(','.join(lint_filters)) + lint_filters = cpplint._Filters() + lint_filters.extend(DISABLED_LINT_FILTERS) + cpplint._SetFilters(','.join(lint_filters)) - # Create a platform independent exempt list for cpplint. - disabled_paths = [ - input_api.os_path.join(*path.split('/')) for path in CPPLINT_EXCEPTIONS - ] + # Create a platform independent exempt list for cpplint. + disabled_paths = [ + input_api.os_path.join(*path.split('/')) for path in CPPLINT_EXCEPTIONS + ] - # Use the strictest verbosity level for cpplint.py (level 1) which is the - # default when running cpplint.py from command line. To make it possible to - # work with not-yet-converted code, we're only applying it to new (or - # moved/renamed) files and files not listed in CPPLINT_EXCEPTIONS. - verbosity_level = 1 - files = [] - for f in input_api.AffectedSourceFiles(source_file_filter): - # Note that moved/renamed files also count as added. - if f.Action() == 'A' or not IsLintDisabled(disabled_paths, f.LocalPath()): - files.append(f.AbsoluteLocalPath()) + # Use the strictest verbosity level for cpplint.py (level 1) which is the + # default when running cpplint.py from command line. To make it possible to + # work with not-yet-converted code, we're only applying it to new (or + # moved/renamed) files and files not listed in CPPLINT_EXCEPTIONS. + verbosity_level = 1 + files = [] + for f in input_api.AffectedSourceFiles(source_file_filter): + # Note that moved/renamed files also count as added. + if f.Action() == 'A' or not IsLintDisabled(disabled_paths, + f.LocalPath()): + files.append(f.AbsoluteLocalPath()) - for file_name in files: - cpplint.ProcessFile(file_name, verbosity_level) + for file_name in files: + cpplint.ProcessFile(file_name, verbosity_level) - if cpplint._cpplint_state.error_count > 0: - if input_api.is_committing: - res_type = output_api.PresubmitError - else: - res_type = output_api.PresubmitPromptWarning - result = [res_type('Changelist failed cpplint.py check.')] + if cpplint._cpplint_state.error_count > 0: + if input_api.is_committing: + res_type = output_api.PresubmitError + else: + res_type = output_api.PresubmitPromptWarning + result = [res_type('Changelist failed cpplint.py check.')] - return result + return result def CheckNoSourcesAbove(input_api, gn_files, output_api): - # Disallow referencing source files with paths above the GN file location. - source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]', - re.MULTILINE | re.DOTALL) - file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"') - violating_gn_files = set() - violating_source_entries = [] - for gn_file in gn_files: - contents = input_api.ReadFile(gn_file) - for source_block_match in source_pattern.finditer(contents): - # Find all source list entries starting with ../ in the source block - # (exclude overrides entries). - for file_list_match in file_pattern.finditer(source_block_match.group(1)): - source_file = file_list_match.group(1) - if 'overrides/' not in source_file: - violating_source_entries.append(source_file) - violating_gn_files.add(gn_file) - if violating_gn_files: - return [ - output_api.PresubmitError( - 'Referencing source files above the directory of the GN file ' - 'is not allowed. Please introduce new GN targets in the proper ' - 'location instead.\n' - 'Invalid source entries:\n' - '%s\n' - 'Violating GN files:' % '\n'.join(violating_source_entries), - items=violating_gn_files) - ] - return [] + # Disallow referencing source files with paths above the GN file location. + source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]', + re.MULTILINE | re.DOTALL) + file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"') + violating_gn_files = set() + violating_source_entries = [] + for gn_file in gn_files: + contents = input_api.ReadFile(gn_file) + for source_block_match in source_pattern.finditer(contents): + # Find all source list entries starting with ../ in the source block + # (exclude overrides entries). + for file_list_match in file_pattern.finditer( + source_block_match.group(1)): + source_file = file_list_match.group(1) + if 'overrides/' not in source_file: + violating_source_entries.append(source_file) + violating_gn_files.add(gn_file) + if violating_gn_files: + return [ + output_api.PresubmitError( + 'Referencing source files above the directory of the GN file ' + 'is not allowed. Please introduce new GN targets in the proper ' + 'location instead.\n' + 'Invalid source entries:\n' + '%s\n' + 'Violating GN files:' % '\n'.join(violating_source_entries), + items=violating_gn_files) + ] + return [] def CheckAbseilDependencies(input_api, gn_files, output_api): - """Checks that Abseil dependencies are declared in `absl_deps`.""" - absl_re = re.compile(r'third_party/abseil-cpp', re.MULTILINE | re.DOTALL) - target_types_to_check = [ - 'rtc_library', - 'rtc_source_set', - 'rtc_static_library', - 'webrtc_fuzzer_test', - ] - error_msg = ('Abseil dependencies in target "%s" (file: %s) ' - 'should be moved to the "absl_deps" parameter.') - errors = [] + """Checks that Abseil dependencies are declared in `absl_deps`.""" + absl_re = re.compile(r'third_party/abseil-cpp', re.MULTILINE | re.DOTALL) + target_types_to_check = [ + 'rtc_library', + 'rtc_source_set', + 'rtc_static_library', + 'webrtc_fuzzer_test', + ] + error_msg = ('Abseil dependencies in target "%s" (file: %s) ' + 'should be moved to the "absl_deps" parameter.') + errors = [] - # pylint: disable=too-many-nested-blocks - for gn_file in gn_files: - gn_file_content = input_api.ReadFile(gn_file) - for target_match in TARGET_RE.finditer(gn_file_content): - target_type = target_match.group('target_type') - target_name = target_match.group('target_name') - target_contents = target_match.group('target_contents') - if target_type in target_types_to_check: - for deps_match in DEPS_RE.finditer(target_contents): - deps = deps_match.group('deps').splitlines() - for dep in deps: - if re.search(absl_re, dep): - errors.append( - output_api.PresubmitError(error_msg % - (target_name, gn_file.LocalPath()))) - break # no need to warn more than once per target - return errors + # pylint: disable=too-many-nested-blocks + for gn_file in gn_files: + gn_file_content = input_api.ReadFile(gn_file) + for target_match in TARGET_RE.finditer(gn_file_content): + target_type = target_match.group('target_type') + target_name = target_match.group('target_name') + target_contents = target_match.group('target_contents') + if target_type in target_types_to_check: + for deps_match in DEPS_RE.finditer(target_contents): + deps = deps_match.group('deps').splitlines() + for dep in deps: + if re.search(absl_re, dep): + errors.append( + output_api.PresubmitError( + error_msg % + (target_name, gn_file.LocalPath()))) + break # no need to warn more than once per target + return errors def CheckNoMixingSources(input_api, gn_files, output_api): - """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target. + """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target. See bugs.webrtc.org/7743 for more context. """ + def _MoreThanOneSourceUsed(*sources_lists): + sources_used = 0 + for source_list in sources_lists: + if len(source_list) > 0: + sources_used += 1 + return sources_used > 1 - def _MoreThanOneSourceUsed(*sources_lists): - sources_used = 0 - for source_list in sources_lists: - if len(source_list) > 0: - sources_used += 1 - return sources_used > 1 - - errors = defaultdict(lambda: []) - for gn_file in gn_files: - gn_file_content = input_api.ReadFile(gn_file) - for target_match in TARGET_RE.finditer(gn_file_content): - # list_of_sources is a list of tuples of the form - # (c_files, cc_files, objc_files) that keeps track of all the - # sources defined in a target. A GN target can have more that - # on definition of sources (since it supports if/else statements). - # E.g.: - # rtc_static_library("foo") { - # if (is_win) { - # sources = [ "foo.cc" ] - # } else { - # sources = [ "foo.mm" ] - # } - # } - # This is allowed and the presubmit check should support this case. - list_of_sources = [] - c_files = [] - cc_files = [] - objc_files = [] - target_name = target_match.group('target_name') - target_contents = target_match.group('target_contents') - for sources_match in SOURCES_RE.finditer(target_contents): - if '+=' not in sources_match.group(0): - if c_files or cc_files or objc_files: + errors = defaultdict(lambda: []) + for gn_file in gn_files: + gn_file_content = input_api.ReadFile(gn_file) + for target_match in TARGET_RE.finditer(gn_file_content): + # list_of_sources is a list of tuples of the form + # (c_files, cc_files, objc_files) that keeps track of all the + # sources defined in a target. A GN target can have more that + # on definition of sources (since it supports if/else statements). + # E.g.: + # rtc_static_library("foo") { + # if (is_win) { + # sources = [ "foo.cc" ] + # } else { + # sources = [ "foo.mm" ] + # } + # } + # This is allowed and the presubmit check should support this case. + list_of_sources = [] + c_files = [] + cc_files = [] + objc_files = [] + target_name = target_match.group('target_name') + target_contents = target_match.group('target_contents') + for sources_match in SOURCES_RE.finditer(target_contents): + if '+=' not in sources_match.group(0): + if c_files or cc_files or objc_files: + list_of_sources.append((c_files, cc_files, objc_files)) + c_files = [] + cc_files = [] + objc_files = [] + for file_match in FILE_PATH_RE.finditer( + sources_match.group(1)): + file_path = file_match.group('file_path') + extension = file_match.group('extension') + if extension == '.c': + c_files.append(file_path + extension) + if extension == '.cc': + cc_files.append(file_path + extension) + if extension in ['.m', '.mm']: + objc_files.append(file_path + extension) list_of_sources.append((c_files, cc_files, objc_files)) - c_files = [] - cc_files = [] - objc_files = [] - for file_match in FILE_PATH_RE.finditer(sources_match.group(1)): - file_path = file_match.group('file_path') - extension = file_match.group('extension') - if extension == '.c': - c_files.append(file_path + extension) - if extension == '.cc': - cc_files.append(file_path + extension) - if extension in ['.m', '.mm']: - objc_files.append(file_path + extension) - list_of_sources.append((c_files, cc_files, objc_files)) - for c_files_list, cc_files_list, objc_files_list in list_of_sources: - if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list): - all_sources = sorted(c_files_list + cc_files_list + objc_files_list) - errors[gn_file.LocalPath()].append((target_name, all_sources)) - if errors: - return [ - output_api.PresubmitError( - 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n' - 'Please create a separate target for each collection of ' - 'sources.\n' - 'Mixed sources: \n' - '%s\n' - 'Violating GN files:\n%s\n' % - (json.dumps(errors, indent=2), '\n'.join(list(errors.keys())))) - ] - return [] + for c_files_list, cc_files_list, objc_files_list in list_of_sources: + if _MoreThanOneSourceUsed(c_files_list, cc_files_list, + objc_files_list): + all_sources = sorted(c_files_list + cc_files_list + + objc_files_list) + errors[gn_file.LocalPath()].append( + (target_name, all_sources)) + if errors: + return [ + output_api.PresubmitError( + 'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n' + 'Please create a separate target for each collection of ' + 'sources.\n' + 'Mixed sources: \n' + '%s\n' + 'Violating GN files:\n%s\n' % + (json.dumps(errors, indent=2), '\n'.join(list(errors.keys())))) + ] + return [] def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api): - cwd = input_api.PresubmitLocalPath() - with _AddToPath( - input_api.os_path.join(cwd, 'tools_webrtc', 'presubmit_checks_lib')): - from check_package_boundaries import CheckPackageBoundaries - build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files] - errors = CheckPackageBoundaries(cwd, build_files)[:5] - if errors: - return [ - output_api.PresubmitError( - 'There are package boundary violations in the following GN ' - 'files:', - long_text='\n\n'.join(str(err) for err in errors)) + cwd = input_api.PresubmitLocalPath() + with _AddToPath( + input_api.os_path.join(cwd, 'tools_webrtc', + 'presubmit_checks_lib')): + from check_package_boundaries import CheckPackageBoundaries + build_files = [ + os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files ] - return [] + errors = CheckPackageBoundaries(cwd, build_files)[:5] + if errors: + return [ + output_api.PresubmitError( + 'There are package boundary violations in the following GN ' + 'files:', + long_text='\n\n'.join(str(err) for err in errors)) + ] + return [] def _ReportFileAndLine(filename, line_num): - """Default error formatter for _FindNewViolationsOfRule.""" - return '%s (line %s)' % (filename, line_num) + """Default error formatter for _FindNewViolationsOfRule.""" + return '%s (line %s)' % (filename, line_num) def CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, output_api, error_formatter=_ReportFileAndLine): - """Ensure warning suppression flags are not added without a reason.""" - msg = ('Usage of //build/config/clang:extra_warnings is discouraged ' - 'in WebRTC.\n' - 'If you are not adding this code (e.g. you are just moving ' - 'existing code) or you want to add an exception,\n' - 'you can add a comment on the line that causes the problem:\n\n' - '"-Wno-odr" # no-presubmit-check TODO(bugs.webrtc.org/BUG_ID)\n' - '\n' - 'Affected files:\n') - errors = [] # 2-element tuples with (file, line number) - clang_warn_re = input_api.re.compile(r'//build/config/clang:extra_warnings') - # pylint: disable-next=fixme - no_presubmit_re = input_api.re.compile( - r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)') - for f in gn_files: - for line_num, line in f.ChangedContents(): - if clang_warn_re.search(line) and not no_presubmit_re.search(line): - errors.append(error_formatter(f.LocalPath(), line_num)) - if errors: - return [output_api.PresubmitError(msg, errors)] - return [] + """Ensure warning suppression flags are not added without a reason.""" + msg = ('Usage of //build/config/clang:extra_warnings is discouraged ' + 'in WebRTC.\n' + 'If you are not adding this code (e.g. you are just moving ' + 'existing code) or you want to add an exception,\n' + 'you can add a comment on the line that causes the problem:\n\n' + '"-Wno-odr" # no-presubmit-check TODO(bugs.webrtc.org/BUG_ID)\n' + '\n' + 'Affected files:\n') + errors = [] # 2-element tuples with (file, line number) + clang_warn_re = input_api.re.compile( + r'//build/config/clang:extra_warnings') + # pylint: disable-next=fixme + no_presubmit_re = input_api.re.compile( + r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)') + for f in gn_files: + for line_num, line in f.ChangedContents(): + if clang_warn_re.search(line) and not no_presubmit_re.search(line): + errors.append(error_formatter(f.LocalPath(), line_num)) + if errors: + return [output_api.PresubmitError(msg, errors)] + return [] def CheckNoTestCaseUsageIsAdded(input_api, output_api, source_file_filter, error_formatter=_ReportFileAndLine): - error_msg = ('Usage of legacy GoogleTest API detected!\nPlease use the ' - 'new API: https://github.com/google/googletest/blob/master/' - 'googletest/docs/primer.md#beware-of-the-nomenclature.\n' - 'Affected files:\n') - errors = [] # 2-element tuples with (file, line number) - test_case_re = input_api.re.compile(r'TEST_CASE') - file_filter = lambda f: (source_file_filter(f) and f.LocalPath().endswith( - '.cc')) - for f in input_api.AffectedSourceFiles(file_filter): - for line_num, line in f.ChangedContents(): - if test_case_re.search(line): - errors.append(error_formatter(f.LocalPath(), line_num)) - if errors: - return [output_api.PresubmitError(error_msg, errors)] - return [] + error_msg = ('Usage of legacy GoogleTest API detected!\nPlease use the ' + 'new API: https://github.com/google/googletest/blob/master/' + 'googletest/docs/primer.md#beware-of-the-nomenclature.\n' + 'Affected files:\n') + errors = [] # 2-element tuples with (file, line number) + test_case_re = input_api.re.compile(r'TEST_CASE') + file_filter = lambda f: (source_file_filter(f) and f.LocalPath().endswith( + '.cc')) + for f in input_api.AffectedSourceFiles(file_filter): + for line_num, line in f.ChangedContents(): + if test_case_re.search(line): + errors.append(error_formatter(f.LocalPath(), line_num)) + if errors: + return [output_api.PresubmitError(error_msg, errors)] + return [] def CheckNoStreamUsageIsAdded(input_api, output_api, source_file_filter, error_formatter=_ReportFileAndLine): - """Make sure that no more dependencies on stringstream are added.""" - error_msg = ('Usage of , and in WebRTC is ' - 'deprecated.\n' - 'This includes the following types:\n' - 'std::istringstream, std::ostringstream, std::wistringstream, ' - 'std::wostringstream,\n' - 'std::wstringstream, std::ostream, std::wostream, std::istream,' - 'std::wistream,\n' - 'std::iostream, std::wiostream.\n' - 'If you are not adding this code (e.g. you are just moving ' - 'existing code),\n' - 'you can add a comment on the line that causes the problem:\n\n' - '#include // no-presubmit-check TODO(webrtc:8982)\n' - 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n' - '\n' - 'If you are adding new code, consider using ' - 'rtc::SimpleStringBuilder\n' - '(in rtc_base/strings/string_builder.h).\n' - 'Affected files:\n') - errors = [] # 2-element tuples with (file, line number) - include_re = input_api.re.compile(r'#include <(i|o|s)stream>') - usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream') - no_presubmit_re = input_api.re.compile( - r'// no-presubmit-check TODO\(webrtc:8982\)') - file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter( - x)) + """Make sure that no more dependencies on stringstream are added.""" + error_msg = ( + 'Usage of , and in WebRTC is ' + 'deprecated.\n' + 'This includes the following types:\n' + 'std::istringstream, std::ostringstream, std::wistringstream, ' + 'std::wostringstream,\n' + 'std::wstringstream, std::ostream, std::wostream, std::istream,' + 'std::wistream,\n' + 'std::iostream, std::wiostream.\n' + 'If you are not adding this code (e.g. you are just moving ' + 'existing code),\n' + 'you can add a comment on the line that causes the problem:\n\n' + '#include // no-presubmit-check TODO(webrtc:8982)\n' + 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n' + '\n' + 'If you are adding new code, consider using ' + 'rtc::SimpleStringBuilder\n' + '(in rtc_base/strings/string_builder.h).\n' + 'Affected files:\n') + errors = [] # 2-element tuples with (file, line number) + include_re = input_api.re.compile(r'#include <(i|o|s)stream>') + usage_re = input_api.re.compile( + r'std::(w|i|o|io|wi|wo|wio)(string)*stream') + no_presubmit_re = input_api.re.compile( + r'// no-presubmit-check TODO\(webrtc:8982\)') + file_filter = lambda x: (input_api.FilterSourceFile(x) and + source_file_filter(x)) - def _IsException(file_path): - is_test = any( - file_path.endswith(x) - for x in ['_test.cc', '_tests.cc', '_unittest.cc', '_unittests.cc']) - return (file_path.startswith('examples') or file_path.startswith('test') - or is_test) + def _IsException(file_path): + is_test = any( + file_path.endswith(x) for x in + ['_test.cc', '_tests.cc', '_unittest.cc', '_unittests.cc']) + return (file_path.startswith('examples') + or file_path.startswith('test') or is_test) - for f in input_api.AffectedSourceFiles(file_filter): - # Usage of stringstream is allowed under examples/ and in tests. - if f.LocalPath() == 'PRESUBMIT.py' or _IsException(f.LocalPath()): - continue - for line_num, line in f.ChangedContents(): - if ((include_re.search(line) or usage_re.search(line)) - and not no_presubmit_re.search(line)): - errors.append(error_formatter(f.LocalPath(), line_num)) - if errors: - return [output_api.PresubmitError(error_msg, errors)] - return [] + for f in input_api.AffectedSourceFiles(file_filter): + # Usage of stringstream is allowed under examples/ and in tests. + if f.LocalPath() == 'PRESUBMIT.py' or _IsException(f.LocalPath()): + continue + for line_num, line in f.ChangedContents(): + if ((include_re.search(line) or usage_re.search(line)) + and not no_presubmit_re.search(line)): + errors.append(error_formatter(f.LocalPath(), line_num)) + if errors: + return [output_api.PresubmitError(error_msg, errors)] + return [] def CheckPublicDepsIsNotUsed(gn_files, input_api, output_api): - """Checks that public_deps is not used without a good reason.""" - result = [] - no_presubmit_check_re = input_api.re.compile( - r'# no-presubmit-check TODO\(webrtc:\d+\)') - error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files ' - 'because it doesn\'t map well to downstream build systems.\n' - 'Used in: %s (line %d).\n' - 'If you are not adding this code (e.g. you are just moving ' - 'existing code) or you have a good reason, you can add this ' - 'comment (verbatim) on the line that causes the problem:\n\n' - 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n') - for affected_file in gn_files: - for (line_number, affected_line) in affected_file.ChangedContents(): - if 'public_deps' in affected_line: - surpressed = no_presubmit_check_re.search(affected_line) - if not surpressed: - result.append( - output_api.PresubmitError( - error_msg % (affected_file.LocalPath(), line_number))) - return result + """Checks that public_deps is not used without a good reason.""" + result = [] + no_presubmit_check_re = input_api.re.compile( + r'# no-presubmit-check TODO\(webrtc:\d+\)') + error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files ' + 'because it doesn\'t map well to downstream build systems.\n' + 'Used in: %s (line %d).\n' + 'If you are not adding this code (e.g. you are just moving ' + 'existing code) or you have a good reason, you can add this ' + 'comment (verbatim) on the line that causes the problem:\n\n' + 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n') + for affected_file in gn_files: + for (line_number, affected_line) in affected_file.ChangedContents(): + if 'public_deps' in affected_line: + surpressed = no_presubmit_check_re.search(affected_line) + if not surpressed: + result.append( + output_api.PresubmitError( + error_msg % + (affected_file.LocalPath(), line_number))) + return result def CheckCheckIncludesIsNotUsed(gn_files, input_api, output_api): - result = [] - error_msg = ('check_includes overrides are not allowed since it can cause ' - 'incorrect dependencies to form. It effectively means that your ' - 'module can include any .h file without depending on its ' - 'corresponding target. There are some exceptional cases when ' - 'this is allowed: if so, get approval from a .gn owner in the ' - 'root OWNERS file.\n' - 'Used in: %s (line %d).') - # pylint: disable-next=fixme - no_presubmit_re = input_api.re.compile( - r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)') - for affected_file in gn_files: - for (line_number, affected_line) in affected_file.ChangedContents(): - if ('check_includes' in affected_line - and not no_presubmit_re.search(affected_line)): - result.append( - output_api.PresubmitError(error_msg % - (affected_file.LocalPath(), line_number))) - return result + result = [] + error_msg = ( + 'check_includes overrides are not allowed since it can cause ' + 'incorrect dependencies to form. It effectively means that your ' + 'module can include any .h file without depending on its ' + 'corresponding target. There are some exceptional cases when ' + 'this is allowed: if so, get approval from a .gn owner in the ' + 'root OWNERS file.\n' + 'Used in: %s (line %d).') + # pylint: disable-next=fixme + no_presubmit_re = input_api.re.compile( + r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)') + for affected_file in gn_files: + for (line_number, affected_line) in affected_file.ChangedContents(): + if ('check_includes' in affected_line + and not no_presubmit_re.search(affected_line)): + result.append( + output_api.PresubmitError( + error_msg % (affected_file.LocalPath(), line_number))) + return result def CheckGnChanges(input_api, output_api): - file_filter = lambda x: (input_api.FilterSourceFile( - x, - files_to_check=(r'.+\.(gn|gni)$', ), - files_to_skip=(r'.*/presubmit_checks_lib/testdata/.*', ))) + file_filter = lambda x: (input_api.FilterSourceFile( + x, + files_to_check=(r'.+\.(gn|gni)$', ), + files_to_skip=(r'.*/presubmit_checks_lib/testdata/.*', ))) - gn_files = [] - for f in input_api.AffectedSourceFiles(file_filter): - gn_files.append(f) + gn_files = [] + for f in input_api.AffectedSourceFiles(file_filter): + gn_files.append(f) - result = [] - if gn_files: - result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api)) - result.extend(CheckNoMixingSources(input_api, gn_files, output_api)) - result.extend(CheckAbseilDependencies(input_api, gn_files, output_api)) - result.extend( - CheckNoPackageBoundaryViolations(input_api, gn_files, output_api)) - result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api)) - result.extend(CheckCheckIncludesIsNotUsed(gn_files, input_api, output_api)) - result.extend( - CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, output_api)) - return result + result = [] + if gn_files: + result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api)) + result.extend(CheckNoMixingSources(input_api, gn_files, output_api)) + result.extend(CheckAbseilDependencies(input_api, gn_files, output_api)) + result.extend( + CheckNoPackageBoundaryViolations(input_api, gn_files, output_api)) + result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, + output_api)) + result.extend( + CheckCheckIncludesIsNotUsed(gn_files, input_api, output_api)) + result.extend( + CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, + output_api)) + return result def CheckGnGen(input_api, output_api): - """Runs `gn gen --check` with default args to detect mismatches between + """Runs `gn gen --check` with default args to detect mismatches between #includes and dependencies in the BUILD.gn files, as well as general build errors. """ - with _AddToPath( - input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools_webrtc', - 'presubmit_checks_lib')): - from build_helpers import RunGnCheck - errors = RunGnCheck(FindSrcDirPath(input_api.PresubmitLocalPath()))[:5] - if errors: - return [ - output_api.PresubmitPromptWarning( - 'Some #includes do not match the build dependency graph. ' - 'Please run:\n' - ' gn gen --check ', - long_text='\n\n'.join(errors)) - ] - return [] + with _AddToPath( + input_api.os_path.join(input_api.PresubmitLocalPath(), + 'tools_webrtc', 'presubmit_checks_lib')): + from build_helpers import RunGnCheck + errors = RunGnCheck(FindSrcDirPath(input_api.PresubmitLocalPath()))[:5] + if errors: + return [ + output_api.PresubmitPromptWarning( + 'Some #includes do not match the build dependency graph. ' + 'Please run:\n' + ' gn gen --check ', + long_text='\n\n'.join(errors)) + ] + return [] def CheckUnwantedDependencies(input_api, output_api, source_file_filter): - """Runs checkdeps on #include statements added in this + """Runs checkdeps on #include statements added in this change. Breaking - rules is an error, breaking ! rules is a warning. """ - # Copied from Chromium's src/PRESUBMIT.py. + # Copied from Chromium's src/PRESUBMIT.py. - # We need to wait until we have an input_api object and use this - # roundabout construct to import checkdeps because this file is - # eval-ed and thus doesn't have __file__. - src_path = FindSrcDirPath(input_api.PresubmitLocalPath()) - checkdeps_path = input_api.os_path.join(src_path, 'buildtools', 'checkdeps') - if not os.path.exists(checkdeps_path): - return [ - output_api.PresubmitError( - 'Cannot find checkdeps at %s\nHave you run "gclient sync" to ' - 'download all the DEPS entries?' % checkdeps_path) - ] - with _AddToPath(checkdeps_path): - import checkdeps - from cpp_checker import CppChecker - from rules import Rule + # We need to wait until we have an input_api object and use this + # roundabout construct to import checkdeps because this file is + # eval-ed and thus doesn't have __file__. + src_path = FindSrcDirPath(input_api.PresubmitLocalPath()) + checkdeps_path = input_api.os_path.join(src_path, 'buildtools', + 'checkdeps') + if not os.path.exists(checkdeps_path): + return [ + output_api.PresubmitError( + 'Cannot find checkdeps at %s\nHave you run "gclient sync" to ' + 'download all the DEPS entries?' % checkdeps_path) + ] + with _AddToPath(checkdeps_path): + import checkdeps + from cpp_checker import CppChecker + from rules import Rule - added_includes = [] - for f in input_api.AffectedFiles(file_filter=source_file_filter): - if not CppChecker.IsCppFile(f.LocalPath()): - continue + added_includes = [] + for f in input_api.AffectedFiles(file_filter=source_file_filter): + if not CppChecker.IsCppFile(f.LocalPath()): + continue - changed_lines = [line for _, line in f.ChangedContents()] - added_includes.append([f.LocalPath(), changed_lines]) + changed_lines = [line for _, line in f.ChangedContents()] + added_includes.append([f.LocalPath(), changed_lines]) - deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) + deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath()) - error_descriptions = [] - warning_descriptions = [] - for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes( - added_includes): - description_with_path = '%s\n %s' % (path, rule_description) - if rule_type == Rule.DISALLOW: - error_descriptions.append(description_with_path) - else: - warning_descriptions.append(description_with_path) + error_descriptions = [] + warning_descriptions = [] + for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes( + added_includes): + description_with_path = '%s\n %s' % (path, rule_description) + if rule_type == Rule.DISALLOW: + error_descriptions.append(description_with_path) + else: + warning_descriptions.append(description_with_path) - results = [] - if error_descriptions: - results.append( - output_api.PresubmitError( - 'You added one or more #includes that violate checkdeps rules.' - '\nCheck that the DEPS files in these locations contain valid ' - 'rules.\nSee ' - 'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ ' - 'for more details about checkdeps.', error_descriptions)) - if warning_descriptions: - results.append( - output_api.PresubmitPromptOrNotify( - 'You added one or more #includes of files that are temporarily' - '\nallowed but being removed. Can you avoid introducing the\n' - '#include? See relevant DEPS file(s) for details and contacts.' - '\nSee ' - 'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ ' - 'for more details about checkdeps.', warning_descriptions)) - return results + results = [] + if error_descriptions: + results.append( + output_api.PresubmitError( + 'You added one or more #includes that violate checkdeps rules.' + '\nCheck that the DEPS files in these locations contain valid ' + 'rules.\nSee ' + 'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ ' + 'for more details about checkdeps.', error_descriptions)) + if warning_descriptions: + results.append( + output_api.PresubmitPromptOrNotify( + 'You added one or more #includes of files that are temporarily' + '\nallowed but being removed. Can you avoid introducing the\n' + '#include? See relevant DEPS file(s) for details and contacts.' + '\nSee ' + 'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ ' + 'for more details about checkdeps.', warning_descriptions)) + return results def CheckCommitMessageBugEntry(input_api, output_api): - """Check that bug entries are well-formed in commit message.""" - bogus_bug_msg = ( - 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the ' - 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.') - results = [] - for bug in input_api.change.BugsFromDescription(): - bug = bug.strip() - if bug.lower() == 'none': - continue - if 'b/' not in bug and ':' not in bug: - try: - if int(bug) > 100000: - # Rough indicator for current chromium bugs. - prefix_guess = 'chromium' - else: - prefix_guess = 'webrtc' - results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' % - (prefix_guess, bug)) - except ValueError: - results.append(bogus_bug_msg % bug) - elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)): - results.append(bogus_bug_msg % bug) - return [output_api.PresubmitError(r) for r in results] + """Check that bug entries are well-formed in commit message.""" + bogus_bug_msg = ( + 'Bogus Bug entry: %s. Please specify the issue tracker prefix and the ' + 'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.' + ) + results = [] + for bug in input_api.change.BugsFromDescription(): + bug = bug.strip() + if bug.lower() == 'none': + continue + if 'b/' not in bug and ':' not in bug: + try: + if int(bug) > 100000: + # Rough indicator for current chromium bugs. + prefix_guess = 'chromium' + else: + prefix_guess = 'webrtc' + results.append( + 'Bug entry requires issue tracker prefix, e.g. %s:%s' % + (prefix_guess, bug)) + except ValueError: + results.append(bogus_bug_msg % bug) + elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)): + results.append(bogus_bug_msg % bug) + return [output_api.PresubmitError(r) for r in results] def CheckChangeHasBugField(input_api, output_api): - """Requires that the changelist is associated with a bug. + """Requires that the changelist is associated with a bug. This check is stricter than the one in depot_tools/presubmit_canned_checks.py since it fails the presubmit if the bug field is missing or doesn't contain @@ -775,277 +801,291 @@ def CheckChangeHasBugField(input_api, output_api): This supports both 'BUG=' and 'Bug:' since we are in the process of migrating to Gerrit and it encourages the usage of 'Bug:'. """ - if input_api.change.BugsFromDescription(): - return [] - return [ - output_api.PresubmitError( - 'The "Bug: [bug number]" footer is mandatory. Please create a ' - 'bug and reference it using either of:\n' - ' * https://bugs.webrtc.org - reference it using Bug: ' - 'webrtc:XXXX\n' - ' * https://crbug.com - reference it using Bug: chromium:XXXXXX') - ] + if input_api.change.BugsFromDescription(): + return [] + return [ + output_api.PresubmitError( + 'The "Bug: [bug number]" footer is mandatory. Please create a ' + 'bug and reference it using either of:\n' + ' * https://bugs.webrtc.org - reference it using Bug: ' + 'webrtc:XXXX\n' + ' * https://crbug.com - reference it using Bug: chromium:XXXXXX') + ] def CheckJSONParseErrors(input_api, output_api, source_file_filter): - """Check that JSON files do not contain syntax errors.""" + """Check that JSON files do not contain syntax errors.""" + def FilterFile(affected_file): + return (input_api.os_path.splitext(affected_file.LocalPath())[1] + == '.json' and source_file_filter(affected_file)) - def FilterFile(affected_file): - return (input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json' - and source_file_filter(affected_file)) + def GetJSONParseError(input_api, filename): + try: + contents = input_api.ReadFile(filename) + input_api.json.loads(contents) + except ValueError as e: + return e + return None - def GetJSONParseError(input_api, filename): - try: - contents = input_api.ReadFile(filename) - input_api.json.loads(contents) - except ValueError as e: - return e - return None - - results = [] - for affected_file in input_api.AffectedFiles(file_filter=FilterFile, - include_deletes=False): - parse_error = GetJSONParseError(input_api, - affected_file.AbsoluteLocalPath()) - if parse_error: - results.append( - output_api.PresubmitError('%s could not be parsed: %s' % - (affected_file.LocalPath(), parse_error))) - return results + results = [] + for affected_file in input_api.AffectedFiles(file_filter=FilterFile, + include_deletes=False): + parse_error = GetJSONParseError(input_api, + affected_file.AbsoluteLocalPath()) + if parse_error: + results.append( + output_api.PresubmitError( + '%s could not be parsed: %s' % + (affected_file.LocalPath(), parse_error))) + return results def RunPythonTests(input_api, output_api): - def Join(*args): - return input_api.os_path.join(input_api.PresubmitLocalPath(), *args) + def Join(*args): + return input_api.os_path.join(input_api.PresubmitLocalPath(), *args) - excluded_files = [ - # These tests should be run manually after webrtc_dashboard_upload target - # has been built. - 'catapult_uploader_test.py', - 'process_perf_results_test.py', - ] + excluded_files = [ + # These tests should be run manually after webrtc_dashboard_upload + # target has been built. + 'catapult_uploader_test.py', + 'process_perf_results_test.py', + ] - test_directories = [ - input_api.PresubmitLocalPath(), - Join('rtc_tools', 'py_event_log_analyzer'), - ] + [ - root for root, _, files in os.walk(Join('tools_webrtc')) if any( - f.endswith('_test.py') and f not in excluded_files for f in files) - ] + test_directories = [ + input_api.PresubmitLocalPath(), + Join('rtc_tools', 'py_event_log_analyzer'), + ] + [ + root for root, _, files in os.walk(Join('tools_webrtc')) if any( + f.endswith('_test.py') and f not in excluded_files for f in files) + ] - tests = [] + tests = [] - for directory in test_directories: - tests.extend( - input_api.canned_checks.GetUnitTestsInDirectory( - input_api, - output_api, - directory, - files_to_check=[r'.+_test\.py$'], - run_on_python2=False)) - return input_api.RunTests(tests, parallel=True) + for directory in test_directories: + tests.extend( + input_api.canned_checks.GetUnitTestsInDirectory( + input_api, + output_api, + directory, + files_to_check=[r'.+_test\.py$'], + run_on_python2=False)) + return input_api.RunTests(tests, parallel=True) def CheckUsageOfGoogleProtobufNamespace(input_api, output_api, source_file_filter): - """Checks that the namespace google::protobuf has not been used.""" - files = [] - pattern = input_api.re.compile(r'google::protobuf') - proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h') - file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter( - x)) - for f in input_api.AffectedSourceFiles(file_filter): - if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']: - continue - contents = input_api.ReadFile(f) - if pattern.search(contents): - files.append(f) + """Checks that the namespace google::protobuf has not been used.""" + files = [] + pattern = input_api.re.compile(r'google::protobuf') + proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h') + file_filter = lambda x: (input_api.FilterSourceFile(x) and + source_file_filter(x)) + for f in input_api.AffectedSourceFiles(file_filter): + if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']: + continue + contents = input_api.ReadFile(f) + if pattern.search(contents): + files.append(f) - if files: - return [ - output_api.PresubmitError( - 'Please avoid to use namespace `google::protobuf` directly.\n' - 'Add a using directive in `%s` and include that header instead.' % - proto_utils_path, files) - ] - return [] + if files: + return [ + output_api.PresubmitError( + 'Please avoid to use namespace `google::protobuf` directly.\n' + 'Add a using directive in `%s` and include that header instead.' + % proto_utils_path, files) + ] + return [] def _LicenseHeader(input_api): - """Returns the license header regexp.""" - # Accept any year number from 2003 to the current year - current_year = int(input_api.time.strftime('%Y')) - allowed_years = (str(s) for s in reversed(range(2003, current_year + 1))) - years_re = '(' + '|'.join(allowed_years) + ')' - license_header = ( - r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. ' - r'All [Rr]ights [Rr]eserved\.\n' - r'.*?\n' - r'.*? Use of this source code is governed by a BSD-style license\n' - r'.*? that can be found in the LICENSE file in the root of the source\n' - r'.*? tree\. An additional intellectual property rights grant can be ' - r'found\n' - r'.*? in the file PATENTS\. All contributing project authors may\n' - r'.*? be found in the AUTHORS file in the root of the source tree\.\n' - ) % { - 'year': years_re, - } - return license_header + """Returns the license header regexp.""" + # Accept any year number from 2003 to the current year + current_year = int(input_api.time.strftime('%Y')) + allowed_years = (str(s) for s in reversed(range(2003, current_year + 1))) + years_re = '(' + '|'.join(allowed_years) + ')' + license_header = ( + r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. ' + r'All [Rr]ights [Rr]eserved\.\n' + r'.*?\n' + r'.*? Use of this source code is governed by a BSD-style license\n' + r'.*? that can be found in the LICENSE file in the root of the source\n' + r'.*? tree\. An additional intellectual property rights grant can be ' + r'found\n' + r'.*? in the file PATENTS\. All contributing project authors may\n' + r'.*? be found in the AUTHORS file in the root of the source tree\.\n' + ) % { + 'year': years_re, + } + return license_header def CommonChecks(input_api, output_api): - """Checks common to both upload and commit.""" - results = [] - # Filter out files that are in objc or ios dirs from being cpplint-ed since - # they do not follow C++ lint rules. - exception_list = input_api.DEFAULT_FILES_TO_SKIP + ( - r".*\bobjc[\\\/].*", - r".*objc\.[hcm]+$", - ) - source_file_filter = lambda x: input_api.FilterSourceFile( - x, None, exception_list) - results.extend( - CheckApprovedFilesLintClean(input_api, output_api, source_file_filter)) - results.extend( - input_api.canned_checks.CheckLicense(input_api, output_api, - _LicenseHeader(input_api))) + """Checks common to both upload and commit.""" + results = [] + # Filter out files that are in objc or ios dirs from being cpplint-ed since + # they do not follow C++ lint rules. + exception_list = input_api.DEFAULT_FILES_TO_SKIP + ( + r".*\bobjc[\\\/].*", + r".*objc\.[hcm]+$", + ) + source_file_filter = lambda x: input_api.FilterSourceFile( + x, None, exception_list) + results.extend( + CheckApprovedFilesLintClean(input_api, output_api, source_file_filter)) + results.extend( + input_api.canned_checks.CheckLicense(input_api, output_api, + _LicenseHeader(input_api))) - # TODO(bugs.webrtc.org/12114): Delete this filter and run pylint on - # all python files. This is a temporary solution. - python_file_filter = lambda f: (f.LocalPath().endswith('.py') and - source_file_filter(f)) - python_changed_files = [ - f.LocalPath() - for f in input_api.AffectedFiles(include_deletes=False, - file_filter=python_file_filter) - ] + # TODO(bugs.webrtc.org/12114): Delete this filter and run pylint on + # all python files. This is a temporary solution. + python_file_filter = lambda f: (f.LocalPath().endswith('.py') and + source_file_filter(f)) + python_changed_files = [ + f.LocalPath() + for f in input_api.AffectedFiles(include_deletes=False, + file_filter=python_file_filter) + ] + pylint_new_style = [ + f for f in python_changed_files if f not in PYLINT_OLD_STYLE + ] + pylint_old_style = [ + f for f in python_changed_files if f in PYLINT_OLD_STYLE + ] + if pylint_new_style: + results.extend( + input_api.canned_checks.RunPylint( + input_api, + output_api, + files_to_check=pylint_new_style, + files_to_skip=( + r'^base[\\\/].*\.py$', + r'^build[\\\/].*\.py$', + r'^buildtools[\\\/].*\.py$', + r'^infra[\\\/].*\.py$', + r'^ios[\\\/].*\.py$', + r'^out.*[\\\/].*\.py$', + r'^testing[\\\/].*\.py$', + r'^third_party[\\\/].*\.py$', + r'^tools[\\\/].*\.py$', + r'^xcodebuild.*[\\\/].*\.py$', + ), + pylintrc='pylintrc', + version='2.7')) - results.extend( - input_api.canned_checks.RunPylint( - input_api, - output_api, - files_to_check=python_changed_files, - files_to_skip=( - r'^base[\\\/].*\.py$', - r'^build[\\\/].*\.py$', - r'^buildtools[\\\/].*\.py$', - r'^infra[\\\/].*\.py$', - r'^ios[\\\/].*\.py$', - r'^out.*[\\\/].*\.py$', - r'^testing[\\\/].*\.py$', - r'^third_party[\\\/].*\.py$', - r'^tools[\\\/].*\.py$', - r'^xcodebuild.*[\\\/].*\.py$', - ), - pylintrc='pylintrc', - version='2.7')) + if pylint_old_style: + results.extend( + input_api.canned_checks.RunPylint(input_api, + output_api, + files_to_check=pylint_old_style, + pylintrc='pylintrc_old_style', + version='2.7')) + # TODO(bugs.webrtc.org/13606): talk/ is no more, so make below checks + # simpler. WebRTC can't use the presubmit_canned_checks.PanProjectChecks + # function since we need to have different license checks in talk/ and + # webrtc/directories. Instead, hand-picked checks are included below. - # TODO(bugs.webrtc.org/13606): talk/ is no more, so make below checks simpler? - # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function - # since we need to have different license checks - # in talk/ and webrtc/directories. - # Instead, hand-picked checks are included below. + # .m and .mm files are ObjC files. For simplicity we will consider + # .h files in ObjC subdirectories ObjC headers. + objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$') + # Skip long-lines check for DEPS and GN files. + build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS') + # Also we will skip most checks for third_party directory. + third_party_filter_list = (r'(^|.*[\\\/])third_party[\\\/].+', ) + eighty_char_sources = lambda x: input_api.FilterSourceFile( + x, + files_to_skip=build_file_filter_list + objc_filter_list + + third_party_filter_list) + hundred_char_sources = lambda x: input_api.FilterSourceFile( + x, files_to_check=objc_filter_list) + non_third_party_sources = lambda x: input_api.FilterSourceFile( + x, files_to_skip=third_party_filter_list) - # .m and .mm files are ObjC files. For simplicity we will consider - # .h files in ObjC subdirectories ObjC headers. - objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$') - # Skip long-lines check for DEPS and GN files. - build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS') - # Also we will skip most checks for third_party directory. - third_party_filter_list = (r'(^|.*[\\\/])third_party[\\\/].+', ) - eighty_char_sources = lambda x: input_api.FilterSourceFile( - x, - files_to_skip=build_file_filter_list + objc_filter_list + - third_party_filter_list) - hundred_char_sources = lambda x: input_api.FilterSourceFile( - x, files_to_check=objc_filter_list) - non_third_party_sources = lambda x: input_api.FilterSourceFile( - x, files_to_skip=third_party_filter_list) - - results.extend( - input_api.canned_checks.CheckLongLines( - input_api, - output_api, - maxlen=80, - source_file_filter=eighty_char_sources)) - results.extend( - input_api.canned_checks.CheckLongLines( - input_api, - output_api, - maxlen=100, - source_file_filter=hundred_char_sources)) - results.extend( - input_api.canned_checks.CheckChangeHasNoTabs( - input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend( - input_api.canned_checks.CheckChangeHasNoStrayWhitespace( - input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend( - input_api.canned_checks.CheckAuthorizedAuthor( - input_api, - output_api, - bot_allowlist=[ - 'chromium-webrtc-autoroll@webrtc-ci.iam.gserviceaccount.com', - 'webrtc-version-updater@webrtc-ci.iam.gserviceaccount.com', - ])) - results.extend( - input_api.canned_checks.CheckChangeTodoHasOwner( - input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend( - input_api.canned_checks.CheckPatchFormatted(input_api, output_api)) - results.extend(CheckNativeApiHeaderChanges(input_api, output_api)) - results.extend( - CheckNoIOStreamInHeaders(input_api, - output_api, - source_file_filter=non_third_party_sources)) - results.extend( - CheckNoPragmaOnce(input_api, - output_api, - source_file_filter=non_third_party_sources)) - results.extend( - CheckNoFRIEND_TEST(input_api, - output_api, - source_file_filter=non_third_party_sources)) - results.extend(CheckGnChanges(input_api, output_api)) - results.extend( - CheckUnwantedDependencies(input_api, - output_api, - source_file_filter=non_third_party_sources)) - results.extend( - CheckJSONParseErrors(input_api, + results.extend( + input_api.canned_checks.CheckLongLines( + input_api, + output_api, + maxlen=80, + source_file_filter=eighty_char_sources)) + results.extend( + input_api.canned_checks.CheckLongLines( + input_api, + output_api, + maxlen=100, + source_file_filter=hundred_char_sources)) + results.extend( + input_api.canned_checks.CheckChangeHasNoTabs( + input_api, output_api, source_file_filter=non_third_party_sources)) + results.extend( + input_api.canned_checks.CheckChangeHasNoStrayWhitespace( + input_api, output_api, source_file_filter=non_third_party_sources)) + results.extend( + input_api.canned_checks.CheckAuthorizedAuthor( + input_api, + output_api, + bot_allowlist=[ + 'chromium-webrtc-autoroll@webrtc-ci.iam.gserviceaccount.com', + 'webrtc-version-updater@webrtc-ci.iam.gserviceaccount.com', + ])) + results.extend( + input_api.canned_checks.CheckChangeTodoHasOwner( + input_api, output_api, source_file_filter=non_third_party_sources)) + results.extend( + input_api.canned_checks.CheckPatchFormatted(input_api, output_api)) + results.extend(CheckNativeApiHeaderChanges(input_api, output_api)) + results.extend( + CheckNoIOStreamInHeaders(input_api, + output_api, + source_file_filter=non_third_party_sources)) + results.extend( + CheckNoPragmaOnce(input_api, + output_api, + source_file_filter=non_third_party_sources)) + results.extend( + CheckNoFRIEND_TEST(input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend(RunPythonTests(input_api, output_api)) - results.extend( - CheckUsageOfGoogleProtobufNamespace( - input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend( - CheckOrphanHeaders(input_api, - output_api, - source_file_filter=non_third_party_sources)) - results.extend( - CheckNewlineAtTheEndOfProtoFiles( - input_api, output_api, source_file_filter=non_third_party_sources)) - results.extend( - CheckNoStreamUsageIsAdded(input_api, output_api, non_third_party_sources)) - results.extend( - CheckNoTestCaseUsageIsAdded(input_api, output_api, + results.extend(CheckGnChanges(input_api, output_api)) + results.extend( + CheckUnwantedDependencies(input_api, + output_api, + source_file_filter=non_third_party_sources)) + results.extend( + CheckJSONParseErrors(input_api, + output_api, + source_file_filter=non_third_party_sources)) + results.extend(RunPythonTests(input_api, output_api)) + results.extend( + CheckUsageOfGoogleProtobufNamespace( + input_api, output_api, source_file_filter=non_third_party_sources)) + results.extend( + CheckOrphanHeaders(input_api, + output_api, + source_file_filter=non_third_party_sources)) + results.extend( + CheckNewlineAtTheEndOfProtoFiles( + input_api, output_api, source_file_filter=non_third_party_sources)) + results.extend( + CheckNoStreamUsageIsAdded(input_api, output_api, non_third_party_sources)) - results.extend(CheckAddedDepsHaveTargetApprovals(input_api, output_api)) - results.extend(CheckApiDepsFileIsUpToDate(input_api, output_api)) - results.extend( - CheckAbslMemoryInclude(input_api, output_api, non_third_party_sources)) - results.extend( - CheckAssertUsage(input_api, output_api, non_third_party_sources)) - results.extend( - CheckBannedAbslMakeUnique(input_api, output_api, non_third_party_sources)) - results.extend( - CheckObjcApiSymbols(input_api, output_api, non_third_party_sources)) - return results + results.extend( + CheckNoTestCaseUsageIsAdded(input_api, output_api, + non_third_party_sources)) + results.extend(CheckAddedDepsHaveTargetApprovals(input_api, output_api)) + results.extend(CheckApiDepsFileIsUpToDate(input_api, output_api)) + results.extend( + CheckAbslMemoryInclude(input_api, output_api, non_third_party_sources)) + results.extend( + CheckAssertUsage(input_api, output_api, non_third_party_sources)) + results.extend( + CheckBannedAbslMakeUnique(input_api, output_api, + non_third_party_sources)) + results.extend( + CheckObjcApiSymbols(input_api, output_api, non_third_party_sources)) + return results def CheckApiDepsFileIsUpToDate(input_api, output_api): - """Check that 'include_rules' in api/DEPS is up to date. + """Check that 'include_rules' in api/DEPS is up to date. The file api/DEPS must be kept up to date in order to avoid to avoid to include internal header from WebRTC's api/ headers. @@ -1054,378 +1094,384 @@ def CheckApiDepsFileIsUpToDate(input_api, output_api): rule for each root level directory. More focused allow rules can be added to 'specific_include_rules'. """ - results = [] - api_deps = os.path.join(input_api.PresubmitLocalPath(), 'api', 'DEPS') - with open(api_deps) as f: - deps_content = _ParseDeps(f.read()) + results = [] + api_deps = os.path.join(input_api.PresubmitLocalPath(), 'api', 'DEPS') + with open(api_deps) as f: + deps_content = _ParseDeps(f.read()) - include_rules = deps_content.get('include_rules', []) - dirs_to_skip = set(['api', 'docs']) + include_rules = deps_content.get('include_rules', []) + dirs_to_skip = set(['api', 'docs']) - # Only check top level directories affected by the current CL. - dirs_to_check = set() - for f in input_api.AffectedFiles(): - path_tokens = [t for t in f.LocalPath().split(os.sep) if t] - if len(path_tokens) > 1: - if (path_tokens[0] not in dirs_to_skip and os.path.isdir( - os.path.join(input_api.PresubmitLocalPath(), path_tokens[0]))): - dirs_to_check.add(path_tokens[0]) + # Only check top level directories affected by the current CL. + dirs_to_check = set() + for f in input_api.AffectedFiles(): + path_tokens = [t for t in f.LocalPath().split(os.sep) if t] + if len(path_tokens) > 1: + if (path_tokens[0] not in dirs_to_skip and os.path.isdir( + os.path.join(input_api.PresubmitLocalPath(), + path_tokens[0]))): + dirs_to_check.add(path_tokens[0]) - missing_include_rules = set() - for p in dirs_to_check: - rule = '-%s' % p - if rule not in include_rules: - missing_include_rules.add(rule) + missing_include_rules = set() + for p in dirs_to_check: + rule = '-%s' % p + if rule not in include_rules: + missing_include_rules.add(rule) - if missing_include_rules: - error_msg = [ - 'include_rules = [\n', - ' ...\n', - ] + if missing_include_rules: + error_msg = [ + 'include_rules = [\n', + ' ...\n', + ] - for r in sorted(missing_include_rules): - error_msg.append(' "%s",\n' % str(r)) + for r in sorted(missing_include_rules): + error_msg.append(' "%s",\n' % str(r)) - error_msg.append(' ...\n') - error_msg.append(']\n') + error_msg.append(' ...\n') + error_msg.append(']\n') - results.append( - output_api.PresubmitError( - 'New root level directory detected! WebRTC api/ headers should ' - 'not #include headers from \n' - 'the new directory, so please update "include_rules" in file\n' - '"%s". Example:\n%s\n' % (api_deps, ''.join(error_msg)))) + results.append( + output_api.PresubmitError( + 'New root level directory detected! WebRTC api/ headers should ' + 'not #include headers from \n' + 'the new directory, so please update "include_rules" in file\n' + '"%s". Example:\n%s\n' % (api_deps, ''.join(error_msg)))) - return results + return results def CheckBannedAbslMakeUnique(input_api, output_api, source_file_filter): - file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and - source_file_filter(f)) + file_filter = lambda f: (f.LocalPath().endswith( + ('.cc', '.h')) and source_file_filter(f)) - files = [] - for f in input_api.AffectedFiles(include_deletes=False, - file_filter=file_filter): - for _, line in f.ChangedContents(): - if 'absl::make_unique' in line: - files.append(f) - break + files = [] + for f in input_api.AffectedFiles(include_deletes=False, + file_filter=file_filter): + for _, line in f.ChangedContents(): + if 'absl::make_unique' in line: + files.append(f) + break - if files: - return [ - output_api.PresubmitError( - 'Please use std::make_unique instead of absl::make_unique.\n' - 'Affected files:', files) - ] - return [] + if files: + return [ + output_api.PresubmitError( + 'Please use std::make_unique instead of absl::make_unique.\n' + 'Affected files:', files) + ] + return [] def CheckObjcApiSymbols(input_api, output_api, source_file_filter): - rtc_objc_export = re.compile(r'RTC_OBJC_EXPORT(.|\n){26}', - re.MULTILINE | re.DOTALL) - file_filter = lambda f: (f.LocalPath().endswith(('.h')) and - source_file_filter(f)) + rtc_objc_export = re.compile(r'RTC_OBJC_EXPORT(.|\n){26}', + re.MULTILINE | re.DOTALL) + file_filter = lambda f: (f.LocalPath().endswith( + ('.h')) and source_file_filter(f)) - files = [] - file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter( - x)) - for f in input_api.AffectedSourceFiles(file_filter): - if not f.LocalPath().endswith('.h') or not 'sdk/objc' in f.LocalPath(): - continue - if f.LocalPath().endswith('sdk/objc/base/RTCMacros.h'): - continue - contents = input_api.ReadFile(f) - for match in rtc_objc_export.finditer(contents): - export_block = match.group(0) - if 'RTC_OBJC_TYPE' not in export_block: - files.append(f.LocalPath()) + files = [] + file_filter = lambda x: (input_api.FilterSourceFile(x) and + source_file_filter(x)) + for f in input_api.AffectedSourceFiles(file_filter): + if not f.LocalPath().endswith('.h') or not 'sdk/objc' in f.LocalPath(): + continue + if f.LocalPath().endswith('sdk/objc/base/RTCMacros.h'): + continue + contents = input_api.ReadFile(f) + for match in rtc_objc_export.finditer(contents): + export_block = match.group(0) + if 'RTC_OBJC_TYPE' not in export_block: + files.append(f.LocalPath()) - if len(files) > 0: - return [ - output_api.PresubmitError( - 'RTC_OBJC_EXPORT types must be wrapped into an RTC_OBJC_TYPE() ' + - 'macro.\n\n' + 'For example:\n' + - 'RTC_OBJC_EXPORT @protocol RTC_OBJC_TYPE(RtcFoo)\n\n' + - 'RTC_OBJC_EXPORT @interface RTC_OBJC_TYPE(RtcFoo)\n\n' + - 'Please fix the following files:', files) - ] - return [] + if len(files) > 0: + return [ + output_api.PresubmitError( + 'RTC_OBJC_EXPORT types must be wrapped into an RTC_OBJC_TYPE() ' + + 'macro.\n\n' + 'For example:\n' + + 'RTC_OBJC_EXPORT @protocol RTC_OBJC_TYPE(RtcFoo)\n\n' + + 'RTC_OBJC_EXPORT @interface RTC_OBJC_TYPE(RtcFoo)\n\n' + + 'Please fix the following files:', files) + ] + return [] def CheckAssertUsage(input_api, output_api, source_file_filter): - pattern = input_api.re.compile(r'\bassert\(') - file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h', '.m', '.mm')) - and source_file_filter(f)) + pattern = input_api.re.compile(r'\bassert\(') + file_filter = lambda f: (f.LocalPath().endswith( + ('.cc', '.h', '.m', '.mm')) and source_file_filter(f)) - files = [] - for f in input_api.AffectedFiles(include_deletes=False, - file_filter=file_filter): - for _, line in f.ChangedContents(): - if pattern.search(line): - files.append(f.LocalPath()) - break + files = [] + for f in input_api.AffectedFiles(include_deletes=False, + file_filter=file_filter): + for _, line in f.ChangedContents(): + if pattern.search(line): + files.append(f.LocalPath()) + break - if len(files) > 0: - return [ - output_api.PresubmitError( - 'Usage of assert() has been detected in the following files, ' - 'please use RTC_DCHECK() instead.\n Files:', files) - ] - return [] + if len(files) > 0: + return [ + output_api.PresubmitError( + 'Usage of assert() has been detected in the following files, ' + 'please use RTC_DCHECK() instead.\n Files:', files) + ] + return [] def CheckAbslMemoryInclude(input_api, output_api, source_file_filter): - pattern = input_api.re.compile(r'^#include\s*"absl/memory/memory.h"', - input_api.re.MULTILINE) - file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and - source_file_filter(f)) + pattern = input_api.re.compile(r'^#include\s*"absl/memory/memory.h"', + input_api.re.MULTILINE) + file_filter = lambda f: (f.LocalPath().endswith( + ('.cc', '.h')) and source_file_filter(f)) - files = [] - for f in input_api.AffectedFiles(include_deletes=False, - file_filter=file_filter): - contents = input_api.ReadFile(f) - if pattern.search(contents): - continue - for _, line in f.ChangedContents(): - if 'absl::WrapUnique' in line: - files.append(f) - break + files = [] + for f in input_api.AffectedFiles(include_deletes=False, + file_filter=file_filter): + contents = input_api.ReadFile(f) + if pattern.search(contents): + continue + for _, line in f.ChangedContents(): + if 'absl::WrapUnique' in line: + files.append(f) + break - if len(files) > 0: - return [ - output_api.PresubmitError( - 'Please include "absl/memory/memory.h" header for ' - 'absl::WrapUnique.\nThis header may or may not be included ' - 'transitively depending on the C++ standard version.', files) - ] - return [] + if len(files) > 0: + return [ + output_api.PresubmitError( + 'Please include "absl/memory/memory.h" header for ' + 'absl::WrapUnique.\nThis header may or may not be included ' + 'transitively depending on the C++ standard version.', files) + ] + return [] def CheckChangeOnUpload(input_api, output_api): - results = [] - results.extend(CommonChecks(input_api, output_api)) - results.extend(CheckGnGen(input_api, output_api)) - results.extend(input_api.canned_checks.CheckGNFormatted( - input_api, output_api)) - return results + results = [] + results.extend(CommonChecks(input_api, output_api)) + results.extend(CheckGnGen(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckGNFormatted(input_api, output_api)) + return results def CheckChangeOnCommit(input_api, output_api): - results = [] - results.extend(CommonChecks(input_api, output_api)) - results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api)) - results.extend(input_api.canned_checks.CheckOwners(input_api, output_api)) - results.extend( - input_api.canned_checks.CheckChangeWasUploaded(input_api, output_api)) - results.extend( - input_api.canned_checks.CheckChangeHasDescription(input_api, output_api)) - results.extend(CheckChangeHasBugField(input_api, output_api)) - results.extend(CheckCommitMessageBugEntry(input_api, output_api)) - results.extend( - input_api.canned_checks.CheckTreeIsOpen( - input_api, - output_api, - json_url='http://webrtc-status.appspot.com/current?format=json')) - return results + results = [] + results.extend(CommonChecks(input_api, output_api)) + results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api)) + results.extend(input_api.canned_checks.CheckOwners(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckChangeWasUploaded(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckChangeHasDescription( + input_api, output_api)) + results.extend(CheckChangeHasBugField(input_api, output_api)) + results.extend(CheckCommitMessageBugEntry(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckTreeIsOpen( + input_api, + output_api, + json_url='http://webrtc-status.appspot.com/current?format=json')) + return results def CheckOrphanHeaders(input_api, output_api, source_file_filter): - # We need to wait until we have an input_api object and use this - # roundabout construct to import prebubmit_checks_lib because this file is - # eval-ed and thus doesn't have __file__. - error_msg = """{} should be listed in {}.""" - results = [] - exempt_paths = [re.escape(os.path.join('tools_webrtc', 'ios', 'SDK'))] + # We need to wait until we have an input_api object and use this + # roundabout construct to import prebubmit_checks_lib because this file is + # eval-ed and thus doesn't have __file__. + error_msg = """{} should be listed in {}.""" + results = [] + exempt_paths = [re.escape(os.path.join('tools_webrtc', 'ios', 'SDK'))] - with _AddToPath( - input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools_webrtc', - 'presubmit_checks_lib')): - from check_orphan_headers import GetBuildGnPathFromFilePath - from check_orphan_headers import IsHeaderInBuildGn + with _AddToPath( + input_api.os_path.join(input_api.PresubmitLocalPath(), + 'tools_webrtc', 'presubmit_checks_lib')): + from check_orphan_headers import GetBuildGnPathFromFilePath + from check_orphan_headers import IsHeaderInBuildGn - file_filter = lambda x: input_api.FilterSourceFile( - x, files_to_skip=exempt_paths) and source_file_filter(x) - for f in input_api.AffectedSourceFiles(file_filter): - if f.LocalPath().endswith('.h'): - file_path = os.path.abspath(f.LocalPath()) - root_dir = os.getcwd() - gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists, - root_dir) - in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path) - if not in_build_gn: - results.append( - output_api.PresubmitError( - error_msg.format(f.LocalPath(), os.path.relpath(gn_file_path)))) - return results + file_filter = lambda x: input_api.FilterSourceFile( + x, files_to_skip=exempt_paths) and source_file_filter(x) + for f in input_api.AffectedSourceFiles(file_filter): + if f.LocalPath().endswith('.h'): + file_path = os.path.abspath(f.LocalPath()) + root_dir = os.getcwd() + gn_file_path = GetBuildGnPathFromFilePath(file_path, + os.path.exists, root_dir) + in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path) + if not in_build_gn: + results.append( + output_api.PresubmitError( + error_msg.format(f.LocalPath(), + os.path.relpath(gn_file_path)))) + return results def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api, source_file_filter): - """Checks that all .proto files are terminated with a newline.""" - error_msg = 'File {} must end with exactly one newline.' - results = [] - file_filter = lambda x: input_api.FilterSourceFile( - x, files_to_check=(r'.+\.proto$', )) and source_file_filter(x) - for f in input_api.AffectedSourceFiles(file_filter): - file_path = f.LocalPath() - with open(file_path) as f: - lines = f.readlines() - if len(lines) > 0 and not lines[-1].endswith('\n'): - results.append(output_api.PresubmitError(error_msg.format(file_path))) - return results + """Checks that all .proto files are terminated with a newline.""" + error_msg = 'File {} must end with exactly one newline.' + results = [] + file_filter = lambda x: input_api.FilterSourceFile( + x, files_to_check=(r'.+\.proto$', )) and source_file_filter(x) + for f in input_api.AffectedSourceFiles(file_filter): + file_path = f.LocalPath() + with open(file_path) as f: + lines = f.readlines() + if len(lines) > 0 and not lines[-1].endswith('\n'): + results.append( + output_api.PresubmitError(error_msg.format(file_path))) + return results def _ExtractAddRulesFromParsedDeps(parsed_deps): - """Extract the rules that add dependencies from a parsed DEPS file. + """Extract the rules that add dependencies from a parsed DEPS file. Args: parsed_deps: the locals dictionary from evaluating the DEPS file.""" - add_rules = set() - add_rules.update([ - rule[1:] for rule in parsed_deps.get('include_rules', []) - if rule.startswith('+') or rule.startswith('!') - ]) - for _, rules in parsed_deps.get('specific_include_rules', {}).items(): + add_rules = set() add_rules.update([ - rule[1:] for rule in rules + rule[1:] for rule in parsed_deps.get('include_rules', []) if rule.startswith('+') or rule.startswith('!') ]) - return add_rules + for _, rules in parsed_deps.get('specific_include_rules', {}).items(): + add_rules.update([ + rule[1:] for rule in rules + if rule.startswith('+') or rule.startswith('!') + ]) + return add_rules def _ParseDeps(contents): - """Simple helper for parsing DEPS files.""" + """Simple helper for parsing DEPS files.""" - # Stubs for handling special syntax in the root DEPS file. - class VarImpl: - def __init__(self, local_scope): - self._local_scope = local_scope + # Stubs for handling special syntax in the root DEPS file. + class VarImpl: + def __init__(self, local_scope): + self._local_scope = local_scope - def Lookup(self, var_name): - """Implements the Var syntax.""" - try: - return self._local_scope['vars'][var_name] - except KeyError as var_not_defined: - raise Exception('Var is not defined: %s' % - var_name) from var_not_defined + def Lookup(self, var_name): + """Implements the Var syntax.""" + try: + return self._local_scope['vars'][var_name] + except KeyError as var_not_defined: + raise Exception('Var is not defined: %s' % + var_name) from var_not_defined - local_scope = {} - global_scope = { - 'Var': VarImpl(local_scope).Lookup, - } - exec(contents, global_scope, local_scope) - return local_scope + local_scope = {} + global_scope = { + 'Var': VarImpl(local_scope).Lookup, + } + exec(contents, global_scope, local_scope) + return local_scope def _CalculateAddedDeps(os_path, old_contents, new_contents): - """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns + """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns a set of DEPS entries that we should look up. For a directory (rather than a specific filename) we fake a path to a specific filename by adding /DEPS. This is chosen as a file that will seldom or never be subject to per-file include_rules. """ - # We ignore deps entries on auto-generated directories. - auto_generated_dirs = ['grit', 'jni'] + # We ignore deps entries on auto-generated directories. + auto_generated_dirs = ['grit', 'jni'] - old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents)) - new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents)) + old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents)) + new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents)) - added_deps = new_deps.difference(old_deps) + added_deps = new_deps.difference(old_deps) - results = set() - for added_dep in added_deps: - if added_dep.split('/')[0] in auto_generated_dirs: - continue - # Assume that a rule that ends in .h is a rule for a specific file. - if added_dep.endswith('.h'): - results.add(added_dep) - else: - results.add(os_path.join(added_dep, 'DEPS')) - return results + results = set() + for added_dep in added_deps: + if added_dep.split('/')[0] in auto_generated_dirs: + continue + # Assume that a rule that ends in .h is a rule for a specific file. + if added_dep.endswith('.h'): + results.add(added_dep) + else: + results.add(os_path.join(added_dep, 'DEPS')) + return results def CheckAddedDepsHaveTargetApprovals(input_api, output_api): - """When a dependency prefixed with + is added to a DEPS file, we + """When a dependency prefixed with + is added to a DEPS file, we want to make sure that the change is reviewed by an OWNER of the target file or directory, to avoid layering violations from being introduced. This check verifies that this happens. """ - virtual_depended_on_files = set() + virtual_depended_on_files = set() - file_filter = lambda f: not input_api.re.match( - r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath()) - for f in input_api.AffectedFiles(include_deletes=False, - file_filter=file_filter): - filename = input_api.os_path.basename(f.LocalPath()) - if filename == 'DEPS': - virtual_depended_on_files.update( - _CalculateAddedDeps(input_api.os_path, '\n'.join(f.OldContents()), - '\n'.join(f.NewContents()))) + file_filter = lambda f: not input_api.re.match( + r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath()) + for f in input_api.AffectedFiles(include_deletes=False, + file_filter=file_filter): + filename = input_api.os_path.basename(f.LocalPath()) + if filename == 'DEPS': + virtual_depended_on_files.update( + _CalculateAddedDeps(input_api.os_path, + '\n'.join(f.OldContents()), + '\n'.join(f.NewContents()))) - if not virtual_depended_on_files: - return [] + if not virtual_depended_on_files: + return [] - if input_api.is_committing: - if input_api.tbr: - return [ - output_api.PresubmitNotifyResult( - '--tbr was specified, skipping OWNERS check for DEPS ' - 'additions') - ] - if input_api.dry_run: - return [ - output_api.PresubmitNotifyResult( - 'This is a dry run, skipping OWNERS check for DEPS ' - 'additions') - ] - if not input_api.change.issue: - return [ - output_api.PresubmitError( - "DEPS approval by OWNERS check failed: this change has " - "no change number, so we can't check it for approvals.") - ] - output = output_api.PresubmitError - else: - output = output_api.PresubmitNotifyResult + if input_api.is_committing: + if input_api.tbr: + return [ + output_api.PresubmitNotifyResult( + '--tbr was specified, skipping OWNERS check for DEPS ' + 'additions') + ] + if input_api.dry_run: + return [ + output_api.PresubmitNotifyResult( + 'This is a dry run, skipping OWNERS check for DEPS ' + 'additions') + ] + if not input_api.change.issue: + return [ + output_api.PresubmitError( + "DEPS approval by OWNERS check failed: this change has " + "no change number, so we can't check it for approvals.") + ] + output = output_api.PresubmitError + else: + output = output_api.PresubmitNotifyResult - owner_email, reviewers = ( - input_api.canned_checks.GetCodereviewOwnerAndReviewers( - input_api, None, approval_needed=input_api.is_committing)) + owner_email, reviewers = ( + input_api.canned_checks.GetCodereviewOwnerAndReviewers( + input_api, None, approval_needed=input_api.is_committing)) - owner_email = owner_email or input_api.change.author_email + owner_email = owner_email or input_api.change.author_email - approval_status = input_api.owners_client.GetFilesApprovalStatus( - virtual_depended_on_files, reviewers.union([owner_email]), []) - missing_files = [ - f for f in virtual_depended_on_files - if approval_status[f] != input_api.owners_client.APPROVED - ] - - # We strip the /DEPS part that was added by - # _FilesToCheckForIncomingDeps to fake a path to a file in a - # directory. - def StripDeps(path): - start_deps = path.rfind('/DEPS') - if start_deps != -1: - return path[:start_deps] - return path - - unapproved_dependencies = [ - "'+%s'," % StripDeps(path) for path in missing_files - ] - - if unapproved_dependencies: - output_list = [ - output('You need LGTM from owners of depends-on paths in DEPS that ' - ' were modified in this CL:\n %s' % - '\n '.join(sorted(unapproved_dependencies))) + approval_status = input_api.owners_client.GetFilesApprovalStatus( + virtual_depended_on_files, reviewers.union([owner_email]), []) + missing_files = [ + f for f in virtual_depended_on_files + if approval_status[f] != input_api.owners_client.APPROVED ] - suggested_owners = input_api.owners_client.SuggestOwners( - missing_files, exclude=[owner_email]) - output_list.append( - output('Suggested missing target path OWNERS:\n %s' % - '\n '.join(suggested_owners or []))) - return output_list - return [] + # We strip the /DEPS part that was added by + # _FilesToCheckForIncomingDeps to fake a path to a file in a + # directory. + def StripDeps(path): + start_deps = path.rfind('/DEPS') + if start_deps != -1: + return path[:start_deps] + return path + + unapproved_dependencies = [ + "'+%s'," % StripDeps(path) for path in missing_files + ] + + if unapproved_dependencies: + output_list = [ + output( + 'You need LGTM from owners of depends-on paths in DEPS that ' + ' were modified in this CL:\n %s' % + '\n '.join(sorted(unapproved_dependencies))) + ] + suggested_owners = input_api.owners_client.SuggestOwners( + missing_files, exclude=[owner_email]) + output_list.append( + output('Suggested missing target path OWNERS:\n %s' % + '\n '.join(suggested_owners or []))) + return output_list + + return [] diff --git a/api/BUILD.gn b/api/BUILD.gn index 07e1e0c3d3..270f36170c 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -162,7 +162,10 @@ rtc_library("candidate") { "../rtc_base:stringutils", "../rtc_base/system:rtc_export", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/strings", + ] } rtc_source_set("turn_customizer") { diff --git a/api/README.md b/api/README.md index 7153cb57c4..cf6d73a855 100644 --- a/api/README.md +++ b/api/README.md @@ -13,8 +13,9 @@ Mostly, just follow the regular [style guide](/g3doc/style-guide.md), but: mountain of technical debt that we’re trying to shrink. * `.cc` files in `api/`, on the other hand, are free to `#include` headers outside `api/`. +* Avoid structs in api, prefer classes. -That is, the preferred way for `api/` code to access non-`api/` code is to call +The preferred way for `api/` code to access non-`api/` code is to call it from a `.cc` file, so that users of our API headers won’t transitively `#include` non-public headers. @@ -25,3 +26,12 @@ usual [rules](/g3doc/style-guide.md#forward-declarations) still apply, though. `.cc` files in `api/` should preferably be kept reasonably small. If a substantial implementation is needed, consider putting it with our non-public code, and just call it from the `api/` `.cc` file. + +Avoid defining api with structs as it makes harder for the api to evolve. +Your struct may gain invariant, or change how it represents data. +Evolving struct from the api is particular challenging as it is designed to be +used in other code bases and thus needs to be updated independetly from its usage. +Class with accessors and setters makes such migration safer. +See [Google C++ style guide](https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes) for more. + +If you need to evolve existent struct in api, prefer first to convert it into a class. diff --git a/api/async_resolver_factory.h b/api/async_resolver_factory.h index ffa958268d..997fe5ce57 100644 --- a/api/async_resolver_factory.h +++ b/api/async_resolver_factory.h @@ -19,13 +19,16 @@ namespace webrtc { // client applications to provide WebRTC with their own mechanism for // performing DNS resolution. // TODO(bugs.webrtc.org/12598): Deprecate and remove. -class AsyncResolverFactory { +class [[deprecated("Use AsyncDnsResolverFactory")]] AsyncResolverFactory { public: AsyncResolverFactory() = default; virtual ~AsyncResolverFactory() = default; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // The caller should call Destroy on the returned object to delete it. virtual rtc::AsyncResolverInterface* Create() = 0; +#pragma clang diagnostic pop }; } // namespace webrtc diff --git a/api/audio/BUILD.gn b/api/audio/BUILD.gn index 4832751b5f..0ecab64086 100644 --- a/api/audio/BUILD.gn +++ b/api/audio/BUILD.gn @@ -55,24 +55,6 @@ rtc_library("aec3_config") { ] } -rtc_library("aec3_config_json") { - visibility = [ "*" ] - allow_poison = [ "rtc_json" ] - sources = [ - "echo_canceller3_config_json.cc", - "echo_canceller3_config_json.h", - ] - deps = [ - ":aec3_config", - "../../rtc_base:checks", - "../../rtc_base:logging", - "../../rtc_base:rtc_json", - "../../rtc_base:stringutils", - "../../rtc_base/system:rtc_export", - ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] -} - rtc_library("aec3_factory") { visibility = [ "*" ] configs += [ "../../modules/audio_processing:apm_debug_dump" ] diff --git a/api/audio/test/BUILD.gn b/api/audio/test/BUILD.gn index dfe8c32f80..8d5822fa54 100644 --- a/api/audio/test/BUILD.gn +++ b/api/audio/test/BUILD.gn @@ -17,13 +17,12 @@ if (rtc_include_tests) { testonly = true sources = [ "audio_frame_unittest.cc", - "echo_canceller3_config_json_unittest.cc", "echo_canceller3_config_unittest.cc", ] deps = [ "..:aec3_config", - "..:aec3_config_json", "..:audio_frame_api", + "../../../modules/audio_processing:aec3_config_json", "../../../test:test_support", ] } diff --git a/api/audio/test/echo_canceller3_config_unittest.cc b/api/audio/test/echo_canceller3_config_unittest.cc index 91312a0f40..da0255806e 100644 --- a/api/audio/test/echo_canceller3_config_unittest.cc +++ b/api/audio/test/echo_canceller3_config_unittest.cc @@ -10,7 +10,7 @@ #include "api/audio/echo_canceller3_config.h" -#include "api/audio/echo_canceller3_config_json.h" +#include "modules/audio_processing/test/echo_canceller3_config_json.h" #include "test/gtest.h" namespace webrtc { diff --git a/api/call/call_factory_interface.h b/api/call/call_factory_interface.h index 6051409cc3..fde8cba66e 100644 --- a/api/call/call_factory_interface.h +++ b/api/call/call_factory_interface.h @@ -26,9 +26,9 @@ struct CallConfig; // is constructed with a CallFactoryInterface, which may or may not be null. class CallFactoryInterface { public: - virtual ~CallFactoryInterface() {} + virtual ~CallFactoryInterface() = default; - virtual Call* CreateCall(const CallConfig& config) = 0; + virtual std::unique_ptr CreateCall(const CallConfig& config) = 0; }; RTC_EXPORT std::unique_ptr CreateCallFactory(); diff --git a/api/call/transport.h b/api/call/transport.h index 6c6cbb8941..292aa11da3 100644 --- a/api/call/transport.h +++ b/api/call/transport.h @@ -45,29 +45,9 @@ struct PacketOptions { class Transport { public: - // New style functions. Default implementations are to accomodate - // subclasses that haven't been converted to new style yet. - // TODO(bugs.webrtc.org/14870): Deprecate and remove old functions. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" virtual bool SendRtp(rtc::ArrayView packet, - const PacketOptions& options) { - return SendRtp(packet.data(), packet.size(), options); - } - virtual bool SendRtcp(rtc::ArrayView packet) { - return SendRtcp(packet.data(), packet.size()); - } -#pragma clang diagnostic pop - // Old style functions. - [[deprecated("Use ArrayView version")]] virtual bool - SendRtp(const uint8_t* packet, size_t length, const PacketOptions& options) { - return SendRtp(rtc::MakeArrayView(packet, length), options); - } - [[deprecated("Use ArrayView version")]] virtual bool SendRtcp( - const uint8_t* packet, - size_t length) { - return SendRtcp(rtc::MakeArrayView(packet, length)); - } + const PacketOptions& options) = 0; + virtual bool SendRtcp(rtc::ArrayView packet) = 0; protected: virtual ~Transport() {} diff --git a/api/candidate.h b/api/candidate.h index 15cd48c7b4..8141d8ce38 100644 --- a/api/candidate.h +++ b/api/candidate.h @@ -17,6 +17,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/strings/string_view.h" #include "rtc_base/checks.h" #include "rtc_base/network_constants.h" @@ -43,7 +44,7 @@ class RTC_EXPORT Candidate { uint32_t priority, absl::string_view username, absl::string_view password, - absl::string_view type, + absl::string_view type ABSL_ATTRIBUTE_LIFETIME_BOUND, uint32_t generation, absl::string_view foundation, uint16_t network_id = 0, @@ -101,7 +102,14 @@ class RTC_EXPORT Candidate { void set_password(absl::string_view password) { Assign(password_, password); } const std::string& type() const { return type_; } - void set_type(absl::string_view type) { Assign(type_, type); } + + // Setting the type requires a constant string (e.g. + // cricket::LOCAL_PORT_TYPE). The type should really be an enum rather than a + // string, but until we make that change the lifetime attribute helps us lock + // things down. See also the `Port` class. + void set_type(absl::string_view type ABSL_ATTRIBUTE_LIFETIME_BOUND) { + Assign(type_, type); + } const std::string& network_name() const { return network_name_; } void set_network_name(absl::string_view network_name) { diff --git a/api/crypto/crypto_options.h b/api/crypto/crypto_options.h index 869dc4f497..29ee46c8cb 100644 --- a/api/crypto/crypto_options.h +++ b/api/crypto/crypto_options.h @@ -42,7 +42,7 @@ struct RTC_EXPORT CryptoOptions { struct Srtp { // Enable GCM crypto suites from RFC 7714 for SRTP. GCM will only be used // if both sides enable it. - bool enable_gcm_crypto_suites = false; + bool enable_gcm_crypto_suites = true; // If set to true, the (potentially insecure) crypto cipher // kSrtpAes128CmSha1_32 will be included in the list of supported ciphers diff --git a/api/frame_transformer_interface.h b/api/frame_transformer_interface.h index bd9ea2d67a..9024988db6 100644 --- a/api/frame_transformer_interface.h +++ b/api/frame_transformer_interface.h @@ -12,6 +12,7 @@ #define API_FRAME_TRANSFORMER_INTERFACE_H_ #include +#include #include #include "api/scoped_refptr.h" @@ -53,6 +54,11 @@ class TransformableFrameInterface { // sender frames to allow received frames to be directly re-transmitted on // other PeerConnectionss. virtual Direction GetDirection() const { return Direction::kUnknown; } + virtual std::string GetMimeType() const { + // TODO(bugs.webrtc.org/15579): Change this to pure virtual after it + // is implemented everywhere. + return "unknown/unknown"; + } }; class TransformableVideoFrameInterface : public TransformableFrameInterface { @@ -78,11 +84,7 @@ class TransformableAudioFrameInterface : public TransformableFrameInterface { return absl::nullopt; } - // TODO(crbug.com/1456628): Change this to pure virtual after it - // is implemented everywhere. - virtual absl::optional AbsoluteCaptureTimestamp() const { - return absl::nullopt; - } + virtual absl::optional AbsoluteCaptureTimestamp() const = 0; enum class FrameType { kEmptyFrame, kAudioFrameSpeech, kAudioFrameCN }; diff --git a/api/ice_transport_interface.h b/api/ice_transport_interface.h index 431f3330a5..001395c215 100644 --- a/api/ice_transport_interface.h +++ b/api/ice_transport_interface.h @@ -115,8 +115,11 @@ struct IceTransportInit final { private: cricket::PortAllocator* port_allocator_ = nullptr; AsyncDnsResolverFactoryInterface* async_dns_resolver_factory_ = nullptr; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // For backwards compatibility. Only one resolver factory can be set. AsyncResolverFactory* async_resolver_factory_ = nullptr; +#pragma clang diagnostic pop RtcEventLog* event_log_ = nullptr; cricket::IceControllerFactoryInterface* ice_controller_factory_ = nullptr; cricket::ActiveIceControllerFactoryInterface* active_ice_controller_factory_ = diff --git a/api/packet_socket_factory.h b/api/packet_socket_factory.h index 29d2606b9b..e389ccb2ff 100644 --- a/api/packet_socket_factory.h +++ b/api/packet_socket_factory.h @@ -76,7 +76,9 @@ class RTC_EXPORT PacketSocketFactory { // to switch to the AsyncDnsResolverInterface. // TODO(bugs.webrtc.org/12598): Remove once all downstream users // are converted. - virtual AsyncResolverInterface* CreateAsyncResolver() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[deprecated]] virtual AsyncResolverInterface* CreateAsyncResolver() { // Default implementation, so that downstream users can remove this // immediately after changing to CreateAsyncDnsResolver RTC_DCHECK_NOTREACHED(); @@ -89,6 +91,7 @@ class RTC_EXPORT PacketSocketFactory { return std::make_unique( CreateAsyncResolver()); } +#pragma clang diagnostic pop private: PacketSocketFactory(const PacketSocketFactory&) = delete; diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h index 3c4ac94593..be5b8724bf 100644 --- a/api/peer_connection_interface.h +++ b/api/peer_connection_interface.h @@ -651,8 +651,7 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface { // will also cause PeerConnection to ignore all but the first m= section of // the same media type (if the PeerConnection is given Unified Plan SDP to // process). - // RingRTC Change to use "Plan B" - SdpSemantics sdp_semantics = SdpSemantics::kPlanB_DEPRECATED; + SdpSemantics sdp_semantics = SdpSemantics::kUnifiedPlan; // TODO(bugs.webrtc.org/9891) - Move to crypto_options or remove. // Actively reset the SRTP parameters whenever the DTLS transports @@ -680,9 +679,6 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface { // Added to be able to control rollout of this feature. bool enable_implicit_rollback = false; - // Whether network condition based codec switching is allowed. - absl::optional allow_codec_switching; - // The delay before doing a usage histogram report for long-lived // PeerConnections. Used for testing only. absl::optional report_usage_pattern_delay_ms; @@ -1453,10 +1449,12 @@ struct RTC_EXPORT PeerConnectionDependencies final { std::unique_ptr async_dns_resolver_factory; // Deprecated - use async_dns_resolver_factory - // Deprecation is in abeyance until Chromium is updated. - // TODO(crbug.com/1475925): Deprecate once Chromium is updated - // [[deprecated("Use async_dns_resolver_factory")]] - std::unique_ptr async_resolver_factory; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[deprecated("Use async_dns_resolver_factory")]] std::unique_ptr< + webrtc::AsyncResolverFactory> + async_resolver_factory; +#pragma clang diagnostic pop std::unique_ptr ice_transport_factory; std::unique_ptr cert_generator; std::unique_ptr tls_cert_verifier; @@ -1560,7 +1558,7 @@ class RTC_EXPORT PeerConnectionFactoryInterface rtc::SSLProtocolVersion ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; // Sets crypto related options, e.g. enabled cipher suites. - CryptoOptions crypto_options = CryptoOptions::Default(); + CryptoOptions crypto_options = {}; }; // Set the options to be used for subsequently created PeerConnections. diff --git a/api/sequence_checker.h b/api/sequence_checker.h index 33e0f3c074..5ff5860371 100644 --- a/api/sequence_checker.h +++ b/api/sequence_checker.h @@ -46,8 +46,22 @@ class RTC_LOCKABLE SequenceChecker public: enum InitialState : bool { kDetached = false, kAttached = true }; + // TODO(tommi): We could maybe join these two ctors and have fewer factory + // functions. At the moment they're separate to minimize code changes when + // we added the second ctor as well as avoiding to have unnecessary code at + // the SequenceChecker which much only run for the SequenceCheckerImpl + // implementation. + // In theory we could have something like: + // + // SequenceChecker(InitialState initial_state = kAttached, + // TaskQueueBase* attached_queue = TaskQueueBase::Current()); + // + // But the problem with that is having the call to `Current()` exist for + // `SequenceCheckerDoNothing`. explicit SequenceChecker(InitialState initial_state = kAttached) : Impl(initial_state) {} + explicit SequenceChecker(TaskQueueBase* attached_queue) + : Impl(attached_queue) {} // Returns true if sequence checker is attached to the current sequence. bool IsCurrent() const { return Impl::IsCurrent(); } diff --git a/api/sequence_checker_unittest.cc b/api/sequence_checker_unittest.cc index f117926d73..e54f33dba9 100644 --- a/api/sequence_checker_unittest.cc +++ b/api/sequence_checker_unittest.cc @@ -83,6 +83,13 @@ TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) { queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); }); } +TEST(SequenceCheckerTest, InitializeForDifferentTaskQueue) { + TaskQueueForTest queue; + SequenceChecker sequence_checker(queue.Get()); + EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); + queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); }); +} + TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) { TaskQueueForTest queue; queue.SendTask([] { diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 8bb1ff2d05..c28b635660 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -286,6 +286,17 @@ class RTC_EXPORT RTCInboundRtpStreamStats final RTCStatsMember total_processing_delay; RTCStatsMember total_assembly_time; RTCStatsMember frames_assembled_from_multiple_packets; + // TODO(https://crbug.com/webrtc/15600): Implement framesRendered, which is + // incremented at the same time that totalInterFrameDelay and + // totalSquaredInterFrameDelay is incremented. (Dividing inter-frame delay by + // framesDecoded is slightly wrong.) + // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-framesrendered + // + // TODO(https://crbug.com/webrtc/15601): Inter-frame, pause and freeze metrics + // all related to when the frame is rendered, but our implementation measures + // at delivery to sink, not at actual render time. When we have an actual + // frame rendered callback, move the calculating of these metrics to there in + // order to make them more accurate. RTCStatsMember total_inter_frame_delay; RTCStatsMember total_squared_inter_frame_delay; RTCStatsMember pause_count; diff --git a/api/task_queue/BUILD.gn b/api/task_queue/BUILD.gn index 527fac414b..e0e2e50514 100644 --- a/api/task_queue/BUILD.gn +++ b/api/task_queue/BUILD.gn @@ -132,7 +132,10 @@ rtc_library("pending_task_safety_flag") { "../../rtc_base/system:no_unique_address", "../../rtc_base/system:rtc_export", ] - absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/functional:any_invocable", + ] } if (rtc_include_tests) { diff --git a/api/task_queue/pending_task_safety_flag.cc b/api/task_queue/pending_task_safety_flag.cc index 437ce0755d..4d8fc2b9f4 100644 --- a/api/task_queue/pending_task_safety_flag.cc +++ b/api/task_queue/pending_task_safety_flag.cc @@ -32,6 +32,17 @@ PendingTaskSafetyFlag::CreateDetached() { return safety_flag; } +// Creates a flag, but with its SequenceChecker explicitly initialized for +// a given task queue and the `alive()` flag specified. +rtc::scoped_refptr +PendingTaskSafetyFlag::CreateAttachedToTaskQueue( + bool alive, + absl::Nonnull attached_queue) { + RTC_DCHECK(attached_queue) << "Null TaskQueue provided"; + return rtc::scoped_refptr( + new PendingTaskSafetyFlag(alive, attached_queue)); +} + rtc::scoped_refptr PendingTaskSafetyFlag::CreateDetachedInactive() { rtc::scoped_refptr safety_flag = CreateInternal(false); diff --git a/api/task_queue/pending_task_safety_flag.h b/api/task_queue/pending_task_safety_flag.h index 7f6a592856..12b1e00ee4 100644 --- a/api/task_queue/pending_task_safety_flag.h +++ b/api/task_queue/pending_task_safety_flag.h @@ -13,6 +13,7 @@ #include +#include "absl/base/nullability.h" #include "absl/functional/any_invocable.h" #include "api/ref_counted_base.h" #include "api/scoped_refptr.h" @@ -68,6 +69,12 @@ class RTC_EXPORT PendingTaskSafetyFlag final // may be created on a different thread than the flag will be used on. static rtc::scoped_refptr CreateDetached(); + // Creates a flag, but with its SequenceChecker explicitly initialized for + // a given task queue and the `alive()` flag specified. + static rtc::scoped_refptr CreateAttachedToTaskQueue( + bool alive, + absl::Nonnull attached_queue); + // Same as `CreateDetached()` except the initial state of the returned flag // will be `!alive()`. static rtc::scoped_refptr CreateDetachedInactive(); @@ -95,6 +102,9 @@ class RTC_EXPORT PendingTaskSafetyFlag final protected: explicit PendingTaskSafetyFlag(bool alive) : alive_(alive) {} + PendingTaskSafetyFlag(bool alive, + absl::Nonnull attached_queue) + : alive_(alive), main_sequence_(attached_queue) {} private: static rtc::scoped_refptr CreateInternal(bool alive); diff --git a/api/task_queue/pending_task_safety_flag_unittest.cc b/api/task_queue/pending_task_safety_flag_unittest.cc index cedf0eb8df..3a1ed268fc 100644 --- a/api/task_queue/pending_task_safety_flag_unittest.cc +++ b/api/task_queue/pending_task_safety_flag_unittest.cc @@ -167,6 +167,17 @@ TEST(PendingTaskSafetyFlagTest, PendingTaskNotAliveInitialized) { EXPECT_TRUE(task_2_ran); } +TEST(PendingTaskSafetyFlagTest, PendingTaskInitializedForTaskQueue) { + TaskQueueForTest tq("PendingTaskAliveInitializedForTaskQueue"); + + // Create a new flag that initially `alive`, attached to a specific TQ. + auto flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(true, tq.Get()); + tq.SendTask([&flag]() { EXPECT_TRUE(flag->alive()); }); + // Repeat the same steps but initialize as inactive. + flag = PendingTaskSafetyFlag::CreateAttachedToTaskQueue(false, tq.Get()); + tq.SendTask([&flag]() { EXPECT_FALSE(flag->alive()); }); +} + TEST(PendingTaskSafetyFlagTest, SafeTask) { rtc::scoped_refptr flag = PendingTaskSafetyFlag::Create(); diff --git a/api/task_queue/task_queue_base.h b/api/task_queue/task_queue_base.h index da7a00d438..89e9e9e3b0 100644 --- a/api/task_queue/task_queue_base.h +++ b/api/task_queue/task_queue_base.h @@ -94,8 +94,7 @@ class RTC_LOCKABLE RTC_EXPORT TaskQueueBase { void PostDelayedTask(absl::AnyInvocable task, TimeDelta delay, const Location& location = Location::Current()) { - PostDelayedTaskImpl(std::move(task), delay, - PostDelayedTaskTraits{.high_precision = false}, + PostDelayedTaskImpl(std::move(task), delay, PostDelayedTaskTraits{}, location); } @@ -119,9 +118,9 @@ class RTC_LOCKABLE RTC_EXPORT TaskQueueBase { absl::AnyInvocable task, TimeDelta delay, const Location& location = Location::Current()) { - PostDelayedTaskImpl(std::move(task), delay, - PostDelayedTaskTraits{.high_precision = true}, - location); + PostDelayedTaskTraits traits; + traits.high_precision = true; + PostDelayedTaskImpl(std::move(task), delay, traits, location); } // As specified by `precision`, calls either PostDelayedTask() or diff --git a/api/test/create_time_controller.cc b/api/test/create_time_controller.cc index d198f2b0fe..2c356cb887 100644 --- a/api/test/create_time_controller.cc +++ b/api/test/create_time_controller.cc @@ -36,7 +36,7 @@ std::unique_ptr CreateTimeControllerBasedCallFactory( public: explicit TimeControllerBasedCallFactory(TimeController* time_controller) : time_controller_(time_controller) {} - Call* CreateCall(const Call::Config& config) override { + std::unique_ptr CreateCall(const CallConfig& config) override { RtpTransportConfig transportConfig = config.ExtractTransportConfig(); return Call::Create(config, time_controller_->GetClock(), diff --git a/api/test/mock_transformable_video_frame.h b/api/test/mock_transformable_video_frame.h index 21c4dc2b69..b3825ddf48 100644 --- a/api/test/mock_transformable_video_frame.h +++ b/api/test/mock_transformable_video_frame.h @@ -11,6 +11,7 @@ #ifndef API_TEST_MOCK_TRANSFORMABLE_VIDEO_FRAME_H_ #define API_TEST_MOCK_TRANSFORMABLE_VIDEO_FRAME_H_ +#include #include #include "api/frame_transformer_interface.h" @@ -36,6 +37,7 @@ class MockTransformableVideoFrame GetDirection, (), (const, override)); + MOCK_METHOD(std::string, GetMimeType, (), (const, override)); MOCK_METHOD(VideoFrameMetadata, Metadata, (), (const, override)); MOCK_METHOD(absl::optional, GetCaptureTimeIdentifier, diff --git a/api/test/pclf/BUILD.gn b/api/test/pclf/BUILD.gn index f3d78370ed..372ff51f49 100644 --- a/api/test/pclf/BUILD.gn +++ b/api/test/pclf/BUILD.gn @@ -66,14 +66,12 @@ rtc_library("media_quality_test_params") { deps = [ ":media_configuration", "../..:async_dns_resolver", - "../../../api:callfactory_api", "../../../api:fec_controller_api", "../../../api:field_trials_view", "../../../api:libjingle_peerconnection_api", "../../../api:packet_socket_factory", "../../../api/audio:audio_mixer_api", "../../../api/rtc_event_log", - "../../../api/task_queue", "../../../api/transport:network_control", "../../../api/video_codecs:video_codecs_api", "../../../modules/audio_processing:api", @@ -96,21 +94,29 @@ rtc_library("peer_configurer") { ":media_configuration", ":media_quality_test_params", "../..:async_dns_resolver", - "../../../api:callfactory_api", "../../../api:create_peer_connection_quality_test_frame_generator", "../../../api:fec_controller_api", - "../../../api:packet_socket_factory", + "../../../api:field_trials_view", + "../../../api:frame_generator_api", + "../../../api:ice_transport_interface", + "../../../api:libjingle_peerconnection_api", "../../../api:peer_network_dependencies", + "../../../api:scoped_refptr", "../../../api/audio:audio_mixer_api", + "../../../api/audio_codecs:audio_codecs_api", + "../../../api/neteq:neteq_api", "../../../api/rtc_event_log", - "../../../api/task_queue", + "../../../api/transport:bitrate_settings", "../../../api/transport:network_control", "../../../api/video_codecs:video_codecs_api", "../../../modules/audio_processing:api", - "../../../rtc_base:network", + "../../../rtc_base:checks", "../../../rtc_base:rtc_certificate_generator", "../../../rtc_base:ssl", - "../../../rtc_base:threading", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + "//third_party/abseil-cpp/absl/types:variant", + ] } diff --git a/api/test/pclf/media_quality_test_params.h b/api/test/pclf/media_quality_test_params.h index a247f342b0..b2ccdf18c5 100644 --- a/api/test/pclf/media_quality_test_params.h +++ b/api/test/pclf/media_quality_test_params.h @@ -17,11 +17,9 @@ #include "api/async_dns_resolver.h" #include "api/audio/audio_mixer.h" -#include "api/call/call_factory_interface.h" #include "api/fec_controller.h" #include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log_factory_interface.h" -#include "api/task_queue/task_queue_factory.h" #include "api/test/pclf/media_configuration.h" #include "api/transport/network_control.h" #include "api/video_codecs/video_decoder_factory.h" @@ -46,8 +44,6 @@ namespace webrtc_pc_e2e { // can override only some parts of media engine like video encoder/decoder // factories. struct PeerConnectionFactoryComponents { - std::unique_ptr task_queue_factory; - std::unique_ptr call_factory; std::unique_ptr event_log_factory; std::unique_ptr fec_controller_factory; std::unique_ptr network_controller_factory; diff --git a/api/test/pclf/peer_configurer.cc b/api/test/pclf/peer_configurer.cc index b614940c99..5e385452b1 100644 --- a/api/test/pclf/peer_configurer.cc +++ b/api/test/pclf/peer_configurer.cc @@ -10,12 +10,38 @@ #include "api/test/pclf/peer_configurer.h" -#include +#include +#include +#include +#include +#include #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/async_dns_resolver.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/fec_controller.h" +#include "api/field_trials_view.h" +#include "api/ice_transport_interface.h" +#include "api/neteq/neteq_factory.h" +#include "api/peer_connection_interface.h" +#include "api/rtc_event_log/rtc_event_log_factory_interface.h" +#include "api/scoped_refptr.h" +#include "api/test/create_peer_connection_quality_test_frame_generator.h" +#include "api/test/frame_generator_interface.h" #include "api/test/pclf/media_configuration.h" #include "api/test/pclf/media_quality_test_params.h" #include "api/test/peer_network_dependencies.h" +#include "api/transport/bitrate_settings.h" +#include "api/transport/network_control.h" +#include "api/video_codecs/video_decoder_factory.h" +#include "api/video_codecs/video_encoder_factory.h" +#include "modules/audio_processing/include/audio_processing.h" +#include "rtc_base/checks.h" +#include "rtc_base/rtc_certificate_generator.h" +#include "rtc_base/ssl_certificate.h" namespace webrtc { namespace webrtc_pc_e2e { @@ -34,17 +60,6 @@ PeerConfigurer* PeerConfigurer::SetName(absl::string_view name) { return this; } -PeerConfigurer* PeerConfigurer::SetTaskQueueFactory( - std::unique_ptr task_queue_factory) { - components_->pcf_dependencies->task_queue_factory = - std::move(task_queue_factory); - return this; -} -PeerConfigurer* PeerConfigurer::SetCallFactory( - std::unique_ptr call_factory) { - components_->pcf_dependencies->call_factory = std::move(call_factory); - return this; -} PeerConfigurer* PeerConfigurer::SetEventLogFactory( std::unique_ptr event_log_factory) { components_->pcf_dependencies->event_log_factory = @@ -212,6 +227,12 @@ PeerConfigurer* PeerConfigurer::SetIceTransportFactory( return this; } +PeerConfigurer* PeerConfigurer::SetFieldTrials( + std::unique_ptr field_trials) { + components_->pcf_dependencies->trials = std::move(field_trials); + return this; +} + PeerConfigurer* PeerConfigurer::SetPortAllocatorExtraFlags( uint32_t extra_flags) { params_->port_allocator_extra_flags = extra_flags; diff --git a/api/test/pclf/peer_configurer.h b/api/test/pclf/peer_configurer.h index d10b53fa3d..c0faf8573a 100644 --- a/api/test/pclf/peer_configurer.h +++ b/api/test/pclf/peer_configurer.h @@ -10,30 +10,35 @@ #ifndef API_TEST_PCLF_PEER_CONFIGURER_H_ #define API_TEST_PCLF_PEER_CONFIGURER_H_ +#include #include #include -#include #include #include "absl/strings/string_view.h" +#include "absl/types/variant.h" #include "api/async_dns_resolver.h" #include "api/audio/audio_mixer.h" -#include "api/call/call_factory_interface.h" +#include "api/audio_codecs/audio_decoder_factory.h" +#include "api/audio_codecs/audio_encoder_factory.h" #include "api/fec_controller.h" +#include "api/field_trials_view.h" +#include "api/ice_transport_interface.h" +#include "api/neteq/neteq_factory.h" +#include "api/peer_connection_interface.h" #include "api/rtc_event_log/rtc_event_log_factory_interface.h" -#include "api/task_queue/task_queue_factory.h" -#include "api/test/create_peer_connection_quality_test_frame_generator.h" +#include "api/scoped_refptr.h" +#include "api/test/frame_generator_interface.h" #include "api/test/pclf/media_configuration.h" #include "api/test/pclf/media_quality_test_params.h" #include "api/test/peer_network_dependencies.h" +#include "api/transport/bitrate_settings.h" #include "api/transport/network_control.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_encoder_factory.h" #include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/network.h" #include "rtc_base/rtc_certificate_generator.h" #include "rtc_base/ssl_certificate.h" -#include "rtc_base/thread.h" namespace webrtc { namespace webrtc_pc_e2e { @@ -52,13 +57,9 @@ class PeerConfigurer { // unique. PeerConfigurer* SetName(absl::string_view name); - // The parameters of the following 9 methods will be passed to the + // The parameters of the following 7 methods will be passed to the // PeerConnectionFactoryInterface implementation that will be created for // this peer. - PeerConfigurer* SetTaskQueueFactory( - std::unique_ptr task_queue_factory); - PeerConfigurer* SetCallFactory( - std::unique_ptr call_factory); PeerConfigurer* SetEventLogFactory( std::unique_ptr event_log_factory); PeerConfigurer* SetFecControllerFactory( @@ -90,7 +91,7 @@ class PeerConfigurer { // peer. PeerConfigurer* SetAsyncDnsResolverFactory( std::unique_ptr - async_resolver_factory); + async_dns_resolver_factory); PeerConfigurer* SetRTCCertificateGenerator( std::unique_ptr cert_generator); PeerConfigurer* SetSSLCertificateVerifier( @@ -164,6 +165,8 @@ class PeerConfigurer { // Set bitrate parameters on PeerConnection. This constraints will be // applied to all summed RTP streams for this peer. PeerConfigurer* SetBitrateSettings(BitrateSettings bitrate_settings); + // Set field trials used for this PeerConnection. + PeerConfigurer* SetFieldTrials(std::unique_ptr field_trials); // Returns InjectableComponents and transfer ownership to the caller. // Can be called once. diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn index 12a1f57066..84a0968ee9 100644 --- a/api/transport/BUILD.gn +++ b/api/transport/BUILD.gn @@ -53,6 +53,7 @@ rtc_library("field_trial_based_config") { ] deps = [ "../../api:field_trials_registry", + "../../rtc_base/system:rtc_export", "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] diff --git a/api/transport/field_trial_based_config.h b/api/transport/field_trial_based_config.h index d47140e579..441f89e51d 100644 --- a/api/transport/field_trial_based_config.h +++ b/api/transport/field_trial_based_config.h @@ -14,10 +14,11 @@ #include "absl/strings/string_view.h" #include "api/field_trials_registry.h" +#include "rtc_base/system/rtc_export.h" namespace webrtc { // Implementation using the field trial API fo the key value lookup. -class FieldTrialBasedConfig : public FieldTrialsRegistry { +class RTC_EXPORT FieldTrialBasedConfig : public FieldTrialsRegistry { private: std::string GetValue(absl::string_view key) const override; }; diff --git a/api/transport/network_types.cc b/api/transport/network_types.cc index d6495ce490..53d5e5a443 100644 --- a/api/transport/network_types.cc +++ b/api/transport/network_types.cc @@ -97,7 +97,7 @@ PacedPacketInfo::PacedPacketInfo(int probe_cluster_id, probe_cluster_min_bytes(probe_cluster_min_bytes) {} bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const { - return send_bitrate_bps == rhs.send_bitrate_bps && + return send_bitrate == rhs.send_bitrate && probe_cluster_id == rhs.probe_cluster_id && probe_cluster_min_probes == rhs.probe_cluster_min_probes && probe_cluster_min_bytes == rhs.probe_cluster_min_bytes; diff --git a/api/transport/network_types.h b/api/transport/network_types.h index a62c350474..b8ef4e938b 100644 --- a/api/transport/network_types.h +++ b/api/transport/network_types.h @@ -93,7 +93,7 @@ struct PacedPacketInfo { // TODO(srte): Move probing info to a separate, optional struct. static constexpr int kNotAProbe = -1; - int send_bitrate_bps = -1; + DataRate send_bitrate = DataRate::BitsPerSec(0); int probe_cluster_id = kNotAProbe; int probe_cluster_min_probes = -1; int probe_cluster_min_bytes = -1; diff --git a/api/transport/rtp/rtp_source.h b/api/transport/rtp/rtp_source.h index 41a0552db0..11149f5421 100644 --- a/api/transport/rtp/rtp_source.h +++ b/api/transport/rtp/rtp_source.h @@ -56,33 +56,12 @@ class RtpSource { extensions_(extensions), rtp_timestamp_(rtp_timestamp) {} - // TODO(bugs.webrtc.org/13757): deprecate when chromium stop using this - // and remove after 2023-09-18 - RtpSource(int64_t timestamp_ms, - uint32_t source_id, - RtpSourceType source_type, - uint32_t rtp_timestamp, - const RtpSource::Extensions& extensions) - : timestamp_(Timestamp::Millis(timestamp_ms)), - source_id_(source_id), - source_type_(source_type), - extensions_(extensions), - rtp_timestamp_(rtp_timestamp) {} - RtpSource(const RtpSource&) = default; RtpSource& operator=(const RtpSource&) = default; ~RtpSource() = default; Timestamp timestamp() const { return timestamp_; } - // TODO(bugs.webrtc.org/13757): deprecate when chromium stop using this - // and remove after 2023-09-18 - int64_t timestamp_ms() const { return timestamp_.ms(); } - [[deprecated]] void update_timestamp_ms(int64_t timestamp_ms) { - RTC_DCHECK_LE(timestamp_.ms(), timestamp_ms); - timestamp_ = Timestamp::Millis(timestamp_ms); - } - // The identifier of the source can be the CSRC or the SSRC. uint32_t source_id() const { return source_id_; } diff --git a/api/video/color_space.cc b/api/video/color_space.cc index a0cd32edb2..dcb9c67da5 100644 --- a/api/video/color_space.cc +++ b/api/video/color_space.cc @@ -10,6 +10,8 @@ #include "api/video/color_space.h" +#include "rtc_base/strings/string_builder.h" + namespace webrtc { namespace { // Try to convert `enum_value` into the enum class T. `enum_bitmask` is created @@ -124,6 +126,80 @@ const HdrMetadata* ColorSpace::hdr_metadata() const { return hdr_metadata_ ? &*hdr_metadata_ : nullptr; } +#define PRINT_ENUM_CASE(TYPE, NAME) \ + case TYPE::NAME: \ + ss << #NAME; \ + break; + +std::string ColorSpace::AsString() const { + char buf[1024]; + rtc::SimpleStringBuilder ss(buf); + ss << "{primaries:"; + switch (primaries_) { + PRINT_ENUM_CASE(PrimaryID, kBT709) + PRINT_ENUM_CASE(PrimaryID, kUnspecified) + PRINT_ENUM_CASE(PrimaryID, kBT470M) + PRINT_ENUM_CASE(PrimaryID, kBT470BG) + PRINT_ENUM_CASE(PrimaryID, kSMPTE170M) + PRINT_ENUM_CASE(PrimaryID, kSMPTE240M) + PRINT_ENUM_CASE(PrimaryID, kFILM) + PRINT_ENUM_CASE(PrimaryID, kBT2020) + PRINT_ENUM_CASE(PrimaryID, kSMPTEST428) + PRINT_ENUM_CASE(PrimaryID, kSMPTEST431) + PRINT_ENUM_CASE(PrimaryID, kSMPTEST432) + PRINT_ENUM_CASE(PrimaryID, kJEDECP22) + } + ss << ", transfer:"; + switch (transfer_) { + PRINT_ENUM_CASE(TransferID, kBT709) + PRINT_ENUM_CASE(TransferID, kUnspecified) + PRINT_ENUM_CASE(TransferID, kGAMMA22) + PRINT_ENUM_CASE(TransferID, kGAMMA28) + PRINT_ENUM_CASE(TransferID, kSMPTE170M) + PRINT_ENUM_CASE(TransferID, kSMPTE240M) + PRINT_ENUM_CASE(TransferID, kLINEAR) + PRINT_ENUM_CASE(TransferID, kLOG) + PRINT_ENUM_CASE(TransferID, kLOG_SQRT) + PRINT_ENUM_CASE(TransferID, kIEC61966_2_4) + PRINT_ENUM_CASE(TransferID, kBT1361_ECG) + PRINT_ENUM_CASE(TransferID, kIEC61966_2_1) + PRINT_ENUM_CASE(TransferID, kBT2020_10) + PRINT_ENUM_CASE(TransferID, kBT2020_12) + PRINT_ENUM_CASE(TransferID, kSMPTEST2084) + PRINT_ENUM_CASE(TransferID, kSMPTEST428) + PRINT_ENUM_CASE(TransferID, kARIB_STD_B67) + } + ss << ", matrix:"; + switch (matrix_) { + PRINT_ENUM_CASE(MatrixID, kRGB) + PRINT_ENUM_CASE(MatrixID, kBT709) + PRINT_ENUM_CASE(MatrixID, kUnspecified) + PRINT_ENUM_CASE(MatrixID, kFCC) + PRINT_ENUM_CASE(MatrixID, kBT470BG) + PRINT_ENUM_CASE(MatrixID, kSMPTE170M) + PRINT_ENUM_CASE(MatrixID, kSMPTE240M) + PRINT_ENUM_CASE(MatrixID, kYCOCG) + PRINT_ENUM_CASE(MatrixID, kBT2020_NCL) + PRINT_ENUM_CASE(MatrixID, kBT2020_CL) + PRINT_ENUM_CASE(MatrixID, kSMPTE2085) + PRINT_ENUM_CASE(MatrixID, kCDNCLS) + PRINT_ENUM_CASE(MatrixID, kCDCLS) + PRINT_ENUM_CASE(MatrixID, kBT2100_ICTCP) + } + + ss << ", range:"; + switch (range_) { + PRINT_ENUM_CASE(RangeID, kInvalid) + PRINT_ENUM_CASE(RangeID, kLimited) + PRINT_ENUM_CASE(RangeID, kFull) + PRINT_ENUM_CASE(RangeID, kDerived) + } + ss << "}"; + return ss.str(); +} + +#undef PRINT_ENUM_CASE + bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) { constexpr PrimaryID kPrimaryIds[] = { PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M, diff --git a/api/video/color_space.h b/api/video/color_space.h index e491c52e72..31963a1253 100644 --- a/api/video/color_space.h +++ b/api/video/color_space.h @@ -13,6 +13,8 @@ #include +#include + #include "absl/types/optional.h" #include "api/video/hdr_metadata.h" #include "rtc_base/system/rtc_export.h" @@ -155,6 +157,7 @@ class RTC_EXPORT ColorSpace { ChromaSiting chroma_siting_horizontal() const; ChromaSiting chroma_siting_vertical() const; const HdrMetadata* hdr_metadata() const; + std::string AsString() const; bool set_primaries_from_uint8(uint8_t enum_value); bool set_transfer_from_uint8(uint8_t enum_value); diff --git a/api/video/encoded_image.h b/api/video/encoded_image.h index 5fc4a0e60a..8f0226c7a7 100644 --- a/api/video/encoded_image.h +++ b/api/video/encoded_image.h @@ -79,17 +79,16 @@ class RTC_EXPORT EncodedImage { EncodedImage& operator=(EncodedImage&&); EncodedImage& operator=(const EncodedImage&); - // TODO(bugs.webrtc.org/9378): Change style to timestamp(), set_timestamp(), - // for consistency with the VideoFrame class. Set frame timestamp (90kHz). - void SetTimestamp(uint32_t timestamp) { timestamp_rtp_ = timestamp; } - - // Get frame timestamp (90kHz). - uint32_t Timestamp() const { return timestamp_rtp_; } + // Frame capture time in RTP timestamp representation (90kHz). + void SetRtpTimestamp(uint32_t timestamp) { timestamp_rtp_ = timestamp; } + uint32_t RtpTimestamp() const { return timestamp_rtp_; } void SetEncodeTime(int64_t encode_start_ms, int64_t encode_finish_ms); - webrtc::Timestamp CaptureTime() const; + // Frame capture time in local time. + Timestamp CaptureTime() const; + // Frame capture time in ntp epoch time, i.e. time since 1st Jan 1900 int64_t NtpTimeMs() const { return ntp_time_ms_; } // Every simulcast layer (= encoding) has its own encoder and RTP stream. @@ -101,11 +100,11 @@ class RTC_EXPORT EncodedImage { simulcast_index_ = simulcast_index; } - const absl::optional& CaptureTimeIdentifier() const { + const absl::optional& CaptureTimeIdentifier() const { return capture_time_identifier_; } void SetCaptureTimeIdentifier( - const absl::optional& capture_time_identifier) { + const absl::optional& capture_time_identifier) { capture_time_identifier_ = capture_time_identifier; } @@ -245,7 +244,7 @@ class RTC_EXPORT EncodedImage { size_t size_ = 0; // Size of encoded frame data. uint32_t timestamp_rtp_ = 0; absl::optional simulcast_index_; - absl::optional capture_time_identifier_; + absl::optional capture_time_identifier_; absl::optional spatial_index_; absl::optional temporal_index_; std::map spatial_layer_frame_size_bytes_; diff --git a/api/video/frame_buffer.cc b/api/video/frame_buffer.cc index 4cdf2212a6..5e8fc0ff44 100644 --- a/api/video/frame_buffer.cc +++ b/api/video/frame_buffer.cc @@ -50,7 +50,7 @@ int64_t GetFrameId(const FrameIteratorT& it) { template uint32_t GetTimestamp(const FrameIteratorT& it) { - return it->second.encoded_frame->Timestamp(); + return it->second.encoded_frame->RtpTimestamp(); } template @@ -76,7 +76,7 @@ bool FrameBuffer::InsertFrame(std::unique_ptr frame) { if (frame->Id() <= decoded_frame_history_.GetLastDecodedFrameId()) { if (legacy_frame_id_jump_behavior_ && frame->is_keyframe() && - AheadOf(frame->Timestamp(), + AheadOf(frame->RtpTimestamp(), *decoded_frame_history_.GetLastDecodedFrameTimestamp())) { RTC_DLOG(LS_WARNING) << "Keyframe " << frame->Id() diff --git a/api/video/rtp_video_frame_assembler.cc b/api/video/rtp_video_frame_assembler.cc index 3d041ca218..a19fcdcb97 100644 --- a/api/video/rtp_video_frame_assembler.cc +++ b/api/video/rtp_video_frame_assembler.cc @@ -51,6 +51,10 @@ std::unique_ptr CreateDepacketizer( return std::make_unique(); case RtpVideoFrameAssembler::kGeneric: return std::make_unique(); + case RtpVideoFrameAssembler::kH265: + // TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265 + RTC_DCHECK_NOTREACHED(); + return nullptr; } RTC_DCHECK_NOTREACHED(); return nullptr; diff --git a/api/video/rtp_video_frame_assembler.h b/api/video/rtp_video_frame_assembler.h index 83162cb818..099c962f23 100644 --- a/api/video/rtp_video_frame_assembler.h +++ b/api/video/rtp_video_frame_assembler.h @@ -52,7 +52,7 @@ class RtpVideoFrameAssembler { // FrameVector is just a vector-like type of std::unique_ptr. // The vector type may change without notice. using FrameVector = absl::InlinedVector; - enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric }; + enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric, kH265 }; explicit RtpVideoFrameAssembler(PayloadFormat payload_format); RtpVideoFrameAssembler(const RtpVideoFrameAssembler& other) = delete; diff --git a/api/video/rtp_video_frame_assembler_unittests.cc b/api/video/rtp_video_frame_assembler_unittests.cc index 82defb8399..50d1aaae12 100644 --- a/api/video/rtp_video_frame_assembler_unittests.cc +++ b/api/video/rtp_video_frame_assembler_unittests.cc @@ -89,6 +89,9 @@ class PacketBuilder { case PayloadFormat::kAv1: { return kVideoCodecAV1; } + case PayloadFormat::kH265: { + return kVideoCodecH265; + } case PayloadFormat::kGeneric: { return kVideoCodecGeneric; } diff --git a/api/video/test/color_space_unittest.cc b/api/video/test/color_space_unittest.cc index 1d8b3a87f6..ae66b018f5 100644 --- a/api/video/test/color_space_unittest.cc +++ b/api/video/test/color_space_unittest.cc @@ -71,4 +71,13 @@ TEST(ColorSpace, TestSettingChromaSitingVerticalFromUint8) { EXPECT_FALSE(color_space.set_chroma_siting_vertical_from_uint8(3)); } +TEST(ColorSpace, TestAsStringFunction) { + ColorSpace color_space( + ColorSpace::PrimaryID::kBT709, ColorSpace::TransferID::kBT709, + ColorSpace::MatrixID::kBT709, ColorSpace::RangeID::kLimited); + EXPECT_EQ( + color_space.AsString(), + "{primaries:kBT709, transfer:kBT709, matrix:kBT709, range:kLimited}"); +} + } // namespace webrtc diff --git a/api/video/video_codec_type.h b/api/video/video_codec_type.h index 74a4bc4258..444eb9bcd0 100644 --- a/api/video/video_codec_type.h +++ b/api/video/video_codec_type.h @@ -22,6 +22,7 @@ enum VideoCodecType { kVideoCodecAV1, kVideoCodecH264, kVideoCodecMultiplex, + kVideoCodecH265, }; } // namespace webrtc diff --git a/api/video/video_frame.cc b/api/video/video_frame.cc index 35dedce1b2..fd975dfd87 100644 --- a/api/video/video_frame.cc +++ b/api/video/video_frame.cc @@ -164,9 +164,9 @@ VideoFrame::Builder::~Builder() = default; VideoFrame VideoFrame::Builder::build() { RTC_CHECK(video_frame_buffer_ != nullptr); return VideoFrame(id_, video_frame_buffer_, timestamp_us_, - capture_time_identifier_, timestamp_rtp_, ntp_time_ms_, - rotation_, color_space_, render_parameters_, update_rect_, - packet_infos_); + capture_time_identifier_, reference_time_, timestamp_rtp_, + ntp_time_ms_, rotation_, color_space_, render_parameters_, + update_rect_, packet_infos_); } VideoFrame::Builder& VideoFrame::Builder::set_video_frame_buffer( @@ -193,6 +193,12 @@ VideoFrame::Builder& VideoFrame::Builder::set_capture_time_identifier( return *this; } +VideoFrame::Builder& VideoFrame::Builder::set_reference_time( + const absl::optional& reference_time) { + reference_time_ = reference_time; + return *this; +} + VideoFrame::Builder& VideoFrame::Builder::set_timestamp_rtp( uint32_t timestamp_rtp) { timestamp_rtp_ = timestamp_rtp; @@ -264,6 +270,7 @@ VideoFrame::VideoFrame(uint16_t id, const rtc::scoped_refptr& buffer, int64_t timestamp_us, const absl::optional& capture_time_identifier, + const absl::optional& reference_time, uint32_t timestamp_rtp, int64_t ntp_time_ms, VideoRotation rotation, @@ -277,6 +284,7 @@ VideoFrame::VideoFrame(uint16_t id, ntp_time_ms_(ntp_time_ms), timestamp_us_(timestamp_us), capture_time_identifier_(capture_time_identifier), + reference_time_(reference_time), rotation_(rotation), color_space_(color_space), render_parameters_(render_parameters), diff --git a/api/video/video_frame.h b/api/video/video_frame.h index a257a3209e..2608f9aa42 100644 --- a/api/video/video_frame.h +++ b/api/video/video_frame.h @@ -109,6 +109,8 @@ class RTC_EXPORT VideoFrame { Builder& set_timestamp_us(int64_t timestamp_us); Builder& set_capture_time_identifier( const absl::optional& capture_time_identifier); + Builder& set_reference_time( + const absl::optional& reference_time); Builder& set_timestamp_rtp(uint32_t timestamp_rtp); Builder& set_ntp_time_ms(int64_t ntp_time_ms); Builder& set_rotation(VideoRotation rotation); @@ -123,6 +125,7 @@ class RTC_EXPORT VideoFrame { rtc::scoped_refptr video_frame_buffer_; int64_t timestamp_us_ = 0; absl::optional capture_time_identifier_; + absl::optional reference_time_; uint32_t timestamp_rtp_ = 0; int64_t ntp_time_ms_ = 0; VideoRotation rotation_ = kVideoRotation_0; @@ -177,6 +180,13 @@ class RTC_EXPORT VideoFrame { capture_time_identifier_ = capture_time_identifier; } + const absl::optional& reference_time() const { + return reference_time_; + } + void set_reference_time(const absl::optional& reference_time) { + reference_time_ = reference_time; + } + // Set frame timestamp (90kHz). void set_timestamp(uint32_t timestamp) { timestamp_rtp_ = timestamp; } @@ -274,6 +284,7 @@ class RTC_EXPORT VideoFrame { const rtc::scoped_refptr& buffer, int64_t timestamp_us, const absl::optional& capture_time_identifier, + const absl::optional& reference_time, uint32_t timestamp_rtp, int64_t ntp_time_ms, VideoRotation rotation, @@ -289,6 +300,11 @@ class RTC_EXPORT VideoFrame { int64_t ntp_time_ms_; int64_t timestamp_us_; absl::optional capture_time_identifier_; + // Contains a monotonically increasing clock time and represents the time + // when the frame was captured. Not all platforms provide the "true" sample + // capture time in |reference_time| but might instead use a somewhat delayed + // (by the time it took to capture the frame) version of it. + absl::optional reference_time_; VideoRotation rotation_; absl::optional color_space_; // Contains parameters that affect have the frame should be rendered. diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn index d9dd5aea2b..94c9cc8b87 100644 --- a/api/video_codecs/BUILD.gn +++ b/api/video_codecs/BUILD.gn @@ -31,7 +31,10 @@ rtc_source_set("scalability_mode_helper") { "scalability_mode_helper.cc", "scalability_mode_helper.h", ] - deps = [ "../../modules/video_coding/svc:scalability_mode_util" ] + deps = [ + ":scalability_mode", + "../../modules/video_coding/svc:scalability_mode_util", + ] absl_deps = [ "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", diff --git a/api/video_codecs/scalability_mode_helper.cc b/api/video_codecs/scalability_mode_helper.cc index b4571632d9..09ede9c87d 100644 --- a/api/video_codecs/scalability_mode_helper.cc +++ b/api/video_codecs/scalability_mode_helper.cc @@ -34,4 +34,9 @@ absl::optional ScalabilityModeStringToNumTemporalLayers( return ScalabilityModeToNumTemporalLayers(*scalability_mode); } +absl::optional ScalabilityModeStringToEnum( + absl::string_view scalability_mode_string) { + return ScalabilityModeFromString(scalability_mode_string); +} + } // namespace webrtc diff --git a/api/video_codecs/scalability_mode_helper.h b/api/video_codecs/scalability_mode_helper.h index a8b060d079..21dcfc2f30 100644 --- a/api/video_codecs/scalability_mode_helper.h +++ b/api/video_codecs/scalability_mode_helper.h @@ -13,6 +13,7 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" +#include "api/video_codecs/scalability_mode.h" namespace webrtc { @@ -26,6 +27,11 @@ absl::optional ScalabilityModeStringToNumSpatialLayers( absl::optional ScalabilityModeStringToNumTemporalLayers( absl::string_view scalability_mode_string); +// Convert the `scalability_mode_string` to the scalability mode enum value +// or nullopt if the given mode is unknown. +absl::optional ScalabilityModeStringToEnum( + absl::string_view scalability_mode_string); + } // namespace webrtc #endif // API_VIDEO_CODECS_SCALABILITY_MODE_HELPER_H_ diff --git a/api/video_codecs/sdp_video_format.cc b/api/video_codecs/sdp_video_format.cc index cb7e98a682..51ae18cd78 100644 --- a/api/video_codecs/sdp_video_format.cc +++ b/api/video_codecs/sdp_video_format.cc @@ -15,6 +15,9 @@ #include "api/array_view.h" #include "api/video_codecs/av1_profile.h" #include "api/video_codecs/h264_profile_level_id.h" +#ifdef RTC_ENABLE_H265 +#include "api/video_codecs/h265_profile_tier_level.h" +#endif #include "api/video_codecs/video_codec.h" #include "api/video_codecs/vp9_profile.h" #include "rtc_base/checks.h" @@ -61,6 +64,10 @@ bool IsSameCodecSpecific(const SdpVideoFormat& format1, return VP9IsSameProfile(format1.parameters, format2.parameters); case kVideoCodecAV1: return AV1IsSameProfile(format1.parameters, format2.parameters); +#ifdef RTC_ENABLE_H265 + case kVideoCodecH265: + return H265IsSameProfileTierLevel(format1.parameters, format2.parameters); +#endif default: return true; } diff --git a/api/video_codecs/test/sdp_video_format_unittest.cc b/api/video_codecs/test/sdp_video_format_unittest.cc index bb158aeb95..797a9a2e72 100644 --- a/api/video_codecs/test/sdp_video_format_unittest.cc +++ b/api/video_codecs/test/sdp_video_format_unittest.cc @@ -25,12 +25,18 @@ TEST(SdpVideoFormatTest, SameCodecNameNoParameters) { EXPECT_TRUE(Sdp("VP8").IsSameCodec(Sdp("vp8"))); EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("vp9"))); EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("Av1"))); +#ifdef RTC_ENABLE_H265 + EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp("h265"))); +#endif } TEST(SdpVideoFormatTest, DifferentCodecNameNoParameters) { EXPECT_FALSE(Sdp("H264").IsSameCodec(Sdp("VP8"))); EXPECT_FALSE(Sdp("VP8").IsSameCodec(Sdp("VP9"))); EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("VP8"))); +#ifdef RTC_ENABLE_H265 + EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp("VP8"))); +#endif } TEST(SdpVideoFormatTest, SameCodecNameSameParameters) { @@ -50,6 +56,17 @@ TEST(SdpVideoFormatTest, SameCodecNameSameParameters) { .IsSameCodec(Sdp("AV1", Params{{"profile", "0"}}))); EXPECT_TRUE(Sdp("AV1", Params{{"profile", "2"}}) .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}}))); +#ifdef RTC_ENABLE_H265 + EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp( + "H265", + Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}}))); + EXPECT_TRUE( + Sdp("H265", + Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}}) + .IsSameCodec(Sdp("H265", Params{{"profile-id", "2"}, + {"tier-flag", "0"}, + {"level-id", "93"}}))); +#endif } TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) { @@ -69,6 +86,35 @@ TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) { .IsSameCodec(Sdp("AV1", Params{{"profile", "1"}}))); EXPECT_FALSE(Sdp("AV1", Params{{"profile", "1"}}) .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}}))); +#ifdef RTC_ENABLE_H265 + EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp( + "H265", + Params{{"profile-id", "0"}, {"tier-flag", "0"}, {"level-id", "93"}}))); + EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp( + "H265", + Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "93"}}))); + EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp( + "H265", + Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "90"}}))); + EXPECT_FALSE( + Sdp("H265", + Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}}) + .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"}, + {"tier-flag", "0"}, + {"level-id", "93"}}))); + EXPECT_FALSE( + Sdp("H265", + Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "120"}}) + .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"}, + {"tier-flag", "0"}, + {"level-id", "120"}}))); + EXPECT_FALSE( + Sdp("H265", + Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}}) + .IsSameCodec(Sdp("H265", Params{{"profile-id", "1"}, + {"tier-flag", "0"}, + {"level-id", "90"}}))); +#endif } TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) { @@ -86,6 +132,12 @@ TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) { .IsSameCodec(Sdp("H264", Params{{"profile", "0"}}))); EXPECT_FALSE(Sdp("AV1", Params{{"profile", "2"}}) .IsSameCodec(Sdp("VP9", Params{{"profile", "2"}}))); +#ifdef RTC_ENABLE_H265 + EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "0"}}) + .IsSameCodec(Sdp("H264", Params{{"profile-id", "0"}}))); + EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "2"}}) + .IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}}))); +#endif } TEST(SdpVideoFormatTest, H264PacketizationMode) { diff --git a/api/video_codecs/video_codec.cc b/api/video_codecs/video_codec.cc index c6122d3f6a..39a345d699 100644 --- a/api/video_codecs/video_codec.cc +++ b/api/video_codecs/video_codec.cc @@ -28,6 +28,7 @@ constexpr char kPayloadNameAv1x[] = "AV1X"; constexpr char kPayloadNameH264[] = "H264"; constexpr char kPayloadNameGeneric[] = "Generic"; constexpr char kPayloadNameMultiplex[] = "Multiplex"; +constexpr char kPayloadNameH265[] = "H265"; } // namespace bool VideoCodecVP8::operator==(const VideoCodecVP8& other) const { @@ -102,6 +103,16 @@ const VideoCodecH264& VideoCodec::H264() const { return codec_specific_.H264; } +VideoCodecAV1* VideoCodec::AV1() { + RTC_DCHECK_EQ(codecType, kVideoCodecAV1); + return &codec_specific_.AV1; +} + +const VideoCodecAV1& VideoCodec::AV1() const { + RTC_DCHECK_EQ(codecType, kVideoCodecAV1); + return codec_specific_.AV1; +} + const char* CodecTypeToPayloadString(VideoCodecType type) { switch (type) { case kVideoCodecVP8: @@ -116,6 +127,8 @@ const char* CodecTypeToPayloadString(VideoCodecType type) { return kPayloadNameMultiplex; case kVideoCodecGeneric: return kPayloadNameGeneric; + case kVideoCodecH265: + return kPayloadNameH265; } RTC_CHECK_NOTREACHED(); } @@ -132,6 +145,8 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) { return kVideoCodecH264; if (absl::EqualsIgnoreCase(name, kPayloadNameMultiplex)) return kVideoCodecMultiplex; + if (absl::EqualsIgnoreCase(name, kPayloadNameH265)) + return kVideoCodecH265; return kVideoCodecGeneric; } diff --git a/api/video_codecs/video_codec.h b/api/video_codecs/video_codec.h index 496cfb5e22..a596af1528 100644 --- a/api/video_codecs/video_codec.h +++ b/api/video_codecs/video_codec.h @@ -97,6 +97,16 @@ struct VideoCodecH264 { uint8_t numberOfTemporalLayers; }; +struct VideoCodecAV1 { + bool operator==(const VideoCodecAV1& other) const { + return automatic_resize_on == other.automatic_resize_on; + } + bool operator!=(const VideoCodecAV1& other) const { + return !(*this == other); + } + bool automatic_resize_on; +}; + // Translates from name of codec to codec type and vice versa. RTC_EXPORT const char* CodecTypeToPayloadString(VideoCodecType type); RTC_EXPORT VideoCodecType PayloadStringToCodecType(const std::string& name); @@ -105,6 +115,7 @@ union VideoCodecUnion { VideoCodecVP8 VP8; VideoCodecVP9 VP9; VideoCodecH264 H264; + VideoCodecAV1 AV1; }; enum class VideoCodecMode { kRealtimeVideo, kScreensharing }; @@ -193,6 +204,8 @@ class RTC_EXPORT VideoCodec { const VideoCodecVP9& VP9() const; VideoCodecH264* H264(); const VideoCodecH264& H264() const; + VideoCodecAV1* AV1(); + const VideoCodecAV1& AV1() const; private: // TODO(hta): Consider replacing the union with a pointer type. diff --git a/api/video_codecs/video_decoder_software_fallback_wrapper.cc b/api/video_codecs/video_decoder_software_fallback_wrapper.cc index c52ddbe511..2af4d39b3a 100644 --- a/api/video_codecs/video_decoder_software_fallback_wrapper.cc +++ b/api/video_codecs/video_decoder_software_fallback_wrapper.cc @@ -170,6 +170,10 @@ void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() { RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex", hw_decoded_frames_since_last_fallback_); break; + case kVideoCodecH265: + RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H265", + hw_decoded_frames_since_last_fallback_); + break; } } diff --git a/api/wrapping_async_dns_resolver.h b/api/wrapping_async_dns_resolver.h index d07f1464c5..b384f97652 100644 --- a/api/wrapping_async_dns_resolver.h +++ b/api/wrapping_async_dns_resolver.h @@ -33,9 +33,10 @@ namespace webrtc { -class WrappingAsyncDnsResolver; +class [[deprecated("Use AsyncDnsResolver directly")]] WrappingAsyncDnsResolver; -class RTC_EXPORT WrappingAsyncDnsResolverResult +class [[deprecated( + "Use AsyncDnsResolver directly")]] RTC_EXPORT WrappingAsyncDnsResolverResult : public AsyncDnsResolverResult { public: explicit WrappingAsyncDnsResolverResult(WrappingAsyncDnsResolver* owner) @@ -54,6 +55,8 @@ class RTC_EXPORT WrappingAsyncDnsResolverResult class RTC_EXPORT WrappingAsyncDnsResolver : public AsyncDnsResolverInterface, public sigslot::has_slots<> { public: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" explicit WrappingAsyncDnsResolver(rtc::AsyncResolverInterface* wrapped) : wrapped_(absl::WrapUnique(wrapped)), result_(this) {} @@ -124,6 +127,7 @@ class RTC_EXPORT WrappingAsyncDnsResolver : public AsyncDnsResolverInterface, State state_ RTC_GUARDED_BY(sequence_checker_) = State::kNotStarted; WrappingAsyncDnsResolverResult result_ RTC_GUARDED_BY(sequence_checker_); bool within_resolve_result_ RTC_GUARDED_BY(sequence_checker_) = false; +#pragma clang diagnostic pop }; } // namespace webrtc diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc index ed5ab40d49..84900f22d1 100644 --- a/audio/channel_receive.cc +++ b/audio/channel_receive.cc @@ -481,21 +481,15 @@ AudioMixer::Source::AudioFrameInfo ChannelReceive::GetAudioFrameWithInfo( // Fill in local capture clock offset in `audio_frame->packet_infos_`. RtpPacketInfos::vector_type packet_infos; for (auto& packet_info : audio_frame->packet_infos_) { - absl::optional local_capture_clock_offset_q32x32; + RtpPacketInfo new_packet_info(packet_info); if (packet_info.absolute_capture_time().has_value()) { MutexLock lock(&ts_stats_lock_); - local_capture_clock_offset_q32x32 = - capture_clock_offset_updater_.AdjustEstimatedCaptureClockOffset( - packet_info.absolute_capture_time() - ->estimated_capture_clock_offset); + new_packet_info.set_local_capture_clock_offset( + capture_clock_offset_updater_.ConvertsToTimeDela( + capture_clock_offset_updater_.AdjustEstimatedCaptureClockOffset( + packet_info.absolute_capture_time() + ->estimated_capture_clock_offset))); } - RtpPacketInfo new_packet_info(packet_info); - absl::optional local_capture_clock_offset; - if (local_capture_clock_offset_q32x32.has_value()) { - local_capture_clock_offset = TimeDelta::Millis( - UQ32x32ToInt64Ms(*local_capture_clock_offset_q32x32)); - } - new_packet_info.set_local_capture_clock_offset(local_capture_clock_offset); packet_infos.push_back(std::move(new_packet_info)); } audio_frame->packet_infos_ = RtpPacketInfos(packet_infos); diff --git a/audio/channel_send.cc b/audio/channel_send.cc index e3058fca0d..08dd74591d 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc @@ -411,8 +411,10 @@ ChannelSend::ChannelSend( configuration.event_log = event_log_; configuration.rtt_stats = rtcp_rtt_stats; - configuration.retransmission_rate_limiter = - retransmission_rate_limiter_.get(); + if (field_trials.IsDisabled("WebRTC-DisableRtxRateLimiter")) { + configuration.retransmission_rate_limiter = + retransmission_rate_limiter_.get(); + } configuration.extmap_allow_mixed = extmap_allow_mixed; configuration.rtcp_report_interval_ms = rtcp_report_interval_ms; configuration.rtcp_packet_type_counter_observer = this; diff --git a/audio/channel_send_frame_transformer_delegate.cc b/audio/channel_send_frame_transformer_delegate.cc index 9b88d4d949..0f85216e92 100644 --- a/audio/channel_send_frame_transformer_delegate.cc +++ b/audio/channel_send_frame_transformer_delegate.cc @@ -48,13 +48,14 @@ AudioFrameType InterfaceFrameTypeToInternalFrameType( class TransformableOutgoingAudioFrame : public TransformableAudioFrameInterface { public: - TransformableOutgoingAudioFrame(AudioFrameType frame_type, - uint8_t payload_type, - uint32_t rtp_timestamp_with_offset, - const uint8_t* payload_data, - size_t payload_size, - int64_t absolute_capture_timestamp_ms, - uint32_t ssrc) + TransformableOutgoingAudioFrame( + AudioFrameType frame_type, + uint8_t payload_type, + uint32_t rtp_timestamp_with_offset, + const uint8_t* payload_data, + size_t payload_size, + absl::optional absolute_capture_timestamp_ms, + uint32_t ssrc) : frame_type_(frame_type), payload_type_(payload_type), rtp_timestamp_with_offset_(rtp_timestamp_with_offset), @@ -97,7 +98,7 @@ class TransformableOutgoingAudioFrame uint8_t payload_type_; uint32_t rtp_timestamp_with_offset_; rtc::Buffer payload_; - int64_t absolute_capture_timestamp_ms_; + absl::optional absolute_capture_timestamp_ms_; uint32_t ssrc_; }; } // namespace @@ -168,12 +169,11 @@ void ChannelSendFrameTransformerDelegate::SendFrame( std::unique_ptr CloneSenderAudioFrame( TransformableAudioFrameInterface* original) { - // TODO(crbug.com/webrtc/14949): Ensure the correct timestamps are passed. return std::make_unique( InterfaceFrameTypeToInternalFrameType(original->Type()), original->GetPayloadType(), original->GetTimestamp(), original->GetData().data(), original->GetData().size(), - original->GetTimestamp(), original->GetSsrc()); + original->AbsoluteCaptureTimestamp(), original->GetSsrc()); } } // namespace webrtc diff --git a/audio/voip/test/audio_channel_unittest.cc b/audio/voip/test/audio_channel_unittest.cc index 7097e7f6c9..0c8312b738 100644 --- a/audio/voip/test/audio_channel_unittest.cc +++ b/audio/voip/test/audio_channel_unittest.cc @@ -232,7 +232,7 @@ TEST_F(AudioChannelTest, TestChannelStatistics) { EXPECT_CALL(transport_, SendRtp).WillRepeatedly(Invoke(loop_rtp)); EXPECT_CALL(transport_, SendRtcp).WillRepeatedly(Invoke(loop_rtcp)); - // Simulate microphone giving audio frame (10 ms). This will trigger tranport + // Simulate microphone giving audio frame (10 ms). This will trigger transport // to send RTP as handled in loop_rtp above. auto audio_sender = audio_channel_->GetAudioSender(); audio_sender->SendAudioData(GetAudioFrame(0)); @@ -245,7 +245,7 @@ TEST_F(AudioChannelTest, TestChannelStatistics) { audio_mixer_->Mix(/*number_of_channels=*/1, &audio_frame); // Force sending RTCP SR report in order to have remote_rtcp field available - // in channel statistics. This will trigger tranport to send RTCP as handled + // in channel statistics. This will trigger transport to send RTCP as handled // in loop_rtcp above. audio_channel_->SendRTCPReportForTesting(kRtcpSr); diff --git a/audio/voip/test/audio_egress_unittest.cc b/audio/voip/test/audio_egress_unittest.cc index 8501b2d3d9..83df26eef1 100644 --- a/audio/voip/test/audio_egress_unittest.cc +++ b/audio/voip/test/audio_egress_unittest.cc @@ -218,7 +218,7 @@ TEST_F(AudioEgressTest, SkipAudioEncodingAfterStopSend) { // It should be safe to exit the test case while encoder_queue_ has // outstanding data to process. We are making sure that this doesn't - // result in crahses or sanitizer errors due to remaining data. + // result in crashes or sanitizer errors due to remaining data. for (size_t i = 0; i < kExpected * 2; i++) { egress_->SendAudioData(GetAudioFrame(i)); time_controller_.AdvanceTime(TimeDelta::Millis(10)); diff --git a/build_overrides/OWNERS b/build_overrides/OWNERS index 48e6927746..d4a4d8f1e7 100644 --- a/build_overrides/OWNERS +++ b/build_overrides/OWNERS @@ -1 +1,3 @@ +jansson@webrtc.org +jleconte@webrtc.org mbonadei@webrtc.org diff --git a/call/BUILD.gn b/call/BUILD.gn index 39cbc0a9c1..4cc42fd99f 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -345,7 +345,6 @@ rtc_library("call") { ] absl_deps = [ "//third_party/abseil-cpp/absl/functional:bind_front", - "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -544,7 +543,6 @@ if (rtc_include_tests) { absl_deps = [ "//third_party/abseil-cpp/absl/container:inlined_vector", "//third_party/abseil-cpp/absl/functional:any_invocable", - "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", "//third_party/abseil-cpp/absl/types:variant", @@ -606,6 +604,7 @@ if (rtc_include_tests) { "../test:frame_generator_capturer", "../test:null_transport", "../test:test_common", + "../test:test_flags", "../test:test_support", "../test:video_test_common", "../test:video_test_constants", diff --git a/call/call.cc b/call/call.cc index 49c2cb20cf..854c581cef 100644 --- a/call/call.cc +++ b/call/call.cc @@ -184,7 +184,7 @@ class Call final : public webrtc::Call, public BitrateAllocator::LimitObserver { public: Call(Clock* clock, - const Call::Config& config, + const CallConfig& config, std::unique_ptr transport_send, TaskQueueFactory* task_queue_factory); ~Call() override; @@ -358,7 +358,7 @@ class Call final : public webrtc::Call, const int num_cpu_cores_; const std::unique_ptr call_stats_; const std::unique_ptr bitrate_allocator_; - const Call::Config config_ RTC_GUARDED_BY(worker_thread_); + const CallConfig config_ RTC_GUARDED_BY(worker_thread_); // Maps to config_.trials, can be used from any thread via `trials()`. const FieldTrialsView& trials_; @@ -391,11 +391,6 @@ class Call final : public webrtc::Call, RTC_NO_UNIQUE_ADDRESS SequenceChecker receive_11993_checker_; - // TODO(bugs.webrtc.org/11993): Move receive_rtp_config_ over to the - // network thread. - std::map receive_rtp_config_ - RTC_GUARDED_BY(&receive_11993_checker_); - // Audio and Video send streams are owned by the client that creates them. // TODO(bugs.webrtc.org/11993): `audio_send_ssrcs_` and `video_send_ssrcs_` // should be accessed on the network thread. @@ -481,20 +476,22 @@ std::string Call::Stats::ToString(int64_t time_ms) const { return ss.str(); } -Call* Call::Create(const Call::Config& config) { +std::unique_ptr Call::Create(const CallConfig& config) { Clock* clock = Clock::GetRealTimeClock(); return Create(config, clock, RtpTransportControllerSendFactory().Create( config.ExtractTransportConfig(), clock)); } -Call* Call::Create(const Call::Config& config, - Clock* clock, - std::unique_ptr - transportControllerSend) { +std::unique_ptr Call::Create( + const CallConfig& config, + Clock* clock, + std::unique_ptr + transportControllerSend) { RTC_DCHECK(config.task_queue_factory); - return new internal::Call(clock, config, std::move(transportControllerSend), - config.task_queue_factory); + return std::make_unique(clock, config, + std::move(transportControllerSend), + config.task_queue_factory); } // This method here to avoid subclasses has to implement this method. @@ -661,7 +658,7 @@ void Call::SendStats::SetMinAllocatableRate(BitrateAllocationLimits limits) { } Call::Call(Clock* clock, - const Call::Config& config, + const CallConfig& config, std::unique_ptr transport_send, TaskQueueFactory* task_queue_factory) : clock_(clock), @@ -847,11 +844,6 @@ webrtc::AudioReceiveStreamInterface* Call::CreateAudioReceiveStream( // to live on the network thread. receive_stream->RegisterWithTransport(&audio_receiver_controller_); - // TODO(bugs.webrtc.org/11993): Update the below on the network thread. - // We could possibly set up the audio_receiver_controller_ association up - // as part of the async setup. - RegisterReceiveStream(config.rtp.remote_ssrc, receive_stream); - ConfigureSync(config.sync_group); auto it = audio_send_ssrcs_.find(config.rtp.local_ssrc); @@ -886,8 +878,6 @@ void Call::DestroyAudioReceiveStream( // for this sync_group. ConfigureSync(audio_receive_stream->sync_group()); - UnregisterReceiveStream(ssrc); - UpdateAggregateNetworkState(); // TODO(bugs.webrtc.org/11993): Consider if deleting `audio_receive_stream` // on the network thread would be better or if we'd need to tear down the @@ -1024,15 +1014,6 @@ webrtc::VideoReceiveStreamInterface* Call::CreateVideoReceiveStream( // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network // thread. receive_stream->RegisterWithTransport(&video_receiver_controller_); - - if (receive_stream->rtx_ssrc()) { - // We record identical config for the rtx stream as for the main - // stream. Since the transport_send_cc negotiation is per payload - // type, we may get an incorrect value for the rtx stream, but - // that is unlikely to matter in practice. - RegisterReceiveStream(receive_stream->rtx_ssrc(), receive_stream); - } - RegisterReceiveStream(receive_stream->remote_ssrc(), receive_stream); video_receive_streams_.insert(receive_stream); ConfigureSync(receive_stream->sync_group()); @@ -1051,14 +1032,6 @@ void Call::DestroyVideoReceiveStream( static_cast(receive_stream); // TODO(bugs.webrtc.org/11993): Unregister on the network thread. receive_stream_impl->UnregisterFromTransport(); - - // Remove all ssrcs pointing to a receive stream. As RTX retransmits on a - // separate SSRC there can be either one or two. - UnregisterReceiveStream(receive_stream_impl->remote_ssrc()); - - if (receive_stream_impl->rtx_ssrc()) { - UnregisterReceiveStream(receive_stream_impl->rtx_ssrc()); - } video_receive_streams_.erase(receive_stream_impl); ConfigureSync(receive_stream_impl->sync_group()); @@ -1086,8 +1059,6 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network // thread. receive_stream->RegisterWithTransport(&video_receiver_controller_); - RegisterReceiveStream(receive_stream->remote_ssrc(), receive_stream); - // TODO(brandtr): Store config in RtcEventLog here. return receive_stream; @@ -1103,8 +1074,6 @@ void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { receive_stream_impl->UnregisterFromTransport(); auto ssrc = receive_stream_impl->remote_ssrc(); - UnregisterReceiveStream(ssrc); - // Remove all SSRCs pointing to the FlexfecReceiveStreamImpl to be // destroyed. receive_side_cc_.RemoveStream(ssrc); @@ -1473,26 +1442,6 @@ void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet, receive_side_cc_.OnReceivedPacket(packet, media_type); } -bool Call::RegisterReceiveStream(uint32_t ssrc, - ReceiveStreamInterface* stream) { - RTC_DCHECK_RUN_ON(&receive_11993_checker_); - RTC_DCHECK(stream); - auto inserted = receive_rtp_config_.emplace(ssrc, stream); - if (!inserted.second) { - RTC_DLOG(LS_WARNING) << "ssrc already registered: " << ssrc; - } - return inserted.second; -} - -bool Call::UnregisterReceiveStream(uint32_t ssrc) { - RTC_DCHECK_RUN_ON(&receive_11993_checker_); - size_t erased = receive_rtp_config_.erase(ssrc); - if (!erased) { - RTC_DLOG(LS_WARNING) << "ssrc wasn't registered: " << ssrc; - } - return erased != 0u; -} - } // namespace internal } // namespace webrtc diff --git a/call/call.h b/call/call.h index f2563f6ded..56a375222c 100644 --- a/call/call.h +++ b/call/call.h @@ -46,8 +46,6 @@ namespace webrtc { class Call { public: - using Config = CallConfig; - struct Stats { std::string ToString(int64_t time_ms) const; @@ -58,11 +56,12 @@ class Call { int64_t rtt_ms = -1; }; - static Call* Create(const Call::Config& config); - static Call* Create(const Call::Config& config, - Clock* clock, - std::unique_ptr - transportControllerSend); + static std::unique_ptr Create(const CallConfig& config); + static std::unique_ptr Create( + const CallConfig& config, + Clock* clock, + std::unique_ptr + transportControllerSend); virtual AudioSendStream* CreateAudioSendStream( const AudioSendStream::Config& config) = 0; diff --git a/call/call_factory.cc b/call/call_factory.cc index 380e80ce12..043b11da37 100644 --- a/call/call_factory.cc +++ b/call/call_factory.cc @@ -17,7 +17,6 @@ #include #include -#include "absl/memory/memory.h" #include "absl/types/optional.h" #include "api/test/simulated_network.h" #include "api/units/time_delta.h" @@ -83,7 +82,7 @@ CallFactory::CallFactory() { call_thread_.Detach(); } -Call* CallFactory::CreateCall(const Call::Config& config) { +std::unique_ptr CallFactory::CreateCall(const CallConfig& config) { RTC_DCHECK_RUN_ON(&call_thread_); RTC_DCHECK(config.trials); @@ -95,22 +94,22 @@ Call* CallFactory::CreateCall(const Call::Config& config) { RtpTransportConfig transportConfig = config.ExtractTransportConfig(); - Call* call = + std::unique_ptr call = Call::Create(config, Clock::GetRealTimeClock(), config.rtp_transport_controller_send_factory->Create( transportConfig, Clock::GetRealTimeClock())); if (!send_degradation_configs.empty() || !receive_degradation_configs.empty()) { - return new DegradedCall(absl::WrapUnique(call), send_degradation_configs, - receive_degradation_configs); + return std::make_unique( + std::move(call), send_degradation_configs, receive_degradation_configs); } return call; } std::unique_ptr CreateCallFactory() { - return std::unique_ptr(new CallFactory()); + return std::make_unique(); } } // namespace webrtc diff --git a/call/call_factory.h b/call/call_factory.h index 9feed7bbb6..f75b1bd71b 100644 --- a/call/call_factory.h +++ b/call/call_factory.h @@ -11,6 +11,8 @@ #ifndef CALL_CALL_FACTORY_H_ #define CALL_CALL_FACTORY_H_ +#include + #include "api/call/call_factory_interface.h" #include "api/sequence_checker.h" #include "call/call.h" @@ -22,11 +24,10 @@ namespace webrtc { class CallFactory : public CallFactoryInterface { public: CallFactory(); + ~CallFactory() override = default; private: - ~CallFactory() override {} - - Call* CreateCall(const CallConfig& config) override; + std::unique_ptr CreateCall(const CallConfig& config) override; RTC_NO_UNIQUE_ADDRESS SequenceChecker call_thread_; }; diff --git a/call/call_perf_tests.cc b/call/call_perf_tests.cc index f1ea970db8..0ba6d05b19 100644 --- a/call/call_perf_tests.cc +++ b/call/call_perf_tests.cc @@ -13,6 +13,7 @@ #include #include +#include "absl/flags/flag.h" #include "absl/strings/string_view.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" #include "api/numerics/samples_stats_counter.h" @@ -52,6 +53,7 @@ #include "test/gtest.h" #include "test/null_transport.h" #include "test/rtp_rtcp_observer.h" +#include "test/test_flags.h" #include "test/testsupport/file_utils.h" #include "test/video_encoder_proxy_factory.h" #include "test/video_test_constants.h" @@ -221,12 +223,12 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, send_audio_state_config.audio_processing = AudioProcessingBuilder().Create(); send_audio_state_config.audio_device_module = fake_audio_device; - Call::Config sender_config(send_event_log_.get()); + CallConfig sender_config(send_event_log_.get()); auto audio_state = AudioState::Create(send_audio_state_config); fake_audio_device->RegisterAudioCallback(audio_state->audio_transport()); sender_config.audio_state = audio_state; - Call::Config receiver_config(recv_event_log_.get()); + CallConfig receiver_config(recv_event_log_.get()); receiver_config.audio_state = audio_state; CreateCalls(sender_config, receiver_config); @@ -361,7 +363,7 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, observer->PrintResults(); // In quick test synchronization may not be achieved in time. - if (!field_trial::IsEnabled("WebRTC-QuickPerfTest")) { + if (!absl::GetFlag(FLAGS_webrtc_quick_perf_test)) { // TODO(bugs.webrtc.org/10417): Reenable this for iOS #if !defined(WEBRTC_IOS) EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs")); @@ -975,8 +977,8 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, void PerformTest() override { // Quick test mode, just to exercise all the code paths without actually // caring about performance measurements. - const bool quick_perf_test = - field_trial::IsEnabled("WebRTC-QuickPerfTest"); + const bool quick_perf_test = absl::GetFlag(FLAGS_webrtc_quick_perf_test); + int last_passed_test_bitrate = -1; for (int test_bitrate = test_bitrate_from_; test_bitrate_from_ < test_bitrate_to_ @@ -1125,8 +1127,7 @@ void CallPerfTest::TestEncodeFramerate(VideoEncoderFactory* encoder_factory, } void VerifyStats() const { - const bool quick_perf_test = - field_trial::IsEnabled("WebRTC-QuickPerfTest"); + const bool quick_perf_test = absl::GetFlag(FLAGS_webrtc_quick_perf_test); double input_fps = 0.0; for (const auto& configured_framerate : configured_framerates_) { input_fps = std::max(configured_framerate.second, input_fps); diff --git a/call/call_unittest.cc b/call/call_unittest.cc index 01476eed19..886a15aaf0 100644 --- a/call/call_unittest.cc +++ b/call/call_unittest.cc @@ -15,7 +15,6 @@ #include #include -#include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/media_types.h" @@ -40,6 +39,7 @@ #include "test/mock_transport.h" #include "test/run_loop.h" +namespace webrtc { namespace { using ::testing::_; @@ -47,41 +47,38 @@ using ::testing::Contains; using ::testing::MockFunction; using ::testing::NiceMock; using ::testing::StrictMock; +using ::webrtc::test::MockAudioDeviceModule; +using ::webrtc::test::MockAudioMixer; +using ::webrtc::test::MockAudioProcessing; +using ::webrtc::test::RunLoop; struct CallHelper { explicit CallHelper(bool use_null_audio_processing) { - task_queue_factory_ = webrtc::CreateDefaultTaskQueueFactory(); - webrtc::AudioState::Config audio_state_config; - audio_state_config.audio_mixer = - rtc::make_ref_counted(); + task_queue_factory_ = CreateDefaultTaskQueueFactory(); + AudioState::Config audio_state_config; + audio_state_config.audio_mixer = rtc::make_ref_counted(); audio_state_config.audio_processing = use_null_audio_processing ? nullptr - : rtc::make_ref_counted< - NiceMock>(); + : rtc::make_ref_counted>(); audio_state_config.audio_device_module = - rtc::make_ref_counted(); - webrtc::Call::Config config(&event_log_); - config.audio_state = webrtc::AudioState::Create(audio_state_config); + rtc::make_ref_counted(); + CallConfig config(&event_log_); + config.audio_state = AudioState::Create(audio_state_config); config.task_queue_factory = task_queue_factory_.get(); config.trials = &field_trials_; - call_.reset(webrtc::Call::Create(config)); + call_ = Call::Create(config); } - webrtc::Call* operator->() { return call_.get(); } + Call* operator->() { return call_.get(); } private: - webrtc::test::RunLoop loop_; - webrtc::RtcEventLogNull event_log_; - webrtc::FieldTrialBasedConfig field_trials_; - std::unique_ptr task_queue_factory_; - std::unique_ptr call_; + RunLoop loop_; + RtcEventLogNull event_log_; + FieldTrialBasedConfig field_trials_; + std::unique_ptr task_queue_factory_; + std::unique_ptr call_; }; -} // namespace - -namespace webrtc { - -namespace { rtc::scoped_refptr FindResourceWhoseNameContains( const std::vector>& resources, diff --git a/call/rampup_tests.cc b/call/rampup_tests.cc index 8ddce83a2e..232fe0b3fe 100644 --- a/call/rampup_tests.cc +++ b/call/rampup_tests.cc @@ -329,7 +329,7 @@ void RampUpTester::TriggerTestDone() { RTC_DCHECK_GE(test_start_ms_, 0); // Stop polling stats. - // Corner case for field_trials=WebRTC-QuickPerfTest/Enabled/ + // Corner case for webrtc_quick_perf_test SendTask(task_queue_, [this] { pending_task_.Stop(); }); // TODO(holmer): Add audio send stats here too when those APIs are available. diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc index f4b09ce913..4b63ebefb3 100644 --- a/call/rtp_payload_params.cc +++ b/call/rtp_payload_params.cc @@ -100,6 +100,7 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info, case kVideoCodecGeneric: rtp->codec = kVideoCodecGeneric; return; + // TODO(bugs.webrtc.org/13485): Implement H265 codec specific info default: return; } @@ -341,6 +342,9 @@ void RtpPayloadParams::SetGeneric(const CodecSpecificInfo* codec_specific_info, return; case VideoCodecType::kVideoCodecMultiplex: return; + case VideoCodecType::kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement H265 to generic descriptor. + return; } RTC_DCHECK_NOTREACHED() << "Unsupported codec."; } @@ -402,6 +406,7 @@ absl::optional RtpPayloadParams::GenericStructure( } case VideoCodecType::kVideoCodecAV1: case VideoCodecType::kVideoCodecH264: + case VideoCodecType::kVideoCodecH265: case VideoCodecType::kVideoCodecMultiplex: return absl::nullopt; } diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc index dc1d37168e..556a4dd89a 100644 --- a/call/rtp_transport_controller_send.cc +++ b/call/rtp_transport_controller_send.cc @@ -343,12 +343,13 @@ void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) { is_congested_ = false; pacer_.SetCongested(false); + if (!controller_) { + MaybeCreateControllers(); + } if (controller_) { control_handler_->SetNetworkAvailability(network_available); PostUpdates(controller_->OnNetworkAvailability(msg)); UpdateControlState(); - } else { - MaybeCreateControllers(); } for (auto& rtp_sender : video_rtp_senders_) { rtp_sender->OnNetworkAvailability(network_available); diff --git a/call/rtp_transport_controller_send_interface.h b/call/rtp_transport_controller_send_interface.h index 349fe68039..7edc135037 100644 --- a/call/rtp_transport_controller_send_interface.h +++ b/call/rtp_transport_controller_send_interface.h @@ -57,7 +57,6 @@ struct RtpSenderObservers { BitrateStatisticsObserver* bitrate_observer; FrameCountObserver* frame_count_observer; RtcpPacketTypeCounterObserver* rtcp_type_observer; - SendSideDelayObserver* send_delay_observer; SendPacketObserver* send_packet_observer; }; diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index bf3e995b98..b6be57baff 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc @@ -224,10 +224,11 @@ std::vector CreateRtpStreamSenders( observers.report_block_data_observer; configuration.paced_sender = transport->packet_sender(); configuration.send_bitrate_observer = observers.bitrate_observer; - configuration.send_side_delay_observer = observers.send_delay_observer; configuration.send_packet_observer = observers.send_packet_observer; configuration.event_log = event_log; - configuration.retransmission_rate_limiter = retransmission_rate_limiter; + if (trials.IsDisabled("WebRTC-DisableRtxRateLimiter")) { + configuration.retransmission_rate_limiter = retransmission_rate_limiter; + } configuration.rtp_stats_callback = observers.rtp_stats; configuration.frame_encryptor = frame_encryptor; configuration.require_frame_encryption = @@ -509,7 +510,6 @@ void RtpVideoSender::SetActiveModulesLocked( const bool was_active = rtp_module.Sending(); const bool should_be_active = active_modules[i]; - // Sends a kRtcpByeCode when going from true to false. rtp_module.SetSendingStatus(active_modules[i]); if (was_active && !should_be_active) { @@ -577,7 +577,7 @@ EncodedImageCallback::Result RtpVideoSender::OnEncodedImage( RTC_DCHECK_LT(simulcast_index, rtp_streams_.size()); uint32_t rtp_timestamp = - encoded_image.Timestamp() + + encoded_image.RtpTimestamp() + rtp_streams_[simulcast_index].rtp_rtcp->StartTimestamp(); // RTCPSender has it's own copy of the timestamp offset, added in @@ -585,7 +585,7 @@ EncodedImageCallback::Result RtpVideoSender::OnEncodedImage( // TODO(nisse): Delete RTCPSender:timestamp_offset_, and see if we can confine // knowledge of the offset to a single place. if (!rtp_streams_[simulcast_index].rtp_rtcp->OnSendingRtpFrame( - encoded_image.Timestamp(), encoded_image.capture_time_ms_, + encoded_image.RtpTimestamp(), encoded_image.capture_time_ms_, rtp_config_.payload_type, encoded_image._frameType == VideoFrameType::kVideoFrameKey)) { // The payload router could be active but this module isn't sending. diff --git a/call/rtp_video_sender_unittest.cc b/call/rtp_video_sender_unittest.cc index 77d87dfc97..cd2f1efbcf 100644 --- a/call/rtp_video_sender_unittest.cc +++ b/call/rtp_video_sender_unittest.cc @@ -32,7 +32,6 @@ #include "test/scenario/scenario.h" #include "test/scoped_key_value_config.h" #include "test/time_controller/simulated_time_controller.h" -#include "video/send_delay_stats.h" #include "video/send_statistics_proxy.h" namespace webrtc { @@ -62,17 +61,14 @@ class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver { }; RtpSenderObservers CreateObservers( - RtcpRttStats* rtcp_rtt_stats, RtcpIntraFrameObserver* intra_frame_callback, ReportBlockDataObserver* report_block_data_observer, StreamDataCountersCallback* rtp_stats, BitrateStatisticsObserver* bitrate_observer, FrameCountObserver* frame_count_observer, - RtcpPacketTypeCounterObserver* rtcp_type_observer, - SendSideDelayObserver* send_delay_observer, - SendPacketObserver* send_packet_observer) { + RtcpPacketTypeCounterObserver* rtcp_type_observer) { RtpSenderObservers observers; - observers.rtcp_rtt_stats = rtcp_rtt_stats; + observers.rtcp_rtt_stats = nullptr; observers.intra_frame_callback = intra_frame_callback; observers.rtcp_loss_notification_observer = nullptr; observers.report_block_data_observer = report_block_data_observer; @@ -80,8 +76,7 @@ RtpSenderObservers CreateObservers( observers.bitrate_observer = bitrate_observer; observers.frame_count_observer = frame_count_observer; observers.rtcp_type_observer = rtcp_type_observer; - observers.send_delay_observer = send_delay_observer; - observers.send_packet_observer = send_packet_observer; + observers.send_packet_observer = nullptr; return observers; } @@ -127,7 +122,6 @@ class RtpVideoSenderTestFixture { ssrcs, rtx_ssrcs, payload_type)), - send_delay_stats_(time_controller_.GetClock()), bitrate_config_(GetBitrateConfig()), transport_controller_( time_controller_.GetClock(), @@ -148,9 +142,8 @@ class RtpVideoSenderTestFixture { router_ = std::make_unique( time_controller_.GetClock(), suspended_ssrcs, suspended_payload_states, config_.rtp, config_.rtcp_report_interval_ms, &transport_, - CreateObservers(nullptr, &encoder_feedback_, &stats_proxy_, - &stats_proxy_, &stats_proxy_, frame_count_observer, - &stats_proxy_, &stats_proxy_, &send_delay_stats_), + CreateObservers(&encoder_feedback_, &stats_proxy_, &stats_proxy_, + &stats_proxy_, frame_count_observer, &stats_proxy_), &transport_controller_, &event_log_, &retransmission_rate_limiter_, std::make_unique(time_controller_.GetClock()), nullptr, CryptoOptions{}, frame_transformer, @@ -206,7 +199,6 @@ class RtpVideoSenderTestFixture { GlobalSimulatedTimeController time_controller_; RtcEventLogNull event_log_; VideoSendStream::Config config_; - SendDelayStats send_delay_stats_; BitrateConstraints bitrate_config_; RtpTransportControllerSend transport_controller_; SendStatisticsProxy stats_proxy_; @@ -226,7 +218,7 @@ BitrateAllocationUpdate CreateBitrateAllocationUpdate(int target_bitrate_bps) { TEST(RtpVideoSenderTest, SendOnOneModule) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -251,7 +243,7 @@ TEST(RtpVideoSenderTest, SendOnOneModule) { TEST(RtpVideoSenderTest, SendSimulcastSetActive) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image_1; - encoded_image_1.SetTimestamp(1); + encoded_image_1.SetRtpTimestamp(1); encoded_image_1.capture_time_ms_ = 2; encoded_image_1._frameType = VideoFrameType::kVideoFrameKey; encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -286,7 +278,7 @@ TEST(RtpVideoSenderTest, SendSimulcastSetActive) { TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image_1; - encoded_image_1.SetTimestamp(1); + encoded_image_1.SetRtpTimestamp(1); encoded_image_1.capture_time_ms_ = 2; encoded_image_1._frameType = VideoFrameType::kVideoFrameKey; encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -322,7 +314,7 @@ TEST(RtpVideoSenderTest, DiscardsHigherSimulcastFramesAfterLayerDisabledInVideoLayersAllocation) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image_1; - encoded_image_1.SetTimestamp(1); + encoded_image_1.SetRtpTimestamp(1); encoded_image_1.capture_time_ms_ = 2; encoded_image_1._frameType = VideoFrameType::kVideoFrameKey; encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -407,7 +399,7 @@ TEST(RtpVideoSenderTest, FrameCountCallbacks) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -453,7 +445,7 @@ TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) { constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -474,7 +466,7 @@ TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) { }); EXPECT_EQ(EncodedImageCallback::Result::OK, test.router()->OnEncodedImage(encoded_image, nullptr).error); - encoded_image.SetTimestamp(2); + encoded_image.SetRtpTimestamp(2); encoded_image.capture_time_ms_ = 3; EXPECT_EQ(EncodedImageCallback::Result::OK, test.router()->OnEncodedImage(encoded_image, nullptr).error); @@ -618,7 +610,7 @@ TEST(RtpVideoSenderTest, EarlyRetransmits) { const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData( @@ -725,7 +717,7 @@ TEST(RtpVideoSenderTest, SupportsDependencyDescriptor) { const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image.SetEncodedData( EncodedImageBuffer::Create(kPayload, sizeof(kPayload))); @@ -831,7 +823,7 @@ TEST(RtpVideoSenderTest, SupportsDependencyDescriptorForVp9) { const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData( @@ -887,7 +879,7 @@ TEST(RtpVideoSenderTest, const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image._encodedWidth = 320; @@ -909,7 +901,7 @@ TEST(RtpVideoSenderTest, // Send in 2nd picture. encoded_image._frameType = VideoFrameType::kVideoFrameDelta; - encoded_image.SetTimestamp(3000); + encoded_image.SetRtpTimestamp(3000); codec_specific.codecSpecific.VP9.inter_pic_predicted = true; codec_specific.codecSpecific.VP9.num_ref_pics = 1; codec_specific.codecSpecific.VP9.p_diff[0] = 1; @@ -942,7 +934,7 @@ TEST(RtpVideoSenderTest, GenerateDependecyDescriptorForGenericCodecs) { const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image._encodedWidth = 320; @@ -960,7 +952,7 @@ TEST(RtpVideoSenderTest, GenerateDependecyDescriptorForGenericCodecs) { // Send in 2nd picture. encoded_image._frameType = VideoFrameType::kVideoFrameDelta; - encoded_image.SetTimestamp(3000); + encoded_image.SetRtpTimestamp(3000); EXPECT_EQ(test.router()->OnEncodedImage(encoded_image, &codec_specific).error, EncodedImageCallback::Result::OK); @@ -988,7 +980,7 @@ TEST(RtpVideoSenderTest, SupportsStoppingUsingDependencyDescriptor) { const uint8_t kPayload[1] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image.SetEncodedData( EncodedImageBuffer::Create(kPayload, sizeof(kPayload))); @@ -1107,7 +1099,7 @@ TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) { const size_t kImageSizeBytes = 10000; constexpr uint8_t kPayload[kImageSizeBytes] = {'a'}; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData( @@ -1146,7 +1138,7 @@ TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) { EXPECT_TRUE(sent_packets.empty()); // Send a new frame. - encoded_image.SetTimestamp(3); + encoded_image.SetRtpTimestamp(3); encoded_image.capture_time_ms_ = 4; EXPECT_EQ(test.router() ->OnEncodedImage(encoded_image, /*codec_specific=*/nullptr) @@ -1169,7 +1161,7 @@ TEST(RtpVideoSenderTest, RetransmitsBaseLayerOnly) { test.router()->SetRetransmissionMode(kRetransmitBaseLayer); constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image; - encoded_image.SetTimestamp(1); + encoded_image.SetRtpTimestamp(1); encoded_image.capture_time_ms_ = 2; encoded_image._frameType = VideoFrameType::kVideoFrameKey; encoded_image.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); @@ -1195,7 +1187,7 @@ TEST(RtpVideoSenderTest, RetransmitsBaseLayerOnly) { EXPECT_EQ(EncodedImageCallback::Result::OK, test.router()->OnEncodedImage( encoded_image, &key_codec_info).error); - encoded_image.SetTimestamp(2); + encoded_image.SetRtpTimestamp(2); encoded_image.capture_time_ms_ = 3; encoded_image._frameType = VideoFrameType::kVideoFrameDelta; CodecSpecificInfo delta_codec_info; diff --git a/call/version.cc b/call/version.cc index 0d10edf2cc..44c8c77156 100644 --- a/call/version.cc +++ b/call/version.cc @@ -13,7 +13,7 @@ namespace webrtc { // The timestamp is always in UTC. -const char* const kSourceTimestamp = "WebRTC source stamp 2023-09-05T04:12:20"; +const char* const kSourceTimestamp = "WebRTC source stamp 2023-10-30T04:03:42"; void LoadWebRTCVersionInRegister() { // Using volatile to instruct the compiler to not optimize `p` away even diff --git a/call/video_receive_stream.cc b/call/video_receive_stream.cc index 3e2a51322f..8d88ce23c6 100644 --- a/call/video_receive_stream.cc +++ b/call/video_receive_stream.cc @@ -84,7 +84,7 @@ std::string VideoReceiveStreamInterface::Stats::ToString( << jitter_buffer_target_delay.seconds() << ", "; ss << "jitterBufferEmittedCount: " << jitter_buffer_emitted_count << ", "; ss << "jitterBufferMinimumDelay: " - << jitter_buffer_minimum_delay.seconds(); + << jitter_buffer_minimum_delay.seconds() << ", "; ss << "totalDecodeTime: " << total_decode_time.seconds() << ", "; ss << "totalProcessingDelay: " << total_processing_delay.seconds() << ", "; diff --git a/common_audio/signal_processing/cross_correlation_neon.c b/common_audio/signal_processing/cross_correlation_neon.c index f2afbdf9f5..d3ecf138e3 100644 --- a/common_audio/signal_processing/cross_correlation_neon.c +++ b/common_audio/signal_processing/cross_correlation_neon.c @@ -72,9 +72,9 @@ void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation, size_t dim_cross_correlation, int right_shifts, int step_seq2) { - size_t i = 0; + int i = 0; - for (i = 0; i < dim_cross_correlation; i++) { + for (i = 0; i < (int)dim_cross_correlation; i++) { const int16_t* seq1_ptr = seq1; const int16_t* seq2_ptr = seq2 + (step_seq2 * i); diff --git a/common_audio/signal_processing/downsample_fast_neon.c b/common_audio/signal_processing/downsample_fast_neon.c index 36fc0c8aee..f1b754b798 100644 --- a/common_audio/signal_processing/downsample_fast_neon.c +++ b/common_audio/signal_processing/downsample_fast_neon.c @@ -8,9 +8,11 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include "common_audio/signal_processing/include/signal_processing_library.h" -#include +#include "rtc_base/checks.h" // NEON intrinsics version of WebRtcSpl_DownsampleFast() // for ARM 32-bit/64-bit platforms. @@ -22,19 +24,24 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, size_t coefficients_length, int factor, size_t delay) { - size_t i = 0; - size_t j = 0; + // Using signed indexes to be able to compute negative i-j that + // is used to index data_in. + int i = 0; + int j = 0; int32_t out_s32 = 0; - size_t endpos = delay + factor * (data_out_length - 1) + 1; + int endpos = delay + factor * (data_out_length - 1) + 1; size_t res = data_out_length & 0x7; - size_t endpos1 = endpos - factor * res; + int endpos1 = endpos - factor * res; // Return error if any of the running conditions doesn't meet. if (data_out_length == 0 || coefficients_length == 0 - || data_in_length < endpos) { + || (int)data_in_length < endpos) { return -1; } + RTC_DCHECK_GE(endpos, 0); + RTC_DCHECK_GE(endpos1, 0); + // First part, unroll the loop 8 times, with 3 subcases // (factor == 2, 4, others). switch (factor) { @@ -46,7 +53,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, #if defined(WEBRTC_ARCH_ARM64) // Unroll the loop 2 times. - for (j = 0; j < coefficients_length - 1; j += 2) { + for (j = 0; j < (int)coefficients_length - 1; j += 2) { int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]); int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]); @@ -68,7 +75,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0); } - for (; j < coefficients_length; j++) { + for (; j < (int)coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); @@ -87,7 +94,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, #else // On ARMv7, the loop unrolling 2 times results in performance // regression. - for (j = 0; j < coefficients_length; j++) { + for (j = 0; j < (int)coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); @@ -114,7 +121,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, int32x4_t out32x4_1 = vdupq_n_s32(2048); // Unroll the loop 4 times. - for (j = 0; j < coefficients_length - 3; j += 4) { + for (j = 0; j < (int)coefficients_length - 3; j += 4) { int16x4_t coeff16x4 = vld1_s16(&coefficients[j]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]); @@ -143,7 +150,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0); } - for (; j < coefficients_length; j++) { + for (; j < (int)coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]); @@ -174,7 +181,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, int32x4_t out32x4_0 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048); - for (j = 0; j < coefficients_length; j++) { + for (j = 0; j < (int)coefficients_length; j++) { int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]); in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1); @@ -204,7 +211,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, for (; i < endpos; i += factor) { out_s32 = 2048; // Round value, 0.5 in Q12. - for (j = 0; j < coefficients_length; j++) { + for (j = 0; j < (int)coefficients_length; j++) { out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32); } diff --git a/common_video/h265/h265_bitstream_parser.cc b/common_video/h265/h265_bitstream_parser.cc index ee77166705..1093add102 100644 --- a/common_video/h265/h265_bitstream_parser.cc +++ b/common_video/h265/h265_bitstream_parser.cc @@ -138,8 +138,7 @@ H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu( slice_reader.ConsumeBits(1); } // slice_type: ue(v) - uint32_t slice_type = 0; - slice_type = slice_reader.ReadExponentialGolomb(); + uint32_t slice_type = slice_reader.ReadExponentialGolomb(); IN_RANGE_OR_RETURN(slice_type, 0, 2); if (pps->output_flag_present_flag) { // pic_output_flag: u(1) @@ -274,7 +273,7 @@ H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu( } uint32_t num_pic_total_curr = 0; - uint32_t curr_sps_idx; + uint32_t curr_sps_idx = 0; if (short_term_ref_pic_set_sps_flag) { curr_sps_idx = short_term_ref_pic_set_idx; } else { diff --git a/common_video/h265/h265_common.h b/common_video/h265/h265_common.h index 1a76077b34..fcb97815ff 100644 --- a/common_video/h265/h265_common.h +++ b/common_video/h265/h265_common.h @@ -64,11 +64,11 @@ enum SliceType : uint8_t { kB = 0, kP = 1, kI = 2 }; struct NaluIndex { // Start index of NALU, including start sequence. - size_t start_offset; + size_t start_offset = 0; // Start index of NALU payload, typically type header. - size_t payload_start_offset; + size_t payload_start_offset = 0; // Length of NALU payload, in bytes, counting from payload_start_offset. - size_t payload_size; + size_t payload_size = 0; }; // Returns a vector of the NALU indices in the given buffer. diff --git a/common_video/h265/h265_sps_parser.cc b/common_video/h265/h265_sps_parser.cc index 96aee7c569..a2da4b9b7b 100644 --- a/common_video/h265/h265_sps_parser.cc +++ b/common_video/h265/h265_sps_parser.cc @@ -111,7 +111,7 @@ absl::optional H265SpsParser::ParseSps( } bool H265SpsParser::ParseScalingListData(BitstreamReader& reader) { - int32_t scaling_list_dc_coef_minus8[kMaxNumSizeIds][kMaxNumMatrixIds]; + int32_t scaling_list_dc_coef_minus8[kMaxNumSizeIds][kMaxNumMatrixIds] = {}; for (int size_id = 0; size_id < kMaxNumSizeIds; size_id++) { for (int matrix_id = 0; matrix_id < kMaxNumMatrixIds; matrix_id += (size_id == 3) ? 3 : 1) { @@ -182,8 +182,8 @@ H265SpsParser::ParseShortTermRefPicSet( short_term_ref_pic_set[ref_rps_idx].num_delta_pocs; IN_RANGE_OR_RETURN_NULL(num_delta_pocs, 0, kMaxShortTermRefPicSets); const ShortTermRefPicSet& ref_set = short_term_ref_pic_set[ref_rps_idx]; - bool used_by_curr_pic_flag[kMaxShortTermRefPicSets]; - bool use_delta_flag[kMaxShortTermRefPicSets]; + bool used_by_curr_pic_flag[kMaxShortTermRefPicSets] = {}; + bool use_delta_flag[kMaxShortTermRefPicSets] = {}; // 7.4.8 - use_delta_flag defaults to 1 if not present. std::fill_n(use_delta_flag, kMaxShortTermRefPicSets, true); @@ -266,7 +266,7 @@ H265SpsParser::ParseShortTermRefPicSet( for (uint32_t i = 0; i < st_ref_pic_set.num_negative_pics; i++) { // delta_poc_s0_minus1: ue(v) - int delta_poc_s0_minus1; + int delta_poc_s0_minus1 = 0; delta_poc_s0_minus1 = reader.ReadExponentialGolomb(); IN_RANGE_OR_RETURN_NULL(delta_poc_s0_minus1, 0, 0x7FFF); if (i == 0) { @@ -281,7 +281,7 @@ H265SpsParser::ParseShortTermRefPicSet( for (uint32_t i = 0; i < st_ref_pic_set.num_positive_pics; i++) { // delta_poc_s1_minus1: ue(v) - int delta_poc_s1_minus1; + int delta_poc_s1_minus1 = 0; delta_poc_s1_minus1 = reader.ReadExponentialGolomb(); IN_RANGE_OR_RETURN_NULL(delta_poc_s1_minus1, 0, 0x7FFF); if (i == 0) { @@ -319,10 +319,8 @@ H265SpsParser::ParseProfileTierLevel(bool profile_present, reader.ConsumeBits(1); pf_tier_level.general_profile_idc = reader.ReadBits(5); IN_RANGE_OR_RETURN_NULL(pf_tier_level.general_profile_idc, 0, 11); - uint16_t general_profile_compatibility_flag_high16; - uint16_t general_profile_compatibility_flag_low16; - general_profile_compatibility_flag_high16 = reader.ReadBits(16); - general_profile_compatibility_flag_low16 = reader.ReadBits(16); + uint16_t general_profile_compatibility_flag_high16 = reader.ReadBits(16); + uint16_t general_profile_compatibility_flag_low16 = reader.ReadBits(16); pf_tier_level.general_profile_compatibility_flags = (general_profile_compatibility_flag_high16 << 16) + general_profile_compatibility_flag_low16; @@ -344,8 +342,8 @@ H265SpsParser::ParseProfileTierLevel(bool profile_present, reader.ConsumeBits(1); } pf_tier_level.general_level_idc = reader.ReadBits(8); - bool sub_layer_profile_present_flag[8]; - bool sub_layer_level_present_flag[8]; + bool sub_layer_profile_present_flag[8] = {}; + bool sub_layer_level_present_flag[8] = {}; for (int i = 0; i < max_num_sub_layers_minus1; ++i) { sub_layer_profile_present_flag[i] = reader.ReadBits(1); sub_layer_level_present_flag[i] = reader.ReadBits(1); @@ -443,7 +441,7 @@ absl::optional H265SpsParser::ParseSpsInternal( // Equation A-2: Calculate max_dpb_size. uint32_t max_luma_ps = GetMaxLumaPs(profile_tier_level->general_level_idc); - uint32_t max_dpb_size; + uint32_t max_dpb_size = 0; uint32_t pic_size_in_samples_y = pic_height_in_luma_samples; pic_size_in_samples_y *= pic_width_in_luma_samples; size_t max_dpb_pic_buf = @@ -503,7 +501,7 @@ absl::optional H265SpsParser::ParseSpsInternal( uint32_t sps_sub_layer_ordering_info_present_flag = 0; // sps_sub_layer_ordering_info_present_flag: u(1) sps_sub_layer_ordering_info_present_flag = reader.Read(); - uint32_t sps_max_num_reorder_pics[kMaxSubLayers]; + uint32_t sps_max_num_reorder_pics[kMaxSubLayers] = {}; for (uint32_t i = (sps_sub_layer_ordering_info_present_flag != 0) ? 0 : sps_max_sub_layers_minus1; @@ -552,8 +550,8 @@ absl::optional H265SpsParser::ParseSpsInternal( // log2_min_luma_transform_block_size_minus2: ue(v) int log2_min_luma_transform_block_size_minus2 = reader.ReadExponentialGolomb(); - TRUE_OR_RETURN(log2_min_luma_transform_block_size_minus2 < - min_cb_log2_size_y - 2); + IN_RANGE_OR_RETURN_NULL(log2_min_luma_transform_block_size_minus2, 0, + min_cb_log2_size_y - 3); int min_tb_log2_size_y = log2_min_luma_transform_block_size_minus2 + 2; // log2_diff_max_min_luma_transform_block_size: ue(v) int log2_diff_max_min_luma_transform_block_size = diff --git a/common_video/h265/h265_sps_parser.h b/common_video/h265/h265_sps_parser.h index 2dece2b722..854c0f29eb 100644 --- a/common_video/h265/h265_sps_parser.h +++ b/common_video/h265/h265_sps_parser.h @@ -47,29 +47,29 @@ class H265SpsParser { struct ProfileTierLevel { ProfileTierLevel(); // Syntax elements. - int general_profile_idc; - int general_level_idc; // 30x the actual level. - uint32_t general_profile_compatibility_flags; - bool general_progressive_source_flag; - bool general_interlaced_source_flag; - bool general_non_packed_constraint_flag; - bool general_frame_only_constraint_flag; - bool general_one_picture_only_constraint_flag; + int general_profile_idc = 0; + int general_level_idc = 0; // 30x the actual level. + uint32_t general_profile_compatibility_flags = 0; + bool general_progressive_source_flag = false; + bool general_interlaced_source_flag = false; + bool general_non_packed_constraint_flag = false; + bool general_frame_only_constraint_flag = false; + bool general_one_picture_only_constraint_flag = false; }; struct ShortTermRefPicSet { ShortTermRefPicSet(); // Syntax elements. - uint32_t num_negative_pics; - uint32_t num_positive_pics; - uint32_t delta_poc_s0[kMaxShortTermRefPicSets]; - uint32_t used_by_curr_pic_s0[kMaxShortTermRefPicSets]; - uint32_t delta_poc_s1[kMaxShortTermRefPicSets]; - uint32_t used_by_curr_pic_s1[kMaxShortTermRefPicSets]; + uint32_t num_negative_pics = 0; + uint32_t num_positive_pics = 0; + uint32_t delta_poc_s0[kMaxShortTermRefPicSets] = {}; + uint32_t used_by_curr_pic_s0[kMaxShortTermRefPicSets] = {}; + uint32_t delta_poc_s1[kMaxShortTermRefPicSets] = {}; + uint32_t used_by_curr_pic_s1[kMaxShortTermRefPicSets] = {}; // Calculated fields. - uint32_t num_delta_pocs; + uint32_t num_delta_pocs = 0; }; // The parsed state of the SPS. Only some select values are stored. diff --git a/docs/native-code/rtp-hdrext/video-layers-allocation00/README.md b/docs/native-code/rtp-hdrext/video-layers-allocation00/README.md index c4454d8ee1..cfa8c4cb0d 100644 --- a/docs/native-code/rtp-hdrext/video-layers-allocation00/README.md +++ b/docs/native-code/rtp-hdrext/video-layers-allocation00/README.md @@ -22,6 +22,10 @@ rtp stream (SVC), or independent spatial layers sent on multiple rtp streams ## RTP header extension format +Note: when including the optional width, height and maximum framerate +fields, the total data length of the extension can exceed 16 bytes +and is sent as a two-byte header extension [1] + ### Data layout ``` @@ -68,7 +72,7 @@ alignment. layers. Values are stored in ascending order of spatial id. Zero-padded to byte alignment. -Target bitrate in kbps. Values are stored using leb128 encoding [1]. One value per +Target bitrate in kbps. Values are stored using leb128 encoding [2]. One value per temporal layer. Values are stored in (RTP stream id, spatial id, temporal id) ascending order. All bitrates are total required bitrate to receive the corresponding layer, i.e. in simulcast mode they include only corresponding @@ -78,9 +82,11 @@ temporal layers are also included. Resolution and framerate. Optional. Presence is inferred from the rtp header extension size. Encoded (width - 1), 16-bit, (height - 1), 16-bit, max frame rate 8-bit per spatial layer per RTP stream. Values are stored in (RTP stream -id, spatial id) ascending order. +id, spatial id) ascending order. Only sent when the resolution differs from the +last values, the framerate changed by more than 5fps and on key frames. An empty layer allocation (i.e nothing sent on ssrc) is encoded as special case with a single 0 byte. -[1] https://aomediacodec.github.io/av1-spec/#leb128 +[1] https://www.rfc-editor.org/rfc/rfc8285#section-4.3 +[2] https://aomediacodec.github.io/av1-spec/#leb128 diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 6ae2b71d85..458205cea7 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -11,6 +11,7 @@ import("../webrtc.gni") if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") + import("//third_party/jni_zero/jni_zero.gni") } else if (is_mac) { import("//build/config/mac/rules.gni") } else if (is_ios) { @@ -685,6 +686,7 @@ if (is_linux || is_chromeos || is_win) { ] deps = [ + "../api:async_dns_resolver", "../api:audio_options_api", "../api:create_peerconnection_factory", "../api:libjingle_peerconnection_api", @@ -702,6 +704,7 @@ if (is_linux || is_chromeos || is_win) { "../media:rtc_media_base", "../p2p:rtc_p2p", "../pc:video_track_source", + "../rtc_base:async_dns_resolver", "../rtc_base:checks", "../rtc_base:logging", "../rtc_base:macromagic", diff --git a/examples/androidnativeapi/BUILD.gn b/examples/androidnativeapi/BUILD.gn index 9aba1fbd92..e0eb6d8b24 100644 --- a/examples/androidnativeapi/BUILD.gn +++ b/examples/androidnativeapi/BUILD.gn @@ -1,6 +1,7 @@ import("//webrtc.gni") if (is_android) { + import("//third_party/jni_zero/jni_zero.gni") rtc_android_apk("androidnativeapi") { testonly = true apk_name = "androidnativeapi" diff --git a/examples/androidvoip/BUILD.gn b/examples/androidvoip/BUILD.gn index b4d53f81be..cea05ea128 100644 --- a/examples/androidvoip/BUILD.gn +++ b/examples/androidvoip/BUILD.gn @@ -9,6 +9,7 @@ import("//webrtc.gni") if (is_android) { + import("//third_party/jni_zero/jni_zero.gni") rtc_android_apk("androidvoip") { testonly = true apk_name = "androidvoip" diff --git a/examples/androidvoip/jni/android_voip_client.cc b/examples/androidvoip/jni/android_voip_client.cc index 92fad221d8..8a0a3badb9 100644 --- a/examples/androidvoip/jni/android_voip_client.cc +++ b/examples/androidvoip/jni/android_voip_client.cc @@ -427,10 +427,9 @@ void AndroidVoipClient::SendRtpPacket(const std::vector& packet_copy) { } } -bool AndroidVoipClient::SendRtp(const uint8_t* packet, - size_t length, +bool AndroidVoipClient::SendRtp(rtc::ArrayView packet, const webrtc::PacketOptions& options) { - std::vector packet_copy(packet, packet + length); + std::vector packet_copy(packet.begin(), packet.end()); voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] { SendRtpPacket(packet_copy); }); @@ -447,8 +446,8 @@ void AndroidVoipClient::SendRtcpPacket( } } -bool AndroidVoipClient::SendRtcp(const uint8_t* packet, size_t length) { - std::vector packet_copy(packet, packet + length); +bool AndroidVoipClient::SendRtcp(rtc::ArrayView packet) { + std::vector packet_copy(packet.begin(), packet.end()); voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] { SendRtcpPacket(packet_copy); }); diff --git a/examples/androidvoip/jni/android_voip_client.h b/examples/androidvoip/jni/android_voip_client.h index 8e1edd5ef9..e2f1c64590 100644 --- a/examples/androidvoip/jni/android_voip_client.h +++ b/examples/androidvoip/jni/android_voip_client.h @@ -118,10 +118,9 @@ class AndroidVoipClient : public webrtc::Transport, void Delete(JNIEnv* env); // Implementation for Transport. - bool SendRtp(const uint8_t* packet, - size_t length, + bool SendRtp(rtc::ArrayView packet, const webrtc::PacketOptions& options) override; - bool SendRtcp(const uint8_t* packet, size_t length) override; + bool SendRtcp(rtc::ArrayView packet) override; // Slots for sockets to connect to. void OnSignalReadRTPPacket(rtc::AsyncPacketSocket* socket, diff --git a/examples/peerconnection/client/peer_connection_client.cc b/examples/peerconnection/client/peer_connection_client.cc index 2746752d80..48d5bb6545 100644 --- a/examples/peerconnection/client/peer_connection_client.cc +++ b/examples/peerconnection/client/peer_connection_client.cc @@ -12,6 +12,7 @@ #include "api/units/time_delta.h" #include "examples/peerconnection/client/defaults.h" +#include "rtc_base/async_dns_resolver.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/net_helpers.h" @@ -32,7 +33,7 @@ rtc::Socket* CreateClientSocket(int family) { } // namespace PeerConnectionClient::PeerConnectionClient() - : callback_(NULL), resolver_(NULL), state_(NOT_CONNECTED), my_id_(-1) {} + : callback_(NULL), resolver_(nullptr), state_(NOT_CONNECTED), my_id_(-1) {} PeerConnectionClient::~PeerConnectionClient() = default; @@ -95,26 +96,32 @@ void PeerConnectionClient::Connect(const std::string& server, client_name_ = client_name; if (server_address_.IsUnresolvedIP()) { + RTC_DCHECK_NE(state_, RESOLVING); + RTC_DCHECK(!resolver_); state_ = RESOLVING; - resolver_ = new rtc::AsyncResolver(); - resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult); - resolver_->Start(server_address_); + resolver_ = std::make_unique(); + resolver_->Start(server_address_, + [this] { OnResolveResult(resolver_->result()); }); } else { DoConnect(); } } void PeerConnectionClient::OnResolveResult( - rtc::AsyncResolverInterface* resolver) { - if (resolver_->GetError() != 0) { + const webrtc::AsyncDnsResolverResult& result) { + if (result.GetError() != 0) { callback_->OnServerConnectionFailure(); - resolver_->Destroy(false); - resolver_ = NULL; + resolver_.reset(); state_ = NOT_CONNECTED; - } else { - server_address_ = resolver_->address(); - DoConnect(); + return; } + if (!result.GetResolvedAddress(AF_INET, &server_address_)) { + callback_->OnServerConnectionFailure(); + resolver_.reset(); + state_ = NOT_CONNECTED; + return; + } + DoConnect(); } void PeerConnectionClient::DoConnect() { @@ -196,10 +203,7 @@ void PeerConnectionClient::Close() { hanging_get_->Close(); onconnect_data_.clear(); peers_.clear(); - if (resolver_ != NULL) { - resolver_->Destroy(false); - resolver_ = NULL; - } + resolver_.reset(); my_id_ = -1; state_ = NOT_CONNECTED; } diff --git a/examples/peerconnection/client/peer_connection_client.h b/examples/peerconnection/client/peer_connection_client.h index 8f9c5b6a75..d56752a7fa 100644 --- a/examples/peerconnection/client/peer_connection_client.h +++ b/examples/peerconnection/client/peer_connection_client.h @@ -15,6 +15,7 @@ #include #include +#include "api/async_dns_resolver.h" #include "api/task_queue/pending_task_safety_flag.h" #include "rtc_base/net_helpers.h" #include "rtc_base/physical_socket_server.h" @@ -109,11 +110,11 @@ class PeerConnectionClient : public sigslot::has_slots<> { void OnClose(rtc::Socket* socket, int err); - void OnResolveResult(rtc::AsyncResolverInterface* resolver); + void OnResolveResult(const webrtc::AsyncDnsResolverResult& result); PeerConnectionClientObserver* callback_; rtc::SocketAddress server_address_; - rtc::AsyncResolver* resolver_; + std::unique_ptr resolver_; std::unique_ptr control_socket_; std::unique_ptr hanging_get_; std::string onconnect_data_; diff --git a/experiments/OWNERS b/experiments/OWNERS new file mode 100644 index 0000000000..116a65328a --- /dev/null +++ b/experiments/OWNERS @@ -0,0 +1,2 @@ +# Allow anyone to update the field trial experiment list. +per-file field_trials.py=* diff --git a/experiments/field_trials.py b/experiments/field_trials.py index c9a73ce1f3..e39b53eb47 100755 --- a/experiments/field_trials.py +++ b/experiments/field_trials.py @@ -8,107 +8,1080 @@ # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. +import datetime +from datetime import date import sys -from typing import Set +from typing import FrozenSet, List, Set import argparse import dataclasses -# TODO(bugs.webrtc.org/14154): End date and bug should also be stored. @dataclasses.dataclass(frozen=True) class FieldTrial: - """Representation of all attributes associated with a field trial. + """Representation of all attributes associated with a field trial. - Attributes: - key: Field trial key. - """ - key: str + Attributes: + key: Field trial key. + bug: Associated open bug containing more context. + end_date: Date when the field trial expires and must be deleted. + """ + key: str + bug: str + end_date: date # As per the policy in `g3doc/field-trials.md`, all field trials should be -# registered in the container below. Please keep the keys sorted. -REGISTERED_FIELD_TRIALS: Set[FieldTrial] = { - FieldTrial(''), # TODO(bugs.webrtc.org/14154): Populate -} +# registered in the container below. +ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ + # keep-sorted start + FieldTrial('WebRTC-Aec3DelayEstimatorDetectPreEcho', + 'webrtc:14205', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3PenalyzeHighDelaysInitialPhase', + 'webrtc:14919', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3PreEchoConfiguration', + 'webrtc:14205', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-GainController2', + 'webrtc:7494', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-OpusSetSignalVoiceWithDtx', + 'webrtc:4559', + date(2024, 4, 1)), + FieldTrial('WebRTC-Av1-GetEncoderInfoOverride', + 'webrtc:14931', + date(2024, 4, 1)), + FieldTrial('WebRTC-BurstyPacer', + 'chromium:1354491', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-SubtractAdditionalBackoffTerm', + 'webrtc:13402', + date(2024, 4, 1)), + FieldTrial('WebRTC-DisableRtxRateLimiter', + 'webrtc:15184', + date(2024, 4, 1)), + FieldTrial('WebRTC-EncoderDataDumpDirectory', + 'b/296242528', + date(2024, 4, 1)), + FieldTrial('WebRTC-IPv6NetworkResolutionFixes', + 'webrtc:14334', + date(2024, 4, 1)), + FieldTrial('WebRTC-IncomingTimestampOnMarkerBitOnly', + 'webrtc:14526', + date(2024, 4, 1)), + FieldTrial('WebRTC-IncreaseIceCandidatePriorityHostSrflx', + 'webrtc:15020', + date(2024, 4, 1)), + FieldTrial('WebRTC-JitterEstimatorConfig', + 'webrtc:14151', + date(2024, 4, 1)), + FieldTrial('WebRTC-LibaomAv1Encoder-DisableFrameDropping', + 'webrtc:15225', + date(2024, 4, 1)), + FieldTrial('WebRTC-Pacer-FastRetransmissions', + 'chromium:1354491', + date(2024, 4, 1)), + FieldTrial('WebRTC-Pacer-KeyframeFlushing', + 'webrtc:11340', + date(2024, 4, 1)), + FieldTrial('WebRTC-PaddingMode-RecentLargePacket', + 'webrtc:15201', + date(2024, 4, 1)), + FieldTrial('WebRTC-PermuteTlsClientHello', + 'webrtc:15467', + date(2024, 7, 1)), + FieldTrial('WebRTC-PreventSsrcGroupsWithUnexpectedSize', + 'chromium:1459124', + date(2024, 4, 1)), + FieldTrial('WebRTC-RtcEventLogEncodeDependencyDescriptor', + 'webrtc:14975', + date(2024, 4, 1)), + FieldTrial('WebRTC-RtcEventLogEncodeNetEqSetMinimumDelayKillSwitch', + 'webrtc:14763', + date(2024, 4, 1)), + FieldTrial('WebRTC-SCM-Timestamp', + 'webrtc:5773', + date(2024, 4, 1)), + FieldTrial('WebRTC-SendPacketsOnWorkerThread', + 'webrtc:14502', + date(2024, 4, 1)), + FieldTrial('WebRTC-Stats-RtxReceiveStats', + 'webrtc:15096', + date(2024, 4, 1)), + FieldTrial('WebRTC-TaskQueue-ReplaceLibeventWithStdlib', + 'webrtc:14389', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-EnableRetransmitAllLayers', + 'webrtc:14959', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-EncoderFallbackSettings', + 'webrtc:6634', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-RequestedResolutionOverrideOutputFormatRequest', + 'webrtc:14451', + date(2024, 4, 1)), + FieldTrial('WebRTC-VideoEncoderSettings', + 'chromium:1406331', + date(2024, 4, 1)), + # keep-sorted end +]) # yapf: disable + +INDEFINITE = date(datetime.MAXYEAR, 1, 1) + +# These field trials precedes the policy in `g3doc/field-trials.md` and are +# therefore not required to follow it. Do not add any new field trials here. +POLICY_EXEMPT_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ + # keep-sorted start + FieldTrial('UseTwccPlrForAna', + 'webrtc:7058', + date(2024, 4, 1)), + FieldTrial('WebRTC-AddNetworkCostToVpn', + 'webrtc:13097', + date(2024, 4, 1)), + FieldTrial('WebRTC-AddPacingToCongestionWindowPushback', + 'webrtc:10171', + date(2024, 4, 1)), + FieldTrial('WebRTC-AdjustOpusBandwidth', + 'webrtc:8522', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3AecStateFullResetKillSwitch', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3AntiHowlingMinimizationKillSwitch', + 'b/150764764', + INDEFINITE), + FieldTrial('WebRTC-Aec3ClampInstQualityToOneKillSwitch', + 'webrtc:10913', + INDEFINITE), + FieldTrial('WebRTC-Aec3ClampInstQualityToZeroKillSwitch', + 'webrtc:10913', + INDEFINITE), + FieldTrial('WebRTC-Aec3CoarseFilterResetHangoverKillSwitch', + 'webrtc:12265', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3ConservativeTailFreqResponse', + 'webrtc:13173', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3DeactivateInitialStateResetKillSwitch', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3DelayEstimateSmoothingDelayFoundOverride', + 'webrtc:12775', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3DelayEstimateSmoothingOverride', + 'webrtc:12775', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3EchoSaturationDetectionKillSwitch', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceCaptureDelayEstimationDownmixing', + 'webrtc:11153', + INDEFINITE), + FieldTrial( + 'WebRTC-Aec3EnforceCaptureDelayEstimationLeftRightPrioritization', + 'webrtc:11153', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceConservativeHfSuppression', + 'webrtc:11985', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3EnforceLowActiveRenderLimit', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceMoreTransparentNearendSuppressorHfTuning', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceMoreTransparentNearendSuppressorTuning', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceMoreTransparentNormalSuppressorHfTuning', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceMoreTransparentNormalSuppressorTuning', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceRapidlyAdjustingNearendSuppressorTunings', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceRapidlyAdjustingNormalSuppressorTunings', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceRenderDelayEstimationDownmixing', + 'webrtc:11153', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceSlowlyAdjustingNearendSuppressorTunings', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceSlowlyAdjustingNormalSuppressorTunings', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceStationarityProperties', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceStationarityPropertiesAtInit', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3EnforceVeryLowActiveRenderLimit', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3HighPassFilterEchoReference', + 'webrtc:12265', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3MinErleDuringOnsetsKillSwitch', + 'webrtc:10341', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3NonlinearModeReverbKillSwitch', + 'webrtc:11985', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3OnsetDetectionKillSwitch', + 'webrtc:11475', + INDEFINITE), + FieldTrial( + 'WebRTC-Aec3RenderDelayEstimationLeftRightPrioritizationKillSwitch', + 'webrtc:11153', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SensitiveDominantNearendActivation', + 'webrtc:11475', + INDEFINITE), + FieldTrial('WebRTC-Aec3SetupSpecificDefaultConfigDefaultsKillSwitch', + 'webrtc:11151', + INDEFINITE), + FieldTrial('WebRTC-Aec3ShortHeadroomKillSwitch', + 'webrtc:10341', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3StereoContentDetectionKillSwitch', + 'webrtc:14900', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorAntiHowlingGainOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorDominantNearendEnrExitThresholdOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorDominantNearendEnrThresholdOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorDominantNearendHoldDurationOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorDominantNearendSnrThresholdOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorDominantNearendTriggerThresholdOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorNearendHfMaskSuppressOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorNearendHfMaskTransparentOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorNearendLfMaskSuppressOverride', + 'webrtc:11487', + INDEFINITE), + FieldTrial('WebRTC-Aec3SuppressorNearendLfMaskTransparentOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNearendMaxDecFactorLfOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNearendMaxIncFactorOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalHfMaskSuppressOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalHfMaskTransparentOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalLfMaskSuppressOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalLfMaskTransparentOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalMaxDecFactorLfOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorNormalMaxIncFactorOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3SuppressorTuningOverride', + 'webrtc:11487', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3TransparentAntiHowlingGain', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3TransparentModeHmm', + 'webrtc:12265', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3TransparentModeKillSwitch', + 'webrtc:9256', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3Use1Dot2SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3Use1Dot6SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3Use2Dot0SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseDot1SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseDot2SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseDot3SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseDot6SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseDot9SecondsInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseErleOnsetCompensationInDominantNearend', + 'webrtc:12686', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseLowEarlyReflectionsDefaultGain', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseLowLateReflectionsDefaultGain', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseNearendReverbLen', + 'webrtc:13143', + INDEFINITE), + FieldTrial('WebRTC-Aec3UseShortConfigChangeDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3UseZeroInitialStateDuration', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Aec3VerySensitiveDominantNearendActivation', + 'webrtc:11475', + date(2024, 4, 1)), + FieldTrial('WebRTC-Agc2SimdAvx2KillSwitch', + 'webrtc:7494', + date(2024, 4, 1)), + FieldTrial('WebRTC-Agc2SimdNeonKillSwitch', + 'webrtc:7494', + date(2024, 4, 1)), + FieldTrial('WebRTC-Agc2SimdSse2KillSwitch', + 'webrtc:7494', + date(2024, 4, 1)), + FieldTrial('WebRTC-AllowMACBasedIPv6', + 'webrtc:12268', + date(2024, 4, 1)), + FieldTrial('WebRTC-AlrDetectorParameters', + 'webrtc:10542', + INDEFINITE), + FieldTrial('WebRTC-AndroidNetworkMonitor-IsAdapterAvailable', + 'webrtc:13741', + date(2024, 4, 1)), + FieldTrial('WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch', + 'webrtc:14901', + INDEFINITE), + FieldTrial('WebRTC-ApmExperimentalMultiChannelRenderKillSwitch', + 'webrtc:14902', + INDEFINITE), + FieldTrial('WebRTC-Audio-2ndAgcMinMicLevelExperiment', + 'chromium:1275566', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-ABWENoTWCC', + 'webrtc:8243', + INDEFINITE), + FieldTrial('WebRTC-Audio-AdaptivePtime', + 'chromium:1086942', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-Allocation', + 'webrtc:10286', + INDEFINITE), + FieldTrial('WebRTC-Audio-AlrProbing', + 'webrtc:10200', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-FecAdaptation', + 'webrtc:8127', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-LegacyOverhead', + 'webrtc:11001', + INDEFINITE), + FieldTrial('WebRTC-Audio-MinimizeResamplingOnMobile', + 'webrtc:6181', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-NetEqDecisionLogicConfig', + 'webrtc:13322', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-NetEqDelayManagerConfig', + 'webrtc:10333', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-NetEqNackTrackerConfig', + 'webrtc:10178', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-NetEqSmartFlushing', + 'webrtc:12201', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-OpusAvoidNoisePumpingDuringDtx', + 'webrtc:12380', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-OpusBitrateMultipliers', + 'webrtc:11055', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-OpusPlcUsePrevDecodedSamples', + 'b/143582588', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-Red-For-Opus', + 'webrtc:11640', + date(2024, 4, 1)), + FieldTrial('WebRTC-Audio-StableTargetAdaptation', + 'webrtc:10981', + INDEFINITE), + FieldTrial('WebRTC-Audio-iOS-Holding', + 'webrtc:8126', + date(2024, 4, 1)), + FieldTrial('WebRTC-AudioDevicePlayoutBufferSizeFactor', + 'webrtc:10928', + date(2024, 4, 1)), + FieldTrial('WebRTC-AutomaticAnimationDetectionScreenshare', + 'webrtc:11058', + date(2024, 4, 1)), + FieldTrial('WebRTC-Avx2SupportKillSwitch', + 'webrtc:11663', + date(2024, 4, 1)), + FieldTrial('WebRTC-BindUsingInterfaceName', + 'webrtc:10707', + date(2024, 4, 1)), + FieldTrial('WebRTC-BoostedScreenshareQp', + 'webrtc:9659', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-AllocationProbing', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-AlrProbing', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-EstimateBoundedIncrease', + 'webrtc:10498', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-ExponentialProbing', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate', + 'webrtc:10498', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-InitialProbing', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-InjectedCongestionController', + 'webrtc:8415', + INDEFINITE), + FieldTrial('WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate', + 'webrtc:11498', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-LinkCapacity', + 'webrtc:9718', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-LossBasedBweV2', + 'webrtc:12707', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-LossBasedControl', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-MaxRttLimit', + 'webrtc:9718', + INDEFINITE), + FieldTrial('WebRTC-Bwe-MinAllocAsLowerBound', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-NetworkRouteConstraints', + 'webrtc:11434', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-NoFeedbackReset', + 'webrtc:9718', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-ProbingBehavior', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-ProbingConfiguration', + 'webrtc:10394', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-ReceiveTimeFix', + 'webrtc:9054', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-ReceiverLimitCapsOnly', + 'webrtc:12306', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-RobustThroughputEstimatorSettings', + 'webrtc:10274', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-SafeResetOnRouteChange', + 'webrtc:9718', + INDEFINITE), + FieldTrial('WebRTC-Bwe-SeparateAudioPackets', + 'webrtc:10932', + date(2024, 4, 1)), + FieldTrial('WebRTC-Bwe-TrendlineEstimatorSettings', + 'webrtc:10932', + date(2024, 4, 1)), + FieldTrial('WebRTC-BweBackOffFactor', + 'webrtc:8212', + INDEFINITE), + FieldTrial('WebRTC-BweLossExperiment', + 'webrtc:5839', + date(2024, 4, 1)), + FieldTrial('WebRTC-BweRapidRecoveryExperiment', + 'webrtc:8015', + date(2024, 4, 1)), + FieldTrial('WebRTC-BweThroughputWindowConfig', + 'webrtc:10274', + date(2024, 4, 1)), + FieldTrial('WebRTC-BweWindowSizeInPackets', + 'webrtc:8212', + INDEFINITE), + FieldTrial('WebRTC-CongestionWindow', + 'webrtc:14898', + INDEFINITE), + FieldTrial('WebRTC-CpuLoadEstimator', + 'webrtc:8504', + date(2024, 4, 1)), + FieldTrial('WebRTC-Debugging-RtpDump', + 'webrtc:10675', + INDEFINITE), + FieldTrial('WebRTC-DecoderDataDumpDirectory', + 'webrtc:14236', + INDEFINITE), + FieldTrial('WebRTC-DefaultBitrateLimitsKillSwitch', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-DependencyDescriptorAdvertised', + 'webrtc:10342', + date(2024, 4, 1)), + FieldTrial('WebRTC-DisablePacerEmergencyStop', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-DisableUlpFecExperiment', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-DontIncreaseDelayBasedBweInAlr', + 'webrtc:10542', + date(2024, 4, 1)), + FieldTrial('WebRTC-DscpFieldTrial', + 'webrtc:13622', + date(2024, 4, 1)), + FieldTrial('WebRTC-ExtraICEPing', + 'webrtc:10273', + date(2024, 4, 1)), + FieldTrial('WebRTC-FakeNetworkReceiveConfig', + 'webrtc:14238', + INDEFINITE), + FieldTrial('WebRTC-FakeNetworkSendConfig', + 'webrtc:14238', + INDEFINITE), + FieldTrial('WebRTC-FilterAbsSendTimeExtension', + 'webrtc:10234', + INDEFINITE), + FieldTrial('WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart', + 'webrtc:11067', + date(2024, 4, 1)), + FieldTrial('WebRTC-FlexFEC-03', + 'webrtc:5654', + date(2024, 4, 1)), + FieldTrial('WebRTC-FlexFEC-03-Advertised', + 'webrtc:5654', + date(2024, 4, 1)), + FieldTrial('WebRTC-ForcePlayoutDelay', + 'webrtc:11896', + INDEFINITE), + FieldTrial('WebRTC-ForceSendPlayoutDelay', + 'webrtc:11896', + INDEFINITE), + FieldTrial('WebRTC-ForceSimulatedOveruseIntervalMs', + 'webrtc:14239', + INDEFINITE), + FieldTrial('WebRTC-FrameDropper', + 'webrtc:9711', + INDEFINITE), + FieldTrial('WebRTC-FullBandHpfKillSwitch', + 'webrtc:11193', + date(2024, 4, 1)), + FieldTrial('WebRTC-GenericCodecDependencyDescriptor', + 'webrtc:14969', + INDEFINITE), + FieldTrial('WebRTC-GenericDescriptorAdvertised', + 'webrtc:9361', + INDEFINITE), + FieldTrial('WebRTC-GenericDescriptorAuth', + 'webrtc:10103', + INDEFINITE), + FieldTrial('WebRTC-GenericPictureId', + 'webrtc:9361', + INDEFINITE), + FieldTrial('WebRTC-GetEncoderInfoOverride', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-H264HighProfile', + 'webrtc:6337', + date(2024, 4, 1)), + FieldTrial('WebRTC-IPv6Default', + 'chromium:413437', + date(2024, 4, 1)), + FieldTrial('WebRTC-IceControllerFieldTrials', + 'chromium:1024965', + INDEFINITE), + FieldTrial('WebRTC-IceFieldTrials', + 'webrtc:11021', + INDEFINITE), + FieldTrial('WebRTC-KeyframeInterval', + 'webrtc:10427', + INDEFINITE), + FieldTrial('WebRTC-LegacyFrameIdJumpBehavior', + 'webrtc:13343', + date(2024, 4, 1)), + FieldTrial('WebRTC-LegacySimulcastLayerLimit', + 'webrtc:8785', + INDEFINITE), + FieldTrial('WebRTC-LegacyTlsProtocols', + 'webrtc:10261', + date(2024, 4, 1)), + FieldTrial('WebRTC-LowresSimulcastBitrateInterpolation', + 'webrtc:12415', + date(2024, 4, 1)), + FieldTrial('WebRTC-MutedStateKillSwitch', + 'b/177830919', + date(2024, 4, 1)), + FieldTrial('WebRTC-Network-UseNWPathMonitor', + 'webrtc:10966', + date(2024, 4, 1)), + FieldTrial('WebRTC-NetworkMonitorAutoDetect', + 'webrtc:13741', + date(2024, 4, 1)), + FieldTrial('WebRTC-NormalizeSimulcastResolution', + '', + INDEFINITE), + FieldTrial('WebRTC-Pacer-BlockAudio', + 'webrtc:8415', + INDEFINITE), + FieldTrial('WebRTC-Pacer-DrainQueue', + 'webrtc:8415', + date(2024, 4, 1)), + FieldTrial('WebRTC-Pacer-IgnoreTransportOverhead', + 'webrtc:9883', + INDEFINITE), + FieldTrial('WebRTC-Pacer-PadInSilence', + 'webrtc:8415', + date(2024, 4, 1)), + FieldTrial('WebRTC-PacketBufferMaxSize', + 'webrtc:9851', + INDEFINITE), + FieldTrial('WebRTC-PcFactoryDefaultBitrates', + 'webrtc:10865', + date(2024, 4, 1)), + FieldTrial('WebRTC-PiggybackIceCheckAcknowledgement', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-PixelLimitResource', + 'webrtc:12261', + INDEFINITE), + FieldTrial('WebRTC-ProbingScreenshareBwe', + 'webrtc:7694', + date(2024, 4, 1)), + FieldTrial('WebRTC-ProtectionOverheadRateThreshold', + 'webrtc:14899', + INDEFINITE), + FieldTrial('WebRTC-QpParsingKillSwitch', + 'webrtc:12542', + date(2024, 4, 1)), + FieldTrial('WebRTC-RtcEventLogKillSwitch', + 'webrtc:12084', + INDEFINITE), + FieldTrial('WebRTC-RtcEventLogNewFormat', + 'webrtc:8111', + date(2024, 4, 1)), + FieldTrial('WebRTC-RtcpLossNotification', + 'webrtc:10336', + date(2024, 4, 1)), + FieldTrial('WebRTC-RttMult', + 'webrtc:9670', + INDEFINITE), + FieldTrial('WebRTC-SendBufferSizeBytes', + 'webrtc:11905', + date(2024, 4, 1)), + FieldTrial('WebRTC-ReceiveBufferSize', + 'webrtc:15585', + date(2024, 4, 1)), + FieldTrial('WebRTC-SendNackDelayMs', + 'webrtc:9953', + date(2024, 4, 1)), + FieldTrial('WebRTC-SetSocketReceiveBuffer', + 'webrtc:13753', + date(2024, 4, 1)), + FieldTrial('WebRTC-SignalNetworkPreferenceChange', + 'webrtc:11825', + date(2024, 4, 1)), + FieldTrial('WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-SimulcastLayerLimitRoundUp', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-SpsPpsIdrIsH264Keyframe', + 'webrtc:8423', + INDEFINITE), + FieldTrial('WebRTC-StableTargetRate', + 'webrtc:10126', + date(2024, 4, 1)), + FieldTrial('WebRTC-StrictPacingAndProbing', + 'webrtc:8072', + date(2024, 4, 1)), + FieldTrial('WebRTC-StunInterPacketDelay', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-SurfaceCellularTypes', + 'webrtc:11473', + date(2024, 4, 1)), + FieldTrial('WebRTC-SwitchEncoderOnInitializationFailures', + 'webrtc:13572', + date(2024, 4, 1)), + FieldTrial('WebRTC-Target-Bitrate-Rtcp', + 'webrtc:9969', + INDEFINITE), + FieldTrial('WebRTC-TransientSuppressorForcedOff', + 'chromium:1186705', + INDEFINITE), + FieldTrial('WebRTC-UseBaseHeavyVP8TL3RateAllocation', + 'webrtc:9477', + date(2024, 4, 1)), + FieldTrial('WebRTC-UseDifferentiatedCellularCosts', + 'webrtc:11473', + date(2024, 4, 1)), + FieldTrial('WebRTC-UseShortVP8TL2Pattern', + 'webrtc:9477', + INDEFINITE), + FieldTrial('WebRTC-UseShortVP8TL3Pattern', + 'webrtc:8162', + INDEFINITE), + FieldTrial('WebRTC-UseStandardBytesStats', + 'webrtc:10525', + date(2024, 4, 1)), + FieldTrial('WebRTC-UseTurnServerAsStunServer', + 'webrtc:11059', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP8-CpuSpeed-Arm', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP8-ForcePartitionResilience', + 'webrtc:11832', + INDEFINITE), + FieldTrial('WebRTC-VP8-Forced-Fallback-Encoder-v2', + 'webrtc:6634', + INDEFINITE), + FieldTrial('WebRTC-VP8-GetEncoderInfoOverride', + 'webrtc:11832', + INDEFINITE), + FieldTrial('WebRTC-VP8-MaxFrameInterval', + 'webrtc:15530', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP8-Postproc-Config', + 'webrtc:11551', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP8-Postproc-Config-Arm', + 'webrtc:6634', + INDEFINITE), + FieldTrial('WebRTC-VP8ConferenceTemporalLayers', + 'webrtc:9260', + INDEFINITE), + FieldTrial('WebRTC-VP8IosMaxNumberOfThread', + 'webrtc:10005', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP8VariableFramerateScreenshare', + 'webrtc:10310', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP9-GetEncoderInfoOverride', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP9-LowTierOptimizations', + 'webrtc:13888', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP9-PerformanceFlags', + 'webrtc:11551', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP9QualityScaler', + 'webrtc:11319', + date(2024, 4, 1)), + FieldTrial('WebRTC-VP9VariableFramerateScreenshare', + 'webrtc:10310', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-BalancedDegradation', + 'webrtc:7607', + INDEFINITE), + FieldTrial('WebRTC-Video-BalancedDegradationSettings', + '', + INDEFINITE), + FieldTrial('WebRTC-Video-BandwidthQualityScalerSettings', + 'webrtc:12942', + INDEFINITE), + FieldTrial('WebRTC-Video-DisableAutomaticResize', + 'webrtc:11812', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-DiscardPacketsWithUnknownSsrc', + 'webrtc:9871', + INDEFINITE), + FieldTrial('WebRTC-Video-ForcedSwDecoderFallback', + '', + INDEFINITE), + FieldTrial('WebRTC-Video-InitialDecoderResolution', + 'webrtc:11898', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-MinVideoBitrate', + 'webrtc:10915', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-Pacing', + 'webrtc:10038', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-PreferTemporalSupportOnBaseLayer', + 'webrtc:11324', + INDEFINITE), + FieldTrial('WebRTC-Video-QualityRampupSettings', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-QualityScalerSettings', + '', + INDEFINITE), + FieldTrial('WebRTC-Video-QualityScaling', + 'webrtc:9169', + INDEFINITE), + FieldTrial('WebRTC-Video-UseFrameRateForOverhead', + 'b/166341943', + date(2024, 4, 1)), + FieldTrial('WebRTC-Video-VariableStartScaleFactor', + '', + date(2024, 4, 1)), + FieldTrial('WebRTC-VideoFrameTrackingIdAdvertised', + 'webrtc:12594', + INDEFINITE), + FieldTrial('WebRTC-VideoLayersAllocationAdvertised', + 'webrtc:1200', + INDEFINITE), + FieldTrial('WebRTC-VideoRateControl', + 'webrtc:10223', + INDEFINITE), + FieldTrial('WebRTC-VoIPChannelRemixingAdjustmentKillSwitch', + 'chromium:1027117', + date(2024, 4, 1)), + FieldTrial('WebRTC-Vp9ExternalRefCtrl', + 'webrtc:9585', + date(2024, 4, 1)), + FieldTrial('WebRTC-Vp9InterLayerPred', + 'chromium:949536', + INDEFINITE), + FieldTrial('WebRTC-Vp9IssueKeyFrameOnLayerDeactivation', + 'chromium:889017', + date(2024, 4, 1)), + FieldTrial('WebRTC-ZeroHertzScreenshare', + 'chromium:1255737', + date(2024, 4, 1)), + FieldTrial('WebRTC-ZeroPlayoutDelay', + 'chromium:1335323', + date(2024, 4, 1)), + # keep-sorted end +]) # yapf: disable + +REGISTERED_FIELD_TRIALS: FrozenSet[FieldTrial] = ACTIVE_FIELD_TRIALS.union( + POLICY_EXEMPT_FIELD_TRIALS) -def RegistryHeader(field_trials: Set[FieldTrial] = None) -> str: - """Generates a C++ header with all field trial keys. - - Args: - field_trials: Field trials to include in the header. - - Returns: - String representation of a C++ header file containing all field trial keys. - - >>> trials = {FieldTrial('B'), FieldTrial('A'), FieldTrial('B')} - >>> print(RegistryHeader(trials)) - // This file was automatically generated. Do not edit. - - #ifndef GEN_REGISTERED_FIELD_TRIALS_H_ - #define GEN_REGISTERED_FIELD_TRIALS_H_ - - #include "absl/strings/string_view.h" - - namespace webrtc { - - inline constexpr absl::string_view kRegisteredFieldTrials[] = { - "A", - "B", - }; - - } // namespace webrtc - - #endif // GEN_REGISTERED_FIELD_TRIALS_H_ - - """ - if not field_trials: - field_trials = REGISTERED_FIELD_TRIALS - registered_keys = [f.key for f in field_trials] - keys = '\n'.join(f' "{k}",' for k in sorted(registered_keys)) - return ('// This file was automatically generated. Do not edit.\n' - '\n' - '#ifndef GEN_REGISTERED_FIELD_TRIALS_H_\n' - '#define GEN_REGISTERED_FIELD_TRIALS_H_\n' - '\n' - '#include "absl/strings/string_view.h"\n' - '\n' - 'namespace webrtc {\n' - '\n' - 'inline constexpr absl::string_view kRegisteredFieldTrials[] = {\n' - f'{keys}\n' - '};\n' - '\n' - '} // namespace webrtc\n' - '\n' - '#endif // GEN_REGISTERED_FIELD_TRIALS_H_\n') +def todays_date() -> date: + now = datetime.datetime.now(datetime.timezone.utc) + return date(now.year, now.month, now.day) -def CmdHeader(args: argparse.Namespace) -> None: - args.output.write(RegistryHeader()) +def registry_header( + field_trials: FrozenSet[FieldTrial] = REGISTERED_FIELD_TRIALS) -> str: + """Generates a C++ header with all field trial keys. + + Args: + field_trials: Field trials to include in the header. + + Returns: + String representation of a C++ header file containing all field trial + keys. + + >>> trials = { + ... FieldTrial('B', '', date(1, 1, 1)), + ... FieldTrial('A', '', date(1, 1, 1)), + ... FieldTrial('B', '', date(2, 2, 2)), + ... } + >>> print(registry_header(trials)) + // This file was automatically generated. Do not edit. + + #ifndef GEN_REGISTERED_FIELD_TRIALS_H_ + #define GEN_REGISTERED_FIELD_TRIALS_H_ + + #include "absl/strings/string_view.h" + + namespace webrtc { + + inline constexpr absl::string_view kRegisteredFieldTrials[] = { + "A", + "B", + }; + + } // namespace webrtc + + #endif // GEN_REGISTERED_FIELD_TRIALS_H_ + + """ + registered_keys = {f.key for f in field_trials} + keys = '\n'.join(f' "{k}",' for k in sorted(registered_keys)) + return ('// This file was automatically generated. Do not edit.\n' + '\n' + '#ifndef GEN_REGISTERED_FIELD_TRIALS_H_\n' + '#define GEN_REGISTERED_FIELD_TRIALS_H_\n' + '\n' + '#include "absl/strings/string_view.h"\n' + '\n' + 'namespace webrtc {\n' + '\n' + 'inline constexpr absl::string_view kRegisteredFieldTrials[] = {\n' + f'{keys}\n' + '};\n' + '\n' + '} // namespace webrtc\n' + '\n' + '#endif // GEN_REGISTERED_FIELD_TRIALS_H_\n') + + +def expired_field_trials( + threshold: date, + field_trials: FrozenSet[FieldTrial] = REGISTERED_FIELD_TRIALS +) -> Set[FieldTrial]: + """Obtains expired field trials. + + Args: + threshold: Date from which to check end date. + field_trials: Field trials to validate. + + Returns: + All expired field trials. + + >>> trials = { + ... FieldTrial('Expired', '', date(1, 1, 1)), + ... FieldTrial('Not-Expired', '', date(1, 1, 2)), + ... } + >>> expired_field_trials(date(1, 1, 1), trials) + {FieldTrial(key='Expired', bug='', end_date=datetime.date(1, 1, 1))} + """ + return {f for f in field_trials if f.end_date <= threshold} + + +def validate_field_trials( + field_trials: FrozenSet[FieldTrial] = ACTIVE_FIELD_TRIALS +) -> List[str]: + """Validate that field trials conforms to the policy. + + Args: + field_trials: Field trials to validate. + + Returns: + A list of explanations for invalid field trials. + """ + invalid = [] + for trial in field_trials: + if not trial.key.startswith('WebRTC-'): + invalid.append(f'{trial.key} does not start with "WebRTC-".') + if len(trial.bug) <= 0: + invalid.append(f'{trial.key} must have an associated bug.') + if trial.end_date >= INDEFINITE: + invalid.append(f'{trial.key} must have an end date.') + return invalid + + +def cmd_header(args: argparse.Namespace) -> None: + args.output.write(registry_header()) + + +def cmd_expired(args: argparse.Namespace) -> None: + today = todays_date() + diff = datetime.timedelta(days=args.in_days) + expired = expired_field_trials(today + diff) + + if len(expired) <= 0: + return + + expired_by_date = sorted([(f.end_date, f.key) for f in expired]) + print('\n'.join( + f'{key} {"expired" if date <= today else "expires"} on {date}' + for date, key in expired_by_date)) + if any(date <= today for date, _ in expired_by_date): + sys.exit(1) + + +def cmd_validate(args: argparse.Namespace) -> None: + del args + invalid = validate_field_trials() + + if len(invalid) <= 0: + return + + print('\n'.join(sorted(invalid))) + sys.exit(1) def main() -> None: - parser = argparse.ArgumentParser() - subcommand = parser.add_subparsers(dest='cmd') - parser_header = subcommand.add_parser( - 'header', - help='generate C++ header file containing registered field trial keys') - parser_header.add_argument('--output', - default=sys.stdout, - type=argparse.FileType('w'), - required=False, - help='output file') - parser_header.set_defaults(cmd=CmdHeader) - args = parser.parse_args() + parser = argparse.ArgumentParser() + subcommand = parser.add_subparsers(dest='cmd') - if not args.cmd: - parser.print_help(sys.stderr) - sys.exit(1) + parser_header = subcommand.add_parser( + 'header', + help='generate C++ header file containing registered field trial keys') + parser_header.add_argument('--output', + default=sys.stdout, + type=argparse.FileType('w'), + required=False, + help='output file') + parser_header.set_defaults(cmd=cmd_header) - args.cmd(args) + parser_expired = subcommand.add_parser( + 'expired', + help='lists all expired field trials', + description=''' + Lists all expired field trials. Exits with a non-zero exit status if + any field trials has expired, ignoring the --in-days argument. + ''') + parser_expired.add_argument( + '--in-days', + default=0, + type=int, + required=False, + help='number of days relative to today to check') + parser_expired.set_defaults(cmd=cmd_expired) + + parser_validate = subcommand.add_parser( + 'validate', + help='validates that all field trials conforms to the policy.', + description=''' + Validates that all field trials conforms to the policy. Exits with a + non-zero exit status if any field trials does not. + ''') + parser_validate.set_defaults(cmd=cmd_validate) + + args = parser.parse_args() + + if not args.cmd: + parser.print_help(sys.stderr) + sys.exit(1) + + args.cmd(args) if __name__ == '__main__': - main() + main() diff --git a/g3doc/abseil-in-webrtc.md b/g3doc/abseil-in-webrtc.md index 32fc42d953..034f6c2fb4 100644 --- a/g3doc/abseil-in-webrtc.md +++ b/g3doc/abseil-in-webrtc.md @@ -29,6 +29,7 @@ will generate a shared library. * `absl::bind_front` * `absl::Cleanup` * `absl::InlinedVector` +* `absl::Nonnull` and `absl::Nullable` * `absl::WrapUnique` * `absl::optional` and related stuff from `absl/types/optional.h`. * `absl::string_view` diff --git a/g3doc/field-trials.md b/g3doc/field-trials.md index e4f946a175..724a302fe1 100644 --- a/g3doc/field-trials.md +++ b/g3doc/field-trials.md @@ -39,7 +39,32 @@ The policy for field trials is: - The field trial must have an end date. The end date may be pushed back if necessary, but should not be pushed back indefinitely. - A field trial must be associated with a bug that - - reserves the field trial key, - - is open, - - is assigned to an owner, and - - has the end date specified. + - reserves the field trial key, and + - is assigned to an owner. + +## Creating a field trial + +Before creating a new field trial, make sure to read the [policy](#policy). + +Either create a new or reuse an existing bug and make sure it is assigned to the +correct owner. Take note of the bug ID. Next, decide how long you need the field +trial to last. It should be rare to have field trials lasting more than 12 +months. You can use the `NextAction` field in the bug to help you remember the +end date. + +Using this information, add a new entry to `ACTIVE_FIELD_TRIALS` in +`experiments/field_trials.py`. You may not add new items to +`POLICY_EXEMPT_FIELD_TRIALS` since it is reserved for field trials that were +created before the policy was in place. + +## Removing a field trial + +Any field trial that has expired or otherwise is not needed anymore may be +removed by following these steps: + +- Remove all references from the code base. You can find these by, e.g. + grepping for the field trial key. +- Clean up potential glue code that might have been added. +- Remove the field trial from `ACTIVE_FIELD_TRIALS` in + `experiments/field_trials.py`. +- If all work is finished, also close the associated bug. diff --git a/g3doc/style-guide.md b/g3doc/style-guide.md index 71d1196df2..b32163f906 100644 --- a/g3doc/style-guide.md +++ b/g3doc/style-guide.md @@ -127,6 +127,19 @@ For example, See the [source code for `rtc::ArrayView`](api/array_view.h) for more detailed docs. +### Strings + +WebRTC uses std::string, with content assumed to be UTF-8. Note that this +has to be verified whenever accepting external input. + +For concatenation of strings, use rtc::SimpleStringBuilder. + +The following string building tools are NOT recommended: +* The + operator. See https://abseil.io/tips/3 for why not. +* absl::StrCat, absl::StrAppend, absl::StrJoin. These are optimized for + speed, not code size, and have significant code size overhead. +* strcat. It is too easy to create buffer overflows. + ### sigslot SIGSLOT IS DEPRECATED. diff --git a/infra/config/commit-queue.cfg b/infra/config/commit-queue.cfg index 162590f0b4..c51eb0cd8b 100644 --- a/infra/config/commit-queue.cfg +++ b/infra/config/commit-queue.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see Config message: -# https://luci-config.appspot.com/schemas/projects:commit-queue.cfg +# https://config.luci.app/schemas/projects:commit-queue.cfg cq_status_host: "chromium-cq-status.appspot.com" submit_options { diff --git a/infra/config/config.star b/infra/config/config.star index 103b4ae318..eecac11c94 100755 --- a/infra/config/config.star +++ b/infra/config/config.star @@ -13,7 +13,7 @@ lucicfg.check_version("1.30.9") WEBRTC_GIT = "https://webrtc.googlesource.com/src" WEBRTC_GERRIT = "https://webrtc-review.googlesource.com/src" WEBRTC_TROOPER_EMAIL = "webrtc-troopers-robots@google.com" -WEBRTC_XCODE13 = "13c100" +WEBRTC_XCODE14 = "14c18" DEFAULT_CPU = "x86-64" # Helpers: @@ -677,10 +677,10 @@ def normal_builder_factory(**common_kwargs): # Mixins: ios_builder, ios_try_job = normal_builder_factory( - properties = {"xcode_build_version": WEBRTC_XCODE13}, + properties = {"xcode_build_version": WEBRTC_XCODE14}, caches = [swarming.cache( - name = "xcode_ios_" + WEBRTC_XCODE13, - path = "xcode_ios_" + WEBRTC_XCODE13 + ".app", + name = "xcode_ios_" + WEBRTC_XCODE14, + path = "xcode_ios_" + WEBRTC_XCODE14 + ".app", )], ) diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index e9ab652b45..cc36dc359c 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see BuildbucketCfg message: -# https://luci-config.appspot.com/schemas/projects:buildbucket.cfg +# https://config.luci.app/schemas/projects:buildbucket.cfg buckets { name: "ci" @@ -1593,13 +1593,13 @@ buckets { ' },' ' "builder_group": "client.webrtc",' ' "recipe": "webrtc/ios_api_framework",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 29 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -1645,13 +1645,13 @@ buckets { ' },' ' "builder_group": "client.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -1697,13 +1697,13 @@ buckets { ' },' ' "builder_group": "client.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -1749,13 +1749,13 @@ buckets { ' },' ' "builder_group": "client.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -3395,13 +3395,13 @@ buckets { ' },' ' "builder_group": "tryserver.webrtc",' ' "recipe": "webrtc/ios_api_framework",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -3447,13 +3447,13 @@ buckets { ' },' ' "builder_group": "tryserver.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -3499,13 +3499,13 @@ buckets { ' },' ' "builder_group": "tryserver.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -3551,13 +3551,13 @@ buckets { ' },' ' "builder_group": "tryserver.webrtc",' ' "recipe": "webrtc/standalone",' - ' "xcode_build_version": "13c100"' + ' "xcode_build_version": "14c18"' '}' priority: 30 execution_timeout_secs: 7200 caches { - name: "xcode_ios_13c100" - path: "xcode_ios_13c100.app" + name: "xcode_ios_14c18" + path: "xcode_ios_14c18.app" } build_numbers: YES service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" diff --git a/infra/config/luci-analysis.cfg b/infra/config/luci-analysis.cfg index 3a08bae367..6150da33f7 100644 --- a/infra/config/luci-analysis.cfg +++ b/infra/config/luci-analysis.cfg @@ -1,20 +1,18 @@ # Schema for this config file: ProjectConfig in: # https://luci-config.appspot.com/schemas/projects:luci-analysis.cfg -bug_filing_thresholds { - metric_id: "human-cls-failed-presubmit" - threshold { - # clusters blocking developers should have bugs filed. - one_day: 3 - } -} -bug_filing_thresholds { - metric_id: "test-runs-failed" - threshold { - # clusters that aren't blocking developers but are failing a significant - # amount of tasks should have bugs filed to look into optimizing machine - # resource usage. - one_day: 500 +bug_management { + default_bug_system: MONORAIL + monorail { + project: "webrtc" + default_field_values { + # Type field. + field_id: 38 + value: "Bug" + } + priority_field_id: 36 + monorail_hostname: "bugs.chromium.org" + display_prefix: "bugs.webrtc.org" } } @@ -30,107 +28,4 @@ clustering { like_template: "ninja:${target}/%${suite}.${case}%" } } -monorail { - project: "webrtc" - default_field_values { - # Type field. - field_id: 38 - value: "Bug" - } - priority_field_id: 36 - priorities { - priority: "0" - thresholds { - metric_id: "human-cls-failed-presubmit" - threshold { - one_day: 20 - } - } - } - priorities { - priority: "1" - thresholds { - metric_id: "human-cls-failed-presubmit" - threshold { - one_day: 10 - } - } - } - priorities { - priority: "2" - thresholds { - metric_id: "human-cls-failed-presubmit" - threshold { - one_day: 2 - } - } - } - priorities { - priority: "3" - # Clusters which fail to meet this threshold will be closed. - thresholds { - metric_id: "test-runs-failed" - threshold { - one_day: 2 - } - } - thresholds { - metric_id: "human-cls-failed-presubmit" - threshold { - one_day: 1 - seven_day: 1 - } - } - } - priority_hysteresis_percent: 50 - monorail_hostname: "bugs.chromium.org" - display_prefix: "bugs.webrtc.org" -} -realms { - name: "ci" - test_variant_analysis { - update_test_variant_task { - update_test_variant_task_interval { - seconds: 3600 # 1 hour - } - test_variant_status_update_duration { - seconds: 86400 # 24 hours - } - } - bq_exports { - table { - cloud_project: "webrtc-ci" - dataset: "weetbix" - table: "ci_flaky_test_variants" - } - predicate { - status: FLAKY - } - } - } -} - -realms { - name: "try" - test_variant_analysis { - update_test_variant_task { - update_test_variant_task_interval { - seconds: 3600 # 1 hour - } - test_variant_status_update_duration { - seconds: 86400 # 24 hours - } - } - bq_exports { - table { - cloud_project: "webrtc-ci" - dataset: "weetbix" - table: "try_flaky_test_variants" - } - predicate { - status: FLAKY - } - } - } -} diff --git a/infra/config/luci-logdog.cfg b/infra/config/luci-logdog.cfg index adc75bef49..01a391261d 100644 --- a/infra/config/luci-logdog.cfg +++ b/infra/config/luci-logdog.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see ProjectConfig message: -# https://luci-config.appspot.com/schemas/projects:luci-logdog.cfg +# https://config.luci.app/schemas/projects:luci-logdog.cfg reader_auth_groups: "all" writer_auth_groups: "luci-logdog-chromium-writers" diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index c3319ddb63..cca46cd157 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see Project message: -# https://luci-config.appspot.com/schemas/projects:luci-milo.cfg +# https://config.luci.app/schemas/projects:luci-milo.cfg consoles { id: "ci" diff --git a/infra/config/luci-notify.cfg b/infra/config/luci-notify.cfg index 0c22a488fa..8cae9b3f93 100644 --- a/infra/config/luci-notify.cfg +++ b/infra/config/luci-notify.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see ProjectConfig message: -# https://luci-config.appspot.com/schemas/projects:luci-notify.cfg +# https://config.luci.app/schemas/projects:luci-notify.cfg notifiers { notifications { diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg index c1bafa7a66..275b169bd9 100644 --- a/infra/config/luci-scheduler.cfg +++ b/infra/config/luci-scheduler.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see ProjectConfig message: -# https://luci-config.appspot.com/schemas/projects:luci-scheduler.cfg +# https://config.luci.app/schemas/projects:luci-scheduler.cfg job { id: "Android32" diff --git a/infra/config/project.cfg b/infra/config/project.cfg index f4a6bbb47c..ce5419c65c 100644 --- a/infra/config/project.cfg +++ b/infra/config/project.cfg @@ -2,12 +2,12 @@ # Do not modify manually. # # For the schema of this file, see ProjectCfg message: -# https://luci-config.appspot.com/schemas/projects:project.cfg +# https://config.luci.app/schemas/projects:project.cfg name: "webrtc" access: "group:all" lucicfg { - version: "1.39.11" + version: "1.40.0" package_dir: "." config_dir: "." entry_point: "config.star" diff --git a/infra/config/realms.cfg b/infra/config/realms.cfg index 6d5937a89b..171667555f 100644 --- a/infra/config/realms.cfg +++ b/infra/config/realms.cfg @@ -2,7 +2,7 @@ # Do not modify manually. # # For the schema of this file, see RealmsCfg message: -# https://luci-config.appspot.com/schemas/projects:realms.cfg +# https://config.luci.app/schemas/projects:realms.cfg realms { name: "@root" diff --git a/infra/specs/client.webrtc.json b/infra/specs/client.webrtc.json index 68632f1ad0..5f8adfc40e 100644 --- a/infra/specs/client.webrtc.json +++ b/infra/specs/client.webrtc.json @@ -7,6 +7,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -26,6 +27,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -45,6 +47,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -64,6 +67,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -83,6 +87,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -102,6 +107,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -121,6 +127,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -141,6 +148,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -161,6 +169,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -181,6 +190,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -200,6 +210,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -219,6 +230,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -238,6 +250,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -258,6 +271,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -277,6 +291,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -284,11 +299,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -297,6 +312,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -316,6 +332,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -335,6 +352,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -354,6 +372,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -374,6 +393,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -393,6 +413,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -439,6 +460,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -458,6 +480,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -477,6 +500,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -496,6 +520,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -515,6 +540,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -534,6 +560,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -553,6 +580,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -573,6 +601,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -593,6 +622,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -613,6 +643,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -632,6 +663,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -651,6 +683,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -670,6 +703,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -690,6 +724,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -709,6 +744,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -716,11 +752,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -729,6 +765,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -748,6 +785,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -767,6 +805,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -786,6 +825,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -806,6 +846,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -825,6 +866,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -871,6 +913,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -898,6 +941,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -917,6 +961,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -936,6 +981,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -955,6 +1001,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -974,6 +1021,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -993,6 +1041,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1012,6 +1061,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1032,6 +1082,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1052,6 +1103,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1072,6 +1124,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1091,6 +1144,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1110,6 +1164,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1129,6 +1184,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1149,6 +1205,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1168,6 +1225,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1175,11 +1233,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -1188,6 +1246,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1207,6 +1266,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1226,6 +1286,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1245,6 +1306,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1265,6 +1327,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1284,6 +1347,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1330,6 +1394,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1349,6 +1414,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1368,6 +1434,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1387,6 +1454,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1406,6 +1474,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1425,6 +1494,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1444,6 +1514,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1464,6 +1535,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1484,6 +1556,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1504,6 +1577,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1523,6 +1597,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1542,6 +1617,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1561,6 +1637,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1581,6 +1658,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1600,6 +1678,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1607,11 +1686,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -1620,6 +1699,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1639,6 +1719,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1658,6 +1739,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1677,6 +1759,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1697,6 +1780,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1716,6 +1800,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1768,7 +1853,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1783,6 +1867,7 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { @@ -1792,7 +1877,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1807,6 +1891,7 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { @@ -1816,7 +1901,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1831,6 +1915,7 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { @@ -1840,7 +1925,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1855,6 +1939,7 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { @@ -1864,7 +1949,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1879,6 +1963,7 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { @@ -1888,7 +1973,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1903,6 +1987,7 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { @@ -1912,7 +1997,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1928,6 +2012,7 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { @@ -1937,7 +2022,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1952,6 +2036,7 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { @@ -1961,7 +2046,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1977,6 +2061,7 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { @@ -1986,7 +2071,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2001,6 +2085,7 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { @@ -2010,7 +2095,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2025,6 +2109,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -2032,7 +2117,6 @@ "Linux (more configs)": { "isolated_scripts": [ { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2047,6 +2131,7 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" } ] @@ -2054,7 +2139,6 @@ "Linux Asan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2068,10 +2152,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2085,10 +2169,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2102,10 +2186,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2119,10 +2203,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2137,10 +2221,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2155,10 +2239,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2173,10 +2257,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2190,10 +2274,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2207,10 +2291,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2224,10 +2308,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2242,10 +2326,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2259,10 +2343,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2276,10 +2360,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2294,10 +2378,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2311,10 +2395,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2328,10 +2412,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2345,10 +2429,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2363,10 +2447,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2380,10 +2464,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2397,6 +2481,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -2404,7 +2489,6 @@ "Linux MSan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2418,10 +2502,10 @@ "os": "Ubuntu-20.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2435,10 +2519,10 @@ "os": "Ubuntu-20.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2452,10 +2536,10 @@ "os": "Ubuntu-20.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2469,10 +2553,10 @@ "os": "Ubuntu-20.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2487,10 +2571,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2505,10 +2589,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2523,10 +2607,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2540,10 +2624,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2557,10 +2641,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2574,10 +2658,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2592,10 +2676,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2609,10 +2693,10 @@ "os": "Ubuntu-20.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2627,10 +2711,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2644,10 +2728,10 @@ "os": "Ubuntu-20.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2661,10 +2745,10 @@ "os": "Ubuntu-20.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2678,10 +2762,10 @@ "os": "Ubuntu-20.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2696,10 +2780,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2713,10 +2797,10 @@ "os": "Ubuntu-20.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2730,6 +2814,7 @@ "os": "Ubuntu-20.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -2737,7 +2822,6 @@ "Linux Tsan v2": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2751,10 +2835,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2768,10 +2852,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2785,10 +2869,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2802,10 +2886,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2820,10 +2904,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2838,10 +2922,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2856,10 +2940,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2873,10 +2957,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2890,10 +2974,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2907,10 +2991,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2925,10 +3009,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2942,10 +3026,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2960,10 +3044,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2977,10 +3061,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2994,10 +3078,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3011,10 +3095,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3029,10 +3113,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3046,10 +3130,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3063,6 +3147,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -3070,7 +3155,6 @@ "Linux UBSan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3084,10 +3168,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3101,10 +3185,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3118,10 +3202,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3135,10 +3219,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3153,10 +3237,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3171,10 +3255,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3189,10 +3273,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3206,10 +3290,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3223,10 +3307,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3240,10 +3324,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3258,10 +3342,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3275,10 +3359,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3292,10 +3376,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3310,10 +3394,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3327,10 +3411,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3344,10 +3428,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3361,10 +3445,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3379,10 +3463,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3396,10 +3480,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3413,6 +3497,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -3420,7 +3505,6 @@ "Linux UBSan vptr": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3434,10 +3518,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3451,10 +3535,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3468,10 +3552,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3485,10 +3569,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3503,10 +3587,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3521,10 +3605,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3539,10 +3623,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3556,10 +3640,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3573,10 +3657,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3590,10 +3674,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3608,10 +3692,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3625,10 +3709,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3642,10 +3726,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3660,10 +3744,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3677,10 +3761,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3694,10 +3778,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3711,10 +3795,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3729,10 +3813,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3746,10 +3830,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3763,6 +3847,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -3770,7 +3855,6 @@ "Linux32 Debug": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3784,10 +3868,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3801,10 +3885,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3818,10 +3902,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3835,10 +3919,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3853,10 +3937,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3871,10 +3955,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3889,10 +3973,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3906,10 +3990,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3923,10 +4007,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3940,10 +4024,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3958,10 +4042,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3975,10 +4059,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3993,10 +4077,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4010,10 +4094,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4027,10 +4111,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4044,10 +4128,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4062,10 +4146,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4079,10 +4163,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4096,6 +4180,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -4104,7 +4189,6 @@ "Linux32 Release": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4118,10 +4202,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4135,10 +4219,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4152,10 +4236,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4169,10 +4253,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4187,10 +4271,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4205,10 +4289,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4223,10 +4307,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4240,10 +4324,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4257,10 +4341,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4274,10 +4358,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4292,10 +4376,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4309,10 +4393,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4327,10 +4411,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4344,10 +4428,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4361,10 +4445,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4378,10 +4462,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4396,10 +4480,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4413,10 +4497,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4430,6 +4514,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -4439,7 +4524,6 @@ "Linux64 Debug": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4453,10 +4537,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4470,10 +4554,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4487,10 +4571,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4504,10 +4588,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4522,10 +4606,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4540,10 +4624,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4558,10 +4642,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4575,10 +4659,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4592,10 +4676,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4609,10 +4693,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4627,10 +4711,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4644,10 +4728,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4661,10 +4745,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4679,10 +4763,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4696,10 +4780,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4713,10 +4797,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4730,10 +4814,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4748,10 +4832,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4765,10 +4849,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4782,6 +4866,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -4790,7 +4875,6 @@ "Linux64 Release": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4804,10 +4888,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4821,10 +4905,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4838,10 +4922,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4855,10 +4939,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4873,10 +4957,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4891,10 +4975,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4909,10 +4993,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4926,10 +5010,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4943,10 +5027,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4960,10 +5044,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4978,10 +5062,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4995,10 +5079,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5012,10 +5096,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5030,10 +5114,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5047,10 +5131,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5064,10 +5148,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5081,10 +5165,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5099,10 +5183,10 @@ "pool": "WebRTC-baremetal" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5117,10 +5201,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5134,10 +5218,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5151,6 +5235,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -5160,7 +5245,6 @@ "Mac Asan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5175,10 +5259,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5193,10 +5277,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5211,10 +5295,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5229,10 +5313,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5248,10 +5332,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5267,10 +5351,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5286,10 +5370,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5304,10 +5388,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5322,10 +5406,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5340,10 +5424,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5359,10 +5443,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5377,10 +5461,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5396,10 +5480,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5414,10 +5498,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5432,10 +5516,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5450,10 +5534,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5469,10 +5553,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5487,10 +5571,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5505,6 +5589,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -5513,7 +5598,6 @@ "Mac64 Debug": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5528,10 +5612,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5546,10 +5630,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5564,10 +5648,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5582,10 +5666,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5601,10 +5685,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5620,10 +5704,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5639,10 +5723,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5657,10 +5741,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5675,10 +5759,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5693,10 +5777,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5712,10 +5796,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5730,10 +5814,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5749,10 +5833,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5767,10 +5851,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5785,10 +5869,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5803,10 +5887,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5822,10 +5906,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5840,10 +5924,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5858,6 +5942,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -5865,7 +5950,6 @@ "Mac64 Release": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5879,10 +5963,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5896,10 +5980,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5913,10 +5997,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5930,10 +6014,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5948,10 +6032,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5966,10 +6050,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5984,10 +6068,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6001,10 +6085,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6018,10 +6102,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6035,10 +6119,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6053,10 +6137,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6070,10 +6154,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6088,10 +6172,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6105,10 +6189,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6122,10 +6206,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6139,10 +6223,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6157,10 +6241,10 @@ "pool": "WebRTC-baremetal" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6175,10 +6259,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6192,10 +6276,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6209,6 +6293,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -6216,7 +6301,6 @@ "MacARM64 M1 Release": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6230,10 +6314,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6247,10 +6331,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6264,10 +6348,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6281,10 +6365,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6299,10 +6383,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6317,10 +6401,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6335,10 +6419,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6352,10 +6436,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6369,10 +6453,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6386,10 +6470,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6404,10 +6488,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6421,10 +6505,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6439,10 +6523,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6456,10 +6540,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6473,10 +6557,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6490,10 +6574,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6508,10 +6592,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6525,10 +6609,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6542,6 +6626,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -6550,7 +6635,6 @@ "Win (more configs)": { "isolated_scripts": [ { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6565,6 +6649,7 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" } ] @@ -6574,7 +6659,6 @@ "Win32 Release (Clang)": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6588,10 +6672,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6605,10 +6689,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6622,10 +6706,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6639,10 +6723,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6657,10 +6741,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6675,10 +6759,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6693,10 +6777,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6710,10 +6794,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6727,10 +6811,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6744,10 +6828,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6762,10 +6846,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6779,10 +6863,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6797,10 +6881,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6814,10 +6898,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6831,10 +6915,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6848,10 +6932,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6866,10 +6950,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6883,10 +6967,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6900,6 +6984,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -6907,7 +6992,6 @@ "Win64 ASan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6921,10 +7005,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6938,10 +7022,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6955,10 +7039,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6972,10 +7056,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6990,10 +7074,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7008,10 +7092,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7026,10 +7110,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7043,10 +7127,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7060,10 +7144,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7077,10 +7161,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7095,10 +7179,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7112,10 +7196,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7130,10 +7214,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7147,10 +7231,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7164,10 +7248,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7181,10 +7265,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7199,10 +7283,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7216,10 +7300,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7233,6 +7317,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -7240,7 +7325,6 @@ "Win64 Debug (Clang)": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7254,10 +7338,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7271,10 +7355,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7288,10 +7372,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7305,10 +7389,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7323,10 +7407,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7341,10 +7425,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7359,10 +7443,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7376,10 +7460,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7393,10 +7477,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7410,10 +7494,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7428,10 +7512,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7445,10 +7529,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7463,10 +7547,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7480,10 +7564,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7497,10 +7581,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7514,10 +7598,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7532,10 +7616,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7549,10 +7633,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7566,6 +7650,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -7573,7 +7658,6 @@ "Win64 Release (Clang)": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7587,10 +7671,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7604,10 +7688,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7621,10 +7705,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7638,10 +7722,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7656,10 +7740,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7674,10 +7758,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7692,10 +7776,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7709,10 +7793,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7726,10 +7810,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7743,10 +7827,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7761,10 +7845,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7778,10 +7862,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7796,10 +7880,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7813,10 +7897,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7830,10 +7914,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7847,10 +7931,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7865,10 +7949,10 @@ "pool": "WebRTC-baremetal" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7883,10 +7967,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7900,10 +7984,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7917,6 +8001,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -7936,7 +8021,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7969,6 +8053,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 14.5" }, @@ -7985,7 +8070,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8018,6 +8102,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 15.5" }, @@ -8034,7 +8119,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8067,6 +8151,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 16.2" }, @@ -8082,7 +8167,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8115,6 +8199,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 14.5" }, @@ -8130,7 +8215,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8163,6 +8247,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 15.5" }, @@ -8178,7 +8263,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8211,6 +8295,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 16.2" }, @@ -8226,7 +8311,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8259,6 +8343,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 14.5" }, @@ -8274,7 +8359,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8307,6 +8391,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 15.5" }, @@ -8322,7 +8407,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8355,6 +8439,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 16.2" }, @@ -8370,7 +8455,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8403,6 +8487,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 14.5" }, @@ -8418,7 +8503,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8451,6 +8535,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 15.5" }, @@ -8466,7 +8551,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8499,6 +8583,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 16.2" }, @@ -8514,7 +8599,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8547,6 +8631,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 14.5" }, @@ -8562,7 +8647,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8595,6 +8679,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 15.5" }, @@ -8610,7 +8695,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8643,6 +8727,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 16.2" }, @@ -8658,7 +8743,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8692,6 +8776,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 14.5" }, @@ -8707,7 +8792,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8741,6 +8825,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 15.5" }, @@ -8756,7 +8841,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8790,6 +8874,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 16.2" }, @@ -8805,7 +8890,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8840,6 +8924,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 14.5" }, @@ -8855,7 +8940,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8890,6 +8974,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 15.5" }, @@ -8905,7 +8990,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8940,6 +9024,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 16.2" }, @@ -8955,7 +9040,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8988,6 +9072,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9003,7 +9088,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9036,6 +9120,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9051,7 +9136,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9084,6 +9168,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9099,7 +9184,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9132,6 +9216,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9147,7 +9232,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9180,6 +9264,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9195,7 +9280,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9228,6 +9312,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9243,7 +9328,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9276,6 +9360,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9291,7 +9376,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9324,6 +9408,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9339,7 +9424,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9372,6 +9456,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9387,7 +9472,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9421,6 +9505,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9436,7 +9521,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9470,6 +9554,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9485,7 +9570,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9519,6 +9603,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9535,7 +9620,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9568,6 +9652,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9584,7 +9669,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9617,6 +9701,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9633,7 +9718,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9666,6 +9750,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9682,7 +9767,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9715,6 +9799,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 14.5" }, @@ -9731,7 +9816,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9764,6 +9848,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 15.5" }, @@ -9780,7 +9865,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9813,6 +9897,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 16.2" }, @@ -9828,7 +9913,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9863,6 +9947,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 14.5" }, @@ -9878,7 +9963,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9913,6 +9997,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 15.5" }, @@ -9928,7 +10013,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9963,6 +10047,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 16.2" }, @@ -9978,7 +10063,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10011,6 +10095,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 14.5" }, @@ -10026,7 +10111,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10059,6 +10143,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 15.5" }, @@ -10074,7 +10159,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10107,6 +10191,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 16.2" }, @@ -10122,7 +10207,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10155,6 +10239,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 14.5" }, @@ -10170,7 +10255,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10203,6 +10287,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 15.5" }, @@ -10218,7 +10303,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10251,6 +10335,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 16.2" }, @@ -10266,7 +10351,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10299,6 +10383,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 14.5" }, @@ -10314,7 +10399,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10347,6 +10431,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 15.5" }, @@ -10362,7 +10447,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10395,6 +10479,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 16.2" }, @@ -10410,7 +10495,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10443,6 +10527,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 14.5" }, @@ -10458,7 +10543,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10491,6 +10575,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 15.5" }, @@ -10506,7 +10591,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10539,6 +10623,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 16.2" }, @@ -10554,7 +10639,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10588,6 +10672,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 14.5" }, @@ -10603,7 +10688,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10637,6 +10721,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 15.5" }, @@ -10652,7 +10737,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10686,6 +10770,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 16.2" }, @@ -10701,7 +10786,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10734,6 +10818,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 14.5" }, @@ -10749,7 +10834,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10782,6 +10866,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 15.5" }, @@ -10797,7 +10882,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10830,6 +10914,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 16.2" }, @@ -10845,7 +10930,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10878,6 +10962,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 14.5" }, @@ -10893,7 +10978,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10926,6 +11010,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 15.5" }, @@ -10941,7 +11026,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10974,6 +11058,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 16.2" } diff --git a/infra/specs/client.webrtc.perf.json b/infra/specs/client.webrtc.perf.json index 80a1bc21b7..bb05e580ca 100644 --- a/infra/specs/client.webrtc.perf.json +++ b/infra/specs/client.webrtc.perf.json @@ -14,6 +14,7 @@ ], "script": "//tools_webrtc/perf/process_perf_results.py" }, + "name": "video_codec_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -47,6 +48,7 @@ ], "script": "//tools_webrtc/perf/process_perf_results.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -83,6 +85,7 @@ ], "script": "//tools_webrtc/perf/process_perf_results.py" }, + "name": "video_codec_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -116,6 +119,7 @@ ], "script": "//tools_webrtc/perf/process_perf_results.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -149,7 +153,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb" ], - "isolate_name": "video_codec_perf_tests", "merge": { "args": [ "--test-suite", @@ -174,6 +177,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { @@ -185,7 +189,6 @@ "--isolated-script-test-perf-output=${ISOLATED_OUTDIR}/perftest-output.pb", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -210,6 +213,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -220,7 +224,6 @@ "args": [ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "args": [ "--test-suite", @@ -244,6 +247,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { @@ -253,7 +257,6 @@ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -277,6 +280,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -287,7 +291,6 @@ "args": [ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "args": [ "--test-suite", @@ -312,6 +315,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { @@ -321,7 +325,6 @@ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -346,6 +349,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -356,7 +360,6 @@ "args": [ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "args": [ "--test-suite", @@ -381,6 +384,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { @@ -390,7 +394,6 @@ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -415,6 +418,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -425,7 +429,6 @@ "args": [ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "args": [ "--test-suite", @@ -449,6 +452,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { @@ -458,7 +462,6 @@ "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -482,6 +485,7 @@ "idempotent": false, "io_timeout": 10800 }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] diff --git a/infra/specs/internal.client.webrtc.json b/infra/specs/internal.client.webrtc.json index eff9fe0704..1e3a147201 100644 --- a/infra/specs/internal.client.webrtc.json +++ b/infra/specs/internal.client.webrtc.json @@ -7,11 +7,10 @@ "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -29,28 +28,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -68,17 +68,19 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { @@ -86,11 +88,10 @@ "--readline-timeout=1200", "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -108,6 +109,7 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, @@ -115,24 +117,24 @@ "io_timeout": 7200, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -150,29 +152,30 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -190,28 +193,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -229,28 +233,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -268,28 +273,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -307,28 +313,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -346,28 +353,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -385,28 +393,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -424,18 +433,20 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" } ] @@ -447,12 +458,11 @@ "--write_perf_output_on_ios", "--xctest", "--xcode-build-version", - "13c100", + "14c18", "--out-dir", "${ISOLATED_OUTDIR}", "--nologs" ], - "isolate_name": "webrtc_perf_tests", "merge": { "args": [ "--test-suite", @@ -474,8 +484,9 @@ } ], "dimensions": { + "device_status": "available", "id": "mac-254-e504", - "os": "iOS-12.4.1", + "os": "iOS-15.7.8", "pool": "WebRTC" }, "hard_timeout": 10800, @@ -483,12 +494,13 @@ "io_timeout": 10800, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_14c18", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -499,11 +511,10 @@ "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -521,28 +532,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -560,17 +572,19 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { @@ -578,11 +592,10 @@ "--readline-timeout=1200", "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -600,6 +613,7 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, @@ -607,24 +621,24 @@ "io_timeout": 7200, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -642,29 +656,30 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -682,28 +697,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -721,28 +737,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -760,28 +777,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -799,28 +817,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -838,28 +857,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -877,28 +897,29 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ "--xctest", "--xcode-build-version", - "15a5229h", + "15a240d", "--out-dir", "${ISOLATED_OUTDIR}" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -916,18 +937,20 @@ } ], "dimensions": { + "device_status": "available", "os": "iOS-16.6", "pool": "chrome.tests" }, "named_caches": [ { - "name": "xcode_ios_15a5229h", + "name": "xcode_ios_15a240d", "path": "Xcode.app" } ], "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" } ] diff --git a/infra/specs/mixins.pyl b/infra/specs/mixins.pyl index 055fbeacda..cbf9b2472f 100644 --- a/infra/specs/mixins.pyl +++ b/infra/specs/mixins.pyl @@ -51,6 +51,14 @@ } } }, + 'crosshatch': { + 'swarming': { + 'dimensions': { + 'device_type': 'crosshatch', + 'os': 'Android' + } + } + }, 'fuchsia-gtest-output': { 'args': [ '--test-launcher-summary-output=${ISOLATED_OUTDIR}/gtest_output.json', @@ -68,7 +76,8 @@ 'swarming': { 'dimensions': { 'os': 'iOS-16.6', - 'pool': 'chrome.tests' + 'pool': 'chrome.tests', + 'device_status': 'available' } } }, @@ -76,9 +85,10 @@ 'swarming': { 'idempotent': False, 'dimensions': { - 'os': 'iOS-12.4.1', + 'os': 'iOS-15.7.8', 'pool': 'WebRTC', - 'id': 'mac-254-e504' + 'id': 'mac-254-e504', + 'device_status': 'available' } } }, @@ -210,7 +220,7 @@ 'args': ['--nologs'] }, 'quick-perf-tests': { - 'args': ['--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/', '--nologs'] + 'args': ['--webrtc_quick_perf_test', '--nologs'] }, 'redfin': { 'swarming': { @@ -247,6 +257,11 @@ 'shards': 6 } }, + 'shards-8': { + 'swarming': { + 'shards': 8 + } + }, 'timeout-2h': { 'swarming': { 'hard_timeout': 7200, @@ -310,10 +325,10 @@ } }, 'xcode_15_main': { - 'args': ['--xcode-build-version', '15a5229h'], + 'args': ['--xcode-build-version', '15a240d'], 'swarming': { 'named_caches': [{ - 'name': 'xcode_ios_15a5229h', + 'name': 'xcode_ios_15a240d', 'path': 'Xcode.app' }] } diff --git a/infra/specs/mixins_webrtc.pyl b/infra/specs/mixins_webrtc.pyl index c6d8e5dc75..f8fa66b27f 100644 --- a/infra/specs/mixins_webrtc.pyl +++ b/infra/specs/mixins_webrtc.pyl @@ -35,6 +35,14 @@ } } }, + 'crosshatch': { + 'swarming': { + 'dimensions': { + 'device_type': 'crosshatch', + 'os': 'Android', + }, + }, + }, # Hack to use the test-launcher-summary-output flag + emulator folders for gtest-output # but it's currently the only way to get the file out of the emulator. 'fuchsia-gtest-output': { @@ -48,7 +56,8 @@ 'swarming': { 'dimensions': { 'os': 'iOS-16.6', - 'pool': 'chrome.tests' + 'pool': 'chrome.tests', + 'device_status': 'available' } } }, @@ -56,9 +65,10 @@ 'swarming': { 'idempotent': False, 'dimensions': { - 'os': 'iOS-12.4.1', + 'os': 'iOS-15.7.8', 'pool': 'WebRTC', 'id': 'mac-254-e504', + 'device_status': 'available' }, }, }, @@ -148,7 +158,7 @@ }, 'quick-perf-tests': { 'args': [ - '--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/', + '--webrtc_quick_perf_test', '--nologs', ], }, @@ -189,6 +199,11 @@ 'shards': 6, }, }, + 'shards-8': { + 'swarming': { + 'shards': 8, + }, + }, 'timeout-2h': { 'swarming': { 'hard_timeout': 7200, diff --git a/infra/specs/test_suites.pyl b/infra/specs/test_suites.pyl index 9430d45a39..570314c9bd 100644 --- a/infra/specs/test_suites.pyl +++ b/infra/specs/test_suites.pyl @@ -42,7 +42,7 @@ }, 'slow_peer_connection_unittests': {}, 'svc_tests': { - 'mixins': ['shards-4'], + 'mixins': ['shards-8', 'crosshatch'], }, 'system_wrappers_unittests': {}, 'test_support_unittests': {}, diff --git a/infra/specs/tryserver.webrtc.json b/infra/specs/tryserver.webrtc.json index b89ee5f731..61f4221970 100644 --- a/infra/specs/tryserver.webrtc.json +++ b/infra/specs/tryserver.webrtc.json @@ -7,6 +7,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -26,6 +27,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -45,6 +47,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -64,6 +67,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -83,6 +87,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -102,6 +107,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -121,6 +127,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -141,6 +148,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -161,6 +169,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -181,6 +190,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -200,6 +210,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -219,6 +230,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -238,6 +250,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -258,6 +271,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -277,6 +291,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -284,11 +299,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -297,6 +312,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -316,6 +332,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -335,6 +352,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -354,6 +372,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -374,6 +393,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -393,6 +413,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -410,12 +431,13 @@ }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs" ], "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -462,6 +484,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -481,6 +504,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -500,6 +524,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -519,6 +544,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -538,6 +564,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -557,6 +584,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -576,6 +604,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -596,6 +625,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -616,6 +646,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -636,6 +667,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -655,6 +687,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -674,6 +707,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -693,6 +727,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -713,6 +748,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -732,6 +768,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -739,11 +776,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -752,6 +789,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -771,6 +809,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -790,6 +829,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -809,6 +849,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -829,6 +870,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -848,6 +890,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -865,12 +908,13 @@ }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs" ], "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -917,6 +961,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -936,6 +981,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -955,6 +1001,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -974,6 +1021,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -993,6 +1041,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1012,6 +1061,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1031,6 +1081,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1051,6 +1102,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1071,6 +1123,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1091,6 +1144,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1110,6 +1164,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1129,6 +1184,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1148,6 +1204,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1168,6 +1225,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1187,6 +1245,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1194,11 +1253,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -1207,6 +1266,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1226,6 +1286,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1245,6 +1306,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1264,6 +1326,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1284,6 +1347,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1303,6 +1367,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1320,12 +1385,13 @@ }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs" ], "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1372,6 +1438,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1396,6 +1463,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "AppRTCMobile_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1415,6 +1483,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "android_instrumentation_test_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1434,6 +1503,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "audio_decoder_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1453,6 +1523,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_audio_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1472,6 +1543,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "common_video_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1491,6 +1563,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "dcsctp_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1510,6 +1583,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1530,6 +1604,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "modules_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1550,6 +1625,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "peerconnection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1570,6 +1646,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_media_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1589,6 +1666,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_pc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1608,6 +1686,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_stats_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1627,6 +1706,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "rtc_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1647,6 +1727,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "slow_peer_connection_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1666,6 +1747,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "svc_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1673,11 +1755,11 @@ "swarming": { "dimensions": { "android_devices": "1", - "device_type": "walleye", + "device_type": "crosshatch", "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "shards": 8 }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" @@ -1686,6 +1768,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "system_wrappers_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1705,6 +1788,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "test_support_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1724,6 +1808,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "tools_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1743,6 +1828,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "video_engine_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1763,6 +1849,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "voip_unittests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1782,6 +1869,7 @@ "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_nonparallel_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1799,12 +1887,13 @@ }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs" ], "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, + "name": "webrtc_perf_tests", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1862,7 +1951,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1877,6 +1965,7 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { @@ -1886,7 +1975,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1901,6 +1989,7 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { @@ -1910,7 +1999,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1925,6 +2013,7 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { @@ -1934,7 +2023,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1949,6 +2037,7 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { @@ -1958,7 +2047,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1973,6 +2061,7 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { @@ -1982,7 +2071,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -1997,6 +2085,7 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { @@ -2006,7 +2095,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2022,6 +2110,7 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { @@ -2031,7 +2120,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2046,6 +2134,7 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { @@ -2055,7 +2144,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2071,6 +2159,7 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { @@ -2080,7 +2169,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2095,6 +2183,7 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { @@ -2104,7 +2193,6 @@ "--test-arg=--undefok=test_launcher_summary_output", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2119,6 +2207,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -2140,7 +2229,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2173,6 +2261,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 14.5" }, @@ -2189,7 +2278,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2222,6 +2310,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 15.5" }, @@ -2238,7 +2327,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "apprtcmobile_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2271,6 +2359,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", "variant_id": "iPhone X 16.2" }, @@ -2286,7 +2375,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2319,6 +2407,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 14.5" }, @@ -2334,7 +2423,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2367,6 +2455,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 15.5" }, @@ -2382,7 +2471,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2415,6 +2503,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", "variant_id": "iPhone X 16.2" }, @@ -2430,7 +2519,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2463,6 +2551,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 14.5" }, @@ -2478,7 +2567,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2511,6 +2599,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 15.5" }, @@ -2526,7 +2615,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2559,6 +2647,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", "variant_id": "iPhone X 16.2" }, @@ -2574,7 +2663,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2607,6 +2695,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 14.5" }, @@ -2622,7 +2711,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2655,6 +2743,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 15.5" }, @@ -2670,7 +2759,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2703,6 +2791,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", "variant_id": "iPhone X 16.2" }, @@ -2718,7 +2807,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2751,6 +2839,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 14.5" }, @@ -2766,7 +2855,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2799,6 +2887,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 15.5" }, @@ -2814,7 +2903,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2847,6 +2935,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", "variant_id": "iPhone X 16.2" }, @@ -2862,7 +2951,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2896,6 +2984,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 14.5" }, @@ -2911,7 +3000,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2945,6 +3033,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 15.5" }, @@ -2960,7 +3049,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -2994,6 +3082,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", "variant_id": "iPhone X 16.2" }, @@ -3009,7 +3098,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3044,6 +3132,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3059,7 +3148,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3094,6 +3182,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3109,7 +3198,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3144,6 +3232,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3159,7 +3248,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3192,6 +3280,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3207,7 +3296,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3240,6 +3328,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3255,7 +3344,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3288,6 +3376,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3303,7 +3392,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3336,6 +3424,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3351,7 +3440,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3384,6 +3472,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3399,7 +3488,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3432,6 +3520,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3447,7 +3536,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3480,6 +3568,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3495,7 +3584,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3528,6 +3616,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3543,7 +3632,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3576,6 +3664,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3591,7 +3680,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3625,6 +3713,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3640,7 +3729,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3674,6 +3762,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3689,7 +3778,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3723,6 +3811,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3739,7 +3828,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3772,6 +3860,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3788,7 +3877,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3821,6 +3909,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3837,7 +3926,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_framework_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3870,6 +3958,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", "variant_id": "iPhone X 16.2" }, @@ -3886,7 +3975,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3919,6 +4007,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 14.5" }, @@ -3935,7 +4024,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -3968,6 +4056,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 15.5" }, @@ -3984,7 +4073,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "sdk_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4017,6 +4105,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", "variant_id": "iPhone X 16.2" }, @@ -4032,7 +4121,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4067,6 +4155,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 14.5" }, @@ -4082,7 +4171,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4117,6 +4205,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 15.5" }, @@ -4132,7 +4221,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4167,6 +4255,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", "variant_id": "iPhone X 16.2" }, @@ -4182,7 +4271,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4215,6 +4303,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 14.5" }, @@ -4230,7 +4319,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4263,6 +4351,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 15.5" }, @@ -4278,7 +4367,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4311,6 +4399,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", "variant_id": "iPhone X 16.2" }, @@ -4326,7 +4415,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4359,6 +4447,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 14.5" }, @@ -4374,7 +4463,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4407,6 +4495,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 15.5" }, @@ -4422,7 +4511,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4455,6 +4543,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", "variant_id": "iPhone X 16.2" }, @@ -4470,7 +4559,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4503,6 +4591,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 14.5" }, @@ -4518,7 +4607,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4551,6 +4639,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 15.5" }, @@ -4566,7 +4655,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4599,6 +4687,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", "variant_id": "iPhone X 16.2" }, @@ -4614,7 +4703,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4647,6 +4735,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 14.5" }, @@ -4662,7 +4751,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4695,6 +4783,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 15.5" }, @@ -4710,7 +4799,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4743,6 +4831,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", "variant_id": "iPhone X 16.2" }, @@ -4758,7 +4847,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4792,6 +4880,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 14.5" }, @@ -4807,7 +4896,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4841,6 +4929,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 15.5" }, @@ -4856,7 +4945,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4890,6 +4978,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 16.2" }, @@ -4905,7 +4994,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4938,6 +5026,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 14.5" }, @@ -4953,7 +5042,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -4986,6 +5074,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 15.5" }, @@ -5001,7 +5090,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5034,6 +5122,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 16.2" }, @@ -5049,7 +5138,6 @@ "--xcode-build-version", "13c100" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5082,6 +5170,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 14.5" }, @@ -5097,7 +5186,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5130,6 +5218,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 15.5" }, @@ -5145,7 +5234,6 @@ "--xcode-build-version", "14c18" ], - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5178,6 +5266,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 16.2" } @@ -5186,7 +5275,6 @@ "linux_asan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5200,10 +5288,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5217,10 +5305,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5234,10 +5322,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5251,10 +5339,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5269,10 +5357,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5287,10 +5375,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5305,10 +5393,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5322,10 +5410,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5339,10 +5427,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5356,10 +5444,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5374,10 +5462,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5391,10 +5479,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5408,10 +5496,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5426,10 +5514,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5443,10 +5531,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5460,10 +5548,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5477,10 +5565,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5495,10 +5583,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5512,10 +5600,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5529,6 +5617,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -5542,7 +5631,6 @@ "linux_coverage": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5557,10 +5645,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5575,10 +5663,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5593,10 +5681,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5611,10 +5699,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5630,10 +5718,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5649,10 +5737,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5668,10 +5756,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5686,10 +5774,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5704,10 +5792,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5722,10 +5810,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5741,10 +5829,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5759,10 +5847,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5777,10 +5865,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5796,10 +5884,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5814,10 +5902,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5832,10 +5920,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5850,10 +5938,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5869,15 +5957,15 @@ "pool": "WebRTC-baremetal-try" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5893,10 +5981,10 @@ "os": "Ubuntu-18.04" } }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { - "isolate_name": "video_engine_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5912,10 +6000,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5930,10 +6018,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5948,15 +6036,15 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_perf_tests", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5972,6 +6060,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -5979,7 +6068,6 @@ "linux_dbg": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -5993,10 +6081,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6010,10 +6098,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6027,10 +6115,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6044,10 +6132,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6062,10 +6150,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6080,10 +6168,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6098,10 +6186,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6115,10 +6203,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6132,10 +6220,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6149,10 +6237,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6167,10 +6255,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6184,10 +6272,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6201,10 +6289,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6219,10 +6307,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6236,10 +6324,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6253,10 +6341,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6270,10 +6358,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6288,10 +6376,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6305,10 +6393,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6322,6 +6410,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -6330,7 +6419,6 @@ "linux_memcheck": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6344,10 +6432,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6361,10 +6449,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6378,10 +6466,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6395,10 +6483,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6413,10 +6501,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6431,10 +6519,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6449,10 +6537,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6466,10 +6554,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6483,10 +6571,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6500,10 +6588,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6518,10 +6606,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6535,10 +6623,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6552,10 +6640,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6570,10 +6658,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6587,10 +6675,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6604,10 +6692,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6621,10 +6709,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6639,10 +6727,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6656,10 +6744,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6673,6 +6761,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -6680,7 +6769,6 @@ "linux_more_configs": { "isolated_scripts": [ { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6695,6 +6783,7 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" } ] @@ -6702,7 +6791,6 @@ "linux_msan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6716,10 +6804,10 @@ "os": "Ubuntu-20.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6733,10 +6821,10 @@ "os": "Ubuntu-20.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6750,10 +6838,10 @@ "os": "Ubuntu-20.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6767,10 +6855,10 @@ "os": "Ubuntu-20.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6785,10 +6873,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6803,10 +6891,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6821,10 +6909,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6838,10 +6926,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6855,10 +6943,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6872,10 +6960,10 @@ "os": "Ubuntu-20.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6890,10 +6978,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6907,10 +6995,10 @@ "os": "Ubuntu-20.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6925,10 +7013,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6942,10 +7030,10 @@ "os": "Ubuntu-20.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6959,10 +7047,10 @@ "os": "Ubuntu-20.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6976,10 +7064,10 @@ "os": "Ubuntu-20.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -6994,10 +7082,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7011,10 +7099,10 @@ "os": "Ubuntu-20.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7028,6 +7116,7 @@ "os": "Ubuntu-20.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -7035,7 +7124,6 @@ "linux_rel": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7049,10 +7137,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7066,10 +7154,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7083,10 +7171,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7100,10 +7188,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7118,10 +7206,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7136,10 +7224,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7154,10 +7242,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7171,10 +7259,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7188,10 +7276,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7205,10 +7293,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7223,10 +7311,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7240,10 +7328,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7257,10 +7345,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7275,10 +7363,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7292,10 +7380,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7309,10 +7397,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7326,10 +7414,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7344,15 +7432,15 @@ "pool": "WebRTC-baremetal-try" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7367,10 +7455,10 @@ "os": "Ubuntu-18.04" } }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7385,10 +7473,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7402,10 +7490,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7419,15 +7507,15 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7442,6 +7530,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -7449,7 +7538,6 @@ "linux_tsan2": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7463,10 +7551,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7480,10 +7568,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7497,10 +7585,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7514,10 +7602,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7532,10 +7620,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7550,10 +7638,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7568,10 +7656,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7585,10 +7673,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7602,10 +7690,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7619,10 +7707,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7637,10 +7725,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7654,10 +7742,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7672,10 +7760,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7689,10 +7777,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7706,10 +7794,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7723,10 +7811,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7741,10 +7829,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7758,10 +7846,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7775,6 +7863,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -7782,7 +7871,6 @@ "linux_ubsan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7796,10 +7884,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7813,10 +7901,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7830,10 +7918,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7847,10 +7935,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7865,10 +7953,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7883,10 +7971,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7901,10 +7989,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7918,10 +8006,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7935,10 +8023,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7952,10 +8040,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7970,10 +8058,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -7987,10 +8075,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8004,10 +8092,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8022,10 +8110,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8039,10 +8127,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8056,10 +8144,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8073,10 +8161,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8091,10 +8179,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8108,10 +8196,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8125,6 +8213,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -8132,7 +8221,6 @@ "linux_ubsan_vptr": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8146,10 +8234,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8163,10 +8251,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8180,10 +8268,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8197,10 +8285,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8215,10 +8303,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8233,10 +8321,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8251,10 +8339,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8268,10 +8356,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8285,10 +8373,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8302,10 +8390,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8320,10 +8408,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "shared_screencast_stream_test", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8337,10 +8425,10 @@ "os": "Ubuntu-18.04" } }, + "test": "shared_screencast_stream_test", "test_id_prefix": "ninja://modules/desktop_capture:shared_screencast_stream_test/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8354,10 +8442,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8372,10 +8460,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8389,10 +8477,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8406,10 +8494,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8423,10 +8511,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8441,10 +8529,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8458,10 +8546,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8475,6 +8563,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -8482,7 +8571,6 @@ "linux_x86_dbg": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8496,10 +8584,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8513,10 +8601,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8530,10 +8618,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8547,10 +8635,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8565,10 +8653,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8583,10 +8671,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8601,10 +8689,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8618,10 +8706,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8635,10 +8723,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8652,10 +8740,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8670,10 +8758,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8687,10 +8775,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8705,10 +8793,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8722,10 +8810,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8739,10 +8827,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8756,10 +8844,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8774,10 +8862,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8791,10 +8879,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8808,6 +8896,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -8815,7 +8904,6 @@ "linux_x86_rel": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8829,10 +8917,10 @@ "os": "Ubuntu-18.04" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8846,10 +8934,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8863,10 +8951,10 @@ "os": "Ubuntu-18.04" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8880,10 +8968,10 @@ "os": "Ubuntu-18.04" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8898,10 +8986,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8916,10 +9004,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8934,10 +9022,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8951,10 +9039,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8968,10 +9056,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -8985,10 +9073,10 @@ "os": "Ubuntu-18.04" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9003,10 +9091,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9020,10 +9108,10 @@ "os": "Ubuntu-18.04" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9038,10 +9126,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9055,10 +9143,10 @@ "os": "Ubuntu-18.04" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9072,10 +9160,10 @@ "os": "Ubuntu-18.04" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9089,10 +9177,10 @@ "os": "Ubuntu-18.04" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9107,10 +9195,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9124,10 +9212,10 @@ "os": "Ubuntu-18.04" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9141,6 +9229,7 @@ "os": "Ubuntu-18.04" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -9148,7 +9237,6 @@ "mac_asan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9163,10 +9251,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9181,10 +9269,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9199,10 +9287,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9217,10 +9305,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9236,10 +9324,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9255,10 +9343,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9274,10 +9362,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9292,10 +9380,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9310,10 +9398,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9328,10 +9416,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9347,10 +9435,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9365,10 +9453,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9384,10 +9472,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9402,10 +9490,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9420,10 +9508,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9438,10 +9526,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9457,10 +9545,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9475,10 +9563,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9493,6 +9581,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -9502,7 +9591,6 @@ "mac_dbg": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9517,10 +9605,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9535,10 +9623,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9553,10 +9641,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9571,10 +9659,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9590,10 +9678,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9609,10 +9697,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9628,10 +9716,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9646,10 +9734,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9664,10 +9752,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9682,10 +9770,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9701,10 +9789,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9719,10 +9807,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9738,10 +9826,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9756,10 +9844,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9774,10 +9862,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9792,10 +9880,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9811,10 +9899,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9829,10 +9917,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9847,6 +9935,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -9854,7 +9943,6 @@ "mac_dbg_m1": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9868,10 +9956,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9885,10 +9973,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9902,10 +9990,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9919,10 +10007,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9937,10 +10025,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9955,10 +10043,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9973,10 +10061,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -9990,10 +10078,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10007,10 +10095,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10024,10 +10112,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10042,10 +10130,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10059,10 +10147,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10077,10 +10165,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10094,10 +10182,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10111,10 +10199,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10128,10 +10216,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10146,10 +10234,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10163,10 +10251,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10180,6 +10268,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -10187,7 +10276,6 @@ "mac_rel": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10201,10 +10289,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10218,10 +10306,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10235,10 +10323,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10252,10 +10340,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10270,10 +10358,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10288,10 +10376,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10306,10 +10394,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10323,10 +10411,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10340,10 +10428,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10357,10 +10445,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10375,10 +10463,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10392,10 +10480,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10410,10 +10498,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10427,10 +10515,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10444,10 +10532,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10461,10 +10549,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10479,15 +10567,15 @@ "pool": "WebRTC-baremetal-try" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10502,10 +10590,10 @@ "os": "Mac-12" } }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10520,10 +10608,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10537,10 +10625,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10554,15 +10642,15 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10577,6 +10665,7 @@ "os": "Mac-12" } }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -10584,7 +10673,6 @@ "mac_rel_m1": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10598,10 +10686,10 @@ "os": "Mac-12" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10615,10 +10703,10 @@ "os": "Mac-12" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10632,10 +10720,10 @@ "os": "Mac-12" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10649,10 +10737,10 @@ "os": "Mac-12" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10667,10 +10755,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10685,10 +10773,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10703,10 +10791,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10720,10 +10808,10 @@ "os": "Mac-12" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10737,10 +10825,10 @@ "os": "Mac-12" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10754,10 +10842,10 @@ "os": "Mac-12" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10772,10 +10860,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10789,10 +10877,10 @@ "os": "Mac-12" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10807,10 +10895,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10824,10 +10912,10 @@ "os": "Mac-12" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10841,10 +10929,10 @@ "os": "Mac-12" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10858,10 +10946,10 @@ "os": "Mac-12" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10876,10 +10964,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10893,10 +10981,10 @@ "os": "Mac-12" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10910,6 +10998,7 @@ "os": "Mac-12" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -10917,7 +11006,6 @@ "win_asan": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10931,10 +11019,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10948,10 +11036,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10965,10 +11053,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -10982,10 +11070,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11000,10 +11088,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11018,10 +11106,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11036,10 +11124,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11053,10 +11141,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11070,10 +11158,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11087,10 +11175,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11105,10 +11193,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11122,10 +11210,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11140,10 +11228,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11157,10 +11245,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11174,10 +11262,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11191,10 +11279,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11209,10 +11297,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11226,10 +11314,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11243,6 +11331,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -11254,7 +11343,6 @@ "win_x64_clang_dbg": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11268,10 +11356,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11285,10 +11373,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11302,10 +11390,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11319,10 +11407,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11337,10 +11425,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11355,10 +11443,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11373,10 +11461,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11390,10 +11478,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11407,10 +11495,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11424,10 +11512,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11442,10 +11530,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11459,10 +11547,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11477,10 +11565,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11494,10 +11582,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11511,10 +11599,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11528,10 +11616,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11546,10 +11634,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11563,10 +11651,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11580,6 +11668,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -11587,7 +11676,6 @@ "win_x64_clang_rel": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11601,10 +11689,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11618,10 +11706,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11635,10 +11723,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11652,10 +11740,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11670,10 +11758,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11688,10 +11776,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11706,10 +11794,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11723,10 +11811,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11740,10 +11828,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11757,10 +11845,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11775,10 +11863,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11792,10 +11880,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11810,10 +11898,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11827,10 +11915,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11844,10 +11932,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11861,10 +11949,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11879,10 +11967,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11896,10 +11984,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11913,6 +12001,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -11920,7 +12009,6 @@ "win_x86_clang_dbg": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11934,10 +12022,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11951,10 +12039,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11968,10 +12056,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -11985,10 +12073,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12003,10 +12091,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12021,10 +12109,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12039,10 +12127,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12056,10 +12144,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12073,10 +12161,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12090,10 +12178,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12108,10 +12196,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12125,10 +12213,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12143,10 +12231,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12160,10 +12248,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12177,10 +12265,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12194,10 +12282,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12212,10 +12300,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12229,10 +12317,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12246,6 +12334,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" } ] @@ -12253,7 +12342,6 @@ "win_x86_clang_rel": { "isolated_scripts": [ { - "isolate_name": "audio_decoder_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12267,10 +12355,10 @@ "os": "Windows-10-19045" } }, + "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" }, { - "isolate_name": "common_audio_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12284,10 +12372,10 @@ "os": "Windows-10-19045" } }, + "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/" }, { - "isolate_name": "common_video_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12301,10 +12389,10 @@ "os": "Windows-10-19045" } }, + "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/" }, { - "isolate_name": "dcsctp_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12318,10 +12406,10 @@ "os": "Windows-10-19045" } }, + "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" }, { - "isolate_name": "modules_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12336,10 +12424,10 @@ }, "shards": 2 }, + "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/" }, { - "isolate_name": "modules_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12354,10 +12442,10 @@ }, "shards": 6 }, + "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/" }, { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12372,10 +12460,10 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" }, { - "isolate_name": "rtc_media_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12389,10 +12477,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/" }, { - "isolate_name": "rtc_pc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12406,10 +12494,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/" }, { - "isolate_name": "rtc_stats_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12423,10 +12511,10 @@ "os": "Windows-10-19045" } }, + "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/" }, { - "isolate_name": "rtc_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12441,10 +12529,10 @@ }, "shards": 6 }, + "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/" }, { - "isolate_name": "slow_peer_connection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12458,10 +12546,10 @@ "os": "Windows-10-19045" } }, + "test": "slow_peer_connection_unittests", "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" }, { - "isolate_name": "svc_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12476,10 +12564,10 @@ }, "shards": 4 }, + "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/" }, { - "isolate_name": "system_wrappers_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12493,10 +12581,10 @@ "os": "Windows-10-19045" } }, + "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" }, { - "isolate_name": "test_support_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12510,10 +12598,10 @@ "os": "Windows-10-19045" } }, + "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/" }, { - "isolate_name": "tools_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12527,10 +12615,10 @@ "os": "Windows-10-19045" } }, + "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, { - "isolate_name": "video_capture_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12545,15 +12633,15 @@ "pool": "WebRTC-baremetal-try" } }, + "test": "video_capture_tests", "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "video_codec_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12568,10 +12656,10 @@ "os": "Windows-10-19045" } }, + "test": "video_codec_perf_tests", "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" }, { - "isolate_name": "video_engine_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12586,10 +12674,10 @@ }, "shards": 4 }, + "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/" }, { - "isolate_name": "voip_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12603,10 +12691,10 @@ "os": "Windows-10-19045" } }, + "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/" }, { - "isolate_name": "webrtc_nonparallel_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12620,15 +12708,15 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" }, { "args": [ - "--force_fieldtrials=WebRTC-QuickPerfTest/Enabled/", + "--webrtc_quick_perf_test", "--nologs", "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" ], - "isolate_name": "webrtc_perf_tests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12643,6 +12731,7 @@ "os": "Windows-10-19045" } }, + "test": "webrtc_perf_tests", "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] @@ -12650,7 +12739,6 @@ "win_x86_more_configs": { "isolated_scripts": [ { - "isolate_name": "peerconnection_unittests", "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, @@ -12665,6 +12753,7 @@ }, "shards": 4 }, + "test": "peerconnection_unittests", "test_id_prefix": "ninja://pc:peerconnection_unittests/" } ] diff --git a/infra/specs/waterfalls.pyl b/infra/specs/waterfalls.pyl index 79e8cdd860..76c1760d1d 100644 --- a/infra/specs/waterfalls.pyl +++ b/infra/specs/waterfalls.pyl @@ -335,7 +335,7 @@ 'iOS64 Perf': { 'mixins': [ 'ios-device-perf', 'webrtc-xctest', 'timeout-3h', - 'chrome-tester-service-account', 'xcode_13_main', 'mac_toolchain', + 'chrome-tester-service-account', 'xcode_14_main', 'mac_toolchain', 'has_native_resultdb_integration', 'out_dir_arg' ], 'test_suites': { diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc index 5d83c72a0b..2c9e42e064 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.cc @@ -110,6 +110,8 @@ rtclog2::FrameDecodedEvents::Codec ConvertToProtoFormat(VideoCodecType codec) { case VideoCodecType::kVideoCodecMultiplex: // This codec type is afaik not used. return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN; + case VideoCodecType::kVideoCodecH265: + return rtclog2::FrameDecodedEvents::CODEC_H265; } RTC_DCHECK_NOTREACHED(); return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN; diff --git a/logging/rtc_event_log/rtc_event_log2.proto b/logging/rtc_event_log/rtc_event_log2.proto index 658df6b6ff..a417ded706 100644 --- a/logging/rtc_event_log/rtc_event_log2.proto +++ b/logging/rtc_event_log/rtc_event_log2.proto @@ -339,6 +339,7 @@ message FrameDecodedEvents { CODEC_VP9 = 3; CODEC_AV1 = 4; CODEC_H264 = 5; + CODEC_H265 = 6; } // required diff --git a/logging/rtc_event_log/rtc_event_log_parser.cc b/logging/rtc_event_log/rtc_event_log_parser.cc index 0ea96431a7..37bb70a69b 100644 --- a/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/logging/rtc_event_log/rtc_event_log_parser.cc @@ -261,6 +261,8 @@ VideoCodecType GetRuntimeCodecType(rtclog2::FrameDecodedEvents::Codec codec) { return VideoCodecType::kVideoCodecAV1; case rtclog2::FrameDecodedEvents::CODEC_H264: return VideoCodecType::kVideoCodecH264; + case rtclog2::FrameDecodedEvents::CODEC_H265: + return VideoCodecType::kVideoCodecH265; case rtclog2::FrameDecodedEvents::CODEC_UNKNOWN: RTC_LOG(LS_ERROR) << "Unknown codec type. Assuming " "VideoCodecType::kVideoCodecMultiplex"; diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index b378e8ff48..aece4b5753 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -169,11 +169,11 @@ std::unique_ptr EventGenerator::NewFrameDecodedEvent( constexpr int kMaxHeight = 8640; constexpr int kMinWidth = 16; constexpr int kMinHeight = 16; - constexpr int kNumCodecTypes = 5; + constexpr int kNumCodecTypes = 6; constexpr VideoCodecType kCodecList[kNumCodecTypes] = { - kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9, kVideoCodecAV1, - kVideoCodecH264}; + kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9, + kVideoCodecAV1, kVideoCodecH264, kVideoCodecH265}; const int64_t render_time_ms = rtc::TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs); const int width = prng_.Rand(kMinWidth, kMaxWidth); diff --git a/media/BUILD.gn b/media/BUILD.gn index 22eb02ab4f..cf7c523201 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -339,8 +339,10 @@ rtc_library("rtc_simulcast_encoder_adapter") { deps = [ ":rtc_media_base", "../api:fec_controller_api", + "../api:field_trials_view", "../api:scoped_refptr", "../api:sequence_checker", + "../api/transport:field_trial_based_config", "../api/video:video_codec_constants", "../api/video:video_frame", "../api/video:video_rtp_headers", @@ -348,6 +350,7 @@ rtc_library("rtc_simulcast_encoder_adapter") { "../api/video_codecs:video_codecs_api", "../call:video_stream_api", "../common_video", + "../media:media_constants", "../modules/video_coding:video_codec_interface", "../modules/video_coding:video_coding_utility", "../rtc_base:checks", @@ -357,7 +360,6 @@ rtc_library("rtc_simulcast_encoder_adapter") { "../rtc_base/system:no_unique_address", "../rtc_base/system:rtc_export", "../system_wrappers", - "../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -813,6 +815,7 @@ if (rtc_include_tests) { ":stream_params", ":turn_utils", "../api:create_simulcast_test_fixture_api", + "../api:field_trials_view", "../api:libjingle_peerconnection_api", "../api:mock_encoder_selector", "../api:mock_video_bitrate_allocator", diff --git a/media/base/codec.cc b/media/base/codec.cc index 7ecf383d9f..b819707702 100644 --- a/media/base/codec.cc +++ b/media/base/codec.cc @@ -362,6 +362,14 @@ Codec CreateVideoRtxCodec(int rtx_payload_type, int associated_payload_type) { return rtx_codec; } +const Codec* FindCodecById(const std::vector& codecs, int payload_type) { + for (const auto& codec : codecs) { + if (codec.id == payload_type) + return &codec; + } + return nullptr; +} + bool HasLntf(const Codec& codec) { return codec.HasFeedbackParam( FeedbackParam(kRtcpFbParamLntf, kParamValueEmpty)); @@ -387,11 +395,10 @@ bool HasTransportCc(const Codec& codec) { FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); } -const VideoCodec* FindMatchingCodec( - const std::vector& supported_codecs, - const VideoCodec& codec) { +const Codec* FindMatchingVideoCodec(const std::vector& supported_codecs, + const Codec& codec) { webrtc::SdpVideoFormat sdp_video_format{codec.name, codec.params}; - for (const VideoCodec& supported_codec : supported_codecs) { + for (const Codec& supported_codec : supported_codecs) { if (sdp_video_format.IsSameCodec( {supported_codec.name, supported_codec.params})) { return &supported_codec; @@ -400,6 +407,19 @@ const VideoCodec* FindMatchingCodec( return nullptr; } +std::vector FindAllMatchingCodecs( + const std::vector& supported_codecs, + const Codec& codec) { + std::vector result; + webrtc::SdpVideoFormat sdp(codec.name, codec.params); + for (const Codec& supported_codec : supported_codecs) { + if (sdp.IsSameCodec({supported_codec.name, supported_codec.params})) { + result.push_back(&supported_codec); + } + } + return result; +} + // If a decoder supports any H264 profile, it is implicitly assumed to also // support constrained base line even though it's not explicitly listed. void AddH264ConstrainedBaselineProfileToSupportedFormats( diff --git a/media/base/codec.h b/media/base/codec.h index 5595708cfa..228acad07a 100644 --- a/media/base/codec.h +++ b/media/base/codec.h @@ -28,7 +28,7 @@ namespace cricket { -typedef std::map CodecParameterMap; +using CodecParameterMap = std::map; class FeedbackParam { public: @@ -187,6 +187,9 @@ struct RTC_EXPORT Codec { using VideoCodec = Codec; using AudioCodec = Codec; +using VideoCodecs = std::vector; +using AudioCodecs = std::vector; + Codec CreateAudioCodec(int id, const std::string& name, int clockrate, @@ -200,25 +203,23 @@ Codec CreateVideoRtxCodec(int rtx_payload_type, int associated_payload_type); // Get the codec setting associated with `payload_type`. If there // is no codec associated with that payload type it returns nullptr. -template -const Codec* FindCodecById(const std::vector& codecs, int payload_type) { - for (const auto& codec : codecs) { - if (codec.id == payload_type) - return &codec; - } - return nullptr; -} +const Codec* FindCodecById(const std::vector& codecs, int payload_type); bool HasLntf(const Codec& codec); bool HasNack(const Codec& codec); bool HasRemb(const Codec& codec); bool HasRrtr(const Codec& codec); bool HasTransportCc(const Codec& codec); + // Returns the first codec in `supported_codecs` that matches `codec`, or // nullptr if no codec matches. -const VideoCodec* FindMatchingCodec( - const std::vector& supported_codecs, - const VideoCodec& codec); +const Codec* FindMatchingVideoCodec(const std::vector& supported_codecs, + const Codec& codec); + +// Returns all codecs in `supported_codecs` that matches `codec`. +std::vector FindAllMatchingCodecs( + const std::vector& supported_codecs, + const Codec& codec); RTC_EXPORT void AddH264ConstrainedBaselineProfileToSupportedFormats( std::vector* supported_formats); diff --git a/media/base/fake_media_engine.h b/media/base/fake_media_engine.h index 51828c3535..eddc76057d 100644 --- a/media/base/fake_media_engine.h +++ b/media/base/fake_media_engine.h @@ -741,7 +741,6 @@ class FakeVideoMediaSendChannel void SetSsrcListChangedCallback( absl::AnyInvocable&)> callback) override {} - void SetVideoCodecSwitchingEnabled(bool enabled) override {} bool SendCodecHasLntf() const override { return false; } bool SendCodecHasNack() const override { return false; } absl::optional SendCodecRtxTime() const override { diff --git a/media/base/media_channel.h b/media/base/media_channel.h index 7355976aba..f90ad9ef60 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -972,8 +972,6 @@ class VideoMediaSendChannelInterface : public MediaSendChannelInterface { // Cause generation of a keyframe for `ssrc` on a sending channel. virtual void GenerateSendKeyFrame(uint32_t ssrc, const std::vector& rids) = 0; - // Enable network condition based codec switching. - virtual void SetVideoCodecSwitchingEnabled(bool enabled) = 0; virtual bool GetStats(VideoMediaSendInfo* stats) = 0; // This fills the "bitrate parts" (rtx, video bitrate) of the // BandwidthEstimationInfo, since that part that isn't possible to get diff --git a/media/base/media_constants.cc b/media/base/media_constants.cc index 94ce3c7b21..2af0295a5a 100644 --- a/media/base/media_constants.cc +++ b/media/base/media_constants.cc @@ -127,6 +127,11 @@ const char kH265FmtpTxMode[] = "tx-mode"; const char kVP9ProfileId[] = "profile-id"; const int kDefaultVideoMaxFramerate = 60; +// Max encode quantizer for VP8/9 and AV1 encoders assuming libvpx/libaom API +// range [0, 63] +const int kDefaultVideoMaxQpVpx = 56; +// Max encode quantizer for H264/5 assuming the bitstream range [0, 51]. +const int kDefaultVideoMaxQpH26x = 51; const size_t kConferenceMaxNumSpatialLayers = 3; const size_t kConferenceMaxNumTemporalLayers = 3; diff --git a/media/base/media_constants.h b/media/base/media_constants.h index 3321aac41d..877cc7a296 100644 --- a/media/base/media_constants.h +++ b/media/base/media_constants.h @@ -150,6 +150,8 @@ RTC_EXPORT extern const char kH265FmtpTxMode[]; extern const char kVP9ProfileId[]; extern const int kDefaultVideoMaxFramerate; +extern const int kDefaultVideoMaxQpVpx; +extern const int kDefaultVideoMaxQpH26x; extern const size_t kConferenceMaxNumSpatialLayers; extern const size_t kConferenceMaxNumTemporalLayers; diff --git a/media/base/test_utils.h b/media/base/test_utils.h index fb18485d32..dc14e44046 100644 --- a/media/base/test_utils.h +++ b/media/base/test_utils.h @@ -35,20 +35,6 @@ inline std::vector MakeVector(const T a[], size_t s) { } #define MAKE_VECTOR(a) cricket::MakeVector(a, arraysize(a)) -// Checks whether `codecs` contains `codec`; checks using Codec::Matches(). -template -bool ContainsMatchingCodec(const std::vector& codecs, - const C& codec, - const webrtc::FieldTrialsView* field_trials) { - typename std::vector::const_iterator it; - for (it = codecs.begin(); it != codecs.end(); ++it) { - if (it->Matches(codec, field_trials)) { - return true; - } - } - return false; -} - // Create Simulcast StreamParams with given `ssrcs` and `cname`. cricket::StreamParams CreateSimStreamParams(const std::string& cname, const std::vector& ssrcs); diff --git a/media/engine/fake_webrtc_call.cc b/media/engine/fake_webrtc_call.cc index 846be4d7ae..16e7169b21 100644 --- a/media/engine/fake_webrtc_call.cc +++ b/media/engine/fake_webrtc_call.cc @@ -211,6 +211,16 @@ bool FakeVideoSendStream::GetH264Settings( return true; } +bool FakeVideoSendStream::GetAv1Settings( + webrtc::VideoCodecAV1* settings) const { + if (!codec_settings_set_) { + return false; + } + + *settings = codec_specific_settings_.av1; + return true; +} + int FakeVideoSendStream::GetNumberOfSwappedFrames() const { return num_swapped_frames_; } @@ -315,6 +325,9 @@ void FakeVideoSendStream::ReconfigureVideoEncoder( } else if (config_.rtp.payload_name == "H264") { codec_specific_settings_.h264.numberOfTemporalLayers = num_temporal_layers; + } else if (config_.rtp.payload_name == "AV1") { + config.encoder_specific_settings->FillVideoCodecAv1( + &codec_specific_settings_.av1); } else { ADD_FAILURE() << "Unsupported encoder payload: " << config_.rtp.payload_name; diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h index 8d9ecb6396..3dd6bdf397 100644 --- a/media/engine/fake_webrtc_call.h +++ b/media/engine/fake_webrtc_call.h @@ -169,6 +169,7 @@ class FakeVideoSendStream final bool GetVp8Settings(webrtc::VideoCodecVP8* settings) const; bool GetVp9Settings(webrtc::VideoCodecVP9* settings) const; bool GetH264Settings(webrtc::VideoCodecH264* settings) const; + bool GetAv1Settings(webrtc::VideoCodecAV1* settings) const; int GetNumberOfSwappedFrames() const; int GetLastWidth() const; @@ -226,6 +227,7 @@ class FakeVideoSendStream final webrtc::VideoCodecVP8 vp8; webrtc::VideoCodecVP9 vp9; webrtc::VideoCodecH264 h264; + webrtc::VideoCodecAV1 av1; } codec_specific_settings_; bool resolution_scaling_enabled_; bool framerate_scaling_enabled_; diff --git a/media/engine/fake_webrtc_video_engine.cc b/media/engine/fake_webrtc_video_engine.cc index adbaf6cce3..cf402478a0 100644 --- a/media/engine/fake_webrtc_video_engine.cc +++ b/media/engine/fake_webrtc_video_engine.cc @@ -281,11 +281,13 @@ void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodec( } void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodecType( - const std::string& name) { + const std::string& name, + const std::vector& scalability_modes) { // This is to match the default H264 params of cricket::VideoCodec. cricket::VideoCodec video_codec = cricket::CreateVideoCodec(name); - formats_.push_back( - webrtc::SdpVideoFormat(video_codec.name, video_codec.params)); + formats_.push_back(webrtc::SdpVideoFormat( + video_codec.name, video_codec.params, + {scalability_modes.begin(), scalability_modes.end()})); } int FakeWebRtcVideoEncoderFactory::GetNumCreatedEncoders() { diff --git a/media/engine/fake_webrtc_video_engine.h b/media/engine/fake_webrtc_video_engine.h index 87d107ac37..3db4225ced 100644 --- a/media/engine/fake_webrtc_video_engine.h +++ b/media/engine/fake_webrtc_video_engine.h @@ -124,7 +124,9 @@ class FakeWebRtcVideoEncoderFactory : public webrtc::VideoEncoderFactory { void EncoderDestroyed(FakeWebRtcVideoEncoder* encoder); void set_encoders_have_internal_sources(bool internal_source); void AddSupportedVideoCodec(const webrtc::SdpVideoFormat& format); - void AddSupportedVideoCodecType(const std::string& name); + void AddSupportedVideoCodecType( + const std::string& name, + const std::vector& scalability_modes = {}); int GetNumCreatedEncoders(); const std::vector encoders(); diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc index 7ee95b1a30..4853e68996 100644 --- a/media/engine/simulcast_encoder_adapter.cc +++ b/media/engine/simulcast_encoder_adapter.cc @@ -19,7 +19,9 @@ #include #include "absl/algorithm/container.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" +#include "api/transport/field_trial_based_config.h" #include "api/video/i420_buffer.h" #include "api/video/video_codec_constants.h" #include "api/video/video_frame_buffer.h" @@ -27,24 +29,23 @@ #include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder_factory.h" #include "api/video_codecs/video_encoder_software_fallback_wrapper.h" +#include "media/base/media_constants.h" #include "media/base/video_common.h" #include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/utility/simulcast_rate_allocator.h" #include "rtc_base/checks.h" #include "rtc_base/experiments/rate_control_settings.h" #include "rtc_base/logging.h" -#include "system_wrappers/include/field_trial.h" namespace { -const unsigned int kDefaultMinQp = 2; -const unsigned int kDefaultMaxQp = 56; // Max qp for lowest spatial resolution when doing simulcast. const unsigned int kLowestResMaxQp = 45; -absl::optional GetScreenshareBoostedQpValue() { +absl::optional GetScreenshareBoostedQpValue( + const webrtc::FieldTrialsView& field_trials) { std::string experiment_group = - webrtc::field_trial::FindFullName("WebRTC-BoostedScreenshareQp"); + field_trials.Lookup("WebRTC-BoostedScreenshareQp"); unsigned int qp; if (sscanf(experiment_group.c_str(), "%u", &qp) != 1) return absl::nullopt; @@ -244,12 +245,16 @@ void SimulcastEncoderAdapter::StreamContext::OnDroppedFrame( SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory, const SdpVideoFormat& format) - : SimulcastEncoderAdapter(factory, nullptr, format) {} + : SimulcastEncoderAdapter(factory, + nullptr, + format, + FieldTrialBasedConfig()) {} SimulcastEncoderAdapter::SimulcastEncoderAdapter( VideoEncoderFactory* primary_factory, VideoEncoderFactory* fallback_factory, - const SdpVideoFormat& format) + const SdpVideoFormat& format, + const FieldTrialsView& field_trials) : inited_(0), primary_encoder_factory_(primary_factory), fallback_encoder_factory_(fallback_factory), @@ -257,10 +262,12 @@ SimulcastEncoderAdapter::SimulcastEncoderAdapter( total_streams_count_(0), bypass_mode_(false), encoded_complete_callback_(nullptr), - experimental_boosted_screenshare_qp_(GetScreenshareBoostedQpValue()), - boost_base_layer_quality_(RateControlSettings::ParseFromFieldTrials() - .Vp8BoostBaseLayerQuality()), - prefer_temporal_support_on_base_layer_(field_trial::IsEnabled( + experimental_boosted_screenshare_qp_( + GetScreenshareBoostedQpValue(field_trials)), + boost_base_layer_quality_( + RateControlSettings::ParseFromKeyValueConfig(&field_trials) + .Vp8BoostBaseLayerQuality()), + prefer_temporal_support_on_base_layer_(field_trials.IsEnabled( "WebRTC-Video-PreferTemporalSupportOnBaseLayer")) { RTC_DCHECK(primary_factory); @@ -319,11 +326,6 @@ int SimulcastEncoderAdapter::InitEncode( codec_ = *codec_settings; total_streams_count_ = CountAllStreams(*codec_settings); - // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder. - if (codec_.qpMax < kDefaultMinQp) { - codec_.qpMax = kDefaultMaxQp; - } - bool is_legacy_singlecast = codec_.numberOfSimulcastStreams == 0; int lowest_quality_stream_idx = 0; int highest_quality_stream_idx = 0; diff --git a/media/engine/simulcast_encoder_adapter.h b/media/engine/simulcast_encoder_adapter.h index ef8205e91a..553a6a0819 100644 --- a/media/engine/simulcast_encoder_adapter.h +++ b/media/engine/simulcast_encoder_adapter.h @@ -22,6 +22,7 @@ #include "absl/types/optional.h" #include "api/fec_controller_override.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/video_encoder.h" @@ -48,7 +49,8 @@ class RTC_EXPORT SimulcastEncoderAdapter : public VideoEncoder { // will be used if InitEncode() fails for the primary encoder. SimulcastEncoderAdapter(VideoEncoderFactory* primary_factory, VideoEncoderFactory* fallback_factory, - const SdpVideoFormat& format); + const SdpVideoFormat& format, + const FieldTrialsView& field_trials); ~SimulcastEncoderAdapter() override; // Implements VideoEncoder. diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc index 7d86dcc4f9..e2ac5ea390 100644 --- a/media/engine/simulcast_encoder_adapter_unittest.cc +++ b/media/engine/simulcast_encoder_adapter_unittest.cc @@ -14,6 +14,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/test/create_simulcast_test_fixture.h" #include "api/test/simulcast_test_fixture.h" #include "api/test/video/function_video_decoder_factory.h" @@ -29,9 +30,9 @@ #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/utility/simulcast_test_fixture_impl.h" #include "rtc_base/checks.h" -#include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" using ::testing::_; using ::testing::Return; @@ -402,17 +403,20 @@ class TestSimulcastEncoderAdapterFakeHelper { public: explicit TestSimulcastEncoderAdapterFakeHelper( bool use_fallback_factory, - const SdpVideoFormat& video_format) + const SdpVideoFormat& video_format, + const FieldTrialsView& field_trials) : primary_factory_(new MockVideoEncoderFactory()), fallback_factory_(use_fallback_factory ? new MockVideoEncoderFactory() : nullptr), - video_format_(video_format) {} + video_format_(video_format), + field_trials_(field_trials) {} // Can only be called once as the SimulcastEncoderAdapter will take the // ownership of `factory_`. VideoEncoder* CreateMockEncoderAdapter() { return new SimulcastEncoderAdapter(primary_factory_.get(), - fallback_factory_.get(), video_format_); + fallback_factory_.get(), video_format_, + field_trials_); } MockVideoEncoderFactory* factory() { return primary_factory_.get(); } @@ -424,6 +428,7 @@ class TestSimulcastEncoderAdapterFakeHelper { std::unique_ptr primary_factory_; std::unique_ptr fallback_factory_; SdpVideoFormat video_format_; + const FieldTrialsView& field_trials_; }; static const int kTestTemporalLayerProfile[3] = {3, 2, 1}; @@ -441,7 +446,8 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, void SetUp() override { helper_.reset(new TestSimulcastEncoderAdapterFakeHelper( - use_fallback_factory_, SdpVideoFormat("VP8", sdp_video_parameters_))); + use_fallback_factory_, SdpVideoFormat("VP8", sdp_video_parameters_), + field_trials_)); adapter_.reset(helper_->CreateMockEncoderAdapter()); last_encoded_image_width_ = absl::nullopt; last_encoded_image_height_ = absl::nullopt; @@ -464,7 +470,7 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, last_encoded_image_height_ = encoded_image._encodedHeight; last_encoded_image_simulcast_index_ = encoded_image.SimulcastIndex(); - return Result(Result::OK, encoded_image.Timestamp()); + return Result(Result::OK, encoded_image.RtpTimestamp()); } bool GetLastEncodedImageInfo(absl::optional* out_width, @@ -581,6 +587,7 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, std::unique_ptr rate_allocator_; bool use_fallback_factory_; SdpVideoFormat::Parameters sdp_video_parameters_; + test::ScopedKeyValueConfig field_trials_; }; TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) { @@ -1435,12 +1442,14 @@ TEST_F(TestSimulcastEncoderAdapterFake, TEST_F( TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrialDoesNotOverrideExistingBitrateLimitsInSinglecast) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" "frame_size_pixels:123|456|789," "min_start_bitrate_bps:11000|22000|33000," "min_bitrate_bps:44000|55000|66000," "max_bitrate_bps:77000|88000|99000/"); + SetUp(); std::vector bitrate_limits; bitrate_limits.push_back( @@ -1463,7 +1472,8 @@ TEST_F( } TEST_F(TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrial) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" "requested_resolution_alignment:8," "apply_alignment_to_all_simulcast_layers/"); @@ -1483,7 +1493,8 @@ TEST_F(TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrial) { TEST_F(TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrialForSingleStream) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" "requested_resolution_alignment:9," "frame_size_pixels:123|456|789," @@ -1798,8 +1809,8 @@ TEST_F(TestSimulcastEncoderAdapterFake, // Normally SEA reuses encoders. But, when TL-based SW fallback is enabled, // the encoder which served the lowest stream should be recreated before it // can be used to process an upper layer and vice-versa. - test::ScopedFieldTrials field_trials( - "WebRTC-Video-PreferTemporalSupportOnBaseLayer/Enabled/"); + test::ScopedKeyValueConfig field_trials( + field_trials_, "WebRTC-Video-PreferTemporalSupportOnBaseLayer/Enabled/"); use_fallback_factory_ = true; ReSetUp(); diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 14e1b4869b..264850bbc8 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -29,6 +29,7 @@ #include "api/media_stream_interface.h" #include "api/media_types.h" #include "api/priority.h" +#include "api/rtc_error.h" #include "api/rtp_transceiver_direction.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -47,6 +48,7 @@ #include "common_video/frame_counts.h" #include "common_video/include/quality_limitation_reason.h" #include "media/base/codec.h" +#include "media/base/media_channel.h" #include "media/base/media_constants.h" #include "media/base/rid_description.h" #include "media/base/rtp_utils.h" @@ -357,8 +359,11 @@ static bool ValidateStreamParams(const StreamParams& sp) { } } for (const auto& group : sp.ssrc_groups) { - if (group.semantics != kSimSsrcGroupSemantics) + if (!(group.semantics == kFidSsrcGroupSemantics || + group.semantics == kSimSsrcGroupSemantics || + group.semantics == kFecFrSsrcGroupSemantics)) { continue; + } for (uint32_t group_ssrc : group.ssrcs) { auto it = absl::c_find_if(sp.ssrcs, [&group_ssrc](uint32_t ssrc) { return ssrc == group_ssrc; @@ -366,7 +371,7 @@ static bool ValidateStreamParams(const StreamParams& sp) { if (it == sp.ssrcs.end()) { RTC_LOG(LS_ERROR) << "SSRC '" << group_ssrc << "' missing from StreamParams ssrcs with semantics " - << kSimSsrcGroupSemantics << ": " << sp.ToString(); + << group.semantics << ": " << sp.ToString(); return false; } } @@ -741,6 +746,19 @@ void ExtractCodecInformation( } } +int ParseReceiveBufferSize(const webrtc::FieldTrialsView& trials) { + webrtc::FieldTrialParameter size_bytes("size_bytes", + kVideoRtpRecvBufferSize); + webrtc::ParseFieldTrial({&size_bytes}, + trials.Lookup("WebRTC-ReceiveBufferSize")); + if (size_bytes.Get() < 10'000 || size_bytes.Get() > 10'000'000) { + RTC_LOG(LS_WARNING) << "WebRTC-ReceiveBufferSize out of bounds: " + << size_bytes.Get(); + return kVideoRtpRecvBufferSize; + } + return size_bytes.Get(); +} + } // namespace // --------------- WebRtcVideoEngine --------------------------- @@ -968,6 +986,15 @@ WebRtcVideoSendChannel::WebRtcVideoSendStream::ConfigureVideoEncoderSettings( return rtc::make_ref_counted< webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings); } + if (absl::EqualsIgnoreCase(codec.name, kAv1CodecName)) { + webrtc::VideoCodecAV1 av1_settings = {.automatic_resize_on = + automatic_resize}; + if (NumSpatialLayersFromEncoding(rtp_parameters_, /*idx=*/0) > 1) { + av1_settings.automatic_resize_on = false; + } + return rtc::make_ref_counted< + webrtc::VideoEncoderConfig::Av1EncoderSpecificSettings>(av1_settings); + } return nullptr; } std::vector WebRtcVideoSendChannel::SelectSendVideoCodecs( @@ -1329,17 +1356,24 @@ webrtc::RTCError WebRtcVideoSendChannel::SetRtpSendParameters( break; } + // Since we validate that all layers have the same value, we can just check + // the first layer. // TODO(orphis): Support mixed-codec simulcast if (parameters.encodings[0].codec && send_codec_ && !send_codec_->codec.MatchesRtpCodec(*parameters.encodings[0].codec)) { - RTC_LOG(LS_ERROR) << "Trying to change codec to " - << parameters.encodings[0].codec->name; + RTC_LOG(LS_VERBOSE) << "Trying to change codec to " + << parameters.encodings[0].codec->name; auto matched_codec = absl::c_find_if(negotiated_codecs_, [&](auto negotiated_codec) { return negotiated_codec.codec.MatchesRtpCodec( *parameters.encodings[0].codec); }); - RTC_CHECK(matched_codec != negotiated_codecs_.end()); + if (matched_codec == negotiated_codecs_.end()) { + return webrtc::InvokeSetParametersCallback( + callback, webrtc::RTCError( + webrtc::RTCErrorType::INVALID_MODIFICATION, + "Attempted to use an unsupported codec for layer 0")); + } ChangedSenderParameters params; params.send_codec = *matched_codec; @@ -1645,14 +1679,6 @@ void WebRtcVideoSendChannel::SetEncoderSelector( } } -void WebRtcVideoSendChannel::SetVideoCodecSwitchingEnabled(bool enabled) { - RTC_DCHECK_RUN_ON(&thread_checker_); - allow_codec_switching_ = enabled; - if (allow_codec_switching_) { - RTC_LOG(LS_INFO) << "Encoder switching enabled."; - } -} - WebRtcVideoSendChannel::WebRtcVideoSendStream::VideoSendStreamParameters:: VideoSendStreamParameters( webrtc::VideoSendStream::Config config, @@ -2207,7 +2233,20 @@ WebRtcVideoSendChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig( // Ensure frame dropping is always enabled. encoder_config.frame_drop_enabled = true; - int max_qp = kDefaultQpMax; + int max_qp; + switch (encoder_config.codec_type) { + case webrtc::kVideoCodecH264: + case webrtc::kVideoCodecH265: + max_qp = kDefaultVideoMaxQpH26x; + break; + case webrtc::kVideoCodecVP8: + case webrtc::kVideoCodecVP9: + case webrtc::kVideoCodecAV1: + case webrtc::kVideoCodecGeneric: + case webrtc::kVideoCodecMultiplex: + max_qp = kDefaultVideoMaxQpVpx; + break; + } codec.GetParam(kCodecParamMaxQuantization, &max_qp); encoder_config.max_qp = max_qp; @@ -2569,7 +2608,8 @@ WebRtcVideoReceiveChannel::WebRtcVideoReceiveChannel( discard_unknown_ssrc_packets_( IsEnabled(call_->trials(), "WebRTC-Video-DiscardPacketsWithUnknownSsrc")), - crypto_options_(crypto_options) { + crypto_options_(crypto_options), + receive_buffer_size_(ParseReceiveBufferSize(call_->trials())) { RTC_DCHECK_RUN_ON(&thread_checker_); rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc; recv_codecs_ = MapCodecs(GetPayloadTypesAndDefaultCodecs( @@ -2675,7 +2715,7 @@ bool WebRtcVideoReceiveChannel::GetChangedReceiverParameters( /*is_decoder_factory=*/true, /*include_rtx=*/true, call_->trials()); for (const VideoCodecSettings& mapped_codec : mapped_codecs) { - if (!FindMatchingCodec(local_supported_codecs, mapped_codec.codec)) { + if (!FindMatchingVideoCodec(local_supported_codecs, mapped_codec.codec)) { RTC_LOG(LS_ERROR) << "GetChangedReceiverParameters called with " "unsupported video codec: " << mapped_codec.codec.ToString(); @@ -3167,7 +3207,7 @@ void WebRtcVideoReceiveChannel::SetInterface( MediaChannelUtil::SetInterface(iface); // Set the RTP recv/send buffer to a bigger size. MediaChannelUtil::SetOption(MediaChannelNetworkInterface::ST_RTP, - rtc::Socket::OPT_RCVBUF, kVideoRtpRecvBufferSize); + rtc::Socket::OPT_RCVBUF, receive_buffer_size_); } void WebRtcVideoReceiveChannel::SetFrameDecryptor( diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index 11f1b99ac2..e4b1b2765b 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -225,8 +225,6 @@ class WebRtcVideoSendChannel : public MediaChannelUtil, webrtc::VideoEncoderFactory::EncoderSelectorInterface* encoder_selector) override; - void SetVideoCodecSwitchingEnabled(bool enabled) override; - void SetSendCodecChangedCallback( absl::AnyInvocable callback) override { send_codec_changed_callback_ = std::move(callback); @@ -252,6 +250,8 @@ class WebRtcVideoSendChannel : public MediaChannelUtil, ADAPTREASON_BANDWIDTH = 2, }; + // TODO(webrtc:14852): Update downstream projects to use + // cricket::kDefaultVideoMaxQpVpx/H26x and remove. static constexpr int kDefaultQpMax = 56; // Implements webrtc::EncoderSwitchRequestCallback. @@ -549,11 +549,6 @@ class WebRtcVideoSendChannel : public MediaChannelUtil, rtc::scoped_refptr unsignaled_frame_transformer_ RTC_GUARDED_BY(thread_checker_); - // TODO(bugs.webrtc.org/11341): Remove this and relevant PC API. Presence - // of multiple negotiated codecs allows generic encoder fallback on failures. - // Presence of EncoderSelector allows switching to specific encoders. - bool allow_codec_switching_ = false; - // RTP parameters that need to be set when creating a video receive stream. // Only used in Receiver mode - in Both mode, it reads those things from the // codec. @@ -891,6 +886,8 @@ class WebRtcVideoReceiveChannel : public MediaChannelUtil, // Callback invoked whenever the list of SSRCs changes. absl::AnyInvocable&)> ssrc_list_changed_callback_; + + const int receive_buffer_size_; }; // Keeping the old name "WebRtcVideoChannel" around because some external diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index 4262aa03db..e8b7ee4b2d 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -19,7 +19,6 @@ #include #include "absl/algorithm/container.h" -#include "absl/memory/memory.h" #include "absl/strings/match.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/rtp_parameters.h" @@ -38,6 +37,7 @@ #include "api/video/video_bitrate_allocation.h" #include "api/video_codecs/h264_profile_level_id.h" #include "api/video_codecs/sdp_video_format.h" +#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_decoder_factory_template.h" #include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h" @@ -99,6 +99,8 @@ using ::testing::StrNe; using ::testing::Values; using ::testing::WithArg; using ::webrtc::BitrateConstraints; +using ::webrtc::Call; +using ::webrtc::CallConfig; using ::webrtc::kDefaultScalabilityModeStr; using ::webrtc::RtpExtension; using ::webrtc::RtpPacket; @@ -109,7 +111,6 @@ using ::webrtc::Timestamp; using ::webrtc::test::RtcpPacketParser; namespace { -static const int kDefaultQpMax = 56; static const uint8_t kRedRtxPayloadType = 125; @@ -355,8 +356,8 @@ class WebRtcVideoEngineTest : public ::testing::Test { : field_trials_(field_trials), time_controller_(webrtc::Timestamp::Millis(4711)), task_queue_factory_(time_controller_.CreateTaskQueueFactory()), - call_(webrtc::Call::Create([&] { - webrtc::Call::Config call_config(&event_log_); + call_(Call::Create([&] { + CallConfig call_config(&event_log_); call_config.task_queue_factory = task_queue_factory_.get(); call_config.trials = &field_trials_; return call_config; @@ -382,7 +383,9 @@ class WebRtcVideoEngineTest : public ::testing::Test { // Find the codec in the engine with the given name. The codec must be // present. cricket::VideoCodec GetEngineCodec(const std::string& name) const; - void AddSupportedVideoCodecType(const std::string& name); + void AddSupportedVideoCodecType( + const std::string& name, + const std::vector& scalability_modes = {}); std::unique_ptr SetSendParamsWithAllSupportedCodecs(); @@ -399,7 +402,7 @@ class WebRtcVideoEngineTest : public ::testing::Test { std::unique_ptr task_queue_factory_; // Used in WebRtcVideoEngineVoiceTest, but defined here so it's properly // initialized when the constructor is called. - std::unique_ptr call_; + std::unique_ptr call_; cricket::FakeWebRtcVideoEncoderFactory* encoder_factory_; cricket::FakeWebRtcVideoDecoderFactory* decoder_factory_; std::unique_ptr @@ -720,16 +723,17 @@ TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) { // Now search for RTX codecs for them. Expect that they all have associated // RTX codecs. EXPECT_TRUE(HasRtxCodec( - codecs, FindMatchingCodec( + codecs, FindMatchingVideoCodec( codecs, cricket::CreateVideoCodec(h264_constrained_baseline)) ->id)); EXPECT_TRUE(HasRtxCodec( - codecs, FindMatchingCodec( + codecs, FindMatchingVideoCodec( codecs, cricket::CreateVideoCodec(h264_constrained_high)) ->id)); EXPECT_TRUE(HasRtxCodec( codecs, - FindMatchingCodec(codecs, cricket::CreateVideoCodec(h264_high))->id)); + FindMatchingVideoCodec(codecs, cricket::CreateVideoCodec(h264_high)) + ->id)); } #if defined(RTC_ENABLE_VP9) @@ -855,8 +859,9 @@ cricket::VideoCodec WebRtcVideoEngineTest::GetEngineCodec( } void WebRtcVideoEngineTest::AddSupportedVideoCodecType( - const std::string& name) { - encoder_factory_->AddSupportedVideoCodecType(name); + const std::string& name, + const std::vector& scalability_modes) { + encoder_factory_->AddSupportedVideoCodecType(name, scalability_modes); decoder_factory_->AddSupportedVideoCodecType(name); } @@ -972,6 +977,45 @@ TEST_F(WebRtcVideoEngineTest, SendsFeedbackAfterUnsignaledRtxPacket) { receive_channel->SetInterface(nullptr); } +TEST_F(WebRtcVideoEngineTest, ReceiveBufferSizeViaFieldTrial) { + webrtc::test::ScopedKeyValueConfig override_field_trials( + field_trials_, "WebRTC-ReceiveBufferSize/size_bytes:10000/"); + std::unique_ptr receive_channel = + engine_.CreateReceiveChannel(call_.get(), GetMediaConfig(), + VideoOptions(), webrtc::CryptoOptions()); + cricket::FakeNetworkInterface network; + receive_channel->SetInterface(&network); + EXPECT_EQ(10000, network.recvbuf_size()); + receive_channel->SetInterface(nullptr); +} + +TEST_F(WebRtcVideoEngineTest, TooLowReceiveBufferSizeViaFieldTrial) { + // 10000001 is too high, it will revert to the default + // kVideoRtpRecvBufferSize. + webrtc::test::ScopedKeyValueConfig override_field_trials( + field_trials_, "WebRTC-ReceiveBufferSize/size_bytes:10000001/"); + std::unique_ptr receive_channel = + engine_.CreateReceiveChannel(call_.get(), GetMediaConfig(), + VideoOptions(), webrtc::CryptoOptions()); + cricket::FakeNetworkInterface network; + receive_channel->SetInterface(&network); + EXPECT_EQ(kVideoRtpRecvBufferSize, network.recvbuf_size()); + receive_channel->SetInterface(nullptr); +} + +TEST_F(WebRtcVideoEngineTest, TooHighReceiveBufferSizeViaFieldTrial) { + // 9999 is too low, it will revert to the default kVideoRtpRecvBufferSize. + webrtc::test::ScopedKeyValueConfig override_field_trials( + field_trials_, "WebRTC-ReceiveBufferSize/size_bytes:9999/"); + std::unique_ptr receive_channel = + engine_.CreateReceiveChannel(call_.get(), GetMediaConfig(), + VideoOptions(), webrtc::CryptoOptions()); + cricket::FakeNetworkInterface network; + receive_channel->SetInterface(&network); + EXPECT_EQ(kVideoRtpRecvBufferSize, network.recvbuf_size()); + receive_channel->SetInterface(nullptr); +} + TEST_F(WebRtcVideoEngineTest, UpdatesUnsignaledRtxSsrcAndRecoversPayload) { // Setup a channel with VP8, RTX and transport sequence number header // extension. Receive stream is not explicitly configured. @@ -1439,11 +1483,11 @@ TEST(WebRtcVideoEngineNewVideoCodecFactoryTest, Vp8) { webrtc::GlobalSimulatedTimeController time_controller( webrtc::Timestamp::Millis(4711)); auto task_queue_factory = time_controller.CreateTaskQueueFactory(); - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); webrtc::FieldTrialBasedConfig field_trials; call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); - const auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + const std::unique_ptr call = Call::Create(call_config); // Create send channel. const int send_ssrc = 123; @@ -1571,10 +1615,9 @@ TEST_F(WebRtcVideoEngineTest, SetVideoRtxEnabled) { class WebRtcVideoChannelEncodedFrameCallbackTest : public ::testing::Test { protected: - webrtc::Call::Config GetCallConfig( - webrtc::RtcEventLogNull* event_log, - webrtc::TaskQueueFactory* task_queue_factory) { - webrtc::Call::Config call_config(event_log); + CallConfig GetCallConfig(webrtc::RtcEventLogNull* event_log, + webrtc::TaskQueueFactory* task_queue_factory) { + CallConfig call_config(event_log); call_config.task_queue_factory = task_queue_factory; call_config.trials = &field_trials_; return call_config; @@ -1582,8 +1625,8 @@ class WebRtcVideoChannelEncodedFrameCallbackTest : public ::testing::Test { WebRtcVideoChannelEncodedFrameCallbackTest() : task_queue_factory_(time_controller_.CreateTaskQueueFactory()), - call_(absl::WrapUnique(webrtc::Call::Create( - GetCallConfig(&event_log_, task_queue_factory_.get())))), + call_(Call::Create( + GetCallConfig(&event_log_, task_queue_factory_.get()))), video_bitrate_allocator_factory_( webrtc::CreateBuiltinVideoBitrateAllocatorFactory()), engine_( @@ -1635,7 +1678,7 @@ class WebRtcVideoChannelEncodedFrameCallbackTest : public ::testing::Test { webrtc::test::ScopedKeyValueConfig field_trials_; webrtc::RtcEventLogNull event_log_; std::unique_ptr task_queue_factory_; - std::unique_ptr call_; + std::unique_ptr call_; std::unique_ptr video_bitrate_allocator_factory_; WebRtcVideoEngine engine_; @@ -1771,10 +1814,10 @@ class WebRtcVideoChannelBaseTest : public ::testing::Test { void SetUp() override { // One testcase calls SetUp in a loop, only create call_ once. if (!call_) { - webrtc::Call::Config call_config(&event_log_); + CallConfig call_config(&event_log_); call_config.task_queue_factory = task_queue_factory_.get(); call_config.trials = &field_trials_; - call_.reset(webrtc::Call::Create(call_config)); + call_ = Call::Create(call_config); } cricket::MediaConfig media_config; @@ -1977,7 +2020,7 @@ class WebRtcVideoChannelBaseTest : public ::testing::Test { webrtc::test::ScopedKeyValueConfig field_trials_; std::unique_ptr override_field_trials_; std::unique_ptr task_queue_factory_; - std::unique_ptr call_; + std::unique_ptr call_; std::unique_ptr video_bitrate_allocator_factory_; WebRtcVideoEngine engine_; @@ -2617,7 +2660,6 @@ TEST_F(WebRtcVideoChannelBaseTest, SendCodecIsMovedToFrontInRtpParameters) { parameters.codecs.push_back(GetEngineCodec("VP9")); parameters.codecs.push_back(GetEngineCodec("VP8")); EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); - send_channel_->SetVideoCodecSwitchingEnabled(true); auto send_codecs = send_channel_->GetRtpSendParameters(kSsrc).codecs; ASSERT_EQ(send_codecs.size(), 2u); @@ -2645,6 +2687,8 @@ class WebRtcVideoChannelTest : public WebRtcVideoEngineTest { void SetUp() override { AddSupportedVideoCodecType("VP8"); AddSupportedVideoCodecType("VP9"); + AddSupportedVideoCodecType( + "AV1", {ScalabilityMode::kL1T3, ScalabilityMode::kL2T3}); #if defined(WEBRTC_USE_H264) AddSupportedVideoCodecType("H264"); #endif @@ -3664,6 +3708,42 @@ TEST_F(WebRtcVideoChannelTest, VerifyVp8SpecificSettings) { EXPECT_TRUE(send_channel_->SetVideoSend(last_ssrc_, nullptr, nullptr)); } +TEST_F(WebRtcVideoChannelTest, VerifyAv1SpecificSettings) { + cricket::VideoSenderParameters parameters; + parameters.codecs.push_back(GetEngineCodec("AV1")); + ASSERT_TRUE(send_channel_->SetSenderParameters(parameters)); + webrtc::test::FrameForwarder frame_forwarder; + webrtc::VideoCodecAV1 settings; + + // Single-stream settings should apply with RTX as well (verifies that we + // check number of regular SSRCs and not StreamParams::ssrcs which contains + // both RTX and regular SSRCs). + FakeVideoSendStream* stream = SetUpSimulcast(false, /*with_rtx=*/true); + EXPECT_TRUE( + send_channel_->SetVideoSend(last_ssrc_, nullptr, &frame_forwarder)); + send_channel_->SetSend(true); + frame_forwarder.IncomingCapturedFrame(frame_source_.GetFrame()); + + ASSERT_TRUE(stream->GetAv1Settings(&settings)) << "No AV1 config set."; + EXPECT_TRUE(settings.automatic_resize_on); + + webrtc::RtpParameters rtp_parameters = + send_channel_->GetRtpSendParameters(last_ssrc_); + EXPECT_THAT( + rtp_parameters.encodings, + ElementsAre(Field(&webrtc::RtpEncodingParameters::scalability_mode, + absl::nullopt))); + rtp_parameters.encodings[0].scalability_mode = "L2T3"; + EXPECT_TRUE( + send_channel_->SetRtpSendParameters(last_ssrc_, rtp_parameters).ok()); + frame_forwarder.IncomingCapturedFrame(frame_source_.GetFrame()); + + ASSERT_TRUE(stream->GetAv1Settings(&settings)) << "No AV1 config set."; + EXPECT_FALSE(settings.automatic_resize_on); + + EXPECT_TRUE(send_channel_->SetVideoSend(last_ssrc_, nullptr, nullptr)); +} + // Test that setting the same options doesn't result in the encoder being // reconfigured. TEST_F(WebRtcVideoChannelTest, SetIdenticalOptionsDoesntReconfigureEncoder) { @@ -4786,7 +4866,7 @@ TEST_F(WebRtcVideoChannelFlexfecSendRecvTest, TEST_F(WebRtcVideoChannelTest, SetSendCodecsChangesExistingStreams) { cricket::VideoSenderParameters parameters; cricket::VideoCodec codec = cricket::CreateVideoCodec(100, "VP8"); - codec.SetParam(kCodecParamMaxQuantization, kDefaultQpMax); + codec.SetParam(kCodecParamMaxQuantization, kDefaultVideoMaxQpVpx); parameters.codecs.push_back(codec); ASSERT_TRUE(send_channel_->SetSenderParameters(parameters)); @@ -4798,14 +4878,14 @@ TEST_F(WebRtcVideoChannelTest, SetSendCodecsChangesExistingStreams) { send_channel_->SetVideoSend(last_ssrc_, nullptr, &frame_forwarder)); std::vector streams = stream->GetVideoStreams(); - EXPECT_EQ(kDefaultQpMax, streams[0].max_qp); + EXPECT_EQ(kDefaultVideoMaxQpVpx, streams[0].max_qp); parameters.codecs.clear(); - codec.SetParam(kCodecParamMaxQuantization, kDefaultQpMax + 1); + codec.SetParam(kCodecParamMaxQuantization, kDefaultVideoMaxQpVpx + 1); parameters.codecs.push_back(codec); ASSERT_TRUE(send_channel_->SetSenderParameters(parameters)); streams = fake_call_->GetVideoSendStreams()[0]->GetVideoStreams(); - EXPECT_EQ(kDefaultQpMax + 1, streams[0].max_qp); + EXPECT_EQ(kDefaultVideoMaxQpVpx + 1, streams[0].max_qp); EXPECT_TRUE(send_channel_->SetVideoSend(last_ssrc_, nullptr, nullptr)); } @@ -6735,7 +6815,7 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesReceivePacketStatsCorrectly) { TEST_F(WebRtcVideoChannelTest, TranslatesCallStatsCorrectly) { AddSendStream(); AddSendStream(); - webrtc::Call::Stats stats; + Call::Stats stats; stats.rtt_ms = 123; fake_call_->SetStats(stats); @@ -9692,8 +9772,9 @@ class WebRtcVideoChannelSimulcastTest : public ::testing::Test { if (num_configured_streams > 1 || conference_mode) { expected_streams = GetSimulcastConfig( /*min_layers=*/1, num_configured_streams, capture_width, - capture_height, webrtc::kDefaultBitratePriority, kDefaultQpMax, - screenshare && conference_mode, true, field_trials_); + capture_height, webrtc::kDefaultBitratePriority, + kDefaultVideoMaxQpVpx, screenshare && conference_mode, true, + field_trials_); if (screenshare && conference_mode) { for (const webrtc::VideoStream& stream : expected_streams) { // Never scale screen content. @@ -9709,7 +9790,7 @@ class WebRtcVideoChannelSimulcastTest : public ::testing::Test { stream.min_bitrate_bps = webrtc::kDefaultMinVideoBitrateBps; stream.target_bitrate_bps = stream.max_bitrate_bps = GetMaxDefaultBitrateBps(capture_width, capture_height); - stream.max_qp = kDefaultQpMax; + stream.max_qp = kDefaultVideoMaxQpVpx; expected_streams.push_back(stream); } diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc index 81fc31c69a..c83b7e144a 100644 --- a/media/engine/webrtc_voice_engine.cc +++ b/media/engine/webrtc_voice_engine.cc @@ -1130,9 +1130,10 @@ class WebRtcVoiceSendChannel::WebRtcAudioSendStream : public AudioSource::Sink { RTC_DCHECK_RUN_ON(&worker_thread_checker_); RTC_DCHECK(stream_); RTC_DCHECK_EQ(1UL, rtp_parameters_.encodings.size()); - if (send_ && source_ != nullptr && rtp_parameters_.encodings[0].active) { + // Stream can be started without |source_| being set. + if (send_ && rtp_parameters_.encodings[0].active) { stream_->Start(); - } else { // !send || source_ = nullptr + } else { stream_->Stop(); } } @@ -1900,17 +1901,25 @@ webrtc::RTCError WebRtcVoiceSendChannel::SetRtpSendParameters( SetPreferredDscp(new_dscp); absl::optional send_codec = GetSendCodec(); + // Since we validate that all layers have the same value, we can just check + // the first layer. // TODO(orphis): Support mixed-codec simulcast if (parameters.encodings[0].codec && send_codec && !send_codec->MatchesRtpCodec(*parameters.encodings[0].codec)) { - RTC_LOG(LS_ERROR) << "Trying to change codec to " + RTC_LOG(LS_VERBOSE) << "Trying to change codec to " << parameters.encodings[0].codec->name; auto matched_codec = absl::c_find_if(send_codecs_, [&](auto negotiated_codec) { return negotiated_codec.MatchesRtpCodec( *parameters.encodings[0].codec); }); - RTC_DCHECK(matched_codec != send_codecs_.end()); + + if (matched_codec == send_codecs_.end()) { + return webrtc::InvokeSetParametersCallback( + callback, webrtc::RTCError( + webrtc::RTCErrorType::INVALID_MODIFICATION, + "Attempted to use an unsupported codec for layer 0")); + } SetSendCodecs(send_codecs_, *matched_codec); } diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc index e303a53c36..55e0027fda 100644 --- a/media/engine/webrtc_voice_engine_unittest.cc +++ b/media/engine/webrtc_voice_engine_unittest.cc @@ -55,6 +55,8 @@ using ::testing::ReturnPointee; using ::testing::SaveArg; using ::testing::StrictMock; using ::testing::UnorderedElementsAreArray; +using ::webrtc::Call; +using ::webrtc::CallConfig; namespace { using webrtc::BitrateConstraints; @@ -2252,20 +2254,6 @@ TEST_P(WebRtcVoiceEngineTestFake, Send) { EXPECT_FALSE(GetSendStream(kSsrcX).IsSending()); } -// Test that a channel will send if and only if it has a source and is enabled -// for sending. -TEST_P(WebRtcVoiceEngineTestFake, SendStateWithAndWithoutSource) { - EXPECT_TRUE(SetupSendStream()); - SetSenderParameters(send_parameters_); - SetAudioSend(kSsrcX, true, nullptr); - SetSend(true); - EXPECT_FALSE(GetSendStream(kSsrcX).IsSending()); - SetAudioSend(kSsrcX, true, &fake_source_); - EXPECT_TRUE(GetSendStream(kSsrcX).IsSending()); - SetAudioSend(kSsrcX, true, nullptr); - EXPECT_FALSE(GetSendStream(kSsrcX).IsSending()); -} - // Test that a channel is muted/unmuted. TEST_P(WebRtcVoiceEngineTestFake, SendStateMuteUnmute) { EXPECT_TRUE(SetupSendStream()); @@ -3708,10 +3696,10 @@ TEST(WebRtcVoiceEngineTest, StartupShutdown) { nullptr, nullptr, field_trials); engine.Init(); webrtc::RtcEventLogNull event_log; - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); - auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + std::unique_ptr call = Call::Create(call_config); std::unique_ptr send_channel = engine.CreateSendChannel( call.get(), cricket::MediaConfig(), cricket::AudioOptions(), @@ -3744,10 +3732,10 @@ TEST(WebRtcVoiceEngineTest, StartupShutdownWithExternalADM) { nullptr, nullptr, field_trials); engine.Init(); webrtc::RtcEventLogNull event_log; - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); - auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + std::unique_ptr call = Call::Create(call_config); std::unique_ptr send_channel = engine.CreateSendChannel( call.get(), cricket::MediaConfig(), cricket::AudioOptions(), @@ -3834,10 +3822,10 @@ TEST(WebRtcVoiceEngineTest, Has32Channels) { nullptr, nullptr, field_trials); engine.Init(); webrtc::RtcEventLogNull event_log; - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); - auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + std::unique_ptr call = Call::Create(call_config); std::vector> channels; @@ -3880,10 +3868,10 @@ TEST(WebRtcVoiceEngineTest, SetRecvCodecs) { nullptr, field_trials); engine.Init(); webrtc::RtcEventLogNull event_log; - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); - auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + std::unique_ptr call = Call::Create(call_config); cricket::WebRtcVoiceReceiveChannel channel( &engine, cricket::MediaConfig(), cricket::AudioOptions(), webrtc::CryptoOptions(), call.get(), @@ -3909,7 +3897,7 @@ TEST(WebRtcVoiceEngineTest, SetRtpSendParametersMaxBitrate) { field_trials); engine.Init(); webrtc::RtcEventLogNull event_log; - webrtc::Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.trials = &field_trials; call_config.task_queue_factory = task_queue_factory.get(); { @@ -3919,7 +3907,7 @@ TEST(WebRtcVoiceEngineTest, SetRtpSendParametersMaxBitrate) { webrtc::test::MockAudioDeviceModule::CreateNice(); call_config.audio_state = webrtc::AudioState::Create(config); } - auto call = absl::WrapUnique(webrtc::Call::Create(call_config)); + std::unique_ptr call = Call::Create(call_config); cricket::WebRtcVoiceSendChannel channel( &engine, cricket::MediaConfig(), cricket::AudioOptions(), webrtc::CryptoOptions(), call.get(), webrtc::AudioCodecPairId::Create()); diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn index 85b56b7f1f..09a7ec9833 100644 --- a/modules/audio_coding/BUILD.gn +++ b/modules/audio_coding/BUILD.gn @@ -1122,10 +1122,11 @@ if (rtc_include_tests) { "../../rtc_base:macromagic", "../../rtc_base:timeutils", "../../system_wrappers", - "../../system_wrappers:field_trial", "../../test:fileutils", + "../../test:test_flags", "../../test:test_support", ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] } rtc_library("acm_receive_test") { diff --git a/modules/audio_coding/neteq/test/neteq_performance_unittest.cc b/modules/audio_coding/neteq/test/neteq_performance_unittest.cc index 961f74ab66..1b453cf7bf 100644 --- a/modules/audio_coding/neteq/test/neteq_performance_unittest.cc +++ b/modules/audio_coding/neteq/test/neteq_performance_unittest.cc @@ -8,11 +8,12 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "absl/flags/flag.h" #include "api/test/metrics/global_metrics_logger_and_exporter.h" #include "api/test/metrics/metric.h" #include "modules/audio_coding/neteq/tools/neteq_performance_test.h" -#include "system_wrappers/include/field_trial.h" #include "test/gtest.h" +#include "test/test_flags.h" namespace webrtc { namespace { @@ -29,8 +30,8 @@ TEST(NetEqPerformanceTest, 10_Pl_10_Drift) { const int kLossPeriod = 10; // Drop every 10th packet. const double kDriftFactor = 0.1; int64_t runtime = test::NetEqPerformanceTest::Run( - field_trial::IsEnabled("WebRTC-QuickPerfTest") ? kQuickSimulationTimeMs - : kSimulationTimeMs, + absl::GetFlag(FLAGS_webrtc_quick_perf_test) ? kQuickSimulationTimeMs + : kSimulationTimeMs, kLossPeriod, kDriftFactor); ASSERT_GT(runtime, 0); GetGlobalMetricsLogger()->LogSingleValueMetric( @@ -47,8 +48,8 @@ TEST(NetEqPerformanceTest, 0_Pl_0_Drift) { const int kLossPeriod = 0; // No losses. const double kDriftFactor = 0.0; // No clock drift. int64_t runtime = test::NetEqPerformanceTest::Run( - field_trial::IsEnabled("WebRTC-QuickPerfTest") ? kQuickSimulationTimeMs - : kSimulationTimeMs, + absl::GetFlag(FLAGS_webrtc_quick_perf_test) ? kQuickSimulationTimeMs + : kSimulationTimeMs, kLossPeriod, kDriftFactor); ASSERT_GT(runtime, 0); GetGlobalMetricsLogger()->LogSingleValueMetric( diff --git a/modules/audio_device/linux/audio_device_alsa_linux.cc b/modules/audio_device/linux/audio_device_alsa_linux.cc index eab73737c5..1e0ac8be28 100644 --- a/modules/audio_device/linux/audio_device_alsa_linux.cc +++ b/modules/audio_device/linux/audio_device_alsa_linux.cc @@ -588,7 +588,7 @@ int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(uint16_t index) { return -1; } - uint32_t nDevices = GetDevicesInfo(0, true); + int32_t nDevices = GetDevicesInfo(0, true); RTC_LOG(LS_VERBOSE) << "number of available audio output devices is " << nDevices; @@ -657,7 +657,7 @@ int32_t AudioDeviceLinuxALSA::SetRecordingDevice(uint16_t index) { return -1; } - uint32_t nDevices = GetDevicesInfo(0, false); + int32_t nDevices = GetDevicesInfo(0, false); RTC_LOG(LS_VERBOSE) << "number of availiable audio input devices is " << nDevices; diff --git a/modules/audio_mixer/audio_mixer_impl_unittest.cc b/modules/audio_mixer/audio_mixer_impl_unittest.cc index 641c966570..2044cb9b90 100644 --- a/modules/audio_mixer/audio_mixer_impl_unittest.cc +++ b/modules/audio_mixer/audio_mixer_impl_unittest.cc @@ -142,6 +142,7 @@ void MixMonoAtGivenNativeRate(int native_sample_rate, } TEST(AudioMixer, UpdatesSourceCountHistogram) { + metrics::Reset(); constexpr int kAudioSourcesGroup1 = 5; constexpr int kAudioSourcesGroup2 = 3; diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 64e83a006b..2b81427da9 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -371,10 +371,12 @@ if (rtc_include_tests) { "echo_control_mobile_unittest.cc", "gain_controller2_unittest.cc", "splitting_filter_unittest.cc", + "test/echo_canceller3_config_json_unittest.cc", "test/fake_recording_device_unittest.cc", ] deps = [ + ":aec3_config_json", ":analog_mic_simulation", ":api", ":apm_logging", @@ -558,6 +560,7 @@ if (rtc_include_tests) { ] deps = [ + ":aec3_config_json", ":analog_mic_simulation", ":api", ":apm_logging", @@ -566,7 +569,6 @@ if (rtc_include_tests) { ":audioproc_protobuf_utils", ":audioproc_test_utils", ":runtime_settings_protobuf_utils", - "../../api/audio:aec3_config_json", "../../api/audio:aec3_factory", "../../api/audio:echo_detector_creator", "../../common_audio", @@ -675,3 +677,21 @@ rtc_library("audioproc_test_utils") { "//third_party/abseil-cpp/absl/types:optional", ] } + +rtc_library("aec3_config_json") { + visibility = [ "*" ] + testonly = true + sources = [ + "test/echo_canceller3_config_json.cc", + "test/echo_canceller3_config_json.h", + ] + deps = [ + "../../api/audio:aec3_config", + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:rtc_json", + "../../rtc_base:stringutils", + "../../rtc_base/system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} diff --git a/modules/audio_processing/logging/apm_data_dumper.h b/modules/audio_processing/logging/apm_data_dumper.h index 4ab6baad83..76f8b34c0b 100644 --- a/modules/audio_processing/logging/apm_data_dumper.h +++ b/modules/audio_processing/logging/apm_data_dumper.h @@ -91,7 +91,7 @@ class ApmDataDumper { static void SetOutputDirectory(absl::string_view output_dir) { #if WEBRTC_APM_DEBUG_DUMP == 1 RTC_CHECK_LT(output_dir.size(), kOutputDirMaxLength); - rtc::strcpyn(output_dir_, output_dir.size(), output_dir); + rtc::strcpyn(output_dir_, kOutputDirMaxLength, output_dir); #endif } diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc index 7497d49fde..7bd6da0133 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -19,13 +19,13 @@ #include #include "absl/strings/string_view.h" -#include "api/audio/echo_canceller3_config_json.h" #include "api/audio/echo_canceller3_factory.h" #include "api/audio/echo_detector_creator.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/echo_control_mobile_impl.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/logging/apm_data_dumper.h" +#include "modules/audio_processing/test/echo_canceller3_config_json.h" #include "modules/audio_processing/test/fake_recording_device.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" diff --git a/api/audio/echo_canceller3_config_json.cc b/modules/audio_processing/test/echo_canceller3_config_json.cc similarity index 99% rename from api/audio/echo_canceller3_config_json.cc rename to modules/audio_processing/test/echo_canceller3_config_json.cc index 96e45ffe6d..d05e2841f0 100644 --- a/api/audio/echo_canceller3_config_json.cc +++ b/modules/audio_processing/test/echo_canceller3_config_json.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 "api/audio/echo_canceller3_config_json.h" +#include "modules/audio_processing/test/echo_canceller3_config_json.h" #include @@ -429,13 +429,6 @@ void Aec3ConfigFromJsonString(absl::string_view json_string, } } -EchoCanceller3Config Aec3ConfigFromJsonString(absl::string_view json_string) { - EchoCanceller3Config cfg; - bool not_used; - Aec3ConfigFromJsonString(json_string, &cfg, ¬_used); - return cfg; -} - std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) { rtc::StringBuilder ost; ost << "{"; diff --git a/api/audio/echo_canceller3_config_json.h b/modules/audio_processing/test/echo_canceller3_config_json.h similarity index 64% rename from api/audio/echo_canceller3_config_json.h rename to modules/audio_processing/test/echo_canceller3_config_json.h index ecee9541c7..6637c8fbfb 100644 --- a/api/audio/echo_canceller3_config_json.h +++ b/modules/audio_processing/test/echo_canceller3_config_json.h @@ -8,14 +8,13 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef API_AUDIO_ECHO_CANCELLER3_CONFIG_JSON_H_ -#define API_AUDIO_ECHO_CANCELLER3_CONFIG_JSON_H_ +#ifndef MODULES_AUDIO_PROCESSING_TEST_ECHO_CANCELLER3_CONFIG_JSON_H_ +#define MODULES_AUDIO_PROCESSING_TEST_ECHO_CANCELLER3_CONFIG_JSON_H_ #include #include "absl/strings/string_view.h" #include "api/audio/echo_canceller3_config.h" -#include "rtc_base/system/rtc_export.h" namespace webrtc { // Parses a JSON-encoded string into an Aec3 config. Fields corresponds to @@ -23,23 +22,15 @@ namespace webrtc { // "aec3". Produces default config values for anything that cannot be parsed // from the string. If any error was found in the parsing, parsing_successful is // set to false. -RTC_EXPORT void Aec3ConfigFromJsonString(absl::string_view json_string, +void Aec3ConfigFromJsonString(absl::string_view json_string, EchoCanceller3Config* config, bool* parsing_successful); -// To be deprecated. -// Parses a JSON-encoded string into an Aec3 config. Fields corresponds to -// substruct names, with the addition that there must be a top-level node -// "aec3". Returns default config values for anything that cannot be parsed from -// the string. -RTC_EXPORT EchoCanceller3Config -Aec3ConfigFromJsonString(absl::string_view json_string); - // Encodes an Aec3 config in JSON format. Fields corresponds to substruct names, // with the addition that the top-level node is named "aec3". -RTC_EXPORT std::string Aec3ConfigToJsonString( +std::string Aec3ConfigToJsonString( const EchoCanceller3Config& config); } // namespace webrtc -#endif // API_AUDIO_ECHO_CANCELLER3_CONFIG_JSON_H_ +#endif // MODULES_AUDIO_PROCESSING_TEST_ECHO_CANCELLER3_CONFIG_JSON_H_ diff --git a/api/audio/test/echo_canceller3_config_json_unittest.cc b/modules/audio_processing/test/echo_canceller3_config_json_unittest.cc similarity index 94% rename from api/audio/test/echo_canceller3_config_json_unittest.cc rename to modules/audio_processing/test/echo_canceller3_config_json_unittest.cc index 4146dda9fe..18c7e9f110 100644 --- a/api/audio/test/echo_canceller3_config_json_unittest.cc +++ b/modules/audio_processing/test/echo_canceller3_config_json_unittest.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "api/audio/echo_canceller3_config_json.h" +#include "modules/audio_processing/test/echo_canceller3_config_json.h" #include "api/audio/echo_canceller3_config.h" #include "test/gtest.h" @@ -36,8 +36,12 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) { cfg.multi_channel.stereo_detection_threshold += 1.0f; cfg.multi_channel.stereo_detection_timeout_threshold_seconds += 1; cfg.multi_channel.stereo_detection_hysteresis_seconds += 1; + std::string json_string = Aec3ConfigToJsonString(cfg); - EchoCanceller3Config cfg_transformed = Aec3ConfigFromJsonString(json_string); + EchoCanceller3Config cfg_transformed; + bool parsing_successful; + Aec3ConfigFromJsonString(json_string, &cfg_transformed, & parsing_successful); + ASSERT_TRUE(parsing_successful); // Expect unchanged values to remain default. EXPECT_EQ(cfg.ep_strength.default_len, diff --git a/modules/congestion_controller/DEPS b/modules/congestion_controller/DEPS index 2ed9952e22..4bb4026c37 100644 --- a/modules/congestion_controller/DEPS +++ b/modules/congestion_controller/DEPS @@ -3,3 +3,9 @@ include_rules = [ "+system_wrappers", "+video", ] +specific_include_rules = { + "goog_cc_network_control_unittest.cc": [ + "+call/video_receive_stream.h", + ], +} + diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 150201e1bd..c017d39f5d 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -156,7 +156,6 @@ rtc_library("loss_based_bwe_v2") { deps = [ "../../../api:array_view", "../../../api:field_trials_view", - "../../../api:network_state_predictor_api", "../../../api/transport:network_control", "../../../api/units:data_rate", "../../../api/units:data_size", @@ -231,10 +230,13 @@ rtc_library("delay_based_bwe") { deps = [ ":estimators", + ":link_capacity_estimator", "../../../api:field_trials_view", "../../../api:network_state_predictor_api", "../../../api/rtc_event_log", "../../../api/transport:network_control", + "../../../api/units:data_rate", + "../../../api/units:data_size", "../../../api/units:time_delta", "../../../api/units:timestamp", "../../../logging:rtc_event_bwe", @@ -347,6 +349,7 @@ if (rtc_include_tests) { "../../../api/units:data_size", "../../../api/units:time_delta", "../../../api/units:timestamp", + "../../../call:video_stream_api", "../../../logging:mocks", "../../../logging:rtc_event_bwe", "../../../rtc_base:checks", @@ -360,10 +363,14 @@ if (rtc_include_tests) { "../../../test:field_trial", "../../../test:test_support", "../../../test/scenario", + "../../../test/scenario:column_printer", "../../pacing", "//testing/gmock", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] } } } diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc index 08b42a8168..11bae888f3 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc @@ -10,14 +10,19 @@ #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" -#include - #include #include #include +#include +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/bitrate_estimator.h" #include "rtc_base/checks.h" -#include "rtc_base/numerics/safe_conversions.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h index d10846ab3a..a31c4df390 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h @@ -18,6 +18,7 @@ #include "api/field_trials_view.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/timestamp.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/bitrate_estimator.h" diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc index c043353a7a..571bbff71a 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.cc @@ -11,10 +11,13 @@ #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include +#include +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/robust_throughput_estimator.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/logging.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h index 6184cdc114..44e455d9d9 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h @@ -11,7 +11,6 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_ -#include #include #include diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc index e5b733b119..6e28f8e478 100644 --- a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc +++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc @@ -10,11 +10,19 @@ #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" +#include +#include #include #include +#include +#include "absl/types/optional.h" #include "api/transport/field_trial_based_config.h" -#include "rtc_base/fake_clock.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/bitrate_estimator.h" #include "test/gmock.h" #include "test/gtest.h" diff --git a/modules/congestion_controller/goog_cc/alr_detector_unittest.cc b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc index eac19d0081..da5852cbb3 100644 --- a/modules/congestion_controller/goog_cc/alr_detector_unittest.cc +++ b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc @@ -10,6 +10,9 @@ #include "modules/congestion_controller/goog_cc/alr_detector.h" +#include + +#include "absl/types/optional.h" #include "api/transport/field_trial_based_config.h" #include "rtc_base/checks.h" #include "rtc_base/experiments/alr_experiment.h" diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.cc b/modules/congestion_controller/goog_cc/bitrate_estimator.cc index 9c68e48886..e4f12ae06f 100644 --- a/modules/congestion_controller/goog_cc/bitrate_estimator.cc +++ b/modules/congestion_controller/goog_cc/bitrate_estimator.cc @@ -10,15 +10,19 @@ #include "modules/congestion_controller/goog_cc/bitrate_estimator.h" -#include - #include #include -#include +#include +#include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" -#include "rtc_base/logging.h" +#include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.h b/modules/congestion_controller/goog_cc/bitrate_estimator.h index a6f985800e..5ca8234ba8 100644 --- a/modules/congestion_controller/goog_cc/bitrate_estimator.h +++ b/modules/congestion_controller/goog_cc/bitrate_estimator.h @@ -16,6 +16,7 @@ #include "absl/types/optional.h" #include "api/field_trials_view.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" #include "api/units/timestamp.h" #include "rtc_base/experiments/field_trial_parser.h" diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc index 2f188f30ca..8a5bf93aa3 100644 --- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc +++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.cc @@ -10,14 +10,12 @@ #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" -#include -#include - #include -#include +#include #include "absl/strings/match.h" -#include "rtc_base/checks.h" +#include "api/field_trials_view.h" +#include "api/units/data_size.h" #include "rtc_base/experiments/rate_control_settings.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h index ea9ed97c3d..c18d9c686f 100644 --- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h +++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h @@ -11,7 +11,6 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_CONGESTION_WINDOW_PUSHBACK_CONTROLLER_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_CONGESTION_WINDOW_PUSHBACK_CONTROLLER_H_ -#include #include #include "absl/types/optional.h" diff --git a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller_unittest.cc b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller_unittest.cc index 62dde02323..c584c05eba 100644 --- a/modules/congestion_controller/goog_cc/congestion_window_pushback_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/congestion_window_pushback_controller_unittest.cc @@ -10,9 +10,11 @@ #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" +#include #include #include "api/transport/field_trial_based_config.h" +#include "api/units/data_size.h" #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc index f0562bc964..fbbe507dc7 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc @@ -12,21 +12,29 @@ #include #include -#include #include -#include #include +#include -#include "absl/strings/match.h" -#include "api/rtc_event_log/rtc_event.h" +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/network_state_predictor.h" #include "api/rtc_event_log/rtc_event_log.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" #include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" +#include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" +#include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" #include "modules/congestion_controller/goog_cc/trendline_estimator.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" #include "rtc_base/checks.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/logging.h" +#include "rtc_base/race_checker.h" #include "system_wrappers/include/metrics.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.h b/modules/congestion_controller/goog_cc/delay_based_bwe.h index e91a1dff54..741b10c157 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe.h +++ b/modules/congestion_controller/goog_cc/delay_based_bwe.h @@ -11,7 +11,6 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_ -#include #include #include @@ -21,8 +20,12 @@ #include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h" #include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" +#include "modules/congestion_controller/goog_cc/link_capacity_estimator.h" #include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" #include "modules/remote_bitrate_estimator/aimd_rate_control.h" #include "modules/remote_bitrate_estimator/inter_arrival.h" diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc index 5a4dbfdcc0..a824d90f92 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc @@ -10,10 +10,12 @@ #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" -#include +#include +#include "api/network_state_predictor.h" #include "api/transport/network_types.h" -#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h" #include "system_wrappers/include/clock.h" #include "test/gtest.h" diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc index 2730c5d49b..16bd4153a6 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc +++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc @@ -10,12 +10,22 @@ #include "modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h" #include +#include #include #include +#include -#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" +#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" #include "rtc_base/checks.h" +#include "test/field_trial.h" namespace webrtc { constexpr size_t kMtu = 1200; @@ -156,6 +166,7 @@ DelayBasedBweTest::DelayBasedBweTest() stream_generator_(new test::StreamGenerator(1e6, // Capacity. clock_.TimeInMicroseconds())), arrival_time_offset_ms_(0), + next_sequence_number_(0), first_update_(true) {} DelayBasedBweTest::~DelayBasedBweTest() {} @@ -191,6 +202,7 @@ void DelayBasedBweTest::IncomingFeedback(Timestamp receive_time, packet.sent_packet.send_time = send_time; packet.sent_packet.size = DataSize::Bytes(payload_size); packet.sent_packet.pacing_info = pacing_info; + packet.sent_packet.sequence_number = next_sequence_number_++; if (packet.sent_packet.pacing_info.probe_cluster_id != PacedPacketInfo::kNotAProbe) probe_bitrate_estimator_->HandleProbeAndEstimateBitrate(packet); diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h index 4b06173cdb..89eb1a353f 100644 --- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h +++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h @@ -180,6 +180,7 @@ class DelayBasedBweTest : public ::testing::Test { std::unique_ptr bitrate_estimator_; std::unique_ptr stream_generator_; int64_t arrival_time_offset_ms_; + int64_t next_sequence_number_; bool first_update_; }; diff --git a/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h b/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h index fc12cff7d5..7b2f790f65 100644 --- a/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h +++ b/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h @@ -12,6 +12,8 @@ #include +#include + #include "api/network_state_predictor.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index 67363367fd..58f183a657 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -10,30 +10,40 @@ #include "modules/congestion_controller/goog_cc/goog_cc_network_control.h" -#include #include #include #include #include #include -#include #include #include #include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" +#include "api/transport/network_control.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_remote_estimate.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/alr_detector.h" +#include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" +#include "modules/congestion_controller/goog_cc/delay_based_bwe.h" #include "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h" +#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/probe_controller.h" #include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" #include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/rate_control_settings.h" #include "rtc_base/logging.h" namespace webrtc { @@ -63,25 +73,26 @@ bool IsNotDisabled(const FieldTrialsView* config, absl::string_view key) { return !absl::StartsWith(config->Lookup(key), "Disabled"); } -BandwidthLimitedCause GetBandwidthLimitedCause( - LossBasedState loss_based_state, - bool is_rtt_above_limit, - BandwidthUsage bandwidth_usage, - bool not_probe_if_delay_increased) { - if (not_probe_if_delay_increased) { - if (bandwidth_usage == BandwidthUsage::kBwOverusing || - bandwidth_usage == BandwidthUsage::kBwUnderusing) { - return BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased; - } else if (is_rtt_above_limit) { - return BandwidthLimitedCause::kRttBasedBackOffHighRtt; - } +BandwidthLimitedCause GetBandwidthLimitedCause(LossBasedState loss_based_state, + bool is_rtt_above_limit, + BandwidthUsage bandwidth_usage) { + if (bandwidth_usage == BandwidthUsage::kBwOverusing || + bandwidth_usage == BandwidthUsage::kBwUnderusing) { + return BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased; + } else if (is_rtt_above_limit) { + return BandwidthLimitedCause::kRttBasedBackOffHighRtt; } switch (loss_based_state) { case LossBasedState::kDecreasing: - return BandwidthLimitedCause::kLossLimitedBweDecreasing; + // Probes may not be sent in this state. + return BandwidthLimitedCause::kLossLimitedBwe; + case webrtc::LossBasedState::kIncreaseUsingPadding: + // Probes may not be sent in this state. + return BandwidthLimitedCause::kLossLimitedBwe; case LossBasedState::kIncreasing: + // Probes may be sent in this state. return BandwidthLimitedCause::kLossLimitedBweIncreasing; - default: + case LossBasedState::kDelayBasedEstimate: return BandwidthLimitedCause::kDelayBasedLimited; } } @@ -102,8 +113,8 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, key_value_config_, "WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate")), limit_probes_lower_than_throughput_estimate_( - IsEnabled(key_value_config_, - "WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate")), + IsNotDisabled(key_value_config_, + "WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate")), rate_control_settings_( RateControlSettings::ParseFromKeyValueConfig(key_value_config_)), pace_at_max_of_bwe_and_lower_link_capacity_( @@ -134,6 +145,7 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config, last_loss_based_target_rate_(*config.constraints.starting_rate), last_pushback_target_rate_(last_loss_based_target_rate_), last_stable_target_rate_(last_loss_based_target_rate_), + last_loss_base_state_(LossBasedState::kDelayBasedEstimate), pacing_factor_(config.stream_based_config.pacing_factor.value_or( kDefaultPaceMultiplier)), min_total_allocated_bitrate_( @@ -230,7 +242,7 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval( probes.begin(), probes.end()); if (rate_control_settings_.UseCongestionWindow() && - last_packet_received_time_.IsFinite() && !feedback_max_rtts_.empty()) { + !feedback_max_rtts_.empty()) { UpdateCongestionWindowSize(); } if (congestion_window_pushback_controller_ && current_data_window_) { @@ -296,7 +308,6 @@ NetworkControlUpdate GoogCcNetworkController::OnSentPacket( NetworkControlUpdate GoogCcNetworkController::OnReceivedPacket( ReceivedPacket received_packet) { - last_packet_received_time_ = received_packet.receive_time; return NetworkControlUpdate(); } @@ -566,7 +577,6 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( } bandwidth_estimation_->UpdateLossBasedEstimator( report, result.delay_detector_state, probe_bitrate, - estimate_ ? estimate_->link_capacity_upper : DataRate::PlusInfinity(), alr_start_time.has_value()); if (result.updated) { // Update the estimate in the ProbeController, in case we want to probe. @@ -631,6 +641,7 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( uint8_t fraction_loss = bandwidth_estimation_->fraction_loss(); TimeDelta round_trip_time = bandwidth_estimation_->round_trip_time(); DataRate loss_based_target_rate = bandwidth_estimation_->target_rate(); + LossBasedState loss_based_state = bandwidth_estimation_->loss_based_state(); DataRate pushback_target_rate = loss_based_target_rate; BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(), @@ -658,6 +669,7 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( stable_target_rate = std::min(stable_target_rate, pushback_target_rate); if ((loss_based_target_rate != last_loss_based_target_rate_) || + (loss_based_state != last_loss_base_state_) || (fraction_loss != last_estimated_fraction_loss_) || (round_trip_time != last_estimated_round_trip_time_) || (pushback_target_rate != last_pushback_target_rate_) || @@ -667,6 +679,7 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( last_estimated_fraction_loss_ = fraction_loss; last_estimated_round_trip_time_ = round_trip_time; last_stable_target_rate_ = stable_target_rate; + last_loss_base_state_ = loss_based_state; alr_detector_->SetEstimatedBitrate(loss_based_target_rate.bps()); @@ -690,11 +703,9 @@ void GoogCcNetworkController::MaybeTriggerOnNetworkChanged( auto probes = probe_controller_->SetEstimatedBitrate( loss_based_target_rate, - GetBandwidthLimitedCause( - bandwidth_estimation_->loss_based_state(), - bandwidth_estimation_->IsRttAboveLimit(), - delay_based_bwe_->last_state(), - probe_controller_->DontProbeIfDelayIncreased()), + GetBandwidthLimitedCause(bandwidth_estimation_->loss_based_state(), + bandwidth_estimation_->IsRttAboveLimit(), + delay_based_bwe_->last_state()), at_time); update->probe_cluster_configs.insert(update->probe_cluster_configs.end(), probes.begin(), probes.end()); @@ -720,7 +731,10 @@ PacerConfig GoogCcNetworkController::GetPacingRates(Timestamp at_time) const { pacing_factor_; } DataRate padding_rate = - std::min(max_padding_rate_, last_pushback_target_rate_); + (last_loss_base_state_ == LossBasedState::kIncreaseUsingPadding) + ? std::max(max_padding_rate_, last_loss_based_target_rate_) + : max_padding_rate_; + padding_rate = std::min(padding_rate, last_pushback_target_rate_); PacerConfig msg; msg.at_time = at_time; msg.time_window = TimeDelta::Seconds(1); diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index 37a064e37c..957cedbac6 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -26,11 +26,13 @@ #include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/goog_cc/alr_detector.h" #include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" +#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/probe_controller.h" #include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -128,10 +130,10 @@ class GoogCcNetworkController : public NetworkControllerInterface { DataRate last_loss_based_target_rate_; DataRate last_pushback_target_rate_; DataRate last_stable_target_rate_; + LossBasedState last_loss_base_state_; absl::optional last_estimated_fraction_loss_ = 0; TimeDelta last_estimated_round_trip_time_ = TimeDelta::PlusInfinity(); - Timestamp last_packet_received_time_ = Timestamp::MinusInfinity(); double pacing_factor_; DataRate min_total_allocated_bitrate_; diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc index 0483dbf54d..c97d34da22 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc @@ -8,20 +8,34 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include +#include +#include +#include #include +#include +#include +#include #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "api/test/network_emulation/create_cross_traffic.h" #include "api/test/network_emulation/cross_traffic.h" #include "api/transport/goog_cc_factory.h" +#include "api/transport/network_control.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "call/video_receive_stream.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "test/field_trial.h" #include "test/gtest.h" +#include "test/scenario/call_client.h" +#include "test/scenario/column_printer.h" #include "test/scenario/scenario.h" +#include "test/scenario/scenario_config.h" using ::testing::IsEmpty; using ::testing::NiceMock; @@ -276,12 +290,15 @@ class NetworkControllerTestFixture { GoogCcNetworkControllerFactory factory_; }; -TEST(GoogCcNetworkControllerTest, InitializeTargetRateOnFirstProcessInterval) { +TEST(GoogCcNetworkControllerTest, + InitializeTargetRateOnFirstProcessIntervalAfterNetworkAvailable) { NetworkControllerTestFixture fixture; std::unique_ptr controller = fixture.CreateController(); - NetworkControlUpdate update = + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = Timestamp::Millis(123456), .network_available = true}); + update = controller->OnProcessInterval({.at_time = Timestamp::Millis(123456)}); EXPECT_EQ(update.target_rate->target_rate, kInitialBitrate); @@ -298,8 +315,9 @@ TEST(GoogCcNetworkControllerTest, ReactsToChangedNetworkConditions) { std::unique_ptr controller = fixture.CreateController(); Timestamp current_time = Timestamp::Millis(123); - NetworkControlUpdate update = - controller->OnProcessInterval({.at_time = current_time}); + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = current_time, .network_available = true}); + update = controller->OnProcessInterval({.at_time = current_time}); update = controller->OnRemoteBitrateReport( {.receive_time = current_time, .bandwidth = kInitialBitrate * 2}); @@ -323,8 +341,11 @@ TEST(GoogCcNetworkControllerTest, OnNetworkRouteChanged) { std::unique_ptr controller = fixture.CreateController(); Timestamp current_time = Timestamp::Millis(123); + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = current_time, .network_available = true}); DataRate new_bitrate = DataRate::BitsPerSec(200000); - NetworkControlUpdate update = controller->OnNetworkRouteChange( + + update = controller->OnNetworkRouteChange( CreateRouteChange(current_time, new_bitrate)); EXPECT_EQ(update.target_rate->target_rate, new_bitrate); EXPECT_EQ(update.pacer_config->data_rate(), new_bitrate * kDefaultPacingRate); @@ -345,7 +366,11 @@ TEST(GoogCcNetworkControllerTest, ProbeOnRouteChange) { std::unique_ptr controller = fixture.CreateController(); Timestamp current_time = Timestamp::Millis(123); - NetworkControlUpdate update = controller->OnNetworkRouteChange( + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = current_time, .network_available = true}); + current_time += TimeDelta::Seconds(3); + + update = controller->OnNetworkRouteChange( CreateRouteChange(current_time, 2 * kInitialBitrate, DataRate::Zero(), 20 * kInitialBitrate)); @@ -390,6 +415,8 @@ TEST(GoogCcNetworkControllerTest, UpdatesDelayBasedEstimate) { fixture.CreateController(); const int64_t kRunTimeMs = 6000; Timestamp current_time = Timestamp::Millis(123); + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = current_time, .network_available = true}); // The test must run and insert packets/feedback long enough that the // BWE computes a valid estimate. This is first done in an environment which @@ -414,8 +441,9 @@ TEST(GoogCcNetworkControllerTest, PaceAtMaxOfLowerLinkCapacityAndBwe) { std::unique_ptr controller = fixture.CreateController(); Timestamp current_time = Timestamp::Millis(123); - NetworkControlUpdate update = - controller->OnProcessInterval({.at_time = current_time}); + NetworkControlUpdate update = controller->OnNetworkAvailability( + {.at_time = current_time, .network_available = true}); + update = controller->OnProcessInterval({.at_time = current_time}); current_time += TimeDelta::Millis(100); NetworkStateEstimate network_estimate = {.link_capacity_lower = 10 * kInitialBitrate}; diff --git a/modules/congestion_controller/goog_cc/inter_arrival_delta.cc b/modules/congestion_controller/goog_cc/inter_arrival_delta.cc index 2d50d08e6a..0d69257355 100644 --- a/modules/congestion_controller/goog_cc/inter_arrival_delta.cc +++ b/modules/congestion_controller/goog_cc/inter_arrival_delta.cc @@ -11,9 +11,11 @@ #include "modules/congestion_controller/goog_cc/inter_arrival_delta.h" #include +#include #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/inter_arrival_delta.h b/modules/congestion_controller/goog_cc/inter_arrival_delta.h index 4046590eeb..cfa87f8631 100644 --- a/modules/congestion_controller/goog_cc/inter_arrival_delta.h +++ b/modules/congestion_controller/goog_cc/inter_arrival_delta.h @@ -11,6 +11,8 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_ +#include + #include "api/units/time_delta.h" #include "api/units/timestamp.h" diff --git a/modules/congestion_controller/goog_cc/link_capacity_estimator.cc b/modules/congestion_controller/goog_cc/link_capacity_estimator.cc index 9fd537a422..05664bcac7 100644 --- a/modules/congestion_controller/goog_cc/link_capacity_estimator.cc +++ b/modules/congestion_controller/goog_cc/link_capacity_estimator.cc @@ -10,7 +10,9 @@ #include "modules/congestion_controller/goog_cc/link_capacity_estimator.h" #include +#include +#include "api/units/data_rate.h" #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc index 7524c84d92..fa2e468f4f 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.cc @@ -11,12 +11,17 @@ #include "modules/congestion_controller/goog_cc/loss_based_bandwidth_estimation.h" #include -#include #include #include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "api/field_trials_view.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { namespace { diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc index 4c0f5fc5ee..e26fcc6cb1 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc @@ -12,18 +12,15 @@ #include #include -#include #include #include #include -#include #include #include "absl/algorithm/container.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/field_trials_view.h" -#include "api/network_state_predictor.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" @@ -38,6 +35,9 @@ namespace webrtc { namespace { +constexpr TimeDelta kInitHoldDuration = TimeDelta::Millis(300); +constexpr TimeDelta kMaxHoldDuration = TimeDelta::Seconds(60); + bool IsValid(DataRate datarate) { return datarate.IsFinite(); } @@ -50,10 +50,13 @@ bool IsValid(Timestamp timestamp) { return timestamp.IsFinite(); } +double ToKiloBytes(DataSize datasize) { return datasize.bytes() / 1000.0; } + struct PacketResultsSummary { int num_packets = 0; int num_lost_packets = 0; DataSize total_size = DataSize::Zero(); + DataSize lost_size = DataSize::Zero(); Timestamp first_send_time = Timestamp::PlusInfinity(); Timestamp last_send_time = Timestamp::MinusInfinity(); }; @@ -68,6 +71,7 @@ PacketResultsSummary GetPacketResultsSummary( for (const PacketResult& packet : packet_results) { if (!packet.IsReceived()) { packet_results_summary.num_lost_packets++; + packet_results_summary.lost_size += packet.sent_packet.size; } packet_results_summary.total_size += packet.sent_packet.size; packet_results_summary.first_send_time = std::min( @@ -121,12 +125,14 @@ LossBasedBweV2::LossBasedBweV2(const FieldTrialsView* key_value_config) return; } - current_estimate_.inherent_loss = config_->initial_inherent_loss_estimate; + current_best_estimate_.inherent_loss = + config_->initial_inherent_loss_estimate; observations_.resize(config_->observation_window_size); temporal_weights_.resize(config_->observation_window_size); instant_upper_bound_temporal_weights_.resize( config_->observation_window_size); CalculateTemporalWeights(); + hold_duration_ = kInitHoldDuration; } bool LossBasedBweV2::IsEnabled() const { @@ -134,47 +140,43 @@ bool LossBasedBweV2::IsEnabled() const { } bool LossBasedBweV2::IsReady() const { - return IsEnabled() && IsValid(current_estimate_.loss_limited_bandwidth) && - num_observations_ > 0; + return IsEnabled() && + IsValid(current_best_estimate_.loss_limited_bandwidth) && + num_observations_ >= config_->min_num_observations; +} + +bool LossBasedBweV2::ReadyToUseInStartPhase() const { + return IsReady() && config_->use_in_start_phase; } LossBasedBweV2::Result LossBasedBweV2::GetLossBasedResult() const { - Result result; - result.state = current_state_; if (!IsReady()) { if (!IsEnabled()) { RTC_LOG(LS_WARNING) << "The estimator must be enabled before it can be used."; } else { - if (!IsValid(current_estimate_.loss_limited_bandwidth)) { + if (!IsValid(current_best_estimate_.loss_limited_bandwidth)) { RTC_LOG(LS_WARNING) << "The estimator must be initialized before it can be used."; } - if (num_observations_ <= 0) { + if (num_observations_ <= config_->min_num_observations) { RTC_LOG(LS_WARNING) << "The estimator must receive enough loss " "statistics before it can be used."; } } - result.bandwidth_estimate = IsValid(delay_based_estimate_) - ? delay_based_estimate_ - : DataRate::PlusInfinity(); - return result; + return {.bandwidth_estimate = IsValid(delay_based_estimate_) + ? delay_based_estimate_ + : DataRate::PlusInfinity(), + .state = LossBasedState::kDelayBasedEstimate}; } - if (IsValid(delay_based_estimate_)) { - result.bandwidth_estimate = - std::min({current_estimate_.loss_limited_bandwidth, - GetInstantUpperBound(), delay_based_estimate_}); - } else { - result.bandwidth_estimate = std::min( - current_estimate_.loss_limited_bandwidth, GetInstantUpperBound()); - } - return result; + return loss_based_result_; } void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) { if (IsValid(acknowledged_bitrate)) { acknowledged_bitrate_ = acknowledged_bitrate; + CalculateInstantLowerBound(); } else { RTC_LOG(LS_WARNING) << "The acknowledged bitrate must be finite: " << ToString(acknowledged_bitrate); @@ -183,7 +185,9 @@ void LossBasedBweV2::SetAcknowledgedBitrate(DataRate acknowledged_bitrate) { void LossBasedBweV2::SetBandwidthEstimate(DataRate bandwidth_estimate) { if (IsValid(bandwidth_estimate)) { - current_estimate_.loss_limited_bandwidth = bandwidth_estimate; + current_best_estimate_.loss_limited_bandwidth = bandwidth_estimate; + loss_based_result_ = {.bandwidth_estimate = bandwidth_estimate, + .state = LossBasedState::kDelayBasedEstimate}; } else { RTC_LOG(LS_WARNING) << "The bandwidth estimate must be finite: " << ToString(bandwidth_estimate); @@ -194,6 +198,7 @@ void LossBasedBweV2::SetMinMaxBitrate(DataRate min_bitrate, DataRate max_bitrate) { if (IsValid(min_bitrate)) { min_bitrate_ = min_bitrate; + CalculateInstantLowerBound(); } else { RTC_LOG(LS_WARNING) << "The min bitrate must be finite: " << ToString(min_bitrate); @@ -207,22 +212,11 @@ void LossBasedBweV2::SetMinMaxBitrate(DataRate min_bitrate, } } -void LossBasedBweV2::SetProbeBitrate(absl::optional probe_bitrate) { - if (probe_bitrate.has_value() && IsValid(probe_bitrate.value())) { - probe_bitrate_ = probe_bitrate.value(); - last_probe_timestamp_ = last_send_time_most_recent_observation_; - } -} - void LossBasedBweV2::UpdateBandwidthEstimate( rtc::ArrayView packet_results, DataRate delay_based_estimate, - BandwidthUsage delay_detector_state, - absl::optional probe_bitrate, - DataRate upper_link_capacity, bool in_alr) { delay_based_estimate_ = delay_based_estimate; - upper_link_capacity_ = upper_link_capacity; if (!IsEnabled()) { RTC_LOG(LS_WARNING) << "The estimator must be enabled before it can be used."; @@ -235,19 +229,22 @@ void LossBasedBweV2::UpdateBandwidthEstimate( return; } - if (!PushBackObservation(packet_results, delay_detector_state)) { + if (!PushBackObservation(packet_results)) { return; } - SetProbeBitrate(probe_bitrate); - - if (!IsValid(current_estimate_.loss_limited_bandwidth)) { - RTC_LOG(LS_VERBOSE) - << "The estimator must be initialized before it can be used."; - return; + if (!IsValid(current_best_estimate_.loss_limited_bandwidth)) { + if (!IsValid(delay_based_estimate)) { + RTC_LOG(LS_WARNING) << "The delay based estimate must be finite: " + << ToString(delay_based_estimate); + return; + } + current_best_estimate_.loss_limited_bandwidth = delay_based_estimate; + loss_based_result_ = {.bandwidth_estimate = delay_based_estimate, + .state = LossBasedState::kDelayBasedEstimate}; } - ChannelParameters best_candidate = current_estimate_; + ChannelParameters best_candidate = current_best_estimate_; double objective_max = std::numeric_limits::lowest(); for (ChannelParameters candidate : GetCandidates(in_alr)) { NewtonsMethodUpdate(candidate); @@ -259,7 +256,7 @@ void LossBasedBweV2::UpdateBandwidthEstimate( } } if (best_candidate.loss_limited_bandwidth < - current_estimate_.loss_limited_bandwidth) { + current_best_estimate_.loss_limited_bandwidth) { last_time_estimate_reduced_ = last_send_time_most_recent_observation_; } @@ -267,13 +264,13 @@ void LossBasedBweV2::UpdateBandwidthEstimate( // inherent loss. if (GetAverageReportedLossRatio() > best_candidate.inherent_loss && config_->not_increase_if_inherent_loss_less_than_average_loss && - current_estimate_.loss_limited_bandwidth < + current_best_estimate_.loss_limited_bandwidth < best_candidate.loss_limited_bandwidth) { best_candidate.loss_limited_bandwidth = - current_estimate_.loss_limited_bandwidth; + current_best_estimate_.loss_limited_bandwidth; } - if (IsBandwidthLimitedDueToLoss()) { + if (IsInLossLimitedState()) { // Bound the estimate increase if: // 1. The estimate has been increased for less than // `delayed_increase_window` ago, and @@ -287,63 +284,107 @@ void LossBasedBweV2::UpdateBandwidthEstimate( bandwidth_limit_in_current_window_; } - bool increasing_when_loss_limited = - IsEstimateIncreasingWhenLossLimited(best_candidate); - // Bound the best candidate by the acked bitrate unless there is a recent - // probe result. - if (increasing_when_loss_limited && !IsValid(probe_bitrate_) && - IsValid(acknowledged_bitrate_)) { + bool increasing_when_loss_limited = IsEstimateIncreasingWhenLossLimited( + /*old_estimate=*/current_best_estimate_.loss_limited_bandwidth, + /*new_estimate=*/best_candidate.loss_limited_bandwidth); + // Bound the best candidate by the acked bitrate. + if (increasing_when_loss_limited && IsValid(acknowledged_bitrate_)) { best_candidate.loss_limited_bandwidth = - IsValid(best_candidate.loss_limited_bandwidth) - ? std::min(best_candidate.loss_limited_bandwidth, - config_->bandwidth_rampup_upper_bound_factor * - (*acknowledged_bitrate_)) - : config_->bandwidth_rampup_upper_bound_factor * - (*acknowledged_bitrate_); + std::max(current_best_estimate_.loss_limited_bandwidth, + std::min(best_candidate.loss_limited_bandwidth, + config_->bandwidth_rampup_upper_bound_factor * + (*acknowledged_bitrate_))); } } - if (IsEstimateIncreasingWhenLossLimited(best_candidate) && - best_candidate.loss_limited_bandwidth < delay_based_estimate_) { - current_state_ = LossBasedState::kIncreasing; - } else if (best_candidate.loss_limited_bandwidth < delay_based_estimate_) { - current_state_ = LossBasedState::kDecreasing; - } else if (best_candidate.loss_limited_bandwidth >= delay_based_estimate_) { - current_state_ = LossBasedState::kDelayBasedEstimate; - } + current_best_estimate_ = best_candidate; + UpdateResult(); - // Use probe bitrate as the estimate limit when probes are requested. - if (config_->probe_integration_enabled && IsValid(probe_bitrate_) && - IsRequestingProbe()) { - if (last_probe_timestamp_ + config_->probe_expiration >= - last_send_time_most_recent_observation_) { - best_candidate.loss_limited_bandwidth = - std::min(probe_bitrate_, best_candidate.loss_limited_bandwidth); - } - } - - current_estimate_ = best_candidate; - - if (IsBandwidthLimitedDueToLoss() && + if (IsInLossLimitedState() && (recovering_after_loss_timestamp_.IsInfinite() || recovering_after_loss_timestamp_ + config_->delayed_increase_window < last_send_time_most_recent_observation_)) { bandwidth_limit_in_current_window_ = std::max(kCongestionControllerMinBitrate, - current_estimate_.loss_limited_bandwidth * + current_best_estimate_.loss_limited_bandwidth * config_->max_increase_factor); recovering_after_loss_timestamp_ = last_send_time_most_recent_observation_; } } +void LossBasedBweV2::UpdateResult() { + DataRate bounded_bandwidth_estimate = DataRate::PlusInfinity(); + if (IsValid(delay_based_estimate_)) { + bounded_bandwidth_estimate = + std::max(GetInstantLowerBound(), + std::min({current_best_estimate_.loss_limited_bandwidth, + GetInstantUpperBound(), delay_based_estimate_})); + } else { + bounded_bandwidth_estimate = + std::max(GetInstantLowerBound(), + std::min(current_best_estimate_.loss_limited_bandwidth, + GetInstantUpperBound())); + } + + if (loss_based_result_.state == LossBasedState::kDecreasing && + last_hold_timestamp_ > last_send_time_most_recent_observation_ && + bounded_bandwidth_estimate < delay_based_estimate_) { + // BWE is not allowed to increase during the HOLD duration. The purpose of + // HOLD is to not immediately ramp up BWE to a rate that may cause loss. + loss_based_result_.bandwidth_estimate = std::min( + loss_based_result_.bandwidth_estimate, bounded_bandwidth_estimate); + return; + } + + if (IsEstimateIncreasingWhenLossLimited( + /*old_estimate=*/loss_based_result_.bandwidth_estimate, + /*new_estimate=*/bounded_bandwidth_estimate) && + CanKeepIncreasingState(bounded_bandwidth_estimate) && + bounded_bandwidth_estimate < delay_based_estimate_ && + bounded_bandwidth_estimate < max_bitrate_) { + if (config_->padding_duration > TimeDelta::Zero() && + bounded_bandwidth_estimate > last_padding_info_.padding_rate) { + // Start a new padding duration. + last_padding_info_.padding_rate = bounded_bandwidth_estimate; + last_padding_info_.padding_timestamp = + last_send_time_most_recent_observation_; + } + loss_based_result_.state = config_->padding_duration > TimeDelta::Zero() + ? LossBasedState::kIncreaseUsingPadding + : LossBasedState::kIncreasing; + } else if (bounded_bandwidth_estimate < delay_based_estimate_ && + bounded_bandwidth_estimate < max_bitrate_) { + if (loss_based_result_.state != LossBasedState::kDecreasing && + config_->hold_duration_factor > 0) { + RTC_LOG(LS_INFO) << this << " " + << "Switch to HOLD. Bounded BWE: " + << bounded_bandwidth_estimate.kbps() + << ", duration: " << hold_duration_.seconds(); + last_hold_timestamp_ = + last_send_time_most_recent_observation_ + hold_duration_; + hold_duration_ = std::min(kMaxHoldDuration, + hold_duration_ * config_->hold_duration_factor); + } + last_padding_info_ = PaddingInfo(); + loss_based_result_.state = LossBasedState::kDecreasing; + } else { + // Reset the HOLD duration if delay based estimate works to avoid getting + // stuck in low bitrate. + hold_duration_ = kInitHoldDuration; + last_padding_info_ = PaddingInfo(); + loss_based_result_.state = LossBasedState::kDelayBasedEstimate; + } + loss_based_result_.bandwidth_estimate = bounded_bandwidth_estimate; +} + bool LossBasedBweV2::IsEstimateIncreasingWhenLossLimited( - const ChannelParameters& best_candidate) { - return (current_estimate_.loss_limited_bandwidth < - best_candidate.loss_limited_bandwidth || - (current_estimate_.loss_limited_bandwidth == - best_candidate.loss_limited_bandwidth && - current_state_ == LossBasedState::kIncreasing)) && - IsBandwidthLimitedDueToLoss(); + DataRate old_estimate, DataRate new_estimate) { + return (old_estimate < new_estimate || + (old_estimate == new_estimate && + (loss_based_result_.state == LossBasedState::kIncreasing || + loss_based_result_.state == + LossBasedState::kIncreaseUsingPadding))) && + IsInLossLimitedState(); } // Returns a `LossBasedBweV2::Config` iff the `key_value_config` specifies a @@ -381,6 +422,8 @@ absl::optional LossBasedBweV2::CreateConfig( "AckedRateCandidate", true); FieldTrialParameter append_delay_based_estimate_candidate( "DelayBasedCandidate", true); + FieldTrialParameter append_upper_bound_candidate_in_alr( + "UpperBoundCandidateInAlr", false); FieldTrialParameter observation_duration_lower_bound( "ObservationDurationLowerBound", TimeDelta::Millis(250)); FieldTrialParameter observation_window_size("ObservationWindowSize", 20); @@ -396,15 +439,9 @@ absl::optional LossBasedBweV2::CreateConfig( 0.9); FieldTrialParameter bandwidth_backoff_lower_bound_factor( "BwBackoffLowerBoundFactor", 1.0); - FieldTrialParameter trendline_integration_enabled( - "TrendlineIntegrationEnabled", false); - FieldTrialParameter trendline_observations_window_size( - "TrendlineObservationsWindowSize", 20); FieldTrialParameter max_increase_factor("MaxIncreaseFactor", 1.3); FieldTrialParameter delayed_increase_window( "DelayedIncreaseWindow", TimeDelta::Millis(300)); - FieldTrialParameter use_acked_bitrate_only_when_overusing( - "UseAckedBitrateOnlyWhenOverusing", false); FieldTrialParameter not_increase_if_inherent_loss_less_than_average_loss( "NotIncreaseIfInherentLossLessThanAverageLoss", true); @@ -414,14 +451,16 @@ absl::optional LossBasedBweV2::CreateConfig( "BandwidthCapAtHighLossRate", DataRate::KilobitsPerSec(500.0)); FieldTrialParameter slope_of_bwe_high_loss_func( "SlopeOfBweHighLossFunc", 1000); - FieldTrialParameter probe_integration_enabled("ProbeIntegrationEnabled", - false); - FieldTrialParameter probe_expiration("ProbeExpiration", - TimeDelta::Seconds(10)); - FieldTrialParameter bound_by_upper_link_capacity_when_loss_limited( - "BoundByUpperLinkCapacityWhenLossLimited", true); FieldTrialParameter not_use_acked_rate_in_alr("NotUseAckedRateInAlr", - false); + true); + FieldTrialParameter use_in_start_phase("UseInStartPhase", false); + FieldTrialParameter min_num_observations("MinNumObservations", 3); + FieldTrialParameter lower_bound_by_acked_rate_factor( + "LowerBoundByAckedRateFactor", 0.0); + FieldTrialParameter hold_duration_factor("HoldDurationFactor", 0.0); + FieldTrialParameter use_byte_loss_rate("UseByteLossRate", false); + FieldTrialParameter padding_duration("PaddingDuration", + TimeDelta::Zero()); if (key_value_config) { ParseFieldTrial({&enabled, &bandwidth_rampup_upper_bound_factor, @@ -440,6 +479,7 @@ absl::optional LossBasedBweV2::CreateConfig( &newton_step_size, &append_acknowledged_rate_candidate, &append_delay_based_estimate_candidate, + &append_upper_bound_candidate_in_alr, &observation_duration_lower_bound, &observation_window_size, &sending_rate_smoothing_factor, @@ -448,19 +488,19 @@ absl::optional LossBasedBweV2::CreateConfig( &instant_upper_bound_loss_offset, &temporal_weight_factor, &bandwidth_backoff_lower_bound_factor, - &trendline_integration_enabled, - &trendline_observations_window_size, &max_increase_factor, &delayed_increase_window, - &use_acked_bitrate_only_when_overusing, ¬_increase_if_inherent_loss_less_than_average_loss, - &probe_integration_enabled, - &probe_expiration, &high_loss_rate_threshold, &bandwidth_cap_at_high_loss_rate, &slope_of_bwe_high_loss_func, - &bound_by_upper_link_capacity_when_loss_limited, - ¬_use_acked_rate_in_alr}, + ¬_use_acked_rate_in_alr, + &use_in_start_phase, + &min_num_observations, + &lower_bound_by_acked_rate_factor, + &hold_duration_factor, + &use_byte_loss_rate, + &padding_duration}, key_value_config->Lookup("WebRTC-Bwe-LossBasedBweV2")); } @@ -494,6 +534,8 @@ absl::optional LossBasedBweV2::CreateConfig( append_acknowledged_rate_candidate.Get(); config->append_delay_based_estimate_candidate = append_delay_based_estimate_candidate.Get(); + config->append_upper_bound_candidate_in_alr = + append_upper_bound_candidate_in_alr.Get(); config->observation_duration_lower_bound = observation_duration_lower_bound.Get(); config->observation_window_size = observation_window_size.Get(); @@ -507,24 +549,22 @@ absl::optional LossBasedBweV2::CreateConfig( config->temporal_weight_factor = temporal_weight_factor.Get(); config->bandwidth_backoff_lower_bound_factor = bandwidth_backoff_lower_bound_factor.Get(); - config->trendline_integration_enabled = trendline_integration_enabled.Get(); - config->trendline_observations_window_size = - trendline_observations_window_size.Get(); config->max_increase_factor = max_increase_factor.Get(); config->delayed_increase_window = delayed_increase_window.Get(); - config->use_acked_bitrate_only_when_overusing = - use_acked_bitrate_only_when_overusing.Get(); config->not_increase_if_inherent_loss_less_than_average_loss = not_increase_if_inherent_loss_less_than_average_loss.Get(); config->high_loss_rate_threshold = high_loss_rate_threshold.Get(); config->bandwidth_cap_at_high_loss_rate = bandwidth_cap_at_high_loss_rate.Get(); config->slope_of_bwe_high_loss_func = slope_of_bwe_high_loss_func.Get(); - config->probe_integration_enabled = probe_integration_enabled.Get(); - config->probe_expiration = probe_expiration.Get(); - config->bound_by_upper_link_capacity_when_loss_limited = - bound_by_upper_link_capacity_when_loss_limited.Get(); config->not_use_acked_rate_in_alr = not_use_acked_rate_in_alr.Get(); + config->use_in_start_phase = use_in_start_phase.Get(); + config->min_num_observations = min_num_observations.Get(); + config->lower_bound_by_acked_rate_factor = + lower_bound_by_acked_rate_factor.Get(); + config->hold_duration_factor = hold_duration_factor.Get(); + config->use_byte_loss_rate = use_byte_loss_rate.Get(); + config->padding_duration = padding_duration.Get(); return config; } @@ -689,11 +729,6 @@ bool LossBasedBweV2::IsConfigValid() const { << config_->bandwidth_backoff_lower_bound_factor; valid = false; } - if (config_->trendline_observations_window_size < 1) { - RTC_LOG(LS_WARNING) << "The trendline window size must be at least 1: " - << config_->trendline_observations_window_size; - valid = false; - } if (config_->max_increase_factor <= 0.0) { RTC_LOG(LS_WARNING) << "The maximum increase factor must be positive: " << config_->max_increase_factor; @@ -710,10 +745,27 @@ bool LossBasedBweV2::IsConfigValid() const { << config_->high_loss_rate_threshold; valid = false; } + if (config_->min_num_observations <= 0) { + RTC_LOG(LS_WARNING) << "The min number of observations must be positive: " + << config_->min_num_observations; + valid = false; + } + if (config_->lower_bound_by_acked_rate_factor < 0.0) { + RTC_LOG(LS_WARNING) + << "The estimate lower bound by acknowledged rate factor must be " + "non-negative: " + << config_->lower_bound_by_acked_rate_factor; + valid = false; + } return valid; } double LossBasedBweV2::GetAverageReportedLossRatio() const { + return config_->use_byte_loss_rate ? GetAverageReportedByteLossRatio() + : GetAverageReportedPacketLossRatio(); +} + +double LossBasedBweV2::GetAverageReportedPacketLossRatio() const { if (num_observations_ <= 0) { return 0.0; } @@ -735,20 +787,31 @@ double LossBasedBweV2::GetAverageReportedLossRatio() const { return num_lost_packets / num_packets; } -DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const { - DataRate candidate_bandwidth_upper_bound = max_bitrate_; - if (IsBandwidthLimitedDueToLoss() && - IsValid(bandwidth_limit_in_current_window_)) { - candidate_bandwidth_upper_bound = bandwidth_limit_in_current_window_; +double LossBasedBweV2::GetAverageReportedByteLossRatio() const { + if (num_observations_ <= 0) { + return 0.0; } - if (config_->trendline_integration_enabled) { - candidate_bandwidth_upper_bound = - std::min(GetInstantUpperBound(), candidate_bandwidth_upper_bound); - if (IsValid(delay_based_estimate_)) { - candidate_bandwidth_upper_bound = - std::min(delay_based_estimate_, candidate_bandwidth_upper_bound); + DataSize total_bytes = DataSize::Zero(); + DataSize lost_bytes = DataSize::Zero(); + for (const Observation& observation : observations_) { + if (!observation.IsInitialized()) { + continue; } + + double instant_temporal_weight = + instant_upper_bound_temporal_weights_[(num_observations_ - 1) - + observation.id]; + total_bytes += instant_temporal_weight * observation.size; + lost_bytes += instant_temporal_weight * observation.lost_size; + } + return lost_bytes / total_bytes; +} + +DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const { + DataRate candidate_bandwidth_upper_bound = max_bitrate_; + if (IsInLossLimitedState() && IsValid(bandwidth_limit_in_current_window_)) { + candidate_bandwidth_upper_bound = bandwidth_limit_in_current_window_; } if (!acknowledged_bitrate_.has_value()) @@ -772,18 +835,13 @@ DataRate LossBasedBweV2::GetCandidateBandwidthUpperBound() const { std::vector LossBasedBweV2::GetCandidates( bool in_alr) const { std::vector bandwidths; - bool can_increase_bitrate = TrendlineEsimateAllowBitrateIncrease(); for (double candidate_factor : config_->candidate_factors) { - if (!can_increase_bitrate && candidate_factor > 1.0) { - continue; - } bandwidths.push_back(candidate_factor * - current_estimate_.loss_limited_bandwidth); + current_best_estimate_.loss_limited_bandwidth); } if (acknowledged_bitrate_.has_value() && - config_->append_acknowledged_rate_candidate && - TrendlineEsimateAllowEmergencyBackoff()) { + config_->append_acknowledged_rate_candidate) { if (!(config_->not_use_acked_rate_in_alr && in_alr)) { bandwidths.push_back(*acknowledged_bitrate_ * config_->bandwidth_backoff_lower_bound_factor); @@ -792,27 +850,26 @@ std::vector LossBasedBweV2::GetCandidates( if (IsValid(delay_based_estimate_) && config_->append_delay_based_estimate_candidate) { - if (can_increase_bitrate && - delay_based_estimate_ > current_estimate_.loss_limited_bandwidth) { + if (delay_based_estimate_ > current_best_estimate_.loss_limited_bandwidth) { bandwidths.push_back(delay_based_estimate_); } } + if (in_alr && config_->append_upper_bound_candidate_in_alr && + current_best_estimate_.loss_limited_bandwidth > GetInstantUpperBound()) { + bandwidths.push_back(GetInstantUpperBound()); + } + const DataRate candidate_bandwidth_upper_bound = GetCandidateBandwidthUpperBound(); std::vector candidates; candidates.resize(bandwidths.size()); for (size_t i = 0; i < bandwidths.size(); ++i) { - ChannelParameters candidate = current_estimate_; - if (config_->trendline_integration_enabled) { - candidate.loss_limited_bandwidth = - std::min(bandwidths[i], candidate_bandwidth_upper_bound); - } else { - candidate.loss_limited_bandwidth = std::min( - bandwidths[i], std::max(current_estimate_.loss_limited_bandwidth, - candidate_bandwidth_upper_bound)); - } + ChannelParameters candidate = current_best_estimate_; + candidate.loss_limited_bandwidth = std::min( + bandwidths[i], std::max(current_best_estimate_.loss_limited_bandwidth, + candidate_bandwidth_upper_bound)); candidate.inherent_loss = GetFeasibleInherentLoss(candidate); candidates[i] = candidate; } @@ -834,16 +891,29 @@ LossBasedBweV2::Derivatives LossBasedBweV2::GetDerivatives( double temporal_weight = temporal_weights_[(num_observations_ - 1) - observation.id]; - - derivatives.first += - temporal_weight * - ((observation.num_lost_packets / loss_probability) - - (observation.num_received_packets / (1.0 - loss_probability))); - derivatives.second -= - temporal_weight * - ((observation.num_lost_packets / std::pow(loss_probability, 2)) + - (observation.num_received_packets / - std::pow(1.0 - loss_probability, 2))); + if (config_->use_byte_loss_rate) { + derivatives.first += + temporal_weight * + ((ToKiloBytes(observation.lost_size) / loss_probability) - + (ToKiloBytes(observation.size - observation.lost_size) / + (1.0 - loss_probability))); + derivatives.second -= + temporal_weight * + ((ToKiloBytes(observation.lost_size) / + std::pow(loss_probability, 2)) + + (ToKiloBytes(observation.size - observation.lost_size) / + std::pow(1.0 - loss_probability, 2))); + } else { + derivatives.first += + temporal_weight * + ((observation.num_lost_packets / loss_probability) - + (observation.num_received_packets / (1.0 - loss_probability))); + derivatives.second -= + temporal_weight * + ((observation.num_lost_packets / std::pow(loss_probability, 2)) + + (observation.num_received_packets / + std::pow(1.0 - loss_probability, 2))); + } } if (derivatives.second >= 0.0) { @@ -915,13 +985,23 @@ double LossBasedBweV2::GetObjective( double temporal_weight = temporal_weights_[(num_observations_ - 1) - observation.id]; - - objective += - temporal_weight * - ((observation.num_lost_packets * std::log(loss_probability)) + - (observation.num_received_packets * std::log(1.0 - loss_probability))); - objective += - temporal_weight * high_bandwidth_bias * observation.num_packets; + if (config_->use_byte_loss_rate) { + objective += + temporal_weight * + ((ToKiloBytes(observation.lost_size) * std::log(loss_probability)) + + (ToKiloBytes(observation.size - observation.lost_size) * + std::log(1.0 - loss_probability))); + objective += + temporal_weight * high_bandwidth_bias * ToKiloBytes(observation.size); + } else { + objective += + temporal_weight * + ((observation.num_lost_packets * std::log(loss_probability)) + + (observation.num_received_packets * + std::log(1.0 - loss_probability))); + objective += + temporal_weight * high_bandwidth_bias * observation.num_packets; + } } return objective; @@ -967,15 +1047,27 @@ void LossBasedBweV2::CalculateInstantUpperBound() { } } - if (IsBandwidthLimitedDueToLoss()) { - if (IsValid(upper_link_capacity_) && - config_->bound_by_upper_link_capacity_when_loss_limited) { - instant_limit = std::min(instant_limit, upper_link_capacity_); - } - } cached_instant_upper_bound_ = instant_limit; } +DataRate LossBasedBweV2::GetInstantLowerBound() const { + return cached_instant_lower_bound_.value_or(DataRate::Zero()); +} + +void LossBasedBweV2::CalculateInstantLowerBound() { + DataRate instance_lower_bound = DataRate::Zero(); + if (IsValid(acknowledged_bitrate_) && + config_->lower_bound_by_acked_rate_factor > 0.0) { + instance_lower_bound = config_->lower_bound_by_acked_rate_factor * + acknowledged_bitrate_.value(); + } + + if (IsValid(min_bitrate_)) { + instance_lower_bound = std::max(instance_lower_bound, min_bitrate_); + } + cached_instant_lower_bound_ = instance_lower_bound; +} + void LossBasedBweV2::CalculateTemporalWeights() { for (int i = 0; i < config_->observation_window_size; ++i) { temporal_weights_[i] = std::pow(config_->temporal_weight_factor, i); @@ -999,47 +1091,8 @@ void LossBasedBweV2::NewtonsMethodUpdate( } } -bool LossBasedBweV2::TrendlineEsimateAllowBitrateIncrease() const { - if (!config_->trendline_integration_enabled) { - return true; - } - - for (const auto& detector_state : delay_detector_states_) { - if (detector_state == BandwidthUsage::kBwOverusing || - detector_state == BandwidthUsage::kBwUnderusing) { - return false; - } - } - return true; -} - -bool LossBasedBweV2::TrendlineEsimateAllowEmergencyBackoff() const { - if (!config_->trendline_integration_enabled) { - return true; - } - - if (!config_->use_acked_bitrate_only_when_overusing) { - return true; - } - - for (const auto& detector_state : delay_detector_states_) { - if (detector_state == BandwidthUsage::kBwOverusing) { - return true; - } - } - - return false; -} - bool LossBasedBweV2::PushBackObservation( - rtc::ArrayView packet_results, - BandwidthUsage delay_detector_state) { - delay_detector_states_.push_front(delay_detector_state); - if (static_cast(delay_detector_states_.size()) > - config_->trendline_observations_window_size) { - delay_detector_states_.pop_back(); - } - + rtc::ArrayView packet_results) { if (packet_results.empty()) { return false; } @@ -1051,6 +1104,7 @@ bool LossBasedBweV2::PushBackObservation( partial_observation_.num_lost_packets += packet_results_summary.num_lost_packets; partial_observation_.size += packet_results_summary.total_size; + partial_observation_.lost_size += packet_results_summary.lost_size; // This is the first packet report we have received. if (!IsValid(last_send_time_most_recent_observation_)) { @@ -1063,9 +1117,7 @@ bool LossBasedBweV2::PushBackObservation( last_send_time - last_send_time_most_recent_observation_; // Too small to be meaningful. if (observation_duration <= TimeDelta::Zero() || - (observation_duration < config_->observation_duration_lower_bound && - (delay_detector_state != BandwidthUsage::kBwOverusing || - !config_->trendline_integration_enabled))) { + observation_duration < config_->observation_duration_lower_bound) { return false; } @@ -1078,6 +1130,8 @@ bool LossBasedBweV2::PushBackObservation( observation.num_packets - observation.num_lost_packets; observation.sending_rate = GetSendingRate(partial_observation_.size / observation_duration); + observation.lost_size = partial_observation_.lost_size; + observation.size = partial_observation_.size; observation.id = num_observations_++; observations_[observation.id % config_->observation_window_size] = observation; @@ -1088,12 +1142,21 @@ bool LossBasedBweV2::PushBackObservation( return true; } -bool LossBasedBweV2::IsBandwidthLimitedDueToLoss() const { - return current_state_ != LossBasedState::kDelayBasedEstimate; +bool LossBasedBweV2::IsInLossLimitedState() const { + return loss_based_result_.state != LossBasedState::kDelayBasedEstimate; } -bool LossBasedBweV2::IsRequestingProbe() const { - return current_state_ == LossBasedState::kIncreasing; +bool LossBasedBweV2::CanKeepIncreasingState(DataRate estimate) const { + if (config_->padding_duration == TimeDelta::Zero() || + loss_based_result_.state != LossBasedState::kIncreaseUsingPadding) + return true; + + // Keep using the kIncreaseUsingPadding if either the state has been + // kIncreaseUsingPadding for less than kPaddingDuration or the estimate + // increases. + return last_padding_info_.padding_timestamp + config_->padding_duration >= + last_send_time_most_recent_observation_ || + last_padding_info_.padding_rate < estimate; } } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h index f5a6396de2..425ca2a0c8 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2.h @@ -11,14 +11,11 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LOSS_BASED_BWE_V2_H_ -#include -#include #include #include "absl/types/optional.h" #include "api/array_view.h" #include "api/field_trials_view.h" -#include "api/network_state_predictor.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" @@ -31,8 +28,12 @@ namespace webrtc { // when network is loss limited, or equal to the delay based estimate. enum class LossBasedState { kIncreasing = 0, - kDecreasing = 1, - kDelayBasedEstimate = 2 + // TODO(bugs.webrtc.org/12707): Remove one of the increasing states once we + // have decided if padding is usefull for ramping up when BWE is loss + // limited. + kIncreaseUsingPadding = 1, + kDecreasing = 2, + kDelayBasedEstimate = 3 }; class LossBasedBweV2 { @@ -58,20 +59,22 @@ class LossBasedBweV2 { // initialized with a BWE and then has received enough `PacketResult`s. bool IsReady() const; + // Returns true if loss based BWE is ready to be used in the start phase. + bool ReadyToUseInStartPhase() const; + // Returns `DataRate::PlusInfinity` if no BWE can be calculated. Result GetLossBasedResult() const; void SetAcknowledgedBitrate(DataRate acknowledged_bitrate); - void SetBandwidthEstimate(DataRate bandwidth_estimate); void SetMinMaxBitrate(DataRate min_bitrate, DataRate max_bitrate); void UpdateBandwidthEstimate( rtc::ArrayView packet_results, DataRate delay_based_estimate, - BandwidthUsage delay_detector_state, - absl::optional probe_bitrate, - DataRate upper_link_capacity, bool in_alr); + // For unit testing only. + void SetBandwidthEstimate(DataRate bandwidth_estimate); + private: struct ChannelParameters { double inherent_loss = 0.0; @@ -96,6 +99,7 @@ class LossBasedBweV2 { double newton_step_size = 0.0; bool append_acknowledged_rate_candidate = true; bool append_delay_based_estimate_candidate = false; + bool append_upper_bound_candidate_in_alr = false; TimeDelta observation_duration_lower_bound = TimeDelta::Zero(); int observation_window_size = 0; double sending_rate_smoothing_factor = 0.0; @@ -104,19 +108,19 @@ class LossBasedBweV2 { double instant_upper_bound_loss_offset = 0.0; double temporal_weight_factor = 0.0; double bandwidth_backoff_lower_bound_factor = 0.0; - bool trendline_integration_enabled = false; - int trendline_observations_window_size = 0; double max_increase_factor = 0.0; TimeDelta delayed_increase_window = TimeDelta::Zero(); - bool use_acked_bitrate_only_when_overusing = false; bool not_increase_if_inherent_loss_less_than_average_loss = false; double high_loss_rate_threshold = 1.0; DataRate bandwidth_cap_at_high_loss_rate = DataRate::MinusInfinity(); double slope_of_bwe_high_loss_func = 1000.0; - bool probe_integration_enabled = false; - TimeDelta probe_expiration = TimeDelta::Zero(); - bool bound_by_upper_link_capacity_when_loss_limited = false; bool not_use_acked_rate_in_alr = false; + bool use_in_start_phase = false; + int min_num_observations = 0; + double lower_bound_by_acked_rate_factor = 0.0; + double hold_duration_factor = 0.0; + bool use_byte_loss_rate = false; + TimeDelta padding_duration = TimeDelta::Zero(); }; struct Derivatives { @@ -131,6 +135,8 @@ class LossBasedBweV2 { int num_lost_packets = 0; int num_received_packets = 0; DataRate sending_rate = DataRate::MinusInfinity(); + DataSize size = DataSize::Zero(); + DataSize lost_size = DataSize::Zero(); int id = -1; }; @@ -138,6 +144,12 @@ class LossBasedBweV2 { int num_packets = 0; int num_lost_packets = 0; DataSize size = DataSize::Zero(); + DataSize lost_size = DataSize::Zero(); + }; + + struct PaddingInfo { + DataRate padding_rate = DataRate::MinusInfinity(); + Timestamp padding_timestamp = Timestamp::MinusInfinity(); }; static absl::optional CreateConfig( @@ -146,6 +158,8 @@ class LossBasedBweV2 { // Returns `0.0` if not enough loss statistics have been received. double GetAverageReportedLossRatio() const; + double GetAverageReportedPacketLossRatio() const; + double GetAverageReportedByteLossRatio() const; std::vector GetCandidates(bool in_alr) const; DataRate GetCandidateBandwidthUpperBound() const; Derivatives GetDerivatives(const ChannelParameters& channel_parameters) const; @@ -158,51 +172,41 @@ class LossBasedBweV2 { DataRate GetSendingRate(DataRate instantaneous_sending_rate) const; DataRate GetInstantUpperBound() const; void CalculateInstantUpperBound(); + DataRate GetInstantLowerBound() const; + void CalculateInstantLowerBound(); void CalculateTemporalWeights(); void NewtonsMethodUpdate(ChannelParameters& channel_parameters) const; - // Returns false if there exists a kBwOverusing or kBwUnderusing in the - // window. - bool TrendlineEsimateAllowBitrateIncrease() const; - - // Returns true if there exists an overusing state in the window. - bool TrendlineEsimateAllowEmergencyBackoff() const; - // Returns false if no observation was created. - bool PushBackObservation(rtc::ArrayView packet_results, - BandwidthUsage delay_detector_state); - void UpdateTrendlineEstimator( - const std::vector& packet_feedbacks, - Timestamp at_time); - void UpdateDelayDetector(BandwidthUsage delay_detector_state); - bool IsEstimateIncreasingWhenLossLimited( - const ChannelParameters& best_candidate); - bool IsBandwidthLimitedDueToLoss() const; - void SetProbeBitrate(absl::optional probe_bitrate); - bool IsRequestingProbe() const; + bool PushBackObservation(rtc::ArrayView packet_results); + void UpdateResult(); + bool IsEstimateIncreasingWhenLossLimited(DataRate old_estimate, + DataRate new_estimate); + bool IsInLossLimitedState() const; + bool CanKeepIncreasingState(DataRate estimate) const; absl::optional acknowledged_bitrate_; absl::optional config_; - ChannelParameters current_estimate_; + ChannelParameters current_best_estimate_; int num_observations_ = 0; std::vector observations_; PartialObservation partial_observation_; Timestamp last_send_time_most_recent_observation_ = Timestamp::PlusInfinity(); Timestamp last_time_estimate_reduced_ = Timestamp::MinusInfinity(); absl::optional cached_instant_upper_bound_; + absl::optional cached_instant_lower_bound_; std::vector instant_upper_bound_temporal_weights_; std::vector temporal_weights_; - std::deque delay_detector_states_; Timestamp recovering_after_loss_timestamp_ = Timestamp::MinusInfinity(); DataRate bandwidth_limit_in_current_window_ = DataRate::PlusInfinity(); DataRate min_bitrate_ = DataRate::KilobitsPerSec(1); DataRate max_bitrate_ = DataRate::PlusInfinity(); - LossBasedState current_state_ = LossBasedState::kDelayBasedEstimate; - DataRate probe_bitrate_ = DataRate::PlusInfinity(); DataRate delay_based_estimate_ = DataRate::PlusInfinity(); - DataRate upper_link_capacity_ = DataRate::PlusInfinity(); - Timestamp last_probe_timestamp_ = Timestamp::MinusInfinity(); + LossBasedBweV2::Result loss_based_result_ = LossBasedBweV2::Result(); + Timestamp last_hold_timestamp_ = Timestamp::MinusInfinity(); + TimeDelta hold_duration_ = TimeDelta::Zero(); + PaddingInfo last_padding_info_ = PaddingInfo(); }; } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc index d745f37a5c..347e2a86d1 100644 --- a/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc +++ b/modules/congestion_controller/goog_cc/loss_based_bwe_v2_test.cc @@ -13,7 +13,6 @@ #include #include -#include "api/network_state_predictor.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" @@ -29,15 +28,14 @@ namespace { using ::webrtc::test::ExplicitKeyValueConfig; -constexpr TimeDelta kObservationDurationLowerBound = TimeDelta::Millis(200); +constexpr TimeDelta kObservationDurationLowerBound = TimeDelta::Millis(250); constexpr TimeDelta kDelayedIncreaseWindow = TimeDelta::Millis(300); constexpr double kMaxIncreaseFactor = 1.5; +constexpr int kPacketSize = 15'000; class LossBasedBweV2Test : public ::testing::TestWithParam { protected: - std::string Config(bool enabled, - bool valid, - bool trendline_integration_enabled) { + std::string Config(bool enabled, bool valid) { char buffer[1024]; rtc::SimpleStringBuilder config_string(buffer); @@ -54,16 +52,8 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { } else { config_string << ",BwRampupUpperBoundFactor:0.0"; } - - if (trendline_integration_enabled) { - config_string << ",TrendlineIntegrationEnabled:true"; - } else { - config_string << ",TrendlineIntegrationEnabled:false"; - } - config_string << ",CandidateFactors:1.1|1.0|0.95,HigherBwBiasFactor:0.01," - "DelayBasedCandidate:true," "InherentLossLowerBound:0.001,InherentLossUpperBoundBwBalance:" "14kbps," "InherentLossUpperBoundOffset:0.9,InitialInherentLossEstimate:0.01," @@ -71,7 +61,8 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { "SendingRateSmoothingFactor:0.01," "InstantUpperBoundTemporalWeightFactor:0.97," "InstantUpperBoundBwBalance:90kbps," - "InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98"; + "InstantUpperBoundLossOffset:0.1,TemporalWeightFactor:0.98," + "MinNumObservations:1"; config_string.AppendFormat( ",ObservationDurationLowerBound:%dms", @@ -85,11 +76,23 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { return config_string.str(); } + std::string ShortObservationConfig(std::string custom_config) { + char buffer[1024]; + rtc::SimpleStringBuilder config_string(buffer); + + config_string << "WebRTC-Bwe-LossBasedBweV2/" + "MinNumObservations:1,ObservationWindowSize:2,"; + config_string << custom_config; + config_string << "/"; + + return config_string.str(); + } + std::vector CreatePacketResultsWithReceivedPackets( Timestamp first_packet_timestamp) { std::vector enough_feedback(2); - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.size = DataSize::Bytes(kPacketSize); + enough_feedback[1].sent_packet.size = DataSize::Bytes(kPacketSize); enough_feedback[0].sent_packet.send_time = first_packet_timestamp; enough_feedback[1].sent_packet.send_time = first_packet_timestamp + kObservationDurationLowerBound; @@ -100,12 +103,13 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { return enough_feedback; } - std::vector CreatePacketResultsWith10pLossRate( - Timestamp first_packet_timestamp) { + std::vector CreatePacketResultsWith10pPacketLossRate( + Timestamp first_packet_timestamp, + DataSize lost_packet_size = DataSize::Bytes(kPacketSize)) { std::vector enough_feedback(10); - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.size = DataSize::Bytes(kPacketSize); for (unsigned i = 0; i < enough_feedback.size(); ++i) { - enough_feedback[i].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[i].sent_packet.size = DataSize::Bytes(kPacketSize); enough_feedback[i].sent_packet.send_time = first_packet_timestamp + static_cast(i) * kObservationDurationLowerBound; @@ -114,14 +118,15 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { static_cast(i + 1) * kObservationDurationLowerBound; } enough_feedback[9].receive_time = Timestamp::PlusInfinity(); + enough_feedback[9].sent_packet.size = lost_packet_size; return enough_feedback; } - std::vector CreatePacketResultsWith50pLossRate( + std::vector CreatePacketResultsWith50pPacketLossRate( Timestamp first_packet_timestamp) { std::vector enough_feedback(2); - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.size = DataSize::Bytes(kPacketSize); + enough_feedback[1].sent_packet.size = DataSize::Bytes(kPacketSize); enough_feedback[0].sent_packet.send_time = first_packet_timestamp; enough_feedback[1].sent_packet.send_time = first_packet_timestamp + kObservationDurationLowerBound; @@ -134,8 +139,8 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { std::vector CreatePacketResultsWith100pLossRate( Timestamp first_packet_timestamp) { std::vector enough_feedback(2); - enough_feedback[0].sent_packet.size = DataSize::Bytes(15'000); - enough_feedback[1].sent_packet.size = DataSize::Bytes(15'000); + enough_feedback[0].sent_packet.size = DataSize::Bytes(kPacketSize); + enough_feedback[1].sent_packet.size = DataSize::Bytes(kPacketSize); enough_feedback[0].sent_packet.send_time = first_packet_timestamp; enough_feedback[1].sent_packet.send_time = first_packet_timestamp + kObservationDurationLowerBound; @@ -145,135 +150,124 @@ class LossBasedBweV2Test : public ::testing::TestWithParam { } }; -TEST_P(LossBasedBweV2Test, EnabledWhenGivenValidConfigurationValues) { +TEST_F(LossBasedBweV2Test, EnabledWhenGivenValidConfigurationValues) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_TRUE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST_P(LossBasedBweV2Test, DisabledWhenGivenDisabledConfiguration) { +TEST_F(LossBasedBweV2Test, DisabledWhenGivenDisabledConfiguration) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/false, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/false, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonValidConfigurationValues) { +TEST_F(LossBasedBweV2Test, DisabledWhenGivenNonValidConfigurationValues) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/false, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/false)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST_P(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) { +TEST_F(LossBasedBweV2Test, DisabledWhenGivenNonPositiveCandidateFactor) { ExplicitKeyValueConfig key_value_config_negative_candidate_factor( - "WebRTC-Bwe-LossBasedBweV2/Enabled:true,CandidateFactors:-1.3|1.1/"); + "WebRTC-Bwe-LossBasedBweV2/CandidateFactors:-1.3|1.1/"); LossBasedBweV2 loss_based_bandwidth_estimator_1( &key_value_config_negative_candidate_factor); EXPECT_FALSE(loss_based_bandwidth_estimator_1.IsEnabled()); ExplicitKeyValueConfig key_value_config_zero_candidate_factor( - "WebRTC-Bwe-LossBasedBweV2/Enabled:true,CandidateFactors:0.0|1.1/"); + "WebRTC-Bwe-LossBasedBweV2/CandidateFactors:0.0|1.1/"); LossBasedBweV2 loss_based_bandwidth_estimator_2( &key_value_config_zero_candidate_factor); EXPECT_FALSE(loss_based_bandwidth_estimator_2.IsEnabled()); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, DisabledWhenGivenConfigurationThatDoesNotAllowGeneratingCandidates) { ExplicitKeyValueConfig key_value_config( "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false," + "CandidateFactors:1.0,AckedRateCandidate:false," "DelayBasedCandidate:false/"); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); EXPECT_FALSE(loss_based_bandwidth_estimator.IsEnabled()); } -TEST_P(LossBasedBweV2Test, ReturnsDelayBasedEstimateWhenDisabled) { +TEST_F(LossBasedBweV2Test, ReturnsDelayBasedEstimateWhenDisabled) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/false, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/false, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( /*packet_results=*/{}, /*delay_based_estimate=*/DataRate::KilobitsPerSec(100), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, DataRate::KilobitsPerSec(100)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, ReturnsDelayBasedEstimateWhenWhenGivenNonValidConfigurationValues) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/false, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/false)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( /*packet_results=*/{}, /*delay_based_estimate=*/DataRate::KilobitsPerSec(100), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, DataRate::KilobitsPerSec(100)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, BandwidthEstimateGivenInitializationAndThenFeedback) { std::vector enough_feedback = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_TRUE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult() .bandwidth_estimate.IsFinite()); } -TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { +TEST_F(LossBasedBweV2Test, NoBandwidthEstimateGivenNoInitialization) { std::vector enough_feedback = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult() .bandwidth_estimate.IsPlusInfinity()); } -TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { +TEST_F(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { // Create packet results where the observation duration is less than the lower // bound. PacketResult not_enough_feedback[2]; @@ -288,8 +282,7 @@ TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { Timestamp::Zero() + kObservationDurationLowerBound; ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -301,16 +294,15 @@ TEST_P(LossBasedBweV2Test, NoBandwidthEstimateGivenNotEnoughFeedback) { loss_based_bandwidth_estimator.UpdateBandwidthEstimate( not_enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_FALSE(loss_based_bandwidth_estimator.IsReady()); EXPECT_TRUE(loss_based_bandwidth_estimator.GetLossBasedResult() .bandwidth_estimate.IsPlusInfinity()); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, SetValueIsTheEstimateUntilAdditionalFeedbackHasBeenReceived) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( @@ -321,17 +313,15 @@ TEST_P(LossBasedBweV2Test, 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_NE( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, @@ -346,16 +336,15 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_NE( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, DataRate::KilobitsPerSec(600)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, SetAcknowledgedBitrateOnlyAffectsTheBweWhenAdditionalFeedbackIsGiven) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( @@ -366,8 +355,7 @@ TEST_P(LossBasedBweV2Test, 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator_1(&key_value_config); LossBasedBweV2 loss_based_bandwidth_estimator_2(&key_value_config); @@ -377,14 +365,12 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator_1.GetLossBasedResult().bandwidth_estimate, @@ -399,29 +385,26 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator_1.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); loss_based_bandwidth_estimator_2.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_NE( loss_based_bandwidth_estimator_1.GetLossBasedResult().bandwidth_estimate, loss_based_bandwidth_estimator_2.GetLossBasedResult().bandwidth_estimate); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, BandwidthEstimateIsCappedToBeTcpFairGivenTooHighLossRate) { std::vector enough_feedback_no_received_packets = CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -429,54 +412,16 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_no_received_packets, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, DataRate::KilobitsPerSec(100)); } -TEST_P(LossBasedBweV2Test, BandwidthEstimateNotIncreaseWhenNetworkUnderusing) { - if (!GetParam()) { - GTEST_SKIP() << "This test should run only if " - "trendline_integration_enabled is enabled"; - } - std::vector enough_feedback_1 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero()); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - 2 * kObservationDurationLowerBound); - - ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - EXPECT_LE( - loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - EXPECT_LE( - loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, - DataRate::KilobitsPerSec(600)); -} - // When network is normal, estimate can increase but never be higher than // the delay based estimate. -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, BandwidthEstimateCappedByDelayBasedEstimateWhenNetworkNormal) { // Create two packet results, network is in normal state, 100% packets are // received, and no delay increase. @@ -488,17 +433,15 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero() + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // If the delay based estimate is infinity, then loss based estimate increases // and not bounded by delay based estimate. EXPECT_GT( @@ -506,9 +449,8 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::KilobitsPerSec(500), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // If the delay based estimate is not infinity, then loss based estimate is // bounded by delay based estimate. EXPECT_EQ( @@ -518,11 +460,11 @@ TEST_P(LossBasedBweV2Test, // When loss based bwe receives a strong signal of overusing and an increase in // loss rate, it should acked bitrate for emegency backoff. -TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { +TEST_F(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { // Create two packet results, first packet has 50% loss rate, second packet // has 100% loss rate. std::vector enough_feedback_1 = - CreatePacketResultsWith50pLossRate( + CreatePacketResultsWith50pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); std::vector enough_feedback_2 = CreatePacketResultsWith100pLossRate( @@ -530,8 +472,7 @@ TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( @@ -541,16 +482,12 @@ TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { // Update estimate when network is overusing, and 50% loss rate. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + /*in_alr=*/false); // Update estimate again when network is continuously overusing, and 100% // loss rate. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + /*in_alr=*/false); // The estimate bitrate now is backed off based on acked bitrate. EXPECT_LE( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, @@ -559,13 +496,12 @@ TEST_P(LossBasedBweV2Test, UseAckedBitrateForEmegencyBackOff) { // When receiving the same packet feedback, loss based bwe ignores the feedback // and returns the current estimate. -TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { +TEST_F(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero()); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); @@ -574,18 +510,16 @@ TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); DataRate estimate_1 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; // Use the same feedback and check if the estimate is unchanged. loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); DataRate estimate_2 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; EXPECT_EQ(estimate_2, estimate_1); @@ -594,7 +528,7 @@ TEST_P(LossBasedBweV2Test, NoBweChangeIfObservationDurationUnchanged) { // When receiving feedback of packets that were sent within an observation // duration, and network is in the normal state, loss based bwe returns the // current estimate. -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, NoBweChangeIfObservationDurationIsSmallAndNetworkNormal) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( @@ -604,24 +538,21 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound - TimeDelta::Millis(1)); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); DataRate estimate_1 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); DataRate estimate_2 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; EXPECT_EQ(estimate_2, estimate_1); @@ -630,7 +561,7 @@ TEST_P(LossBasedBweV2Test, // When receiving feedback of packets that were sent within an observation // duration, and network is in the underusing state, loss based bwe returns the // current estimate. -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, NoBweIncreaseIfObservationDurationIsSmallAndNetworkUnderusing) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( @@ -640,72 +571,26 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound - TimeDelta::Millis(1)); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); DataRate estimate_1 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwUnderusing, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + /*in_alr=*/false); DataRate estimate_2 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; EXPECT_LE(estimate_2, estimate_1); } -// When receiving feedback of packets that were sent within an observation -// duration, network is overusing, and trendline integration is enabled, loss -// based bwe updates its estimate. -TEST_P(LossBasedBweV2Test, - UpdateEstimateIfObservationDurationIsSmallAndNetworkOverusing) { - if (!GetParam()) { - GTEST_SKIP() << "This test should run only if " - "trendline_integration_enabled is enabled"; - } - std::vector enough_feedback_1 = - CreatePacketResultsWith50pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero()); - std::vector enough_feedback_2 = - CreatePacketResultsWith100pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound - TimeDelta::Millis(1)); - ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate( - DataRate::KilobitsPerSec(300)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - DataRate estimate_1 = - loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; - - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwOverusing, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - DataRate estimate_2 = - loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; - EXPECT_LT(estimate_2, estimate_1); -} - -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, IncreaseToDelayBasedEstimateIfNoLossOrDelayIncrease) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( @@ -715,38 +600,34 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero() + 2 * kObservationDurationLowerBound); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, delay_based_estimate); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2, + delay_based_estimate, + /*in_alr=*/false); EXPECT_EQ( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, delay_based_estimate); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, IncreaseByMaxIncreaseFactorAfterLossBasedBweBacksOff) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "CandidateFactors:1.2|1|0.5," "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:1.5,BwRampupUpperBoundFactor:" - "2.0,NotIncreaseIfInherentLossLessThanAverageLoss:false/"); + "MaxIncreaseFactor:1.5,NotIncreaseIfInherentLossLessThanAverageLoss:" + "false")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); DataRate acked_rate = DataRate::KilobitsPerSec(300); @@ -758,10 +639,9 @@ TEST_P(LossBasedBweV2Test, std::vector enough_feedback_1 = CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); LossBasedBweV2::Result result_at_loss = loss_based_bandwidth_estimator.GetLossBasedResult(); @@ -772,10 +652,9 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2, + delay_based_estimate, + /*in_alr=*/false); LossBasedBweV2::Result result_after_recovery = loss_based_bandwidth_estimator.GetLossBasedResult(); @@ -783,16 +662,13 @@ TEST_P(LossBasedBweV2Test, result_at_loss.bandwidth_estimate * 1.5); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, LossBasedStateIsDelayBasedEstimateAfterNetworkRecovering) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:100|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "CandidateFactors:100|1|0.5," "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:100," - "BwRampupUpperBoundFactor:" - "2.0,NotIncreaseIfInherentLossLessThanAverageLoss:false/"); + "MaxIncreaseFactor:100," + "NotIncreaseIfInherentLossLessThanAverageLoss:false")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(600); DataRate acked_rate = DataRate::KilobitsPerSec(300); @@ -804,10 +680,9 @@ TEST_P(LossBasedBweV2Test, std::vector enough_feedback_1 = CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, LossBasedState::kDecreasing); @@ -818,10 +693,9 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2, + delay_based_estimate, + /*in_alr=*/false); EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, LossBasedState::kDelayBasedEstimate); @@ -832,39 +706,31 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound * 2); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_3, + delay_based_estimate, + /*in_alr=*/false); EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, LossBasedState::kDelayBasedEstimate); } -TEST_P(LossBasedBweV2Test, - LossBasedStateIsNotDelayBasedEstimateIfDelayBasedEsimtateInfinite) { +TEST_F(LossBasedBweV2Test, + LossBasedStateIsNotDelayBasedEstimateIfDelayBasedEstimateInfinite) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:100|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:100," - "BwRampupUpperBoundFactor:" - "2.0/"); + ShortObservationConfig("CandidateFactors:100|1|0.5," + "InstantUpperBoundBwBalance:10000kbps," + "MaxIncreaseFactor:100")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::PlusInfinity(); - DataRate acked_rate = DataRate::KilobitsPerSec(300); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); // Create some loss to create the loss limited scenario. std::vector enough_feedback_1 = CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + enough_feedback_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, LossBasedState::kDecreasing); @@ -876,29 +742,25 @@ TEST_P(LossBasedBweV2Test, loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + enough_feedback_2, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); EXPECT_NE(loss_based_bandwidth_estimator.GetLossBasedResult().state, LossBasedState::kDelayBasedEstimate); } // After loss based bwe backs off, the next estimate is capped by // a factor of acked bitrate. -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, IncreaseByFactorOfAckedBitrateAfterLossBasedBweBacksOff) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,LossThresholdOfHighBandwidthPreference:0.99," + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "LossThresholdOfHighBandwidthPreference:0.99," "BwRampupUpperBoundFactor:1.2," - "InherentLossUpperBoundOffset:0.9,ObservationDurationLowerBound:200ms/"); + // Set InstantUpperBoundBwBalance high to disable InstantUpperBound cap. + "InstantUpperBoundBwBalance:10000kbps,")); std::vector enough_feedback_1 = CreatePacketResultsWith100pLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); - std::vector enough_feedback_2 = - CreatePacketResultsWith10pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); @@ -906,35 +768,56 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(300)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + LossBasedBweV2::Result result = + loss_based_bandwidth_estimator.GetLossBasedResult(); + DataRate estimate_1 = result.bandwidth_estimate; + ASSERT_LT(estimate_1.kbps(), 600); - // Change the acked bitrate to make sure that the estimate is bounded by a - // factor of acked bitrate. - DataRate acked_bitrate = DataRate::KilobitsPerSec(50); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_bitrate); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(estimate_1 * 0.9); + + int feedback_count = 1; + while (feedback_count < 5 && result.state != LossBasedState::kIncreasing) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + feedback_count++ * kObservationDurationLowerBound), + delay_based_estimate, + /*in_alr=*/false); + result = loss_based_bandwidth_estimator.GetLossBasedResult(); + } + ASSERT_EQ(result.state, LossBasedState::kIncreasing); // The estimate is capped by acked_bitrate * BwRampupUpperBoundFactor. - DataRate estimate_2 = - loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; - EXPECT_EQ(estimate_2, acked_bitrate * 1.2); + EXPECT_EQ(result.bandwidth_estimate, estimate_1 * 0.9 * 1.2); + + // But if acked bitrate decrease, BWE does not decrease when there is no + // loss. + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(estimate_1 * 0.9); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + feedback_count++ * kObservationDurationLowerBound), + delay_based_estimate, + /*in_alr=*/false); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + result.bandwidth_estimate); } // After loss based bwe backs off, the estimate is bounded during the delayed // window. -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, EstimateBitrateIsBoundedDuringDelayedWindowAfterLossBasedBweBacksOff) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero()); std::vector enough_feedback_2 = - CreatePacketResultsWith50pLossRate( + CreatePacketResultsWith50pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kDelayedIncreaseWindow - TimeDelta::Millis(2)); std::vector enough_feedback_3 = @@ -942,8 +825,7 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero() + kDelayedIncreaseWindow - TimeDelta::Millis(1)); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); @@ -951,28 +833,25 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(300)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); // Increase the acknowledged bitrate to make sure that the estimate is not // capped too low. loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(5000)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2, + delay_based_estimate, + /*in_alr=*/false); // The estimate is capped by current_estimate * kMaxIncreaseFactor because // it recently backed off. DataRate estimate_2 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_3, + delay_based_estimate, + /*in_alr=*/false); // The latest estimate is the same as the previous estimate since the sent // packets were sent within the DelayedIncreaseWindow. EXPECT_EQ( @@ -981,7 +860,7 @@ TEST_P(LossBasedBweV2Test, } // The estimate is not bounded after the delayed increase window. -TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { +TEST_F(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { std::vector enough_feedback_1 = CreatePacketResultsWithReceivedPackets( /*first_packet_timestamp=*/Timestamp::Zero()); @@ -994,8 +873,7 @@ TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { /*first_packet_timestamp=*/Timestamp::Zero() + kDelayedIncreaseWindow + TimeDelta::Millis(1)); ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); @@ -1003,64 +881,56 @@ TEST_P(LossBasedBweV2Test, KeepIncreasingEstimateAfterDelayedIncreaseWindow) { DataRate::KilobitsPerSec(600)); loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(300)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_1, + delay_based_estimate, + /*in_alr=*/false); // Increase the acknowledged bitrate to make sure that the estimate is not // capped too low. loss_based_bandwidth_estimator.SetAcknowledgedBitrate( DataRate::KilobitsPerSec(5000)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_2, + delay_based_estimate, + /*in_alr=*/false); // The estimate is capped by current_estimate * kMaxIncreaseFactor because it // recently backed off. DataRate estimate_2 = loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate(enough_feedback_3, + delay_based_estimate, + /*in_alr=*/false); // The estimate can continue increasing after the DelayedIncreaseWindow. EXPECT_GE( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, estimate_2); } -TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms," - "NotIncreaseIfInherentLossLessThanAverageLoss:true/"); +TEST_F(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "CandidateFactors:1.2," + "NotIncreaseIfInherentLossLessThanAverageLoss:true")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); loss_based_bandwidth_estimator.SetBandwidthEstimate( DataRate::KilobitsPerSec(600)); std::vector enough_feedback_10p_loss_1 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + enough_feedback_10p_loss_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); std::vector enough_feedback_10p_loss_2 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + enough_feedback_10p_loss_2, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); // Do not increase the bitrate because inherent loss is less than average loss EXPECT_EQ( @@ -1068,16 +938,11 @@ TEST_P(LossBasedBweV2Test, NotIncreaseIfInherentLossLessThanAverageLoss) { DataRate::KilobitsPerSec(600)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, SelectHighBandwidthCandidateIfLossRateIsLessThanThreshold) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "20,NotIncreaseIfInherentLossLessThanAverageLoss:false/"); + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "LossThresholdOfHighBandwidthPreference:0.20," + "NotIncreaseIfInherentLossLessThanAverageLoss:false")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); @@ -1085,21 +950,21 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); std::vector enough_feedback_10p_loss_1 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_10p_loss_2 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // Because LossThresholdOfHighBandwidthPreference is 20%, the average loss is // 10%, bandwidth estimate should increase. @@ -1108,16 +973,10 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, SelectLowBandwidthCandidateIfLossRateIsIsHigherThanThreshold) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|0.8,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "05/"); + ShortObservationConfig("LossThresholdOfHighBandwidthPreference:0.05")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); @@ -1125,21 +984,21 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); std::vector enough_feedback_10p_loss_1 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_10p_loss_2 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // Because LossThresholdOfHighBandwidthPreference is 5%, the average loss is // 10%, bandwidth estimate should decrease. @@ -1148,255 +1007,10 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); } -TEST_P(LossBasedBweV2Test, LimitByProbeResultWhenRecoveringFromLoss) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps,DelayedIncreaseWindow:100s," - "DelayBasedCandidate:true,MaxIncreaseFactor:1.3," - "BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true/"); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); - DataRate acked_rate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); - - // Create some loss to create the loss limited scenario. - std::vector enough_feedback_1 = - CreatePacketResultsWith100pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - - // Network recovers after loss - DataRate probe_estimate = DataRate::KilobitsPerSec(300); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - probe_estimate, /*upper_link_capacity=*/DataRate::PlusInfinity(), - /*in_alr=*/false); - - for (int i = 2; i < 5; ++i) { - enough_feedback_2 = CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound * i); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), - /*in_alr=*/false); - LossBasedBweV2::Result result_after_recovery = - loss_based_bandwidth_estimator.GetLossBasedResult(); - EXPECT_LE(result_after_recovery.bandwidth_estimate, probe_estimate); - } -} - -TEST_P(LossBasedBweV2Test, NotLimitByProbeResultWhenProbeResultIsExpired) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps,DelayedIncreaseWindow:100s," - "DelayBasedCandidate:true,MaxIncreaseFactor:1.3," - "BwRampupUpperBoundFactor:2.0,ProbeIntegrationEnabled:true," - "ProbeExpiration:10s/"); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); - DataRate acked_rate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); - - // Create some loss to create the loss limited scenario. - std::vector enough_feedback_1 = - CreatePacketResultsWith100pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - - // Network recovers after loss - DataRate probe_estimate = DataRate::KilobitsPerSec(300); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - probe_estimate, /*upper_link_capacity=*/DataRate::PlusInfinity(), - /*in_alr=*/false); - - for (int i = 2; i < 5; ++i) { - enough_feedback_2 = CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound * i); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), - /*in_alr=*/false); - } - - std::vector enough_feedback_3 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound + TimeDelta::Seconds(11)); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_3, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), - /*in_alr=*/false); - - // Probe result is expired after 10s. - LossBasedBweV2::Result result_after_recovery = - loss_based_bandwidth_estimator.GetLossBasedResult(); - EXPECT_GT(result_after_recovery.bandwidth_estimate, probe_estimate); -} - -// If BoundByUpperLinkCapacityWhenLossLimited is enabled, the estimate is -// bounded by the upper link capacity when bandwidth is loss limited. -TEST_P(LossBasedBweV2Test, BoundEstimateByUpperLinkCapacityWhenLossLimited) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:1000," - "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:" - "true/"); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); - DataRate acked_rate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); - - // Create some loss to create the loss limited scenario. - std::vector enough_feedback_1 = - CreatePacketResultsWith100pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - - // Network recovers after loss. - DataRate upper_link_capacity = DataRate::KilobitsPerSec(10); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, upper_link_capacity, /*in_alr=*/false); - - LossBasedBweV2::Result result_after_recovery = - loss_based_bandwidth_estimator.GetLossBasedResult(); - EXPECT_EQ(result_after_recovery.bandwidth_estimate, upper_link_capacity); -} - -// If BoundByUpperLinkCapacityWhenLossLimited is enabled, the estimate is not -// bounded by the upper link capacity when bandwidth is not loss limited. -TEST_P(LossBasedBweV2Test, - NotBoundEstimateByUpperLinkCapacityWhenNotLossLimited) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:1000," - "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:" - "true/"); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); - DataRate acked_rate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); - - // Create a normal network without loss - std::vector enough_feedback_1 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - - DataRate upper_link_capacity = DataRate::KilobitsPerSec(10); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, upper_link_capacity, /*in_alr=*/false); - - LossBasedBweV2::Result loss_based_result = - loss_based_bandwidth_estimator.GetLossBasedResult(); - EXPECT_GT(loss_based_result.bandwidth_estimate, upper_link_capacity); -} - -// If BoundByUpperLinkCapacityWhenLossLimited is disabled, the estimate is not -// bounded by the upper link capacity. -TEST_P(LossBasedBweV2Test, NotBoundEstimateByUpperLinkCapacity) { - ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.2|1|0.5,AckedRateCandidate:true," - "ObservationWindowSize:2,ObservationDurationLowerBound:200ms," - "InstantUpperBoundBwBalance:10000kbps," - "DelayBasedCandidate:true,MaxIncreaseFactor:1000," - "BwRampupUpperBoundFactor:2.0,BoundByUpperLinkCapacityWhenLossLimited:" - "false/"); - LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); - DataRate delay_based_estimate = DataRate::KilobitsPerSec(5000); - DataRate acked_rate = DataRate::KilobitsPerSec(300); - loss_based_bandwidth_estimator.SetBandwidthEstimate( - DataRate::KilobitsPerSec(600)); - loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acked_rate); - - // Create some loss to create the loss limited scenario. - std::vector enough_feedback_1 = - CreatePacketResultsWith100pLossRate( - /*first_packet_timestamp=*/Timestamp::Zero()); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_1, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); - - // Network recovers after loss. - DataRate upper_link_capacity = DataRate::KilobitsPerSec(10); - std::vector enough_feedback_2 = - CreatePacketResultsWithReceivedPackets( - /*first_packet_timestamp=*/Timestamp::Zero() + - kObservationDurationLowerBound); - loss_based_bandwidth_estimator.UpdateBandwidthEstimate( - enough_feedback_2, delay_based_estimate, BandwidthUsage::kBwNormal, - /*probe_estimate=*/absl::nullopt, upper_link_capacity, /*in_alr=*/false); - - LossBasedBweV2::Result result_after_recovery = - loss_based_bandwidth_estimator.GetLossBasedResult(); - EXPECT_GT(result_after_recovery.bandwidth_estimate, upper_link_capacity); -} - -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, StricterBoundUsingHighLossRateThresholdAt10pLossRate) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "05,HighLossRateThreshold:0.09/"); + ShortObservationConfig("HighLossRateThreshold:0.09")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1406,21 +1020,21 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); std::vector enough_feedback_10p_loss_1 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_10p_loss_2 = - CreatePacketResultsWith10pLossRate( + CreatePacketResultsWith10pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_10p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // At 10% loss rate and high loss rate threshold to be 10%, cap the estimate // to be 500 * 1000-0.1 = 400kbps. @@ -1429,16 +1043,10 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(400)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, StricterBoundUsingHighLossRateThresholdAt50pLossRate) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "05,HighLossRateThreshold:0.3/"); + ShortObservationConfig("HighLossRateThreshold:0.3")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1448,21 +1056,21 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(600)); std::vector enough_feedback_50p_loss_1 = - CreatePacketResultsWith50pLossRate( + CreatePacketResultsWith50pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_50p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_50p_loss_2 = - CreatePacketResultsWith50pLossRate( + CreatePacketResultsWith50pPacketLossRate( /*first_packet_timestamp=*/Timestamp::Zero() + kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_50p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // At 50% loss rate and high loss rate threshold to be 30%, cap the estimate // to be the min bitrate. @@ -1471,16 +1079,10 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(10)); } -TEST_P(LossBasedBweV2Test, +TEST_F(LossBasedBweV2Test, StricterBoundUsingHighLossRateThresholdAt100pLossRate) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.0,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "05,HighLossRateThreshold:0.3/"); + ShortObservationConfig("HighLossRateThreshold:0.3")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1494,8 +1096,8 @@ TEST_P(LossBasedBweV2Test, /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_100p_loss_2 = CreatePacketResultsWith100pLossRate( @@ -1503,8 +1105,8 @@ TEST_P(LossBasedBweV2Test, kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // At 100% loss rate and high loss rate threshold to be 30%, cap the estimate // to be the min bitrate. @@ -1513,15 +1115,9 @@ TEST_P(LossBasedBweV2Test, DataRate::KilobitsPerSec(10)); } -TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { +TEST_F(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.1|1.0|0.9,AckedRateCandidate:false," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,HigherBwBiasFactor:1000," - "HigherLogBwBiasFactor:1000,LossThresholdOfHighBandwidthPreference:0." - "05,HighLossRateThreshold:0.3/"); + ShortObservationConfig("HighLossRateThreshold:0.3")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1535,8 +1131,8 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // Make sure that the estimate is set to min bitrate because of 100% loss // rate. @@ -1551,8 +1147,8 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { kObservationDurationLowerBound); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_0p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); std::vector enough_feedback_0p_loss_2 = CreatePacketResultsWithReceivedPackets( @@ -1560,8 +1156,8 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { kObservationDurationLowerBound * 2); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_0p_loss_2, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // The estimate increases as network recovers. EXPECT_GT( @@ -1569,10 +1165,9 @@ TEST_P(LossBasedBweV2Test, EstimateRecoversAfterHighLoss) { DataRate::KilobitsPerSec(10)); } -TEST_P(LossBasedBweV2Test, EstimateIsNotHigherThanMaxBitrate) { +TEST_F(LossBasedBweV2Test, EstimateIsNotHigherThanMaxBitrate) { ExplicitKeyValueConfig key_value_config( - Config(/*enabled=*/true, /*valid=*/true, - /*trendline_integration_enabled=*/GetParam())); + Config(/*enabled=*/true, /*valid=*/true)); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1584,21 +1179,17 @@ TEST_P(LossBasedBweV2Test, EstimateIsNotHigherThanMaxBitrate) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback, /*delay_based_estimate=*/DataRate::PlusInfinity(), - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); EXPECT_LE( loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, DataRate::KilobitsPerSec(1000)); } -TEST_P(LossBasedBweV2Test, NotBackOffToAckedRateInAlr) { +TEST_F(LossBasedBweV2Test, NotBackOffToAckedRateInAlr) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.1|1.0|0.9,AckedRateCandidate:true," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,NotUseAckedRateInAlr:true/"); + ShortObservationConfig("InstantUpperBoundBwBalance:100kbps")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1614,8 +1205,7 @@ TEST_P(LossBasedBweV2Test, NotBackOffToAckedRateInAlr) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/true); + /*in_alr=*/true); // Make sure that the estimate decreases but higher than acked rate. EXPECT_GT( @@ -1627,13 +1217,9 @@ TEST_P(LossBasedBweV2Test, NotBackOffToAckedRateInAlr) { DataRate::KilobitsPerSec(600)); } -TEST_P(LossBasedBweV2Test, BackOffToAckedRateIfNotInAlr) { +TEST_F(LossBasedBweV2Test, BackOffToAckedRateIfNotInAlr) { ExplicitKeyValueConfig key_value_config( - "WebRTC-Bwe-LossBasedBweV2/" - "Enabled:true,CandidateFactors:1.1|1.0|0.9,AckedRateCandidate:true," - "ObservationWindowSize:2," - "DelayBasedCandidate:true,InstantUpperBoundBwBalance:100kbps," - "ObservationDurationLowerBound:200ms,NotUseAckedRateInAlr:true/"); + ShortObservationConfig("InstantUpperBoundBwBalance:100kbps")); LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); loss_based_bandwidth_estimator.SetMinMaxBitrate( /*min_bitrate=*/DataRate::KilobitsPerSec(10), @@ -1649,8 +1235,8 @@ TEST_P(LossBasedBweV2Test, BackOffToAckedRateIfNotInAlr) { /*first_packet_timestamp=*/Timestamp::Zero()); loss_based_bandwidth_estimator.UpdateBandwidthEstimate( enough_feedback_100p_loss_1, delay_based_estimate, - BandwidthUsage::kBwNormal, /*probe_estimate=*/absl::nullopt, - /*upper_link_capacity=*/DataRate::PlusInfinity(), /*in_alr=*/false); + + /*in_alr=*/false); // Make sure that the estimate decreases but higher than acked rate. EXPECT_EQ( @@ -1658,9 +1244,472 @@ TEST_P(LossBasedBweV2Test, BackOffToAckedRateIfNotInAlr) { acked_rate); } -INSTANTIATE_TEST_SUITE_P(LossBasedBweV2Tests, - LossBasedBweV2Test, - ::testing::Bool()); +TEST_F(LossBasedBweV2Test, NotReadyToUseInStartPhase) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("UseInStartPhase:true")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + // Make sure that the estimator is not ready to use in start phase because of + // lacking TWCC feedback. + EXPECT_FALSE(loss_based_bandwidth_estimator.ReadyToUseInStartPhase()); +} + +TEST_F(LossBasedBweV2Test, ReadyToUseInStartPhase) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("UseInStartPhase:true")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + std::vector enough_feedback = + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback, /*delay_based_estimate=*/DataRate::KilobitsPerSec(600), + /*in_alr=*/false); + EXPECT_TRUE(loss_based_bandwidth_estimator.ReadyToUseInStartPhase()); +} + +TEST_F(LossBasedBweV2Test, BoundEstimateByAckedRate) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("LowerBoundByAckedRateFactor:1.0")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(500)); + + std::vector enough_feedback_100p_loss_1 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_100p_loss_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(500)); +} + +TEST_F(LossBasedBweV2Test, NotBoundEstimateByAckedRate) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("LowerBoundByAckedRateFactor:0.0")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(600)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(500)); + + std::vector enough_feedback_100p_loss_1 = + CreatePacketResultsWith100pLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_100p_loss_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + + EXPECT_LT( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(500)); +} + +TEST_F(LossBasedBweV2Test, HasDecreaseStateBecauseOfUpperBound) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "CandidateFactors:1.0,InstantUpperBoundBwBalance:10kbps")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(500)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(500)); + + std::vector enough_feedback_10p_loss_1 = + CreatePacketResultsWith10pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_10p_loss_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + + // Verify that the instant upper bound decreases the estimate, and state is + // updated to kDecreasing. + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(200)); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); +} + +TEST_F(LossBasedBweV2Test, HasIncreaseStateBecauseOfLowerBound) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "CandidateFactors:1.0,LowerBoundByAckedRateFactor:10.0")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000000)); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(500)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(1)); + + // Network has a high loss to create a loss scenario. + std::vector enough_feedback_50p_loss_1 = + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_50p_loss_1, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + + // Network still has a high loss, but better acked rate. + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(200)); + std::vector enough_feedback_50p_loss_2 = + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + enough_feedback_50p_loss_2, + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + + // Verify that the instant lower bound increases the estimate, and state is + // updated to kIncreasing. + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(200) * 10); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreasing); +} + +TEST_F(LossBasedBweV2Test, + EstimateIncreaseSlowlyFromInstantUpperBoundInAlrIfFieldTrial) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("UpperBoundCandidateInAlr:true")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(1000)); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate( + DataRate::KilobitsPerSec(150)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/true); + LossBasedBweV2::Result result_after_loss = + loss_based_bandwidth_estimator.GetLossBasedResult(); + ASSERT_EQ(result_after_loss.state, LossBasedState::kDecreasing); + + for (int feedback_count = 1; feedback_count <= 3; ++feedback_count) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + feedback_count * kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/true); + } + // Expect less than 100% increase. + EXPECT_LT( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + 2 * result_after_loss.bandwidth_estimate); +} + +TEST_F(LossBasedBweV2Test, HasDelayBasedStateIfLossBasedBweIsMax) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig("")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetMinMaxBitrate( + /*min_bitrate=*/DataRate::KilobitsPerSec(10), + /*max_bitrate=*/DataRate::KilobitsPerSec(1000)); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + /*feedback = */ CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(2000), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDelayBasedEstimate); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(1000)); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + /*feedback=*/CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(2000), + /*in_alr=*/false); + LossBasedBweV2::Result result = + loss_based_bandwidth_estimator.GetLossBasedResult(); + ASSERT_EQ(result.state, LossBasedState::kDecreasing); + ASSERT_LT(result.bandwidth_estimate, DataRate::KilobitsPerSec(1000)); + + // Eventually the estimator recovers to delay based state. + int feedback_count = 2; + while (feedback_count < 5 && + result.state != LossBasedState::kDelayBasedEstimate) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + /*feedback = */ CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + feedback_count++ * kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::KilobitsPerSec(2000), + /*in_alr=*/false); + result = loss_based_bandwidth_estimator.GetLossBasedResult(); + } + EXPECT_EQ(result.state, LossBasedState::kDelayBasedEstimate); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(1000)); +} + +TEST_F(LossBasedBweV2Test, IncreaseUsingPaddingStateIfFieldTrial) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("PaddingDuration:1000ms")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(2500)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreaseUsingPadding); +} + +TEST_F(LossBasedBweV2Test, DecreaseAfterPadding) { + ExplicitKeyValueConfig key_value_config(ShortObservationConfig( + "PaddingDuration:1000ms,BwRampupUpperBoundFactor:2.0")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(2500)); + DataRate acknowledged_bitrate = DataRate::KilobitsPerSec(51); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acknowledged_bitrate); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + ASSERT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + acknowledged_bitrate); + + acknowledged_bitrate = DataRate::KilobitsPerSec(26); + loss_based_bandwidth_estimator.SetAcknowledgedBitrate(acknowledged_bitrate); + int feedback_id = 1; + while (loss_based_bandwidth_estimator.GetLossBasedResult().state != + LossBasedState::kIncreaseUsingPadding) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * feedback_id), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + feedback_id++; + } + + const Timestamp estimate_increased = + Timestamp::Zero() + kObservationDurationLowerBound * feedback_id; + // The state is kIncreaseUsingPadding for a while without changing the + // estimate, which is limited by 2 * acked rate. + while (loss_based_bandwidth_estimator.GetLossBasedResult().state == + LossBasedState::kIncreaseUsingPadding) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * feedback_id), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + feedback_id++; + } + + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + const Timestamp start_decreasing = + Timestamp::Zero() + kObservationDurationLowerBound * (feedback_id - 1); + EXPECT_EQ(start_decreasing - estimate_increased, TimeDelta::Seconds(1)); +} + +TEST_F(LossBasedBweV2Test, IncreaseEstimateIfNotHold) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("HoldDurationFactor:0")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(2500)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + DataRate estimate = + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreasing); + EXPECT_GT( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate); +} + +TEST_F(LossBasedBweV2Test, IncreaseEstimateAfterHoldDuration) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("HoldDurationFactor:3")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(2500)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + DataRate estimate = + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; + + // During the hold duration, e.g. first 300ms, the estimate cannot increase. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate); + + // After the hold duration, the estimate can increase. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * 2), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreasing); + EXPECT_GE( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate); + + // Get another 50p packet loss. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * 3), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + estimate = + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; + + // During the hold duration, e.g. next 900ms, the estimate cannot increase. + for (int i = 4; i <= 6; ++i) { + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * i), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate); + } + + // After the hold duration, the estimate can increase again. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound * 7), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kIncreasing); + EXPECT_GE( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate); +} + +TEST_F(LossBasedBweV2Test, EndHoldDurationIfDelayBasedEstimateWorks) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("HoldDurationFactor:3")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(2500)); + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith50pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero()), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + ASSERT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + DataRate estimate = + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate; + + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWithReceivedPackets( + /*first_packet_timestamp=*/Timestamp::Zero() + + kObservationDurationLowerBound), + /*delay_based_estimate=*/estimate + DataRate::KilobitsPerSec(10), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDelayBasedEstimate); + EXPECT_EQ( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + estimate + DataRate::KilobitsPerSec(10)); +} + +TEST_F(LossBasedBweV2Test, UseByteLossRate) { + ExplicitKeyValueConfig key_value_config( + ShortObservationConfig("UseByteLossRate:true")); + LossBasedBweV2 loss_based_bandwidth_estimator(&key_value_config); + loss_based_bandwidth_estimator.SetBandwidthEstimate( + DataRate::KilobitsPerSec(500)); + // Create packet feedback having 10% packet loss but more than 50% byte loss. + loss_based_bandwidth_estimator.UpdateBandwidthEstimate( + CreatePacketResultsWith10pPacketLossRate( + /*first_packet_timestamp=*/Timestamp::Zero(), + /*lost_packet_size=*/DataSize::Bytes(kPacketSize * 20)), + /*delay_based_estimate=*/DataRate::PlusInfinity(), + /*in_alr=*/false); + EXPECT_EQ(loss_based_bandwidth_estimator.GetLossBasedResult().state, + LossBasedState::kDecreasing); + // The estimate is bounded by the instant upper bound due to high loss. + EXPECT_LT( + loss_based_bandwidth_estimator.GetLossBasedResult().bandwidth_estimate, + DataRate::KilobitsPerSec(150)); +} } // namespace } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc index a94f653157..99d7d4c591 100644 --- a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc +++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc @@ -13,12 +13,17 @@ #include #include +#include "absl/types/optional.h" #include "api/rtc_event_log/rtc_event_log.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "rtc_base/numerics/safe_conversions.h" namespace webrtc { namespace { diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h index d5a523b7f3..f11aeceeb8 100644 --- a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h +++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h @@ -11,12 +11,13 @@ #ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_BITRATE_ESTIMATOR_H_ #define MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_BITRATE_ESTIMATOR_H_ -#include #include #include "absl/types/optional.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" namespace webrtc { class RtcEventLog; diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc b/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc index 6b4146d2bf..efb9725215 100644 --- a/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc @@ -12,7 +12,14 @@ #include +#include + +#include "absl/types/optional.h" #include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "test/gtest.h" namespace webrtc { diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index 8fde515934..32b1b93c0b 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -11,18 +11,23 @@ #include "modules/congestion_controller/goog_cc/probe_controller.h" #include +#include #include #include -#include +#include #include "absl/strings/match.h" #include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/rtc_event_log/rtc_event_log.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" #include "system_wrappers/include/metrics.h" @@ -104,35 +109,23 @@ ProbeControllerConfig::ProbeControllerConfig( allocation_probe_max("alloc_probe_max", DataRate::PlusInfinity()), min_probe_packets_sent("min_probe_packets_sent", 5), min_probe_duration("min_probe_duration", TimeDelta::Millis(15)), - limit_probe_target_rate_to_loss_bwe("limit_probe_target_rate_to_loss_bwe", - false), loss_limited_probe_scale("loss_limited_scale", 1.5), skip_if_estimate_larger_than_fraction_of_max( "skip_if_est_larger_than_fraction_of_max", - 0.0), - not_probe_if_delay_increased("not_probe_if_delay_increased", false) { - ParseFieldTrial({&first_exponential_probe_scale, - &second_exponential_probe_scale, - &further_exponential_probe_scale, - &further_probe_threshold, - &alr_probing_interval, - &alr_probe_scale, - &probe_on_max_allocated_bitrate_change, - &first_allocation_probe_scale, - &second_allocation_probe_scale, - &allocation_allow_further_probing, - &min_probe_duration, - &network_state_estimate_probing_interval, - &probe_if_estimate_lower_than_network_state_estimate_ratio, - &estimate_lower_than_network_state_estimate_probing_interval, - &network_state_probe_scale, - &network_state_probe_duration, - &min_probe_packets_sent, - &limit_probe_target_rate_to_loss_bwe, - &loss_limited_probe_scale, - &skip_if_estimate_larger_than_fraction_of_max, - ¬_probe_if_delay_increased}, - key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); + 0.0) { + ParseFieldTrial( + {&first_exponential_probe_scale, &second_exponential_probe_scale, + &further_exponential_probe_scale, &further_probe_threshold, + &alr_probing_interval, &alr_probe_scale, + &probe_on_max_allocated_bitrate_change, &first_allocation_probe_scale, + &second_allocation_probe_scale, &allocation_allow_further_probing, + &min_probe_duration, &network_state_estimate_probing_interval, + &probe_if_estimate_lower_than_network_state_estimate_ratio, + &estimate_lower_than_network_state_estimate_probing_interval, + &network_state_probe_scale, &network_state_probe_duration, + &min_probe_packets_sent, &loss_limited_probe_scale, + &skip_if_estimate_larger_than_fraction_of_max}, + key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration ParseFieldTrial( @@ -157,7 +150,7 @@ ProbeControllerConfig::~ProbeControllerConfig() = default; ProbeController::ProbeController(const FieldTrialsView* key_value_config, RtcEventLog* event_log) - : network_available_(true), + : network_available_(false), enable_periodic_alr_probing_(false), in_rapid_recovery_experiment_(absl::StartsWith( key_value_config->Lookup(kBweRapidRecoveryExperiment), @@ -479,29 +472,21 @@ std::vector ProbeController::InitiateProbing( } DataRate estimate_capped_bitrate = DataRate::PlusInfinity(); - if (config_.limit_probe_target_rate_to_loss_bwe) { - switch (bandwidth_limited_cause_) { - case BandwidthLimitedCause::kLossLimitedBweDecreasing: - // If bandwidth estimate is decreasing because of packet loss, do not - // send probes. - return {}; - case BandwidthLimitedCause::kLossLimitedBweIncreasing: - estimate_capped_bitrate = - std::min(max_probe_bitrate, - estimated_bitrate_ * config_.loss_limited_probe_scale); - break; - case BandwidthLimitedCause::kDelayBasedLimited: - break; - default: - break; - } - } - if (config_.not_probe_if_delay_increased && - (bandwidth_limited_cause_ == - BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased || - bandwidth_limited_cause_ == - BandwidthLimitedCause::kRttBasedBackOffHighRtt)) { - return {}; + switch (bandwidth_limited_cause_) { + case BandwidthLimitedCause::kRttBasedBackOffHighRtt: + case BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased: + case BandwidthLimitedCause::kLossLimitedBwe: + RTC_LOG(LS_INFO) << "Not sending probe in bandwidth limited state."; + return {}; + case BandwidthLimitedCause::kLossLimitedBweIncreasing: + estimate_capped_bitrate = + std::min(max_probe_bitrate, + estimated_bitrate_ * config_.loss_limited_probe_scale); + break; + case BandwidthLimitedCause::kDelayBasedLimited: + break; + default: + break; } if (config_.network_state_estimate_probing_interval->IsFinite() && @@ -510,16 +495,15 @@ std::vector ProbeController::InitiateProbing( RTC_LOG(LS_INFO) << "Not sending probe, Network state estimate is zero"; return {}; } - estimate_capped_bitrate = - std::min({estimate_capped_bitrate, max_probe_bitrate, - network_estimate_->link_capacity_upper * - config_.network_state_probe_scale}); + estimate_capped_bitrate = std::min( + {estimate_capped_bitrate, max_probe_bitrate, + std::max(estimated_bitrate_, network_estimate_->link_capacity_upper * + config_.network_state_probe_scale)}); } std::vector pending_probes; for (DataRate bitrate : bitrates_to_probe) { RTC_DCHECK(!bitrate.IsZero()); - bitrate = std::min(bitrate, estimate_capped_bitrate); if (bitrate > max_probe_bitrate) { bitrate = max_probe_bitrate; diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index ae00182c68..feec81f2dc 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -13,16 +13,15 @@ #include -#include #include #include "absl/base/attributes.h" #include "absl/types/optional.h" #include "api/field_trials_view.h" #include "api/rtc_event_log/rtc_event_log.h" -#include "api/transport/network_control.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "rtc_base/experiments/field_trial_parser.h" @@ -72,14 +71,10 @@ struct ProbeControllerConfig { FieldTrialParameter min_probe_packets_sent; // The minimum probing duration. FieldTrialParameter min_probe_duration; - // Periodically probe when bandwidth estimate is loss limited. - FieldTrialParameter limit_probe_target_rate_to_loss_bwe; FieldTrialParameter loss_limited_probe_scale; // Dont send a probe if min(estimate, network state estimate) is larger than // this fraction of the set max bitrate. FieldTrialParameter skip_if_estimate_larger_than_fraction_of_max; - // Do not send probes if either overusing/underusing network or high rtt. - FieldTrialParameter not_probe_if_delay_increased; }; // Reason that bandwidth estimate is limited. Bandwidth estimate can be limited @@ -87,7 +82,7 @@ struct ProbeControllerConfig { // estimate. enum class BandwidthLimitedCause { kLossLimitedBweIncreasing = 0, - kLossLimitedBweDecreasing = 1, + kLossLimitedBwe = 1, kDelayBasedLimited = 2, kDelayBasedLimitedDelayIncreased = 3, kRttBasedBackOffHighRtt = 4 @@ -143,11 +138,6 @@ class ProbeController { ABSL_MUST_USE_RESULT std::vector Process( Timestamp at_time); - // Gets the value of field trial not_probe_if_delay_increased. - bool DontProbeIfDelayIncreased() { - return config_.not_probe_if_delay_increased; - } - private: enum class State { // Initial state where no probing has been triggered yet. diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 99efde80e0..94025b30ea 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -10,12 +10,14 @@ #include "modules/congestion_controller/goog_cc/probe_controller.h" #include +#include +#include "absl/strings/string_view.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" -#include "rtc_base/logging.h" #include "system_wrappers/include/clock.h" #include "test/explicit_key_value_config.h" #include "test/gmock.h" @@ -58,13 +60,28 @@ class ProbeControllerFixture { NiceMock mock_rtc_event_log; }; -TEST(ProbeControllerTest, InitiatesProbingAtStart) { +TEST(ProbeControllerTest, InitiatesProbingAfterSetBitrates) { + ProbeControllerFixture fixture; + std::unique_ptr probe_controller = + fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); + + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_GE(probes.size(), 2u); +} + +TEST(ProbeControllerTest, InitiatesProbingWhenNetworkAvailable) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); - auto probes = probe_controller->SetBitrates( + std::vector probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_THAT(probes, IsEmpty()); + probes = probe_controller->OnNetworkAvailability({.network_available = true}); EXPECT_GE(probes.size(), 2u); } @@ -72,6 +89,9 @@ TEST(ProbeControllerTest, SetsDefaultTargetDurationAndTargetProbeCount) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); std::vector probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_GE(probes.size(), 2u); @@ -87,6 +107,9 @@ TEST(ProbeControllerTest, "min_probe_packets_sent:2,min_probe_duration:123ms/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); std::vector probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_GE(probes.size(), 2u); @@ -113,6 +136,9 @@ TEST(ProbeControllerTest, CanConfigureInitialProbeRateFactor) { ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:3/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); @@ -124,6 +150,9 @@ TEST(ProbeControllerTest, DisableSecondInitialProbeIfRateFactorZero) { ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:0/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 1u); @@ -134,6 +163,9 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); // Long enough to time out exponential probing. @@ -153,6 +185,9 @@ TEST(ProbeControllerTest, ProbesOnMaxAllocatedBitrateIncreaseOnlyWhenInAlr) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( @@ -184,7 +219,9 @@ TEST(ProbeControllerTest, CanDisableProbingOnMaxTotalAllocatedBitrateIncrease) { "probe_max_allocation:false/"); std::unique_ptr probe_controller = fixture.CreateController(); - + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( @@ -206,6 +243,9 @@ TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); // Long enough to time out exponential probing. @@ -229,6 +269,9 @@ TEST(ProbeControllerTest, TestExponentialProbing) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -250,6 +293,9 @@ TEST(ProbeControllerTest, TestExponentialProbingTimeout) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); // Advance far enough to cause a time out in waiting for probing result. @@ -266,6 +312,9 @@ TEST(ProbeControllerTest, RequestProbeInAlr) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_GE(probes.size(), 2u); @@ -289,6 +338,9 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); @@ -314,6 +366,9 @@ TEST(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); @@ -337,6 +392,9 @@ TEST(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); EXPECT_EQ(probes.size(), 2u); @@ -359,6 +417,9 @@ TEST(ProbeControllerTest, PeriodicProbing) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -403,6 +464,9 @@ TEST(ProbeControllerTest, PeriodicProbingAfterReset) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); Timestamp alr_start_time = fixture.CurrentTime(); probe_controller->SetAlrStartTimeMs(alr_start_time.ms()); @@ -461,6 +525,9 @@ TEST(ProbeControllerTest, TestExponentialProbingOverflow) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000); auto probes = probe_controller->SetBitrates(kMinBitrate, 10 * kMbpsMultiplier, 100 * kMbpsMultiplier, @@ -482,6 +549,9 @@ TEST(ProbeControllerTest, TestAllocatedBitrateCap) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); const DataRate kMbpsMultiplier = DataRate::KilobitsPerSec(1000); const DataRate kMaxBitrate = 100 * kMbpsMultiplier; auto probes = probe_controller->SetBitrates( @@ -527,6 +597,9 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { "alloc_p1:2,alloc_p2,min_probe_packets_sent:2/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates(kMinBitrate, kStartBitrate, DataRate::KilobitsPerSec(5000), @@ -561,11 +634,12 @@ TEST(ProbeControllerTest, ConfigurableProbingFieldTrial) { } TEST(ProbeControllerTest, LimitAlrProbeWhenLossBasedBweLimited) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "limit_probe_target_rate_to_loss_bwe:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -600,6 +674,9 @@ TEST(ProbeControllerTest, PeriodicProbeAtUpperNetworkStateEstimate) { "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -625,9 +702,12 @@ TEST(ProbeControllerTest, LimitProbeAtUpperNetworkStateEstimateIfLossBasedLimited) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -657,6 +737,9 @@ TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { "WebRTC-Bwe-ProbingConfiguration/network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -685,6 +768,9 @@ TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { "network_state_interval:5s,network_state_probe_duration:100ms/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -704,11 +790,12 @@ TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { } TEST(ProbeControllerTest, ProbeInAlrIfLossBasedIncreasing) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "limit_probe_target_rate_to_loss_bwe:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probe_controller->EnablePeriodicAlrProbing(true); @@ -730,11 +817,12 @@ TEST(ProbeControllerTest, ProbeInAlrIfLossBasedIncreasing) { } TEST(ProbeControllerTest, ProbeFurtherInAlrIfLossBasedIncreasing) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "limit_probe_target_rate_to_loss_bwe:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probe_controller->EnablePeriodicAlrProbing(true); @@ -762,16 +850,17 @@ TEST(ProbeControllerTest, ProbeFurtherInAlrIfLossBasedIncreasing) { } TEST(ProbeControllerTest, NotProbeWhenInAlrIfLossBasedDecreases) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probe_controller->EnablePeriodicAlrProbing(true); probes = probe_controller->SetEstimatedBitrate( - kStartBitrate, BandwidthLimitedCause::kLossLimitedBweDecreasing, + kStartBitrate, BandwidthLimitedCause::kLossLimitedBwe, fixture.CurrentTime()); // Wait long enough to time out exponential probing. @@ -787,11 +876,12 @@ TEST(ProbeControllerTest, NotProbeWhenInAlrIfLossBasedDecreases) { } TEST(ProbeControllerTest, NotProbeIfLossBasedIncreasingOutsideAlr) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "limit_probe_target_rate_to_loss_bwe:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probe_controller->EnablePeriodicAlrProbing(true); @@ -813,9 +903,12 @@ TEST(ProbeControllerTest, NotProbeIfLossBasedIncreasingOutsideAlr) { TEST(ProbeControllerTest, ProbeFurtherWhenLossBasedIsSameAsDelayBasedEstimate) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -853,6 +946,9 @@ TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) { "target_rate_to_loss_bwe:true/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -894,9 +990,12 @@ TEST(ProbeControllerTest, ProbeIfEstimateLowerThanNetworkStateEstimate) { TEST(ProbeControllerTest, DontProbeFurtherWhenLossLimited) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -916,17 +1015,20 @@ TEST(ProbeControllerTest, DontProbeFurtherWhenLossLimited) { EXPECT_LT(probes[0].target_data_rate, state_estimate.link_capacity_upper); // Expect that no more probes are sent immediately if BWE is loss limited. probes = probe_controller->SetEstimatedBitrate( - probes[0].target_data_rate, - BandwidthLimitedCause::kLossLimitedBweDecreasing, fixture.CurrentTime()); + probes[0].target_data_rate, BandwidthLimitedCause::kLossLimitedBwe, + fixture.CurrentTime()); EXPECT_TRUE(probes.empty()); } TEST(ProbeControllerTest, ProbeFurtherWhenDelayBasedLimited) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -956,9 +1058,12 @@ TEST(ProbeControllerTest, ProbeFurtherIfNetworkStateEstimateIncreaseAfterProbeSent) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_FALSE(probes.empty()); @@ -997,6 +1102,9 @@ TEST(ProbeControllerTest, SkipAlrProbeIfEstimateLargerThanMaxProbe) { "skip_if_est_larger_than_fraction_of_max:0.9/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -1025,6 +1133,9 @@ TEST(ProbeControllerTest, "skip_if_est_larger_than_fraction_of_max:1.0/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -1055,6 +1166,9 @@ TEST(ProbeControllerTest, SkipNetworkStateProbeIfEstimateLargerThanMaxProbe) { "network_state_interval:2s,skip_if_est_larger_than_fraction_of_max:0.9/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_FALSE(probes.empty()); @@ -1078,6 +1192,9 @@ TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) { "/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); ASSERT_FALSE(probes.empty()); @@ -1101,12 +1218,17 @@ TEST(ProbeControllerTest, SendsProbeIfNetworkStateEstimateLowerThanMaxProbe) { EXPECT_FALSE(probes.empty()); } -TEST(ProbeControllerTest, DontSendProbeIfNetworkStateEstimateIsZero) { +TEST(ProbeControllerTest, + ProbeNotLimitedByNetworkStateEsimateIfLowerThantCurrent) { ProbeControllerFixture fixture( "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,limit_probe_target_rate_to_loss_bwe:true/"); + "network_state_interval:5s/"); std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); + probe_controller->EnablePeriodicAlrProbing(true); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); probes = probe_controller->SetEstimatedBitrate( @@ -1119,21 +1241,22 @@ TEST(ProbeControllerTest, DontSendProbeIfNetworkStateEstimateIsZero) { probes = probe_controller->Process(fixture.CurrentTime()); ASSERT_TRUE(probes.empty()); + probe_controller->SetAlrStartTimeMs(fixture.CurrentTime().ms()); probe_controller->SetNetworkStateEstimate( - {.link_capacity_upper = DataRate::Zero()}); - probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); + {.link_capacity_upper = kStartBitrate / 2}); fixture.AdvanceTime(TimeDelta::Seconds(6)); probes = probe_controller->Process(fixture.CurrentTime()); - EXPECT_TRUE(probes.empty()); + ASSERT_FALSE(probes.empty()); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate); } TEST(ProbeControllerTest, DontProbeIfDelayIncreased) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,not_probe_if_delay_increased:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); @@ -1158,11 +1281,12 @@ TEST(ProbeControllerTest, DontProbeIfDelayIncreased) { } TEST(ProbeControllerTest, DontProbeIfHighRtt) { - ProbeControllerFixture fixture( - "WebRTC-Bwe-ProbingConfiguration/" - "network_state_interval:5s,not_probe_if_delay_increased:true/"); + ProbeControllerFixture fixture; std::unique_ptr probe_controller = fixture.CreateController(); + ASSERT_THAT( + probe_controller->OnNetworkAvailability({.network_available = true}), + IsEmpty()); auto probes = probe_controller->SetBitrates( kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); diff --git a/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc b/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc index 3f66f7fdae..5a22910fe3 100644 --- a/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc +++ b/modules/congestion_controller/goog_cc/robust_throughput_estimator.cc @@ -14,11 +14,15 @@ #include #include +#include +#include "absl/types/optional.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" diff --git a/modules/congestion_controller/goog_cc/robust_throughput_estimator_unittest.cc b/modules/congestion_controller/goog_cc/robust_throughput_estimator_unittest.cc index f41ee7f3d6..c207149ee4 100644 --- a/modules/congestion_controller/goog_cc/robust_throughput_estimator_unittest.cc +++ b/modules/congestion_controller/goog_cc/robust_throughput_estimator_unittest.cc @@ -14,12 +14,15 @@ #include #include -#include +#include #include "absl/strings/string_view.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "test/explicit_key_value_config.h" #include "test/gtest.h" diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc index 55270be7f5..b09cb22f49 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -11,22 +11,27 @@ #include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h" #include +#include #include #include #include #include +#include #include "absl/strings/match.h" +#include "absl/types/optional.h" #include "api/field_trials_view.h" #include "api/network_state_predictor.h" -#include "api/rtc_event_log/rtc_event.h" #include "api/rtc_event_log/rtc_event_log.h" +#include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" #include "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/logging.h" #include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" @@ -375,7 +380,6 @@ void SendSideBandwidthEstimation::UpdateLossBasedEstimator( const TransportPacketsFeedback& report, BandwidthUsage delay_detector_state, absl::optional probe_bitrate, - DataRate upper_link_capacity, bool in_alr) { if (LossBasedBandwidthEstimatorV1Enabled()) { loss_based_bandwidth_estimator_v1_.UpdateLossStatistics( @@ -383,8 +387,7 @@ void SendSideBandwidthEstimation::UpdateLossBasedEstimator( } if (LossBasedBandwidthEstimatorV2Enabled()) { loss_based_bandwidth_estimator_v2_.UpdateBandwidthEstimate( - report.packet_feedbacks, delay_based_limit_, delay_detector_state, - probe_bitrate, upper_link_capacity, in_alr); + report.packet_feedbacks, delay_based_limit_, in_alr); UpdateEstimate(report.feedback_time); } } @@ -488,7 +491,8 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { // We trust the REMB and/or delay-based estimate during the first 2 seconds if // we haven't had any packet loss reported, to allow startup bitrate probing. - if (last_fraction_loss_ == 0 && IsInStartPhase(at_time)) { + if (last_fraction_loss_ == 0 && IsInStartPhase(at_time) && + !loss_based_bandwidth_estimator_v2_.ReadyToUseInStartPhase()) { DataRate new_bitrate = current_target_; // TODO(srte): We should not allow the new_bitrate to be larger than the // receiver limit here. @@ -499,9 +503,6 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { if (LossBasedBandwidthEstimatorV1Enabled()) { loss_based_bandwidth_estimator_v1_.Initialize(new_bitrate); } - if (LossBasedBandwidthEstimatorV2Enabled()) { - loss_based_bandwidth_estimator_v2_.SetBandwidthEstimate(new_bitrate); - } if (new_bitrate != current_target_) { min_bitrate_history_.clear(); diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h index 5a037db045..3a4efc47c7 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h @@ -127,7 +127,6 @@ class SendSideBandwidthEstimation { void UpdateLossBasedEstimator(const TransportPacketsFeedback& report, BandwidthUsage delay_detector_state, absl::optional probe_bitrate, - DataRate upper_link_capacity, bool in_alr); private: diff --git a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation_unittest.cc b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation_unittest.cc index 1e4ca6a01d..866700b09a 100644 --- a/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation_unittest.cc +++ b/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation_unittest.cc @@ -10,7 +10,12 @@ #include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h" +#include + #include "api/rtc_event_log/rtc_event.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "test/explicit_key_value_config.h" diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.cc b/modules/congestion_controller/goog_cc/trendline_estimator.cc index 88182d4f80..13fb55e6b8 100644 --- a/modules/congestion_controller/goog_cc/trendline_estimator.cc +++ b/modules/congestion_controller/goog_cc/trendline_estimator.cc @@ -13,10 +13,17 @@ #include #include +#include +#include +#include +#include +#include #include +#include #include "absl/strings/match.h" #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/network_state_predictor.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" #include "rtc_base/checks.h" diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.h b/modules/congestion_controller/goog_cc/trendline_estimator.h index ffda25df74..fa5a41ea53 100644 --- a/modules/congestion_controller/goog_cc/trendline_estimator.h +++ b/modules/congestion_controller/goog_cc/trendline_estimator.h @@ -15,7 +15,6 @@ #include #include -#include #include "api/field_trials_view.h" #include "api/network_state_predictor.h" diff --git a/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc b/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc index b0195abdf5..b7a3089ba2 100644 --- a/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc +++ b/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc @@ -11,11 +11,13 @@ #include "modules/congestion_controller/goog_cc/trendline_estimator.h" #include -#include +#include +#include #include +#include "api/network_state_predictor.h" #include "api/transport/field_trial_based_config.h" -#include "rtc_base/random.h" +#include "rtc_base/checks.h" #include "test/gtest.h" namespace webrtc { diff --git a/modules/congestion_controller/rtp/control_handler.cc b/modules/congestion_controller/rtp/control_handler.cc index ffa373aeba..da6451c97e 100644 --- a/modules/congestion_controller/rtp/control_handler.cc +++ b/modules/congestion_controller/rtp/control_handler.cc @@ -30,9 +30,7 @@ bool IsPacerEmergencyStopDisabled() { } // namespace CongestionControlHandler::CongestionControlHandler() - : disable_pacer_emergency_stop_(IsPacerEmergencyStopDisabled()) { - sequenced_checker_.Detach(); -} + : disable_pacer_emergency_stop_(IsPacerEmergencyStopDisabled()) {} CongestionControlHandler::~CongestionControlHandler() {} diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index 4ef00e68ab..40764de7ae 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -82,8 +82,10 @@ void BaseCapturerPipeWire::OnScreenCastRequestResult(RequestResponse result, << static_cast(result); } else if (ScreenCastPortal* screencast_portal = GetScreenCastPortal()) { if (!screencast_portal->RestoreToken().empty()) { + const SourceId token_id = + selected_source_id_ ? selected_source_id_ : source_id_; RestoreTokenManager::GetInstance().AddToken( - source_id_, screencast_portal->RestoreToken()); + token_id, screencast_portal->RestoreToken()); } } @@ -137,7 +139,7 @@ void BaseCapturerPipeWire::Start(Callback* callback) { ScreenCastPortal::PersistMode::kTransient); if (selected_source_id_) { screencast_portal->SetRestoreToken( - RestoreTokenManager::GetInstance().TakeToken(selected_source_id_)); + RestoreTokenManager::GetInstance().GetToken(selected_source_id_)); } } diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.cc b/modules/desktop_capture/linux/wayland/restore_token_manager.cc index 5ca9b957a9..a17d9a49bb 100644 --- a/modules/desktop_capture/linux/wayland/restore_token_manager.cc +++ b/modules/desktop_capture/linux/wayland/restore_token_manager.cc @@ -23,10 +23,8 @@ void RestoreTokenManager::AddToken(DesktopCapturer::SourceId id, restore_tokens_.insert({id, token}); } -std::string RestoreTokenManager::TakeToken(DesktopCapturer::SourceId id) { - std::string token = restore_tokens_[id]; - // Remove the token as it cannot be used anymore - restore_tokens_.erase(id); +std::string RestoreTokenManager::GetToken(DesktopCapturer::SourceId id) { + const std::string token = restore_tokens_[id]; return token; } diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.h b/modules/desktop_capture/linux/wayland/restore_token_manager.h index 174bef121f..ad4f74790f 100644 --- a/modules/desktop_capture/linux/wayland/restore_token_manager.h +++ b/modules/desktop_capture/linux/wayland/restore_token_manager.h @@ -27,7 +27,7 @@ class RestoreTokenManager { static RestoreTokenManager& GetInstance(); void AddToken(DesktopCapturer::SourceId id, const std::string& token); - std::string TakeToken(DesktopCapturer::SourceId id); + std::string GetToken(DesktopCapturer::SourceId id); // Returns a source ID which does not have any token associated with it yet. DesktopCapturer::SourceId GetUnusedId(); diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/desktop_capture/mac/screen_capturer_mac.mm index 8f0c68d48b..28cc410573 100644 --- a/modules/desktop_capture/mac/screen_capturer_mac.mm +++ b/modules/desktop_capture/mac/screen_capturer_mac.mm @@ -20,87 +20,6 @@ #include "rtc_base/trace_event.h" #include "sdk/objc/helpers/scoped_cftyperef.h" -// All these symbols have incorrect availability annotations in the 13.3 SDK. -// These have the correct annotation. See https://crbug.com/1431897. -// TODO(thakis): Remove this once FB12109479 is fixed and we updated to an SDK -// with the fix. - -static CGDisplayStreamRef __nullable - wrapCGDisplayStreamCreate(CGDirectDisplayID display, - size_t outputWidth, - size_t outputHeight, - int32_t pixelFormat, - CFDictionaryRef __nullable properties, - CGDisplayStreamFrameAvailableHandler __nullable handler) - CG_AVAILABLE_BUT_DEPRECATED( - 10.8, - 14.0, - "Please use ScreenCaptureKit API's initWithFilter:configuration:delegate: instead") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return CGDisplayStreamCreate( - display, outputWidth, outputHeight, pixelFormat, properties, handler); -#pragma clang diagnostic pop -} - -static CFRunLoopSourceRef __nullable - wrapCGDisplayStreamGetRunLoopSource(CGDisplayStreamRef cg_nullable displayStream) - CG_AVAILABLE_BUT_DEPRECATED(10.8, - 14.0, - "There is no direct replacement for this function. Please use " - "ScreenCaptureKit API's SCStream to replace CGDisplayStream") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return CGDisplayStreamGetRunLoopSource(displayStream); -#pragma clang diagnostic pop -} - -static CGError wrapCGDisplayStreamStart(CGDisplayStreamRef cg_nullable displayStream) - CG_AVAILABLE_BUT_DEPRECATED(10.8, - 14.0, - "Please use ScreenCaptureKit API's " - "startCaptureWithCompletionHandler: to start a stream instead") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return CGDisplayStreamStart(displayStream); -#pragma clang diagnostic pop -} - -static CGError wrapCGDisplayStreamStop(CGDisplayStreamRef cg_nullable displayStream) - CG_AVAILABLE_BUT_DEPRECATED(10.8, - 14.0, - "Please use ScreenCaptureKit API's " - "stopCaptureWithCompletionHandler: to stop a stream instead") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return CGDisplayStreamStop(displayStream); -#pragma clang diagnostic pop -} - -static CFStringRef wrapkCGDisplayStreamShowCursor() CG_AVAILABLE_BUT_DEPRECATED( - 10.8, - 14.0, - "Please use ScreenCaptureKit API's SCStreamConfiguration showsCursor property instead") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return kCGDisplayStreamShowCursor; -#pragma clang diagnostic pop -} - -static const CGRect* __nullable - wrapCGDisplayStreamUpdateGetRects(CGDisplayStreamUpdateRef __nullable updateRef, - CGDisplayStreamUpdateRectType rectType, - size_t* rectCount) - CG_AVAILABLE_BUT_DEPRECATED(10.8, - 14.0, - "Please use ScreenCaptureKit API's SCStreamFrameInfo with " - "SCStreamFrameInfoContentRect instead") { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - return CGDisplayStreamUpdateGetRects(updateRef, rectType, rectCount); -#pragma clang diagnostic pop -} - namespace webrtc { namespace { @@ -540,7 +459,7 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { size_t count = 0; const CGRect* rects = - wrapCGDisplayStreamUpdateGetRects(updateRef, kCGDisplayStreamUpdateDirtyRects, &count); + CGDisplayStreamUpdateGetRects(updateRef, kCGDisplayStreamUpdateDirtyRects, &count); if (count != 0) { // According to CGDisplayStream.h, it's safe to call // CGDisplayStreamStop() from within the callback. @@ -550,20 +469,20 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { rtc::ScopedCFTypeRef properties_dict( CFDictionaryCreate(kCFAllocatorDefault, - (const void*[]){wrapkCGDisplayStreamShowCursor()}, + (const void*[]){kCGDisplayStreamShowCursor}, (const void*[]){kCFBooleanFalse}, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - CGDisplayStreamRef display_stream = wrapCGDisplayStreamCreate( + CGDisplayStreamRef display_stream = CGDisplayStreamCreate( display_id, pixel_width, pixel_height, 'BGRA', properties_dict.get(), handler); if (display_stream) { - CGError error = wrapCGDisplayStreamStart(display_stream); + CGError error = CGDisplayStreamStart(display_stream); if (error != kCGErrorSuccess) return false; - CFRunLoopSourceRef source = wrapCGDisplayStreamGetRunLoopSource(display_stream); + CFRunLoopSourceRef source = CGDisplayStreamGetRunLoopSource(display_stream); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); display_streams_.push_back(display_stream); } @@ -576,9 +495,9 @@ void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { RTC_DCHECK(thread_checker_.IsCurrent()); for (CGDisplayStreamRef stream : display_streams_) { - CFRunLoopSourceRef source = wrapCGDisplayStreamGetRunLoopSource(stream); + CFRunLoopSourceRef source = CGDisplayStreamGetRunLoopSource(stream); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); - wrapCGDisplayStreamStop(stream); + CGDisplayStreamStop(stream); CFRelease(stream); } display_streams_.clear(); diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h index 34d1313234..5d6f2aa5fc 100644 --- a/modules/desktop_capture/mac/window_list_utils.h +++ b/modules/desktop_capture/mac/window_list_utils.h @@ -20,6 +20,7 @@ #include "modules/desktop_capture/desktop_capturer.h" #include "modules/desktop_capture/desktop_geometry.h" #include "modules/desktop_capture/mac/desktop_configuration.h" +#include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -29,14 +30,15 @@ namespace webrtc { // failed. Menus, dock (if `only_zero_layer`), minimized windows (if // `ignore_minimized` is true) and any windows which do not have a valid window // id or title will be ignored. -bool GetWindowList(rtc::FunctionView on_window, - bool ignore_minimized, - bool only_zero_layer); +bool RTC_EXPORT +GetWindowList(rtc::FunctionView on_window, + bool ignore_minimized, + bool only_zero_layer); // Another helper function to get the on-screen windows. -bool GetWindowList(DesktopCapturer::SourceList* windows, - bool ignore_minimized, - bool only_zero_layer); +bool RTC_EXPORT GetWindowList(DesktopCapturer::SourceList* windows, + bool ignore_minimized, + bool only_zero_layer); // Returns true if the window is occupying a full screen. bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config, diff --git a/modules/desktop_capture/win/wgc_capture_session.cc b/modules/desktop_capture/win/wgc_capture_session.cc index a291f20167..8c74c2bf24 100644 --- a/modules/desktop_capture/win/wgc_capture_session.cc +++ b/modules/desktop_capture/win/wgc_capture_session.cc @@ -75,7 +75,8 @@ enum class GetFrameResult { kGetContentSizeFailed = 9, kResizeMappedTextureFailed = 10, kRecreateFramePoolFailed = 11, - kMaxValue = kRecreateFramePoolFailed + kFramePoolEmpty = 12, + kMaxValue = kFramePoolEmpty }; void RecordStartCaptureResult(StartCaptureResult error) { @@ -187,6 +188,18 @@ HRESULT WgcCaptureSession::StartCapture(const DesktopCaptureOptions& options) { } } + // By default, the WGC capture API adds a yellow border around the captured + // window or display to indicate that a capture is in progress. The section + // below is an attempt to remove this yellow border to make the capture + // experience more inline with the DXGI capture path. + // This requires 10.0.20348.0 or later, which practically means Windows 11. + ComPtr session3; + if (SUCCEEDED(session_->QueryInterface( + ABI::Windows::Graphics::Capture::IID_IGraphicsCaptureSession3, + &session3))) { + session3->put_IsBorderRequired(false); + } + allow_zero_hertz_ = options.allow_wgc_zero_hertz(); hr = session_->StartCapture(); @@ -244,10 +257,16 @@ void WgcCaptureSession::EnsureFrame() { << "Unable to process a valid frame even after trying 10 times."; } -bool WgcCaptureSession::GetFrame(std::unique_ptr* output_frame) { +bool WgcCaptureSession::GetFrame(std::unique_ptr* output_frame, + bool source_should_be_capturable) { RTC_DCHECK_RUN_ON(&sequence_checker_); - EnsureFrame(); + // Try to process the captured frame and wait some if needed. Avoid trying + // if we know that the source will not be capturable. This can happen e.g. + // when captured window is minimized and if EnsureFrame() was called in this + // state a large amount of kFrameDropped errors would be logged. + if (source_should_be_capturable) + EnsureFrame(); // Return a NULL frame and false as `result` if we still don't have a valid // frame. This will lead to a DesktopCapturer::Result::ERROR_PERMANENT being @@ -314,10 +333,15 @@ HRESULT WgcCaptureSession::ProcessFrame() { } if (!capture_frame) { - // Avoid logging errors until at least one valid frame has been captured. - if (queue_.current_frame()) { - RTC_DLOG(LS_WARNING) << "Frame pool was empty => kFrameDropped."; + if (!queue_.current_frame()) { + // The frame pool was empty and so is the external queue. + RTC_DLOG(LS_ERROR) << "Frame pool was empty => kFrameDropped."; RecordGetFrameResult(GetFrameResult::kFrameDropped); + } else { + // The frame pool was empty but there is still one old frame available in + // external the queue. + RTC_DLOG(LS_WARNING) << "Frame pool was empty => kFramePoolEmpty."; + RecordGetFrameResult(GetFrameResult::kFramePoolEmpty); } return E_FAIL; } diff --git a/modules/desktop_capture/win/wgc_capture_session.h b/modules/desktop_capture/win/wgc_capture_session.h index 499c75ee98..d2901d9199 100644 --- a/modules/desktop_capture/win/wgc_capture_session.h +++ b/modules/desktop_capture/win/wgc_capture_session.h @@ -44,17 +44,20 @@ class WgcCaptureSession final { HRESULT StartCapture(const DesktopCaptureOptions& options); // Returns a frame from the local frame queue, if any are present. - bool GetFrame(std::unique_ptr* output_frame); + bool GetFrame(std::unique_ptr* output_frame, + bool source_should_be_capturable); bool IsCaptureStarted() const { RTC_DCHECK_RUN_ON(&sequence_checker_); return is_capture_started_; } - // We only keep 1 buffer in the internal frame pool to reduce the latency as - // much as possible. + // We keep 2 buffers in the frame pool since it results in a good compromise + // between latency/capture-rate and the rate at which + // Direct3D11CaptureFramePool.TryGetNextFrame returns NULL and we have to fall + // back to providing a copy from our external queue instead. // We make this public for tests. - static constexpr int kNumBuffers = 1; + static constexpr int kNumBuffers = 2; private: // Initializes `mapped_texture_` with the properties of the `src_texture`, diff --git a/modules/desktop_capture/win/wgc_capture_source.cc b/modules/desktop_capture/win/wgc_capture_source.cc index 24e6129ec7..1688878cde 100644 --- a/modules/desktop_capture/win/wgc_capture_source.cc +++ b/modules/desktop_capture/win/wgc_capture_source.cc @@ -29,6 +29,10 @@ WgcCaptureSource::WgcCaptureSource(DesktopCapturer::SourceId source_id) : source_id_(source_id) {} WgcCaptureSource::~WgcCaptureSource() = default; +bool WgcCaptureSource::ShouldBeCapturable() { + return true; +} + bool WgcCaptureSource::IsCapturable() { // If we can create a capture item, then we can capture it. Unfortunately, // we can't cache this item because it may be created in a different COM @@ -105,9 +109,14 @@ ABI::Windows::Graphics::SizeInt32 WgcWindowSource::GetSize() { window_rect.bottom - window_rect.top}; } +bool WgcWindowSource::ShouldBeCapturable() { + return IsWindowValidAndVisible(reinterpret_cast(GetSourceId())); +} + bool WgcWindowSource::IsCapturable() { - if (!IsWindowValidAndVisible(reinterpret_cast(GetSourceId()))) + if (!ShouldBeCapturable()) { return false; + } return WgcCaptureSource::IsCapturable(); } diff --git a/modules/desktop_capture/win/wgc_capture_source.h b/modules/desktop_capture/win/wgc_capture_source.h index d1275b6168..57b105c2f8 100644 --- a/modules/desktop_capture/win/wgc_capture_source.h +++ b/modules/desktop_capture/win/wgc_capture_source.h @@ -33,6 +33,10 @@ class WgcCaptureSource { virtual ~WgcCaptureSource(); virtual DesktopVector GetTopLeft() = 0; + // Lightweight version of IsCapturable which avoids allocating/deallocating + // COM objects for each call. As such may return a different value than + // IsCapturable. + virtual bool ShouldBeCapturable(); virtual bool IsCapturable(); virtual bool FocusOnSource(); virtual ABI::Windows::Graphics::SizeInt32 GetSize(); @@ -99,6 +103,7 @@ class WgcWindowSource final : public WgcCaptureSource { DesktopVector GetTopLeft() override; ABI::Windows::Graphics::SizeInt32 GetSize() override; + bool ShouldBeCapturable() override; bool IsCapturable() override; bool FocusOnSource() override; diff --git a/modules/desktop_capture/win/wgc_capturer_win.cc b/modules/desktop_capture/win/wgc_capturer_win.cc index 20d4eb938d..9c545597aa 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.cc +++ b/modules/desktop_capture/win/wgc_capturer_win.cc @@ -323,7 +323,8 @@ void WgcCapturerWin::CaptureFrame() { } std::unique_ptr frame; - if (!capture_session->GetFrame(&frame)) { + if (!capture_session->GetFrame(&frame, + capture_source_->ShouldBeCapturable())) { RTC_LOG(LS_ERROR) << "GetFrame failed."; ongoing_captures_.erase(capture_source_->GetSourceId()); callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm index f99b4a74d1..56c94baada 100644 --- a/modules/desktop_capture/window_capturer_mac.mm +++ b/modules/desktop_capture/window_capturer_mac.mm @@ -127,8 +127,7 @@ bool WindowCapturerMac::FocusOnSelectedSource() { // TODO(jiayl): this will bring the process main window to the front. We // should find a way to bring only the window to the front. bool result = - [[NSRunningApplication runningApplicationWithProcessIdentifier: pid] - activateWithOptions: NSApplicationActivateIgnoringOtherApps]; + [[NSRunningApplication runningApplicationWithProcessIdentifier:pid] activateWithOptions:0]; CFRelease(window_id_array); CFRelease(window_array); diff --git a/modules/pacing/bitrate_prober.cc b/modules/pacing/bitrate_prober.cc index 3151a35075..e60a1e5283 100644 --- a/modules/pacing/bitrate_prober.cc +++ b/modules/pacing/bitrate_prober.cc @@ -97,7 +97,7 @@ void BitrateProber::CreateProbeCluster( (cluster_config.target_data_rate * cluster_config.target_duration) .bytes(); RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0); - cluster.pace_info.send_bitrate_bps = cluster_config.target_data_rate.bps(); + cluster.pace_info.send_bitrate = cluster_config.target_data_rate; cluster.pace_info.probe_cluster_id = cluster_config.id; clusters_.push(cluster); @@ -109,7 +109,7 @@ void BitrateProber::CreateProbeCluster( probing_state_ == ProbingState::kInactive); RTC_LOG(LS_INFO) << "Probe cluster (bitrate_bps:min bytes:min packets): (" - << cluster.pace_info.send_bitrate_bps << ":" + << cluster.pace_info.send_bitrate << ":" << cluster.pace_info.probe_cluster_min_bytes << ":" << cluster.pace_info.probe_cluster_min_probes << ", " << (probing_state_ == ProbingState::kInactive ? "Inactive" @@ -153,8 +153,7 @@ DataSize BitrateProber::RecommendedMinProbeSize() const { if (clusters_.empty()) { return DataSize::Zero(); } - DataRate send_rate = - DataRate::BitsPerSec(clusters_.front().pace_info.send_bitrate_bps); + DataRate send_rate = clusters_.front().pace_info.send_bitrate; return send_rate * config_.min_probe_delta; } @@ -183,14 +182,13 @@ void BitrateProber::ProbeSent(Timestamp now, DataSize size) { Timestamp BitrateProber::CalculateNextProbeTime( const ProbeCluster& cluster) const { - RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0); + RTC_CHECK_GT(cluster.pace_info.send_bitrate.bps(), 0); RTC_CHECK(cluster.started_at.IsFinite()); // Compute the time delta from the cluster start to ensure probe bitrate stays // close to the target bitrate. Result is in milliseconds. DataSize sent_bytes = DataSize::Bytes(cluster.sent_bytes); - DataRate send_bitrate = - DataRate::BitsPerSec(cluster.pace_info.send_bitrate_bps); + DataRate send_bitrate = cluster.pace_info.send_bitrate; TimeDelta delta = sent_bytes / send_bitrate; return cluster.started_at + delta; diff --git a/modules/pacing/pacing_controller.cc b/modules/pacing/pacing_controller.cc index 67d0c6c4ef..55f949cd78 100644 --- a/modules/pacing/pacing_controller.cc +++ b/modules/pacing/pacing_controller.cc @@ -17,6 +17,8 @@ #include "absl/cleanup/cleanup.h" #include "absl/strings/match.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" #include "modules/pacing/bitrate_prober.h" #include "modules/pacing/interval_budget.h" #include "rtc_base/checks.h" @@ -162,7 +164,6 @@ void PacingController::SetProbingEnabled(bool enabled) { void PacingController::SetPacingRates(DataRate pacing_rate, DataRate padding_rate) { - static constexpr DataRate kMaxRate = DataRate::KilobitsPerSec(100'000); RTC_CHECK_GT(pacing_rate, DataRate::Zero()); RTC_CHECK_GE(padding_rate, DataRate::Zero()); if (padding_rate > pacing_rate) { @@ -172,11 +173,12 @@ void PacingController::SetPacingRates(DataRate pacing_rate, padding_rate = pacing_rate; } - if (pacing_rate > kMaxRate || padding_rate > kMaxRate) { - RTC_LOG(LS_WARNING) << "Very high pacing rates ( > " << kMaxRate.kbps() + if (pacing_rate > max_rate || padding_rate > max_rate) { + RTC_LOG(LS_WARNING) << "Very high pacing rates ( > " << max_rate.kbps() << " kbps) configured: pacing = " << pacing_rate.kbps() << " kbps, padding = " << padding_rate.kbps() << " kbps."; + max_rate = std::max(pacing_rate, padding_rate) * 1.1; } pacing_rate_ = pacing_rate; padding_rate_ = padding_rate; @@ -343,9 +345,13 @@ Timestamp PacingController::NextSendTime() const { // debt is allowed to grow up to one packet more than what can be sent // during 'send_burst_period_'. TimeDelta drain_time = media_debt_ / adjusted_media_rate_; + // Ensure that a burst of sent packet is not larger than kMaxBurstSize in + // order to not risk overfilling socket buffers at high bitrate. + TimeDelta send_burst_interval = + std::min(send_burst_interval_, kMaxBurstSize / adjusted_media_rate_); next_send_time = last_process_time_ + - ((send_burst_interval_ > drain_time) ? TimeDelta::Zero() : drain_time); + ((send_burst_interval > drain_time) ? TimeDelta::Zero() : drain_time); } else if (padding_rate_ > DataRate::Zero() && packet_queue_.Empty()) { // If we _don't_ have pending packets, check how long until we have // bandwidth for padding packets. Both media and padding debts must diff --git a/modules/pacing/pacing_controller.h b/modules/pacing/pacing_controller.h index 2145868a62..dd5636ccef 100644 --- a/modules/pacing/pacing_controller.h +++ b/modules/pacing/pacing_controller.h @@ -24,6 +24,7 @@ #include "api/function_view.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/network_types.h" +#include "api/units/data_size.h" #include "modules/pacing/bitrate_prober.h" #include "modules/pacing/interval_budget.h" #include "modules/pacing/prioritized_packet_queue.h" @@ -86,6 +87,11 @@ class PacingController { // set to 1ms as this is intended to allow times be rounded down to the // nearest millisecond. static const TimeDelta kMaxEarlyProbeProcessing; + // Max total size of packets expected to be sent in a burst in order to not + // risk loosing packets due to too small send socket buffers. It upper limits + // the send burst interval. + // Ex: max send burst interval = 63Kb / 10Mbit/s = 50ms. + static constexpr DataSize kMaxBurstSize = DataSize::Bytes(63 * 1000); PacingController(Clock* clock, PacketSender* packet_sender, @@ -208,7 +214,7 @@ class PacingController { const bool ignore_transport_overhead_; const bool fast_retransmissions_; const bool keyframe_flushing_; - + DataRate max_rate = DataRate::BitsPerSec(100'000'000); DataSize transport_overhead_per_packet_; TimeDelta send_burst_interval_; diff --git a/modules/pacing/pacing_controller_unittest.cc b/modules/pacing/pacing_controller_unittest.cc index ade71cd5f5..ba93d05bb7 100644 --- a/modules/pacing/pacing_controller_unittest.cc +++ b/modules/pacing/pacing_controller_unittest.cc @@ -11,17 +11,16 @@ #include "modules/pacing/pacing_controller.h" #include -#include +#include #include -#include #include #include #include "api/transport/network_types.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" -#include "modules/pacing/packet_router.h" #include "system_wrappers/include/clock.h" #include "test/explicit_key_value_config.h" #include "test/gmock.h" @@ -30,6 +29,7 @@ using ::testing::_; using ::testing::AnyNumber; using ::testing::Field; +using ::testing::NiceMock; using ::testing::Pointee; using ::testing::Property; using ::testing::Return; @@ -2146,6 +2146,36 @@ TEST_F(PacingControllerTest, RespectsTargetRateWhenSendingPacketsInBursts) { EXPECT_EQ(number_of_bursts, 4); } +TEST_F(PacingControllerTest, + MaxBurstSizeLimitedAtHighPacingRateWhenSendingPacketsInBursts) { + NiceMock callback; + PacingController pacer(&clock_, &callback, trials_); + pacer.SetSendBurstInterval(TimeDelta::Millis(100)); + pacer.SetPacingRates(DataRate::KilobitsPerSec(10'000), DataRate::Zero()); + + size_t sent_size_in_burst = 0; + EXPECT_CALL(callback, SendPacket) + .WillRepeatedly([&](std::unique_ptr packet, + const PacedPacketInfo& cluster_info) { + sent_size_in_burst += packet->size(); + }); + + // Enqueue 200 packets from a 200Kb encoded frame. + for (int i = 0; i < 200; ++i) { + pacer.EnqueuePacket(video_.BuildNextPacket(1000)); + } + + while (pacer.QueueSizePackets() > 70) { + pacer.ProcessPackets(); + EXPECT_NEAR(sent_size_in_burst, PacingController::kMaxBurstSize.bytes(), + 1000); + sent_size_in_burst = 0; + TimeDelta time_to_next = pacer.NextSendTime() - clock_.CurrentTime(); + EXPECT_NEAR(time_to_next.ms(), 50, 2); + clock_.AdvanceTime(time_to_next); + } +} + TEST_F(PacingControllerTest, RespectsQueueTimeLimit) { static constexpr DataSize kPacketSize = DataSize::Bytes(100); static constexpr DataRate kNominalPacingRate = DataRate::KilobitsPerSec(200); diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.cc b/modules/remote_bitrate_estimator/aimd_rate_control.cc index 5ac4ce829d..fde66657e7 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -79,7 +79,9 @@ AimdRateControl::AimdRateControl(const FieldTrialsView& key_value_config, rtt_(kDefaultRtt), send_side_(send_side), no_bitrate_increase_in_alr_( - key_value_config.IsEnabled("WebRTC-DontIncreaseDelayBasedBweInAlr")) { + key_value_config.IsEnabled("WebRTC-DontIncreaseDelayBasedBweInAlr")), + subtract_additional_backoff_term_(!key_value_config.IsDisabled( + "WebRTC-Bwe-SubtractAdditionalBackoffTerm")) { ParseFieldTrial( {&disable_estimate_bounded_increase_, &use_current_estimate_as_min_upper_bound_}, @@ -287,6 +289,11 @@ void AimdRateControl::ChangeBitrate(const RateControlInput& input, // Set bit rate to something slightly lower than the measured throughput // to get rid of any self-induced delay. decreased_bitrate = estimated_throughput * beta_; + if (decreased_bitrate > DataRate::KilobitsPerSec(5) && + subtract_additional_backoff_term_) { + decreased_bitrate -= DataRate::KilobitsPerSec(5); + } + if (decreased_bitrate > current_bitrate_) { // TODO(terelius): The link_capacity estimate may be based on old // throughput measurements. Relying on them may lead to unnecessary diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.h b/modules/remote_bitrate_estimator/aimd_rate_control.h index 4efde54410..97fa490adf 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -103,6 +103,8 @@ class AimdRateControl { // Allow the delay based estimate to only increase as long as application // limited region (alr) is not detected. const bool no_bitrate_increase_in_alr_; + // If true, subtract an additional 5kbps when backing off. + const bool subtract_additional_backoff_term_; // If "Disabled", estimated link capacity is not used as upper bound. FieldTrialFlag disable_estimate_bounded_increase_{"Disabled"}; FieldTrialParameter use_current_estimate_as_min_upper_bound_{"c_upper", diff --git a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc index 5b8b0caffe..f26afe995c 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc @@ -106,18 +106,22 @@ TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) { EXPECT_NE(aimd_rate_control.GetExpectedBandwidthPeriod(), kDefaultPeriod); } -TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) { +TEST(AimdRateControlTest, ExpectedPeriodAfterTypicalDrop) { AimdRateControl aimd_rate_control(ExplicitKeyValueConfig("")); - constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(110'000); + // The rate increase at 216 kbps should be 12 kbps. If we drop from + // 216 + 4*12 = 264 kbps, it should take 4 seconds to recover. Since we + // back off to 0.85*acked_rate-5kbps, the acked bitrate needs to be 260 + // kbps to end up at 216 kbps. + constexpr DataRate kInitialBitrate = DataRate::BitsPerSec(264'000); + constexpr DataRate kUpdatedBitrate = DataRate::BitsPerSec(216'000); + const DataRate kAckedBitrate = + (kUpdatedBitrate + DataRate::BitsPerSec(5'000)) / kFractionAfterOveruse; Timestamp now = kInitialTime; aimd_rate_control.SetEstimate(kInitialBitrate, now); now += TimeDelta::Millis(100); - // Make the bitrate drop by 20 kbps to get to 90 kbps. - // The rate increase at 90 kbps should be 5 kbps, so the period should be 4 s. - const DataRate kAckedBitrate = - (kInitialBitrate - DataRate::BitsPerSec(20'000)) / kFractionAfterOveruse; aimd_rate_control.Update({BandwidthUsage::kBwOverusing, kAckedBitrate}, now); - EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 5'000); + EXPECT_EQ(aimd_rate_control.LatestEstimate(), kUpdatedBitrate); + EXPECT_EQ(aimd_rate_control.GetNearMaxIncreaseRateBpsPerSecond(), 12'000); EXPECT_EQ(aimd_rate_control.GetExpectedBandwidthPeriod(), TimeDelta::Seconds(4)); } diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc index 64ef39d935..3d72807698 100644 --- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc +++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc @@ -53,7 +53,7 @@ TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) { } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) { - CapacityDropTestHelper(2, true, 767, 0); + CapacityDropTestHelper(2, true, 567, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) { @@ -61,11 +61,11 @@ TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) { } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) { - CapacityDropTestHelper(13, true, 567, 0); + CapacityDropTestHelper(13, true, 767, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) { - CapacityDropTestHelper(19, true, 700, 0); + CapacityDropTestHelper(19, true, 767, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) { diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc index ee9644530a..f8652b455e 100644 --- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc +++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc @@ -477,7 +477,8 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper( uint32_t bitrate_bps = SteadyStateRun( kDefaultSsrc, steady_state_time * kFramerate, kStartBitrate, kMinExpectedBitrate, kMaxExpectedBitrate, kInitialCapacityBps); - EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 130000u); + EXPECT_GE(bitrate_bps, 0.85 * kInitialCapacityBps); + EXPECT_LE(bitrate_bps, 1.05 * kInitialCapacityBps); bitrate_observer_->Reset(); // Add an offset to make sure the BWE can handle it. diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h index 698f284fa5..249cf835ba 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h +++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h @@ -406,23 +406,12 @@ class BitrateStatisticsObserver { uint32_t ssrc) = 0; }; -// Callback, used to notify an observer whenever the send-side delay is updated. -class SendSideDelayObserver { - public: - virtual ~SendSideDelayObserver() {} - virtual void SendSideDelayUpdated(int avg_delay_ms, - int max_delay_ms, - uint32_t ssrc) = 0; -}; - // Callback, used to notify an observer whenever a packet is sent to the // transport. -// TODO(asapersson): This class will remove the need for SendSideDelayObserver. -// Remove SendSideDelayObserver once possible. class SendPacketObserver { public: virtual ~SendPacketObserver() = default; - virtual void OnSendPacket(uint16_t packet_id, + virtual void OnSendPacket(absl::optional packet_id, Timestamp capture_time, uint32_t ssrc) = 0; }; diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc index 99fc030aca..f151084c7d 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc +++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc @@ -15,15 +15,9 @@ #include "rtc_base/checks.h" namespace webrtc { -namespace { - -constexpr Timestamp kInvalidLastReceiveTime = Timestamp::MinusInfinity(); -} // namespace - -constexpr TimeDelta AbsoluteCaptureTimeInterpolator::kInterpolationMaxInterval; AbsoluteCaptureTimeInterpolator::AbsoluteCaptureTimeInterpolator(Clock* clock) - : clock_(clock), last_receive_time_(kInvalidLastReceiveTime) {} + : clock_(clock) {} uint32_t AbsoluteCaptureTimeInterpolator::GetSource( uint32_t ssrc, @@ -39,68 +33,59 @@ absl::optional AbsoluteCaptureTimeInterpolator::OnReceivePacket( uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, + int rtp_clock_frequency_hz, const absl::optional& received_extension) { const Timestamp receive_time = clock_->CurrentTime(); MutexLock lock(&mutex_); - AbsoluteCaptureTime extension; if (received_extension == absl::nullopt) { if (!ShouldInterpolateExtension(receive_time, source, rtp_timestamp, - rtp_clock_frequency)) { - last_receive_time_ = kInvalidLastReceiveTime; + rtp_clock_frequency_hz)) { + last_receive_time_ = Timestamp::MinusInfinity(); return absl::nullopt; } - extension.absolute_capture_timestamp = InterpolateAbsoluteCaptureTimestamp( - rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_, - last_absolute_capture_timestamp_); - extension.estimated_capture_clock_offset = - last_estimated_capture_clock_offset_; + return AbsoluteCaptureTime{ + .absolute_capture_timestamp = InterpolateAbsoluteCaptureTimestamp( + rtp_timestamp, rtp_clock_frequency_hz, last_rtp_timestamp_, + last_received_extension_.absolute_capture_timestamp), + .estimated_capture_clock_offset = + last_received_extension_.estimated_capture_clock_offset, + }; } else { last_source_ = source; last_rtp_timestamp_ = rtp_timestamp; - last_rtp_clock_frequency_ = rtp_clock_frequency; - last_absolute_capture_timestamp_ = - received_extension->absolute_capture_timestamp; - last_estimated_capture_clock_offset_ = - received_extension->estimated_capture_clock_offset; + last_rtp_clock_frequency_hz_ = rtp_clock_frequency_hz; + last_received_extension_ = *received_extension; last_receive_time_ = receive_time; - extension = *received_extension; + return received_extension; } - - return extension; } uint64_t AbsoluteCaptureTimeInterpolator::InterpolateAbsoluteCaptureTimestamp( uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, + int rtp_clock_frequency_hz, uint32_t last_rtp_timestamp, uint64_t last_absolute_capture_timestamp) { - RTC_DCHECK_GT(rtp_clock_frequency, 0); + RTC_DCHECK_GT(rtp_clock_frequency_hz, 0); return last_absolute_capture_timestamp + - static_cast( - rtc::dchecked_cast(rtp_timestamp - last_rtp_timestamp) - << 32) / - rtp_clock_frequency; + static_cast(uint64_t{rtp_timestamp - last_rtp_timestamp} + << 32) / + rtp_clock_frequency_hz; } bool AbsoluteCaptureTimeInterpolator::ShouldInterpolateExtension( Timestamp receive_time, uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency) const { - // Shouldn't if we don't have a previously received extension stored. - if (last_receive_time_ == kInvalidLastReceiveTime) { - return false; - } - - // Shouldn't if the last received extension is too old. - if ((receive_time - last_receive_time_) > kInterpolationMaxInterval) { + int rtp_clock_frequency_hz) const { + // Shouldn't if the last received extension is not eligible for interpolation, + // in particular if we don't have a previously received extension stored. + if (receive_time - last_receive_time_ > kInterpolationMaxInterval) { return false; } @@ -110,12 +95,12 @@ bool AbsoluteCaptureTimeInterpolator::ShouldInterpolateExtension( } // Shouldn't if the RTP clock frequency has changed. - if (last_rtp_clock_frequency_ != rtp_clock_frequency) { + if (last_rtp_clock_frequency_hz_ != rtp_clock_frequency_hz) { return false; } // Shouldn't if the RTP clock frequency is invalid. - if (rtp_clock_frequency <= 0) { + if (rtp_clock_frequency_hz <= 0) { return false; } diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h index f5ec820dd5..c830686359 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h +++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h @@ -35,8 +35,7 @@ namespace webrtc { // class AbsoluteCaptureTimeInterpolator { public: - static constexpr TimeDelta kInterpolationMaxInterval = - TimeDelta::Millis(5000); + static constexpr TimeDelta kInterpolationMaxInterval = TimeDelta::Seconds(5); explicit AbsoluteCaptureTimeInterpolator(Clock* clock); @@ -49,7 +48,7 @@ class AbsoluteCaptureTimeInterpolator { absl::optional OnReceivePacket( uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, + int rtp_clock_frequency_hz, const absl::optional& received_extension); private: @@ -57,29 +56,31 @@ class AbsoluteCaptureTimeInterpolator { static uint64_t InterpolateAbsoluteCaptureTimestamp( uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, + int rtp_clock_frequency_hz, uint32_t last_rtp_timestamp, uint64_t last_absolute_capture_timestamp); bool ShouldInterpolateExtension(Timestamp receive_time, uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency) const + int rtp_clock_frequency_hz) const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); Clock* const clock_; Mutex mutex_; - Timestamp last_receive_time_ RTC_GUARDED_BY(mutex_); + // Time of the last received header extension eligible for interpolation, + // MinusInfinity() if no extension was received, or last received one is + // not eligible for interpolation. + Timestamp last_receive_time_ RTC_GUARDED_BY(mutex_) = + Timestamp::MinusInfinity(); uint32_t last_source_ RTC_GUARDED_BY(mutex_); uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(mutex_); - uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(mutex_); - uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(mutex_); - absl::optional last_estimated_capture_clock_offset_ - RTC_GUARDED_BY(mutex_); -}; // AbsoluteCaptureTimeInterpolator + int last_rtp_clock_frequency_hz_ RTC_GUARDED_BY(mutex_); + AbsoluteCaptureTime last_received_extension_ RTC_GUARDED_BY(mutex_); +}; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc index 6a312f9b43..4a48054777 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc +++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc @@ -32,13 +32,13 @@ TEST(AbsoluteCaptureTimeInterpolatorTest, GetSourceWithCsrcs) { TEST(AbsoluteCaptureTimeInterpolatorTest, ReceiveExtensionReturnsExtension) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9020), absl::nullopt}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9020), + absl::nullopt}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); @@ -55,299 +55,291 @@ TEST(AbsoluteCaptureTimeInterpolatorTest, ReceiveExtensionReturnsExtension) { TEST(AbsoluteCaptureTimeInterpolatorTest, ReceiveNoExtensionReturnsNoExtension) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; - static const absl::optional kExtension0 = absl::nullopt; - static const absl::optional kExtension1 = absl::nullopt; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); - EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - absl::nullopt); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); - EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp1, - kRtpClockFrequency, kExtension1), - absl::nullopt); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); } TEST(AbsoluteCaptureTimeInterpolatorTest, InterpolateLaterPacketArrivingLater) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - absl::optional extension = interpolator.OnReceivePacket( - kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); - EXPECT_TRUE(extension.has_value()); + absl::optional extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) + 20); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); - extension = interpolator.OnReceivePacket(kSource, kRtpTimestamp2, - kRtpClockFrequency, kExtension2); - EXPECT_TRUE(extension.has_value()); + extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) + 40); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); } TEST(AbsoluteCaptureTimeInterpolatorTest, InterpolateEarlierPacketArrivingLater) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - absl::optional extension = interpolator.OnReceivePacket( - kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); - EXPECT_TRUE(extension.has_value()); + absl::optional extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) - 20); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); - extension = interpolator.OnReceivePacket(kSource, kRtpTimestamp2, - kRtpClockFrequency, kExtension2); - EXPECT_TRUE(extension.has_value()); + extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) - 40); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); } TEST(AbsoluteCaptureTimeInterpolatorTest, InterpolateLaterPacketArrivingLaterWithRtpTimestampWrapAround) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; - constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79; + constexpr int kRtpClockFrequency = 64'000; + constexpr uint32_t kRtpTimestamp0 = uint32_t{0} - 80; constexpr uint32_t kRtpTimestamp1 = 1280 - 80; constexpr uint32_t kRtpTimestamp2 = 2560 - 80; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - absl::optional extension = interpolator.OnReceivePacket( - kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); - EXPECT_TRUE(extension.has_value()); + absl::optional extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) + 20); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); - extension = interpolator.OnReceivePacket(kSource, kRtpTimestamp2, - kRtpClockFrequency, kExtension2); - EXPECT_TRUE(extension.has_value()); + extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) + 40); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); } TEST(AbsoluteCaptureTimeInterpolatorTest, InterpolateEarlierPacketArrivingLaterWithRtpTimestampWrapAround) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 799; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - absl::optional extension = interpolator.OnReceivePacket( - kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); - EXPECT_TRUE(extension.has_value()); + absl::optional extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) - 20); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); - extension = interpolator.OnReceivePacket(kSource, kRtpTimestamp2, - kRtpClockFrequency, kExtension2); - EXPECT_TRUE(extension.has_value()); + extension = + interpolator.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt); + ASSERT_TRUE(extension.has_value()); EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), - UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40); + UQ32x32ToInt64Ms(kExtension.absolute_capture_timestamp) - 40); EXPECT_EQ(extension->estimated_capture_clock_offset, - kExtension0->estimated_capture_clock_offset); + kExtension.estimated_capture_clock_offset); } TEST(AbsoluteCaptureTimeInterpolatorTest, SkipInterpolateIfTooLate) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); clock.AdvanceTime(AbsoluteCaptureTimeInterpolator::kInterpolationMaxInterval); - EXPECT_TRUE(interpolator - .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1) - .has_value()); + EXPECT_NE( + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); - clock.AdvanceTimeMilliseconds(1); + clock.AdvanceTime(TimeDelta::Millis(1)); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2) - .has_value()); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); } TEST(AbsoluteCaptureTimeInterpolatorTest, SkipInterpolateIfSourceChanged) { constexpr uint32_t kSource0 = 1337; constexpr uint32_t kSource1 = 1338; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource0, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource1, kRtpTimestamp1, - kRtpClockFrequency, kExtension1) - .has_value()); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource1, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); } TEST(AbsoluteCaptureTimeInterpolatorTest, SkipInterpolateIfRtpClockFrequencyChanged) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency0 = 64000; - constexpr uint32_t kRtpClockFrequency1 = 32000; + constexpr int kRtpClockFrequency0 = 64'000; + constexpr int kRtpClockFrequency1 = 32'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency0, kExtension0), - kExtension0); + kRtpClockFrequency0, kExtension), + kExtension); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource, kRtpTimestamp1, - kRtpClockFrequency1, kExtension1) - .has_value()); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency1, + /*received_extension=*/absl::nullopt), + absl::nullopt); } TEST(AbsoluteCaptureTimeInterpolatorTest, SkipInterpolateIfRtpClockFrequencyIsInvalid) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 0; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); - EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource, kRtpTimestamp0, + /*rtp_clock_frequency_hz=*/0, kExtension), + kExtension); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1) - .has_value()); + EXPECT_EQ(interpolator.OnReceivePacket(kSource, kRtpTimestamp1, + /*rtp_clock_frequency_hz=*/0, + /*received_extension=*/absl::nullopt), + absl::nullopt); } TEST(AbsoluteCaptureTimeInterpolatorTest, SkipInterpolateIsSticky) { constexpr uint32_t kSource0 = 1337; constexpr uint32_t kSource1 = 1338; - constexpr uint32_t kSource2 = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = absl::nullopt; - static const absl::optional kExtension2 = absl::nullopt; + const AbsoluteCaptureTime kExtension = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeInterpolator interpolator(&clock); EXPECT_EQ(interpolator.OnReceivePacket(kSource0, kRtpTimestamp0, - kRtpClockFrequency, kExtension0), - kExtension0); + kRtpClockFrequency, kExtension), + kExtension); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource1, kRtpTimestamp1, - kRtpClockFrequency, kExtension1) - .has_value()); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource1, kRtpTimestamp1, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); - EXPECT_FALSE(interpolator - .OnReceivePacket(kSource2, kRtpTimestamp2, - kRtpClockFrequency, kExtension2) - .has_value()); + EXPECT_EQ( + interpolator.OnReceivePacket(kSource0, kRtpTimestamp2, kRtpClockFrequency, + /*received_extension=*/absl::nullopt), + absl::nullopt); } } // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc index 28266769ff..09f61a0ace 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_sender.cc +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc @@ -16,14 +16,6 @@ #include "system_wrappers/include/ntp_time.h" namespace webrtc { -namespace { - -constexpr Timestamp kInvalidLastSendTime = Timestamp::MinusInfinity(); - -} // namespace - -constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxInterval; -constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxError; static_assert( AbsoluteCaptureTimeInterpolator::kInterpolationMaxInterval >= @@ -31,7 +23,7 @@ static_assert( "Receivers should be as willing to interpolate timestamps as senders."); AbsoluteCaptureTimeSender::AbsoluteCaptureTimeSender(Clock* clock) - : clock_(clock), last_send_time_(kInvalidLastSendTime) {} + : clock_(clock) {} uint32_t AbsoluteCaptureTimeSender::GetSource( uint32_t ssrc, @@ -45,44 +37,48 @@ absl::optional AbsoluteCaptureTimeSender::OnSendPacket( uint32_t rtp_clock_frequency, uint64_t absolute_capture_timestamp, absl::optional estimated_capture_clock_offset) { - const Timestamp send_time = clock_->CurrentTime(); + return OnSendPacket(source, rtp_timestamp, rtp_clock_frequency, + NtpTime(absolute_capture_timestamp), + estimated_capture_clock_offset, /*force=*/false); +} - MutexLock lock(&mutex_); - - if (!ShouldSendExtension(send_time, source, rtp_timestamp, - rtp_clock_frequency, absolute_capture_timestamp, - estimated_capture_clock_offset)) { +absl::optional AbsoluteCaptureTimeSender::OnSendPacket( + uint32_t source, + uint32_t rtp_timestamp, + int rtp_clock_frequency_hz, + NtpTime absolute_capture_time, + absl::optional estimated_capture_clock_offset, + bool force) { + Timestamp send_time = clock_->CurrentTime(); + if (!(force || ShouldSendExtension( + send_time, source, rtp_timestamp, rtp_clock_frequency_hz, + absolute_capture_time, estimated_capture_clock_offset))) { return absl::nullopt; } last_source_ = source; last_rtp_timestamp_ = rtp_timestamp; - last_rtp_clock_frequency_ = rtp_clock_frequency; - last_absolute_capture_timestamp_ = absolute_capture_timestamp; + last_rtp_clock_frequency_hz_ = rtp_clock_frequency_hz; + last_absolute_capture_time_ = absolute_capture_time; last_estimated_capture_clock_offset_ = estimated_capture_clock_offset; - last_send_time_ = send_time; - AbsoluteCaptureTime extension; - extension.absolute_capture_timestamp = absolute_capture_timestamp; - extension.estimated_capture_clock_offset = estimated_capture_clock_offset; - return extension; + return AbsoluteCaptureTime{ + .absolute_capture_timestamp = uint64_t{absolute_capture_time}, + .estimated_capture_clock_offset = estimated_capture_clock_offset, + }; } bool AbsoluteCaptureTimeSender::ShouldSendExtension( Timestamp send_time, uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, - uint64_t absolute_capture_timestamp, + int rtp_clock_frequency_hz, + NtpTime absolute_capture_time, absl::optional estimated_capture_clock_offset) const { - // Should if we've never sent anything before. - if (last_send_time_ == kInvalidLastSendTime) { - return true; - } - - // Should if the last sent extension is too old. - if ((send_time - last_send_time_) > kInterpolationMaxInterval) { + // Should if the last sent extension is too old, in particular if we've never + // sent anything before. + if (send_time - last_send_time_ > kInterpolationMaxInterval) { return true; } @@ -92,12 +88,12 @@ bool AbsoluteCaptureTimeSender::ShouldSendExtension( } // Should if the RTP clock frequency has changed. - if (last_rtp_clock_frequency_ != rtp_clock_frequency) { + if (last_rtp_clock_frequency_hz_ != rtp_clock_frequency_hz) { return true; } // Should if the RTP clock frequency is invalid. - if (rtp_clock_frequency <= 0) { + if (rtp_clock_frequency_hz <= 0) { return true; } @@ -109,8 +105,9 @@ bool AbsoluteCaptureTimeSender::ShouldSendExtension( // Should if interpolation would introduce too much error. const uint64_t interpolated_absolute_capture_timestamp = AbsoluteCaptureTimeInterpolator::InterpolateAbsoluteCaptureTimestamp( - rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_, - last_absolute_capture_timestamp_); + rtp_timestamp, rtp_clock_frequency_hz, last_rtp_timestamp_, + uint64_t{last_absolute_capture_time_}); + const uint64_t absolute_capture_timestamp = uint64_t{absolute_capture_time}; const int64_t interpolation_error_ms = UQ32x32ToInt64Ms(std::min( interpolated_absolute_capture_timestamp - absolute_capture_timestamp, absolute_capture_timestamp - interpolated_absolute_capture_timestamp)); diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.h b/modules/rtp_rtcp/source/absolute_capture_time_sender.h index be5a77d5e1..a961c3bb2f 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_sender.h +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.h @@ -15,9 +15,8 @@ #include "api/rtp_headers.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" -#include "rtc_base/synchronization/mutex.h" -#include "rtc_base/thread_annotations.h" #include "system_wrappers/include/clock.h" +#include "system_wrappers/include/ntp_time.h" namespace webrtc { @@ -40,8 +39,7 @@ namespace webrtc { // class AbsoluteCaptureTimeSender { public: - static constexpr TimeDelta kInterpolationMaxInterval = - TimeDelta::Millis(1000); + static constexpr TimeDelta kInterpolationMaxInterval = TimeDelta::Seconds(1); static constexpr TimeDelta kInterpolationMaxError = TimeDelta::Millis(1); explicit AbsoluteCaptureTimeSender(Clock* clock); @@ -50,9 +48,34 @@ class AbsoluteCaptureTimeSender { static uint32_t GetSource(uint32_t ssrc, rtc::ArrayView csrcs); + // Returns value to write into AbsoluteCaptureTime RTP header extension to be + // sent, or `absl::nullopt` if the header extension shouldn't be attached to + // the outgoing packet. + // + // - `source` - id of the capture system. + // - `rtp_timestamp` - capture time represented as rtp timestamp in the + // outgoing packet + // - `rtp_clock_frequency_hz` - description of the `rtp_timestamp` units - + // `rtp_timetamp` delta of `rtp_clock_freqnecy_hz` represents 1 second. + // - `absolute_capture_time` - time when a frame was captured by the capture + // system. + // - `estimated_capture_clock_offset` - estimated offset between capture + // system clock and local `clock` passed as the AbsoluteCaptureTimeSender + // construction paramter. Uses the same units as `absolute_capture_time`, + // i.e. delta of 2^32 represents 1 second. See AbsoluteCaptureTime type + // comments for more details. + // - `force` - when set to true, OnSendPacket is forced to return non-nullopt. + absl::optional OnSendPacket( + uint32_t source, + uint32_t rtp_timestamp, + int rtp_clock_frequency_hz, + NtpTime absolute_capture_time, + absl::optional estimated_capture_clock_offset, + bool force = false); + // Returns a header extension to be sent, or `absl::nullopt` if the header // extension shouldn't be sent. - absl::optional OnSendPacket( + [[deprecated]] absl::optional OnSendPacket( uint32_t source, uint32_t rtp_timestamp, uint32_t rtp_clock_frequency, @@ -64,24 +87,20 @@ class AbsoluteCaptureTimeSender { Timestamp send_time, uint32_t source, uint32_t rtp_timestamp, - uint32_t rtp_clock_frequency, - uint64_t absolute_capture_timestamp, - absl::optional estimated_capture_clock_offset) const - RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + int rtp_clock_frequency_hz, + NtpTime absolute_capture_time, + absl::optional estimated_capture_clock_offset) const; Clock* const clock_; - Mutex mutex_; + Timestamp last_send_time_ = Timestamp::MinusInfinity(); - Timestamp last_send_time_ RTC_GUARDED_BY(mutex_); - - uint32_t last_source_ RTC_GUARDED_BY(mutex_); - uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(mutex_); - uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(mutex_); - uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(mutex_); - absl::optional last_estimated_capture_clock_offset_ - RTC_GUARDED_BY(mutex_); -}; // AbsoluteCaptureTimeSender + uint32_t last_source_; + uint32_t last_rtp_timestamp_; + int last_rtp_clock_frequency_hz_; + NtpTime last_absolute_capture_time_; + absl::optional last_estimated_capture_clock_offset_; +}; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc index db3fc75100..d9146e4611 100644 --- a/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc @@ -19,7 +19,7 @@ namespace webrtc { TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithoutCsrcs) { constexpr uint32_t kSsrc = 12; - EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, nullptr), kSsrc); + EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, {}), kSsrc); } TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithCsrcs) { @@ -31,343 +31,368 @@ TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithCsrcs) { TEST(AbsoluteCaptureTimeSenderTest, InterpolateLaterPacketSentLater) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, InterpolateEarlierPacketSentLater) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 - 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 - 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, InterpolateLaterPacketSentLaterWithRtpTimestampWrapAround) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; - constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79; + constexpr int kRtpClockFrequency = 64'000; + constexpr uint32_t kRtpTimestamp0 = uint32_t{0} - 80; constexpr uint32_t kRtpTimestamp1 = 1280 - 80; constexpr uint32_t kRtpTimestamp2 = 2560 - 80; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, InterpolateEarlierPacketSentLaterWithRtpTimestampWrapAround) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 799; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 - 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 - 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfTooLate) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); clock.AdvanceTime(AbsoluteCaptureTimeSender::kInterpolationMaxInterval); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); - clock.AdvanceTimeMicroseconds(1); + clock.AdvanceTime(TimeDelta::Millis(1)); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), kExtension2); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfSourceChanged) { constexpr uint32_t kSource0 = 1337; constexpr uint32_t kSource1 = 1338; - constexpr uint32_t kSource2 = 1338; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource0, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource1, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), kExtension1); - EXPECT_EQ(sender.OnSendPacket(kSource2, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + EXPECT_EQ(sender.OnSendPacket(kSource1, kRtpTimestamp2, kRtpClockFrequency, + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateWhenForced) { + constexpr uint32_t kSource = 1337; + constexpr int kRtpClockFrequency = 64'000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset, + /*force=*/true), + kExtension1); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset, + /*force=*/false), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfRtpClockFrequencyChanged) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency0 = 64000; - constexpr uint32_t kRtpClockFrequency1 = 32000; - constexpr uint32_t kRtpClockFrequency2 = 32000; + constexpr int kRtpClockFrequency0 = 64'000; + constexpr int kRtpClockFrequency1 = 32'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 1280; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), kExtension1); - EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency1, + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), absl::nullopt); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfRtpClockFrequencyIsInvalid) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency0 = 0; - constexpr uint32_t kRtpClockFrequency1 = 0; - constexpr uint32_t kRtpClockFrequency2 = 0; - constexpr uint32_t kRtpTimestamp0 = 1020300000; - constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0; - constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + constexpr int kRtpClockFrequency = 0; + constexpr uint32_t kRtpTimestamp = 1020300000; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); - EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp, kRtpClockFrequency, + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); - EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp, kRtpClockFrequency, + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), kExtension1); - EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp, kRtpClockFrequency, + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), kExtension2); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfEstimatedCaptureClockOffsetChanged) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(370)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), absl::nullopt}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = {Int64MsToUQ32x32(9000 + 20), + Int64MsToQ32x32(370)}; + const AbsoluteCaptureTime kExtension2 = {Int64MsToUQ32x32(9000 + 40), + absl::nullopt}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), kExtension1); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), kExtension2); } TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfTooMuchInterpolationError) { constexpr uint32_t kSource = 1337; - constexpr uint32_t kRtpClockFrequency = 64000; + constexpr int kRtpClockFrequency = 64'000; constexpr uint32_t kRtpTimestamp0 = 1020300000; constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; - static const absl::optional kExtension0 = - AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; - static const absl::optional kExtension1 = - AbsoluteCaptureTime{ - Int64MsToUQ32x32( - 9000 + 20 + - AbsoluteCaptureTimeSender::kInterpolationMaxError.ms()), - Int64MsToQ32x32(-350)}; - static const absl::optional kExtension2 = - AbsoluteCaptureTime{ - Int64MsToUQ32x32( - 9000 + 40 + - AbsoluteCaptureTimeSender::kInterpolationMaxError.ms() + 1), - Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension0 = {Int64MsToUQ32x32(9000), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension1 = { + Int64MsToUQ32x32(9000 + 20 + + AbsoluteCaptureTimeSender::kInterpolationMaxError.ms()), + Int64MsToQ32x32(-350)}; + const AbsoluteCaptureTime kExtension2 = { + Int64MsToUQ32x32(9000 + 40 + + AbsoluteCaptureTimeSender::kInterpolationMaxError.ms() + + 1), + Int64MsToQ32x32(-350)}; SimulatedClock clock(0); AbsoluteCaptureTimeSender sender(&clock); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, - kExtension0->absolute_capture_timestamp, - kExtension0->estimated_capture_clock_offset), + NtpTime(kExtension0.absolute_capture_timestamp), + kExtension0.estimated_capture_clock_offset), kExtension0); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, - kExtension1->absolute_capture_timestamp, - kExtension1->estimated_capture_clock_offset), + NtpTime(kExtension1.absolute_capture_timestamp), + kExtension1.estimated_capture_clock_offset), absl::nullopt); EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, - kExtension2->absolute_capture_timestamp, - kExtension2->estimated_capture_clock_offset), + NtpTime(kExtension2.absolute_capture_timestamp), + kExtension2.estimated_capture_clock_offset), kExtension2); } diff --git a/modules/rtp_rtcp/source/capture_clock_offset_updater.cc b/modules/rtp_rtcp/source/capture_clock_offset_updater.cc index a5b12cb422..ad935a94f0 100644 --- a/modules/rtp_rtcp/source/capture_clock_offset_updater.cc +++ b/modules/rtp_rtcp/source/capture_clock_offset_updater.cc @@ -10,6 +10,8 @@ #include "modules/rtp_rtcp/source/capture_clock_offset_updater.h" +#include "system_wrappers/include/ntp_time.h" + namespace webrtc { absl::optional @@ -25,6 +27,14 @@ CaptureClockOffsetUpdater::AdjustEstimatedCaptureClockOffset( static_cast(*remote_to_local_clock_offset_); } +absl::optional CaptureClockOffsetUpdater::ConvertsToTimeDela( + absl::optional q32x32) { + if (q32x32 == absl::nullopt) { + return absl::nullopt; + } + return TimeDelta::Millis(Q32x32ToInt64Ms(*q32x32)); +} + void CaptureClockOffsetUpdater::SetRemoteToLocalClockOffset( absl::optional offset_q32x32) { remote_to_local_clock_offset_ = offset_q32x32; diff --git a/modules/rtp_rtcp/source/capture_clock_offset_updater.h b/modules/rtp_rtcp/source/capture_clock_offset_updater.h index 71d3eb4831..9b28848169 100644 --- a/modules/rtp_rtcp/source/capture_clock_offset_updater.h +++ b/modules/rtp_rtcp/source/capture_clock_offset_updater.h @@ -14,6 +14,7 @@ #include #include "absl/types/optional.h" +#include "api/units/time_delta.h" namespace webrtc { @@ -42,6 +43,10 @@ class CaptureClockOffsetUpdater { // Note that the value must be in Q32.32-formatted fixed-point seconds. void SetRemoteToLocalClockOffset(absl::optional offset_q32x32); + // Converts a signed Q32.32-formatted fixed-point to a TimeDelta. + static absl::optional ConvertsToTimeDela( + absl::optional q32x32); + private: absl::optional remote_to_local_clock_offset_; }; diff --git a/modules/rtp_rtcp/source/capture_clock_offset_updater_unittest.cc b/modules/rtp_rtcp/source/capture_clock_offset_updater_unittest.cc index 43e1dd1379..f6bea4ba96 100644 --- a/modules/rtp_rtcp/source/capture_clock_offset_updater_unittest.cc +++ b/modules/rtp_rtcp/source/capture_clock_offset_updater_unittest.cc @@ -55,4 +55,25 @@ TEST(AbsoluteCaptureTimeReceiverTest, EstimatedCaptureClockOffsetArithmetic) { *kRemoteToLocalClockOffset))); } +TEST(AbsoluteCaptureTimeReceiverTest, ConvertClockOffset) { + constexpr TimeDelta kNegative = TimeDelta::Millis(-350); + constexpr int64_t kNegativeQ32x32 = + kNegative.ms() * (NtpTime::kFractionsPerSecond / 1000); + constexpr TimeDelta kPositive = TimeDelta::Millis(400); + constexpr int64_t kPositiveQ32x32 = + kPositive.ms() * (NtpTime::kFractionsPerSecond / 1000); + constexpr TimeDelta kEpsilon = TimeDelta::Millis(1); + absl::optional converted = + CaptureClockOffsetUpdater::ConvertsToTimeDela(kNegativeQ32x32); + EXPECT_GT(converted, kNegative - kEpsilon); + EXPECT_LT(converted, kNegative + kEpsilon); + + converted = CaptureClockOffsetUpdater::ConvertsToTimeDela(kPositiveQ32x32); + EXPECT_GT(converted, kPositive - kEpsilon); + EXPECT_LT(converted, kPositive + kEpsilon); + + EXPECT_FALSE( + CaptureClockOffsetUpdater::ConvertsToTimeDela(absl::nullopt).has_value()); +} + } // namespace webrtc diff --git a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc index f1e4eddb4b..95db212bef 100644 --- a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc +++ b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc @@ -33,6 +33,9 @@ std::unique_ptr CreateVideoRtpDepacketizer( return std::make_unique(); case kVideoCodecAV1: return std::make_unique(); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265. + return nullptr; case kVideoCodecGeneric: case kVideoCodecMultiplex: return std::make_unique(); diff --git a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc index e2531bb1b1..59ff9d70f1 100644 --- a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc @@ -23,7 +23,6 @@ namespace webrtc { namespace { constexpr uint32_t kTimestampTicksPerMs = 90; -constexpr int kSendSideDelayWindowMs = 1000; constexpr TimeDelta kBitrateStatisticsWindow = TimeDelta::Seconds(1); constexpr size_t kRtpSequenceNumberMapMaxEntries = 1 << 13; @@ -73,15 +72,12 @@ DEPRECATED_RtpSenderEgress::DEPRECATED_RtpSenderEgress( is_audio_(config.audio), need_rtp_packet_infos_(config.need_rtp_packet_infos), transport_feedback_observer_(config.transport_feedback_callback), - send_side_delay_observer_(config.send_side_delay_observer), send_packet_observer_(config.send_packet_observer), rtp_stats_callback_(config.rtp_stats_callback), bitrate_callback_(config.send_bitrate_observer), media_has_been_sent_(false), force_part_of_allocation_(false), timestamp_offset_(0), - max_delay_it_(send_delays_.end()), - sum_delays_ms_(0), send_rates_(kNumMediaTypes, BitrateTracker(kBitrateStatisticsWindow)), rtp_sequence_number_map_(need_rtp_packet_infos_ ? std::make_unique( @@ -180,7 +176,6 @@ void DEPRECATED_RtpSenderEgress::SendPacket( if (packet->packet_type() != RtpPacketMediaType::kPadding && packet->packet_type() != RtpPacketMediaType::kRetransmission) { - UpdateDelayStatistics(packet->capture_time().ms(), now_ms, packet_ssrc); UpdateOnSendPacket(options.packet_id, packet->capture_time().ms(), packet_ssrc); } @@ -317,88 +312,6 @@ void DEPRECATED_RtpSenderEgress::AddPacketToTransportFeedback( } } -void DEPRECATED_RtpSenderEgress::UpdateDelayStatistics(int64_t capture_time_ms, - int64_t now_ms, - uint32_t ssrc) { - if (!send_side_delay_observer_ || capture_time_ms <= 0) - return; - - int avg_delay_ms = 0; - int max_delay_ms = 0; - { - MutexLock lock(&lock_); - // Compute the max and average of the recent capture-to-send delays. - // The time complexity of the current approach depends on the distribution - // of the delay values. This could be done more efficiently. - - // Remove elements older than kSendSideDelayWindowMs. - auto lower_bound = - send_delays_.lower_bound(now_ms - kSendSideDelayWindowMs); - for (auto it = send_delays_.begin(); it != lower_bound; ++it) { - if (max_delay_it_ == it) { - max_delay_it_ = send_delays_.end(); - } - sum_delays_ms_ -= it->second; - } - send_delays_.erase(send_delays_.begin(), lower_bound); - if (max_delay_it_ == send_delays_.end()) { - // Removed the previous max. Need to recompute. - RecomputeMaxSendDelay(); - } - - // Add the new element. - RTC_DCHECK_GE(now_ms, 0); - RTC_DCHECK_LE(now_ms, std::numeric_limits::max() / 2); - RTC_DCHECK_GE(capture_time_ms, 0); - RTC_DCHECK_LE(capture_time_ms, std::numeric_limits::max() / 2); - int64_t diff_ms = now_ms - capture_time_ms; - RTC_DCHECK_GE(diff_ms, static_cast(0)); - RTC_DCHECK_LE(diff_ms, std::numeric_limits::max()); - int new_send_delay = rtc::dchecked_cast(now_ms - capture_time_ms); - SendDelayMap::iterator it; - bool inserted; - std::tie(it, inserted) = - send_delays_.insert(std::make_pair(now_ms, new_send_delay)); - if (!inserted) { - // TODO(terelius): If we have multiple delay measurements during the same - // millisecond then we keep the most recent one. It is not clear that this - // is the right decision, but it preserves an earlier behavior. - int previous_send_delay = it->second; - sum_delays_ms_ -= previous_send_delay; - it->second = new_send_delay; - if (max_delay_it_ == it && new_send_delay < previous_send_delay) { - RecomputeMaxSendDelay(); - } - } - if (max_delay_it_ == send_delays_.end() || - it->second >= max_delay_it_->second) { - max_delay_it_ = it; - } - sum_delays_ms_ += new_send_delay; - - size_t num_delays = send_delays_.size(); - RTC_DCHECK(max_delay_it_ != send_delays_.end()); - max_delay_ms = rtc::dchecked_cast(max_delay_it_->second); - int64_t avg_ms = (sum_delays_ms_ + num_delays / 2) / num_delays; - RTC_DCHECK_GE(avg_ms, static_cast(0)); - RTC_DCHECK_LE(avg_ms, - static_cast(std::numeric_limits::max())); - avg_delay_ms = - rtc::dchecked_cast((sum_delays_ms_ + num_delays / 2) / num_delays); - } - send_side_delay_observer_->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, - ssrc); -} - -void DEPRECATED_RtpSenderEgress::RecomputeMaxSendDelay() { - max_delay_it_ = send_delays_.begin(); - for (auto it = send_delays_.begin(); it != send_delays_.end(); ++it) { - if (it->second >= max_delay_it_->second) { - max_delay_it_ = it; - } - } -} - void DEPRECATED_RtpSenderEgress::UpdateOnSendPacket(int packet_id, int64_t capture_time_ms, uint32_t ssrc) { diff --git a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.h b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.h index e786d90c2f..9d343c2d08 100644 --- a/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.h +++ b/modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.h @@ -83,20 +83,11 @@ class DEPRECATED_RtpSenderEgress { RTC_LOCKS_EXCLUDED(lock_); private: - // Maps capture time in milliseconds to send-side delay in milliseconds. - // Send-side delay is the difference between transmission time and capture - // time. - typedef std::map SendDelayMap; - RtpSendRates GetSendRatesLocked() const RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); bool HasCorrectSsrc(const RtpPacketToSend& packet) const; void AddPacketToTransportFeedback(uint16_t packet_id, const RtpPacketToSend& packet, const PacedPacketInfo& pacing_info); - void UpdateDelayStatistics(int64_t capture_time_ms, - int64_t now_ms, - uint32_t ssrc); - void RecomputeMaxSendDelay() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); void UpdateOnSendPacket(int packet_id, int64_t capture_time_ms, uint32_t ssrc); @@ -119,7 +110,6 @@ class DEPRECATED_RtpSenderEgress { const bool need_rtp_packet_infos_; TransportFeedbackObserver* const transport_feedback_observer_; - SendSideDelayObserver* const send_side_delay_observer_; SendPacketObserver* const send_packet_observer_; StreamDataCountersCallback* const rtp_stats_callback_; BitrateStatisticsObserver* const bitrate_callback_; @@ -129,10 +119,6 @@ class DEPRECATED_RtpSenderEgress { bool force_part_of_allocation_ RTC_GUARDED_BY(lock_); uint32_t timestamp_offset_ RTC_GUARDED_BY(lock_); - SendDelayMap send_delays_ RTC_GUARDED_BY(lock_); - SendDelayMap::const_iterator max_delay_it_ RTC_GUARDED_BY(lock_); - // The sum of delays over a kSendSideDelayWindowMs sliding window. - int64_t sum_delays_ms_ RTC_GUARDED_BY(lock_); StreamDataCounters rtp_stats_ RTC_GUARDED_BY(lock_); StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(lock_); // One element per value in RtpPacketMediaType, with index matching value. diff --git a/modules/rtp_rtcp/source/frame_object.cc b/modules/rtp_rtcp/source/frame_object.cc index 734f1b0a4f..23abe3a61f 100644 --- a/modules/rtp_rtcp/source/frame_object.cc +++ b/modules/rtp_rtcp/source/frame_object.cc @@ -51,7 +51,7 @@ RtpFrameObject::RtpFrameObject( // VCMEncodedFrame members CopyCodecSpecific(&rtp_video_header_); _payloadType = payload_type; - SetTimestamp(rtp_timestamp); + SetRtpTimestamp(rtp_timestamp); ntp_time_ms_ = ntp_time_ms; _frameType = rtp_video_header_.frame_type; diff --git a/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc index 8dbfaec940..3737d66f07 100644 --- a/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc +++ b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc @@ -44,7 +44,7 @@ class RemoteNtpTimeEstimatorTest : public ::testing::Test { NtpTime ntp = remote_clock_.CurrentNtpTime(); AdvanceTime(kTestRtt / 2); - RTC_DCHECK(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp)); + EXPECT_TRUE(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp)); } void SendRtcpSrInaccurately(TimeDelta ntp_error, TimeDelta networking_delay) { @@ -53,7 +53,7 @@ class RemoteNtpTimeEstimatorTest : public ::testing::Test { NtpTime ntp(static_cast(remote_clock_.CurrentNtpTime()) + ntp_error_fractions); AdvanceTime(kTestRtt / 2 + networking_delay); - RTC_DCHECK(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp)); + EXPECT_TRUE(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp)); } SimulatedClock local_clock_{kLocalClockInitialTime}; 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 4248a4d3ee..356d7a2340 100644 --- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc @@ -60,11 +60,11 @@ MATCHER(IsValidFeedback, "") { TransportFeedback Parse(rtc::ArrayView buffer) { rtcp::CommonHeader header; - RTC_DCHECK(header.Parse(buffer.data(), buffer.size())); - RTC_DCHECK_EQ(header.type(), TransportFeedback::kPacketType); - RTC_DCHECK_EQ(header.fmt(), TransportFeedback::kFeedbackMessageType); + EXPECT_TRUE(header.Parse(buffer.data(), buffer.size())); + EXPECT_EQ(header.type(), TransportFeedback::kPacketType); + EXPECT_EQ(header.fmt(), TransportFeedback::kFeedbackMessageType); TransportFeedback feedback; - RTC_DCHECK(feedback.Parse(header)); + EXPECT_TRUE(feedback.Parse(header)); return feedback; } @@ -89,7 +89,7 @@ class FeedbackTester { temp_timestamps = GenerateReceiveTimestamps(received_seq); received_ts = temp_timestamps; } - RTC_DCHECK_EQ(received_seq.size(), received_ts.size()); + ASSERT_EQ(received_seq.size(), received_ts.size()); expected_deltas_.clear(); feedback_.emplace(include_timestamps_); @@ -150,7 +150,7 @@ class FeedbackTester { std::vector GenerateReceiveTimestamps( rtc::ArrayView seq_nums) { - RTC_DCHECK(!seq_nums.empty()); + RTC_CHECK(!seq_nums.empty()); uint16_t last_seq = seq_nums[0]; Timestamp time = Timestamp::Zero(); std::vector result; diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc index 9ca092c0cf..de68885519 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/modules/rtp_rtcp/source/rtcp_sender.cc @@ -212,23 +212,8 @@ bool RTCPSender::Sending() const { void RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, bool sending) { - bool sendRTCPBye = false; - { - MutexLock lock(&mutex_rtcp_sender_); - - if (method_ != RtcpMode::kOff) { - if (sending == false && sending_ == true) { - // Trigger RTCP bye - sendRTCPBye = true; - } - } - sending_ = sending; - } - if (sendRTCPBye) { - if (SendRTCP(feedback_state, kRtcpBye) != 0) { - RTC_LOG(LS_WARNING) << "Failed to send RTCP BYE"; - } - } + MutexLock lock(&mutex_rtcp_sender_); + sending_ = sending; } void RTCPSender::SetNonSenderRttMeasurement(bool enabled) { diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 1dcb628722..002a5f86f1 100644 --- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -328,13 +328,12 @@ TEST_F(RtcpSenderTest, SendBye) { EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc()); } -TEST_F(RtcpSenderTest, StopSendingTriggersBye) { +TEST_F(RtcpSenderTest, StopSendingDoesNotTriggersBye) { auto rtcp_sender = CreateRtcpSender(GetDefaultConfig()); rtcp_sender->SetRTCPStatus(RtcpMode::kReducedSize); rtcp_sender->SetSendingStatus(feedback_state(), true); rtcp_sender->SetSendingStatus(feedback_state(), false); - EXPECT_EQ(1, parser()->bye()->num_packets()); - EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc()); + EXPECT_EQ(0, parser()->bye()->num_packets()); } TEST_F(RtcpSenderTest, SendFir) { diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 7550b70f69..2c11a29bfa 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -57,6 +57,7 @@ std::unique_ptr RtpPacketizer::Create( return std::make_unique( payload, limits, rtp_video_header.frame_type, rtp_video_header.is_last_frame_in_picture); + // TODO(bugs.webrtc.org/13485): Implement RtpPacketizerH265. default: { return std::make_unique(payload, limits, rtp_video_header); diff --git a/modules/rtp_rtcp/source/rtp_format_h264.cc b/modules/rtp_rtcp/source/rtp_format_h264.cc index cc8d1bff34..d066bafb90 100644 --- a/modules/rtp_rtcp/source/rtp_format_h264.cc +++ b/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -153,28 +153,25 @@ bool RtpPacketizerH264::PacketizeFuA(size_t fragment_index) { size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { // Aggregate fragments into one packet (STAP-A). size_t payload_size_left = limits_.max_payload_len; - if (input_fragments_.size() == 1) - payload_size_left -= limits_.single_packet_reduction_len; - else if (fragment_index == 0) - payload_size_left -= limits_.first_packet_reduction_len; int aggregated_fragments = 0; size_t fragment_headers_length = 0; rtc::ArrayView fragment = input_fragments_[fragment_index]; RTC_CHECK_GE(payload_size_left, fragment.size()); ++num_packets_left_; + const bool has_first_fragment = fragment_index == 0; auto payload_size_needed = [&] { size_t fragment_size = fragment.size() + fragment_headers_length; - if (input_fragments_.size() == 1) { - // Single fragment, single packet, payload_size_left already adjusted - // with limits_.single_packet_reduction_len. + bool has_last_fragment = fragment_index == input_fragments_.size() - 1; + if (has_first_fragment && has_last_fragment) { + return fragment_size + limits_.single_packet_reduction_len; + } else if (has_first_fragment) { + return fragment_size + limits_.first_packet_reduction_len; + } else if (has_last_fragment) { + return fragment_size + limits_.last_packet_reduction_len; + } else { return fragment_size; } - if (fragment_index == input_fragments_.size() - 1) { - // Last fragment, so STAP-A might be the last packet. - return fragment_size + limits_.last_packet_reduction_len; - } - return fragment_size; }; while (payload_size_left >= payload_size_needed()) { diff --git a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc index 80d8801437..18311c6e8c 100644 --- a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -285,14 +285,50 @@ TEST(RtpPacketizerH264Test, StapARespectsFirstPacketReduction) { 0, 2, nalus[2][0], nalus[2][1])); } +TEST(RtpPacketizerH264Test, StapARespectsSinglePacketReduction) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 1000; + // It is possible for single_packet_reduction_len to be greater than + // first_packet_reduction_len + last_packet_reduction_len. Check that the + // right limit is used when first and last fragment go to one packet. + limits.first_packet_reduction_len = 4; + limits.last_packet_reduction_len = 0; + limits.single_packet_reduction_len = 8; + // 3 fragments of sizes 2 + 2 + 981, plus 7 bytes of headers, is expected to + // be packetized to single packet of size 992. + rtc::Buffer first_nalus[] = {GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/981)}; + rtc::Buffer first_frame = CreateFrame(first_nalus); + + RtpPacketizerH264 first_packetizer(first_frame, limits, + H264PacketizationMode::NonInterleaved); + std::vector packets = FetchAllPackets(&first_packetizer); + + // Expect that everything fits in a single packet. + ASSERT_THAT(packets, SizeIs(1)); + EXPECT_EQ(packets[0].payload_size(), 992u); + + // Increasing the last fragment size by one exceeds + // single_packet_reduction_len and produces two packets. + rtc::Buffer second_nalus[] = {GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/2), + GenerateNalUnit(/*size=*/982)}; + rtc::Buffer second_frame = CreateFrame(second_nalus); + RtpPacketizerH264 second_packetizer(second_frame, limits, + H264PacketizationMode::NonInterleaved); + packets = FetchAllPackets(&second_packetizer); + ASSERT_THAT(packets, SizeIs(2)); +} + TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) { RtpPacketizer::PayloadSizeLimits limits; limits.max_payload_len = 1000; limits.last_packet_reduction_len = 100; + const size_t kFirstFragmentSize = 1000; const size_t kLastFragmentSize = - limits.max_payload_len - limits.last_packet_reduction_len; - rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2), - GenerateNalUnit(/*size=*/2), + limits.max_payload_len - limits.last_packet_reduction_len + 1; + rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/kFirstFragmentSize), GenerateNalUnit(/*size=*/kLastFragmentSize)}; rtc::Buffer frame = CreateFrame(nalus); @@ -300,14 +336,13 @@ TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) { H264PacketizationMode::NonInterleaved); std::vector packets = FetchAllPackets(&packetizer); - ASSERT_THAT(packets, SizeIs(2)); - // Expect 1st packet is aggregate of 1st two fragments. - EXPECT_THAT(packets[0].payload(), - ElementsAre(kStapA, // - 0, 2, nalus[0][0], nalus[0][1], // - 0, 2, nalus[1][0], nalus[1][1])); - // Expect 2nd packet is single nalu. - EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2])); + ASSERT_THAT(packets, SizeIs(3)); + // Expect 1st packet contains first fragment. + EXPECT_THAT(packets[0].payload()[0], kSlice); + // Expect 2nd and 3rd packets to be FU-A since last_packet_reduction_len + // was exceeded by one byte. + EXPECT_THAT(packets[1].payload()[0], kFuA); + EXPECT_THAT(packets[2].payload()[0], kFuA); } TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) { diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 3f9e093ff0..20862e3c45 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -296,7 +296,6 @@ RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() { int32_t ModuleRtpRtcpImpl::SetSendingStatus(const bool sending) { if (rtcp_sender_.Sending() != sending) { - // Sends RTCP BYE when going from true to false rtcp_sender_.SetSendingStatus(GetFeedbackState(), sending); } return 0; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc index 0821f6deb0..8df4c3ecbd 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc @@ -196,10 +196,12 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver, counter_map_[ssrc] = packet_counter; } - void OnSendPacket(uint16_t packet_id, + void OnSendPacket(absl::optional packet_id, Timestamp capture_time, uint32_t ssrc) override { - last_sent_packet_.emplace(packet_id, capture_time, ssrc); + if (packet_id.has_value()) { + last_sent_packet_.emplace(*packet_id, capture_time, ssrc); + } } absl::optional last_sent_packet() const { diff --git a/modules/rtp_rtcp/source/rtp_rtcp_interface.h b/modules/rtp_rtcp/source/rtp_rtcp_interface.h index d366bb77a2..924c764ccd 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_interface.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_interface.h @@ -95,7 +95,6 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface { VideoFecGenerator* fec_generator = nullptr; BitrateStatisticsObserver* send_bitrate_observer = nullptr; - SendSideDelayObserver* send_side_delay_observer = nullptr; RtcEventLog* event_log = nullptr; SendPacketObserver* send_packet_observer = nullptr; RateLimiter* retransmission_rate_limiter = nullptr; @@ -275,7 +274,7 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface { // Returns the FlexFEC SSRC, if there is one. virtual absl::optional FlexfecSsrc() const = 0; - // Sets sending status. Sends kRtcpByeCode when going from true to false. + // Sets sending status. // Returns -1 on failure else 0. virtual int32_t SetSendingStatus(bool sending) = 0; diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.cc b/modules/rtp_rtcp/source/rtp_sender_audio.cc index ca37e10837..b826c30e07 100644 --- a/modules/rtp_rtcp/source/rtp_sender_audio.cc +++ b/modules/rtp_rtcp/source/rtp_sender_audio.cc @@ -30,6 +30,7 @@ #include "modules/rtp_rtcp/source/time_util.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/ntp_time.h" @@ -92,7 +93,7 @@ int32_t RTPSenderAudio::RegisterAudioPayload(absl::string_view payload_name, return 0; } else if (payload_name == "audio") { MutexLock lock(&send_audio_mutex_); - encoder_rtp_timestamp_frequency_ = frequency; + encoder_rtp_timestamp_frequency_ = rtc::dchecked_cast(frequency); return 0; } return 0; @@ -141,35 +142,6 @@ bool RTPSenderAudio::MarkerBit(AudioFrameType frame_type, int8_t payload_type) { return marker_bit; } -bool RTPSenderAudio::SendAudio(AudioFrameType frame_type, - int8_t payload_type, - uint32_t rtp_timestamp, - const uint8_t* payload_data, - size_t payload_size) { - return SendAudio({.type = frame_type, - .payload{payload_data, payload_size}, - .payload_id = payload_type, - .rtp_timestamp = rtp_timestamp}); -} - -bool RTPSenderAudio::SendAudio(AudioFrameType frame_type, - int8_t payload_type, - uint32_t rtp_timestamp, - const uint8_t* payload_data, - size_t payload_size, - int64_t absolute_capture_timestamp_ms) { - RtpAudioFrame frame = { - .type = frame_type, - .payload{payload_data, payload_size}, - .payload_id = payload_type, - .rtp_timestamp = rtp_timestamp, - }; - if (absolute_capture_timestamp_ms > 0) { - frame.capture_time = Timestamp::Millis(absolute_capture_timestamp_ms); - } - return SendAudio(frame); -} - bool RTPSenderAudio::SendAudio(const RtpAudioFrame& frame) { RTC_DCHECK_GE(frame.payload_id, 0); RTC_DCHECK_LE(frame.payload_id, 127); @@ -182,14 +154,23 @@ bool RTPSenderAudio::SendAudio(const RtpAudioFrame& frame) { // Alternatively, a source MAY decide to use a different spacing for event // updates, with a value of 50 ms RECOMMENDED. constexpr int kDtmfIntervalTimeMs = 50; - uint8_t audio_level_dbov = 0; uint32_t dtmf_payload_freq = 0; - absl::optional encoder_rtp_timestamp_frequency; + absl::optional absolute_capture_time; { MutexLock lock(&send_audio_mutex_); - audio_level_dbov = audio_level_dbov_; dtmf_payload_freq = dtmf_payload_freq_; - encoder_rtp_timestamp_frequency = encoder_rtp_timestamp_frequency_; + if (frame.capture_time.has_value()) { + // Send absolute capture time periodically in order to optimize and save + // network traffic. Missing absolute capture times can be interpolated on + // the receiving end if sending intervals are small enough. + absolute_capture_time = absolute_capture_time_sender_.OnSendPacket( + rtp_sender_->SSRC(), frame.rtp_timestamp, + // Replace missing value with 0 (invalid frequency), this will trigger + // absolute capture time sending. + encoder_rtp_timestamp_frequency_.value_or(0), + clock_->ConvertTimestampToNtpTime(*frame.capture_time), + /*estimated_capture_clock_offset=*/0); + } } // Check if we have pending DTMFs to send @@ -278,34 +259,15 @@ bool RTPSenderAudio::SendAudio(const RtpAudioFrame& frame) { packet->SetPayloadType(frame.payload_id); packet->SetTimestamp(frame.rtp_timestamp); packet->set_capture_time(clock_->CurrentTime()); - // RingRTC change to reduce unneeded information on the wire - // Make the audio level less precise (0, 10, 20, 30, ...). - audio_level_dbov -= (audio_level_dbov % 10); - - // Update audio level extension, if included. + // Set audio level extension, if included. packet->SetExtension( frame.type == AudioFrameType::kAudioFrameSpeech, - frame.audio_level_dbov.value_or(audio_level_dbov)); + frame.audio_level_dbov.value_or(127)); - if (frame.capture_time.has_value()) { - // Send absolute capture time periodically in order to optimize and save - // network traffic. Missing absolute capture times can be interpolated on - // the receiving end if sending intervals are small enough. - auto absolute_capture_time = absolute_capture_time_sender_.OnSendPacket( - AbsoluteCaptureTimeSender::GetSource(packet->Ssrc(), packet->Csrcs()), - packet->Timestamp(), - // Replace missing value with 0 (invalid frequency), this will trigger - // absolute capture time sending. - encoder_rtp_timestamp_frequency.value_or(0), - static_cast( - clock_->ConvertTimestampToNtpTime(*frame.capture_time)), - /*estimated_capture_clock_offset=*/0); - if (absolute_capture_time) { - // It also checks that extension was registered during SDP negotiation. If - // not then setter won't do anything. - packet->SetExtension( - *absolute_capture_time); - } + if (absolute_capture_time.has_value()) { + // It also checks that extension was registered during SDP negotiation. If + // not then setter won't do anything. + packet->SetExtension(*absolute_capture_time); } uint8_t* payload = packet->AllocatePayload(frame.payload.size()); @@ -330,16 +292,6 @@ bool RTPSenderAudio::SendAudio(const RtpAudioFrame& frame) { return true; } -// Audio level magnitude and voice activity flag are set for each RTP packet -int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) { - if (level_dbov > 127) { - return -1; - } - MutexLock lock(&send_audio_mutex_); - audio_level_dbov_ = level_dbov; - return 0; -} - // Send a TelephoneEvent tone using RFC 2833 (4733) int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key, uint16_t time_ms, diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.h b/modules/rtp_rtcp/source/rtp_sender_audio.h index ee4e92635f..662f908216 100644 --- a/modules/rtp_rtcp/source/rtp_sender_audio.h +++ b/modules/rtp_rtcp/source/rtp_sender_audio.h @@ -64,26 +64,6 @@ class RTPSenderAudio { }; bool SendAudio(const RtpAudioFrame& frame); - [[deprecated]] bool SendAudio(AudioFrameType frame_type, - int8_t payload_type, - uint32_t rtp_timestamp, - const uint8_t* payload_data, - size_t payload_size); - - // `absolute_capture_timestamp_ms` and `Clock::CurrentTime` - // should be using the same epoch. - [[deprecated]] bool SendAudio(AudioFrameType frame_type, - int8_t payload_type, - uint32_t rtp_timestamp, - const uint8_t* payload_data, - size_t payload_size, - int64_t absolute_capture_timestamp_ms); - - // Store the audio level in dBov for - // header-extension-for-audio-level-indication. - // Valid range is [0,127]. Actual value is negative. - [[deprecated]] int32_t SetAudioLevel(uint8_t level_dbov); - // Send a DTMF tone using RFC 2833 (4733) int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level); @@ -122,15 +102,13 @@ class RTPSenderAudio { int8_t cngfb_payload_type_ RTC_GUARDED_BY(send_audio_mutex_) = -1; int8_t last_payload_type_ RTC_GUARDED_BY(send_audio_mutex_) = -1; - // Audio level indication. - // (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/) - uint8_t audio_level_dbov_ RTC_GUARDED_BY(send_audio_mutex_) = 127; OneTimeEvent first_packet_sent_; - absl::optional encoder_rtp_timestamp_frequency_ + absl::optional encoder_rtp_timestamp_frequency_ RTC_GUARDED_BY(send_audio_mutex_); - AbsoluteCaptureTimeSender absolute_capture_time_sender_; + AbsoluteCaptureTimeSender absolute_capture_time_sender_ + RTC_GUARDED_BY(send_audio_mutex_); }; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc index 7265f409c6..7fcea096ec 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc @@ -23,7 +23,6 @@ namespace webrtc { namespace { constexpr uint32_t kTimestampTicksPerMs = 90; -constexpr TimeDelta kSendSideDelayWindow = TimeDelta::Seconds(1); constexpr TimeDelta kBitrateStatisticsWindow = TimeDelta::Seconds(1); constexpr size_t kRtpSequenceNumberMapMaxEntries = 1 << 13; constexpr TimeDelta kUpdateInterval = kBitrateStatisticsWindow; @@ -96,15 +95,12 @@ RtpSenderEgress::RtpSenderEgress(const RtpRtcpInterface::Configuration& config, need_rtp_packet_infos_(config.need_rtp_packet_infos), fec_generator_(config.fec_generator), transport_feedback_observer_(config.transport_feedback_callback), - send_side_delay_observer_(config.send_side_delay_observer), send_packet_observer_(config.send_packet_observer), rtp_stats_callback_(config.rtp_stats_callback), bitrate_callback_(config.send_bitrate_observer), media_has_been_sent_(false), force_part_of_allocation_(false), timestamp_offset_(0), - max_delay_it_(send_delays_.end()), - sum_delays_(TimeDelta::Zero()), send_rates_(kNumMediaTypes, BitrateTracker(kBitrateStatisticsWindow)), rtp_sequence_number_map_(need_rtp_packet_infos_ ? std::make_unique( @@ -252,7 +248,9 @@ void RtpSenderEgress::CompleteSendPacket(const Packet& compound_packet, // Downstream code actually uses this flag to distinguish between media and // everything else. options.is_retransmit = !is_media; - if (auto packet_id = packet->GetExtension()) { + absl::optional packet_id = + packet->GetExtension(); + if (packet_id.has_value()) { options.packet_id = *packet_id; options.included_in_feedback = true; options.included_in_allocation = true; @@ -261,11 +259,11 @@ void RtpSenderEgress::CompleteSendPacket(const Packet& compound_packet, options.additional_data = packet->additional_data(); - const uint32_t packet_ssrc = packet->Ssrc(); if (packet->packet_type() != RtpPacketMediaType::kPadding && - packet->packet_type() != RtpPacketMediaType::kRetransmission) { - UpdateDelayStatistics(packet->capture_time(), now, packet_ssrc); - UpdateOnSendPacket(options.packet_id, packet->capture_time(), packet_ssrc); + packet->packet_type() != RtpPacketMediaType::kRetransmission && + send_packet_observer_ != nullptr && packet->capture_time().IsFinite()) { + send_packet_observer_->OnSendPacket(packet_id, packet->capture_time(), + packet->Ssrc()); } options.batchable = enable_send_packet_batching_ && !is_audio_; options.last_packet_in_batch = last_in_batch; @@ -292,8 +290,8 @@ void RtpSenderEgress::CompleteSendPacket(const Packet& compound_packet, RTC_DCHECK(packet->packet_type().has_value()); RtpPacketMediaType packet_type = *packet->packet_type(); RtpPacketCounter counter(*packet); - size_t size = packet->size(); - UpdateRtpStats(now, packet_ssrc, packet_type, std::move(counter), size); + UpdateRtpStats(now, packet->Ssrc(), packet_type, std::move(counter), + packet->size()); } } @@ -439,83 +437,6 @@ void RtpSenderEgress::AddPacketToTransportFeedback( } } -void RtpSenderEgress::UpdateDelayStatistics(Timestamp capture_time, - Timestamp now, - uint32_t ssrc) { - RTC_DCHECK_RUN_ON(worker_queue_); - if (!send_side_delay_observer_ || capture_time.IsInfinite()) - return; - - TimeDelta avg_delay = TimeDelta::Zero(); - TimeDelta max_delay = TimeDelta::Zero(); - { - // Compute the max and average of the recent capture-to-send delays. - // The time complexity of the current approach depends on the distribution - // of the delay values. This could be done more efficiently. - - // Remove elements older than kSendSideDelayWindowMs. - auto lower_bound = send_delays_.lower_bound(now - kSendSideDelayWindow); - for (auto it = send_delays_.begin(); it != lower_bound; ++it) { - if (max_delay_it_ == it) { - max_delay_it_ = send_delays_.end(); - } - sum_delays_ -= it->second; - } - send_delays_.erase(send_delays_.begin(), lower_bound); - if (max_delay_it_ == send_delays_.end()) { - // Removed the previous max. Need to recompute. - RecomputeMaxSendDelay(); - } - - // Add the new element. - TimeDelta new_send_delay = now - capture_time; - auto [it, inserted] = send_delays_.emplace(now, new_send_delay); - if (!inserted) { - // TODO(terelius): If we have multiple delay measurements during the same - // millisecond then we keep the most recent one. It is not clear that this - // is the right decision, but it preserves an earlier behavior. - TimeDelta previous_send_delay = it->second; - sum_delays_ -= previous_send_delay; - it->second = new_send_delay; - if (max_delay_it_ == it && new_send_delay < previous_send_delay) { - RecomputeMaxSendDelay(); - } - } - if (max_delay_it_ == send_delays_.end() || - it->second >= max_delay_it_->second) { - max_delay_it_ = it; - } - sum_delays_ += new_send_delay; - - size_t num_delays = send_delays_.size(); - RTC_DCHECK(max_delay_it_ != send_delays_.end()); - max_delay = max_delay_it_->second; - avg_delay = sum_delays_ / num_delays; - } - send_side_delay_observer_->SendSideDelayUpdated(avg_delay.ms(), - max_delay.ms(), ssrc); -} - -void RtpSenderEgress::RecomputeMaxSendDelay() { - RTC_DCHECK_RUN_ON(worker_queue_); - max_delay_it_ = send_delays_.begin(); - for (auto it = send_delays_.begin(); it != send_delays_.end(); ++it) { - if (it->second >= max_delay_it_->second) { - max_delay_it_ = it; - } - } -} - -void RtpSenderEgress::UpdateOnSendPacket(int packet_id, - Timestamp capture_time, - uint32_t ssrc) { - if (!send_packet_observer_ || capture_time.IsInfinite() || packet_id == -1) { - return; - } - - send_packet_observer_->OnSendPacket(packet_id, capture_time, ssrc); -} - bool RtpSenderEgress::SendPacketToNetwork(const RtpPacketToSend& packet, const PacketOptions& options, const PacedPacketInfo& pacing_info) { diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.h b/modules/rtp_rtcp/source/rtp_sender_egress.h index 3e5b2b21c3..42f3c96ff0 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress.h +++ b/modules/rtp_rtcp/source/rtp_sender_egress.h @@ -113,11 +113,7 @@ class RtpSenderEgress { void AddPacketToTransportFeedback(uint16_t packet_id, const RtpPacketToSend& packet, const PacedPacketInfo& pacing_info); - void UpdateDelayStatistics(Timestamp capture_time, - Timestamp now, - uint32_t ssrc); - void RecomputeMaxSendDelay(); - void UpdateOnSendPacket(int packet_id, Timestamp capture_time, uint32_t ssrc); + // Sends packet on to `transport_`, leaving the RTP module. bool SendPacketToNetwork(const RtpPacketToSend& packet, const PacketOptions& options, @@ -151,7 +147,6 @@ class RtpSenderEgress { absl::optional last_sent_rtx_seq_ RTC_GUARDED_BY(worker_queue_); TransportFeedbackObserver* const transport_feedback_observer_; - SendSideDelayObserver* const send_side_delay_observer_; SendPacketObserver* const send_packet_observer_; StreamDataCountersCallback* const rtp_stats_callback_; BitrateStatisticsObserver* const bitrate_callback_; @@ -160,13 +155,6 @@ class RtpSenderEgress { bool force_part_of_allocation_ RTC_GUARDED_BY(worker_queue_); uint32_t timestamp_offset_ RTC_GUARDED_BY(worker_queue_); - // Maps capture time to send-side delay. Send-side delay is the difference - // between transmission time and capture time. - std::map send_delays_ RTC_GUARDED_BY(worker_queue_); - std::map::const_iterator max_delay_it_ - RTC_GUARDED_BY(worker_queue_); - // The sum of delays over a kSendSideDelayWindowMs sliding window. - TimeDelta sum_delays_ RTC_GUARDED_BY(worker_queue_); StreamDataCounters rtp_stats_ RTC_GUARDED_BY(worker_queue_); StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(worker_queue_); // One element per value in RtpPacketMediaType, with index matching value. diff --git a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc index 6c798e4595..b278ea2f06 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc @@ -36,6 +36,7 @@ namespace { using ::testing::_; using ::testing::AllOf; +using ::testing::Eq; using ::testing::Field; using ::testing::InSequence; using ::testing::NiceMock; @@ -57,7 +58,10 @@ enum : int { class MockSendPacketObserver : public SendPacketObserver { public: - MOCK_METHOD(void, OnSendPacket, (uint16_t, Timestamp, uint32_t), (override)); + MOCK_METHOD(void, + OnSendPacket, + (absl::optional, Timestamp, uint32_t), + (override)); }; class MockTransportFeedbackObserver : public TransportFeedbackObserver { @@ -73,11 +77,6 @@ class MockStreamDataCountersCallback : public StreamDataCountersCallback { (override)); }; -class MockSendSideDelayObserver : public SendSideDelayObserver { - public: - MOCK_METHOD(void, SendSideDelayUpdated, (int, int, uint32_t), (override)); -}; - struct TransmittedPacket { TransmittedPacket(rtc::ArrayView data, const PacketOptions& packet_options, @@ -325,48 +324,6 @@ TEST_F(RtpSenderEgressTest, EXPECT_EQ(offset, 0); } -TEST_F(RtpSenderEgressTest, OnSendSideDelayUpdated) { - StrictMock send_side_delay_observer; - RtpRtcpInterface::Configuration config = DefaultConfig(); - config.send_side_delay_observer = &send_side_delay_observer; - auto sender = std::make_unique(config, &packet_history_); - - // Send packet with 10 ms send-side delay. The average, max and total should - // be 10 ms. - EXPECT_CALL(send_side_delay_observer, SendSideDelayUpdated(10, 10, kSsrc)); - int64_t capture_time_ms = clock_->TimeInMilliseconds(); - time_controller_.AdvanceTime(TimeDelta::Millis(10)); - sender->SendPacket(BuildRtpPacket(/*marker=*/true, capture_time_ms), - PacedPacketInfo()); - - // Send another packet with 20 ms delay. The average, max and total should be - // 15, 20 and 30 ms respectively. - EXPECT_CALL(send_side_delay_observer, SendSideDelayUpdated(15, 20, kSsrc)); - capture_time_ms = clock_->TimeInMilliseconds(); - time_controller_.AdvanceTime(TimeDelta::Millis(20)); - sender->SendPacket(BuildRtpPacket(/*marker=*/true, capture_time_ms), - PacedPacketInfo()); - - // Send another packet at the same time, which replaces the last packet. - // Since this packet has 0 ms delay, the average is now 5 ms and max is 10 ms. - // The total counter stays the same though. - // TODO(terelius): Is is not clear that this is the right behavior. - EXPECT_CALL(send_side_delay_observer, SendSideDelayUpdated(5, 10, kSsrc)); - capture_time_ms = clock_->TimeInMilliseconds(); - sender->SendPacket(BuildRtpPacket(/*marker=*/true, capture_time_ms), - PacedPacketInfo()); - - // Send a packet 1 second later. The earlier packets should have timed - // out, so both max and average should be the delay of this packet. The total - // keeps increasing. - time_controller_.AdvanceTime(TimeDelta::Seconds(1)); - EXPECT_CALL(send_side_delay_observer, SendSideDelayUpdated(1, 1, kSsrc)); - capture_time_ms = clock_->TimeInMilliseconds(); - time_controller_.AdvanceTime(TimeDelta::Millis(1)); - sender->SendPacket(BuildRtpPacket(/*marker=*/true, capture_time_ms), - PacedPacketInfo()); -} - TEST_F(RtpSenderEgressTest, WritesPacerExitToTimingExtension) { std::unique_ptr sender = CreateRtpSenderEgress(); header_extensions_.RegisterByUri(kVideoTimingExtensionId, @@ -421,12 +378,20 @@ TEST_F(RtpSenderEgressTest, OnSendPacketUpdated) { const uint16_t kTransportSequenceNumber = 1; EXPECT_CALL( send_packet_observer_, - OnSendPacket(kTransportSequenceNumber, clock_->CurrentTime(), kSsrc)); + OnSendPacket(Eq(kTransportSequenceNumber), clock_->CurrentTime(), kSsrc)); std::unique_ptr packet = BuildRtpPacket(); packet->SetExtension(kTransportSequenceNumber); sender->SendPacket(std::move(packet), PacedPacketInfo()); } +TEST_F(RtpSenderEgressTest, OnSendPacketUpdatedWithoutTransportSequenceNumber) { + std::unique_ptr sender = CreateRtpSenderEgress(); + + EXPECT_CALL(send_packet_observer_, + OnSendPacket(Eq(absl::nullopt), clock_->CurrentTime(), kSsrc)); + sender->SendPacket(BuildRtpPacket(), PacedPacketInfo()); +} + TEST_F(RtpSenderEgressTest, OnSendPacketNotUpdatedForRetransmits) { std::unique_ptr sender = CreateRtpSenderEgress(); header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId, @@ -840,7 +805,6 @@ TEST_F(RtpSenderEgressTest, SendPacketSetsPacketOptions) { TEST_F(RtpSenderEgressTest, SendPacketUpdatesStats) { const size_t kPayloadSize = 1000; - StrictMock send_side_delay_observer; const rtc::ArrayView kNoRtpHeaderExtensionSizes; FlexfecSender flexfec(kFlexfectPayloadType, kFlexFecSsrc, kSsrc, /*mid=*/"", @@ -848,7 +812,6 @@ TEST_F(RtpSenderEgressTest, SendPacketUpdatesStats) { /*rtp_state=*/nullptr, time_controller_.GetClock()); RtpRtcpInterface::Configuration config = DefaultConfig(); config.fec_generator = &flexfec; - config.send_side_delay_observer = &send_side_delay_observer; auto sender = std::make_unique(config, &packet_history_); header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId, @@ -877,21 +840,16 @@ TEST_F(RtpSenderEgressTest, SendPacketUpdatesStats) { const int64_t kDiffMs = 25; time_controller_.AdvanceTime(TimeDelta::Millis(kDiffMs)); - EXPECT_CALL(send_side_delay_observer, - SendSideDelayUpdated(kDiffMs, kDiffMs, kSsrc)); - EXPECT_CALL(send_side_delay_observer, - SendSideDelayUpdated(kDiffMs, kDiffMs, kFlexFecSsrc)); - - EXPECT_CALL(send_packet_observer_, OnSendPacket(1, capture_time, kSsrc)); + EXPECT_CALL(send_packet_observer_, OnSendPacket(Eq(1), capture_time, kSsrc)); sender->SendPacket(std::move(video_packet), PacedPacketInfo()); // Send packet observer not called for padding/retransmissions. - EXPECT_CALL(send_packet_observer_, OnSendPacket(2, _, _)).Times(0); + EXPECT_CALL(send_packet_observer_, OnSendPacket(Eq(2), _, _)).Times(0); sender->SendPacket(std::move(rtx_packet), PacedPacketInfo()); EXPECT_CALL(send_packet_observer_, - OnSendPacket(3, capture_time, kFlexFecSsrc)); + OnSendPacket(Eq(3), capture_time, kFlexFecSsrc)); sender->SendPacket(std::move(fec_packet), PacedPacketInfo()); time_controller_.AdvanceTime(TimeDelta::Zero()); diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc index e48730ed2e..58af54900c 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -92,6 +92,10 @@ bool IsBaseLayer(const RTPVideoHeader& video_header) { // TODO(kron): Implement logic for H264 once WebRTC supports temporal // layers for H264. break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement logic for H265 once WebRTC + // supports temporal layers for H265. + break; default: break; } @@ -114,7 +118,7 @@ absl::optional LoadVideoPlayoutDelayOverride( // Some packets can be skipped and the stream can still be decoded. Those // packets are less likely to be retransmitted if they are lost. -bool PacketWillLikelyBeRequestedForRestransmitionIfLost( +bool PacketWillLikelyBeRequestedForRestransmissionIfLost( const RTPVideoHeader& video_header) { return IsBaseLayer(video_header) && !(video_header.generic.has_value() @@ -438,7 +442,7 @@ void RTPSenderVideo::AddRtpHeaderExtensions(const RTPVideoHeader& video_header, first_packet && send_allocation_ != SendVideoLayersAllocation::kDontSend && (video_header.frame_type == VideoFrameType::kVideoFrameKey || - PacketWillLikelyBeRequestedForRestransmitionIfLost(video_header))) { + PacketWillLikelyBeRequestedForRestransmissionIfLost(video_header))) { VideoLayersAllocation allocation = allocation_.value(); allocation.resolution_and_frame_rate_is_valid = send_allocation_ == SendVideoLayersAllocation::kSendWithResolution; @@ -544,10 +548,10 @@ bool RTPSenderVideo::SendVideo(int payload_type, if (video_header.absolute_capture_time.has_value()) { video_header.absolute_capture_time = absolute_capture_time_sender_.OnSendPacket( - AbsoluteCaptureTimeSender::GetSource(single_packet->Ssrc(), - single_packet->Csrcs()), + AbsoluteCaptureTimeSender::GetSource(single_packet->Ssrc(), csrcs), single_packet->Timestamp(), kVideoPayloadTypeFrequency, - video_header.absolute_capture_time->absolute_capture_timestamp, + NtpTime( + video_header.absolute_capture_time->absolute_capture_timestamp), video_header.absolute_capture_time->estimated_capture_clock_offset); } @@ -732,7 +736,7 @@ bool RTPSenderVideo::SendVideo(int payload_type, } if (video_header.frame_type == VideoFrameType::kVideoFrameKey || - PacketWillLikelyBeRequestedForRestransmitionIfLost(video_header)) { + PacketWillLikelyBeRequestedForRestransmissionIfLost(video_header)) { // This frame will likely be delivered, no need to populate playout // delay extensions until it changes again. playout_delay_pending_ = false; diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h index 5459e14888..9400b436d3 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.h +++ b/modules/rtp_rtcp/source/rtp_sender_video.h @@ -244,7 +244,8 @@ class RTPSenderVideo : public RTPVideoFrameSenderInterface { // Set to true if the generic descriptor should be authenticated. const bool generic_descriptor_auth_experiment_; - AbsoluteCaptureTimeSender absolute_capture_time_sender_; + AbsoluteCaptureTimeSender absolute_capture_time_sender_ + RTC_GUARDED_BY(send_checker_); // Tracks updates to the active decode targets and decides when active decode // targets bitmask should be attached to the dependency descriptor. ActiveDecodeTargetsHelper active_decode_targets_tracker_; diff --git a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc index 2281a2ae27..d255ef4aa9 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc @@ -10,6 +10,7 @@ #include "modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.h" +#include #include #include @@ -97,6 +98,13 @@ class TransformableVideoSenderFrame : public TransformableVideoFrameInterface { } Direction GetDirection() const override { return Direction::kSender; } + std::string GetMimeType() const override { + if (!codec_type_.has_value()) { + return "video/x-unknown"; + } + std::string mime_type = "video/"; + return mime_type + CodecTypeToPayloadString(*codec_type_); + } private: rtc::scoped_refptr encoded_data_; diff --git a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc index 54cfdbadd7..a376be77b4 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate_unittest.cc @@ -74,9 +74,15 @@ class RtpSenderVideoFrameTransformerDelegateTest : public ::testing::Test { frame_to_transform) { frame = std::move(frame_to_transform); }); + RTPVideoHeader rtp_header; + + VideoFrameMetadata metadata; + metadata.SetCodec(VideoCodecType::kVideoCodecVP8); + metadata.SetRTPVideoHeaderCodecSpecifics(RTPVideoHeaderVP8()); + delegate->TransformFrame( /*payload_type=*/1, VideoCodecType::kVideoCodecVP8, /*rtp_timestamp=*/2, - encoded_image, RTPVideoHeader(), + encoded_image, RTPVideoHeader::FromMetadata(metadata), /*expected_retransmission_time=*/TimeDelta::PlusInfinity()); return frame; } @@ -135,6 +141,7 @@ TEST_F(RtpSenderVideoFrameTransformerDelegateTest, std::unique_ptr frame = GetTransformableFrame(delegate); ASSERT_TRUE(frame); + EXPECT_STRCASEEQ("video/VP8", frame->GetMimeType().c_str()); rtc::Event event; EXPECT_CALL(test_sender_, SendVideo).WillOnce(WithoutArgs([&] { @@ -162,6 +169,7 @@ TEST_F(RtpSenderVideoFrameTransformerDelegateTest, CloneSenderVideoFrame) { EXPECT_EQ(clone->IsKeyFrame(), video_frame.IsKeyFrame()); EXPECT_EQ(clone->GetPayloadType(), video_frame.GetPayloadType()); + EXPECT_EQ(clone->GetMimeType(), video_frame.GetMimeType()); EXPECT_EQ(clone->GetSsrc(), video_frame.GetSsrc()); EXPECT_EQ(clone->GetTimestamp(), video_frame.GetTimestamp()); EXPECT_EQ(clone->Metadata(), video_frame.Metadata()); @@ -182,6 +190,7 @@ TEST_F(RtpSenderVideoFrameTransformerDelegateTest, CloneKeyFrame) { EXPECT_EQ(clone->IsKeyFrame(), video_frame.IsKeyFrame()); EXPECT_EQ(clone->GetPayloadType(), video_frame.GetPayloadType()); + EXPECT_EQ(clone->GetMimeType(), video_frame.GetMimeType()); EXPECT_EQ(clone->GetSsrc(), video_frame.GetSsrc()); EXPECT_EQ(clone->GetTimestamp(), video_frame.GetTimestamp()); EXPECT_EQ(clone->Metadata(), video_frame.Metadata()); diff --git a/modules/rtp_rtcp/source/rtp_video_header.cc b/modules/rtp_rtcp/source/rtp_video_header.cc index b07a7beec4..c4ab6097be 100644 --- a/modules/rtp_rtcp/source/rtp_video_header.cc +++ b/modules/rtp_rtcp/source/rtp_video_header.cc @@ -59,6 +59,9 @@ VideoFrameMetadata RTPVideoHeader::GetAsMetadata() const { metadata.SetRTPVideoHeaderCodecSpecifics( absl::get(video_type_header)); break; + case VideoCodecType::kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: // Codec-specifics are not supported for this codec. break; diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc index 4913445860..ddbd22e34a 100644 --- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc +++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc @@ -10,6 +10,7 @@ #include "modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.h" +#include #include #include @@ -47,9 +48,9 @@ class TransformableVideoReceiverFrame uint8_t GetPayloadType() const override { return frame_->PayloadType(); } uint32_t GetSsrc() const override { return Metadata().GetSsrc(); } - uint32_t GetTimestamp() const override { return frame_->Timestamp(); } + uint32_t GetTimestamp() const override { return frame_->RtpTimestamp(); } void SetRTPTimestamp(uint32_t timestamp) override { - frame_->SetTimestamp(timestamp); + frame_->SetRtpTimestamp(timestamp); } bool IsKeyFrame() const override { @@ -75,6 +76,10 @@ class TransformableVideoReceiverFrame } Direction GetDirection() const override { return Direction::kReceiver; } + std::string GetMimeType() const override { + std::string mime_type = "video/"; + return mime_type + CodecTypeToPayloadString(frame_->codec_type()); + } const RtpVideoFrameReceiver* Receiver() { return receiver_; } diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc index bbc1b62b5e..f403c91a74 100644 --- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc @@ -138,6 +138,7 @@ TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest, ON_CALL(*mock_frame_transformer, Transform) .WillByDefault( [&callback](std::unique_ptr frame) { + EXPECT_STRCASEEQ("video/Generic", frame->GetMimeType().c_str()); callback->OnTransformedFrame(std::move(frame)); }); delegate->TransformFrame(CreateRtpFrameObject(RTPVideoHeader(), csrcs)); diff --git a/modules/video_capture/linux/pipewire_session.cc b/modules/video_capture/linux/pipewire_session.cc index 3f52b3dd61..4d1b200aca 100644 --- a/modules/video_capture/linux/pipewire_session.cc +++ b/modules/video_capture/linux/pipewire_session.cc @@ -360,6 +360,10 @@ void PipeWireSession::OnRegistryGlobal(void* data, if (!spa_dict_lookup(props, PW_KEY_NODE_DESCRIPTION)) return; + auto node_role = spa_dict_lookup(props, PW_KEY_MEDIA_ROLE); + if (!node_role || strcmp(node_role, "Camera")) + return; + that->nodes_.emplace_back(that, id, props); that->PipeWireSync(); } diff --git a/modules/video_capture/linux/video_capture_pipewire.cc b/modules/video_capture/linux/video_capture_pipewire.cc index 46cfe9bc15..7b79f15a6c 100644 --- a/modules/video_capture/linux/video_capture_pipewire.cc +++ b/modules/video_capture/linux/video_capture_pipewire.cc @@ -301,6 +301,10 @@ void VideoCaptureModulePipeWire::OnFormatChanged(const struct spa_pod* format) { &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))))); + params.push_back(reinterpret_cast(spa_pod_builder_add_object( + &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type, + SPA_POD_Id(SPA_META_VideoTransform), SPA_PARAM_META_size, + SPA_POD_Int(sizeof(struct spa_meta_videotransform))))); pw_stream_update_params(stream_, params.data(), params.size()); } @@ -341,6 +345,19 @@ void VideoCaptureModulePipeWire::OnStreamProcess(void* data) { that->ProcessBuffers(); } +static VideoRotation VideorotationFromPipeWireTransform(uint32_t transform) { + switch (transform) { + case SPA_META_TRANSFORMATION_90: + return kVideoRotation_90; + case SPA_META_TRANSFORMATION_180: + return kVideoRotation_180; + case SPA_META_TRANSFORMATION_270: + return kVideoRotation_270; + default: + return kVideoRotation_0; + } +} + void VideoCaptureModulePipeWire::ProcessBuffers() { RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); @@ -349,6 +366,17 @@ void VideoCaptureModulePipeWire::ProcessBuffers() { h = static_cast( spa_buffer_find_meta_data(buffer->buffer, SPA_META_Header, sizeof(*h))); + struct spa_meta_videotransform* videotransform; + videotransform = + static_cast(spa_buffer_find_meta_data( + buffer->buffer, SPA_META_VideoTransform, sizeof(*videotransform))); + if (videotransform) { + VideoRotation rotation = + VideorotationFromPipeWireTransform(videotransform->transform); + SetCaptureRotation(rotation); + SetApplyRotation(rotation != kVideoRotation_0); + } + if (h->flags & SPA_META_HEADER_FLAG_CORRUPTED) { RTC_LOG(LS_INFO) << "Dropping corruped frame."; } else { diff --git a/modules/video_capture/video_capture_impl.cc b/modules/video_capture/video_capture_impl.cc index a1461fb687..428253bf23 100644 --- a/modules/video_capture/video_capture_impl.cc +++ b/modules/video_capture/video_capture_impl.cc @@ -214,7 +214,7 @@ int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, buffer.get()->StrideV(), 0, 0, // No Cropping width, height, target_width, target_height, rotation_mode, ConvertVideoType(frameInfo.videoType)); - if (conversionResult < 0) { + if (conversionResult != 0) { RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type " << static_cast(frameInfo.videoType) << "to I420."; return -1; diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 738d3d4edf..cca9d8883a 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -409,6 +409,7 @@ rtc_library("video_coding_utility") { ":video_codec_interface", "../../api:array_view", "../../api:field_trials_view", + "../../api:field_trials_view", "../../api:scoped_refptr", "../../api:sequence_checker", "../../api/units:time_delta", @@ -583,6 +584,8 @@ rtc_library("webrtc_vp8") { ":webrtc_vp8_temporal_layers", "../../api:fec_controller_api", "../../api:scoped_refptr", + "../../api/units:time_delta", + "../../api/units:timestamp", "../../api/video:encoded_image", "../../api/video:video_frame", "../../api/video:video_rtp_headers", @@ -1053,8 +1056,8 @@ if (rtc_include_tests) { "../../api/video_codecs:video_codecs_api", "../../media:rtc_internal_video_codecs", "../../rtc_base:logging", - "../../system_wrappers:field_trial", "../../test:fileutils", + "../../test:test_flags", "../../test:test_main", "../../test:test_support", "../../test:video_test_support", @@ -1074,7 +1077,10 @@ if (rtc_include_tests) { shard_timeout = 900 } - absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/flags:flag", + "//third_party/abseil-cpp/absl/functional:any_invocable", + ] data = [ "../../resources/FourPeople_1280x720_30.yuv" ] } @@ -1258,6 +1264,7 @@ if (rtc_include_tests) { "../../api:array_view", "../../api:create_simulcast_test_fixture_api", "../../api:fec_controller_api", + "../../api:field_trials_view", "../../api:mock_fec_controller_override", "../../api:mock_video_decoder", "../../api:mock_video_encoder", diff --git a/modules/video_coding/codecs/av1/av1_svc_config.cc b/modules/video_coding/codecs/av1/av1_svc_config.cc index 43dcf96ab7..09b840cb76 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config.cc @@ -23,6 +23,22 @@ namespace webrtc { namespace { +const int kMinAv1SpatialLayerLongSideLength = 240; +const int kMinAv1SpatialLayerShortSideLength = 135; + +int GetLimitedNumSpatialLayers(int width, int height) { + const bool is_landscape = width >= height; + const int min_width = is_landscape ? kMinAv1SpatialLayerLongSideLength + : kMinAv1SpatialLayerShortSideLength; + const int min_height = is_landscape ? kMinAv1SpatialLayerShortSideLength + : kMinAv1SpatialLayerLongSideLength; + const int num_layers_fit_horz = static_cast( + std::floor(1 + std::max(0.0f, std::log2(1.0f * width / min_width)))); + const int num_layers_fit_vert = static_cast( + std::floor(1 + std::max(0.0f, std::log2(1.0f * height / min_height)))); + return std::min(num_layers_fit_horz, num_layers_fit_vert); +} + absl::optional BuildScalabilityMode(int num_temporal_layers, int num_spatial_layers) { char name[20]; @@ -69,6 +85,19 @@ bool SetAv1SvcConfig(VideoCodec& video_codec, } } + bool requested_single_spatial_layer = + ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1; + + if (ScalabilityMode reduced = LimitNumSpatialLayers( + *scalability_mode, + GetLimitedNumSpatialLayers(video_codec.width, video_codec.height)); + *scalability_mode != reduced) { + RTC_LOG(LS_WARNING) << "Reduced number of spatial layers from " + << ScalabilityModeToString(*scalability_mode) << " to " + << ScalabilityModeToString(reduced); + scalability_mode = reduced; + } + std::unique_ptr structure = CreateScalabilityStructure(*scalability_mode); if (structure == nullptr) { @@ -92,7 +121,7 @@ bool SetAv1SvcConfig(VideoCodec& video_codec, spatial_layer.active = true; } - if (info.num_spatial_layers == 1) { + if (requested_single_spatial_layer) { SpatialLayer& spatial_layer = video_codec.spatialLayers[0]; spatial_layer.minBitrate = video_codec.minBitrate; spatial_layer.maxBitrate = video_codec.maxBitrate; @@ -103,10 +132,8 @@ bool SetAv1SvcConfig(VideoCodec& video_codec, for (int sl_idx = 0; sl_idx < info.num_spatial_layers; ++sl_idx) { SpatialLayer& spatial_layer = video_codec.spatialLayers[sl_idx]; - // minBitrate and maxBitrate formulas are copied from vp9 settings and - // are not yet tuned for av1. const int num_pixels = spatial_layer.width * spatial_layer.height; - int min_bitrate_kbps = (600.0 * std::sqrt(num_pixels) - 95'000.0) / 1000.0; + int min_bitrate_kbps = (480.0 * std::sqrt(num_pixels) - 95'000.0) / 1000.0; spatial_layer.minBitrate = std::max(min_bitrate_kbps, 20); spatial_layer.maxBitrate = 50 + static_cast(1.6 * num_pixels / 1000.0); spatial_layer.targetBitrate = diff --git a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc index 9f1da9865c..cc2eba6dfb 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc @@ -18,9 +18,16 @@ namespace webrtc { namespace { constexpr int kDontCare = 0; -TEST(Av1SvcConfigTest, TreatsEmptyAsL1T1) { +VideoCodec GetDefaultVideoCodec() { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; + video_codec.width = 1280; + video_codec.height = 720; + return video_codec; +} + +TEST(Av1SvcConfigTest, TreatsEmptyAsL1T1) { + VideoCodec video_codec = GetDefaultVideoCodec(); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/kDontCare, /*num_spatial_layers=*/kDontCare)); @@ -31,8 +38,7 @@ TEST(Av1SvcConfigTest, TreatsEmptyAsL1T1) { } TEST(Av1SvcConfigTest, ScalabilityModeFromNumberOfTemporalLayers) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; + VideoCodec video_codec = GetDefaultVideoCodec(); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/3, /*num_spatial_layers=*/1)); @@ -40,8 +46,7 @@ TEST(Av1SvcConfigTest, ScalabilityModeFromNumberOfTemporalLayers) { } TEST(Av1SvcConfigTest, ScalabilityModeFromNumberOfSpatialLayers) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; + VideoCodec video_codec = GetDefaultVideoCodec(); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/3, /*num_spatial_layers=*/2)); @@ -52,8 +57,7 @@ TEST(Av1SvcConfigTest, ScalabilityModeFromNumberOfSpatialLayers) { } TEST(Av1SvcConfigTest, SetsActiveSpatialLayersFromScalabilityMode) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; + VideoCodec video_codec = GetDefaultVideoCodec(); video_codec.SetScalabilityMode(ScalabilityMode::kL2T1); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/kDontCare, @@ -98,9 +102,7 @@ TEST(Av1SvcConfigTest, ConfiguresSmallResolutionRatioFromScalabilityMode) { } TEST(Av1SvcConfigTest, CopiesFramrate) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; - // h mode uses 1.5:1 ratio + VideoCodec video_codec = GetDefaultVideoCodec(); video_codec.SetScalabilityMode(ScalabilityMode::kL2T1); video_codec.maxFramerate = 27; @@ -112,8 +114,7 @@ TEST(Av1SvcConfigTest, CopiesFramrate) { } TEST(Av1SvcConfigTest, SetsNumberOfTemporalLayers) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; + VideoCodec video_codec = GetDefaultVideoCodec(); video_codec.SetScalabilityMode(ScalabilityMode::kL1T3); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/kDontCare, @@ -143,28 +144,30 @@ TEST(Av1SvcConfigTest, CopiesMinMaxBitrateForSingleSpatialLayer) { TEST(Av1SvcConfigTest, SetsBitratesForMultipleSpatialLayers) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; + video_codec.width = 640; + video_codec.height = 360; + video_codec.SetScalabilityMode(ScalabilityMode::kL2T2); + + EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/kDontCare, + /*num_spatial_layers=*/kDontCare)); + + EXPECT_EQ(video_codec.spatialLayers[0].minBitrate, 20u); + EXPECT_EQ(video_codec.spatialLayers[0].maxBitrate, 142u); + + EXPECT_EQ(video_codec.spatialLayers[1].minBitrate, 135u); + EXPECT_EQ(video_codec.spatialLayers[1].maxBitrate, 418u); +} + +TEST(Av1SvcConfigTest, ReduceSpatialLayersOnInsufficentInputResolution) { + VideoCodec video_codec = GetDefaultVideoCodec(); + video_codec.width = 640; + video_codec.height = 360; video_codec.SetScalabilityMode(ScalabilityMode::kL3T3); EXPECT_TRUE(SetAv1SvcConfig(video_codec, /*num_temporal_layers=*/kDontCare, /*num_spatial_layers=*/kDontCare)); - EXPECT_GT(video_codec.spatialLayers[0].minBitrate, 0u); - EXPECT_LE(video_codec.spatialLayers[0].minBitrate, - video_codec.spatialLayers[0].targetBitrate); - EXPECT_LE(video_codec.spatialLayers[0].targetBitrate, - video_codec.spatialLayers[0].maxBitrate); - - EXPECT_GT(video_codec.spatialLayers[1].minBitrate, 0u); - EXPECT_LE(video_codec.spatialLayers[1].minBitrate, - video_codec.spatialLayers[1].targetBitrate); - EXPECT_LE(video_codec.spatialLayers[1].targetBitrate, - video_codec.spatialLayers[1].maxBitrate); - - EXPECT_GT(video_codec.spatialLayers[2].minBitrate, 0u); - EXPECT_LE(video_codec.spatialLayers[2].minBitrate, - video_codec.spatialLayers[2].targetBitrate); - EXPECT_LE(video_codec.spatialLayers[2].targetBitrate, - video_codec.spatialLayers[2].maxBitrate); + EXPECT_EQ(*video_codec.GetScalabilityMode(), ScalabilityMode::kL2T3); } } // namespace diff --git a/modules/video_coding/codecs/av1/dav1d_decoder.cc b/modules/video_coding/codecs/av1/dav1d_decoder.cc index 3100c0d41b..6a787ff935 100644 --- a/modules/video_coding/codecs/av1/dav1d_decoder.cc +++ b/modules/video_coding/codecs/av1/dav1d_decoder.cc @@ -181,12 +181,13 @@ int32_t Dav1dDecoder::Decode(const EncodedImage& encoded_image, return WEBRTC_VIDEO_CODEC_ERROR; } - VideoFrame decoded_frame = VideoFrame::Builder() - .set_video_frame_buffer(wrapped_buffer) - .set_timestamp_rtp(encoded_image.Timestamp()) - .set_ntp_time_ms(encoded_image.ntp_time_ms_) - .set_color_space(encoded_image.ColorSpace()) - .build(); + VideoFrame decoded_frame = + VideoFrame::Builder() + .set_video_frame_buffer(wrapped_buffer) + .set_timestamp_rtp(encoded_image.RtpTimestamp()) + .set_ntp_time_ms(encoded_image.ntp_time_ms_) + .set_color_space(encoded_image.ColorSpace()) + .build(); decode_complete_callback_->Decoded(decoded_frame, absl::nullopt, absl::nullopt); diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc index 28a8e5f846..4ff22bfe34 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc @@ -41,6 +41,11 @@ #include "third_party/libaom/source/libaom/aom/aom_encoder.h" #include "third_party/libaom/source/libaom/aom/aomcx.h" +#if (defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)) && \ + (defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)) +#define MOBILE_ARM +#endif + #define SET_ENCODER_PARAM_OR_RETURN_ERROR(param_id, param_value) \ do { \ if (!SetEncoderControlParameters(param_id, param_value)) { \ @@ -413,8 +418,7 @@ int LibaomAv1Encoder::NumberOfThreads(int width, return 2; } else { // Use 2 threads for low res on ARM. -#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \ - defined(WEBRTC_ANDROID) +#ifdef MOBILE_ARM if (width * height >= 320 * 180 && number_of_cores > 2) { return 2; } @@ -704,7 +708,7 @@ int32_t LibaomAv1Encoder::Encode( encoded_image._frameType = layer_frame->IsKeyframe() ? VideoFrameType::kVideoFrameKey : VideoFrameType::kVideoFrameDelta; - encoded_image.SetTimestamp(frame.timestamp()); + encoded_image.SetRtpTimestamp(frame.timestamp()); encoded_image.SetCaptureTimeIdentifier(frame.capture_time_identifier()); encoded_image.capture_time_ms_ = frame.render_time_ms(); encoded_image.rotation_ = frame.rotation(); @@ -824,7 +828,10 @@ VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const { info.implementation_name = "libaom"; info.has_trusted_rate_controller = true; info.is_hardware_accelerated = false; - info.scaling_settings = VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex); + info.scaling_settings = + (inited_ && !encoder_settings_.AV1().automatic_resize_on) + ? VideoEncoder::ScalingSettings::kOff + : VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex); info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420, VideoFrameBuffer::Type::kNV12}; if (SvcEnabled()) { diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc index 09bf1bf1ca..04ee9162ba 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc @@ -36,6 +36,7 @@ using ::testing::SizeIs; VideoCodec DefaultCodecSettings() { VideoCodec codec_settings; + codec_settings.codecType = kVideoCodecAV1; codec_settings.width = 320; codec_settings.height = 180; codec_settings.maxFramerate = 30; @@ -398,5 +399,16 @@ TEST(LibaomAv1EncoderTest, AdheresToTargetBitrateDespiteUnevenFrameTiming) { kTargetBitrateBps, kTargetBitrateBps / 10); } +TEST(LibaomAv1EncoderTest, DisableAutomaticResize) { + std::unique_ptr encoder = CreateLibaomAv1Encoder(); + ASSERT_TRUE(encoder); + VideoCodec codec_settings = DefaultCodecSettings(); + codec_settings.AV1()->automatic_resize_on = false; + EXPECT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), + WEBRTC_VIDEO_CODEC_OK); + EXPECT_EQ(encoder->GetEncoderInfo().scaling_settings.thresholds, + absl::nullopt); +} + } // namespace } // namespace webrtc diff --git a/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/modules/video_coding/codecs/h264/h264_decoder_impl.cc index f67718cb23..a9e9926c4f 100644 --- a/modules/video_coding/codecs/h264/h264_decoder_impl.cc +++ b/modules/video_coding/codecs/h264/h264_decoder_impl.cc @@ -612,7 +612,7 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, VideoFrame decoded_frame = VideoFrame::Builder() .set_video_frame_buffer(cropped_buffer) - .set_timestamp_rtp(input_image.Timestamp()) + .set_timestamp_rtp(input_image.RtpTimestamp()) .set_color_space(color_space) .build(); diff --git a/modules/video_coding/codecs/h264/h264_encoder_impl.cc b/modules/video_coding/codecs/h264/h264_encoder_impl.cc index b6023ac502..ee69b9befb 100644 --- a/modules/video_coding/codecs/h264/h264_encoder_impl.cc +++ b/modules/video_coding/codecs/h264/h264_encoder_impl.cc @@ -533,7 +533,7 @@ int32_t H264EncoderImpl::Encode( encoded_images_[i]._encodedWidth = configurations_[i].width; encoded_images_[i]._encodedHeight = configurations_[i].height; - encoded_images_[i].SetTimestamp(input_frame.timestamp()); + encoded_images_[i].SetRtpTimestamp(input_frame.timestamp()); encoded_images_[i].SetColorSpace(input_frame.color_space()); encoded_images_[i]._frameType = ConvertToVideoFrameType(info.eFrameType); encoded_images_[i].SetSimulcastIndex(configurations_[i].simulcast_idx); @@ -565,10 +565,20 @@ int32_t H264EncoderImpl::Encode( codec_specific.codecSpecific.H264.base_layer_sync = tid > 0 && tid < tl0sync_limit_[i]; if (svc_controllers_[i]) { + if (encoded_images_[i]._frameType == VideoFrameType::kVideoFrameKey) { + // Reset the ScalableVideoController on key frame + // to reset the expected dependency structure. + layer_frames = + svc_controllers_[i]->NextFrameConfig(/* restart= */ true); + RTC_CHECK_EQ(layer_frames.size(), 1); + RTC_DCHECK_EQ(layer_frames[0].TemporalId(), 0); + RTC_DCHECK_EQ(layer_frames[0].IsKeyframe(), true); + } + if (layer_frames[0].TemporalId() != tid) { RTC_LOG(LS_WARNING) - << "Encoder produced a frame for layer S" << (i + 1) << "T" - << tid + 1 << " that wasn't requested."; + << "Encoder produced a frame with temporal id " << tid + << ", expected " << layer_frames[0].TemporalId() << "."; continue; } encoded_images_[i].SetTemporalIndex(tid); diff --git a/modules/video_coding/codecs/multiplex/multiplex_decoder_adapter.cc b/modules/video_coding/codecs/multiplex/multiplex_decoder_adapter.cc index 9641df3c2e..551a9490b0 100644 --- a/modules/video_coding/codecs/multiplex/multiplex_decoder_adapter.cc +++ b/modules/video_coding/codecs/multiplex/multiplex_decoder_adapter.cc @@ -129,20 +129,20 @@ int32_t MultiplexDecoderAdapter::Decode(const EncodedImage& input_image, MultiplexImage image = MultiplexEncodedImagePacker::Unpack(input_image); if (supports_augmenting_data_) { - RTC_DCHECK(decoded_augmenting_data_.find(input_image.Timestamp()) == + RTC_DCHECK(decoded_augmenting_data_.find(input_image.RtpTimestamp()) == decoded_augmenting_data_.end()); decoded_augmenting_data_.emplace( std::piecewise_construct, - std::forward_as_tuple(input_image.Timestamp()), + std::forward_as_tuple(input_image.RtpTimestamp()), std::forward_as_tuple(std::move(image.augmenting_data), image.augmenting_data_size)); } if (image.component_count == 1) { - RTC_DCHECK(decoded_data_.find(input_image.Timestamp()) == + RTC_DCHECK(decoded_data_.find(input_image.RtpTimestamp()) == decoded_data_.end()); decoded_data_.emplace(std::piecewise_construct, - std::forward_as_tuple(input_image.Timestamp()), + std::forward_as_tuple(input_image.RtpTimestamp()), std::forward_as_tuple(kAXXStream)); } int32_t rv = 0; diff --git a/modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc b/modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc index 0f05d1a89c..a7ebebd6ca 100644 --- a/modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc +++ b/modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.cc @@ -260,7 +260,7 @@ MultiplexImage MultiplexEncodedImagePacker::Unpack( image_component.codec_type = frame_headers[i].codec_type; EncodedImage encoded_image = combined_image; - encoded_image.SetTimestamp(combined_image.Timestamp()); + encoded_image.SetRtpTimestamp(combined_image.RtpTimestamp()); encoded_image._frameType = frame_headers[i].frame_type; encoded_image.SetEncodedData(EncodedImageBuffer::Create( combined_image.data() + frame_headers[i].bitstream_offset, diff --git a/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc b/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc index 80744e2d8c..61e4b20f05 100644 --- a/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc +++ b/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc @@ -93,6 +93,9 @@ int MultiplexEncoderAdapter::InitEncode( key_frame_interval_ = video_codec.H264()->keyFrameInterval; video_codec.H264()->keyFrameInterval = 0; break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } @@ -318,7 +321,7 @@ EncodedImageCallback::Result MultiplexEncoderAdapter::OnEncodedImage( MutexLock lock(&mutex_); const auto& stashed_image_itr = - stashed_images_.find(encodedImage.Timestamp()); + stashed_images_.find(encodedImage.RtpTimestamp()); const auto& stashed_image_next_itr = std::next(stashed_image_itr, 1); RTC_DCHECK(stashed_image_itr != stashed_images_.end()); MultiplexImage& stashed_image = stashed_image_itr->second; diff --git a/modules/video_coding/codecs/test/video_codec_analyzer.cc b/modules/video_coding/codecs/test/video_codec_analyzer.cc index 6e0ea9f6b4..772c15734a 100644 --- a/modules/video_coding/codecs/test/video_codec_analyzer.cc +++ b/modules/video_coding/codecs/test/video_codec_analyzer.cc @@ -79,7 +79,7 @@ void VideoCodecAnalyzer::StartEncode(const VideoFrame& input_frame) { void VideoCodecAnalyzer::FinishEncode(const EncodedImage& frame) { int64_t encode_finished_us = rtc::TimeMicros(); - task_queue_.PostTask([this, timestamp_rtp = frame.Timestamp(), + task_queue_.PostTask([this, timestamp_rtp = frame.RtpTimestamp(), spatial_idx = frame.SpatialIndex().value_or(0), temporal_idx = frame.TemporalIndex().value_or(0), width = frame._encodedWidth, @@ -114,7 +114,7 @@ void VideoCodecAnalyzer::FinishEncode(const EncodedImage& frame) { void VideoCodecAnalyzer::StartDecode(const EncodedImage& frame) { int64_t decode_start_us = rtc::TimeMicros(); - task_queue_.PostTask([this, timestamp_rtp = frame.Timestamp(), + task_queue_.PostTask([this, timestamp_rtp = frame.RtpTimestamp(), spatial_idx = frame.SpatialIndex().value_or(0), frame_size_bytes = frame.size(), decode_start_us]() { RTC_DCHECK_RUN_ON(&sequence_checker_); diff --git a/modules/video_coding/codecs/test/video_codec_analyzer_unittest.cc b/modules/video_coding/codecs/test/video_codec_analyzer_unittest.cc index d7c5fe28a4..03146417da 100644 --- a/modules/video_coding/codecs/test/video_codec_analyzer_unittest.cc +++ b/modules/video_coding/codecs/test/video_codec_analyzer_unittest.cc @@ -52,7 +52,7 @@ VideoFrame CreateVideoFrame(uint32_t timestamp_rtp, EncodedImage CreateEncodedImage(uint32_t timestamp_rtp, int spatial_idx = 0) { EncodedImage encoded_image; - encoded_image.SetTimestamp(timestamp_rtp); + encoded_image.SetRtpTimestamp(timestamp_rtp); encoded_image.SetSpatialIndex(spatial_idx); return encoded_image; } diff --git a/modules/video_coding/codecs/test/video_codec_test.cc b/modules/video_coding/codecs/test/video_codec_test.cc index 587af46a07..1c8fe97e84 100644 --- a/modules/video_coding/codecs/test/video_codec_test.cc +++ b/modules/video_coding/codecs/test/video_codec_test.cc @@ -15,6 +15,7 @@ #include #include +#include "absl/flags/flag.h" #include "absl/functional/any_invocable.h" #include "api/test/create_video_codec_tester.h" #include "api/test/metrics/global_metrics_logger_and_exporter.h" @@ -38,8 +39,8 @@ #include "modules/video_coding/codecs/test/android_codec_factory_helper.h" #endif #include "rtc_base/logging.h" -#include "system_wrappers/include/field_trial.h" #include "test/gtest.h" +#include "test/test_flags.h" #include "test/testsupport/file_utils.h" #include "test/testsupport/frame_reader.h" @@ -255,7 +256,7 @@ class TestEncoder : public VideoCodecTester::Encoder, Result OnEncodedImage(const EncodedImage& encoded_image, const CodecSpecificInfo* codec_specific_info) override { MutexLock lock(&mutex_); - auto cb = callbacks_.find(encoded_image.Timestamp()); + auto cb = callbacks_.find(encoded_image.RtpTimestamp()); RTC_CHECK(cb != callbacks_.end()); cb->second(encoded_image); @@ -352,7 +353,7 @@ class TestDecoder : public VideoCodecTester::Decoder, void Decode(const EncodedImage& frame, DecodeCallback callback) override { { MutexLock lock(&mutex_); - callbacks_[frame.Timestamp()] = std::move(callback); + callbacks_[frame.RtpTimestamp()] = std::move(callback); } decoder_->Decode(frame, /*render_time_ms=*/0); @@ -612,7 +613,7 @@ TEST_P(SpatialQualityTest, SpatialQuality) { std::vector frames = stats->Slice(); SetTargetRates(frame_settings, frames); stream = stats->Aggregate(frames); - if (field_trial::IsEnabled("WebRTC-QuickPerfTest")) { + if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) { EXPECT_GE(stream.psnr.y.GetAverage(), psnr); } } @@ -697,7 +698,7 @@ TEST_P(BitrateAdaptationTest, BitrateAdaptation) { stats->Slice(VideoCodecStats::Filter{.first_frame = first_frame}); SetTargetRates(frame_settings, frames); stream = stats->Aggregate(frames); - if (field_trial::IsEnabled("WebRTC-QuickPerfTest")) { + if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) { EXPECT_NEAR(stream.bitrate_mismatch_pct.GetAverage(), 0, 10); EXPECT_NEAR(stream.framerate_mismatch_pct.GetAverage(), 0, 10); } @@ -776,7 +777,7 @@ TEST_P(FramerateAdaptationTest, FramerateAdaptation) { stats->Slice(VideoCodecStats::Filter{.first_frame = first_frame}); SetTargetRates(frame_settings, frames); stream = stats->Aggregate(frames); - if (field_trial::IsEnabled("WebRTC-QuickPerfTest")) { + if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) { EXPECT_NEAR(stream.bitrate_mismatch_pct.GetAverage(), 0, 10); EXPECT_NEAR(stream.framerate_mismatch_pct.GetAverage(), 0, 10); } diff --git a/modules/video_coding/codecs/test/video_codec_tester_impl.cc b/modules/video_coding/codecs/test/video_codec_tester_impl.cc index fdfee3d028..f15b1b35f3 100644 --- a/modules/video_coding/codecs/test/video_codec_tester_impl.cc +++ b/modules/video_coding/codecs/test/video_codec_tester_impl.cc @@ -255,7 +255,7 @@ class TesterDecoder { void Decode(const EncodedImage& input_frame) { Timestamp timestamp = - Timestamp::Micros((input_frame.Timestamp() / k90kHz).us()); + Timestamp::Micros((input_frame.RtpTimestamp() / k90kHz).us()); task_queue_.PostScheduledTask( [this, input_frame] { diff --git a/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc b/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc index 524134bd42..a8c118ef20 100644 --- a/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc +++ b/modules/video_coding/codecs/test/video_codec_tester_impl_unittest.cc @@ -64,7 +64,7 @@ VideoFrame CreateVideoFrame(uint32_t timestamp_rtp) { EncodedImage CreateEncodedImage(uint32_t timestamp_rtp) { EncodedImage encoded_image; - encoded_image.SetTimestamp(timestamp_rtp); + encoded_image.SetRtpTimestamp(timestamp_rtp); return encoded_image; } diff --git a/modules/video_coding/codecs/test/video_codec_unittest.cc b/modules/video_coding/codecs/test/video_codec_unittest.cc index a4a8b253fc..5ac589aaa5 100644 --- a/modules/video_coding/codecs/test/video_codec_unittest.cc +++ b/modules/video_coding/codecs/test/video_codec_unittest.cc @@ -111,6 +111,7 @@ VideoFrame VideoCodecUnitTest::NextInputFrame() { last_input_frame_timestamp_ + kVideoPayloadTypeFrequency / codec_settings_.maxFramerate; input_frame.set_timestamp(timestamp); + input_frame.set_timestamp_us(timestamp * (1000 / 90)); last_input_frame_timestamp_ = timestamp; return input_frame; diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc index 7543372e21..eb264e5285 100644 --- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc +++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc @@ -137,6 +137,9 @@ std::string CodecSpecificToString(const VideoCodec& codec) { ss << "\nnum_temporal_layers: " << static_cast(codec.H264().numberOfTemporalLayers); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } @@ -246,6 +249,9 @@ void VideoCodecTestFixtureImpl::Config::SetCodecSettings( codec_settings.H264()->numberOfTemporalLayers = static_cast(num_temporal_layers); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } diff --git a/modules/video_coding/codecs/test/videoprocessor.cc b/modules/video_coding/codecs/test/videoprocessor.cc index 3d7f6ff8a0..2f159fce83 100644 --- a/modules/video_coding/codecs/test/videoprocessor.cc +++ b/modules/video_coding/codecs/test/videoprocessor.cc @@ -387,7 +387,7 @@ void VideoProcessor::FrameEncoded( size_t temporal_idx = GetTemporalLayerIndex(codec_specific); FrameStatistics* frame_stat = - stats_->GetFrameWithTimestamp(encoded_image.Timestamp(), stream_idx); + stats_->GetFrameWithTimestamp(encoded_image.RtpTimestamp(), stream_idx); const size_t frame_number = frame_stat->frame_number; // Ensure that the encode order is monotonically increasing, within this @@ -466,7 +466,7 @@ void VideoProcessor::FrameEncoded( if (!layer_dropped) { base_image = &merged_encoded_frames_[i]; base_stat = - stats_->GetFrameWithTimestamp(encoded_image.Timestamp(), i); + stats_->GetFrameWithTimestamp(encoded_image.RtpTimestamp(), i); } else if (base_image && !base_stat->non_ref_for_inter_layer_pred) { DecodeFrame(*base_image, i); } @@ -634,7 +634,7 @@ void VideoProcessor::DecodeFrame(const EncodedImage& encoded_image, size_t spatial_idx) { RTC_DCHECK_RUN_ON(&sequence_checker_); FrameStatistics* frame_stat = - stats_->GetFrameWithTimestamp(encoded_image.Timestamp(), spatial_idx); + stats_->GetFrameWithTimestamp(encoded_image.RtpTimestamp(), spatial_idx); frame_stat->decode_start_ns = rtc::TimeNanos(); frame_stat->decode_return_code = @@ -659,7 +659,7 @@ const webrtc::EncodedImage* VideoProcessor::BuildAndStoreSuperframe( for (int base_idx = static_cast(spatial_idx) - 1; base_idx >= 0; --base_idx) { EncodedImage lower_layer = merged_encoded_frames_.at(base_idx); - if (lower_layer.Timestamp() == encoded_image.Timestamp()) { + if (lower_layer.RtpTimestamp() == encoded_image.RtpTimestamp()) { base_image = lower_layer; break; } diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc index 01cedb5316..5afd105949 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc @@ -249,8 +249,8 @@ int LibvpxVp8Decoder::Decode(const EncodedImage& input_image, vpx_codec_err_t vpx_ret = vpx_codec_control(decoder_, VPXD_GET_LAST_QUANTIZER, &qp); RTC_DCHECK_EQ(vpx_ret, VPX_CODEC_OK); - int ret = - ReturnFrame(img, input_image.Timestamp(), qp, input_image.ColorSpace()); + int ret = ReturnFrame(img, input_image.RtpTimestamp(), qp, + input_image.ColorSpace()); if (ret != 0) { return ret; } diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index 5457402542..52ef6231ea 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -44,6 +44,11 @@ #include "third_party/libyuv/include/libyuv/scale.h" #include "vpx/vp8cx.h" +#if (defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)) && \ + (defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)) +#define MOBILE_ARM +#endif + namespace webrtc { namespace { #if defined(WEBRTC_IOS) @@ -66,6 +71,13 @@ constexpr uint32_t kVp832ByteAlign = 32u; constexpr int kRtpTicksPerSecond = 90000; constexpr int kRtpTicksPerMs = kRtpTicksPerSecond / 1000; +// If internal frame dropping is enabled, force the encoder to output a frame +// on an encode request after this timeout even if this causes some +// bitrate overshoot compared to the nominal target. Otherwise we risk the +// receivers incorrectly identifying the gap as a fault and they may needlessly +// send keyframe requests to recover. +constexpr TimeDelta kDefaultMaxFrameDropInterval = TimeDelta::Seconds(2); + // VP8 denoiser states. enum denoiserState : uint32_t { kDenoiserOff, @@ -210,6 +222,46 @@ void SetRawImagePlanes(vpx_image_t* raw_image, VideoFrameBuffer* buffer) { } } +// Helper class used to temporarily change the frame drop threshold for an +// encoder. Returns the setting to the previous value when upon destruction. +class FrameDropConfigOverride { + public: + FrameDropConfigOverride(LibvpxInterface* libvpx, + vpx_codec_ctx_t* encoder, + vpx_codec_enc_cfg_t* config, + uint32_t temporary_frame_drop_threshold) + : libvpx_(libvpx), + encoder_(encoder), + config_(config), + original_frame_drop_threshold_(config->rc_dropframe_thresh) { + config_->rc_dropframe_thresh = temporary_frame_drop_threshold; + libvpx_->codec_enc_config_set(encoder_, config_); + } + ~FrameDropConfigOverride() { + config_->rc_dropframe_thresh = original_frame_drop_threshold_; + libvpx_->codec_enc_config_set(encoder_, config_); + } + + private: + LibvpxInterface* const libvpx_; + vpx_codec_ctx_t* const encoder_; + vpx_codec_enc_cfg_t* const config_; + const uint32_t original_frame_drop_threshold_; +}; + +absl::optional ParseFrameDropInterval() { + FieldTrialFlag disabled = FieldTrialFlag("Disabled"); + FieldTrialParameter interval("interval", + kDefaultMaxFrameDropInterval); + ParseFieldTrial({&disabled, &interval}, + field_trial::FindFullName("WebRTC-VP8-MaxFrameInterval")); + if (disabled.Get()) { + // Kill switch set, don't use any max frame interval. + return absl::nullopt; + } + return interval.Get(); +} + } // namespace std::unique_ptr VP8Encoder::Create() { @@ -260,9 +312,12 @@ LibvpxVp8Encoder::LibvpxVp8Encoder(std::unique_ptr interface, std::move(settings.frame_buffer_controller_factory)), resolution_bitrate_limits_(std::move(settings.resolution_bitrate_limits)), key_frame_request_(kMaxSimulcastStreams, false), + last_encoder_output_time_(kMaxSimulcastStreams, + Timestamp::MinusInfinity()), variable_framerate_experiment_(ParseVariableFramerateConfig( "WebRTC-VP8VariableFramerateScreenshare")), - framerate_controller_(variable_framerate_experiment_.framerate_limit) { + framerate_controller_(variable_framerate_experiment_.framerate_limit), + max_frame_drop_interval_(ParseFrameDropInterval()) { // TODO(eladalon/ilnik): These reservations might be wasting memory. // InitEncode() is resizing to the actual size, which might be smaller. raw_images_.reserve(kMaxSimulcastStreams); @@ -505,6 +560,8 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, send_stream_[0] = true; // For non-simulcast case. cpu_speed_.resize(number_of_streams); std::fill(key_frame_request_.begin(), key_frame_request_.end(), false); + std::fill(last_encoder_output_time_.begin(), last_encoder_output_time_.end(), + Timestamp::MinusInfinity()); int idx = number_of_streams - 1; for (int i = 0; i < (number_of_streams - 1); ++i, --idx) { @@ -692,8 +749,7 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, } int LibvpxVp8Encoder::GetCpuSpeed(int width, int height) { -#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \ - defined(WEBRTC_ANDROID) +#ifdef MOBILE_ARM // On mobile platform, use a lower speed setting for lower resolutions for // CPUs with 4 or more cores. RTC_DCHECK_GT(number_of_cores_, 0); @@ -798,12 +854,10 @@ int LibvpxVp8Encoder::InitAndSetControlSettings() { // for getting the denoised frame from the encoder and using that // when encoding lower resolution streams. Would it work with the // multi-res encoding feature? +#ifdef MOBILE_ARM denoiserState denoiser_state = kDenoiserOnYOnly; -#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \ - defined(WEBRTC_ANDROID) - denoiser_state = kDenoiserOnYOnly; #else - denoiser_state = kDenoiserOnAdaptive; + denoiserState denoiser_state = kDenoiserOnAdaptive; #endif libvpx_->codec_control( &encoders_[0], VP8E_SET_NOISE_SENSITIVITY, @@ -953,10 +1007,28 @@ int LibvpxVp8Encoder::Encode(const VideoFrame& frame, } } + // Check if any encoder risks timing out and force a frame in that case. + std::vector frame_drop_overrides_; + if (max_frame_drop_interval_.has_value()) { + Timestamp now = Timestamp::Micros(frame.timestamp_us()); + for (size_t i = 0; i < send_stream_.size(); ++i) { + if (send_stream_[i] && FrameDropThreshold(i) > 0 && + last_encoder_output_time_[i].IsFinite() && + (now - last_encoder_output_time_[i]) >= *max_frame_drop_interval_) { + RTC_LOG(LS_INFO) << "Forcing frame to avoid timeout for stream " << i; + size_t encoder_idx = encoders_.size() - 1 - i; + frame_drop_overrides_.emplace_back(libvpx_.get(), + &encoders_[encoder_idx], + &vpx_configs_[encoder_idx], 0); + } + } + } + if (frame.update_rect().IsEmpty() && num_steady_state_frames_ >= 3 && !key_frame_requested) { if (variable_framerate_experiment_.enabled && - framerate_controller_.DropFrame(frame.timestamp() / kRtpTicksPerMs)) { + framerate_controller_.DropFrame(frame.timestamp() / kRtpTicksPerMs) && + frame_drop_overrides_.empty()) { return WEBRTC_VIDEO_CODEC_OK; } framerate_controller_.AddFrame(frame.timestamp() / kRtpTicksPerMs); @@ -1179,7 +1251,7 @@ int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image, break; } } - encoded_images_[encoder_idx].SetTimestamp(input_image.timestamp()); + encoded_images_[encoder_idx].SetRtpTimestamp(input_image.timestamp()); encoded_images_[encoder_idx].SetCaptureTimeIdentifier( input_image.capture_time_identifier()); encoded_images_[encoder_idx].SetColorSpace(input_image.color_space()); @@ -1198,6 +1270,9 @@ int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image, libvpx_->codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER, &qp_128); encoded_images_[encoder_idx].qp_ = qp_128; + last_encoder_output_time_[stream_idx] = + Timestamp::Micros(input_image.timestamp_us()); + encoded_complete_callback_->OnEncodedImage(encoded_images_[encoder_idx], &codec_specific); const size_t steady_state_size = SteadyStateSize( diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h index 74477eac7e..dad174ceff 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h @@ -16,6 +16,8 @@ #include #include "api/fec_controller_override.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "api/video/encoded_image.h" #include "api/video/video_frame.h" #include "api/video_codecs/video_encoder.h" @@ -132,6 +134,7 @@ class LibvpxVp8Encoder : public VideoEncoder { std::vector vpx_configs_; std::vector config_overrides_; std::vector downsampling_factors_; + std::vector last_encoder_output_time_; // Variable frame-rate screencast related fields and methods. const struct VariableFramerateExperiment { @@ -152,6 +155,8 @@ class LibvpxVp8Encoder : public VideoEncoder { FecControllerOverride* fec_controller_override_ = nullptr; const LibvpxVp8EncoderInfoSettings encoder_info_override_; + + absl::optional max_frame_drop_interval_; }; } // namespace webrtc diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 14ac8aab5b..a6f570f855 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -10,6 +10,7 @@ #include +#include #include #include "api/test/create_frame_generator.h" @@ -259,7 +260,7 @@ TEST_F(TestVp8Impl, OnEncodedImageReportsInfo) { CodecSpecificInfo codec_specific_info; EncodeAndWaitForFrame(input_frame, &encoded_frame, &codec_specific_info); - EXPECT_EQ(kInitialTimestampRtp, encoded_frame.Timestamp()); + EXPECT_EQ(kInitialTimestampRtp, encoded_frame.RtpTimestamp()); EXPECT_EQ(kWidth, static_cast(encoded_frame._encodedWidth)); EXPECT_EQ(kHeight, static_cast(encoded_frame._encodedHeight)); ASSERT_TRUE(encoded_frame.CaptureTimeIdentifier().has_value()); @@ -837,6 +838,146 @@ TEST_F(TestVp8Impl, GetEncoderInfoFpsAllocationSimulcastVideo) { ::testing::ElementsAreArray(expected_fps_allocation)); } +class TestVp8ImplWithMaxFrameDropTrial + : public TestVp8Impl, + public ::testing::WithParamInterface< + std::tuple> { + public: + TestVp8ImplWithMaxFrameDropTrial() + : TestVp8Impl(), trials_(std::get<0>(GetParam())) {} + + protected: + test::ScopedFieldTrials trials_; +}; + +TEST_P(TestVp8ImplWithMaxFrameDropTrial, EnforcesMaxFrameDropInterval) { + static constexpr int kFps = 5; + auto [trial_string, max_interval_config, min_expected_interval] = GetParam(); + + // Allow one frame interval over the configured max frame drop interval. + TimeDelta max_frame_delta = + max_interval_config + (TimeDelta::Seconds(1) / kFps); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); + + // Set up low-bitrate screenshare stream. + codec_settings_.numberOfSimulcastStreams = 1; + codec_settings_.legacy_conference_mode = false; + codec_settings_.mode = VideoCodecMode::kScreensharing; + codec_settings_.maxFramerate = kFps; + codec_settings_.width = 2880; + codec_settings_.height = 1800; + codec_settings_.minBitrate = 30; + codec_settings_.maxBitrate = 420; + codec_settings_.SetFrameDropEnabled(true); + + codec_settings_.simulcastStream[0].active = true; + codec_settings_.simulcastStream[0].minBitrate = codec_settings_.minBitrate; + codec_settings_.simulcastStream[0].targetBitrate = codec_settings_.maxBitrate; + codec_settings_.simulcastStream[0].maxBitrate = codec_settings_.maxBitrate; + codec_settings_.simulcastStream[0].numberOfTemporalLayers = 2; + codec_settings_.simulcastStream[0].width = codec_settings_.width; + codec_settings_.simulcastStream[0].height = codec_settings_.height; + codec_settings_.simulcastStream[0].maxFramerate = + codec_settings_.maxFramerate; + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kSettings)); + + // Allocate a very constained amount of bitrate to increase risk of frame + // drops. + VideoBitrateAllocation bitrate_allocation; + bitrate_allocation.SetBitrate(0, 0, 50'000); + bitrate_allocation.SetBitrate(0, 1, 50'000); + encoder_->SetRates( + VideoEncoder::RateControlParameters(bitrate_allocation, 5.0)); + + EncodedImage encoded_frame; + CodecSpecificInfo codec_specific_info; + // Create a low-complexity 1 square test sequence. + input_frame_generator_ = test::CreateSquareFrameGenerator( + codec_settings_.width, codec_settings_.height, + test::FrameGeneratorInterface::OutputType::kI420, + /*num_squares=*/1); + + class Callback : public EncodedImageCallback { + public: + Callback() : last_callback_(Timestamp::MinusInfinity()) {} + + const std::vector& GetCallbackDeltas() const { + return callback_deltas_; + } + void ClearCallbackDeltas() { callback_deltas_.clear(); } + + protected: + Result OnEncodedImage(const EncodedImage& encoded_image, + const CodecSpecificInfo* codec_specific_info) { + Timestamp timestamp = + Timestamp::Millis(encoded_image.RtpTimestamp() / 90); + if (last_callback_.IsFinite()) { + callback_deltas_.push_back(timestamp - last_callback_); + } + last_callback_ = timestamp; + return Result(Result::Error::OK); + } + + private: + std::vector callback_deltas_; + Timestamp last_callback_; + } callback; + + encoder_->RegisterEncodeCompleteCallback(&callback); + std::vector frame_types = {VideoFrameType::kVideoFrameKey}; + EXPECT_EQ(encoder_->Encode(NextInputFrame(), &frame_types), + WEBRTC_VIDEO_CODEC_OK); + frame_types[0] = VideoFrameType::kVideoFrameDelta; + + // Encode a couple of frames and verify reasonable frame spacing. + for (uint32_t i = 0; i < codec_settings_.maxFramerate * 10; ++i) { + EXPECT_EQ(encoder_->Encode(NextInputFrame(), &frame_types), + WEBRTC_VIDEO_CODEC_OK); + } + auto deltas = callback.GetCallbackDeltas(); + ASSERT_FALSE(deltas.empty()); + EXPECT_LE(*std::max_element(deltas.begin(), deltas.end()), max_frame_delta); + + // Switch to a much more complex input. Verify time deltas are still OK. + input_frame_generator_ = test::CreateSquareFrameGenerator( + codec_settings_.width, codec_settings_.height, + test::FrameGeneratorInterface::OutputType::kI420, + /*num_squares=*/5000); + callback.ClearCallbackDeltas(); + for (uint32_t i = 0; i < codec_settings_.maxFramerate * 10; ++i) { + EXPECT_EQ(encoder_->Encode(NextInputFrame(), &frame_types), + WEBRTC_VIDEO_CODEC_OK); + } + deltas = callback.GetCallbackDeltas(); + ASSERT_FALSE(deltas.empty()); + EXPECT_LE(*std::max_element(deltas.begin(), deltas.end()), max_frame_delta); + + // Check that encoder is causing the expected long frame drop intervals. + EXPECT_GT(*std::max_element(deltas.begin(), deltas.end()), + min_expected_interval); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); +} + +INSTANTIATE_TEST_SUITE_P( + All, + TestVp8ImplWithMaxFrameDropTrial, + ::testing::Values( + // Tuple of { + // trial string, + // configured max frame interval, + // lower bound on expected frame drop intervals + // } + std::make_tuple("WebRTC-VP8-MaxFrameInterval/Disabled/", + TimeDelta::PlusInfinity(), + TimeDelta::Seconds(2)), + std::make_tuple("WebRTC-VP8-MaxFrameInterval/interval:1s/", + TimeDelta::Seconds(1), + TimeDelta::Seconds(0)), + std::make_tuple("", TimeDelta::Seconds(2), TimeDelta::Seconds(1)))); + class TestVp8ImplForPixelFormat : public TestVp8Impl, public ::testing::WithParamInterface { diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc index 2dec061836..8e1bab4ed3 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_decoder.cc @@ -246,8 +246,8 @@ int LibvpxVp9Decoder::Decode(const EncodedImage& input_image, vpx_codec_err_t vpx_ret = vpx_codec_control(decoder_, VPXD_GET_LAST_QUANTIZER, &qp); RTC_DCHECK_EQ(vpx_ret, VPX_CODEC_OK); - int ret = - ReturnFrame(img, input_image.Timestamp(), qp, input_image.ColorSpace()); + int ret = ReturnFrame(img, input_image.RtpTimestamp(), qp, + input_image.ColorSpace()); if (ret != 0) { return ret; } diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc index e460625aea..e26169fd3d 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc @@ -47,6 +47,11 @@ #include "vpx/vp8cx.h" #include "vpx/vpx_encoder.h" +#if (defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)) && \ + (defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)) +#define MOBILE_ARM +#endif + namespace webrtc { namespace { @@ -201,13 +206,12 @@ vpx_svc_ref_frame_config_t Vp9References( } bool AllowDenoising() { - // Do not enable the denoiser on ARM since optimization is pending. - // Denoiser is on by default on other platforms. -#if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) && \ - !defined(ANDROID) - return true; -#else +#ifdef MOBILE_ARM + // Keep the denoiser disabled on mobile ARM devices. It increases encode time + // by up to 16%. return false; +#else + return true; #endif } @@ -766,9 +770,8 @@ int LibvpxVp9Encoder::NumberOfThreads(int width, } else if (width * height >= 640 * 360 && number_of_cores > 2) { return 2; } else { -// Use 2 threads for low res on ARM. -#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \ - defined(WEBRTC_ANDROID) +// Use 2 threads for low res on mobile ARM. +#ifdef MOBILE_ARM if (width * height >= 320 * 180 && number_of_cores > 2) { return 2; } @@ -1733,7 +1736,7 @@ void LibvpxVp9Encoder::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { UpdateReferenceBuffers(*pkt, pics_since_key_); TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_.size()); - encoded_image_.SetTimestamp(input_image_->timestamp()); + encoded_image_.SetRtpTimestamp(input_image_->timestamp()); encoded_image_.SetCaptureTimeIdentifier( input_image_->capture_time_identifier()); encoded_image_.SetColorSpace(input_image_->color_space()); @@ -1768,7 +1771,7 @@ void LibvpxVp9Encoder::DeliverBufferedFrame(bool end_of_picture) { if (codec_.mode == VideoCodecMode::kScreensharing) { const uint8_t spatial_idx = encoded_image_.SpatialIndex().value_or(0); const uint32_t frame_timestamp_ms = - 1000 * encoded_image_.Timestamp() / kVideoPayloadTypeFrequency; + 1000 * encoded_image_.RtpTimestamp() / kVideoPayloadTypeFrequency; framerate_controller_[spatial_idx].AddFrame(frame_timestamp_ms); const size_t steady_state_size = SteadyStateSize( @@ -1998,7 +2001,7 @@ LibvpxVp9Encoder::PerformanceFlags LibvpxVp9Encoder::GetDefaultPerformanceFlags() { PerformanceFlags flags; flags.use_per_layer_speed = true; -#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || defined(ANDROID) +#ifdef MOBILE_ARM // Speed 8 on all layers for all resolutions. flags.settings_by_resolution[0] = {.base_layer_speed = 8, .high_layer_speed = 8, diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index 43def0f6f3..7af8cab3cb 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -172,6 +172,9 @@ std::vector GetVp9SvcConfig(VideoCodec& codec) { absl::optional scalability_mode = codec.GetScalabilityMode(); RTC_DCHECK(scalability_mode.has_value()); + bool requested_single_spatial_layer = + ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1; + // Limit number of spatial layers for given resolution. int limited_num_spatial_layers = GetLimitedNumSpatialLayers(codec.width, codec.height); @@ -205,6 +208,14 @@ std::vector GetVp9SvcConfig(VideoCodec& codec) { spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps; + // Use codec bitrate limits if spatial layering is not requested. + if (requested_single_spatial_layer) { + SpatialLayer& spatial_layer = spatial_layers[0]; + spatial_layer.minBitrate = codec.minBitrate; + spatial_layer.maxBitrate = codec.maxBitrate; + spatial_layer.targetBitrate = codec.maxBitrate; + } + return spatial_layers; } diff --git a/modules/video_coding/codecs/vp9/svc_config_unittest.cc b/modules/video_coding/codecs/vp9/svc_config_unittest.cc index 762fd39287..1b1abe0f6d 100644 --- a/modules/video_coding/codecs/vp9/svc_config_unittest.cc +++ b/modules/video_coding/codecs/vp9/svc_config_unittest.cc @@ -265,6 +265,21 @@ TEST(SvcConfig, BitrateThresholdsWithScalabilityMode) { } } +TEST(SvcConfig, CopiesMinMaxBitrateForSingleSpatialLayer) { + VideoCodec codec; + codec.codecType = kVideoCodecVP9; + codec.SetScalabilityMode(ScalabilityMode::kL1T3); + codec.width = 1280; + codec.height = 720; + codec.minBitrate = 100; + codec.maxBitrate = 500; + + std::vector spatial_layers = GetVp9SvcConfig(codec); + EXPECT_EQ(spatial_layers[0].minBitrate, 100u); + EXPECT_EQ(spatial_layers[0].maxBitrate, 500u); + EXPECT_LE(spatial_layers[0].targetBitrate, 500u); +} + TEST(SvcConfig, ScreenSharing) { std::vector spatial_layers = GetSvcConfig(1920, 1080, 30, 1, 3, 3, true); diff --git a/modules/video_coding/deprecated/decoding_state.cc b/modules/video_coding/deprecated/decoding_state.cc index 1ec8e107a9..01ae03ce93 100644 --- a/modules/video_coding/deprecated/decoding_state.cc +++ b/modules/video_coding/deprecated/decoding_state.cc @@ -58,7 +58,7 @@ bool VCMDecodingState::IsOldFrame(const VCMFrameBuffer* frame) const { RTC_DCHECK(frame); if (in_initial_state_) return false; - return !IsNewerTimestamp(frame->Timestamp(), time_stamp_); + return !IsNewerTimestamp(frame->RtpTimestamp(), time_stamp_); } bool VCMDecodingState::IsOldPacket(const VCMPacket* packet) const { @@ -74,7 +74,7 @@ void VCMDecodingState::SetState(const VCMFrameBuffer* frame) { if (!UsingFlexibleMode(frame)) UpdateSyncState(frame); sequence_num_ = static_cast(frame->GetHighSeqNum()); - time_stamp_ = frame->Timestamp(); + time_stamp_ = frame->RtpTimestamp(); picture_id_ = frame->PictureId(); temporal_id_ = frame->TemporalId(); tl0_pic_id_ = frame->Tl0PicId(); @@ -144,7 +144,7 @@ bool VCMDecodingState::UpdateEmptyFrame(const VCMFrameBuffer* frame) { // Continuous empty packets or continuous frames can be dropped if we // advance the sequence number. sequence_num_ = frame->GetHighSeqNum(); - time_stamp_ = frame->Timestamp(); + time_stamp_ = frame->RtpTimestamp(); return true; } return false; diff --git a/modules/video_coding/deprecated/frame_buffer.cc b/modules/video_coding/deprecated/frame_buffer.cc index 76345ac6e4..a347fb6ccd 100644 --- a/modules/video_coding/deprecated/frame_buffer.cc +++ b/modules/video_coding/deprecated/frame_buffer.cc @@ -81,7 +81,7 @@ VCMFrameBufferEnum VCMFrameBuffer::InsertPacket(const VCMPacket& packet, if (kStateEmpty == _state) { // First packet (empty and/or media) inserted into this frame. // store some info and set some initial values. - SetTimestamp(packet.timestamp); + SetRtpTimestamp(packet.timestamp); // We only take the ntp timestamp of the first packet of a frame. ntp_time_ms_ = packet.ntp_time_ms_; _codec = packet.codec(); diff --git a/modules/video_coding/deprecated/jitter_buffer.cc b/modules/video_coding/deprecated/jitter_buffer.cc index bae4bac9f8..66f4cea090 100644 --- a/modules/video_coding/deprecated/jitter_buffer.cc +++ b/modules/video_coding/deprecated/jitter_buffer.cc @@ -38,7 +38,7 @@ bool HasNonEmptyState(FrameListPair pair) { } void FrameList::InsertFrame(VCMFrameBuffer* frame) { - insert(rbegin().base(), FrameListPair(frame->Timestamp(), frame)); + insert(rbegin().base(), FrameListPair(frame->RtpTimestamp(), frame)); } VCMFrameBuffer* FrameList::PopFrame(uint32_t timestamp) { @@ -286,7 +286,7 @@ VCMEncodedFrame* VCMJitterBuffer::ExtractAndSetDecode(uint32_t timestamp) { // Wait for this one to get complete. waiting_for_completion_.frame_size = frame->size(); waiting_for_completion_.latest_packet_time = frame->LatestPacketTimeMs(); - waiting_for_completion_.timestamp = frame->Timestamp(); + waiting_for_completion_.timestamp = frame->RtpTimestamp(); } } @@ -521,7 +521,8 @@ bool VCMJitterBuffer::IsContinuous(const VCMFrameBuffer& frame) const { for (FrameList::const_iterator it = decodable_frames_.begin(); it != decodable_frames_.end(); ++it) { VCMFrameBuffer* decodable_frame = it->second; - if (IsNewerTimestamp(decodable_frame->Timestamp(), frame.Timestamp())) { + if (IsNewerTimestamp(decodable_frame->RtpTimestamp(), + frame.RtpTimestamp())) { break; } decoding_state.SetState(decodable_frame); @@ -555,7 +556,7 @@ void VCMJitterBuffer::FindAndInsertContinuousFramesWithState( it != incomplete_frames_.end();) { VCMFrameBuffer* frame = it->second; if (IsNewerTimestamp(original_decoded_state.time_stamp(), - frame->Timestamp())) { + frame->RtpTimestamp())) { ++it; continue; } @@ -592,11 +593,11 @@ int VCMJitterBuffer::NonContinuousOrIncompleteDuration() { if (incomplete_frames_.empty()) { return 0; } - uint32_t start_timestamp = incomplete_frames_.Front()->Timestamp(); + uint32_t start_timestamp = incomplete_frames_.Front()->RtpTimestamp(); if (!decodable_frames_.empty()) { - start_timestamp = decodable_frames_.Back()->Timestamp(); + start_timestamp = decodable_frames_.Back()->RtpTimestamp(); } - return incomplete_frames_.Back()->Timestamp() - start_timestamp; + return incomplete_frames_.Back()->RtpTimestamp() - start_timestamp; } uint16_t VCMJitterBuffer::EstimatedLowSequenceNumber( @@ -861,7 +862,7 @@ void VCMJitterBuffer::UpdateJitterEstimate(const VCMFrameBuffer& frame, } // No retransmitted frames should be a part of the jitter // estimate. - UpdateJitterEstimate(frame.LatestPacketTimeMs(), frame.Timestamp(), + UpdateJitterEstimate(frame.LatestPacketTimeMs(), frame.RtpTimestamp(), frame.size(), incomplete_frame); } diff --git a/modules/video_coding/deprecated/jitter_buffer_unittest.cc b/modules/video_coding/deprecated/jitter_buffer_unittest.cc index 81483a1e2c..ee88f9c9cb 100644 --- a/modules/video_coding/deprecated/jitter_buffer_unittest.cc +++ b/modules/video_coding/deprecated/jitter_buffer_unittest.cc @@ -70,7 +70,7 @@ class TestBasicJitterBuffer : public ::testing::Test { VCMEncodedFrame* found_frame = jitter_buffer_->NextCompleteFrame(10); if (!found_frame) return nullptr; - return jitter_buffer_->ExtractAndSetDecode(found_frame->Timestamp()); + return jitter_buffer_->ExtractAndSetDecode(found_frame->RtpTimestamp()); } void CheckOutFrame(VCMEncodedFrame* frame_out, @@ -203,7 +203,7 @@ class TestRunningJitterBuffer : public ::testing::Test { return false; VCMEncodedFrame* frame = - jitter_buffer_->ExtractAndSetDecode(found_frame->Timestamp()); + jitter_buffer_->ExtractAndSetDecode(found_frame->RtpTimestamp()); bool ret = (frame != NULL); jitter_buffer_->ReleaseFrame(frame); return ret; @@ -691,12 +691,12 @@ TEST_F(TestBasicJitterBuffer, TestSkipForwardVp9) { EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(1000U, frame_out->Timestamp()); + EXPECT_EQ(1000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); frame_out = DecodeCompleteFrame(); - EXPECT_EQ(13000U, frame_out->Timestamp()); + EXPECT_EQ(13000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); } @@ -755,7 +755,7 @@ TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_3TlLayers) { EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(3000U, frame_out->Timestamp()); + EXPECT_EQ(3000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); EXPECT_EQ(0, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); EXPECT_FALSE( @@ -763,14 +763,14 @@ TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_3TlLayers) { jitter_buffer_->ReleaseFrame(frame_out); frame_out = DecodeCompleteFrame(); - EXPECT_EQ(6000U, frame_out->Timestamp()); + EXPECT_EQ(6000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out->FrameType()); EXPECT_EQ(2, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); jitter_buffer_->ReleaseFrame(frame_out); frame_out = DecodeCompleteFrame(); - EXPECT_EQ(9000U, frame_out->Timestamp()); + EXPECT_EQ(9000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out->FrameType()); EXPECT_EQ(1, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); @@ -848,7 +848,7 @@ TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_2Tl2SLayers) { EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(3000U, frame_out->Timestamp()); + EXPECT_EQ(3000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); EXPECT_EQ(0, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); EXPECT_FALSE( @@ -856,7 +856,7 @@ TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_2Tl2SLayers) { jitter_buffer_->ReleaseFrame(frame_out); frame_out = DecodeCompleteFrame(); - EXPECT_EQ(6000U, frame_out->Timestamp()); + EXPECT_EQ(6000U, frame_out->RtpTimestamp()); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out->FrameType()); EXPECT_EQ(1, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); @@ -1089,7 +1089,7 @@ TEST_F(TestBasicJitterBuffer, TestInsertOldFrame) { jitter_buffer_->InsertPacket(*packet_, &retransmitted)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(3000u, frame_out->Timestamp()); + EXPECT_EQ(3000u, frame_out->RtpTimestamp()); CheckOutFrame(frame_out, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); @@ -1124,7 +1124,7 @@ TEST_F(TestBasicJitterBuffer, TestInsertOldFrameWithSeqNumWrap) { jitter_buffer_->InsertPacket(*packet_, &retransmitted)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(timestamp_, frame_out->Timestamp()); + EXPECT_EQ(timestamp_, frame_out->RtpTimestamp()); CheckOutFrame(frame_out, size_, false); @@ -1234,13 +1234,13 @@ TEST_F(TestBasicJitterBuffer, 2FrameWithTimestampWrap) { jitter_buffer_->InsertPacket(*packet_, &retransmitted)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(0xffffff00, frame_out->Timestamp()); + EXPECT_EQ(0xffffff00, frame_out->RtpTimestamp()); CheckOutFrame(frame_out, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); - EXPECT_EQ(2700u, frame_out2->Timestamp()); + EXPECT_EQ(2700u, frame_out2->RtpTimestamp()); CheckOutFrame(frame_out2, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out2->FrameType()); jitter_buffer_->ReleaseFrame(frame_out2); @@ -1277,13 +1277,13 @@ TEST_F(TestBasicJitterBuffer, Insert2FramesReOrderedWithTimestampWrap) { jitter_buffer_->InsertPacket(*packet_, &retransmitted)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(0xffffff00, frame_out->Timestamp()); + EXPECT_EQ(0xffffff00, frame_out->RtpTimestamp()); CheckOutFrame(frame_out, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); - EXPECT_EQ(2700u, frame_out2->Timestamp()); + EXPECT_EQ(2700u, frame_out2->RtpTimestamp()); CheckOutFrame(frame_out2, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameDelta, frame_out2->FrameType()); jitter_buffer_->ReleaseFrame(frame_out2); @@ -1377,7 +1377,7 @@ TEST_F(TestBasicJitterBuffer, ExceedNumOfFrameWithSeqNumWrap) { jitter_buffer_->InsertPacket(*packet_, &retransmitted)); VCMEncodedFrame* frame_out = DecodeCompleteFrame(); - EXPECT_EQ(first_key_frame_timestamp, frame_out->Timestamp()); + EXPECT_EQ(first_key_frame_timestamp, frame_out->RtpTimestamp()); CheckOutFrame(frame_out, size_, false); EXPECT_EQ(VideoFrameType::kVideoFrameKey, frame_out->FrameType()); jitter_buffer_->ReleaseFrame(frame_out); diff --git a/modules/video_coding/deprecated/receiver.cc b/modules/video_coding/deprecated/receiver.cc index 44a041d0d1..b76084779d 100644 --- a/modules/video_coding/deprecated/receiver.cc +++ b/modules/video_coding/deprecated/receiver.cc @@ -88,7 +88,7 @@ VCMEncodedFrame* VCMReceiver::FrameForDecoding(uint16_t max_wait_time_ms, if (found_frame == nullptr) { return nullptr; } - uint32_t frame_timestamp = found_frame->Timestamp(); + uint32_t frame_timestamp = found_frame->RtpTimestamp(); if (absl::optional playout_delay = found_frame->EncodedImage().PlayoutDelay()) { @@ -161,8 +161,8 @@ VCMEncodedFrame* VCMReceiver::FrameForDecoding(uint16_t max_wait_time_ms, return NULL; } frame->SetRenderTime(render_time_ms); - TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", frame->Timestamp(), "SetRenderTS", - "render_time", frame->RenderTimeMs()); + TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", frame->RtpTimestamp(), + "SetRenderTS", "render_time", frame->RenderTimeMs()); return frame; } diff --git a/modules/video_coding/encoded_frame.cc b/modules/video_coding/encoded_frame.cc index 637a20cfc9..dbac39c667 100644 --- a/modules/video_coding/encoded_frame.cc +++ b/modules/video_coding/encoded_frame.cc @@ -36,7 +36,7 @@ VCMEncodedFrame::~VCMEncodedFrame() { } void VCMEncodedFrame::Reset() { - SetTimestamp(0); + SetRtpTimestamp(0); SetSpatialIndex(absl::nullopt); _renderTimeMs = -1; _payloadType = 0; @@ -140,6 +140,10 @@ void VCMEncodedFrame::CopyCodecSpecific(const RTPVideoHeader* header) { _codecSpecificInfo.codecType = kVideoCodecAV1; break; } + case kVideoCodecH265: { + _codecSpecificInfo.codecType = kVideoCodecH265; + break; + } default: { _codecSpecificInfo.codecType = kVideoCodecGeneric; break; diff --git a/modules/video_coding/encoded_frame.h b/modules/video_coding/encoded_frame.h index b8c9d14653..88e5490562 100644 --- a/modules/video_coding/encoded_frame.h +++ b/modules/video_coding/encoded_frame.h @@ -46,17 +46,17 @@ class RTC_EXPORT VCMEncodedFrame : public EncodedImage { using EncodedImage::GetEncodedData; using EncodedImage::NtpTimeMs; using EncodedImage::PacketInfos; + using EncodedImage::RtpTimestamp; using EncodedImage::set_size; using EncodedImage::SetColorSpace; using EncodedImage::SetEncodedData; using EncodedImage::SetPacketInfos; + using EncodedImage::SetRtpTimestamp; using EncodedImage::SetSpatialIndex; using EncodedImage::SetSpatialLayerFrameSize; - using EncodedImage::SetTimestamp; using EncodedImage::size; using EncodedImage::SpatialIndex; using EncodedImage::SpatialLayerFrameSize; - using EncodedImage::Timestamp; /** * Get render time in milliseconds diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc index 09e1c41904..5f3b359c48 100644 --- a/modules/video_coding/generic_decoder.cc +++ b/modules/video_coding/generic_decoder.cc @@ -293,9 +293,9 @@ int32_t VCMGenericDecoder::Decode(const EncodedImage& frame, Timestamp now, int64_t render_time_ms) { TRACE_EVENT1("webrtc", "VCMGenericDecoder::Decode", "timestamp", - frame.Timestamp()); + frame.RtpTimestamp()); FrameInfo frame_info; - frame_info.rtp_timestamp = frame.Timestamp(); + frame_info.rtp_timestamp = frame.RtpTimestamp(); frame_info.decode_start = now; frame_info.render_time = render_time_ms >= 0 @@ -335,7 +335,7 @@ int32_t VCMGenericDecoder::Decode(const EncodedImage& frame, ? absl::make_optional(frame_info.packet_infos[0].ssrc()) : absl::nullopt; RTC_LOG(LS_INFO) << "Failed to decode frame with timestamp " - << frame.Timestamp() << ", ssrc " + << frame.RtpTimestamp() << ", ssrc " << (ssrc ? rtc::ToString(*ssrc) : "") << ", error code: " << ret; _callback->ClearTimestampMap(); diff --git a/modules/video_coding/generic_decoder_unittest.cc b/modules/video_coding/generic_decoder_unittest.cc index e8d1dad09f..d0f6d53744 100644 --- a/modules/video_coding/generic_decoder_unittest.cc +++ b/modules/video_coding/generic_decoder_unittest.cc @@ -108,7 +108,7 @@ TEST_F(GenericDecoderTest, FrameDroppedIfTooManyFramesInFlight) { decoder_.SetDelayedDecoding(10); for (int i = 0; i < kMaxFramesInFlight + 1; ++i) { EncodedFrame encoded_frame; - encoded_frame.SetTimestamp(90000 * i); + encoded_frame.SetRtpTimestamp(90000 * i); generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); } diff --git a/modules/video_coding/packet_buffer.cc b/modules/video_coding/packet_buffer.cc index 52ef5c2d85..420a200ba9 100644 --- a/modules/video_coding/packet_buffer.cc +++ b/modules/video_coding/packet_buffer.cc @@ -77,6 +77,13 @@ PacketBuffer::InsertResult PacketBuffer::InsertPacket( return result; } + if (ForwardDiff(first_seq_num_, seq_num) >= max_size_) { + // Large negative jump in rtp sequence number: clear the buffer and treat + // latest packet as the new first packet. + Clear(); + first_packet_received_ = true; + } + first_seq_num_ = seq_num; } diff --git a/modules/video_coding/packet_buffer_unittest.cc b/modules/video_coding/packet_buffer_unittest.cc index 901f44b188..607ec47dc4 100644 --- a/modules/video_coding/packet_buffer_unittest.cc +++ b/modules/video_coding/packet_buffer_unittest.cc @@ -705,6 +705,12 @@ TEST_P(PacketBufferH264ParameterizedTest, OneFrameMaxSeqNum) { StartSeqNumsAre(65534)); } +TEST_P(PacketBufferH264ParameterizedTest, InsertTooOldPackets) { + InsertH264(4660, kKeyFrame, kFirst, kNotLast, 1000); + InsertH264(37429, kDeltaFrame, kFirst, kNotLast, 1000); + InsertH264(4662, kKeyFrame, kFirst, kLast, 1000); +} + TEST_P(PacketBufferH264ParameterizedTest, ClearMissingPacketsOnKeyframe) { InsertH264(0, kKeyFrame, kFirst, kLast, 1000); InsertH264(2, kKeyFrame, kFirst, kLast, 3000); diff --git a/modules/video_coding/utility/ivf_file_reader.cc b/modules/video_coding/utility/ivf_file_reader.cc index 13092b5e24..4c08ca613a 100644 --- a/modules/video_coding/utility/ivf_file_reader.cc +++ b/modules/video_coding/utility/ivf_file_reader.cc @@ -29,6 +29,7 @@ constexpr uint8_t kVp8Header[kCodecTypeBytesCount] = {'V', 'P', '8', '0'}; constexpr uint8_t kVp9Header[kCodecTypeBytesCount] = {'V', 'P', '9', '0'}; constexpr uint8_t kAv1Header[kCodecTypeBytesCount] = {'A', 'V', '0', '1'}; constexpr uint8_t kH264Header[kCodecTypeBytesCount] = {'H', '2', '6', '4'}; +constexpr uint8_t kH265Header[kCodecTypeBytesCount] = {'H', '2', '6', '5'}; // RTP standard required 90kHz clock rate. constexpr int32_t kRtpClockRateHz = 90000; @@ -156,7 +157,7 @@ absl::optional IvfFileReader::NextFrame() { EncodedImage image; image.capture_time_ms_ = current_timestamp; - image.SetTimestamp( + image.SetRtpTimestamp( static_cast(current_timestamp * kRtpClockRateHz / time_scale_)); image.SetEncodedData(payload); image.SetSpatialIndex(static_cast(layer_sizes.size()) - 1); @@ -192,6 +193,9 @@ absl::optional IvfFileReader::ParseCodecType(uint8_t* buffer, if (memcmp(&buffer[start_pos], kH264Header, kCodecTypeBytesCount) == 0) { return VideoCodecType::kVideoCodecH264; } + if (memcmp(&buffer[start_pos], kH265Header, kCodecTypeBytesCount) == 0) { + return VideoCodecType::kVideoCodecH265; + } has_error_ = true; RTC_LOG(LS_ERROR) << "Unknown codec type: " << std::string( diff --git a/modules/video_coding/utility/ivf_file_reader_unittest.cc b/modules/video_coding/utility/ivf_file_reader_unittest.cc index 0e20b7f77c..14bfdcae14 100644 --- a/modules/video_coding/utility/ivf_file_reader_unittest.cc +++ b/modules/video_coding/utility/ivf_file_reader_unittest.cc @@ -58,7 +58,7 @@ class IvfFileReaderTest : public ::testing::Test { if (use_capture_tims_ms) { frame.capture_time_ms_ = i; } else { - frame.SetTimestamp(i); + frame.SetRtpTimestamp(i); } if (!file_writer->WriteFrame(frame, codec_type)) return false; @@ -86,9 +86,9 @@ class IvfFileReaderTest : public ::testing::Test { EXPECT_EQ(frame->SpatialIndex(), spatial_layers_count - 1); if (use_capture_tims_ms) { EXPECT_EQ(frame->capture_time_ms_, static_cast(frame_index)); - EXPECT_EQ(frame->Timestamp(), static_cast(90 * frame_index)); + EXPECT_EQ(frame->RtpTimestamp(), static_cast(90 * frame_index)); } else { - EXPECT_EQ(frame->Timestamp(), static_cast(frame_index)); + EXPECT_EQ(frame->RtpTimestamp(), static_cast(frame_index)); } ASSERT_EQ(frame->size(), sizeof(kDummyPayload) * spatial_layers_count); for (int i = 0; i < spatial_layers_count; ++i) { diff --git a/modules/video_coding/utility/ivf_file_writer.cc b/modules/video_coding/utility/ivf_file_writer.cc index 01025986d6..422e4585a8 100644 --- a/modules/video_coding/utility/ivf_file_writer.cc +++ b/modules/video_coding/utility/ivf_file_writer.cc @@ -10,13 +10,20 @@ #include "modules/video_coding/utility/ivf_file_writer.h" +#include +#include +#include #include +#include "absl/strings/string_view.h" +#include "api/video/encoded_image.h" +#include "api/video/video_codec_type.h" #include "api/video_codecs/video_codec.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/video_coding/utility/ivf_defines.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/system/file_wrapper.h" // TODO(palmkvist): make logging more informative in the absence of a file name // (or get one) @@ -53,6 +60,12 @@ std::unique_ptr IvfFileWriter::Wrap(FileWrapper file, new IvfFileWriter(std::move(file), byte_limit)); } +std::unique_ptr IvfFileWriter::Wrap(absl::string_view filename, + size_t byte_limit) { + return std::unique_ptr( + new IvfFileWriter(FileWrapper::OpenWriteOnly(filename), byte_limit)); +} + bool IvfFileWriter::WriteHeader() { if (!file_.Rewind()) { RTC_LOG(LS_WARNING) << "Unable to rewind ivf output file."; @@ -92,6 +105,12 @@ bool IvfFileWriter::WriteHeader() { ivf_header[10] = '6'; ivf_header[11] = '4'; break; + case kVideoCodecH265: + ivf_header[8] = 'H'; + ivf_header[9] = '2'; + ivf_header[10] = '6'; + ivf_header[11] = '5'; + break; default: // For unknown codec type use **** code. You can specify actual payload // format when playing the video with ffplay: ffplay -f H263 file.ivf @@ -135,7 +154,7 @@ bool IvfFileWriter::InitFromFirstFrame(const EncodedImage& encoded_image, height_ = encoded_image._encodedHeight; } - using_capture_timestamps_ = encoded_image.Timestamp() == 0; + using_capture_timestamps_ = encoded_image.RtpTimestamp() == 0; codec_type_ = codec_type; @@ -162,7 +181,7 @@ bool IvfFileWriter::WriteFrame(const EncodedImage& encoded_image, int64_t timestamp = using_capture_timestamps_ ? encoded_image.capture_time_ms_ - : wrap_handler_.Unwrap(encoded_image.Timestamp()); + : wrap_handler_.Unwrap(encoded_image.RtpTimestamp()); if (last_timestamp_ != -1 && timestamp < last_timestamp_) { RTC_LOG(LS_WARNING) << "Timestamp not increasing: " << last_timestamp_ << " -> " << timestamp; diff --git a/modules/video_coding/utility/ivf_file_writer.h b/modules/video_coding/utility/ivf_file_writer.h index ec8a7bf9e1..c1c088690b 100644 --- a/modules/video_coding/utility/ivf_file_writer.h +++ b/modules/video_coding/utility/ivf_file_writer.h @@ -16,6 +16,7 @@ #include +#include "absl/strings/string_view.h" #include "api/video/encoded_image.h" #include "api/video/video_codec_type.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" @@ -31,6 +32,8 @@ class IvfFileWriter { // will fail. A `byte_limit` of 0 is equivalent to no limit. static std::unique_ptr Wrap(FileWrapper file, size_t byte_limit); + static std::unique_ptr Wrap(absl::string_view filename, + size_t byte_limit); ~IvfFileWriter(); IvfFileWriter(const IvfFileWriter&) = delete; diff --git a/modules/video_coding/utility/ivf_file_writer_unittest.cc b/modules/video_coding/utility/ivf_file_writer_unittest.cc index c5d30a1286..bc6ab65b34 100644 --- a/modules/video_coding/utility/ivf_file_writer_unittest.cc +++ b/modules/video_coding/utility/ivf_file_writer_unittest.cc @@ -54,7 +54,7 @@ class IvfFileWriterTest : public ::testing::Test { if (use_capture_tims_ms) { frame.capture_time_ms_ = i; } else { - frame.SetTimestamp(i); + frame.SetRtpTimestamp(i); } if (!file_writer_->WriteFrame(frame, codec_type)) return false; diff --git a/modules/video_coding/utility/qp_parser.cc b/modules/video_coding/utility/qp_parser.cc index 18f225447d..3b9aaa377e 100644 --- a/modules/video_coding/utility/qp_parser.cc +++ b/modules/video_coding/utility/qp_parser.cc @@ -36,6 +36,8 @@ absl::optional QpParser::Parse(VideoCodecType codec_type, } } else if (codec_type == kVideoCodecH264) { return h264_parsers_[spatial_idx].Parse(frame_data, frame_size); + } else if (codec_type == kVideoCodecH265) { + // TODO(bugs.webrtc.org/13485) } return absl::nullopt; diff --git a/modules/video_coding/utility/quality_scaler.cc b/modules/video_coding/utility/quality_scaler.cc index 9fb41a0ad7..7ecb340ea4 100644 --- a/modules/video_coding/utility/quality_scaler.cc +++ b/modules/video_coding/utility/quality_scaler.cc @@ -13,6 +13,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "api/video/video_adaptation_reason.h" #include "rtc_base/checks.h" @@ -175,37 +176,38 @@ class QualityScaler::CheckQpTask { }; QualityScaler::QualityScaler(QualityScalerQpUsageHandlerInterface* handler, - VideoEncoder::QpThresholds thresholds) - : QualityScaler(handler, thresholds, kMeasureMs) {} + VideoEncoder::QpThresholds thresholds, + const FieldTrialsView& field_trials) + : QualityScaler(handler, thresholds, field_trials, kMeasureMs) {} // Protected ctor, should not be called directly. QualityScaler::QualityScaler(QualityScalerQpUsageHandlerInterface* handler, VideoEncoder::QpThresholds thresholds, + const FieldTrialsView& field_trials, int64_t default_sampling_period_ms) : handler_(handler), thresholds_(thresholds), - sampling_period_ms_(QualityScalerSettings::ParseFromFieldTrials() + sampling_period_ms_(QualityScalerSettings(field_trials) .SamplingPeriodMs() .value_or(default_sampling_period_ms)), fast_rampup_(true), // Arbitrarily choose size based on 30 fps for 5 seconds. - average_qp_(QualityScalerSettings::ParseFromFieldTrials() + average_qp_(QualityScalerSettings(field_trials) .AverageQpWindow() .value_or(5 * 30)), framedrop_percent_media_opt_(5 * 30), framedrop_percent_all_(5 * 30), - experiment_enabled_(QualityScalingExperiment::Enabled()), - min_frames_needed_( - QualityScalerSettings::ParseFromFieldTrials().MinFrames().value_or( - kMinFramesNeededToScale)), - initial_scale_factor_(QualityScalerSettings::ParseFromFieldTrials() + experiment_enabled_(QualityScalingExperiment::Enabled(field_trials)), + min_frames_needed_(QualityScalerSettings(field_trials) + .MinFrames() + .value_or(kMinFramesNeededToScale)), + initial_scale_factor_(QualityScalerSettings(field_trials) .InitialScaleFactor() .value_or(kSamplePeriodScaleFactor)), - scale_factor_( - QualityScalerSettings::ParseFromFieldTrials().ScaleFactor()) { + scale_factor_(QualityScalerSettings(field_trials).ScaleFactor()) { RTC_DCHECK_RUN_ON(&task_checker_); if (experiment_enabled_) { - config_ = QualityScalingExperiment::GetConfig(); + config_ = QualityScalingExperiment::GetConfig(field_trials); qp_smoother_high_.reset(new QpSmoother(config_.alpha_high)); qp_smoother_low_.reset(new QpSmoother(config_.alpha_low)); } diff --git a/modules/video_coding/utility/quality_scaler.h b/modules/video_coding/utility/quality_scaler.h index 93014e36a7..14623ff1f3 100644 --- a/modules/video_coding/utility/quality_scaler.h +++ b/modules/video_coding/utility/quality_scaler.h @@ -17,6 +17,7 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/video_codecs/video_encoder.h" @@ -40,7 +41,8 @@ class QualityScaler { // This starts the quality scaler periodically checking what the average QP // has been recently. QualityScaler(QualityScalerQpUsageHandlerInterface* handler, - VideoEncoder::QpThresholds thresholds); + VideoEncoder::QpThresholds thresholds, + const FieldTrialsView& field_trials); virtual ~QualityScaler(); // Should be called each time a frame is dropped at encoding. void ReportDroppedFrameByMediaOpt(); @@ -55,6 +57,7 @@ class QualityScaler { protected: QualityScaler(QualityScalerQpUsageHandlerInterface* handler, VideoEncoder::QpThresholds thresholds, + const FieldTrialsView& field_trials, int64_t sampling_period_ms); private: diff --git a/modules/video_coding/utility/quality_scaler_unittest.cc b/modules/video_coding/utility/quality_scaler_unittest.cc index 50410dd25b..1142947d54 100644 --- a/modules/video_coding/utility/quality_scaler_unittest.cc +++ b/modules/video_coding/utility/quality_scaler_unittest.cc @@ -13,12 +13,13 @@ #include #include +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "rtc_base/checks.h" #include "rtc_base/event.h" #include "rtc_base/task_queue_for_test.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace { @@ -53,8 +54,9 @@ class FakeQpUsageHandler : public QualityScalerQpUsageHandlerInterface { class QualityScalerUnderTest : public QualityScaler { public: explicit QualityScalerUnderTest(QualityScalerQpUsageHandlerInterface* handler, - VideoEncoder::QpThresholds thresholds) - : QualityScaler(handler, thresholds, 5) {} + VideoEncoder::QpThresholds thresholds, + const FieldTrialsView& field_trials) + : QualityScaler(handler, thresholds, field_trials, 5) {} }; class QualityScalerTest : public ::testing::Test, @@ -74,7 +76,8 @@ class QualityScalerTest : public ::testing::Test, handler_(std::make_unique()) { task_queue_.SendTask([this] { qs_ = std::unique_ptr(new QualityScalerUnderTest( - handler_.get(), VideoEncoder::QpThresholds(kLowQp, kHighQp))); + handler_.get(), VideoEncoder::QpThresholds(kLowQp, kHighQp), + scoped_field_trial_)); }); } @@ -104,7 +107,7 @@ class QualityScalerTest : public ::testing::Test, } } - test::ScopedFieldTrials scoped_field_trial_; + test::ScopedKeyValueConfig scoped_field_trial_; TaskQueueForTest task_queue_; std::unique_ptr qs_; std::unique_ptr handler_; diff --git a/modules/video_coding/utility/simulcast_test_fixture_impl.cc b/modules/video_coding/utility/simulcast_test_fixture_impl.cc index 338835ebb9..c6e51e8068 100644 --- a/modules/video_coding/utility/simulcast_test_fixture_impl.cc +++ b/modules/video_coding/utility/simulcast_test_fixture_impl.cc @@ -101,7 +101,7 @@ class SimulcastTestFixtureImpl::TestEncodedImageCallback temporal_layer_[encoded_image.SimulcastIndex().value_or(0)] = codec_specific_info->codecSpecific.H264.temporal_idx; } - return Result(Result::OK, encoded_image.Timestamp()); + return Result(Result::OK, encoded_image.RtpTimestamp()); } // This method only makes sense for VP8. void GetLastEncodedFrameInfo(int* temporal_layer, diff --git a/modules/video_coding/utility/simulcast_utility.cc b/modules/video_coding/utility/simulcast_utility.cc index 95e9488b01..824f4b0eac 100644 --- a/modules/video_coding/utility/simulcast_utility.cc +++ b/modules/video_coding/utility/simulcast_utility.cc @@ -94,6 +94,9 @@ int SimulcastUtility::NumberOfTemporalLayers(const VideoCodec& codec, case kVideoCodecH264: num_temporal_layers = codec.H264().numberOfTemporalLayers; break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc index 43fab8c432..6098f59fe9 100644 --- a/modules/video_coding/video_codec_initializer.cc +++ b/modules/video_coding/video_codec_initializer.cc @@ -236,18 +236,9 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( if (!config.spatial_layers.empty()) { // Layering is set explicitly. spatial_layers = config.spatial_layers; - } else if (scalability_mode.has_value()) { + } else if (video_codec.GetScalabilityMode().has_value()) { // Layering is set via scalability mode. spatial_layers = GetVp9SvcConfig(video_codec); - if (spatial_layers.empty()) - break; - // Use codec bitrate limits if spatial layering is not requested. - if (video_codec.numberOfSimulcastStreams <= 1 && - ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1) { - spatial_layers.back().minBitrate = video_codec.minBitrate; - spatial_layers.back().targetBitrate = video_codec.maxBitrate; - spatial_layers.back().maxBitrate = video_codec.maxBitrate; - } } else { size_t first_active_layer = 0; for (size_t spatial_idx = 0; @@ -344,6 +335,9 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( kMaxTemporalStreams); break; } + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: // TODO(pbos): Support encoder_settings codec-agnostically. RTC_DCHECK(!config.encoder_specific_settings) diff --git a/net/dcsctp/common/internal_types.h b/net/dcsctp/common/internal_types.h index 2354b92cc4..4f3b1935a2 100644 --- a/net/dcsctp/common/internal_types.h +++ b/net/dcsctp/common/internal_types.h @@ -40,5 +40,10 @@ using VerificationTag = webrtc::StrongAlias; // Tie Tag, used as a nonce when connecting. using TieTag = webrtc::StrongAlias; +// An ID for every outgoing message, to correlate outgoing data chunks with the +// message it was carved from. +using OutgoingMessageId = + webrtc::StrongAlias; + } // namespace dcsctp #endif // NET_DCSCTP_COMMON_INTERNAL_TYPES_H_ diff --git a/net/dcsctp/packet/chunk/data_common.h b/net/dcsctp/packet/chunk/data_common.h index b67efeee1e..66d67bac3d 100644 --- a/net/dcsctp/packet/chunk/data_common.h +++ b/net/dcsctp/packet/chunk/data_common.h @@ -48,7 +48,7 @@ class AnyDataChunk : public Chunk { StreamID stream_id() const { return data_.stream_id; } SSN ssn() const { return data_.ssn; } - MID message_id() const { return data_.message_id; } + MID mid() const { return data_.mid; } FSN fsn() const { return data_.fsn; } PPID ppid() const { return data_.ppid; } rtc::ArrayView payload() const { return data_.payload; } @@ -59,7 +59,7 @@ class AnyDataChunk : public Chunk { AnyDataChunk(TSN tsn, StreamID stream_id, SSN ssn, - MID message_id, + MID mid, FSN fsn, PPID ppid, std::vector payload, @@ -67,7 +67,7 @@ class AnyDataChunk : public Chunk { : tsn_(tsn), data_(stream_id, ssn, - message_id, + mid, fsn, ppid, std::move(payload), diff --git a/net/dcsctp/packet/chunk/forward_tsn_common.h b/net/dcsctp/packet/chunk/forward_tsn_common.h index 37bd2aafff..b9dddd2cbf 100644 --- a/net/dcsctp/packet/chunk/forward_tsn_common.h +++ b/net/dcsctp/packet/chunk/forward_tsn_common.h @@ -24,12 +24,9 @@ class AnyForwardTsnChunk : public Chunk { public: struct SkippedStream { SkippedStream(StreamID stream_id, SSN ssn) - : stream_id(stream_id), ssn(ssn), unordered(false), message_id(0) {} - SkippedStream(IsUnordered unordered, StreamID stream_id, MID message_id) - : stream_id(stream_id), - ssn(0), - unordered(unordered), - message_id(message_id) {} + : stream_id(stream_id), ssn(ssn), unordered(false), mid(0) {} + SkippedStream(IsUnordered unordered, StreamID stream_id, MID mid) + : stream_id(stream_id), ssn(0), unordered(unordered), mid(mid) {} StreamID stream_id; @@ -38,11 +35,11 @@ class AnyForwardTsnChunk : public Chunk { // Set for I-FORWARD_TSN IsUnordered unordered; - MID message_id; + MID mid; bool operator==(const SkippedStream& other) const { return stream_id == other.stream_id && ssn == other.ssn && - unordered == other.unordered && message_id == other.message_id; + unordered == other.unordered && mid == other.mid; } }; diff --git a/net/dcsctp/packet/chunk/idata_chunk.cc b/net/dcsctp/packet/chunk/idata_chunk.cc index 9f19c7f053..e9a777dfdc 100644 --- a/net/dcsctp/packet/chunk/idata_chunk.cc +++ b/net/dcsctp/packet/chunk/idata_chunk.cc @@ -54,7 +54,7 @@ absl::optional IDataChunk::Parse( uint8_t flags = reader->Load8<1>(); TSN tsn(reader->Load32<4>()); StreamID stream_identifier(reader->Load16<8>()); - MID message_id(reader->Load32<12>()); + MID mid(reader->Load32<12>()); uint32_t ppid_or_fsn = reader->Load32<16>(); Options options; @@ -65,7 +65,7 @@ absl::optional IDataChunk::Parse( options.immediate_ack = ImmediateAckFlag((flags & (1 << kFlagsBitImmediateAck)) != 0); - return IDataChunk(tsn, stream_identifier, message_id, + return IDataChunk(tsn, stream_identifier, mid, PPID(options.is_beginning ? ppid_or_fsn : 0), FSN(options.is_beginning ? 0 : ppid_or_fsn), std::vector(reader->variable_data().begin(), @@ -83,7 +83,7 @@ void IDataChunk::SerializeTo(std::vector& out) const { (*options().immediate_ack ? (1 << kFlagsBitImmediateAck) : 0)); writer.Store32<4>(*tsn()); writer.Store16<8>(*stream_id()); - writer.Store32<12>(*message_id()); + writer.Store32<12>(*mid()); writer.Store32<16>(options().is_beginning ? *ppid() : *fsn()); writer.CopyToVariableData(payload()); } @@ -97,7 +97,7 @@ std::string IDataChunk::ToString() const { : *options().is_end ? "last" : "middle") << ", tsn=" << *tsn() << ", stream_id=" << *stream_id() - << ", message_id=" << *message_id(); + << ", mid=" << *mid(); if (*options().is_beginning) { sb << ", ppid=" << *ppid(); diff --git a/net/dcsctp/packet/chunk/idata_chunk.h b/net/dcsctp/packet/chunk/idata_chunk.h index 8cdf2a1fc4..36b7e7eaab 100644 --- a/net/dcsctp/packet/chunk/idata_chunk.h +++ b/net/dcsctp/packet/chunk/idata_chunk.h @@ -42,7 +42,7 @@ class IDataChunk : public AnyDataChunk, public TLVTrait { static constexpr size_t kHeaderSize = IDataChunkConfig::kHeaderSize; IDataChunk(TSN tsn, StreamID stream_id, - MID message_id, + MID mid, PPID ppid, FSN fsn, std::vector payload, @@ -50,7 +50,7 @@ class IDataChunk : public AnyDataChunk, public TLVTrait { : AnyDataChunk(tsn, stream_id, SSN(0), - message_id, + mid, fsn, ppid, std::move(payload), diff --git a/net/dcsctp/packet/chunk/idata_chunk_test.cc b/net/dcsctp/packet/chunk/idata_chunk_test.cc index fea492d71e..d1cc0d8f90 100644 --- a/net/dcsctp/packet/chunk/idata_chunk_test.cc +++ b/net/dcsctp/packet/chunk/idata_chunk_test.cc @@ -44,7 +44,7 @@ TEST(IDataChunkTest, AtBeginningFromCapture) { ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk chunk, IDataChunk::Parse(data)); EXPECT_EQ(*chunk.tsn(), 2487901653); EXPECT_EQ(*chunk.stream_id(), 1); - EXPECT_EQ(*chunk.message_id(), 0u); + EXPECT_EQ(*chunk.mid(), 0u); EXPECT_EQ(*chunk.ppid(), 53u); EXPECT_EQ(*chunk.fsn(), 0u); // Not provided (so set to zero) } @@ -62,13 +62,13 @@ TEST(IDataChunkTest, AtBeginningSerializeAndDeserialize) { IDataChunk::Parse(serialized)); EXPECT_EQ(*deserialized.tsn(), 123u); EXPECT_EQ(*deserialized.stream_id(), 456u); - EXPECT_EQ(*deserialized.message_id(), 789u); + EXPECT_EQ(*deserialized.mid(), 789u); EXPECT_EQ(*deserialized.ppid(), 53u); EXPECT_EQ(*deserialized.fsn(), 0u); EXPECT_EQ(deserialized.ToString(), "I-DATA, type=ordered::first, tsn=123, stream_id=456, " - "message_id=789, ppid=53, length=1"); + "mid=789, ppid=53, length=1"); } TEST(IDataChunkTest, InMiddleFromCapture) { @@ -93,7 +93,7 @@ TEST(IDataChunkTest, InMiddleFromCapture) { ASSERT_HAS_VALUE_AND_ASSIGN(IDataChunk chunk, IDataChunk::Parse(data)); EXPECT_EQ(*chunk.tsn(), 2487901706); EXPECT_EQ(*chunk.stream_id(), 3u); - EXPECT_EQ(*chunk.message_id(), 1u); + EXPECT_EQ(*chunk.mid(), 1u); EXPECT_EQ(*chunk.ppid(), 0u); // Not provided (so set to zero) EXPECT_EQ(*chunk.fsn(), 8u); } @@ -109,14 +109,14 @@ TEST(IDataChunkTest, InMiddleSerializeAndDeserialize) { IDataChunk::Parse(serialized)); EXPECT_EQ(*deserialized.tsn(), 123u); EXPECT_EQ(*deserialized.stream_id(), 456u); - EXPECT_EQ(*deserialized.message_id(), 789u); + EXPECT_EQ(*deserialized.mid(), 789u); EXPECT_EQ(*deserialized.ppid(), 0u); EXPECT_EQ(*deserialized.fsn(), 101112u); EXPECT_THAT(deserialized.payload(), ElementsAre(1, 2, 3)); EXPECT_EQ(deserialized.ToString(), "I-DATA, type=ordered::middle, tsn=123, stream_id=456, " - "message_id=789, fsn=101112, length=3"); + "mid=789, fsn=101112, length=3"); } } // namespace diff --git a/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc b/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc index a647a8bf8a..2b8e9c917a 100644 --- a/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc +++ b/net/dcsctp/packet/chunk/iforward_tsn_chunk.cc @@ -68,8 +68,8 @@ absl::optional IForwardTsnChunk::Parse( StreamID stream_id(sub_reader.Load16<0>()); IsUnordered unordered(sub_reader.Load8<3>() & 0x01); - MID message_id(sub_reader.Load32<4>()); - skipped_streams.emplace_back(unordered, stream_id, message_id); + MID mid(sub_reader.Load32<4>()); + skipped_streams.emplace_back(unordered, stream_id, mid); offset += kSkippedStreamBufferSize; } RTC_DCHECK(offset == reader->variable_data_size()); @@ -89,7 +89,7 @@ void IForwardTsnChunk::SerializeTo(std::vector& out) const { sub_writer.Store16<0>(*skipped[i].stream_id); sub_writer.Store8<3>(skipped[i].unordered ? 1 : 0); - sub_writer.Store32<4>(*skipped[i].message_id); + sub_writer.Store32<4>(*skipped[i].mid); offset += kSkippedStreamBufferSize; } RTC_DCHECK(offset == variable_size); diff --git a/net/dcsctp/packet/data.h b/net/dcsctp/packet/data.h index c1754ed59a..08174dc052 100644 --- a/net/dcsctp/packet/data.h +++ b/net/dcsctp/packet/data.h @@ -42,7 +42,7 @@ struct Data { Data(StreamID stream_id, SSN ssn, - MID message_id, + MID mid, FSN fsn, PPID ppid, std::vector payload, @@ -51,7 +51,7 @@ struct Data { IsUnordered is_unordered) : stream_id(stream_id), ssn(ssn), - message_id(message_id), + mid(mid), fsn(fsn), ppid(ppid), payload(std::move(payload)), @@ -65,8 +65,8 @@ struct Data { // Creates a copy of this `Data` object. Data Clone() const { - return Data(stream_id, ssn, message_id, fsn, ppid, payload, is_beginning, - is_end, is_unordered); + return Data(stream_id, ssn, mid, fsn, ppid, payload, is_beginning, is_end, + is_unordered); } // The size of this data, which translates to the size of its payload. @@ -82,7 +82,7 @@ struct Data { // Message Identifier (MID) per stream and ordered/unordered. Defined by // RFC8260, and used together with options.is_unordered and stream_id to // uniquely identify a message. Used only in I-DATA chunks (not DATA). - MID message_id; + MID mid; // Fragment Sequence Number (FSN) per stream and ordered/unordered, as above. FSN fsn; diff --git a/net/dcsctp/public/dcsctp_socket.h b/net/dcsctp/public/dcsctp_socket.h index 9fda56a3ad..3cfb8052f8 100644 --- a/net/dcsctp/public/dcsctp_socket.h +++ b/net/dcsctp/public/dcsctp_socket.h @@ -255,6 +255,10 @@ struct Metrics { // peers. bool uses_message_interleaving = false; + // Indicates if draft-tuexen-tsvwg-sctp-zero-checksum-00 has been negotiated + // by both peers. + bool uses_zero_checksum = false; + // The number of negotiated incoming and outgoing streams, which is configured // locally as `DcSctpOptions::announced_maximum_incoming_streams` and // `DcSctpOptions::announced_maximum_outgoing_streams`, and which will be diff --git a/net/dcsctp/public/types.h b/net/dcsctp/public/types.h index d0725620d8..7d69875d1a 100644 --- a/net/dcsctp/public/types.h +++ b/net/dcsctp/public/types.h @@ -41,6 +41,9 @@ class DurationMs : public webrtc::StrongAlias { constexpr explicit DurationMs(const UnderlyingType& v) : webrtc::StrongAlias(v) {} + static constexpr DurationMs InfiniteDuration() { + return DurationMs(std::numeric_limits::max()); + } // Convenience methods for working with time. constexpr DurationMs& operator+=(DurationMs d) { value_ += d.value_; diff --git a/net/dcsctp/rx/BUILD.gn b/net/dcsctp/rx/BUILD.gn index d66fd6ba72..f5f5b7ed81 100644 --- a/net/dcsctp/rx/BUILD.gn +++ b/net/dcsctp/rx/BUILD.gn @@ -95,6 +95,7 @@ rtc_library("reassembly_queue") { "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:logging", + "../../../rtc_base/containers:flat_set", "../common:internal_types", "../common:sequence_numbers", "../common:str_join", @@ -109,6 +110,7 @@ rtc_library("reassembly_queue") { "reassembly_queue.h", ] absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] diff --git a/net/dcsctp/rx/data_tracker.cc b/net/dcsctp/rx/data_tracker.cc index 1f2e43f7f5..70b7587c43 100644 --- a/net/dcsctp/rx/data_tracker.cc +++ b/net/dcsctp/rx/data_tracker.cc @@ -214,7 +214,7 @@ bool DataTracker::Observe(TSN tsn, return !is_duplicate; } -void DataTracker::HandleForwardTsn(TSN new_cumulative_ack) { +bool DataTracker::HandleForwardTsn(TSN new_cumulative_ack) { // ForwardTSN is sent to make the receiver (this socket) "forget" about partly // received (or not received at all) data, up until `new_cumulative_ack`. @@ -232,7 +232,7 @@ void DataTracker::HandleForwardTsn(TSN new_cumulative_ack) { // indicate the previous SACK was lost in the network." UpdateAckState(AckState::kImmediate, "FORWARD_TSN new_cumulative_tsn was behind"); - return; + return false; } // https://tools.ietf.org/html/rfc3758#section-3.6 @@ -271,6 +271,7 @@ void DataTracker::HandleForwardTsn(TSN new_cumulative_ack) { UpdateAckState(AckState::kImmediate, "received FORWARD_TSN when already delayed"); } + return true; } SackChunk DataTracker::CreateSelectiveAck(size_t a_rwnd) { diff --git a/net/dcsctp/rx/data_tracker.h b/net/dcsctp/rx/data_tracker.h index e07e1e379d..9991ee6139 100644 --- a/net/dcsctp/rx/data_tracker.h +++ b/net/dcsctp/rx/data_tracker.h @@ -74,8 +74,9 @@ class DataTracker { // Called at the end of processing an SCTP packet. void ObservePacketEnd(); - // Called for incoming FORWARD-TSN/I-FORWARD-TSN chunks - void HandleForwardTsn(TSN new_cumulative_ack); + // Called for incoming FORWARD-TSN/I-FORWARD-TSN chunks. Indicates if the + // chunk had any effect. + bool HandleForwardTsn(TSN new_cumulative_ack); // Indicates if a SACK should be sent. There may be other reasons to send a // SACK, but if this function indicates so, it should be sent as soon as @@ -92,6 +93,10 @@ class DataTracker { return TSN(last_cumulative_acked_tsn_.Wrap()); } + bool IsLaterThanCumulativeAckedTsn(TSN tsn) const { + return tsn_unwrapper_.PeekUnwrap(tsn) > last_cumulative_acked_tsn_; + } + // Returns true if the received `tsn` would increase the cumulative ack TSN. bool will_increase_cum_ack_tsn(TSN tsn) const; diff --git a/net/dcsctp/rx/data_tracker_test.cc b/net/dcsctp/rx/data_tracker_test.cc index f74dd6eb0b..07192fda54 100644 --- a/net/dcsctp/rx/data_tracker_test.cc +++ b/net/dcsctp/rx/data_tracker_test.cc @@ -735,5 +735,54 @@ TEST_F(DataTrackerTest, HandoverWhileSendingSackEveryPacketOnPacketLoss) { EXPECT_FALSE(tracker_->ShouldSendAck()); EXPECT_TRUE(timer_->is_running()); } + +TEST_F(DataTrackerTest, DoesNotAcceptDataBeforeForwardTsn) { + Observer({12, 13, 14, 15, 17}); + tracker_->ObservePacketEnd(); + + tracker_->HandleForwardTsn(TSN(13)); + + EXPECT_FALSE(tracker_->Observe(TSN(11))); +} + +TEST_F(DataTrackerTest, DoesNotAcceptDataAtForwardTsn) { + Observer({12, 13, 14, 15, 17}); + tracker_->ObservePacketEnd(); + + tracker_->HandleForwardTsn(TSN(16)); + + EXPECT_FALSE(tracker_->Observe(TSN(16))); +} + +TEST_F(DataTrackerTest, DoesNotAcceptDataBeforeCumAckTsn) { + EXPECT_EQ(kInitialTSN, TSN(11)); + EXPECT_FALSE(tracker_->Observe(TSN(10))); +} + +TEST_F(DataTrackerTest, DoesNotAcceptContiguousDuplicateData) { + EXPECT_EQ(kInitialTSN, TSN(11)); + EXPECT_TRUE(tracker_->Observe(TSN(11))); + EXPECT_FALSE(tracker_->Observe(TSN(11))); + EXPECT_TRUE(tracker_->Observe(TSN(12))); + EXPECT_FALSE(tracker_->Observe(TSN(12))); + EXPECT_FALSE(tracker_->Observe(TSN(11))); + EXPECT_FALSE(tracker_->Observe(TSN(10))); +} + +TEST_F(DataTrackerTest, DoesNotAcceptGapsWithDuplicateData) { + EXPECT_EQ(kInitialTSN, TSN(11)); + EXPECT_TRUE(tracker_->Observe(TSN(11))); + EXPECT_FALSE(tracker_->Observe(TSN(11))); + + EXPECT_TRUE(tracker_->Observe(TSN(14))); + EXPECT_FALSE(tracker_->Observe(TSN(14))); + + EXPECT_TRUE(tracker_->Observe(TSN(13))); + EXPECT_FALSE(tracker_->Observe(TSN(13))); + + EXPECT_TRUE(tracker_->Observe(TSN(12))); + EXPECT_FALSE(tracker_->Observe(TSN(12))); +} + } // namespace } // namespace dcsctp diff --git a/net/dcsctp/rx/interleaved_reassembly_streams.cc b/net/dcsctp/rx/interleaved_reassembly_streams.cc index 8b316de676..9dc2e43a23 100644 --- a/net/dcsctp/rx/interleaved_reassembly_streams.cc +++ b/net/dcsctp/rx/interleaved_reassembly_streams.cc @@ -106,8 +106,8 @@ size_t InterleavedReassemblyStreams::Stream::AssembleMessage( return payload_size; } -size_t InterleavedReassemblyStreams::Stream::EraseTo(MID message_id) { - UnwrappedMID unwrapped_mid = mid_unwrapper_.Unwrap(message_id); +size_t InterleavedReassemblyStreams::Stream::EraseTo(MID mid) { + UnwrappedMID unwrapped_mid = mid_unwrapper_.Unwrap(mid); size_t removed_bytes = 0; auto it = chunks_by_mid_.begin(); @@ -135,7 +135,7 @@ int InterleavedReassemblyStreams::Stream::Add(UnwrappedTSN tsn, Data data) { RTC_DCHECK_EQ(*data.is_unordered, *stream_id_.unordered); RTC_DCHECK_EQ(*data.stream_id, *stream_id_.stream_id); int queued_bytes = data.size(); - UnwrappedMID mid = mid_unwrapper_.Unwrap(data.message_id); + UnwrappedMID mid = mid_unwrapper_.Unwrap(data.mid); FSN fsn = data.fsn; auto [unused, inserted] = chunks_by_mid_[mid].emplace(fsn, std::make_pair(tsn, std::move(data))); @@ -208,7 +208,7 @@ size_t InterleavedReassemblyStreams::HandleForwardTsn( for (const auto& skipped : skipped_streams) { removed_bytes += GetOrCreateStream(FullStreamId(skipped.unordered, skipped.stream_id)) - .EraseTo(skipped.message_id); + .EraseTo(skipped.mid); } return removed_bytes; } diff --git a/net/dcsctp/rx/interleaved_reassembly_streams.h b/net/dcsctp/rx/interleaved_reassembly_streams.h index 605cf42b93..a6faadd302 100644 --- a/net/dcsctp/rx/interleaved_reassembly_streams.h +++ b/net/dcsctp/rx/interleaved_reassembly_streams.h @@ -67,7 +67,7 @@ class InterleavedReassemblyStreams : public ReassemblyStreams { parent_(*parent), next_mid_(mid_unwrapper_.Unwrap(next_mid)) {} int Add(UnwrappedTSN tsn, Data data); - size_t EraseTo(MID message_id); + size_t EraseTo(MID mid); void Reset() { mid_unwrapper_.Reset(); next_mid_ = mid_unwrapper_.Unwrap(MID(0)); diff --git a/net/dcsctp/rx/reassembly_queue.cc b/net/dcsctp/rx/reassembly_queue.cc index 2cc90a6202..573443635c 100644 --- a/net/dcsctp/rx/reassembly_queue.cc +++ b/net/dcsctp/rx/reassembly_queue.cc @@ -29,6 +29,7 @@ #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h" #include "net/dcsctp/public/dcsctp_message.h" +#include "net/dcsctp/public/types.h" #include "net/dcsctp/rx/interleaved_reassembly_streams.h" #include "net/dcsctp/rx/reassembly_streams.h" #include "net/dcsctp/rx/traditional_reassembly_streams.h" @@ -68,10 +69,9 @@ ReassemblyQueue::ReassemblyQueue(absl::string_view log_prefix, use_message_interleaving)) {} void ReassemblyQueue::Add(TSN tsn, Data data) { - RTC_DCHECK(IsConsistent()); RTC_DLOG(LS_VERBOSE) << log_prefix_ << "added tsn=" << *tsn - << ", stream=" << *data.stream_id << ":" - << *data.message_id << ":" << *data.fsn << ", type=" + << ", stream=" << *data.stream_id << ":" << *data.mid + << ":" << *data.fsn << ", type=" << (data.is_beginning && data.is_end ? "complete" : data.is_beginning ? "first" : data.is_end ? "last" @@ -79,32 +79,27 @@ void ReassemblyQueue::Add(TSN tsn, Data data) { UnwrappedTSN unwrapped_tsn = tsn_unwrapper_.Unwrap(tsn); - if (unwrapped_tsn <= last_assembled_tsn_watermark_ || - delivered_tsns_.find(unwrapped_tsn) != delivered_tsns_.end()) { - RTC_DLOG(LS_VERBOSE) << log_prefix_ - << "Chunk has already been delivered - skipping"; - return; - } - // If a stream reset has been received with a "sender's last assigned tsn" in // the future, the socket is in "deferred reset processing" mode and must // buffer chunks until it's exited. if (deferred_reset_streams_.has_value() && - unwrapped_tsn > - tsn_unwrapper_.Unwrap( - deferred_reset_streams_->req.sender_last_assigned_tsn())) { + unwrapped_tsn > deferred_reset_streams_->sender_last_assigned_tsn && + deferred_reset_streams_->streams.contains(data.stream_id)) { RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Deferring chunk with tsn=" << *tsn - << " until cum_ack_tsn=" - << *deferred_reset_streams_->req.sender_last_assigned_tsn(); + << ", sid=" << *data.stream_id << " until tsn=" + << *deferred_reset_streams_->sender_last_assigned_tsn.Wrap(); // https://tools.ietf.org/html/rfc6525#section-5.2.2 // "In this mode, any data arriving with a TSN larger than the // Sender's Last Assigned TSN for the affected stream(s) MUST be queued // locally and held until the cumulative acknowledgment point reaches the // Sender's Last Assigned TSN." queued_bytes_ += data.size(); - deferred_reset_streams_->deferred_chunks.emplace_back( - std::make_pair(tsn, std::move(data))); + deferred_reset_streams_->deferred_actions.push_back( + [this, tsn, data = std::move(data)]() mutable { + queued_bytes_ -= data.size(); + Add(tsn, std::move(data)); + }); } else { queued_bytes_ += streams_->Add(unwrapped_tsn, std::move(data)); } @@ -120,83 +115,51 @@ void ReassemblyQueue::Add(TSN tsn, Data data) { RTC_DCHECK(IsConsistent()); } -ReconfigurationResponseParameter::Result ReassemblyQueue::ResetStreams( - const OutgoingSSNResetRequestParameter& req, - TSN cum_tsn_ack) { - RTC_DCHECK(IsConsistent()); - if (deferred_reset_streams_.has_value()) { - // In deferred mode already. - return ReconfigurationResponseParameter::Result::kInProgress; - } else if (req.request_sequence_number() <= - last_completed_reset_req_seq_nbr_) { - // Already performed at some time previously. - return ReconfigurationResponseParameter::Result::kSuccessPerformed; - } - - UnwrappedTSN sla_tsn = tsn_unwrapper_.Unwrap(req.sender_last_assigned_tsn()); - UnwrappedTSN unwrapped_cum_tsn_ack = tsn_unwrapper_.Unwrap(cum_tsn_ack); - - // https://tools.ietf.org/html/rfc6525#section-5.2.2 - // "If the Sender's Last Assigned TSN is greater than the - // cumulative acknowledgment point, then the endpoint MUST enter "deferred - // reset processing"." - if (sla_tsn > unwrapped_cum_tsn_ack) { - RTC_DLOG(LS_VERBOSE) - << log_prefix_ - << "Entering deferred reset processing mode until cum_tsn_ack=" - << *req.sender_last_assigned_tsn(); - deferred_reset_streams_ = absl::make_optional(req); - return ReconfigurationResponseParameter::Result::kInProgress; - } +void ReassemblyQueue::ResetStreamsAndLeaveDeferredReset( + rtc::ArrayView stream_ids) { + RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Resetting streams: [" + << StrJoin(stream_ids, ",", + [](rtc::StringBuilder& sb, StreamID sid) { + sb << *sid; + }) + << "]"; // https://tools.ietf.org/html/rfc6525#section-5.2.2 // "... streams MUST be reset to 0 as the next expected SSN." - streams_->ResetStreams(req.stream_ids()); - last_completed_reset_req_seq_nbr_ = req.request_sequence_number(); - RTC_DCHECK(IsConsistent()); - return ReconfigurationResponseParameter::Result::kSuccessPerformed; -} + streams_->ResetStreams(stream_ids); -bool ReassemblyQueue::MaybeResetStreamsDeferred(TSN cum_ack_tsn) { - RTC_DCHECK(IsConsistent()); if (deferred_reset_streams_.has_value()) { - UnwrappedTSN unwrapped_cum_ack_tsn = tsn_unwrapper_.Unwrap(cum_ack_tsn); - UnwrappedTSN unwrapped_sla_tsn = tsn_unwrapper_.Unwrap( - deferred_reset_streams_->req.sender_last_assigned_tsn()); - if (unwrapped_cum_ack_tsn >= unwrapped_sla_tsn) { - RTC_DLOG(LS_VERBOSE) << log_prefix_ - << "Leaving deferred reset processing with tsn=" - << *cum_ack_tsn << ", feeding back " - << deferred_reset_streams_->deferred_chunks.size() - << " chunks"; - // https://tools.ietf.org/html/rfc6525#section-5.2.2 - // "... streams MUST be reset to 0 as the next expected SSN." - streams_->ResetStreams(deferred_reset_streams_->req.stream_ids()); - std::vector> deferred_chunks = - std::move(deferred_reset_streams_->deferred_chunks); - // The response will not be sent now, but as a reply to the retried - // request, which will come as "in progress" has been sent prior. - last_completed_reset_req_seq_nbr_ = - deferred_reset_streams_->req.request_sequence_number(); - deferred_reset_streams_ = absl::nullopt; + RTC_DLOG(LS_VERBOSE) << log_prefix_ + << "Leaving deferred reset processing, feeding back " + << deferred_reset_streams_->deferred_actions.size() + << " actions"; + // https://tools.ietf.org/html/rfc6525#section-5.2.2 + // "Any queued TSNs (queued at step E2) MUST now be released and processed + // normally." + auto deferred_actions = + std::move(deferred_reset_streams_->deferred_actions); + deferred_reset_streams_ = absl::nullopt; - // https://tools.ietf.org/html/rfc6525#section-5.2.2 - // "Any queued TSNs (queued at step E2) MUST now be released and processed - // normally." - for (auto& [tsn, data] : deferred_chunks) { - queued_bytes_ -= data.size(); - Add(tsn, std::move(data)); - } - - RTC_DCHECK(IsConsistent()); - return true; - } else { - RTC_DLOG(LS_VERBOSE) << "Staying in deferred reset processing. tsn=" - << *cum_ack_tsn; + for (auto& action : deferred_actions) { + action(); } } - return false; + RTC_DCHECK(IsConsistent()); +} + +void ReassemblyQueue::EnterDeferredReset( + TSN sender_last_assigned_tsn, + rtc::ArrayView streams) { + if (!deferred_reset_streams_.has_value()) { + RTC_DLOG(LS_VERBOSE) << log_prefix_ + << "Entering deferred reset; sender_last_assigned_tsn=" + << *sender_last_assigned_tsn; + deferred_reset_streams_ = absl::make_optional( + tsn_unwrapper_.Unwrap(sender_last_assigned_tsn), + webrtc::flat_set(streams.begin(), streams.end())); + } + RTC_DCHECK(IsConsistent()); } std::vector ReassemblyQueue::FlushMessages() { @@ -218,15 +181,7 @@ void ReassemblyQueue::AddReassembledMessage( << ", payload=" << message.payload().size() << " bytes"; for (const UnwrappedTSN tsn : tsns) { - if (tsn <= last_assembled_tsn_watermark_) { - // This can be provoked by a misbehaving peer by sending FORWARD-TSN with - // invalid SSNs, allowing ordered messages to stay in the queue that - // should've been discarded. - RTC_DLOG(LS_VERBOSE) - << log_prefix_ - << "Message is built from fragments already seen - skipping"; - return; - } else if (tsn == last_assembled_tsn_watermark_.next_value()) { + if (tsn == last_assembled_tsn_watermark_.next_value()) { // Update watermark, or insert into delivered_tsns_ last_assembled_tsn_watermark_.Increment(); } else { @@ -252,18 +207,32 @@ void ReassemblyQueue::MaybeMoveLastAssembledWatermarkFurther() { } } -void ReassemblyQueue::Handle(const AnyForwardTsnChunk& forward_tsn) { - RTC_DCHECK(IsConsistent()); - UnwrappedTSN tsn = tsn_unwrapper_.Unwrap(forward_tsn.new_cumulative_tsn()); +void ReassemblyQueue::HandleForwardTsn( + TSN new_cumulative_tsn, + rtc::ArrayView skipped_streams) { + UnwrappedTSN tsn = tsn_unwrapper_.Unwrap(new_cumulative_tsn); + if (deferred_reset_streams_.has_value() && + tsn > deferred_reset_streams_->sender_last_assigned_tsn) { + RTC_DLOG(LS_VERBOSE) << log_prefix_ << "ForwardTSN to " << *tsn.Wrap() + << "- deferring."; + deferred_reset_streams_->deferred_actions.emplace_back( + [this, new_cumulative_tsn, + streams = std::vector( + skipped_streams.begin(), skipped_streams.end())] { + HandleForwardTsn(new_cumulative_tsn, streams); + }); + RTC_DCHECK(IsConsistent()); + return; + } + + RTC_DLOG(LS_VERBOSE) << log_prefix_ << "ForwardTSN to " << *tsn.Wrap() + << " - performing."; last_assembled_tsn_watermark_ = std::max(last_assembled_tsn_watermark_, tsn); delivered_tsns_.erase(delivered_tsns_.begin(), delivered_tsns_.upper_bound(tsn)); - MaybeMoveLastAssembledWatermarkFurther(); - - queued_bytes_ -= - streams_->HandleForwardTsn(tsn, forward_tsn.skipped_streams()); + queued_bytes_ -= streams_->HandleForwardTsn(tsn, skipped_streams); RTC_DCHECK(IsConsistent()); } diff --git a/net/dcsctp/rx/reassembly_queue.h b/net/dcsctp/rx/reassembly_queue.h index e1f231e2a3..761ec3556c 100644 --- a/net/dcsctp/rx/reassembly_queue.h +++ b/net/dcsctp/rx/reassembly_queue.h @@ -19,6 +19,7 @@ #include #include +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "api/array_view.h" #include "net/dcsctp/common/internal_types.h" @@ -30,6 +31,7 @@ #include "net/dcsctp/public/dcsctp_handover_state.h" #include "net/dcsctp/public/dcsctp_message.h" #include "net/dcsctp/rx/reassembly_streams.h" +#include "rtc_base/containers/flat_set.h" namespace dcsctp { @@ -88,18 +90,18 @@ class ReassemblyQueue { // Handle a ForwardTSN chunk, when the sender has indicated that the received // (this class) should forget about some chunks. This is used to implement // partial reliability. - void Handle(const AnyForwardTsnChunk& forward_tsn); + void HandleForwardTsn( + TSN new_cumulative_tsn, + rtc::ArrayView skipped_streams); - // Given the reset stream request and the current cum_tsn_ack, might either - // reset the streams directly (returns kSuccessPerformed), or at a later time, - // by entering the "deferred reset processing" mode (returns kInProgress). - ReconfigurationResponseParameter::Result ResetStreams( - const OutgoingSSNResetRequestParameter& req, - TSN cum_tsn_ack); + // Resets the provided streams and leaves deferred reset processing, if + // enabled. + void ResetStreamsAndLeaveDeferredReset( + rtc::ArrayView stream_ids); - // Given the current (updated) cum_tsn_ack, might leave "defererred reset - // processing" mode and reset streams. Returns true if so. - bool MaybeResetStreamsDeferred(TSN cum_ack_tsn); + // Enters deferred reset processing. + void EnterDeferredReset(TSN sender_last_assigned_tsn, + rtc::ArrayView streams); // The number of payload bytes that have been queued. Note that the actual // memory usage is higher due to additional overhead of tracking received @@ -126,18 +128,22 @@ class ReassemblyQueue { void RestoreFromState(const DcSctpSocketHandoverState& state); private: + struct DeferredResetStreams { + DeferredResetStreams(UnwrappedTSN sender_last_assigned_tsn, + webrtc::flat_set streams) + : sender_last_assigned_tsn(sender_last_assigned_tsn), + streams(std::move(streams)) {} + + UnwrappedTSN sender_last_assigned_tsn; + webrtc::flat_set streams; + std::vector> deferred_actions; + }; + bool IsConsistent() const; void AddReassembledMessage(rtc::ArrayView tsns, DcSctpMessage message); void MaybeMoveLastAssembledWatermarkFurther(); - struct DeferredResetStreams { - explicit DeferredResetStreams(OutgoingSSNResetRequestParameter req) - : req(std::move(req)) {} - OutgoingSSNResetRequestParameter req; - std::vector> deferred_chunks; - }; - const absl::string_view log_prefix_; const size_t max_size_bytes_; const size_t watermark_bytes_; diff --git a/net/dcsctp/rx/reassembly_queue_test.cc b/net/dcsctp/rx/reassembly_queue_test.cc index 549bc6fce1..fd8c423a5f 100644 --- a/net/dcsctp/rx/reassembly_queue_test.cc +++ b/net/dcsctp/rx/reassembly_queue_test.cc @@ -34,6 +34,7 @@ namespace { using ::testing::ElementsAre; using ::testing::SizeIs; using ::testing::UnorderedElementsAre; +using SkippedStream = AnyForwardTsnChunk::SkippedStream; // The default maximum size of the Reassembly Queue. static constexpr size_t kBufferSize = 10000; @@ -194,12 +195,7 @@ TEST_F(ReassemblyQueueTest, ForwardTSNRemoveUnordered) { EXPECT_FALSE(reasm.HasMessages()); - reasm.Handle(ForwardTsnChunk(TSN(13), {})); - EXPECT_EQ(reasm.queued_bytes(), 3u); - - // The lost chunk comes, but too late. - reasm.Add(TSN(11), gen_.Unordered({2})); - EXPECT_FALSE(reasm.HasMessages()); + reasm.HandleForwardTsn(TSN(13), std::vector()); EXPECT_EQ(reasm.queued_bytes(), 3u); // The second lost chunk comes, message is assembled. @@ -222,8 +218,8 @@ TEST_F(ReassemblyQueueTest, ForwardTSNRemoveOrdered) { EXPECT_FALSE(reasm.HasMessages()); - reasm.Handle(ForwardTsnChunk( - TSN(13), {ForwardTsnChunk::SkippedStream(kStreamID, kSSN)})); + reasm.HandleForwardTsn( + TSN(13), std::vector({SkippedStream(kStreamID, kSSN)})); EXPECT_EQ(reasm.queued_bytes(), 0u); // The lost chunk comes, but too late. @@ -246,8 +242,8 @@ TEST_F(ReassemblyQueueTest, ForwardTSNRemoveALotOrdered) { EXPECT_FALSE(reasm.HasMessages()); - reasm.Handle(ForwardTsnChunk( - TSN(13), {ForwardTsnChunk::SkippedStream(kStreamID, kSSN)})); + reasm.HandleForwardTsn( + TSN(13), std::vector({SkippedStream(kStreamID, kSSN)})); EXPECT_EQ(reasm.queued_bytes(), 0u); // The lost chunk comes, but too late. @@ -256,52 +252,6 @@ TEST_F(ReassemblyQueueTest, ForwardTSNRemoveALotOrdered) { ElementsAre(SctpMessageIs(kStreamID, kPPID, kMessage2Payload))); } -TEST_F(ReassemblyQueueTest, ShouldntDeliverMessagesBeforeInitialTsn) { - ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - reasm.Add(TSN(5), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 0u); - EXPECT_FALSE(reasm.HasMessages()); -} - -TEST_F(ReassemblyQueueTest, ShouldntRedeliverUnorderedMessages) { - ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - reasm.Add(TSN(10), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 0u); - EXPECT_TRUE(reasm.HasMessages()); - EXPECT_THAT(reasm.FlushMessages(), - ElementsAre(SctpMessageIs(kStreamID, kPPID, kShortPayload))); - reasm.Add(TSN(10), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 0u); - EXPECT_FALSE(reasm.HasMessages()); -} - -TEST_F(ReassemblyQueueTest, ShouldntRedeliverUnorderedMessagesReallyUnordered) { - ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - reasm.Add(TSN(10), gen_.Unordered({1, 2, 3, 4}, "B")); - EXPECT_EQ(reasm.queued_bytes(), 4u); - - EXPECT_FALSE(reasm.HasMessages()); - - reasm.Add(TSN(12), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 4u); - EXPECT_TRUE(reasm.HasMessages()); - - EXPECT_THAT(reasm.FlushMessages(), - ElementsAre(SctpMessageIs(kStreamID, kPPID, kShortPayload))); - reasm.Add(TSN(12), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 4u); - EXPECT_FALSE(reasm.HasMessages()); -} - -TEST_F(ReassemblyQueueTest, ShouldntDeliverBeforeForwardedTsn) { - ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - reasm.Handle(ForwardTsnChunk(TSN(12), {})); - - reasm.Add(TSN(12), gen_.Unordered({1, 2, 3, 4}, "BE")); - EXPECT_EQ(reasm.queued_bytes(), 0u); - EXPECT_FALSE(reasm.HasMessages()); -} - TEST_F(ReassemblyQueueTest, NotReadyForHandoverWhenDeliveredTsnsHaveGap) { ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); reasm.Add(TSN(10), gen_.Unordered({1, 2, 3, 4}, "B")); @@ -325,46 +275,24 @@ TEST_F(ReassemblyQueueTest, NotReadyForHandoverWhenDeliveredTsnsHaveGap) { .Add( HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks)); - reasm.Handle(ForwardTsnChunk(TSN(13), {})); + reasm.HandleForwardTsn(TSN(13), std::vector()); EXPECT_EQ(reasm.GetHandoverReadiness(), HandoverReadinessStatus()); } TEST_F(ReassemblyQueueTest, NotReadyForHandoverWhenResetStreamIsDeferred) { ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - DataGeneratorOptions opts; - opts.message_id = MID(0); - reasm.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - opts.message_id = MID(1); - reasm.Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", opts)); + reasm.Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(0)})); + reasm.Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(1)})); EXPECT_THAT(reasm.FlushMessages(), SizeIs(2)); - reasm.ResetStreams( - OutgoingSSNResetRequestParameter( - ReconfigRequestSN(10), ReconfigRequestSN(3), TSN(13), {StreamID(1)}), - TSN(11)); + reasm.EnterDeferredReset(TSN(12), std::vector({StreamID(1)})); EXPECT_EQ(reasm.GetHandoverReadiness(), HandoverReadinessStatus().Add( HandoverUnreadinessReason::kStreamResetDeferred)); - opts.message_id = MID(3); - opts.ppid = PPID(3); - reasm.Add(TSN(13), gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm.MaybeResetStreamsDeferred(TSN(11)); + reasm.Add(TSN(12), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(2)})); - opts.message_id = MID(2); - opts.ppid = PPID(2); - reasm.Add(TSN(13), gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm.MaybeResetStreamsDeferred(TSN(15)); - EXPECT_EQ(reasm.GetHandoverReadiness(), - HandoverReadinessStatus().Add( - HandoverUnreadinessReason::kReassemblyQueueDeliveredTSNsGap)); - - EXPECT_THAT(reasm.FlushMessages(), SizeIs(2)); - EXPECT_EQ(reasm.GetHandoverReadiness(), - HandoverReadinessStatus().Add( - HandoverUnreadinessReason::kReassemblyQueueDeliveredTSNsGap)); - - reasm.Handle(ForwardTsnChunk(TSN(15), {})); + reasm.ResetStreamsAndLeaveDeferredReset(std::vector({StreamID(1)})); EXPECT_EQ(reasm.GetHandoverReadiness(), HandoverReadinessStatus()); } @@ -400,22 +328,6 @@ TEST_F(ReassemblyQueueTest, HandoverAfterHavingAssembedOneMessage) { EXPECT_THAT(reasm2.FlushMessages(), SizeIs(1)); } -TEST_F(ReassemblyQueueTest, HandleInconsistentForwardTSN) { - // Found when fuzzing. - ReassemblyQueue reasm("log: ", TSN(10), kBufferSize); - // Add TSN=43, SSN=7. Can't be reassembled as previous SSNs aren't known. - reasm.Add(TSN(43), Data(kStreamID, SSN(7), MID(0), FSN(0), kPPID, - std::vector(10), Data::IsBeginning(true), - Data::IsEnd(true), IsUnordered(false))); - - // Invalid, as TSN=44 have to have SSN>=7, but peer says 6. - reasm.Handle(ForwardTsnChunk( - TSN(44), {ForwardTsnChunk::SkippedStream(kStreamID, SSN(6))})); - - // Don't assemble SSN=7, as that TSN is skipped. - EXPECT_FALSE(reasm.HasMessages()); -} - TEST_F(ReassemblyQueueTest, SingleUnorderedChunkMessageInRfc8260) { ReassemblyQueue reasm("log: ", TSN(10), kBufferSize, /*use_message_interleaving=*/true); @@ -494,9 +406,8 @@ TEST_F(ReassemblyQueueTest, IForwardTSNRemoveALotOrdered) { ASSERT_FALSE(reasm.HasMessages()); EXPECT_EQ(reasm.queued_bytes(), 7u); - reasm.Handle( - IForwardTsnChunk(TSN(13), {IForwardTsnChunk::SkippedStream( - IsUnordered(false), kStreamID, MID(0))})); + reasm.HandleForwardTsn(TSN(13), std::vector({SkippedStream( + IsUnordered(false), kStreamID, MID(0))})); EXPECT_EQ(reasm.queued_bytes(), 0u); // The lost chunk comes, but too late. diff --git a/net/dcsctp/socket/capabilities.h b/net/dcsctp/socket/capabilities.h index fa3be37d12..286509a40a 100644 --- a/net/dcsctp/socket/capabilities.h +++ b/net/dcsctp/socket/capabilities.h @@ -21,6 +21,8 @@ struct Capabilities { bool message_interleaving = false; // RFC6525 Stream Reconfiguration bool reconfig = false; + // https://datatracker.ietf.org/doc/draft-tuexen-tsvwg-sctp-zero-checksum/ + bool zero_checksum = false; // Negotiated maximum incoming and outgoing stream count. uint16_t negotiated_maximum_incoming_streams = 0; uint16_t negotiated_maximum_outgoing_streams = 0; diff --git a/net/dcsctp/socket/dcsctp_socket.cc b/net/dcsctp/socket/dcsctp_socket.cc index 712fceaa66..32bcdaaacf 100644 --- a/net/dcsctp/socket/dcsctp_socket.cc +++ b/net/dcsctp/socket/dcsctp_socket.cc @@ -56,6 +56,7 @@ #include "net/dcsctp/packet/parameter/parameter.h" #include "net/dcsctp/packet/parameter/state_cookie_parameter.h" #include "net/dcsctp/packet/parameter/supported_extensions_parameter.h" +#include "net/dcsctp/packet/parameter/zero_checksum_acceptable_chunk_parameter.h" #include "net/dcsctp/packet/sctp_packet.h" #include "net/dcsctp/packet/tlv_trait.h" #include "net/dcsctp/public/dcsctp_message.h" @@ -117,6 +118,11 @@ Capabilities ComputeCapabilities(const DcSctpOptions& options, capabilities.reconfig = true; } + if (options.enable_zero_checksum && + parameters.get().has_value()) { + capabilities.zero_checksum = true; + } + capabilities.negotiated_maximum_incoming_streams = std::min( options.announced_maximum_incoming_streams, peer_nbr_outbound_streams); capabilities.negotiated_maximum_outgoing_streams = std::min( @@ -137,6 +143,9 @@ void AddCapabilityParameters(const DcSctpOptions& options, chunk_types.push_back(IDataChunk::kType); chunk_types.push_back(IForwardTsnChunk::kType); } + if (options.enable_zero_checksum) { + builder.Add(ZeroChecksumAcceptableChunkParameter()); + } builder.Add(SupportedExtensionsParameter(std::move(chunk_types))); } @@ -279,7 +288,10 @@ void DcSctpSocket::SendInit() { connect_params_.initial_tsn, params_builder.Build()); SctpPacket::Builder b(VerificationTag(0), options_); b.Add(init); - packet_sender_.Send(b); + // https://www.ietf.org/archive/id/draft-tuexen-tsvwg-sctp-zero-checksum-01.html#section-4.2 + // "When an end point sends a packet containing an INIT chunk, it MUST include + // a correct CRC32c checksum in the packet containing the INIT chunk." + packet_sender_.Send(b, /*write_checksum=*/true); } void DcSctpSocket::MakeConnectionParameters() { @@ -320,6 +332,7 @@ void DcSctpSocket::CreateTransmissionControlBlock( size_t a_rwnd, TieTag tie_tag) { metrics_.uses_message_interleaving = capabilities.message_interleaving; + metrics_.uses_zero_checksum = capabilities.zero_checksum; metrics_.negotiated_maximum_incoming_streams = capabilities.negotiated_maximum_incoming_streams; metrics_.negotiated_maximum_outgoing_streams = @@ -351,6 +364,7 @@ void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) { capabilities.message_interleaving = state.capabilities.message_interleaving; capabilities.reconfig = state.capabilities.reconfig; + capabilities.zero_checksum = state.capabilities.zero_checksum; capabilities.negotiated_maximum_incoming_streams = state.capabilities.negotiated_maximum_incoming_streams; capabilities.negotiated_maximum_outgoing_streams = @@ -1088,9 +1102,7 @@ void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) { if (tcb_->data_tracker().Observe(tsn, immediate_ack)) { tcb_->reassembly_queue().Add(tsn, std::move(data)); - tcb_->reassembly_queue().MaybeResetStreamsDeferred( - tcb_->data_tracker().last_cumulative_acked_tsn()); - DeliverReassembledMessages(); + MaybeDeliverMessages(); } } @@ -1211,7 +1223,9 @@ void DcSctpSocket::HandleInit(const CommonHeader& header, options_.announced_maximum_incoming_streams, connect_params_.initial_tsn, params_builder.Build()); b.Add(init_ack); - packet_sender_.Send(b); + // If the peer has signaled that it supports zero checksum, INIT-ACK can then + // have its checksum as zero. + packet_sender_.Send(b, /*write_checksum=*/!capabilities.zero_checksum); } void DcSctpSocket::HandleInitAck( @@ -1439,12 +1453,10 @@ void DcSctpSocket::HandleCookieAck( callbacks_.OnConnected(); } -void DcSctpSocket::DeliverReassembledMessages() { - if (tcb_->reassembly_queue().HasMessages()) { - for (auto& message : tcb_->reassembly_queue().FlushMessages()) { - ++metrics_.rx_messages_count; - callbacks_.OnMessageReceived(std::move(message)); - } +void DcSctpSocket::MaybeDeliverMessages() { + for (auto& message : tcb_->reassembly_queue().FlushMessages()) { + ++metrics_.rx_messages_count; + callbacks_.OnMessageReceived(std::move(message)); } } @@ -1554,6 +1566,10 @@ void DcSctpSocket::HandleReconfig( // If a response was processed, pending to-be-reset streams may now have // become unpaused. Try to send more DATA chunks. tcb_->SendBufferedPackets(now); + + // If it leaves "deferred reset processing", there may be chunks to deliver + // that were queued while waiting for the stream to reset. + MaybeDeliverMessages(); } } @@ -1692,14 +1708,13 @@ void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) { "Received a FORWARD_TSN without announced peer support"); return; } - tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn()); - tcb_->reassembly_queue().Handle(chunk); - // A forward TSN - for ordered streams - may allow messages to be - // delivered. - DeliverReassembledMessages(); + if (tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn())) { + tcb_->reassembly_queue().HandleForwardTsn(chunk.new_cumulative_tsn(), + chunk.skipped_streams()); + } - // Processing a FORWARD_TSN might result in sending a SACK. - tcb_->MaybeSendSack(); + // A forward TSN - for ordered streams - may allow messages to be delivered. + MaybeDeliverMessages(); } void DcSctpSocket::MaybeSendShutdownOrAck() { diff --git a/net/dcsctp/socket/dcsctp_socket.h b/net/dcsctp/socket/dcsctp_socket.h index 157c515d65..f91eb3ead4 100644 --- a/net/dcsctp/socket/dcsctp_socket.h +++ b/net/dcsctp/socket/dcsctp_socket.h @@ -179,8 +179,9 @@ class DcSctpSocket : public DcSctpSocketInterface { // Parses `payload`, which is a serialized packet that is just going to be // sent and prints all chunks. void DebugPrintOutgoing(rtc::ArrayView payload); - // Called whenever there may be reassembled messages, and delivers those. - void DeliverReassembledMessages(); + // Called whenever data has been received, or the cumulative acknowledgment + // TSN has moved, that may result in delivering messages. + void MaybeDeliverMessages(); // Returns true if there is a TCB, and false otherwise (and reports an error). bool ValidateHasTCB(); diff --git a/net/dcsctp/socket/dcsctp_socket_test.cc b/net/dcsctp/socket/dcsctp_socket_test.cc index c31c048582..13202846ac 100644 --- a/net/dcsctp/socket/dcsctp_socket_test.cc +++ b/net/dcsctp/socket/dcsctp_socket_test.cc @@ -9,6 +9,7 @@ */ #include "net/dcsctp/socket/dcsctp_socket.h" +#include #include #include #include @@ -23,15 +24,20 @@ #include "api/array_view.h" #include "net/dcsctp/common/handover_testing.h" #include "net/dcsctp/common/math.h" +#include "net/dcsctp/packet/chunk/abort_chunk.h" #include "net/dcsctp/packet/chunk/chunk.h" +#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h" #include "net/dcsctp/packet/chunk/cookie_echo_chunk.h" #include "net/dcsctp/packet/chunk/data_chunk.h" #include "net/dcsctp/packet/chunk/data_common.h" #include "net/dcsctp/packet/chunk/error_chunk.h" +#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h" #include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h" #include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h" #include "net/dcsctp/packet/chunk/idata_chunk.h" +#include "net/dcsctp/packet/chunk/init_ack_chunk.h" #include "net/dcsctp/packet/chunk/init_chunk.h" +#include "net/dcsctp/packet/chunk/reconfig_chunk.h" #include "net/dcsctp/packet/chunk/sack_chunk.h" #include "net/dcsctp/packet/chunk/shutdown_chunk.h" #include "net/dcsctp/packet/error_cause/error_cause.h" @@ -39,6 +45,7 @@ #include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h" #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/parameter.h" +#include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h" #include "net/dcsctp/packet/sctp_packet.h" #include "net/dcsctp/packet/tlv_trait.h" #include "net/dcsctp/public/dcsctp_message.h" @@ -59,8 +66,11 @@ namespace { using ::testing::_; using ::testing::AllOf; using ::testing::ElementsAre; +using ::testing::Eq; using ::testing::HasSubstr; using ::testing::IsEmpty; +using ::testing::Not; +using ::testing::Property; using ::testing::SizeIs; using ::testing::UnorderedElementsAre; @@ -70,243 +80,135 @@ constexpr size_t kSmallMessageSize = 10; constexpr int kMaxBurstPackets = 4; constexpr DcSctpOptions kDefaultOptions; -MATCHER_P(HasDataChunkWithStreamId, stream_id, "") { +MATCHER_P(HasChunks, chunks, "") { absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); if (!packet.has_value()) { *result_listener << "data didn't parse as an SctpPacket"; return false; } - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; - return false; - } - - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->stream_id() != stream_id) { - *result_listener << "the stream_id is " << *dc->stream_id(); - return false; - } - - return true; + return ExplainMatchResult(chunks, packet->descriptors(), result_listener); } -MATCHER_P(HasDataChunkWithPPID, ppid, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; - return false; - } - - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; - return false; - } - - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->ppid() != ppid) { - *result_listener << "the ppid is " << *dc->ppid(); - return false; - } - - return true; +MATCHER_P(IsChunkType, chunk_type, "") { + return ExplainMatchResult(chunk_type, arg.type, result_listener); } -MATCHER_P(HasDataChunkWithSsn, ssn, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsDataChunk, properties, "") { + if (arg.type != DataChunk::kType) { + *result_listener << "the chunk is not a data chunk"; return false; } - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = DataChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a data chunk"; return false; } - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->ssn() != ssn) { - *result_listener << "the ssn is " << *dc->ssn(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasDataChunkWithMid, mid, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsSack, properties, "") { + if (arg.type != SackChunk::kType) { + *result_listener << "the chunk is not a sack chunk"; return false; } - if (packet->descriptors()[0].type != IDataChunk::kType) { - *result_listener << "the first chunk in the packet is not an i-data chunk"; + absl::optional chunk = SackChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a sack chunk"; return false; } - absl::optional dc = - IDataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as an i-data chunk"; - return false; - } - - if (dc->message_id() != mid) { - *result_listener << "the mid is " << *dc->message_id(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasSackWithCumAckTsn, tsn, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsReConfig, properties, "") { + if (arg.type != ReConfigChunk::kType) { + *result_listener << "the chunk is not a re-config chunk"; return false; } - if (packet->descriptors()[0].type != SackChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = ReConfigChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a re-config chunk"; return false; } - absl::optional sc = - SackChunk::Parse(packet->descriptors()[0].data); - if (!sc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (sc->cumulative_tsn_ack() != tsn) { - *result_listener << "the cum_ack_tsn is " << *sc->cumulative_tsn_ack(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER(HasSackWithNoGapAckBlocks, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsHeartbeatAck, properties, "") { + if (arg.type != HeartbeatAckChunk::kType) { + *result_listener << "the chunk is not a HeartbeatAckChunk"; return false; } - if (packet->descriptors()[0].type != SackChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = HeartbeatAckChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a HeartbeatAckChunk"; return false; } - absl::optional sc = - SackChunk::Parse(packet->descriptors()[0].data); - if (!sc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (!sc->gap_ack_blocks().empty()) { - *result_listener << "there are gap ack blocks"; - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasReconfigWithStreams, streams_matcher, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsHeartbeatRequest, properties, "") { + if (arg.type != HeartbeatRequestChunk::kType) { + *result_listener << "the chunk is not a HeartbeatRequestChunk"; return false; } - if (packet->descriptors()[0].type != ReConfigChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = + HeartbeatRequestChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a HeartbeatRequestChunk"; return false; } - absl::optional reconfig = - ReConfigChunk::Parse(packet->descriptors()[0].data); - if (!reconfig.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - const Parameters& parameters = reconfig->parameters(); - if (parameters.descriptors().size() != 1 || - parameters.descriptors()[0].type != - OutgoingSSNResetRequestParameter::kType) { - *result_listener << "Expected the reconfig chunk to have an outgoing SSN " - "reset request parameter"; - return false; - } - - absl::optional p = - OutgoingSSNResetRequestParameter::Parse(parameters.descriptors()[0].data); - testing::Matcher> matcher = streams_matcher; - if (!matcher.MatchAndExplain(p->stream_ids(), result_listener)) { - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasReconfigWithResponse, result, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(HasParameters, parameters, "") { + return ExplainMatchResult(parameters, arg.parameters().descriptors(), + result_listener); +} + +MATCHER_P(IsOutgoingResetRequest, properties, "") { + if (arg.type != OutgoingSSNResetRequestParameter::kType) { + *result_listener + << "the parameter is not an OutgoingSSNResetRequestParameter"; return false; } - if (packet->descriptors()[0].type != ReConfigChunk::kType) { - *result_listener << "the first chunk in the packet is not a reconfig chunk"; + absl::optional parameter = + OutgoingSSNResetRequestParameter::Parse(arg.data); + if (!parameter.has_value()) { + *result_listener + << "The parameter didn't parse as an OutgoingSSNResetRequestParameter"; return false; } - absl::optional reconfig = - ReConfigChunk::Parse(packet->descriptors()[0].data); - if (!reconfig.has_value()) { - *result_listener << "The first chunk didn't parse as a reconfig chunk"; + return ExplainMatchResult(properties, *parameter, result_listener); +} + +MATCHER_P(IsReconfigurationResponse, properties, "") { + if (arg.type != ReconfigurationResponseParameter::kType) { + *result_listener + << "the parameter is not an ReconfigurationResponseParameter"; return false; } - const Parameters& parameters = reconfig->parameters(); - if (parameters.descriptors().size() != 1 || - parameters.descriptors()[0].type != - ReconfigurationResponseParameter::kType) { - *result_listener << "Expected the reconfig chunk to have a " - "ReconfigurationResponse Parameter"; + absl::optional parameter = + ReconfigurationResponseParameter::Parse(arg.data); + if (!parameter.has_value()) { + *result_listener + << "The parameter didn't parse as an ReconfigurationResponseParameter"; return false; } - absl::optional p = - ReconfigurationResponseParameter::Parse(parameters.descriptors()[0].data); - if (p->result() != result) { - *result_listener << "ReconfigurationResponse Parameter doesn't contain the " - "expected result"; - return false; - } - - return true; + return ExplainMatchResult(properties, *parameter, result_listener); } TSN AddTo(TSN tsn, int delta) { @@ -375,6 +277,26 @@ void AdvanceTime(SocketUnderTest& a, SocketUnderTest& z, DurationMs duration) { RunTimers(z); } +// Exchanges messages between `a` and `z`, advancing time until there are no +// more pending timers, or until `max_timeout` is reached. +void ExchangeMessagesAndAdvanceTime( + SocketUnderTest& a, + SocketUnderTest& z, + DurationMs max_timeout = DurationMs(10000)) { + TimeMs time_started = a.cb.TimeMillis(); + while (a.cb.TimeMillis() - time_started < max_timeout) { + ExchangeMessages(a, z); + + DurationMs time_to_next_timeout = + std::min(a.cb.GetTimeToNextTimeout(), z.cb.GetTimeToNextTimeout()); + if (time_to_next_timeout == DurationMs::InfiniteDuration()) { + // No more pending timer. + return; + } + AdvanceTime(a, z, time_to_next_timeout); + } +} + // Calls Connect() on `sock_a_` and make the connection established. void ConnectSockets(SocketUnderTest& a, SocketUnderTest& z) { EXPECT_CALL(a.cb, OnConnected).Times(1); @@ -630,10 +552,8 @@ TEST(DcSctpSocketTest, ResendInitAndEstablishConnection) { a.socket.Connect(); // INIT is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); AdvanceTime(a, z, a.options.t1_init_timeout); @@ -657,19 +577,15 @@ TEST(DcSctpSocketTest, ResendingInitTooManyTimesAborts) { a.socket.Connect(); // INIT is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); for (int i = 0; i < *a.options.max_init_retransmits; ++i) { AdvanceTime(a, z, a.options.t1_init_timeout * (1 << i)); // INIT is resent - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket resent_init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(resent_init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); } // Another timeout, after the max init retransmits. @@ -692,10 +608,8 @@ TEST(DcSctpSocketTest, ResendCookieEchoAndEstablishConnection) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); AdvanceTime(a, z, a.options.t1_init_timeout); @@ -720,19 +634,15 @@ TEST(DcSctpSocketTest, ResendingCookieEchoTooManyTimesAborts) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); for (int i = 0; i < *a.options.max_init_retransmits; ++i) { AdvanceTime(a, z, a.options.t1_cookie_timeout * (1 << i)); // COOKIE_ECHO is resent - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket resent_init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(resent_init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); } // Another timeout, after the max init retransmits. @@ -759,12 +669,9 @@ TEST(DcSctpSocketTest, DoesntSendMorePacketsUntilCookieAckHasBeenReceived) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket cookie_echo_packet1, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_THAT(cookie_echo_packet1.descriptors(), SizeIs(2)); - EXPECT_EQ(cookie_echo_packet1.descriptors()[0].type, CookieEchoChunk::kType); - EXPECT_EQ(cookie_echo_packet1.descriptors()[1].type, DataChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType), + IsDataChunk(_)))); EXPECT_THAT(a.cb.ConsumeSentPacket(), IsEmpty()); @@ -780,12 +687,9 @@ TEST(DcSctpSocketTest, DoesntSendMorePacketsUntilCookieAckHasBeenReceived) { AdvanceTime(a, z, a.options.t1_cookie_timeout - a.options.rto_initial); // And this COOKIE-ECHO and DATA is also lost - never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket cookie_echo_packet2, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_THAT(cookie_echo_packet2.descriptors(), SizeIs(2)); - EXPECT_EQ(cookie_echo_packet2.descriptors()[0].type, CookieEchoChunk::kType); - EXPECT_EQ(cookie_echo_packet2.descriptors()[1].type, DataChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType), + IsDataChunk(_)))); EXPECT_THAT(a.cb.ConsumeSentPacket(), IsEmpty()); @@ -846,10 +750,8 @@ TEST(DcSctpSocketTest, ShutdownTimerExpiresTooManyTimeClosesConnection) { AdvanceTime(a, z, DurationMs(a.options.rto_initial * (1 << i))); // Dropping every shutdown chunk. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(packet.descriptors()[0].type, ShutdownChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(ShutdownChunk::kType)))); EXPECT_TRUE(a.cb.ConsumeSentPacket().empty()); } // The last expiry, makes it abort the connection. @@ -858,10 +760,8 @@ TEST(DcSctpSocketTest, ShutdownTimerExpiresTooManyTimeClosesConnection) { a.options.rto_initial * (1 << *a.options.max_retransmissions)); EXPECT_EQ(a.socket.state(), SocketState::kClosed); - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(packet.descriptors()[0].type, AbortChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(AbortChunk::kType)))); EXPECT_TRUE(a.cb.ConsumeSentPacket().empty()); } @@ -968,15 +868,11 @@ TEST_P(DcSctpSocketParametrizedTest, SendingHeartbeatAnswersWithAck) { a.socket.ReceivePacket(b.Build()); // HEARTBEAT_ACK is sent as a reply. Capture it. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket ack_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z->options)); - ASSERT_THAT(ack_packet.descriptors(), SizeIs(1)); - ASSERT_HAS_VALUE_AND_ASSIGN( - HeartbeatAckChunk ack, - HeartbeatAckChunk::Parse(ack_packet.descriptors()[0].data)); - ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info_param, ack.info()); - EXPECT_THAT(info_param.info(), ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsHeartbeatAck( + Property(&HeartbeatAckChunk::info, + Optional(Property(&HeartbeatInfoParameter::info, + ElementsAre(1, 2, 3, 4)))))))); MaybeHandoverSocketAndSendMessage(a, std::move(z)); } @@ -992,20 +888,16 @@ TEST_P(DcSctpSocketParametrizedTest, ExpectHeartbeatToBeSent) { AdvanceTime(a, *z, a.options.heartbeat_interval); - std::vector hb_packet_raw = a.cb.ConsumeSentPacket(); - ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket hb_packet, - SctpPacket::Parse(hb_packet_raw, z->options)); - ASSERT_THAT(hb_packet.descriptors(), SizeIs(1)); - ASSERT_HAS_VALUE_AND_ASSIGN( - HeartbeatRequestChunk hb, - HeartbeatRequestChunk::Parse(hb_packet.descriptors()[0].data)); - ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info_param, hb.info()); - + std::vector packet = a.cb.ConsumeSentPacket(); // The info is a single 64-bit number. - EXPECT_THAT(hb.info()->info(), SizeIs(8)); + EXPECT_THAT( + packet, + HasChunks(ElementsAre(IsHeartbeatRequest(Property( + &HeartbeatRequestChunk::info, + Optional(Property(&HeartbeatInfoParameter::info, SizeIs(8)))))))); // Feed it to Sock-z and expect a HEARTBEAT_ACK that will be propagated back. - z->socket.ReceivePacket(hb_packet_raw); + z->socket.ReceivePacket(packet); a.socket.ReceivePacket(z->cb.ConsumeSentPacket()); MaybeHandoverSocketAndSendMessage(a, std::move(z)); @@ -1106,10 +998,8 @@ TEST_P(DcSctpSocketParametrizedTest, RecoversAfterASuccessfulAck) { RTC_LOG(LS_INFO) << "Expecting a new heartbeat"; AdvanceTime(a, *z, time_to_next_hearbeat); - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket another_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z->options)); - EXPECT_EQ(another_packet.descriptors()[0].type, HeartbeatRequestChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsHeartbeatRequest(_)))); } TEST_P(DcSctpSocketParametrizedTest, ResetStream) { @@ -1157,11 +1047,15 @@ TEST_P(DcSctpSocketParametrizedTest, ResetStreamWillMakeChunksStartAtZeroSsn) { a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet1 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT( + packet1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); z->socket.ReceivePacket(packet1); auto packet2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet2, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT( + packet2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); z->socket.ReceivePacket(packet2); // Handle SACK @@ -1187,11 +1081,15 @@ TEST_P(DcSctpSocketParametrizedTest, ResetStreamWillMakeChunksStartAtZeroSsn) { a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet3 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet3, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT( + packet3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); z->socket.ReceivePacket(packet3); auto packet4 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet4, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT( + packet4, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); z->socket.ReceivePacket(packet4); // Handle SACK @@ -1215,13 +1113,15 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet1 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet1, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet1, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(packet1); auto packet2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet2, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT(packet2, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(1))))))); z->socket.ReceivePacket(packet2); // Handle SACK @@ -1231,12 +1131,14 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); auto packet3 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet3, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet3, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet3, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(packet3); auto packet4 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet4, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet4, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT(packet4, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(1))))))); z->socket.ReceivePacket(packet4); a.socket.ReceivePacket(z->cb.ConsumeSentPacket()); @@ -1270,13 +1172,16 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); auto packet5 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet5, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet5, HasDataChunkWithSsn(SSN(2))); // Unchanged. + EXPECT_THAT(packet5, + HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(2))))))); // Unchanged. z->socket.ReceivePacket(packet5); auto packet6 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet6, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet6, HasDataChunkWithSsn(SSN(0))); // Reset. + EXPECT_THAT(packet6, HasChunks(ElementsAre(IsDataChunk(AllOf( + Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(0))))))); // Reset z->socket.ReceivePacket(packet6); // Handle SACK @@ -1396,44 +1301,52 @@ TEST_P(DcSctpSocketParametrizedTest, SendManyFragmentedMessagesWithLimitedRtx) { // First DATA, first fragment std::vector packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(51))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(51)))))); z->socket.ReceivePacket(std::move(packet)); // First DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(51))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(51)))))); // Second DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(52))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(52)))))); z->socket.ReceivePacket(std::move(packet)); // Second DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(52))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(52)), + Property(&DataChunk::ssn, SSN(0))))))); // Third DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(53))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(53)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); // Third DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(53))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(53)), + Property(&DataChunk::ssn, SSN(0))))))); // Fourth DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(54))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(54)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); // Fourth DATA, second fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(54))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(54)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); ExchangeMessages(a, *z); @@ -1558,7 +1471,9 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // First DATA will always trigger a SACK. It's not interesting. EXPECT_THAT(z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(tsn), HasSackWithNoGapAckBlocks())); + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, tsn), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA should be accepted - it's advancing cum ack tsn. z.socket.ReceivePacket( @@ -1571,9 +1486,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // The receiver might have moved into delayed ack mode. AdvanceTime(a, z, z.options.rto_initial); - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA will not be accepted - it's not advancing cum ack tsn. z.socket.ReceivePacket( @@ -1584,9 +1500,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { .Build()); // Sack will be sent in IMMEDIATE mode when this is happening. - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA will not be accepted either. z.socket.ReceivePacket( @@ -1597,9 +1514,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { .Build()); // Sack will be sent in IMMEDIATE mode when this is happening. - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA should be accepted, and it fills the reassembly queue. z.socket.ReceivePacket( @@ -1612,9 +1530,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // The receiver might have moved into delayed ack mode. AdvanceTime(a, z, z.options.rto_initial); - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 2)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 2)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); EXPECT_CALL(z.cb, OnAborted(ErrorKind::kResourceExhaustion, _)); EXPECT_CALL(z.cb, OnClosed).Times(0); @@ -2427,7 +2346,10 @@ TEST(DcSctpSocketTest, CloseStreamsWithPendingRequest) { a.socket.ResetStreams(std::vector({StreamID(1)})); std::vector packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); z.socket.ReceivePacket(std::move(packet)); // Sending more reset requests while this one is ongoing. @@ -2809,10 +2731,19 @@ TEST(DcSctpSocketTest, ResetStreamsDeferred) { auto data3 = a.cb.ConsumeSentPacket(); auto reconfig = a.cb.ConsumeSentPacket(); - EXPECT_THAT(data1, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data2, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data3, HasDataChunkWithSsn(SSN(1))); - EXPECT_THAT(reconfig, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT( + data1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); + EXPECT_THAT(reconfig, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); // Receive them slightly out of order to make stream resetting deferred. z.socket.ReceivePacket(reconfig); @@ -2841,20 +2772,34 @@ TEST(DcSctpSocketTest, ResetStreamsDeferred) { AdvanceTime(a, z, a.options.rto_initial); auto reconfig2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(reconfig2, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT(reconfig2, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(1)))); z.socket.ReceivePacket(reconfig2); auto reconfig3 = z.cb.ConsumeSentPacket(); - EXPECT_THAT(reconfig3, - HasReconfigWithResponse( - ReconfigurationResponseParameter::Result::kSuccessPerformed)); + EXPECT_THAT(reconfig3, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsReconfigurationResponse(Property( + &ReconfigurationResponseParameter::result, + ReconfigurationResponseParameter::Result:: + kSuccessPerformed)))))))); a.socket.ReceivePacket(reconfig3); - EXPECT_THAT(data1, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data2, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data3, HasDataChunkWithSsn(SSN(1))); - EXPECT_THAT(reconfig, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT( + data1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); + EXPECT_THAT(reconfig, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); // Send a new message after the stream has been reset. a.socket.Send(DcSctpMessage(StreamID(1), PPID(55), @@ -2903,5 +2848,211 @@ TEST(DcSctpSocketTest, ResetStreamsWithPausedSenderResumesWhenPerformed) { EXPECT_EQ(msg2->payload().size(), kSmallMessageSize); } +TEST_P(DcSctpSocketParametrizedTest, ZeroChecksumMetricsAreSet) { + std::vector> combinations = { + {false, false}, {false, true}, {true, false}, {true, true}}; + for (const auto& [a_enable, z_enable] : combinations) { + DcSctpOptions a_options = {.enable_zero_checksum = a_enable}; + DcSctpOptions z_options = {.enable_zero_checksum = z_enable}; + + SocketUnderTest a("A", a_options); + auto z = std::make_unique("Z", z_options); + + ConnectSockets(a, *z); + z = MaybeHandoverSocket(std::move(z)); + + EXPECT_EQ(a.socket.GetMetrics()->uses_zero_checksum, a_enable && z_enable); + EXPECT_EQ(z->socket.GetMetrics()->uses_zero_checksum, a_enable && z_enable); + } +} + +TEST(DcSctpSocketTest, AlwaysSendsInitWithNonZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + + a.socket.Connect(); + std::vector data = a.cb.ConsumeSentPacket(); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.descriptors(), + ElementsAre(testing::Field(&SctpPacket::ChunkDescriptor::type, + InitChunk::kType))); + EXPECT_THAT(packet.common_header().checksum, Not(Eq(0u))); +} + +TEST(DcSctpSocketTest, MaySendInitAckWithZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + SocketUnderTest z("Z", options); + + a.socket.Connect(); + z.socket.ReceivePacket(a.cb.ConsumeSentPacket()); // INIT + + std::vector data = z.cb.ConsumeSentPacket(); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.descriptors(), + ElementsAre(testing::Field(&SctpPacket::ChunkDescriptor::type, + InitAckChunk::kType))); + EXPECT_THAT(packet.common_header().checksum, 0u); +} + +TEST(DcSctpSocketTest, AlwaysSendsCookieEchoWithNonZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + SocketUnderTest z("Z", options); + + a.socket.Connect(); + z.socket.ReceivePacket(a.cb.ConsumeSentPacket()); // INIT + a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // INIT-ACK + + std::vector data = a.cb.ConsumeSentPacket(); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.descriptors(), + ElementsAre(testing::Field(&SctpPacket::ChunkDescriptor::type, + CookieEchoChunk::kType))); + EXPECT_THAT(packet.common_header().checksum, Not(Eq(0u))); +} + +TEST(DcSctpSocketTest, SendsCookieAckWithZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + SocketUnderTest z("Z", options); + + a.socket.Connect(); + z.socket.ReceivePacket(a.cb.ConsumeSentPacket()); // INIT + a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // INIT-ACK + z.socket.ReceivePacket(a.cb.ConsumeSentPacket()); // COOKIE-ECHO + + std::vector data = z.cb.ConsumeSentPacket(); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.descriptors(), + ElementsAre(testing::Field(&SctpPacket::ChunkDescriptor::type, + CookieAckChunk::kType))); + EXPECT_THAT(packet.common_header().checksum, 0u); +} + +TEST_P(DcSctpSocketParametrizedTest, SendsDataWithZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + auto z = std::make_unique("Z", options); + + ConnectSockets(a, *z); + z = MaybeHandoverSocket(std::move(z)); + + std::vector payload(a.options.mtu - 100); + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); + + std::vector data = a.cb.ConsumeSentPacket(); + z->socket.ReceivePacket(data); + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.descriptors(), + ElementsAre(testing::Field(&SctpPacket::ChunkDescriptor::type, + DataChunk::kType))); + EXPECT_THAT(packet.common_header().checksum, 0u); + + MaybeHandoverSocketAndSendMessage(a, std::move(z)); +} + +TEST_P(DcSctpSocketParametrizedTest, AllPacketsAfterConnectHaveZeroChecksum) { + DcSctpOptions options = {.enable_zero_checksum = true}; + SocketUnderTest a("A", options); + auto z = std::make_unique("Z", options); + + ConnectSockets(a, *z); + z = MaybeHandoverSocket(std::move(z)); + + // Send large messages in both directions, and verify that they arrive and + // that every packet has zero checksum. + std::vector payload(kLargeMessageSize); + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), kSendOptions); + z->socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), kSendOptions); + + for (;;) { + if (auto data = a.cb.ConsumeSentPacket(); !data.empty()) { + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.common_header().checksum, 0u); + z->socket.ReceivePacket(std::move(data)); + + } else if (auto data = z->cb.ConsumeSentPacket(); !data.empty()) { + ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket packet, + SctpPacket::Parse(data, options)); + EXPECT_THAT(packet.common_header().checksum, 0u); + a.socket.ReceivePacket(std::move(data)); + + } else { + break; + } + } + + absl::optional msg1 = z->cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg1.has_value()); + EXPECT_THAT(msg1->payload(), SizeIs(kLargeMessageSize)); + + absl::optional msg2 = a.cb.ConsumeReceivedMessage(); + ASSERT_TRUE(msg2.has_value()); + EXPECT_THAT(msg2->payload(), SizeIs(kLargeMessageSize)); + + MaybeHandoverSocketAndSendMessage(a, std::move(z)); +} + +TEST(DcSctpSocketTest, HandlesForwardTsnOutOfOrderWithStreamResetting) { + // This test ensures that receiving FORWARD-TSN and RECONFIG out of order is + // handled correctly. + SocketUnderTest a("A", {.heartbeat_interval = DurationMs(0)}); + SocketUnderTest z("Z", {.heartbeat_interval = DurationMs(0)}); + + ConnectSockets(a, z); + std::vector payload(kSmallMessageSize); + a.socket.Send(DcSctpMessage(StreamID(1), PPID(51), payload), + { + .max_retransmissions = 0, + }); + + // Packet is lost. + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre( + IsDataChunk(AllOf(Property(&DataChunk::ssn, SSN(0)), + Property(&DataChunk::ppid, PPID(51))))))); + AdvanceTime(a, z, a.options.rto_initial); + + auto fwd_tsn_packet = a.cb.ConsumeSentPacket(); + EXPECT_THAT(fwd_tsn_packet, + HasChunks(ElementsAre(IsChunkType(ForwardTsnChunk::kType)))); + // Reset stream 1 + a.socket.ResetStreams(std::vector({StreamID(1)})); + auto reconfig_packet = a.cb.ConsumeSentPacket(); + EXPECT_THAT(reconfig_packet, + HasChunks(ElementsAre(IsChunkType(ReConfigChunk::kType)))); + + // These two packets are received in the wrong order. + z.socket.ReceivePacket(reconfig_packet); + z.socket.ReceivePacket(fwd_tsn_packet); + ExchangeMessagesAndAdvanceTime(a, z); + + a.socket.Send(DcSctpMessage(StreamID(1), PPID(52), payload), {}); + a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); + + auto data_packet_2 = a.cb.ConsumeSentPacket(); + auto data_packet_3 = a.cb.ConsumeSentPacket(); + EXPECT_THAT(data_packet_2, HasChunks(ElementsAre(IsDataChunk(AllOf( + Property(&DataChunk::ssn, SSN(0)), + Property(&DataChunk::ppid, PPID(52))))))); + EXPECT_THAT(data_packet_3, HasChunks(ElementsAre(IsDataChunk(AllOf( + Property(&DataChunk::ssn, SSN(1)), + Property(&DataChunk::ppid, PPID(53))))))); + + z.socket.ReceivePacket(data_packet_2); + z.socket.ReceivePacket(data_packet_3); + ASSERT_THAT(z.cb.ConsumeReceivedMessage(), + testing::Optional(Property(&DcSctpMessage::ppid, PPID(52)))); + ASSERT_THAT(z.cb.ConsumeReceivedMessage(), + testing::Optional(Property(&DcSctpMessage::ppid, PPID(53)))); +} + } // namespace } // namespace dcsctp diff --git a/net/dcsctp/socket/mock_dcsctp_socket_callbacks.h b/net/dcsctp/socket/mock_dcsctp_socket_callbacks.h index 8b2a772fa3..150c1b9fa5 100644 --- a/net/dcsctp/socket/mock_dcsctp_socket_callbacks.h +++ b/net/dcsctp/socket/mock_dcsctp_socket_callbacks.h @@ -166,6 +166,10 @@ class MockDcSctpSocketCallbacks : public DcSctpSocketCallbacks { return timeout_manager_.GetNextExpiredTimeout(); } + DurationMs GetTimeToNextTimeout() const { + return timeout_manager_.GetTimeToNextTimeout(); + } + private: const std::string log_prefix_; TimeMs now_ = TimeMs(0); diff --git a/net/dcsctp/socket/packet_sender.cc b/net/dcsctp/socket/packet_sender.cc index 85392e205d..f0134eea9b 100644 --- a/net/dcsctp/socket/packet_sender.cc +++ b/net/dcsctp/socket/packet_sender.cc @@ -21,12 +21,12 @@ PacketSender::PacketSender(DcSctpSocketCallbacks& callbacks, SendPacketStatus)> on_sent_packet) : callbacks_(callbacks), on_sent_packet_(std::move(on_sent_packet)) {} -bool PacketSender::Send(SctpPacket::Builder& builder) { +bool PacketSender::Send(SctpPacket::Builder& builder, bool write_checksum) { if (builder.empty()) { return false; } - std::vector payload = builder.Build(); + std::vector payload = builder.Build(write_checksum); SendPacketStatus status = callbacks_.SendPacketWithStatus(payload); on_sent_packet_(payload, status); diff --git a/net/dcsctp/socket/packet_sender.h b/net/dcsctp/socket/packet_sender.h index 7af4d3c47b..395c2efcba 100644 --- a/net/dcsctp/socket/packet_sender.h +++ b/net/dcsctp/socket/packet_sender.h @@ -25,7 +25,7 @@ class PacketSender { SendPacketStatus)> on_sent_packet); // Sends the packet, and returns true if it was sent successfully. - bool Send(SctpPacket::Builder& builder); + bool Send(SctpPacket::Builder& builder, bool write_checksum = true); private: DcSctpSocketCallbacks& callbacks_; diff --git a/net/dcsctp/socket/state_cookie.cc b/net/dcsctp/socket/state_cookie.cc index 86be77aa34..624d783a3b 100644 --- a/net/dcsctp/socket/state_cookie.cc +++ b/net/dcsctp/socket/state_cookie.cc @@ -42,6 +42,7 @@ std::vector StateCookie::Serialize() { buffer.Store8<30>(capabilities_.reconfig); buffer.Store16<32>(capabilities_.negotiated_maximum_incoming_streams); buffer.Store16<34>(capabilities_.negotiated_maximum_outgoing_streams); + buffer.Store8<36>(capabilities_.zero_checksum); return cookie; } @@ -74,6 +75,7 @@ absl::optional StateCookie::Deserialize( capabilities.reconfig = buffer.Load8<30>() != 0; capabilities.negotiated_maximum_incoming_streams = buffer.Load16<32>(); capabilities.negotiated_maximum_outgoing_streams = buffer.Load16<34>(); + capabilities.zero_checksum = buffer.Load8<36>() != 0; return StateCookie(verification_tag, initial_tsn, a_rwnd, tie_tag, capabilities); diff --git a/net/dcsctp/socket/state_cookie.h b/net/dcsctp/socket/state_cookie.h index a26dbf86f7..34cd6d3690 100644 --- a/net/dcsctp/socket/state_cookie.h +++ b/net/dcsctp/socket/state_cookie.h @@ -27,7 +27,7 @@ namespace dcsctp { // Do not trust anything in it; no pointers or anything like that. class StateCookie { public: - static constexpr size_t kCookieSize = 36; + static constexpr size_t kCookieSize = 37; StateCookie(VerificationTag initiate_tag, TSN initial_tsn, diff --git a/net/dcsctp/socket/state_cookie_test.cc b/net/dcsctp/socket/state_cookie_test.cc index 7d8e1339ee..19be71a1ca 100644 --- a/net/dcsctp/socket/state_cookie_test.cc +++ b/net/dcsctp/socket/state_cookie_test.cc @@ -21,6 +21,7 @@ TEST(StateCookieTest, SerializeAndDeserialize) { Capabilities capabilities = {.partial_reliability = true, .message_interleaving = false, .reconfig = true, + .zero_checksum = true, .negotiated_maximum_incoming_streams = 123, .negotiated_maximum_outgoing_streams = 234}; StateCookie cookie(VerificationTag(123), TSN(456), @@ -36,6 +37,7 @@ TEST(StateCookieTest, SerializeAndDeserialize) { EXPECT_TRUE(deserialized.capabilities().partial_reliability); EXPECT_FALSE(deserialized.capabilities().message_interleaving); EXPECT_TRUE(deserialized.capabilities().reconfig); + EXPECT_TRUE(deserialized.capabilities().zero_checksum); EXPECT_EQ(deserialized.capabilities().negotiated_maximum_incoming_streams, 123); EXPECT_EQ(deserialized.capabilities().negotiated_maximum_outgoing_streams, diff --git a/net/dcsctp/socket/stream_reset_handler.cc b/net/dcsctp/socket/stream_reset_handler.cc index c81b34b626..2094309afe 100644 --- a/net/dcsctp/socket/stream_reset_handler.cc +++ b/net/dcsctp/socket/stream_reset_handler.cc @@ -131,7 +131,7 @@ void StreamResetHandler::HandleReConfig(ReConfigChunk chunk) { } bool StreamResetHandler::ValidateReqSeqNbr( - ReconfigRequestSN req_seq_nbr, + UnwrappedReconfigRequestSn req_seq_nbr, std::vector& responses) { if (req_seq_nbr == last_processed_req_seq_nbr_) { // https://www.rfc-editor.org/rfc/rfc6525.html#section-5.2.1 "If the @@ -143,11 +143,11 @@ bool StreamResetHandler::ValidateReqSeqNbr( << " already processed, returning result=" << ToString(last_processed_req_result_); responses.push_back(ReconfigurationResponseParameter( - req_seq_nbr, last_processed_req_result_)); + req_seq_nbr.Wrap(), last_processed_req_result_)); return false; } - if (req_seq_nbr != ReconfigRequestSN(*last_processed_req_seq_nbr_ + 1)) { + if (req_seq_nbr != last_processed_req_seq_nbr_.next_value()) { // Too old, too new, from wrong association etc. // This is expected to happen when handing over a RTCPeerConnection from one // server to another. The client will notice this and may decide to close @@ -156,7 +156,7 @@ bool StreamResetHandler::ValidateReqSeqNbr( RTC_DLOG(LS_VERBOSE) << log_prefix_ << "req=" << *req_seq_nbr << " bad seq_nbr"; responses.push_back(ReconfigurationResponseParameter( - req_seq_nbr, ResponseResult::kErrorBadSequenceNumber)); + req_seq_nbr.Wrap(), ResponseResult::kErrorBadSequenceNumber)); return false; } @@ -174,16 +174,43 @@ void StreamResetHandler::HandleResetOutgoing( return; } - if (ValidateReqSeqNbr(req->request_sequence_number(), responses)) { - RTC_DLOG(LS_VERBOSE) << log_prefix_ - << "Reset outgoing streams with req_seq_nbr=" - << *req->request_sequence_number(); + UnwrappedReconfigRequestSn request_sn = + incoming_reconfig_request_sn_unwrapper_.Unwrap( + req->request_sequence_number()); - last_processed_req_seq_nbr_ = req->request_sequence_number(); - last_processed_req_result_ = reassembly_queue_->ResetStreams( - *req, data_tracker_->last_cumulative_acked_tsn()); - if (last_processed_req_result_ == ResponseResult::kSuccessPerformed) { + if (ValidateReqSeqNbr(request_sn, responses)) { + last_processed_req_seq_nbr_ = request_sn; + if (data_tracker_->IsLaterThanCumulativeAckedTsn( + req->sender_last_assigned_tsn())) { + // https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2 + // E2) "If the Sender's Last Assigned TSN is greater than the cumulative + // acknowledgment point, then the endpoint MUST enter 'deferred reset + // processing'." + reassembly_queue_->EnterDeferredReset(req->sender_last_assigned_tsn(), + req->stream_ids()); + // "If the endpoint enters 'deferred reset processing', it MUST put a + // Re-configuration Response Parameter into a RE-CONFIG chunk indicating + // 'In progress' and MUST send the RE-CONFIG chunk. + last_processed_req_result_ = ResponseResult::kInProgress; + RTC_DLOG(LS_VERBOSE) << log_prefix_ + << "Reset outgoing; Sender last_assigned=" + << *req->sender_last_assigned_tsn() + << " - not yet reached -> InProgress"; + } else { + // https://datatracker.ietf.org/doc/html/rfc6525#section-5.2.2 + // E3) If no stream numbers are listed in the parameter, then all incoming + // streams MUST be reset to 0 as the next expected SSN. If specific stream + // numbers are listed, then only these specific streams MUST be reset to + // 0, and all other non-listed SSNs remain unchanged. E4: Any queued TSNs + // (queued at step E2) MUST now be released and processed normally. + reassembly_queue_->ResetStreamsAndLeaveDeferredReset(req->stream_ids()); ctx_->callbacks().OnIncomingStreamsReset(req->stream_ids()); + last_processed_req_result_ = ResponseResult::kSuccessPerformed; + + RTC_DLOG(LS_VERBOSE) << log_prefix_ + << "Reset outgoing; Sender last_assigned=" + << *req->sender_last_assigned_tsn() + << " - reached -> SuccessPerformed"; } responses.push_back(ReconfigurationResponseParameter( req->request_sequence_number(), last_processed_req_result_)); @@ -200,10 +227,15 @@ void StreamResetHandler::HandleResetIncoming( "Failed to parse Incoming Reset command"); return; } - if (ValidateReqSeqNbr(req->request_sequence_number(), responses)) { + + UnwrappedReconfigRequestSn request_sn = + incoming_reconfig_request_sn_unwrapper_.Unwrap( + req->request_sequence_number()); + + if (ValidateReqSeqNbr(request_sn, responses)) { responses.push_back(ReconfigurationResponseParameter( req->request_sequence_number(), ResponseResult::kSuccessNothingToDo)); - last_processed_req_seq_nbr_ = req->request_sequence_number(); + last_processed_req_seq_nbr_ = request_sn; } } @@ -278,8 +310,8 @@ absl::optional StreamResetHandler::MakeStreamResetRequest() { return absl::nullopt; } - current_request_.emplace(TSN(*retransmission_queue_->next_tsn() - 1), - retransmission_queue_->GetStreamsReadyToBeReset()); + current_request_.emplace(retransmission_queue_->last_assigned_tsn(), + retransmission_queue_->BeginResetStreams()); reconfig_timer_->set_duration(ctx_->current_rto()); reconfig_timer_->Start(); return MakeReconfigChunk(); @@ -345,7 +377,8 @@ HandoverReadinessStatus StreamResetHandler::GetHandoverReadiness() const { } void StreamResetHandler::AddHandoverState(DcSctpSocketHandoverState& state) { - state.rx.last_completed_reset_req_sn = last_processed_req_seq_nbr_.value(); + state.rx.last_completed_reset_req_sn = + last_processed_req_seq_nbr_.Wrap().value(); state.tx.next_reset_req_sn = next_outgoing_req_seq_nbr_.value(); } diff --git a/net/dcsctp/socket/stream_reset_handler.h b/net/dcsctp/socket/stream_reset_handler.h index 8140903c49..c335130175 100644 --- a/net/dcsctp/socket/stream_reset_handler.h +++ b/net/dcsctp/socket/stream_reset_handler.h @@ -86,9 +86,11 @@ class StreamResetHandler { ? ReconfigRequestSN(handover_state->tx.next_reset_req_sn) : ReconfigRequestSN(*ctx_->my_initial_tsn())), last_processed_req_seq_nbr_( - handover_state ? ReconfigRequestSN( - handover_state->rx.last_completed_reset_req_sn) - : ReconfigRequestSN(*ctx_->peer_initial_tsn() - 1)), + incoming_reconfig_request_sn_unwrapper_.Unwrap( + handover_state + ? ReconfigRequestSN( + handover_state->rx.last_completed_reset_req_sn) + : ReconfigRequestSN(*ctx_->peer_initial_tsn() - 1))), last_processed_req_result_( ReconfigurationResponseParameter::Result::kSuccessNothingToDo) {} @@ -113,6 +115,7 @@ class StreamResetHandler { void AddHandoverState(DcSctpSocketHandoverState& state); private: + using UnwrappedReconfigRequestSn = UnwrappedSequenceNumber; // Represents a stream request operation. There can only be one ongoing at // any time, and a sent request may either succeed, fail or result in the // receiver signaling that it can't process it right now, and then it will be @@ -185,7 +188,7 @@ class StreamResetHandler { // fails to validate, and returns false, it will also add a response to // `responses`. bool ValidateReqSeqNbr( - ReconfigRequestSN req_seq_nbr, + UnwrappedReconfigRequestSn req_seq_nbr, std::vector& responses); // Called when this socket receives an outgoing stream reset request. It might @@ -215,6 +218,7 @@ class StreamResetHandler { DataTracker* data_tracker_; ReassemblyQueue* reassembly_queue_; RetransmissionQueue* retransmission_queue_; + UnwrappedReconfigRequestSn::Unwrapper incoming_reconfig_request_sn_unwrapper_; const std::unique_ptr reconfig_timer_; // The next sequence number for outgoing stream requests. @@ -224,7 +228,7 @@ class StreamResetHandler { absl::optional current_request_; // For incoming requests - last processed request sequence number. - ReconfigRequestSN last_processed_req_seq_nbr_; + UnwrappedReconfigRequestSn last_processed_req_seq_nbr_; // The result from last processed incoming request ReconfigurationResponseParameter::Result last_processed_req_result_; }; diff --git a/net/dcsctp/socket/stream_reset_handler_test.cc b/net/dcsctp/socket/stream_reset_handler_test.cc index 503cc89094..091d717f8a 100644 --- a/net/dcsctp/socket/stream_reset_handler_test.cc +++ b/net/dcsctp/socket/stream_reset_handler_test.cc @@ -20,12 +20,14 @@ #include "api/task_queue/task_queue_base.h" #include "net/dcsctp/common/handover_testing.h" #include "net/dcsctp/common/internal_types.h" +#include "net/dcsctp/packet/chunk/forward_tsn_common.h" #include "net/dcsctp/packet/chunk/reconfig_chunk.h" #include "net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/parameter.h" #include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h" #include "net/dcsctp/public/dcsctp_message.h" +#include "net/dcsctp/public/types.h" #include "net/dcsctp/rx/data_tracker.h" #include "net/dcsctp/rx/reassembly_queue.h" #include "net/dcsctp/socket/mock_context.h" @@ -42,10 +44,12 @@ namespace dcsctp { namespace { using ::testing::IsEmpty; using ::testing::NiceMock; +using ::testing::Property; using ::testing::Return; using ::testing::SizeIs; using ::testing::UnorderedElementsAre; using ResponseResult = ReconfigurationResponseParameter::Result; +using SkippedStream = AnyForwardTsnChunk::SkippedStream; constexpr TSN kMyInitialTsn = MockContext::MyInitialTsn(); constexpr ReconfigRequestSN kMyInitialReqSn = ReconfigRequestSN(*kMyInitialTsn); @@ -289,61 +293,187 @@ TEST_F(StreamResetHandlerTest, ResetStreamsNotDeferred) { } TEST_F(StreamResetHandlerTest, ResetStreamsDeferred) { - DataGeneratorOptions opts; - opts.message_id = MID(0); - reasm_->Add(kPeerInitialTsn, gen_.Ordered({1, 2, 3, 4}, "BE", opts)); + constexpr StreamID kStreamId = StreamID(1); + data_tracker_->Observe(TSN(10)); + reasm_->Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(0)})); - opts.message_id = MID(1); - reasm_->Add(AddTo(kPeerInitialTsn, 1), - gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - - data_tracker_->Observe(kPeerInitialTsn); - data_tracker_->Observe(AddTo(kPeerInitialTsn, 1)); - EXPECT_THAT(reasm_->FlushMessages(), - UnorderedElementsAre( - SctpMessageIs(StreamID(1), PPID(53), kShortPayload), - SctpMessageIs(StreamID(1), PPID(53), kShortPayload))); - - Parameters::Builder builder; - builder.Add(OutgoingSSNResetRequestParameter( - kPeerInitialReqSn, ReconfigRequestSN(3), AddTo(kPeerInitialTsn, 3), - {StreamID(1)})); - - std::vector responses = - HandleAndCatchResponse(ReConfigChunk(builder.Build())); - EXPECT_THAT(responses, SizeIs(1)); - EXPECT_EQ(responses[0].result(), ResponseResult::kInProgress); - - opts.message_id = MID(1); - opts.ppid = PPID(5); - reasm_->Add(AddTo(kPeerInitialTsn, 5), - gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm_->MaybeResetStreamsDeferred(AddTo(kPeerInitialTsn, 1)); - - opts.message_id = MID(0); - opts.ppid = PPID(4); - reasm_->Add(AddTo(kPeerInitialTsn, 4), - gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm_->MaybeResetStreamsDeferred(AddTo(kPeerInitialTsn, 1)); - - opts.message_id = MID(3); - opts.ppid = PPID(3); - reasm_->Add(AddTo(kPeerInitialTsn, 3), - gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm_->MaybeResetStreamsDeferred(AddTo(kPeerInitialTsn, 1)); - - opts.message_id = MID(2); - opts.ppid = PPID(2); - reasm_->Add(AddTo(kPeerInitialTsn, 2), - gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm_->MaybeResetStreamsDeferred(AddTo(kPeerInitialTsn, 5)); + data_tracker_->Observe(TSN(11)); + reasm_->Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(1)})); EXPECT_THAT( reasm_->FlushMessages(), - UnorderedElementsAre(SctpMessageIs(StreamID(1), PPID(2), kShortPayload), - SctpMessageIs(StreamID(1), PPID(3), kShortPayload), - SctpMessageIs(StreamID(1), PPID(4), kShortPayload), - SctpMessageIs(StreamID(1), PPID(5), kShortPayload))); + UnorderedElementsAre(SctpMessageIs(kStreamId, PPID(53), kShortPayload), + SctpMessageIs(kStreamId, PPID(53), kShortPayload))); + + Parameters::Builder builder; + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(10), ReconfigRequestSN(3), TSN(13), {kStreamId})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kInProgress))); + + data_tracker_->Observe(TSN(15)); + reasm_->Add(TSN(15), gen_.Ordered({1, 2, 3, 4}, "BE", + {.mid = MID(1), .ppid = PPID(5)})); + + data_tracker_->Observe(TSN(14)); + reasm_->Add(TSN(14), gen_.Ordered({1, 2, 3, 4}, "BE", + {.mid = MID(0), .ppid = PPID(4)})); + + data_tracker_->Observe(TSN(13)); + reasm_->Add(TSN(13), gen_.Ordered({1, 2, 3, 4}, "BE", + {.mid = MID(3), .ppid = PPID(3)})); + + data_tracker_->Observe(TSN(12)); + reasm_->Add(TSN(12), gen_.Ordered({1, 2, 3, 4}, "BE", + {.mid = MID(2), .ppid = PPID(2)})); + + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(11), ReconfigRequestSN(4), TSN(13), {kStreamId})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kSuccessPerformed))); + + EXPECT_THAT( + reasm_->FlushMessages(), + UnorderedElementsAre(SctpMessageIs(kStreamId, PPID(2), kShortPayload), + SctpMessageIs(kStreamId, PPID(3), kShortPayload), + SctpMessageIs(kStreamId, PPID(4), kShortPayload), + SctpMessageIs(kStreamId, PPID(5), kShortPayload))); +} + +TEST_F(StreamResetHandlerTest, ResetStreamsDeferredOnlySelectedStreams) { + // This test verifies the receiving behavior of receiving messages on + // streams 1, 2 and 3, and receiving a reset request on stream 1, 2, causing + // deferred reset processing. + + // Reset stream 1,2 with "last assigned TSN=12" + Parameters::Builder builder; + builder.Add(OutgoingSSNResetRequestParameter(ReconfigRequestSN(10), + ReconfigRequestSN(3), TSN(12), + {StreamID(1), StreamID(2)})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kInProgress))); + + // TSN 10, SID 1 - before TSN 12 -> deliver + data_tracker_->Observe(TSN(10)); + reasm_->Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(1), + .mid = MID(0), + .ppid = PPID(1001)})); + + // TSN 11, SID 2 - before TSN 12 -> deliver + data_tracker_->Observe(TSN(11)); + reasm_->Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(2), + .mid = MID(0), + .ppid = PPID(1002)})); + + // TSN 12, SID 3 - at TSN 12 -> deliver + data_tracker_->Observe(TSN(12)); + reasm_->Add(TSN(12), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(3), + .mid = MID(0), + .ppid = PPID(1003)})); + + // TSN 13, SID 1 - after TSN 12 and SID=1 -> defer + data_tracker_->Observe(TSN(13)); + reasm_->Add(TSN(13), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(1), + .mid = MID(0), + .ppid = PPID(1004)})); + + // TSN 14, SID 2 - after TSN 12 and SID=2 -> defer + data_tracker_->Observe(TSN(14)); + reasm_->Add(TSN(14), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(2), + .mid = MID(0), + .ppid = PPID(1005)})); + + // TSN 15, SID 3 - after TSN 12, but SID 3 is not reset -> deliver + data_tracker_->Observe(TSN(15)); + reasm_->Add(TSN(15), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(3), + .mid = MID(1), + .ppid = PPID(1006)})); + + EXPECT_THAT(reasm_->FlushMessages(), + UnorderedElementsAre( + SctpMessageIs(StreamID(1), PPID(1001), kShortPayload), + SctpMessageIs(StreamID(2), PPID(1002), kShortPayload), + SctpMessageIs(StreamID(3), PPID(1003), kShortPayload), + SctpMessageIs(StreamID(3), PPID(1006), kShortPayload))); + + builder.Add(OutgoingSSNResetRequestParameter(ReconfigRequestSN(11), + ReconfigRequestSN(3), TSN(13), + {StreamID(1), StreamID(2)})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kSuccessPerformed))); + + EXPECT_THAT(reasm_->FlushMessages(), + UnorderedElementsAre( + SctpMessageIs(StreamID(1), PPID(1004), kShortPayload), + SctpMessageIs(StreamID(2), PPID(1005), kShortPayload))); +} + +TEST_F(StreamResetHandlerTest, ResetStreamsDefersForwardTsn) { + // This test verifies that FORWARD-TSNs are deferred if they want to move + // the cumulative ack TSN point past sender's last assigned TSN. + static constexpr StreamID kStreamId = StreamID(42); + + // Simulate sender sends: + // * TSN 10 (SSN=0, BE, lost), + // * TSN 11 (SSN=1, BE, lost), + // * TSN 12 (SSN=2, BE, lost) + // * RESET THE STREAM + // * TSN 13 (SSN=0, B, received) + // * TSN 14 (SSN=0, E, lost), + // * TSN 15 (SSN=1, BE, received) + Parameters::Builder builder; + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(10), ReconfigRequestSN(3), TSN(12), {kStreamId})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kInProgress))); + + // TSN 13, B, after TSN=12 -> defer + data_tracker_->Observe(TSN(13)); + reasm_->Add(TSN(13), + gen_.Ordered( + {1, 2, 3, 4}, "B", + {.stream_id = kStreamId, .mid = MID(0), .ppid = PPID(1004)})); + + // TSN 15, BE, after TSN=12 -> defer + data_tracker_->Observe(TSN(15)); + reasm_->Add(TSN(15), + gen_.Ordered( + {1, 2, 3, 4}, "BE", + {.stream_id = kStreamId, .mid = MID(1), .ppid = PPID(1005)})); + + // Time passes, sender decides to send FORWARD-TSN up to the RESET. + data_tracker_->HandleForwardTsn(TSN(12)); + reasm_->HandleForwardTsn( + TSN(12), std::vector({SkippedStream(kStreamId, SSN(2))})); + + // The receiver sends a SACK in response to that. The stream hasn't been + // reset yet, but the sender now decides that TSN=13-14 is to be skipped. + // As this has a TSN 14, after TSN=12 -> defer it. + data_tracker_->HandleForwardTsn(TSN(14)); + reasm_->HandleForwardTsn( + TSN(14), std::vector({SkippedStream(kStreamId, SSN(0))})); + + // Reset the stream -> deferred TSNs should be re-added. + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(11), ReconfigRequestSN(3), TSN(12), {kStreamId})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kSuccessPerformed))); + + EXPECT_THAT(reasm_->FlushMessages(), + UnorderedElementsAre( + SctpMessageIs(kStreamId, PPID(1005), kShortPayload))); } TEST_F(StreamResetHandlerTest, SendOutgoingRequestDirectly) { @@ -765,9 +895,8 @@ TEST_F(StreamResetHandlerTest, PerformCloseAfterOneFirstFailing) { // Let the socket receive the TSN. DataGeneratorOptions opts; - opts.message_id = MID(0); + opts.mid = MID(0); reasm_->Add(kPeerInitialTsn, gen_.Ordered({1, 2, 3, 4}, "BE", opts)); - reasm_->MaybeResetStreamsDeferred(kPeerInitialTsn); data_tracker_->Observe(kPeerInitialTsn); // And emulate that time has passed, and the peer retries the stream reset, diff --git a/net/dcsctp/socket/transmission_control_block.cc b/net/dcsctp/socket/transmission_control_block.cc index 1dcf394813..0621b48e80 100644 --- a/net/dcsctp/socket/transmission_control_block.cc +++ b/net/dcsctp/socket/transmission_control_block.cc @@ -25,6 +25,7 @@ #include "net/dcsctp/packet/chunk/sack_chunk.h" #include "net/dcsctp/packet/sctp_packet.h" #include "net/dcsctp/public/dcsctp_options.h" +#include "net/dcsctp/public/types.h" #include "net/dcsctp/rx/data_tracker.h" #include "net/dcsctp/rx/reassembly_queue.h" #include "net/dcsctp/socket/capabilities.h" @@ -63,7 +64,9 @@ TransmissionControlBlock::TransmissionControlBlock( TimerOptions(options.rto_initial, TimerBackoffAlgorithm::kExponential, /*max_restarts=*/absl::nullopt, - options.max_timer_backoff_duration))), + options.max_timer_backoff_duration.has_value() + ? *options.max_timer_backoff_duration + : DurationMs::InfiniteDuration()))), delayed_ack_timer_(timer_manager_.CreateTimer( "delayed-ack", absl::bind_front(&TransmissionControlBlock::OnDelayedAckTimerExpiry, @@ -71,7 +74,7 @@ TransmissionControlBlock::TransmissionControlBlock( TimerOptions(options.delayed_ack_max_timeout, TimerBackoffAlgorithm::kExponential, /*max_restarts=*/0, - /*max_backoff_duration=*/absl::nullopt, + /*max_backoff_duration=*/DurationMs::InfiniteDuration(), webrtc::TaskQueueBase::DelayPrecision::kHigh))), my_verification_tag_(my_verification_tag), my_initial_tsn_(my_initial_tsn), @@ -163,7 +166,7 @@ void TransmissionControlBlock::MaybeSendForwardTsn(SctpPacket::Builder& builder, } else { builder.Add(retransmission_queue_.CreateForwardTsn()); } - packet_sender_.Send(builder); + Send(builder); // https://datatracker.ietf.org/doc/html/rfc3758 // "IMPLEMENTATION NOTE: An implementation may wish to limit the number of // duplicate FORWARD TSN chunks it sends by ... waiting a full RTT before @@ -198,7 +201,7 @@ void TransmissionControlBlock::MaybeSendFastRetransmit() { builder.Add(DataChunk(tsn, std::move(data), false)); } } - packet_sender_.Send(builder); + Send(builder); } void TransmissionControlBlock::SendBufferedPackets(SctpPacket::Builder& builder, @@ -245,7 +248,13 @@ void TransmissionControlBlock::SendBufferedPackets(SctpPacket::Builder& builder, } } - if (!packet_sender_.Send(builder)) { + // https://www.ietf.org/archive/id/draft-tuexen-tsvwg-sctp-zero-checksum-02.html#section-4.2 + // "When an end point sends a packet containing a COOKIE ECHO chunk, it MUST + // include a correct CRC32c checksum in the packet containing the COOKIE + // ECHO chunk." + bool write_checksum = + !capabilities_.zero_checksum || cookie_echo_chunk_.has_value(); + if (!packet_sender_.Send(builder, write_checksum)) { break; } @@ -274,6 +283,9 @@ std::string TransmissionControlBlock::ToString() const { if (capabilities_.reconfig) { sb << "Reconfig,"; } + if (capabilities_.zero_checksum) { + sb << "ZeroChecksum,"; + } sb << " max_in=" << capabilities_.negotiated_maximum_incoming_streams; sb << " max_out=" << capabilities_.negotiated_maximum_outgoing_streams; @@ -294,6 +306,7 @@ void TransmissionControlBlock::AddHandoverState( state.capabilities.partial_reliability = capabilities_.partial_reliability; state.capabilities.message_interleaving = capabilities_.message_interleaving; state.capabilities.reconfig = capabilities_.reconfig; + state.capabilities.zero_checksum = capabilities_.zero_checksum; state.capabilities.negotiated_maximum_incoming_streams = capabilities_.negotiated_maximum_incoming_streams; state.capabilities.negotiated_maximum_outgoing_streams = diff --git a/net/dcsctp/socket/transmission_control_block.h b/net/dcsctp/socket/transmission_control_block.h index fc66fcc857..46a39d5a7b 100644 --- a/net/dcsctp/socket/transmission_control_block.h +++ b/net/dcsctp/socket/transmission_control_block.h @@ -80,7 +80,8 @@ class TransmissionControlBlock : public Context { return tx_error_counter_.IsExhausted(); } void Send(SctpPacket::Builder& builder) override { - packet_sender_.Send(builder); + packet_sender_.Send(builder, + /*write_checksum=*/!capabilities_.zero_checksum); } // Other accessors diff --git a/net/dcsctp/socket/transmission_control_block_test.cc b/net/dcsctp/socket/transmission_control_block_test.cc index 40aea58d4b..6106fbb309 100644 --- a/net/dcsctp/socket/transmission_control_block_test.cc +++ b/net/dcsctp/socket/transmission_control_block_test.cc @@ -92,6 +92,7 @@ TEST_F(TransmissionControlBlockTest, LogsAllCapabilitiesInToSring) { capabilities_.negotiated_maximum_outgoing_streams = 2000; capabilities_.message_interleaving = true; capabilities_.partial_reliability = true; + capabilities_.zero_checksum = true; capabilities_.reconfig = true; TransmissionControlBlock tcb( @@ -99,9 +100,10 @@ TEST_F(TransmissionControlBlockTest, LogsAllCapabilitiesInToSring) { kMyVerificationTag, kMyInitialTsn, kPeerVerificationTag, kPeerInitialTsn, kArwnd, kTieTag, sender_, on_connection_established.AsStdFunction()); - EXPECT_EQ(tcb.ToString(), - "verification_tag=000001c8, last_cumulative_ack=999, " - "capabilities=PR,IL,Reconfig, max_in=1000 max_out=2000"); + EXPECT_EQ( + tcb.ToString(), + "verification_tag=000001c8, last_cumulative_ack=999, " + "capabilities=PR,IL,Reconfig,ZeroChecksum, max_in=1000 max_out=2000"); } TEST_F(TransmissionControlBlockTest, IsInitiallyHandoverReady) { diff --git a/net/dcsctp/testing/data_generator.cc b/net/dcsctp/testing/data_generator.cc index e4f9f91384..417695c9d0 100644 --- a/net/dcsctp/testing/data_generator.cc +++ b/net/dcsctp/testing/data_generator.cc @@ -32,13 +32,13 @@ Data DataGenerator::Ordered(std::vector payload, } else { fsn_ = FSN(*fsn_ + 1); } - MID message_id = opts.message_id.value_or(message_id_); - Data ret = Data(opts.stream_id, SSN(static_cast(*message_id)), - message_id, fsn_, opts.ppid, std::move(payload), is_beginning, - is_end, IsUnordered(false)); + MID mid = opts.mid.value_or(mid_); + Data ret = Data(opts.stream_id, SSN(static_cast(*mid)), mid, fsn_, + opts.ppid, std::move(payload), is_beginning, is_end, + IsUnordered(false)); if (is_end) { - message_id_ = MID(*message_id + 1); + mid_ = MID(*mid + 1); } return ret; } @@ -54,11 +54,11 @@ Data DataGenerator::Unordered(std::vector payload, } else { fsn_ = FSN(*fsn_ + 1); } - MID message_id = opts.message_id.value_or(message_id_); - Data ret = Data(opts.stream_id, SSN(0), message_id, fsn_, kPpid, - std::move(payload), is_beginning, is_end, IsUnordered(true)); + MID mid = opts.mid.value_or(mid_); + Data ret = Data(opts.stream_id, SSN(0), mid, fsn_, kPpid, std::move(payload), + is_beginning, is_end, IsUnordered(true)); if (is_end) { - message_id_ = MID(*message_id + 1); + mid_ = MID(*mid + 1); } return ret; } diff --git a/net/dcsctp/testing/data_generator.h b/net/dcsctp/testing/data_generator.h index f917c740a7..52f98dd1cb 100644 --- a/net/dcsctp/testing/data_generator.h +++ b/net/dcsctp/testing/data_generator.h @@ -23,15 +23,14 @@ namespace dcsctp { struct DataGeneratorOptions { StreamID stream_id = StreamID(1); - absl::optional message_id = absl::nullopt; + absl::optional mid = absl::nullopt; PPID ppid = PPID(53); }; // Generates Data with correct sequence numbers, and used only in unit tests. class DataGenerator { public: - explicit DataGenerator(MID start_message_id = MID(0)) - : message_id_(start_message_id) {} + explicit DataGenerator(MID start_mid = MID(0)) : mid_(start_mid) {} // Generates ordered "data" with the provided `payload` and flags, which can // contain "B" for setting the "is_beginning" flag, and/or "E" for setting the @@ -48,10 +47,10 @@ class DataGenerator { DataGeneratorOptions opts = {}); // Resets the Message ID identifier - simulating a "stream reset". - void ResetStream() { message_id_ = MID(0); } + void ResetStream() { mid_ = MID(0); } private: - MID message_id_; + MID mid_; FSN fsn_ = FSN(0); }; } // namespace dcsctp diff --git a/net/dcsctp/timer/fake_timeout.h b/net/dcsctp/timer/fake_timeout.h index 74ffe5af29..4621b2ce83 100644 --- a/net/dcsctp/timer/fake_timeout.h +++ b/net/dcsctp/timer/fake_timeout.h @@ -20,6 +20,7 @@ #include "absl/types/optional.h" #include "api/task_queue/task_queue_base.h" #include "net/dcsctp/public/timeout.h" +#include "net/dcsctp/public/types.h" #include "rtc_base/checks.h" #include "rtc_base/containers/flat_set.h" @@ -53,6 +54,7 @@ class FakeTimeout : public Timeout { } TimeoutID timeout_id() const { return timeout_id_; } + TimeMs expiry() const { return expiry_; } private: const std::function get_time_; @@ -97,6 +99,19 @@ class FakeTimeoutManager { return absl::nullopt; } + DurationMs GetTimeToNextTimeout() const { + TimeMs next_expiry = TimeMs::InfiniteFuture(); + for (const FakeTimeout* timer : timers_) { + if (timer->expiry() < next_expiry) { + next_expiry = timer->expiry(); + } + } + TimeMs now = get_time_(); + return next_expiry != TimeMs::InfiniteFuture() && next_expiry >= now + ? next_expiry - now + : DurationMs::InfiniteDuration(); + } + private: const std::function get_time_; webrtc::flat_set timers_; diff --git a/net/dcsctp/timer/timer.cc b/net/dcsctp/timer/timer.cc index bde07638a5..208f26fdf9 100644 --- a/net/dcsctp/timer/timer.cc +++ b/net/dcsctp/timer/timer.cc @@ -33,19 +33,18 @@ DurationMs GetBackoffDuration(const TimerOptions& options, case TimerBackoffAlgorithm::kFixed: return base_duration; case TimerBackoffAlgorithm::kExponential: { - int32_t duration_ms = *base_duration; + DurationMs duration = base_duration; - while (expiration_count > 0 && duration_ms < *Timer::kMaxTimerDuration) { - duration_ms *= 2; + while (expiration_count > 0 && duration < Timer::kMaxTimerDuration) { + duration *= 2; --expiration_count; - if (options.max_backoff_duration.has_value() && - duration_ms > **options.max_backoff_duration) { - return *options.max_backoff_duration; + if (duration > options.max_backoff_duration) { + return options.max_backoff_duration; } } - return DurationMs(std::min(duration_ms, *Timer::kMaxTimerDuration)); + return DurationMs(std::min(duration, Timer::kMaxTimerDuration)); } } } diff --git a/net/dcsctp/timer/timer.h b/net/dcsctp/timer/timer.h index 31b496dc81..95aae570c8 100644 --- a/net/dcsctp/timer/timer.h +++ b/net/dcsctp/timer/timer.h @@ -47,12 +47,14 @@ struct TimerOptions { TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm, absl::optional max_restarts) - : TimerOptions(duration, backoff_algorithm, max_restarts, absl::nullopt) { - } + : TimerOptions(duration, + backoff_algorithm, + max_restarts, + DurationMs::InfiniteDuration()) {} TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm, absl::optional max_restarts, - absl::optional max_backoff_duration) + DurationMs max_backoff_duration) : TimerOptions(duration, backoff_algorithm, max_restarts, @@ -61,7 +63,7 @@ struct TimerOptions { TimerOptions(DurationMs duration, TimerBackoffAlgorithm backoff_algorithm, absl::optional max_restarts, - absl::optional max_backoff_duration, + DurationMs max_backoff_duration, webrtc::TaskQueueBase::DelayPrecision precision) : duration(duration), backoff_algorithm(backoff_algorithm), @@ -78,7 +80,7 @@ struct TimerOptions { // or absl::nullopt if there is no limit. const absl::optional max_restarts; // The maximum timeout value for exponential backoff. - const absl::optional max_backoff_duration; + const DurationMs max_backoff_duration; // The precision of the webrtc::TaskQueueBase used for scheduling. const webrtc::TaskQueueBase::DelayPrecision precision; }; diff --git a/net/dcsctp/timer/timer_test.cc b/net/dcsctp/timer/timer_test.cc index 4aebe65b48..93876160bb 100644 --- a/net/dcsctp/timer/timer_test.cc +++ b/net/dcsctp/timer/timer_test.cc @@ -442,7 +442,7 @@ TEST(TimerManagerTest, TimerManagerPassesPrecisionToCreateTimeoutMethod) { manager.CreateTimer( "test_timer", []() { return absl::optional(); }, TimerOptions(DurationMs(123), TimerBackoffAlgorithm::kExponential, - absl::nullopt, absl::nullopt, + absl::nullopt, DurationMs::InfiniteDuration(), webrtc::TaskQueueBase::DelayPrecision::kHigh)); EXPECT_EQ(create_timer_precison, webrtc::TaskQueueBase::DelayPrecision::kHigh); @@ -450,7 +450,7 @@ TEST(TimerManagerTest, TimerManagerPassesPrecisionToCreateTimeoutMethod) { manager.CreateTimer( "test_timer", []() { return absl::optional(); }, TimerOptions(DurationMs(123), TimerBackoffAlgorithm::kExponential, - absl::nullopt, absl::nullopt, + absl::nullopt, DurationMs::InfiniteDuration(), webrtc::TaskQueueBase::DelayPrecision::kLow)); EXPECT_EQ(create_timer_precison, webrtc::TaskQueueBase::DelayPrecision::kLow); } diff --git a/net/dcsctp/tx/BUILD.gn b/net/dcsctp/tx/BUILD.gn index 43fd41639e..5547ffa870 100644 --- a/net/dcsctp/tx/BUILD.gn +++ b/net/dcsctp/tx/BUILD.gn @@ -29,6 +29,7 @@ rtc_library("rr_send_queue") { "../../../rtc_base:checks", "../../../rtc_base:logging", "../../../rtc_base/containers:flat_map", + "../common:internal_types", "../common:str_join", "../packet:data", "../public:socket", @@ -104,6 +105,8 @@ rtc_library("outstanding_data") { "../../../api:array_view", "../../../rtc_base:checks", "../../../rtc_base:logging", + "../../../rtc_base/containers:flat_set", + "../common:internal_types", "../common:math", "../common:sequence_numbers", "../common:str_join", @@ -183,6 +186,7 @@ if (rtc_include_tests) { "../../../rtc_base:gunit_helpers", "../../../test:test_support", "../common:handover_testing", + "../common:internal_types", "../common:math", "../common:sequence_numbers", "../packet:chunk", diff --git a/net/dcsctp/tx/mock_send_queue.h b/net/dcsctp/tx/mock_send_queue.h index 0c8f5d141d..04921866ae 100644 --- a/net/dcsctp/tx/mock_send_queue.h +++ b/net/dcsctp/tx/mock_send_queue.h @@ -34,7 +34,7 @@ class MockSendQueue : public SendQueue { (override)); MOCK_METHOD(bool, Discard, - (IsUnordered unordered, StreamID stream_id, MID message_id), + (StreamID stream_id, OutgoingMessageId message_id), (override)); MOCK_METHOD(void, PrepareResetStream, (StreamID stream_id), (override)); MOCK_METHOD(bool, HasStreamsReadyToBeReset, (), (const, override)); diff --git a/net/dcsctp/tx/outstanding_data.cc b/net/dcsctp/tx/outstanding_data.cc index 4f1e863056..c2706bd0d2 100644 --- a/net/dcsctp/tx/outstanding_data.cc +++ b/net/dcsctp/tx/outstanding_data.cc @@ -63,6 +63,8 @@ void OutstandingData::Item::MarkAsRetransmitted() { } void OutstandingData::Item::Abandon() { + RTC_DCHECK(expires_at_ != TimeMs::InfiniteFuture() || + max_retransmissions_ != MaxRetransmits::NoLimit()); lifecycle_ = Lifecycle::kAbandoned; } @@ -159,6 +161,9 @@ void OutstandingData::RemoveAcked(UnwrappedTSN cumulative_tsn_ack, outstanding_data_.erase(outstanding_data_.begin(), first_unacked); last_cumulative_tsn_ack_ = cumulative_tsn_ack; + stream_reset_breakpoint_tsns_.erase(stream_reset_breakpoint_tsns_.begin(), + stream_reset_breakpoint_tsns_.upper_bound( + cumulative_tsn_ack.next_value())); } void OutstandingData::AckGapBlocks( @@ -249,6 +254,7 @@ bool OutstandingData::NackItem(UnwrappedTSN tsn, RTC_DLOG(LS_VERBOSE) << *tsn.Wrap() << " marked for retransmission"; break; case Item::NackAction::kAbandon: + RTC_DLOG(LS_VERBOSE) << *tsn.Wrap() << " Nacked, resulted in abandoning"; AbandonAllFor(item); break; } @@ -257,8 +263,7 @@ bool OutstandingData::NackItem(UnwrappedTSN tsn, void OutstandingData::AbandonAllFor(const Item& item) { // Erase all remaining chunks from the producer, if any. - if (discard_from_send_queue_(item.data().is_unordered, item.data().stream_id, - item.data().message_id)) { + if (discard_from_send_queue_(item.data().stream_id, item.message_id())) { // There were remaining chunks to be produced for this message. Since the // receiver may have already received all chunks (up till now) for this // message, we can't just FORWARD-TSN to the last fragment in this @@ -269,17 +274,17 @@ void OutstandingData::AbandonAllFor(const Item& item) { // TSN in the sent FORWARD-TSN. UnwrappedTSN tsn = next_tsn_; next_tsn_.Increment(); - Data message_end(item.data().stream_id, item.data().ssn, - item.data().message_id, item.data().fsn, item.data().ppid, - std::vector(), Data::IsBeginning(false), - Data::IsEnd(true), item.data().is_unordered); + Data message_end(item.data().stream_id, item.data().ssn, item.data().mid, + item.data().fsn, item.data().ppid, std::vector(), + Data::IsBeginning(false), Data::IsEnd(true), + item.data().is_unordered); Item& added_item = outstanding_data_ .emplace(std::piecewise_construct, std::forward_as_tuple(tsn), - std::forward_as_tuple(std::move(message_end), TimeMs(0), - MaxRetransmits::NoLimit(), - TimeMs::InfiniteFuture(), - LifecycleId::NotSet())) + std::forward_as_tuple( + item.message_id(), std::move(message_end), TimeMs(0), + MaxRetransmits(0), TimeMs::InfiniteFuture(), + LifecycleId::NotSet())) .first->second; // The added chunk shouldn't be included in `outstanding_bytes`, so set it // as acked. @@ -291,8 +296,7 @@ void OutstandingData::AbandonAllFor(const Item& item) { for (auto& [tsn, other] : outstanding_data_) { if (!other.is_abandoned() && other.data().stream_id == item.data().stream_id && - other.data().is_unordered == item.data().is_unordered && - other.data().message_id == item.data().message_id) { + other.message_id() == item.message_id()) { RTC_DLOG(LS_VERBOSE) << "Marking chunk " << *tsn.Wrap() << " as abandoned"; if (other.should_be_retransmitted()) { @@ -375,7 +379,7 @@ void OutstandingData::ExpireOutstandingChunks(TimeMs now) { // Already abandoned. } else if (item.is_nacked() && item.has_expired(now)) { RTC_DLOG(LS_VERBOSE) << "Marking nacked chunk " << *tsn.Wrap() - << " and message " << *item.data().message_id + << " and message " << *item.data().mid << " as expired"; AbandonAllFor(item); } else { @@ -392,6 +396,7 @@ UnwrappedTSN OutstandingData::highest_outstanding_tsn() const { } absl::optional OutstandingData::Insert( + OutgoingMessageId message_id, const Data& data, TimeMs time_sent, MaxRetransmits max_retransmissions, @@ -406,9 +411,9 @@ absl::optional OutstandingData::Insert( ++outstanding_items_; auto it = outstanding_data_ .emplace(std::piecewise_construct, std::forward_as_tuple(tsn), - std::forward_as_tuple(data.Clone(), time_sent, - max_retransmissions, expires_at, - lifecycle_id)) + std::forward_as_tuple(message_id, data.Clone(), + time_sent, max_retransmissions, + expires_at, lifecycle_id)) .first; if (it->second.has_expired(time_sent)) { @@ -416,7 +421,7 @@ absl::optional OutstandingData::Insert( // queue. RTC_DLOG(LS_VERBOSE) << "Marking freshly produced chunk " << *it->first.Wrap() << " and message " - << *it->second.data().message_id << " as expired"; + << *it->second.data().mid << " as expired"; AbandonAllFor(it->second); RTC_DCHECK(IsConsistent()); return absl::nullopt; @@ -487,7 +492,8 @@ ForwardTsnChunk OutstandingData::CreateForwardTsn() const { UnwrappedTSN new_cumulative_ack = last_cumulative_tsn_ack_; for (const auto& [tsn, item] : outstanding_data_) { - if ((tsn != new_cumulative_ack.next_value()) || !item.is_abandoned()) { + if (stream_reset_breakpoint_tsns_.contains(tsn) || + (tsn != new_cumulative_ack.next_value()) || !item.is_abandoned()) { break; } new_cumulative_ack = tsn; @@ -510,22 +516,23 @@ IForwardTsnChunk OutstandingData::CreateIForwardTsn() const { UnwrappedTSN new_cumulative_ack = last_cumulative_tsn_ack_; for (const auto& [tsn, item] : outstanding_data_) { - if ((tsn != new_cumulative_ack.next_value()) || !item.is_abandoned()) { + if (stream_reset_breakpoint_tsns_.contains(tsn) || + (tsn != new_cumulative_ack.next_value()) || !item.is_abandoned()) { break; } new_cumulative_ack = tsn; std::pair stream_id = std::make_pair(item.data().is_unordered, item.data().stream_id); - if (item.data().message_id > skipped_per_stream[stream_id]) { - skipped_per_stream[stream_id] = item.data().message_id; + if (item.data().mid > skipped_per_stream[stream_id]) { + skipped_per_stream[stream_id] = item.data().mid; } } std::vector skipped_streams; skipped_streams.reserve(skipped_per_stream.size()); - for (const auto& [stream, message_id] : skipped_per_stream) { - skipped_streams.emplace_back(stream.first, stream.second, message_id); + for (const auto& [stream, mid] : skipped_per_stream) { + skipped_streams.emplace_back(stream.first, stream.second, mid); } return IForwardTsnChunk(new_cumulative_ack.Wrap(), @@ -540,4 +547,8 @@ void OutstandingData::ResetSequenceNumbers(UnwrappedTSN next_tsn, next_tsn_ = next_tsn; last_cumulative_tsn_ack_ = last_cumulative_tsn; } + +void OutstandingData::BeginResetStreams() { + stream_reset_breakpoint_tsns_.insert(next_tsn_); +} } // namespace dcsctp diff --git a/net/dcsctp/tx/outstanding_data.h b/net/dcsctp/tx/outstanding_data.h index 6b4b7121fb..f8e939661d 100644 --- a/net/dcsctp/tx/outstanding_data.h +++ b/net/dcsctp/tx/outstanding_data.h @@ -16,12 +16,14 @@ #include #include "absl/types/optional.h" +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/common/sequence_numbers.h" #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h" #include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h" #include "net/dcsctp/packet/chunk/sack_chunk.h" #include "net/dcsctp/packet/data.h" #include "net/dcsctp/public/types.h" +#include "rtc_base/containers/flat_set.h" namespace dcsctp { @@ -74,7 +76,7 @@ class OutstandingData { size_t data_chunk_header_size, UnwrappedTSN next_tsn, UnwrappedTSN last_cumulative_tsn_ack, - std::function discard_from_send_queue) + std::function discard_from_send_queue) : data_chunk_header_size_(data_chunk_header_size), next_tsn_(next_tsn), last_cumulative_tsn_ack_(last_cumulative_tsn_ack), @@ -127,6 +129,7 @@ class OutstandingData { // parameters. Returns the TSN if the item was actually added and scheduled to // be sent, and absl::nullopt if it shouldn't be sent. absl::optional Insert( + OutgoingMessageId message_id, const Data& data, TimeMs time_sent, MaxRetransmits max_retransmissions = MaxRetransmits::NoLimit(), @@ -159,6 +162,10 @@ class OutstandingData { void ResetSequenceNumbers(UnwrappedTSN next_tsn, UnwrappedTSN last_cumulative_tsn); + // Called when an outgoing stream reset is sent, marking the last assigned TSN + // as a breakpoint that a FORWARD-TSN shouldn't cross. + void BeginResetStreams(); + private: // A fragmented message's DATA chunk while in the retransmission queue, and // its associated metadata. @@ -170,12 +177,14 @@ class OutstandingData { kAbandon, }; - Item(Data data, + Item(OutgoingMessageId message_id, + Data data, TimeMs time_sent, MaxRetransmits max_retransmissions, TimeMs expires_at, LifecycleId lifecycle_id) - : time_sent_(time_sent), + : message_id_(message_id), + time_sent_(time_sent), max_retransmissions_(max_retransmissions), expires_at_(expires_at), lifecycle_id_(lifecycle_id), @@ -184,6 +193,8 @@ class OutstandingData { Item(const Item&) = delete; Item& operator=(const Item&) = delete; + OutgoingMessageId message_id() const { return message_id_; } + TimeMs time_sent() const { return time_sent_; } const Data& data() const { return data_; } @@ -244,6 +255,8 @@ class OutstandingData { // NOTE: This data structure has been optimized for size, by ordering fields // to avoid unnecessary padding. + const OutgoingMessageId message_id_; + // When the packet was sent, and placed in this queue. const TimeMs time_sent_; // If the message was sent with a maximum number of retransmissions, this is @@ -333,7 +346,7 @@ class OutstandingData { // The last cumulative TSN ack number. UnwrappedTSN last_cumulative_tsn_ack_; // Callback when to discard items from the send queue. - std::function discard_from_send_queue_; + std::function discard_from_send_queue_; std::map outstanding_data_; // The number of bytes that are in-flight (sent but not yet acked or nacked). @@ -345,6 +358,10 @@ class OutstandingData { std::set to_be_fast_retransmitted_; // Data chunks that are to be retransmitted. std::set to_be_retransmitted_; + // Wben a stream reset has begun, the "next TSN to assign" is added to this + // set, and removed when the cum-ack TSN reaches it. This is used to limit a + // FORWARD-TSN to reset streams past a "stream reset last assigned TSN". + webrtc::flat_set stream_reset_breakpoint_tsns_; }; } // namespace dcsctp #endif // NET_DCSCTP_TX_OUTSTANDING_DATA_H_ diff --git a/net/dcsctp/tx/outstanding_data_test.cc b/net/dcsctp/tx/outstanding_data_test.cc index cdca40cfef..b8c2e593a1 100644 --- a/net/dcsctp/tx/outstanding_data_test.cc +++ b/net/dcsctp/tx/outstanding_data_test.cc @@ -12,10 +12,12 @@ #include #include "absl/types/optional.h" +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/common/math.h" #include "net/dcsctp/common/sequence_numbers.h" #include "net/dcsctp/packet/chunk/data_chunk.h" #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h" +#include "net/dcsctp/public/dcsctp_socket.h" #include "net/dcsctp/public/types.h" #include "net/dcsctp/testing/data_generator.h" #include "net/dcsctp/testing/testing_macros.h" @@ -27,13 +29,17 @@ namespace { using ::testing::MockFunction; using State = ::dcsctp::OutstandingData::State; using ::testing::_; +using ::testing::AllOf; using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::Pair; +using ::testing::Property; using ::testing::Return; using ::testing::StrictMock; +using ::testing::UnorderedElementsAre; constexpr TimeMs kNow(42); +constexpr OutgoingMessageId kMessageId = OutgoingMessageId(17); class OutstandingDataTest : public testing::Test { protected: @@ -46,7 +52,7 @@ class OutstandingDataTest : public testing::Test { UnwrappedTSN::Unwrapper unwrapper_; DataGenerator gen_; - StrictMock> on_discard_; + StrictMock> on_discard_; OutstandingData buf_; }; @@ -64,8 +70,8 @@ TEST_F(OutstandingDataTest, HasInitialState) { } TEST_F(OutstandingDataTest, InsertChunk) { - ASSERT_HAS_VALUE_AND_ASSIGN(UnwrappedTSN tsn, - buf_.Insert(gen_.Ordered({1}, "BE"), kNow)); + ASSERT_HAS_VALUE_AND_ASSIGN( + UnwrappedTSN tsn, buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow)); EXPECT_EQ(tsn.Wrap(), TSN(10)); @@ -81,7 +87,7 @@ TEST_F(OutstandingDataTest, InsertChunk) { } TEST_F(OutstandingDataTest, AcksSingleChunk) { - buf_.Insert(gen_.Ordered({1}, "BE"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow); OutstandingData::AckInfo ack = buf_.HandleSack(unwrapper_.Unwrap(TSN(10)), {}, false); @@ -100,7 +106,7 @@ TEST_F(OutstandingDataTest, AcksSingleChunk) { } TEST_F(OutstandingDataTest, AcksPreviousChunkDoesntUpdate) { - buf_.Insert(gen_.Ordered({1}, "BE"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow); buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), {}, false); EXPECT_EQ(buf_.outstanding_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1)); @@ -115,8 +121,8 @@ TEST_F(OutstandingDataTest, AcksPreviousChunkDoesntUpdate) { } TEST_F(OutstandingDataTest, AcksAndNacksWithGapAckBlocks) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow); - buf_.Insert(gen_.Ordered({1}, "E"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow); std::vector gab = {SackChunk::GapAckBlock(2, 2)}; OutstandingData::AckInfo ack = @@ -138,8 +144,8 @@ TEST_F(OutstandingDataTest, AcksAndNacksWithGapAckBlocks) { } TEST_F(OutstandingDataTest, NacksThreeTimesWithSameTsnDoesntRetransmit) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow); - buf_.Insert(gen_.Ordered({1}, "E"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow); std::vector gab1 = {SackChunk::GapAckBlock(2, 2)}; EXPECT_FALSE( @@ -161,10 +167,10 @@ TEST_F(OutstandingDataTest, NacksThreeTimesWithSameTsnDoesntRetransmit) { } TEST_F(OutstandingDataTest, NacksThreeTimesResultsInRetransmission) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, "E"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow); std::vector gab1 = {SackChunk::GapAckBlock(2, 2)}; EXPECT_FALSE( @@ -199,10 +205,10 @@ TEST_F(OutstandingDataTest, NacksThreeTimesResultsInRetransmission) { TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoning) { static constexpr MaxRetransmits kMaxRetransmissions(0); - buf_.Insert(gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, "E"), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow, kMaxRetransmissions); std::vector gab1 = {SackChunk::GapAckBlock(2, 2)}; EXPECT_FALSE( @@ -214,7 +220,7 @@ TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoning) { buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab2, false).has_packet_loss); EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); std::vector gab3 = {SackChunk::GapAckBlock(2, 4)}; OutstandingData::AckInfo ack = @@ -235,10 +241,10 @@ TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoning) { TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoningWithPlaceholder) { static constexpr MaxRetransmits kMaxRetransmissions(0); - buf_.Insert(gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); std::vector gab1 = {SackChunk::GapAckBlock(2, 2)}; EXPECT_FALSE( @@ -250,7 +256,7 @@ TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoningWithPlaceholder) { buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab2, false).has_packet_loss); EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(true)); std::vector gab3 = {SackChunk::GapAckBlock(2, 4)}; OutstandingData::AckInfo ack = @@ -272,17 +278,19 @@ TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoningWithPlaceholder) { TEST_F(OutstandingDataTest, ExpiresChunkBeforeItIsInserted) { static constexpr TimeMs kExpiresAt = kNow + DurationMs(1); - EXPECT_TRUE(buf_.Insert(gen_.Ordered({1}, "B"), kNow, + EXPECT_TRUE(buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, MaxRetransmits::NoLimit(), kExpiresAt) .has_value()); - EXPECT_TRUE(buf_.Insert(gen_.Ordered({1}, ""), kNow + DurationMs(0), - MaxRetransmits::NoLimit(), kExpiresAt) + EXPECT_TRUE(buf_.Insert(kMessageId, gen_.Ordered({1}, ""), + kNow + DurationMs(0), MaxRetransmits::NoLimit(), + kExpiresAt) .has_value()); - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); - EXPECT_FALSE(buf_.Insert(gen_.Ordered({1}, "E"), kNow + DurationMs(1), - MaxRetransmits::NoLimit(), kExpiresAt) + EXPECT_FALSE(buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), + kNow + DurationMs(1), MaxRetransmits::NoLimit(), + kExpiresAt) .has_value()); EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); @@ -298,11 +306,11 @@ TEST_F(OutstandingDataTest, ExpiresChunkBeforeItIsInserted) { TEST_F(OutstandingDataTest, CanGenerateForwardTsn) { static constexpr MaxRetransmits kMaxRetransmissions(0); - buf_.Insert(gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); - buf_.Insert(gen_.Ordered({1}, "E"), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, kMaxRetransmissions); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow, kMaxRetransmissions); - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); buf_.NackAll(); @@ -319,14 +327,14 @@ TEST_F(OutstandingDataTest, CanGenerateForwardTsn) { } TEST_F(OutstandingDataTest, AckWithGapBlocksFromRFC4960Section334) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, ""), kNow); - buf_.Insert(gen_.Ordered({1}, "E"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow); EXPECT_THAT(buf_.GetChunkStatesForTesting(), testing::ElementsAre(Pair(TSN(9), State::kAcked), // @@ -353,9 +361,9 @@ TEST_F(OutstandingDataTest, AckWithGapBlocksFromRFC4960Section334) { } TEST_F(OutstandingDataTest, MeasureRTT) { - buf_.Insert(gen_.Ordered({1}, "BE"), kNow); - buf_.Insert(gen_.Ordered({1}, "BE"), kNow + DurationMs(1)); - buf_.Insert(gen_.Ordered({1}, "BE"), kNow + DurationMs(2)); + buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow); + buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(1)); + buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(2)); static constexpr DurationMs kDuration(123); ASSERT_HAS_VALUE_AND_ASSIGN( @@ -372,7 +380,8 @@ TEST_F(OutstandingDataTest, MustRetransmitBeforeGettingNackedAgain) { static constexpr MaxRetransmits kOneRetransmission(1); for (int tsn = 10; tsn <= 20; ++tsn) { - buf_.Insert(gen_.Ordered({1}, tsn == 10 ? "B" + buf_.Insert(kMessageId, + gen_.Ordered({1}, tsn == 10 ? "B" : tsn == 20 ? "E" : ""), kNow, kOneRetransmission); @@ -431,7 +440,7 @@ TEST_F(OutstandingDataTest, MustRetransmitBeforeGettingNackedAgain) { buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab8, false).has_packet_loss); EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); std::vector gab9 = {SackChunk::GapAckBlock(2, 10)}; @@ -442,54 +451,16 @@ TEST_F(OutstandingDataTest, MustRetransmitBeforeGettingNackedAgain) { EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); } -TEST_F(OutstandingDataTest, CanAbandonChunksMarkedForFastRetransmit) { - // This test is a bit convoluted, and can't really happen with a well behaving - // client, but this was found by fuzzers. This test will verify that a message - // that was both marked as "to be fast retransmitted" and "abandoned" at the - // same time doesn't cause any consistency issues. - - // Add chunks 10-14, but chunk 11 has zero retransmissions. When chunk 10 and - // 11 are NACKed three times, chunk 10 will be marked for retransmission, but - // chunk 11 will be abandoned, which also abandons chunk 10, as it's part of - // the same message. - buf_.Insert(gen_.Ordered({1}, "B"), kNow); // 10 - buf_.Insert(gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); // 11 - buf_.Insert(gen_.Ordered({1}, ""), kNow); // 12 - buf_.Insert(gen_.Ordered({1}, ""), kNow); // 13 - buf_.Insert(gen_.Ordered({1}, "E"), kNow); // 14 - - // ACK 9, 12 - std::vector gab1 = {SackChunk::GapAckBlock(3, 3)}; - EXPECT_FALSE( - buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab1, false).has_packet_loss); - EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - - // ACK 9, 12, 13 - std::vector gab2 = {SackChunk::GapAckBlock(3, 4)}; - EXPECT_FALSE( - buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab2, false).has_packet_loss); - EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) - .WillOnce(Return(false)); - - // ACK 9, 12, 13, 14 - std::vector gab3 = {SackChunk::GapAckBlock(3, 5)}; - OutstandingData::AckInfo ack = - buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab3, false); - EXPECT_TRUE(ack.has_packet_loss); - EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); - EXPECT_THAT(buf_.GetChunksToBeFastRetransmitted(1000), IsEmpty()); - EXPECT_THAT(buf_.GetChunksToBeRetransmitted(1000), IsEmpty()); -} - TEST_F(OutstandingDataTest, LifecyleReturnsAckedItemsInAckInfo) { - buf_.Insert(gen_.Ordered({1}, "BE"), kNow, MaxRetransmits::NoLimit(), - TimeMs::InfiniteFuture(), LifecycleId(42)); - buf_.Insert(gen_.Ordered({1}, "BE"), kNow, MaxRetransmits::NoLimit(), - TimeMs::InfiniteFuture(), LifecycleId(43)); - buf_.Insert(gen_.Ordered({1}, "BE"), kNow, MaxRetransmits::NoLimit(), - TimeMs::InfiniteFuture(), LifecycleId(44)); + buf_.Insert(OutgoingMessageId(1), gen_.Ordered({1}, "BE"), kNow, + MaxRetransmits::NoLimit(), TimeMs::InfiniteFuture(), + LifecycleId(42)); + buf_.Insert(OutgoingMessageId(2), gen_.Ordered({1}, "BE"), kNow, + MaxRetransmits::NoLimit(), TimeMs::InfiniteFuture(), + LifecycleId(43)); + buf_.Insert(OutgoingMessageId(3), gen_.Ordered({1}, "BE"), kNow, + MaxRetransmits::NoLimit(), TimeMs::InfiniteFuture(), + LifecycleId(44)); OutstandingData::AckInfo ack1 = buf_.HandleSack(unwrapper_.Unwrap(TSN(11)), {}, false); @@ -504,10 +475,10 @@ TEST_F(OutstandingDataTest, LifecyleReturnsAckedItemsInAckInfo) { } TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedNackedThreeTimes) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, "E"), kNow, MaxRetransmits(0), + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow, MaxRetransmits(0), TimeMs::InfiniteFuture(), LifecycleId(42)); std::vector gab1 = {SackChunk::GapAckBlock(2, 2)}; @@ -521,7 +492,7 @@ TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedNackedThreeTimes) { EXPECT_FALSE(buf_.has_data_to_be_retransmitted()); std::vector gab3 = {SackChunk::GapAckBlock(2, 4)}; - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); OutstandingData::AckInfo ack1 = buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), gab3, false); @@ -540,10 +511,10 @@ TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedNackedThreeTimes) { } TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedAfterT3rtxExpired) { - buf_.Insert(gen_.Ordered({1}, "B"), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); - buf_.Insert(gen_.Ordered({1}, "E"), kNow, MaxRetransmits(0), + buf_.Insert(kMessageId, gen_.Ordered({1}, "B"), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, ""), kNow, MaxRetransmits(0)); + buf_.Insert(kMessageId, gen_.Ordered({1}, "E"), kNow, MaxRetransmits(0), TimeMs::InfiniteFuture(), LifecycleId(42)); EXPECT_THAT(buf_.GetChunkStatesForTesting(), @@ -566,7 +537,7 @@ TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedAfterT3rtxExpired) { Pair(TSN(13), State::kAcked))); // T3-rtx triggered. - EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(on_discard_, Call(StreamID(1), kMessageId)) .WillOnce(Return(false)); buf_.NackAll(); @@ -587,5 +558,104 @@ TEST_F(OutstandingDataTest, LifecycleReturnsAbandonedAfterT3rtxExpired) { EXPECT_FALSE(ack2.has_packet_loss); EXPECT_THAT(ack2.abandoned_lifecycle_ids, ElementsAre(LifecycleId(42))); } + +TEST_F(OutstandingDataTest, GeneratesForwardTsnUntilNextStreamResetTsn) { + // This test generates: + // * Stream 1: TSN 10, 11, 12 + // * Stream 2: TSN 13, 14 + // * Stream 3: TSN 15, 16 + // + // Then it expires chunk 12-15, and ensures that the generated FORWARD-TSN + // only includes up till TSN 12 until the cum ack TSN has reached 12, and then + // 13 and 14 are included, and then after the cum ack TSN has reached 14, then + // 15 is included. + // + // What it shouldn't do, is to generate a FORWARD-TSN directly at the start + // with new TSN=15, and setting [(sid=1, ssn=44), (sid=2, ssn=46), + // (sid=3, ssn=47)], because that will confuse the receiver at TSN=17, + // receiving SID=1, SSN=0 (it's reset!), expecting SSN to be 45. + constexpr DataGeneratorOptions kStream1 = {.stream_id = StreamID(1)}; + constexpr DataGeneratorOptions kStream2 = {.stream_id = StreamID(2)}; + constexpr DataGeneratorOptions kStream3 = {.stream_id = StreamID(3)}; + constexpr MaxRetransmits kNoRtx = MaxRetransmits(0); + EXPECT_CALL(on_discard_, Call).WillRepeatedly(Return(false)); + + // TSN 10-12 + buf_.Insert(OutgoingMessageId(0), gen_.Ordered({1}, "BE", kStream1), kNow, + kNoRtx); + buf_.Insert(OutgoingMessageId(1), gen_.Ordered({1}, "BE", kStream1), kNow, + kNoRtx); + buf_.Insert(OutgoingMessageId(2), gen_.Ordered({1}, "BE", kStream1), kNow, + kNoRtx); + + buf_.BeginResetStreams(); + + // TSN 13, 14 + buf_.Insert(OutgoingMessageId(3), gen_.Ordered({1}, "BE", kStream2), kNow, + kNoRtx); + buf_.Insert(OutgoingMessageId(4), gen_.Ordered({1}, "BE", kStream2), kNow, + kNoRtx); + + buf_.BeginResetStreams(); + + // TSN 15, 16 + buf_.Insert(OutgoingMessageId(5), gen_.Ordered({1}, "BE", kStream3), kNow, + kNoRtx); + buf_.Insert(OutgoingMessageId(6), gen_.Ordered({1}, "BE", kStream3), kNow); + + EXPECT_FALSE(buf_.ShouldSendForwardTsn()); + + buf_.HandleSack(unwrapper_.Unwrap(TSN(11)), {}, false); + buf_.NackAll(); + EXPECT_THAT(buf_.GetChunkStatesForTesting(), + ElementsAre(Pair(TSN(11), State::kAcked), // + Pair(TSN(12), State::kAbandoned), // + Pair(TSN(13), State::kAbandoned), // + Pair(TSN(14), State::kAbandoned), // + Pair(TSN(15), State::kAbandoned), // + Pair(TSN(16), State::kToBeRetransmitted))); + + EXPECT_TRUE(buf_.ShouldSendForwardTsn()); + EXPECT_THAT( + buf_.CreateForwardTsn(), + AllOf(Property(&ForwardTsnChunk::new_cumulative_tsn, TSN(12)), + Property(&ForwardTsnChunk::skipped_streams, + UnorderedElementsAre(ForwardTsnChunk::SkippedStream( + StreamID(1), SSN(44)))))); + + // Ack 12, allowing a FORWARD-TSN that spans to TSN=14 to be created. + buf_.HandleSack(unwrapper_.Unwrap(TSN(12)), {}, false); + EXPECT_TRUE(buf_.ShouldSendForwardTsn()); + EXPECT_THAT( + buf_.CreateForwardTsn(), + AllOf(Property(&ForwardTsnChunk::new_cumulative_tsn, TSN(14)), + Property(&ForwardTsnChunk::skipped_streams, + UnorderedElementsAre(ForwardTsnChunk::SkippedStream( + StreamID(2), SSN(46)))))); + + // Ack 13, allowing a FORWARD-TSN that spans to TSN=14 to be created. + buf_.HandleSack(unwrapper_.Unwrap(TSN(13)), {}, false); + EXPECT_TRUE(buf_.ShouldSendForwardTsn()); + EXPECT_THAT( + buf_.CreateForwardTsn(), + AllOf(Property(&ForwardTsnChunk::new_cumulative_tsn, TSN(14)), + Property(&ForwardTsnChunk::skipped_streams, + UnorderedElementsAre(ForwardTsnChunk::SkippedStream( + StreamID(2), SSN(46)))))); + + // Ack 14, allowing a FORWARD-TSN that spans to TSN=15 to be created. + buf_.HandleSack(unwrapper_.Unwrap(TSN(14)), {}, false); + EXPECT_TRUE(buf_.ShouldSendForwardTsn()); + EXPECT_THAT( + buf_.CreateForwardTsn(), + AllOf(Property(&ForwardTsnChunk::new_cumulative_tsn, TSN(15)), + Property(&ForwardTsnChunk::skipped_streams, + UnorderedElementsAre(ForwardTsnChunk::SkippedStream( + StreamID(3), SSN(47)))))); + + buf_.HandleSack(unwrapper_.Unwrap(TSN(15)), {}, false); + EXPECT_FALSE(buf_.ShouldSendForwardTsn()); +} + } // namespace } // namespace dcsctp diff --git a/net/dcsctp/tx/retransmission_queue.cc b/net/dcsctp/tx/retransmission_queue.cc index 93084cc27b..2b9843f4a7 100644 --- a/net/dcsctp/tx/retransmission_queue.cc +++ b/net/dcsctp/tx/retransmission_queue.cc @@ -86,8 +86,8 @@ RetransmissionQueue::RetransmissionQueue( data_chunk_header_size_, tsn_unwrapper_.Unwrap(my_initial_tsn), tsn_unwrapper_.Unwrap(TSN(*my_initial_tsn - 1)), - [this](IsUnordered unordered, StreamID stream_id, MID message_id) { - return send_queue_.Discard(unordered, stream_id, message_id); + [this](StreamID stream_id, OutgoingMessageId message_id) { + return send_queue_.Discard(stream_id, message_id); }) {} bool RetransmissionQueue::IsConsistent() const { @@ -491,7 +491,7 @@ std::vector> RetransmissionQueue::GetChunksToSend( rwnd_ -= chunk_size; absl::optional tsn = outstanding_data_.Insert( - chunk_opt->data, now, + chunk_opt->message_id, chunk_opt->data, now, partial_reliability_ ? chunk_opt->max_retransmissions : MaxRetransmits::NoLimit(), partial_reliability_ ? chunk_opt->expires_at : TimeMs::InfiniteFuture(), @@ -573,6 +573,10 @@ void RetransmissionQueue::PrepareResetStream(StreamID stream_id) { bool RetransmissionQueue::HasStreamsReadyToBeReset() const { return send_queue_.HasStreamsReadyToBeReset(); } +std::vector RetransmissionQueue::BeginResetStreams() { + outstanding_data_.BeginResetStreams(); + return send_queue_.GetStreamsReadyToBeReset(); +} void RetransmissionQueue::CommitResetStreams() { send_queue_.CommitResetStreams(); } diff --git a/net/dcsctp/tx/retransmission_queue.h b/net/dcsctp/tx/retransmission_queue.h index 51e9c5b318..b44db2a9a0 100644 --- a/net/dcsctp/tx/retransmission_queue.h +++ b/net/dcsctp/tx/retransmission_queue.h @@ -103,6 +103,10 @@ class RetransmissionQueue { // Returns the next TSN that will be allocated for sent DATA chunks. TSN next_tsn() const { return outstanding_data_.next_tsn().Wrap(); } + TSN last_assigned_tsn() const { + return UnwrappedTSN::AddTo(outstanding_data_.next_tsn(), -1).Wrap(); + } + // Returns the size of the congestion window, in bytes. This is the number of // bytes that may be in-flight. size_t cwnd() const { return cwnd_; } @@ -148,9 +152,7 @@ class RetransmissionQueue { // to stream resetting. void PrepareResetStream(StreamID stream_id); bool HasStreamsReadyToBeReset() const; - std::vector GetStreamsReadyToBeReset() const { - return send_queue_.GetStreamsReadyToBeReset(); - } + std::vector BeginResetStreams(); void CommitResetStreams(); void RollbackResetStreams(); diff --git a/net/dcsctp/tx/retransmission_queue_test.cc b/net/dcsctp/tx/retransmission_queue_test.cc index e62c030bfa..d50494f084 100644 --- a/net/dcsctp/tx/retransmission_queue_test.cc +++ b/net/dcsctp/tx/retransmission_queue_test.cc @@ -20,6 +20,7 @@ #include "api/array_view.h" #include "api/task_queue/task_queue_base.h" #include "net/dcsctp/common/handover_testing.h" +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/common/math.h" #include "net/dcsctp/packet/chunk/data_chunk.h" #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h" @@ -44,6 +45,7 @@ using ::testing::MockFunction; using State = ::dcsctp::RetransmissionQueue::State; using ::testing::_; using ::testing::ElementsAre; +using ::testing::Field; using ::testing::IsEmpty; using ::testing::NiceMock; using ::testing::Pair; @@ -53,6 +55,7 @@ using ::testing::UnorderedElementsAre; constexpr uint32_t kArwnd = 100000; constexpr uint32_t kMaxMtu = 1191; +constexpr OutgoingMessageId kMessageId = OutgoingMessageId(42); DcSctpOptions MakeOptions() { DcSctpOptions options; @@ -74,9 +77,11 @@ class RetransmissionQueueTest : public testing::Test { []() { return absl::nullopt; }, TimerOptions(options_.rto_initial))) {} - std::function CreateChunk() { - return [this](TimeMs now, size_t max_size) { - return SendQueue::DataToSend(gen_.Ordered({1, 2, 3, 4}, "BE")); + std::function CreateChunk( + OutgoingMessageId message_id) { + return [this, message_id](TimeMs now, size_t max_size) { + return SendQueue::DataToSend(message_id, + gen_.Ordered({1, 2, 3, 4}, "BE")); }; } @@ -140,7 +145,7 @@ TEST_F(RetransmissionQueueTest, InitialAckedPrevTsn) { TEST_F(RetransmissionQueueTest, SendOneChunk) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(10))); @@ -153,7 +158,7 @@ TEST_F(RetransmissionQueueTest, SendOneChunk) { TEST_F(RetransmissionQueueTest, SendOneChunkAndAck) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(10))); @@ -167,9 +172,9 @@ TEST_F(RetransmissionQueueTest, SendOneChunkAndAck) { TEST_F(RetransmissionQueueTest, SendThreeChunksAndAckTwo) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -185,14 +190,14 @@ TEST_F(RetransmissionQueueTest, SendThreeChunksAndAckTwo) { TEST_F(RetransmissionQueueTest, AckWithGapBlocksFromRFC4960Section334) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -216,14 +221,14 @@ TEST_F(RetransmissionQueueTest, AckWithGapBlocksFromRFC4960Section334) { TEST_F(RetransmissionQueueTest, ResendPacketsWhenNackedThreeTimes) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -235,7 +240,7 @@ TEST_F(RetransmissionQueueTest, ResendPacketsWhenNackedThreeTimes) { // Send 18 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(8))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(18))); @@ -256,7 +261,7 @@ TEST_F(RetransmissionQueueTest, ResendPacketsWhenNackedThreeTimes) { // Send 19 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(9))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(19))); @@ -268,7 +273,7 @@ TEST_F(RetransmissionQueueTest, ResendPacketsWhenNackedThreeTimes) { // Send 20 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(10))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(20))); @@ -313,9 +318,9 @@ TEST_F(RetransmissionQueueTest, RestartsT3RtxOnRetransmitFirstOutstandingTSN) { // TSN, it will also restart T3-RTX. RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); static constexpr TimeMs kStartTime(100000); @@ -336,7 +341,7 @@ TEST_F(RetransmissionQueueTest, RestartsT3RtxOnRetransmitFirstOutstandingTSN) { // Send 13 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(3))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(13))); @@ -347,7 +352,7 @@ TEST_F(RetransmissionQueueTest, RestartsT3RtxOnRetransmitFirstOutstandingTSN) { // Send 14 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(4))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), testing::ElementsAre(TSN(14))); @@ -393,10 +398,12 @@ TEST_F(RetransmissionQueueTest, CanOnlyProduceTwoPacketsButWantsToSendThree) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered({1, 2, 3, 4}, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered({1, 2, 3, 4}, "BE")); }) .WillOnce([this](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered({1, 2, 3, 4}, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(1), + gen_.Ordered({1, 2, 3, 4}, "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -414,7 +421,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsOnT3Expiry) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered({1, 2, 3, 4}, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered({1, 2, 3, 4}, "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -452,7 +460,7 @@ TEST_F(RetransmissionQueueTest, LimitedRetransmissionOnlyWithRfc3758Support) { CreateQueue(/*supports_partial_reliability=*/false); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "BE")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -473,8 +481,7 @@ TEST_F(RetransmissionQueueTest, LimitedRetransmissionOnlyWithRfc3758Support) { ElementsAre(Pair(TSN(9), State::kAcked), // Pair(TSN(10), State::kToBeRetransmitted))); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(0); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(0); EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); } // namespace dcsctp @@ -482,7 +489,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsAsUdp) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "BE")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -497,8 +504,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsAsUdp) { Pair(TSN(10), State::kInFlight))); // Will force chunks to be retransmitted - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(1); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(1); queue.HandleT3RtxTimerExpiry(); @@ -524,7 +530,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsToThreeSends) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "BE")); dts.max_retransmissions = MaxRetransmits(3); return dts; }) @@ -538,8 +544,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsToThreeSends) { ElementsAre(Pair(TSN(9), State::kAcked), // Pair(TSN(10), State::kInFlight))); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(0); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(0); // Retransmission 1 queue.HandleT3RtxTimerExpiry(); @@ -557,8 +562,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsToThreeSends) { EXPECT_THAT(queue.GetChunksToSend(now_, 1000), SizeIs(1)); // Retransmission 4 - not allowed. - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(1); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(1); queue.HandleT3RtxTimerExpiry(); EXPECT_TRUE(queue.ShouldSendForwardTsn(now_)); EXPECT_THAT(queue.GetChunksToSend(now_, 1000), IsEmpty()); @@ -579,7 +583,8 @@ TEST_F(RetransmissionQueueTest, RetransmitsWhenSendBufferIsFullT3Expiry) { std::vector payload(1000); EXPECT_CALL(producer_, Produce) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -615,17 +620,18 @@ TEST_F(RetransmissionQueueTest, ProducesValidForwardTsn) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "B")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, "")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({5, 6, 7, 8}, "")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "")); + SendQueue::DataToSend dts(kMessageId, + gen_.Ordered({9, 10, 11, 12}, "")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -645,7 +651,7 @@ TEST_F(RetransmissionQueueTest, ProducesValidForwardTsn) { // Chunk 10 is acked, but the remaining are lost queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {})); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)) .WillOnce(Return(true)); queue.HandleT3RtxTimerExpiry(); @@ -670,17 +676,18 @@ TEST_F(RetransmissionQueueTest, ProducesValidForwardTsnWhenFullySent) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "B")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, "")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({5, 6, 7, 8}, "")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "E")); + SendQueue::DataToSend dts(kMessageId, + gen_.Ordered({9, 10, 11, 12}, "E")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -700,7 +707,7 @@ TEST_F(RetransmissionQueueTest, ProducesValidForwardTsnWhenFullySent) { // Chunk 10 is acked, but the remaining are lost queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {})); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)) .WillOnce(Return(false)); queue.HandleT3RtxTimerExpiry(); @@ -725,28 +732,32 @@ TEST_F(RetransmissionQueueTest, ProducesValidIForwardTsn) { .WillOnce([this](TimeMs, size_t) { DataGeneratorOptions opts; opts.stream_id = StreamID(1); - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B", opts)); + SendQueue::DataToSend dts(OutgoingMessageId(42), + gen_.Ordered({1, 2, 3, 4}, "B", opts)); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { DataGeneratorOptions opts; opts.stream_id = StreamID(2); - SendQueue::DataToSend dts(gen_.Unordered({1, 2, 3, 4}, "B", opts)); + SendQueue::DataToSend dts(OutgoingMessageId(43), + gen_.Unordered({1, 2, 3, 4}, "B", opts)); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { DataGeneratorOptions opts; opts.stream_id = StreamID(3); - SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "B", opts)); + SendQueue::DataToSend dts(OutgoingMessageId(44), + gen_.Ordered({9, 10, 11, 12}, "B", opts)); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { DataGeneratorOptions opts; opts.stream_id = StreamID(4); - SendQueue::DataToSend dts(gen_.Ordered({13, 14, 15, 16}, "B", opts)); + SendQueue::DataToSend dts(OutgoingMessageId(45), + gen_.Ordered({13, 14, 15, 16}, "B", opts)); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -773,11 +784,11 @@ TEST_F(RetransmissionQueueTest, ProducesValidIForwardTsn) { Pair(TSN(12), State::kNacked), // Pair(TSN(13), State::kAcked))); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(1), OutgoingMessageId(42))) .WillOnce(Return(true)); - EXPECT_CALL(producer_, Discard(IsUnordered(true), StreamID(2), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(2), OutgoingMessageId(43))) .WillOnce(Return(true)); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(3), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(3), OutgoingMessageId(44))) .WillOnce(Return(true)); queue.HandleT3RtxTimerExpiry(); @@ -840,7 +851,8 @@ TEST_F(RetransmissionQueueTest, MeasureRTT) { RetransmissionQueue queue = CreateQueue(/*use_message_interleaving=*/true); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B")); + SendQueue::DataToSend dts(OutgoingMessageId(0), + gen_.Ordered({1, 2, 3, 4}, "B")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -868,14 +880,14 @@ TEST_F(RetransmissionQueueTest, ValidateCumTsnAckOnInflightData) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -898,14 +910,14 @@ TEST_F(RetransmissionQueueTest, ValidateCumTsnAckOnInflightData) { TEST_F(RetransmissionQueueTest, HandleGapAckBlocksMatchingNoInflightData) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -945,14 +957,14 @@ TEST_F(RetransmissionQueueTest, HandleInvalidGapAckBlocks) { TEST_F(RetransmissionQueueTest, GapAckBlocksDoNotMoveCumTsnAck) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), @@ -987,13 +999,15 @@ TEST_F(RetransmissionQueueTest, StaysWithinAvailableSize) { EXPECT_EQ(size, 1176 - DataChunk::kHeaderSize); std::vector payload(183); - return SendQueue::DataToSend(gen_.Ordered(payload, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "BE")); }) .WillOnce([this](TimeMs, size_t size) { EXPECT_EQ(size, 976 - DataChunk::kHeaderSize); std::vector payload(957); - return SendQueue::DataToSend(gen_.Ordered(payload, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(1), + gen_.Ordered(payload, "BE")); }); std::vector> chunks_to_send = @@ -1005,17 +1019,18 @@ TEST_F(RetransmissionQueueTest, AccountsNackedAbandonedChunksAsNotOutstanding) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "B")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, "")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({5, 6, 7, 8}, "")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "")); + SendQueue::DataToSend dts(kMessageId, + gen_.Ordered({9, 10, 11, 12}, "")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) @@ -1035,8 +1050,7 @@ TEST_F(RetransmissionQueueTest, AccountsNackedAbandonedChunksAsNotOutstanding) { EXPECT_EQ(queue.outstanding_items(), 3u); // Mark the message as lost. - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(1); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(1); queue.HandleT3RtxTimerExpiry(); EXPECT_TRUE(queue.ShouldSendForwardTsn(now_)); @@ -1067,16 +1081,18 @@ TEST_F(RetransmissionQueueTest, ExpireFromSendQueueWhenPartiallySent) { RetransmissionQueue queue = CreateQueue(); DataGeneratorOptions options; options.stream_id = StreamID(17); - options.message_id = MID(42); + options.mid = MID(42); TimeMs test_start = now_; EXPECT_CALL(producer_, Produce) .WillOnce([&](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B", options)); + SendQueue::DataToSend dts(kMessageId, + gen_.Ordered({1, 2, 3, 4}, "B", options)); dts.expires_at = TimeMs(test_start + DurationMs(10)); return dts; }) .WillOnce([&](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, "", options)); + SendQueue::DataToSend dts(kMessageId, + gen_.Ordered({5, 6, 7, 8}, "", options)); dts.expires_at = TimeMs(test_start + DurationMs(10)); return dts; }) @@ -1086,7 +1102,7 @@ TEST_F(RetransmissionQueueTest, ExpireFromSendQueueWhenPartiallySent) { queue.GetChunksToSend(now_, 24); EXPECT_THAT(chunks_to_send, ElementsAre(Pair(TSN(10), _))); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(17), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(17), kMessageId)) .WillOnce(Return(true)); now_ += DurationMs(100); @@ -1100,17 +1116,74 @@ TEST_F(RetransmissionQueueTest, ExpireFromSendQueueWhenPartiallySent) { Pair(TSN(12), State::kAbandoned))); // Placeholder end } +TEST_F(RetransmissionQueueTest, ExpireCorrectMessageFromSendQueue) { + RetransmissionQueue queue = CreateQueue(); + TimeMs test_start = now_; + EXPECT_CALL(producer_, Produce) + .WillOnce([&](TimeMs, size_t) { + SendQueue::DataToSend dts( + OutgoingMessageId(42), + gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(0)})); + dts.expires_at = TimeMs(test_start + DurationMs(10)); + return dts; + }) + .WillOnce([&](TimeMs, size_t) { + SendQueue::DataToSend dts( + OutgoingMessageId(43), + gen_.Ordered({1, 2, 3, 4}, "BE", {.mid = MID(1)})); + dts.expires_at = TimeMs(test_start + DurationMs(10)); + return dts; + }) + // Stream reset - MID reset to zero again. + .WillOnce([&](TimeMs, size_t) { + SendQueue::DataToSend dts( + OutgoingMessageId(44), + gen_.Ordered({1, 2, 3, 4}, "B", {.mid = MID(0)})); + dts.expires_at = TimeMs(test_start + DurationMs(10)); + return dts; + }) + .WillOnce([&](TimeMs, size_t) { + SendQueue::DataToSend dts( + OutgoingMessageId(44), + gen_.Ordered({5, 6, 7, 8}, "", {.mid = MID(0)})); + dts.expires_at = TimeMs(test_start + DurationMs(10)); + return dts; + }) + .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); + EXPECT_CALL(producer_, Discard(StreamID(1), OutgoingMessageId(44))) + .WillOnce(Return(true)); + + EXPECT_THAT(queue.GetChunksToSend(now_, 24), + ElementsAre(Pair(TSN(10), Field(&Data::mid, MID(0))))); + EXPECT_THAT(queue.GetChunksToSend(now_, 24), + ElementsAre(Pair(TSN(11), Field(&Data::mid, MID(1))))); + EXPECT_THAT(queue.GetChunksToSend(now_, 24), + ElementsAre(Pair(TSN(12), Field(&Data::mid, MID(0))))); + + now_ += DurationMs(100); + EXPECT_THAT(queue.GetChunksToSend(now_, 24), IsEmpty()); + + EXPECT_THAT( + queue.GetChunkStatesForTesting(), + ElementsAre(Pair(TSN(9), State::kAcked), // Initial TSN + Pair(TSN(10), State::kInFlight), // OutgoingMessageId=42, BE + Pair(TSN(11), State::kInFlight), // OutgoingMessageId=43, BE + Pair(TSN(12), State::kAbandoned), // OutgoingMessageId=44, B + Pair(TSN(13), State::kAbandoned), // Produced and expired + Pair(TSN(14), State::kAbandoned))); // Placeholder end +} + TEST_F(RetransmissionQueueTest, LimitsRetransmissionsOnlyWhenNackedThreeTimes) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "BE")); dts.max_retransmissions = MaxRetransmits(0); return dts; }) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); @@ -1128,8 +1201,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsOnlyWhenNackedThreeTimes) { EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(0); + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)).Times(0); queue.HandleSack( now_, SackChunk(TSN(9), kArwnd, {SackChunk::GapAckBlock(2, 2)}, {})); @@ -1155,7 +1227,7 @@ TEST_F(RetransmissionQueueTest, LimitsRetransmissionsOnlyWhenNackedThreeTimes) { EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)) .WillOnce(Return(false)); queue.HandleSack( now_, SackChunk(TSN(9), kArwnd, {SackChunk::GapAckBlock(2, 4)}, {})); @@ -1175,19 +1247,19 @@ TEST_F(RetransmissionQueueTest, AbandonsRtxLimit2WhenNackedNineTimes) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) .WillOnce([this](TimeMs, size_t) { - SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE")); + SendQueue::DataToSend dts(kMessageId, gen_.Ordered({1, 2, 3, 4}, "BE")); dts.max_retransmissions = MaxRetransmits(2); return dts; }) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) + .WillOnce(CreateChunk(OutgoingMessageId(8))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); @@ -1213,8 +1285,7 @@ TEST_F(RetransmissionQueueTest, AbandonsRtxLimit2WhenNackedNineTimes) { Pair(TSN(18), State::kInFlight), // Pair(TSN(19), State::kInFlight))); - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) - .Times(0); + EXPECT_CALL(producer_, Discard(StreamID(1), OutgoingMessageId(8))).Times(0); // Ack TSN [11 to 13] - three nacks for TSN(10), which will retransmit it. for (int tsn = 11; tsn <= 13; ++tsn) { @@ -1284,7 +1355,7 @@ TEST_F(RetransmissionQueueTest, AbandonsRtxLimit2WhenNackedNineTimes) { EXPECT_FALSE(queue.ShouldSendForwardTsn(now_)); // Ack TSN 19 - three more nacks for TSN 10, no more retransmissions. - EXPECT_CALL(producer_, Discard(IsUnordered(false), StreamID(1), MID(42))) + EXPECT_CALL(producer_, Discard(StreamID(1), kMessageId)) .WillOnce(Return(false)); queue.HandleSack( now_, SackChunk(TSN(9), kArwnd, {SackChunk::GapAckBlock(2, 10)}, {})); @@ -1316,7 +1387,8 @@ TEST_F(RetransmissionQueueTest, CwndRecoversWhenAcking) { std::vector payload(1000); EXPECT_CALL(producer_, Produce) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "BE")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -1344,6 +1416,7 @@ TEST_F(RetransmissionQueueTest, OnlySendsLargePacketsOnLargeCongestionWindow) { EXPECT_CALL(producer_, Produce) .WillOnce([chunk_size, this](TimeMs, size_t) { return SendQueue::DataToSend( + OutgoingMessageId(0), gen_.Ordered(std::vector(chunk_size), "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -1376,6 +1449,7 @@ TEST_F(RetransmissionQueueTest, AllowsSmallFragmentsOnSmallCongestionWindow) { EXPECT_CALL(producer_, Produce) .WillOnce([chunk_size, this](TimeMs, size_t) { return SendQueue::DataToSend( + OutgoingMessageId(0), gen_.Ordered(std::vector(chunk_size), "BE")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); @@ -1392,7 +1466,7 @@ TEST_F(RetransmissionQueueTest, AllowsSmallFragmentsOnSmallCongestionWindow) { TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenHasNoOutstandingData) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(1)); @@ -1408,14 +1482,14 @@ TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenHasNoOutstandingData) { TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenNothingToRetransmit) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) + .WillOnce(CreateChunk(OutgoingMessageId(5))) + .WillOnce(CreateChunk(OutgoingMessageId(6))) + .WillOnce(CreateChunk(OutgoingMessageId(7))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(8)); EXPECT_EQ( @@ -1428,7 +1502,7 @@ TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenNothingToRetransmit) { // Send 18 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(8))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(1)); @@ -1440,7 +1514,7 @@ TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenNothingToRetransmit) { // Send 19 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(9))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(1)); @@ -1452,7 +1526,7 @@ TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenNothingToRetransmit) { // Send 20 EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(10))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(1)); @@ -1487,8 +1561,8 @@ TEST_F(RetransmissionQueueTest, ReadyForHandoverWhenNothingToRetransmit) { TEST_F(RetransmissionQueueTest, HandoverTest) { RetransmissionQueue queue = CreateQueue(); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(0))) + .WillOnce(CreateChunk(OutgoingMessageId(1))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(queue), SizeIs(2)); queue.HandleSack(now_, SackChunk(TSN(11), kArwnd, {}, {})); @@ -1497,9 +1571,9 @@ TEST_F(RetransmissionQueueTest, HandoverTest) { CreateQueueByHandover(queue); EXPECT_CALL(producer_, Produce) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) - .WillOnce(CreateChunk()) + .WillOnce(CreateChunk(OutgoingMessageId(2))) + .WillOnce(CreateChunk(OutgoingMessageId(3))) + .WillOnce(CreateChunk(OutgoingMessageId(4))) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); EXPECT_THAT(GetSentPacketTSNs(*handedover_queue), testing::ElementsAre(TSN(12), TSN(13), TSN(14))); @@ -1519,19 +1593,24 @@ TEST_F(RetransmissionQueueTest, CanAlwaysSendOnePacket) { EXPECT_CALL(producer_, Produce) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "B")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "B")); }) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "")); }) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "")); }) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "")); }) .WillOnce([this, payload](TimeMs, size_t) { - return SendQueue::DataToSend(gen_.Ordered(payload, "E")); + return SendQueue::DataToSend(OutgoingMessageId(0), + gen_.Ordered(payload, "E")); }) .WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; }); diff --git a/net/dcsctp/tx/rr_send_queue.cc b/net/dcsctp/tx/rr_send_queue.cc index 4df253dddf..facb432c59 100644 --- a/net/dcsctp/tx/rr_send_queue.cc +++ b/net/dcsctp/tx/rr_send_queue.cc @@ -20,6 +20,7 @@ #include "absl/algorithm/container.h" #include "absl/types/optional.h" #include "api/array_view.h" +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/common/str_join.h" #include "net/dcsctp/packet/data.h" #include "net/dcsctp/public/dcsctp_message.h" @@ -123,7 +124,10 @@ void RRSendQueue::OutgoingStream::Add(DcSctpMessage message, bool was_active = bytes_to_send_in_next_message() > 0; buffered_amount_.Increase(message.payload().size()); parent_.total_buffered_amount_.Increase(message.payload().size()); - items_.emplace_back(std::move(message), std::move(attributes)); + OutgoingMessageId message_id = parent_.current_message_id; + parent_.current_message_id = + OutgoingMessageId(*parent_.current_message_id + 1); + items_.emplace_back(message_id, std::move(message), std::move(attributes)); if (!was_active) { scheduler_stream_->MaybeMakeActive(); @@ -143,7 +147,7 @@ absl::optional RRSendQueue::OutgoingStream::Produce( DcSctpMessage& message = item.message; // Allocate Message ID and SSN when the first fragment is sent. - if (!item.message_id.has_value()) { + if (!item.mid.has_value()) { // Oops, this entire message has already expired. Try the next one. if (item.attributes.expires_at <= now) { HandleMessageExpired(item); @@ -153,7 +157,7 @@ absl::optional RRSendQueue::OutgoingStream::Produce( MID& mid = item.attributes.unordered ? next_unordered_mid_ : next_ordered_mid_; - item.message_id = mid; + item.mid = mid; mid = MID(*mid + 1); } if (!item.attributes.unordered && !item.ssn.has_value()) { @@ -184,10 +188,10 @@ absl::optional RRSendQueue::OutgoingStream::Produce( buffered_amount_.Decrease(payload.size()); parent_.total_buffered_amount_.Decrease(payload.size()); - SendQueue::DataToSend chunk(Data(stream_id, item.ssn.value_or(SSN(0)), - item.message_id.value(), fsn, ppid, - std::move(payload), is_beginning, is_end, - item.attributes.unordered)); + SendQueue::DataToSend chunk( + item.message_id, Data(stream_id, item.ssn.value_or(SSN(0)), *item.mid, + fsn, ppid, std::move(payload), is_beginning, + is_end, item.attributes.unordered)); chunk.max_retransmissions = item.attributes.max_retransmissions; chunk.expires_at = item.attributes.expires_at; chunk.lifecycle_id = @@ -231,13 +235,11 @@ void RRSendQueue::OutgoingStream::HandleMessageExpired( } } -bool RRSendQueue::OutgoingStream::Discard(IsUnordered unordered, - MID message_id) { +bool RRSendQueue::OutgoingStream::Discard(OutgoingMessageId message_id) { bool result = false; if (!items_.empty()) { Item& item = items_.front(); - if (item.attributes.unordered == unordered && item.message_id.has_value() && - *item.message_id == message_id) { + if (item.message_id == message_id) { HandleMessageExpired(item); items_.pop_front(); @@ -329,7 +331,7 @@ void RRSendQueue::OutgoingStream::Reset() { item.remaining_size); item.remaining_offset = 0; item.remaining_size = item.message.payload().size(); - item.message_id = absl::nullopt; + item.mid = absl::nullopt; item.ssn = absl::nullopt; item.current_fsn = FSN(0); if (old_pause_state == PauseState::kPaused || @@ -344,7 +346,7 @@ bool RRSendQueue::OutgoingStream::has_partially_sent_message() const { if (items_.empty()) { return false; } - return items_.front().message_id.has_value(); + return items_.front().mid.has_value(); } void RRSendQueue::Add(TimeMs now, @@ -386,11 +388,8 @@ absl::optional RRSendQueue::Produce(TimeMs now, return scheduler_.Produce(now, max_size); } -bool RRSendQueue::Discard(IsUnordered unordered, - StreamID stream_id, - MID message_id) { - bool has_discarded = - GetOrCreateStreamInfo(stream_id).Discard(unordered, message_id); +bool RRSendQueue::Discard(StreamID stream_id, OutgoingMessageId message_id) { + bool has_discarded = GetOrCreateStreamInfo(stream_id).Discard(message_id); RTC_DCHECK(IsConsistent()); return has_discarded; diff --git a/net/dcsctp/tx/rr_send_queue.h b/net/dcsctp/tx/rr_send_queue.h index c4111ff717..bef5fe437d 100644 --- a/net/dcsctp/tx/rr_send_queue.h +++ b/net/dcsctp/tx/rr_send_queue.h @@ -22,6 +22,7 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/array_view.h" +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/public/dcsctp_message.h" #include "net/dcsctp/public/dcsctp_socket.h" #include "net/dcsctp/public/types.h" @@ -76,9 +77,7 @@ class RRSendQueue : public SendQueue { // Implementation of `SendQueue`. absl::optional Produce(TimeMs now, size_t max_size) override; - bool Discard(IsUnordered unordered, - StreamID stream_id, - MID message_id) override; + bool Discard(StreamID stream_id, OutgoingMessageId message_id) override; void PrepareResetStream(StreamID streams) override; bool HasStreamsReadyToBeReset() const override; std::vector GetStreamsReadyToBeReset() override; @@ -163,7 +162,7 @@ class RRSendQueue : public SendQueue { ThresholdWatcher& buffered_amount() { return buffered_amount_; } // Discards a partially sent message, see `SendQueue::Discard`. - bool Discard(IsUnordered unordered, MID message_id); + bool Discard(OutgoingMessageId message_id); // Pauses this stream, which is used before resetting it. void Pause(); @@ -219,11 +218,15 @@ class RRSendQueue : public SendQueue { // An enqueued message and metadata. struct Item { - explicit Item(DcSctpMessage msg, MessageAttributes attributes) - : message(std::move(msg)), + explicit Item(OutgoingMessageId message_id, + DcSctpMessage msg, + MessageAttributes attributes) + : message_id(message_id), + message(std::move(msg)), attributes(std::move(attributes)), remaining_offset(0), remaining_size(message.payload().size()) {} + OutgoingMessageId message_id; DcSctpMessage message; MessageAttributes attributes; // The remaining payload (offset and size) to be sent, when it has been @@ -232,7 +235,7 @@ class RRSendQueue : public SendQueue { size_t remaining_size; // If set, an allocated Message ID and SSN. Will be allocated when the // first fragment is sent. - absl::optional message_id = absl::nullopt; + absl::optional mid = absl::nullopt; absl::optional ssn = absl::nullopt; // The current Fragment Sequence Number, incremented for each fragment. FSN current_fsn = FSN(0); @@ -269,6 +272,7 @@ class RRSendQueue : public SendQueue { DcSctpSocketCallbacks& callbacks_; const size_t buffer_size_; const StreamPriority default_priority_; + OutgoingMessageId current_message_id = OutgoingMessageId(0); StreamScheduler scheduler_; // The total amount of buffer data, for all streams. diff --git a/net/dcsctp/tx/rr_send_queue_test.cc b/net/dcsctp/tx/rr_send_queue_test.cc index 95416b193a..9d6da7bdff 100644 --- a/net/dcsctp/tx/rr_send_queue_test.cc +++ b/net/dcsctp/tx/rr_send_queue_test.cc @@ -13,6 +13,7 @@ #include #include +#include "net/dcsctp/common/internal_types.h" #include "net/dcsctp/packet/data.h" #include "net/dcsctp/public/dcsctp_message.h" #include "net/dcsctp/public/dcsctp_options.h" @@ -227,8 +228,7 @@ TEST_F(RRSendQueueTest, DiscardPartialPackets) { ASSERT_TRUE(chunk_one.has_value()); EXPECT_FALSE(chunk_one->data.is_end); EXPECT_EQ(chunk_one->data.stream_id, kStreamID); - buf_.Discard(IsUnordered(false), chunk_one->data.stream_id, - chunk_one->data.message_id); + buf_.Discard(chunk_one->data.stream_id, chunk_one->message_id); absl::optional chunk_two = buf_.Produce(kNow, kOneFragmentPacketSize); @@ -244,8 +244,7 @@ TEST_F(RRSendQueueTest, DiscardPartialPackets) { ASSERT_FALSE(buf_.Produce(kNow, kOneFragmentPacketSize)); // Calling it again shouldn't cause issues. - buf_.Discard(IsUnordered(false), chunk_one->data.stream_id, - chunk_one->data.message_id); + buf_.Discard(chunk_one->data.stream_id, chunk_one->message_id); ASSERT_FALSE(buf_.Produce(kNow, kOneFragmentPacketSize)); } @@ -366,6 +365,32 @@ TEST_F(RRSendQueueTest, CommittingResetsSSN) { EXPECT_EQ(chunk_three->data.ssn, SSN(0)); } +TEST_F(RRSendQueueTest, CommittingDoesNotResetMessageId) { + std::vector payload(50); + + buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); + ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk1, + buf_.Produce(kNow, kOneFragmentPacketSize)); + EXPECT_EQ(chunk1.data.ssn, SSN(0)); + EXPECT_EQ(chunk1.message_id, OutgoingMessageId(0)); + + buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); + ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk2, + buf_.Produce(kNow, kOneFragmentPacketSize)); + EXPECT_EQ(chunk2.data.ssn, SSN(1)); + EXPECT_EQ(chunk2.message_id, OutgoingMessageId(1)); + + buf_.PrepareResetStream(kStreamID); + EXPECT_THAT(buf_.GetStreamsReadyToBeReset(), UnorderedElementsAre(kStreamID)); + buf_.CommitResetStreams(); + + buf_.Add(kNow, DcSctpMessage(kStreamID, kPPID, payload)); + ASSERT_HAS_VALUE_AND_ASSIGN(SendQueue::DataToSend chunk3, + buf_.Produce(kNow, kOneFragmentPacketSize)); + EXPECT_EQ(chunk3.data.ssn, SSN(0)); + EXPECT_EQ(chunk3.message_id, OutgoingMessageId(2)); +} + TEST_F(RRSendQueueTest, CommittingResetsSSNForPausedStreamsOnly) { std::vector payload(50); @@ -859,8 +884,7 @@ TEST_F(RRSendQueueTest, WillSendLifecycleExpireWhenDiscardingExplicitly) { EXPECT_CALL(callbacks_, OnLifecycleMessageExpired(LifecycleId(1), /*maybe_delivered=*/false)); EXPECT_CALL(callbacks_, OnLifecycleEnd(LifecycleId(1))); - buf_.Discard(IsUnordered(false), chunk_one->data.stream_id, - chunk_one->data.message_id); + buf_.Discard(chunk_one->data.stream_id, chunk_one->message_id); } } // namespace } // namespace dcsctp diff --git a/net/dcsctp/tx/send_queue.h b/net/dcsctp/tx/send_queue.h index 0b96e9041a..48eaefaf6a 100644 --- a/net/dcsctp/tx/send_queue.h +++ b/net/dcsctp/tx/send_queue.h @@ -27,7 +27,11 @@ class SendQueue { public: // Container for a data chunk that is produced by the SendQueue struct DataToSend { - explicit DataToSend(Data data) : data(std::move(data)) {} + DataToSend(OutgoingMessageId message_id, Data data) + : message_id(message_id), data(std::move(data)) {} + + OutgoingMessageId message_id; + // The data to send, including all parameters. Data data; @@ -53,7 +57,7 @@ class SendQueue { // including any headers. virtual absl::optional Produce(TimeMs now, size_t max_size) = 0; - // Discards a partially sent message identified by the parameters `unordered`, + // Discards a partially sent message identified by the parameters // `stream_id` and `message_id`. The `message_id` comes from the returned // information when having called `Produce`. A partially sent message means // that it has had at least one fragment of it returned when `Produce` was @@ -67,9 +71,7 @@ class SendQueue { // // This function returns true if this message had unsent fragments still in // the queue that were discarded, and false if there were no such fragments. - virtual bool Discard(IsUnordered unordered, - StreamID stream_id, - MID message_id) = 0; + virtual bool Discard(StreamID stream_id, OutgoingMessageId message_id) = 0; // Prepares the stream to be reset. This is used to close a WebRTC data // channel and will be signaled to the other side. diff --git a/net/dcsctp/tx/stream_scheduler_test.cc b/net/dcsctp/tx/stream_scheduler_test.cc index 20833371c1..4f5fb0fb84 100644 --- a/net/dcsctp/tx/stream_scheduler_test.cc +++ b/net/dcsctp/tx/stream_scheduler_test.cc @@ -29,8 +29,8 @@ MATCHER_P(HasDataWithMid, mid, "") { return false; } - if (arg->data.message_id != mid) { - *result_listener << "the produced data had mid " << *arg->data.message_id + if (arg->data.mid != mid) { + *result_listener << "the produced data had mid " << *arg->data.mid << " and not the expected " << *mid; return false; } @@ -39,11 +39,16 @@ MATCHER_P(HasDataWithMid, mid, "") { } std::function(TimeMs, size_t)> -CreateChunk(StreamID sid, MID mid, size_t payload_size = kPayloadSize) { - return [sid, mid, payload_size](TimeMs now, size_t max_size) { - return SendQueue::DataToSend(Data( - sid, SSN(0), mid, FSN(0), PPID(42), std::vector(payload_size), - Data::IsBeginning(true), Data::IsEnd(true), IsUnordered(true))); +CreateChunk(OutgoingMessageId message_id, + StreamID sid, + MID mid, + size_t payload_size = kPayloadSize) { + return [sid, mid, payload_size, message_id](TimeMs now, size_t max_size) { + return SendQueue::DataToSend( + message_id, + Data(sid, SSN(0), mid, FSN(0), PPID(42), + std::vector(payload_size), Data::IsBeginning(true), + Data::IsEnd(true), IsUnordered(true))); }; } @@ -76,7 +81,8 @@ class TestStream { StreamPriority priority, size_t packet_size = kPayloadSize) { EXPECT_CALL(producer_, Produce) - .WillRepeatedly(CreateChunk(stream_id, MID(0), packet_size)); + .WillRepeatedly( + CreateChunk(OutgoingMessageId(0), stream_id, MID(0), packet_size)); EXPECT_CALL(producer_, bytes_to_send_in_next_message) .WillRepeatedly(Return(packet_size)); stream_ = scheduler.CreateStream(&producer_, stream_id, priority); @@ -117,7 +123,8 @@ TEST(StreamSchedulerTest, CanProduceFromSingleStream) { StreamScheduler scheduler("", kMtu); StrictMock producer; - EXPECT_CALL(producer, Produce).WillOnce(CreateChunk(StreamID(1), MID(0))); + EXPECT_CALL(producer, Produce) + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(0))); EXPECT_CALL(producer, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(0)); @@ -135,9 +142,9 @@ TEST(StreamSchedulerTest, WillRoundRobinBetweenStreams) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) - .WillOnce(CreateChunk(StreamID(1), MID(101))) - .WillOnce(CreateChunk(StreamID(1), MID(102))); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101))) + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102))); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -149,9 +156,9 @@ TEST(StreamSchedulerTest, WillRoundRobinBetweenStreams) { StrictMock producer2; EXPECT_CALL(producer2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(200))) - .WillOnce(CreateChunk(StreamID(2), MID(201))) - .WillOnce(CreateChunk(StreamID(2), MID(202))); + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(200))) + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(201))) + .WillOnce(CreateChunk(OutgoingMessageId(6), StreamID(2), MID(202))); EXPECT_CALL(producer2, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -177,26 +184,29 @@ TEST(StreamSchedulerTest, WillRoundRobinOnlyWhenFinishedProducingChunk) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) .WillOnce([](...) { return SendQueue::DataToSend( + OutgoingMessageId(1), Data(StreamID(1), SSN(0), MID(101), FSN(0), PPID(42), std::vector(4), Data::IsBeginning(true), Data::IsEnd(false), IsUnordered(true))); }) .WillOnce([](...) { return SendQueue::DataToSend( + OutgoingMessageId(1), Data(StreamID(1), SSN(0), MID(101), FSN(0), PPID(42), std::vector(4), Data::IsBeginning(false), Data::IsEnd(false), IsUnordered(true))); }) .WillOnce([](...) { return SendQueue::DataToSend( + OutgoingMessageId(1), Data(StreamID(1), SSN(0), MID(101), FSN(0), PPID(42), std::vector(4), Data::IsBeginning(false), Data::IsEnd(true), IsUnordered(true))); }) - .WillOnce(CreateChunk(StreamID(1), MID(102))); + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102))); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -210,9 +220,9 @@ TEST(StreamSchedulerTest, WillRoundRobinOnlyWhenFinishedProducingChunk) { StrictMock producer2; EXPECT_CALL(producer2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(200))) - .WillOnce(CreateChunk(StreamID(2), MID(201))) - .WillOnce(CreateChunk(StreamID(2), MID(202))); + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(200))) + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(201))) + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(202))); EXPECT_CALL(producer2, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -239,8 +249,8 @@ TEST(StreamSchedulerTest, StreamsCanBeMadeInactive) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) - .WillOnce(CreateChunk(StreamID(1), MID(101))); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101))); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -264,9 +274,9 @@ TEST(StreamSchedulerTest, SingleStreamCanBeResumed) { StrictMock producer1; // Callbacks are setup so that they hint that there is a MID(2) coming... EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) - .WillOnce(CreateChunk(StreamID(1), MID(101))) - .WillOnce(CreateChunk(StreamID(1), MID(102))); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101))) + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102))); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -293,9 +303,9 @@ TEST(StreamSchedulerTest, WillRoundRobinWithPausedStream) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) - .WillOnce(CreateChunk(StreamID(1), MID(101))) - .WillOnce(CreateChunk(StreamID(1), MID(102))); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101))) + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102))); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -308,9 +318,9 @@ TEST(StreamSchedulerTest, WillRoundRobinWithPausedStream) { StrictMock producer2; EXPECT_CALL(producer2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(200))) - .WillOnce(CreateChunk(StreamID(2), MID(201))) - .WillOnce(CreateChunk(StreamID(2), MID(202))); + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(200))) + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(201))) + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(202))); EXPECT_CALL(producer2, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -384,9 +394,12 @@ TEST(StreamSchedulerTest, WillDoFairQueuingWithSamePriority) { StrictMock callback1; EXPECT_CALL(callback1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100), kSmallPacket)) - .WillOnce(CreateChunk(StreamID(1), MID(101), kSmallPacket)) - .WillOnce(CreateChunk(StreamID(1), MID(102), kSmallPacket)); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100), + kSmallPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101), + kSmallPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102), + kSmallPacket)); EXPECT_CALL(callback1, bytes_to_send_in_next_message) .WillOnce(Return(kSmallPacket)) // When making active .WillOnce(Return(kSmallPacket)) @@ -398,9 +411,12 @@ TEST(StreamSchedulerTest, WillDoFairQueuingWithSamePriority) { StrictMock callback2; EXPECT_CALL(callback2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(200), kLargePacket)) - .WillOnce(CreateChunk(StreamID(2), MID(201), kLargePacket)) - .WillOnce(CreateChunk(StreamID(2), MID(202), kLargePacket)); + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(200), + kLargePacket)) + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(201), + kLargePacket)) + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(202), + kLargePacket)); EXPECT_CALL(callback2, bytes_to_send_in_next_message) .WillOnce(Return(kLargePacket)) // When making active .WillOnce(Return(kLargePacket)) @@ -432,9 +448,9 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingSameSizeDifferentPriority) { StrictMock callback1; EXPECT_CALL(callback1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(100))) - .WillOnce(CreateChunk(StreamID(1), MID(101))) - .WillOnce(CreateChunk(StreamID(1), MID(102))); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100))) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101))) + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102))); EXPECT_CALL(callback1, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -447,9 +463,9 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingSameSizeDifferentPriority) { StrictMock callback2; EXPECT_CALL(callback2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(200))) - .WillOnce(CreateChunk(StreamID(2), MID(201))) - .WillOnce(CreateChunk(StreamID(2), MID(202))); + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(200))) + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(201))) + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(202))); EXPECT_CALL(callback2, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -462,9 +478,9 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingSameSizeDifferentPriority) { StrictMock callback3; EXPECT_CALL(callback3, Produce) - .WillOnce(CreateChunk(StreamID(3), MID(300))) - .WillOnce(CreateChunk(StreamID(3), MID(301))) - .WillOnce(CreateChunk(StreamID(3), MID(302))); + .WillOnce(CreateChunk(OutgoingMessageId(6), StreamID(3), MID(300))) + .WillOnce(CreateChunk(OutgoingMessageId(7), StreamID(3), MID(301))) + .WillOnce(CreateChunk(OutgoingMessageId(8), StreamID(3), MID(302))); EXPECT_CALL(callback3, bytes_to_send_in_next_message) .WillOnce(Return(kPayloadSize)) // When making active .WillOnce(Return(kPayloadSize)) @@ -510,11 +526,14 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingDifferentSizeAndPriority) { StrictMock callback1; EXPECT_CALL(callback1, Produce) // virtual finish time ~ 0 + 50 * 80 = 4000 - .WillOnce(CreateChunk(StreamID(1), MID(100), kMediumPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(100), + kMediumPacket)) // virtual finish time ~ 4000 + 20 * 80 = 5600 - .WillOnce(CreateChunk(StreamID(1), MID(101), kSmallPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(101), + kSmallPacket)) // virtual finish time ~ 5600 + 70 * 80 = 11200 - .WillOnce(CreateChunk(StreamID(1), MID(102), kLargePacket)); + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(1), MID(102), + kLargePacket)); EXPECT_CALL(callback1, bytes_to_send_in_next_message) .WillOnce(Return(kMediumPacket)) // When making active .WillOnce(Return(kSmallPacket)) @@ -528,11 +547,14 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingDifferentSizeAndPriority) { StrictMock callback2; EXPECT_CALL(callback2, Produce) // virtual finish time ~ 0 + 50 * 50 = 2500 - .WillOnce(CreateChunk(StreamID(2), MID(200), kMediumPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(200), + kMediumPacket)) // virtual finish time ~ 2500 + 70 * 50 = 6000 - .WillOnce(CreateChunk(StreamID(2), MID(201), kLargePacket)) + .WillOnce(CreateChunk(OutgoingMessageId(4), StreamID(2), MID(201), + kLargePacket)) // virtual finish time ~ 6000 + 20 * 50 = 7000 - .WillOnce(CreateChunk(StreamID(2), MID(202), kSmallPacket)); + .WillOnce(CreateChunk(OutgoingMessageId(5), StreamID(2), MID(202), + kSmallPacket)); EXPECT_CALL(callback2, bytes_to_send_in_next_message) .WillOnce(Return(kMediumPacket)) // When making active .WillOnce(Return(kLargePacket)) @@ -546,11 +568,14 @@ TEST(StreamSchedulerTest, WillDoWeightedFairQueuingDifferentSizeAndPriority) { StrictMock callback3; EXPECT_CALL(callback3, Produce) // virtual finish time ~ 0 + 20 * 20 = 400 - .WillOnce(CreateChunk(StreamID(3), MID(300), kSmallPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(6), StreamID(3), MID(300), + kSmallPacket)) // virtual finish time ~ 400 + 50 * 20 = 1400 - .WillOnce(CreateChunk(StreamID(3), MID(301), kMediumPacket)) + .WillOnce(CreateChunk(OutgoingMessageId(7), StreamID(3), MID(301), + kMediumPacket)) // virtual finish time ~ 1400 + 70 * 20 = 2800 - .WillOnce(CreateChunk(StreamID(3), MID(302), kLargePacket)); + .WillOnce(CreateChunk(OutgoingMessageId(8), StreamID(3), MID(302), + kLargePacket)); EXPECT_CALL(callback3, bytes_to_send_in_next_message) .WillOnce(Return(kSmallPacket)) // When making active .WillOnce(Return(kMediumPacket)) @@ -677,8 +702,8 @@ TEST(StreamSchedulerTest, SendLargeMessageWithSmallMtu) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(0), 100)) - .WillOnce(CreateChunk(StreamID(1), MID(0), 100)); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(0), 100)) + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(1), MID(0), 100)); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(200)) // When making active .WillOnce(Return(100)) @@ -689,8 +714,8 @@ TEST(StreamSchedulerTest, SendLargeMessageWithSmallMtu) { StrictMock producer2; EXPECT_CALL(producer2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(1), 100)) - .WillOnce(CreateChunk(StreamID(2), MID(1), 50)); + .WillOnce(CreateChunk(OutgoingMessageId(2), StreamID(2), MID(1), 100)) + .WillOnce(CreateChunk(OutgoingMessageId(3), StreamID(2), MID(1), 50)); EXPECT_CALL(producer2, bytes_to_send_in_next_message) .WillOnce(Return(150)) // When making active .WillOnce(Return(50)) @@ -714,7 +739,7 @@ TEST(StreamSchedulerTest, SendLargeMessageWithLargeMtu) { StrictMock producer1; EXPECT_CALL(producer1, Produce) - .WillOnce(CreateChunk(StreamID(1), MID(0), 200)); + .WillOnce(CreateChunk(OutgoingMessageId(0), StreamID(1), MID(0), 200)); EXPECT_CALL(producer1, bytes_to_send_in_next_message) .WillOnce(Return(200)) // When making active .WillOnce(Return(0)); @@ -724,7 +749,7 @@ TEST(StreamSchedulerTest, SendLargeMessageWithLargeMtu) { StrictMock producer2; EXPECT_CALL(producer2, Produce) - .WillOnce(CreateChunk(StreamID(2), MID(1), 150)); + .WillOnce(CreateChunk(OutgoingMessageId(1), StreamID(2), MID(1), 150)); EXPECT_CALL(producer2, bytes_to_send_in_next_message) .WillOnce(Return(150)) // When making active .WillOnce(Return(0)); diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index ee79a55306..c6f69badb2 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -164,6 +164,7 @@ rtc_library("rtc_p2p") { "../api/task_queue:pending_task_safety_flag", "../rtc_base:safe_minmax", "../rtc_base:weak_ptr", + "../rtc_base/network:received_packet", "../rtc_base/network:sent_packet", "../rtc_base/synchronization:mutex", "../rtc_base/system:rtc_export", @@ -396,6 +397,7 @@ rtc_library("libstunprober") { deps = [ ":rtc_p2p", + "../api:async_dns_resolver", "../api:packet_socket_factory", "../api:sequence_checker", "../api/task_queue:pending_task_safety_flag", diff --git a/p2p/base/basic_async_resolver_factory.cc b/p2p/base/basic_async_resolver_factory.cc index 67c81670d2..5a8c7a27a7 100644 --- a/p2p/base/basic_async_resolver_factory.cc +++ b/p2p/base/basic_async_resolver_factory.cc @@ -22,9 +22,12 @@ namespace webrtc { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" rtc::AsyncResolverInterface* BasicAsyncResolverFactory::Create() { return new rtc::AsyncResolver(); } +#pragma clang diagnostic pop std::unique_ptr BasicAsyncDnsResolverFactory::Create() { diff --git a/p2p/base/basic_async_resolver_factory.h b/p2p/base/basic_async_resolver_factory.h index 9c1af6a1e1..1a94fb9679 100644 --- a/p2p/base/basic_async_resolver_factory.h +++ b/p2p/base/basic_async_resolver_factory.h @@ -21,10 +21,15 @@ namespace webrtc { -class BasicAsyncResolverFactory final : public AsyncResolverFactory { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +class [[deprecated( + "Use BasicAsyncDnsResolverFactory")]] BasicAsyncResolverFactory final + : public AsyncResolverFactory { public: rtc::AsyncResolverInterface* Create() override; }; +#pragma clang diagnostic pop // A factory that vends AsyncDnsResolver instances. class BasicAsyncDnsResolverFactory final @@ -47,9 +52,11 @@ class BasicAsyncDnsResolverFactory final // This class wraps a factory using the older webrtc::AsyncResolverFactory API, // and produces webrtc::AsyncDnsResolver objects that contain an // rtc::AsyncResolver object. -class WrappingAsyncDnsResolverFactory final +class [[deprecated]] WrappingAsyncDnsResolverFactory final : public AsyncDnsResolverFactoryInterface { public: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" explicit WrappingAsyncDnsResolverFactory( std::unique_ptr wrapped_factory) : owned_factory_(std::move(wrapped_factory)), @@ -58,6 +65,7 @@ class WrappingAsyncDnsResolverFactory final explicit WrappingAsyncDnsResolverFactory( AsyncResolverFactory* non_owned_factory) : wrapped_factory_(non_owned_factory) {} +#pragma clang diagnostic pop std::unique_ptr CreateAndResolve( const rtc::SocketAddress& addr, diff --git a/p2p/base/basic_async_resolver_factory_unittest.cc b/p2p/base/basic_async_resolver_factory_unittest.cc index 77b97e75e6..313907abb9 100644 --- a/p2p/base/basic_async_resolver_factory_unittest.cc +++ b/p2p/base/basic_async_resolver_factory_unittest.cc @@ -22,6 +22,9 @@ namespace webrtc { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + class BasicAsyncResolverFactoryTest : public ::testing::Test, public sigslot::has_slots<> { public: @@ -108,4 +111,6 @@ TEST(WrappingAsyncDnsResolverFactoryDeathTest, DestroyResolverInCallback) { } #endif +#pragma clang diagnostic pop + } // namespace webrtc diff --git a/p2p/base/basic_packet_socket_factory.cc b/p2p/base/basic_packet_socket_factory.cc index cdfc1e4327..ac57761dea 100644 --- a/p2p/base/basic_packet_socket_factory.cc +++ b/p2p/base/basic_packet_socket_factory.cc @@ -18,6 +18,7 @@ #include "api/async_dns_resolver.h" #include "api/wrapping_async_dns_resolver.h" #include "p2p/base/async_stun_tcp_socket.h" +#include "rtc_base/async_dns_resolver.h" #include "rtc_base/async_tcp_socket.h" #include "rtc_base/async_udp_socket.h" #include "rtc_base/checks.h" @@ -186,8 +187,7 @@ AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() { std::unique_ptr BasicPacketSocketFactory::CreateAsyncDnsResolver() { - return std::make_unique( - new AsyncResolver()); + return std::make_unique(); } int BasicPacketSocketFactory::BindSocket(Socket* socket, diff --git a/p2p/base/connection.cc b/p2p/base/connection.cc index 60fc1e7ff0..517f16b1d0 100644 --- a/p2p/base/connection.cc +++ b/p2p/base/connection.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,9 @@ #include "absl/strings/escaping.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/units/timestamp.h" #include "p2p/base/port_allocator.h" #include "rtc_base/checks.h" #include "rtc_base/crc32.h" @@ -246,6 +250,7 @@ Connection::Connection(rtc::WeakPtr port, Connection::~Connection() { RTC_DCHECK_RUN_ON(network_thread_); RTC_DCHECK(!port_); + RTC_DCHECK(!received_packet_callback_); } webrtc::TaskQueueBase* Connection::network_thread() const { @@ -262,14 +267,17 @@ const Candidate& Connection::remote_candidate() const { } const rtc::Network* Connection::network() const { + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in network()"; return port()->Network(); } int Connection::generation() const { + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in generation()"; return port()->generation(); } uint64_t Connection::priority() const { + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in priority()"; if (!port_) return 0; @@ -442,6 +450,19 @@ void Connection::OnSendStunPacket(const void* data, } } +void Connection::RegisterReceivedPacketCallback( + absl::AnyInvocable + received_packet_callback) { + RTC_DCHECK_RUN_ON(network_thread_); + RTC_CHECK(!received_packet_callback_); + received_packet_callback_ = std::move(received_packet_callback); +} + +void Connection::DeregisterReceivedPacketCallback() { + RTC_DCHECK_RUN_ON(network_thread_); + received_packet_callback_ = nullptr; +} + void Connection::OnReadPacket(const char* data, size_t size, int64_t packet_time_us) { @@ -456,8 +477,22 @@ void Connection::OnReadPacket(const char* data, UpdateReceiving(last_data_received_); recv_rate_tracker_.AddSamples(size); stats_.packets_received++; - SignalReadPacket(this, data, size, packet_time_us); - + if (received_packet_callback_) { + RTC_DCHECK(packet_time_us == -1 || packet_time_us >= 0); + RTC_DCHECK(SignalReadPacket.is_empty()); + received_packet_callback_( + this, rtc::ReceivedPacket( + rtc::reinterpret_array_view( + rtc::MakeArrayView(data, size)), + (packet_time_us >= 0) + ? absl::optional( + webrtc::Timestamp::Micros(packet_time_us)) + : absl::nullopt)); + } else { + // TODO(webrtc:11943): Remove SignalReadPacket once upstream projects have + // switched to use RegisterReceivedPacket. + SignalReadPacket(this, data, size, packet_time_us); + } // If timed out sending writability checks, start up again if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) { RTC_LOG(LS_WARNING) @@ -806,13 +841,14 @@ void Connection::Prune() { void Connection::Destroy() { RTC_DCHECK_RUN_ON(network_thread_); - RTC_DCHECK(port_) << "Calling Destroy() twice?"; + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in Destroy()"; if (port_) port_->DestroyConnection(this); } bool Connection::Shutdown() { RTC_DCHECK_RUN_ON(network_thread_); + RTC_DCHECK(port_) << ToDebugId() << ": Calling Shutdown() twice?"; if (!port_) return false; // already shut down. @@ -832,6 +868,9 @@ bool Connection::Shutdown() { // information required for logging needs access to `port_`. port_.reset(); + // Clear any pending requests (or responses). + requests_.Clear(); + return true; } @@ -846,6 +885,7 @@ void Connection::FailAndPrune() { // will be nulled. // In such a case, there's a chance that the Port object gets // deleted before the Connection object ends up being deleted. + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in FailAndPrune()"; if (!port_) return; @@ -882,6 +922,7 @@ void Connection::set_selected(bool selected) { void Connection::UpdateState(int64_t now) { RTC_DCHECK_RUN_ON(network_thread_); + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in UpdateState()"; if (!port_) return; @@ -958,6 +999,7 @@ int64_t Connection::last_ping_sent() const { void Connection::Ping(int64_t now, std::unique_ptr delta) { RTC_DCHECK_RUN_ON(network_thread_); + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in Ping()"; if (!port_) return; @@ -1251,11 +1293,13 @@ std::string Connection::ToDebugId() const { uint32_t Connection::ComputeNetworkCost() const { // TODO(honghaiz): Will add rtt as part of the network cost. + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in ComputeNetworkCost()"; return port()->network_cost() + remote_candidate_.network_cost(); } std::string Connection::ToString() const { RTC_DCHECK_RUN_ON(network_thread_); + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in ToString()"; constexpr absl::string_view CONNECT_STATE_ABBREV[2] = { "-", // not connected (false) "C", // connected (true) @@ -1457,6 +1501,8 @@ void Connection::OnConnectionRequestResponse(StunRequest* request, void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request, StunMessage* response) { + RTC_DCHECK(port_) << ToDebugId() + << ": port_ null in OnConnectionRequestErrorResponse"; if (!port_) return; @@ -1610,6 +1656,8 @@ ConnectionInfo Connection::stats() { void Connection::MaybeUpdateLocalCandidate(StunRequest* request, StunMessage* response) { + RTC_DCHECK(port_) << ToDebugId() + << ": port_ null in MaybeUpdateLocalCandidate"; if (!port_) return; @@ -1754,6 +1802,7 @@ ProxyConnection::ProxyConnection(rtc::WeakPtr port, int ProxyConnection::Send(const void* data, size_t size, const rtc::PacketOptions& options) { + RTC_DCHECK(port_) << ToDebugId() << ": port_ null in Send()"; if (!port_) return SOCKET_ERROR; diff --git a/p2p/base/connection.h b/p2p/base/connection.h index 8e439855fa..3481c69cd9 100644 --- a/p2p/base/connection.h +++ b/p2p/base/connection.h @@ -28,6 +28,7 @@ #include "p2p/base/transport_description.h" #include "rtc_base/async_packet_socket.h" #include "rtc_base/network.h" +#include "rtc_base/network/received_packet.h" #include "rtc_base/numerics/event_based_exponential_moving_average.h" #include "rtc_base/rate_tracker.h" #include "rtc_base/system/rtc_export.h" @@ -111,6 +112,7 @@ class RTC_EXPORT Connection : public CandidatePairInterface { bool connected() const; bool weak() const; bool active() const; + bool pending_delete() const { return !port_; } // A connection is dead if it can be safely deleted. bool dead(int64_t now) const; @@ -145,8 +147,16 @@ class RTC_EXPORT Connection : public CandidatePairInterface { // Error if Send() returns < 0 virtual int GetError() = 0; + // TODO(webrtc:11943): Remove SignalReadPacket once upstream projects have + // switched to use RegisterReceivedPacket. sigslot::signal4 SignalReadPacket; + // Register as a recipient of received packets. There can only be one. + void RegisterReceivedPacketCallback( + absl::AnyInvocable + received_packet_callback); + void DeregisterReceivedPacketCallback(); + sigslot::signal1 SignalReadyToSend; // Called when a packet is received on this connection. @@ -500,6 +510,8 @@ class RTC_EXPORT Connection : public CandidatePairInterface { absl::optional< std::function)>> goog_delta_ack_consumer_; + absl::AnyInvocable + received_packet_callback_; }; // ProxyConnection defers all the interesting work to the port. diff --git a/p2p/base/dtls_transport.cc b/p2p/base/dtls_transport.cc index 3a61fd4029..a9ff9d3784 100644 --- a/p2p/base/dtls_transport.cc +++ b/p2p/base/dtls_transport.cc @@ -416,6 +416,13 @@ bool DtlsTransport::GetSslVersionBytes(int* version) const { return dtls_->GetSslVersionBytes(version); } +uint16_t DtlsTransport::GetSslPeerSignatureAlgorithm() const { + if (dtls_state() != webrtc::DtlsTransportState::kConnected) { + return rtc::kSslSignatureAlgorithmUnknown; // "not applicable" + } + return dtls_->GetPeerSignatureAlgorithm(); +} + // Called from upper layers to send a media packet. int DtlsTransport::SendPacket(const char* data, size_t size, diff --git a/p2p/base/dtls_transport.h b/p2p/base/dtls_transport.h index 4e21410b76..9408025be5 100644 --- a/p2p/base/dtls_transport.h +++ b/p2p/base/dtls_transport.h @@ -158,6 +158,12 @@ class DtlsTransport : public DtlsTransportInternal { // Find out which DTLS-SRTP cipher was negotiated bool GetSrtpCryptoSuite(int* cipher) override; + // Find out which signature algorithm was used by the peer. Returns values + // from + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme + // If not applicable, it returns zero. + uint16_t GetSslPeerSignatureAlgorithm() const override; + bool GetDtlsRole(rtc::SSLRole* role) const override; bool SetDtlsRole(rtc::SSLRole role) override; diff --git a/p2p/base/dtls_transport_internal.h b/p2p/base/dtls_transport_internal.h index 3d20d1bfd6..cbcd2bdf88 100644 --- a/p2p/base/dtls_transport_internal.h +++ b/p2p/base/dtls_transport_internal.h @@ -71,6 +71,12 @@ class DtlsTransportInternal : public rtc::PacketTransportInternal { // TODO(zhihuang): Remove this once all dependencies implement this. virtual bool GetSslCipherSuite(int* cipher) = 0; + // Find out which signature algorithm was used by the peer. Returns values + // from + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme + // If not applicable, it returns zero. + virtual uint16_t GetSslPeerSignatureAlgorithm() const = 0; + // Gets the local RTCCertificate used for DTLS. virtual rtc::scoped_refptr GetLocalCertificate() const = 0; diff --git a/p2p/base/fake_dtls_transport.h b/p2p/base/fake_dtls_transport.h index 283488bc38..5a3db4886b 100644 --- a/p2p/base/fake_dtls_transport.h +++ b/p2p/base/fake_dtls_transport.h @@ -205,6 +205,7 @@ class FakeDtlsTransport : public DtlsTransportInternal { void SetSslCipherSuite(absl::optional cipher_suite) { ssl_cipher_suite_ = cipher_suite; } + uint16_t GetSslPeerSignatureAlgorithm() const override { return 0; } rtc::scoped_refptr GetLocalCertificate() const override { return local_cert_; } diff --git a/p2p/base/fake_port_allocator.h b/p2p/base/fake_port_allocator.h index c829587f47..395b54a932 100644 --- a/p2p/base/fake_port_allocator.h +++ b/p2p/base/fake_port_allocator.h @@ -67,6 +67,7 @@ class TestUDPPort : public UDPPort { bool emit_localhost_for_anyaddress, const webrtc::FieldTrialsView* field_trials) : UDPPort(thread, + LOCAL_PORT_TYPE, factory, network, min_port, diff --git a/p2p/base/ice_transport_internal.h b/p2p/base/ice_transport_internal.h index 526a8517cd..86b64a4198 100644 --- a/p2p/base/ice_transport_internal.h +++ b/p2p/base/ice_transport_internal.h @@ -110,7 +110,9 @@ webrtc::RTCError VerifyCandidates(const Candidates& candidates); // Information about ICE configuration. // TODO(deadbeef): Use absl::optional to represent unset values, instead of // -1. -struct IceConfig { +// +// TODO(bugs.webrtc.org/15609): Define a public API for this. +struct RTC_EXPORT IceConfig { // The ICE connection receiving timeout value in milliseconds. absl::optional receiving_timeout; // Time interval in milliseconds to ping a backup connection when the ICE @@ -239,6 +241,8 @@ enum class IceTransportState { // Once the public interface is supported, // (https://www.w3.org/TR/webrtc/#rtcicetransport) // the IceTransportInterface will be split from this class. +// +// TODO(bugs.webrtc.org/15609): Define a public API for this. class RTC_EXPORT IceTransportInternal : public rtc::PacketTransportInternal { public: IceTransportInternal(); diff --git a/p2p/base/mock_async_resolver.h b/p2p/base/mock_async_resolver.h index 44164716b2..73ad1a4c34 100644 --- a/p2p/base/mock_async_resolver.h +++ b/p2p/base/mock_async_resolver.h @@ -20,7 +20,10 @@ namespace rtc { using ::testing::_; using ::testing::InvokeWithoutArgs; -class MockAsyncResolver : public AsyncResolverInterface { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +class [[deprecated]] MockAsyncResolver : public AsyncResolverInterface { +#pragma clang diagnostic pop public: MockAsyncResolver() { ON_CALL(*this, Start(_)).WillByDefault(InvokeWithoutArgs([this] { @@ -47,11 +50,13 @@ class MockAsyncResolver : public AsyncResolverInterface { namespace webrtc { -class MockAsyncResolverFactory : public AsyncResolverFactory { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +class [[deprecated]] MockAsyncResolverFactory : public AsyncResolverFactory { public: MOCK_METHOD(rtc::AsyncResolverInterface*, Create, (), (override)); }; - +#pragma clang diagnostic pop } // namespace webrtc #endif // P2P_BASE_MOCK_ASYNC_RESOLVER_H_ diff --git a/p2p/base/p2p_transport_channel.cc b/p2p/base/p2p_transport_channel.cc index 379caa61ea..8263e28a2f 100644 --- a/p2p/base/p2p_transport_channel.cc +++ b/p2p/base/p2p_transport_channel.cc @@ -318,8 +318,10 @@ void P2PTransportChannel::AddConnection(Connection* connection) { connection->set_unwritable_timeout(config_.ice_unwritable_timeout); connection->set_unwritable_min_checks(config_.ice_unwritable_min_checks); connection->set_inactive_timeout(config_.ice_inactive_timeout); - connection->SignalReadPacket.connect(this, - &P2PTransportChannel::OnReadPacket); + connection->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + OnReadPacket(connection, packet); + }); connection->SignalReadyToSend.connect(this, &P2PTransportChannel::OnReadyToSend); connection->SignalStateChange.connect( @@ -2296,6 +2298,7 @@ void P2PTransportChannel::RemoveConnection(Connection* connection) { RTC_DCHECK_RUN_ON(network_thread_); auto it = absl::c_find(connections_, connection); RTC_DCHECK(it != connections_.end()); + connection->DeregisterReceivedPacketCallback(); connections_.erase(it); connection->ClearStunDictConsumer(); ice_controller_->OnConnectionDestroyed(connection); @@ -2366,39 +2369,30 @@ bool P2PTransportChannel::PrunePort(PortInterface* port) { // We data is available, let listeners know void P2PTransportChannel::OnReadPacket(Connection* connection, - const char* data, - size_t len, - int64_t packet_time_us) { + const rtc::ReceivedPacket& packet) { RTC_DCHECK_RUN_ON(network_thread_); - - if (connection == selected_connection_) { - // Let the client know of an incoming packet - packets_received_++; - bytes_received_ += len; - RTC_DCHECK(connection->last_data_received() >= last_data_received_ms_); - last_data_received_ms_ = - std::max(last_data_received_ms_, connection->last_data_received()); - SignalReadPacket(this, data, len, packet_time_us, 0); + if (connection != selected_connection_ && !FindConnection(connection)) { + // Do not deliver, if packet doesn't belong to the correct transport + // channel. + RTC_DCHECK_NOTREACHED(); return; } - // Do not deliver, if packet doesn't belong to the correct transport - // channel. - if (!FindConnection(connection)) - return; + // Let the client know of an incoming packet + packets_received_++; + bytes_received_ += packet.payload().size(); + RTC_DCHECK(connection->last_data_received() >= last_data_received_ms_); + last_data_received_ms_ = + std::max(last_data_received_ms_, connection->last_data_received()); - packets_received_++; - bytes_received_ += len; - RTC_DCHECK(connection->last_data_received() >= last_data_received_ms_); - last_data_received_ms_ = - std::max(last_data_received_ms_, connection->last_data_received()); - - // Let the client know of an incoming packet - SignalReadPacket(this, data, len, packet_time_us, 0); + SignalReadPacket( + this, reinterpret_cast(packet.payload().data()), + packet.payload().size(), + packet.arrival_time() ? packet.arrival_time()->us() : -1, 0); // May need to switch the sending connection based on the receiving media // path if this is the controlled side. - if (ice_role_ == ICEROLE_CONTROLLED) { + if (ice_role_ == ICEROLE_CONTROLLED && connection != selected_connection_) { ice_controller_->OnImmediateSwitchRequest(IceSwitchReason::DATA_RECEIVED, connection); } diff --git a/p2p/base/p2p_transport_channel.h b/p2p/base/p2p_transport_channel.h index 4f4eacaaf8..1304a13966 100644 --- a/p2p/base/p2p_transport_channel.h +++ b/p2p/base/p2p_transport_channel.h @@ -370,10 +370,7 @@ class RTC_EXPORT P2PTransportChannel : public IceTransportInternal, void OnRoleConflictIgnored(PortInterface* port); void OnConnectionStateChange(Connection* connection); - void OnReadPacket(Connection* connection, - const char* data, - size_t len, - int64_t packet_time_us); + void OnReadPacket(Connection* connection, const rtc::ReceivedPacket& packet); void OnSentPacket(const rtc::SentPacket& sent_packet); void OnReadyToSend(Connection* connection); void OnConnectionDestroyed(Connection* connection); diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 2e9dbf63c4..e13e60927a 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -188,11 +188,11 @@ void Port::Construct() { Port::~Port() { RTC_DCHECK_RUN_ON(thread_); - CancelPendingTasks(); DestroyAllConnections(); + CancelPendingTasks(); } -const std::string& Port::Type() const { +const absl::string_view Port::Type() const { return type_; } const rtc::Network* Port::Network() const { diff --git a/p2p/base/port.h b/p2p/base/port.h index f8148da699..2682645152 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -18,6 +18,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/candidate.h" @@ -185,14 +186,14 @@ class RTC_EXPORT Port : public PortInterface, public sigslot::has_slots<> { // 30 seconds. enum class State { INIT, KEEP_ALIVE_UNTIL_PRUNED, PRUNED }; Port(webrtc::TaskQueueBase* thread, - absl::string_view type, + absl::string_view type ABSL_ATTRIBUTE_LIFETIME_BOUND, rtc::PacketSocketFactory* factory, const rtc::Network* network, absl::string_view username_fragment, absl::string_view password, const webrtc::FieldTrialsView* field_trials = nullptr); Port(webrtc::TaskQueueBase* thread, - absl::string_view type, + absl::string_view type ABSL_ATTRIBUTE_LIFETIME_BOUND, rtc::PacketSocketFactory* factory, const rtc::Network* network, uint16_t min_port, @@ -207,7 +208,7 @@ class RTC_EXPORT Port : public PortInterface, public sigslot::has_slots<> { // uniquely identify subclasses. Whenever a new subclass of Port introduces a // conflit in the value of the 2-tuple, make sure that the implementation that // relies on this 2-tuple for RTTI is properly changed. - const std::string& Type() const override; + const absl::string_view Type() const override; const rtc::Network* Network() const override; // Methods to set/get ICE role and tiebreaker values. @@ -391,8 +392,6 @@ class RTC_EXPORT Port : public PortInterface, public sigslot::has_slots<> { protected: virtual void UpdateNetworkCost(); - void set_type(absl::string_view type) { type_ = std::string(type); } - rtc::WeakPtr NewWeakPtr() { return weak_factory_.GetWeakPtr(); } void AddAddress(const rtc::SocketAddress& address, @@ -481,7 +480,7 @@ class RTC_EXPORT Port : public PortInterface, public sigslot::has_slots<> { webrtc::TaskQueueBase* const thread_; rtc::PacketSocketFactory* const factory_; - std::string type_; + const absl::string_view type_; bool send_retransmit_count_attribute_; const rtc::Network* network_; uint16_t min_port_; diff --git a/p2p/base/port_allocator.cc b/p2p/base/port_allocator.cc index 1603ce54dd..b6332d39c4 100644 --- a/p2p/base/port_allocator.cc +++ b/p2p/base/port_allocator.cc @@ -142,6 +142,8 @@ bool PortAllocator::SetConfiguration( webrtc::PortPrunePolicy turn_port_prune_policy, webrtc::TurnCustomizer* turn_customizer, const absl::optional& stun_candidate_keepalive_interval) { + RTC_DCHECK_GE(candidate_pool_size, 0); + RTC_DCHECK_LE(candidate_pool_size, static_cast(UINT16_MAX)); CheckRunOnValidThreadIfInitialized(); // A positive candidate pool size would lead to the creation of a pooled // allocator session and starting getting ports, which we should only do on @@ -153,20 +155,6 @@ bool PortAllocator::SetConfiguration( turn_servers_ = turn_servers; turn_port_prune_policy_ = turn_port_prune_policy; - if (candidate_pool_frozen_) { - if (candidate_pool_size != candidate_pool_size_) { - RTC_LOG(LS_ERROR) - << "Trying to change candidate pool size after pool was frozen."; - return false; - } - return true; - } - - if (candidate_pool_size < 0) { - RTC_LOG(LS_ERROR) << "Can't set negative pool size."; - return false; - } - candidate_pool_size_ = candidate_pool_size; // If ICE servers changed, throw away any existing pooled sessions and create @@ -287,11 +275,6 @@ PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const { return pooled_sessions_.end(); } -void PortAllocator::FreezeCandidatePool() { - CheckRunOnValidThreadAndInitialized(); - candidate_pool_frozen_ = true; -} - void PortAllocator::DiscardCandidatePool() { CheckRunOnValidThreadIfInitialized(); pooled_sessions_.clear(); diff --git a/p2p/base/port_allocator.h b/p2p/base/port_allocator.h index 4f8fecd7e7..e42fbe4a33 100644 --- a/p2p/base/port_allocator.h +++ b/p2p/base/port_allocator.h @@ -458,15 +458,6 @@ class RTC_EXPORT PortAllocator : public sigslot::has_slots<> { const PortAllocatorSession* GetPooledSession( const IceParameters* ice_credentials = nullptr) const; - // After FreezeCandidatePool is called, changing the candidate pool size will - // no longer be allowed, and changing ICE servers will not cause pooled - // sessions to be recreated. - // - // Expected to be called when SetLocalDescription is called on a - // PeerConnection. Can be called safely on any thread as long as not - // simultaneously with SetConfiguration. - void FreezeCandidatePool(); - // Discard any remaining pooled sessions. void DiscardCandidatePool(); @@ -670,7 +661,6 @@ class RTC_EXPORT PortAllocator : public sigslot::has_slots<> { std::vector turn_servers_; int candidate_pool_size_ = 0; // Last value passed into SetConfiguration. std::vector> pooled_sessions_; - bool candidate_pool_frozen_ = false; webrtc::PortPrunePolicy turn_port_prune_policy_ = webrtc::NO_PRUNE; // Customizer for TURN messages. diff --git a/p2p/base/port_allocator_unittest.cc b/p2p/base/port_allocator_unittest.cc index 48d0bc8a6e..836a2fa494 100644 --- a/p2p/base/port_allocator_unittest.cc +++ b/p2p/base/port_allocator_unittest.cc @@ -150,11 +150,6 @@ TEST_F(PortAllocatorTest, SetConfigurationUpdatesCandidatePoolSize) { EXPECT_EQ(4, allocator_->candidate_pool_size()); } -// A negative pool size should just be treated as zero. -TEST_F(PortAllocatorTest, SetConfigurationWithNegativePoolSizeFails) { - SetConfigurationWithPoolSizeExpectFailure(-1); -} - // Test that if the candidate pool size is nonzero, pooled sessions are // created, and StartGettingPorts is called on them. TEST_F(PortAllocatorTest, SetConfigurationCreatesPooledSessions) { @@ -213,33 +208,6 @@ TEST_F(PortAllocatorTest, EXPECT_EQ(0, GetAllPooledSessionsReturnCount()); } -// According to JSEP, after SetLocalDescription, setting different ICE servers -// will not cause the pool to be refilled. This is implemented by the -// PeerConnection calling FreezeCandidatePool when a local description is set. -TEST_F(PortAllocatorTest, - SetConfigurationDoesNotRecreatePooledSessionsAfterFreezeCandidatePool) { - cricket::ServerAddresses stun_servers_1 = {stun_server_1}; - std::vector turn_servers_1 = {turn_server_1}; - allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 1, - webrtc::NO_PRUNE); - EXPECT_EQ(stun_servers_1, allocator_->stun_servers()); - EXPECT_EQ(turn_servers_1, allocator_->turn_servers()); - - // Update with a different set of servers, but first freeze the pool. - allocator_->FreezeCandidatePool(); - cricket::ServerAddresses stun_servers_2 = {stun_server_2}; - std::vector turn_servers_2 = {turn_server_2}; - allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 2, - webrtc::NO_PRUNE); - EXPECT_EQ(stun_servers_2, allocator_->stun_servers()); - EXPECT_EQ(turn_servers_2, allocator_->turn_servers()); - auto session = TakePooledSession(); - ASSERT_NE(nullptr, session.get()); - EXPECT_EQ(stun_servers_1, session->stun_servers()); - EXPECT_EQ(turn_servers_1, session->turn_servers()); - EXPECT_EQ(0, GetAllPooledSessionsReturnCount()); -} - TEST_F(PortAllocatorTest, GetPooledSessionReturnsNextSession) { SetConfigurationWithPoolSize(2); auto peeked_session_1 = GetPooledSession(); diff --git a/p2p/base/port_interface.h b/p2p/base/port_interface.h index 259435aee6..a02d98b3c0 100644 --- a/p2p/base/port_interface.h +++ b/p2p/base/port_interface.h @@ -49,7 +49,7 @@ class PortInterface { public: virtual ~PortInterface(); - virtual const std::string& Type() const = 0; + virtual const absl::string_view Type() const = 0; virtual const rtc::Network* Network() const = 0; // Methods to set/get ICE role and tiebreaker values. diff --git a/p2p/base/stun_port.cc b/p2p/base/stun_port.cc index 232afc1601..489627df48 100644 --- a/p2p/base/stun_port.cc +++ b/p2p/base/stun_port.cc @@ -158,6 +158,7 @@ bool UDPPort::AddressResolver::GetResolvedAddress( } UDPPort::UDPPort(rtc::Thread* thread, + absl::string_view type, rtc::PacketSocketFactory* factory, const rtc::Network* network, rtc::AsyncPacketSocket* socket, @@ -165,13 +166,7 @@ UDPPort::UDPPort(rtc::Thread* thread, absl::string_view password, bool emit_local_for_anyaddress, const webrtc::FieldTrialsView* field_trials) - : Port(thread, - LOCAL_PORT_TYPE, - factory, - network, - username, - password, - field_trials), + : Port(thread, type, factory, network, username, password, field_trials), request_manager_( thread, [this](const void* data, size_t size, StunRequest* request) { @@ -185,6 +180,7 @@ UDPPort::UDPPort(rtc::Thread* thread, emit_local_for_anyaddress_(emit_local_for_anyaddress) {} UDPPort::UDPPort(rtc::Thread* thread, + absl::string_view type, rtc::PacketSocketFactory* factory, const rtc::Network* network, uint16_t min_port, @@ -194,7 +190,7 @@ UDPPort::UDPPort(rtc::Thread* thread, bool emit_local_for_anyaddress, const webrtc::FieldTrialsView* field_trials) : Port(thread, - LOCAL_PORT_TYPE, + type, factory, network, min_port, @@ -656,6 +652,7 @@ StunPort::StunPort(rtc::Thread* thread, const ServerAddresses& servers, const webrtc::FieldTrialsView* field_trials) : UDPPort(thread, + STUN_PORT_TYPE, factory, network, min_port, @@ -664,8 +661,6 @@ StunPort::StunPort(rtc::Thread* thread, password, false, field_trials) { - // UDPPort will set these to local udp, updating these to STUN. - set_type(STUN_PORT_TYPE); set_server_addresses(servers); } diff --git a/p2p/base/stun_port.h b/p2p/base/stun_port.h index 380dbecd2d..3df725eaf9 100644 --- a/p2p/base/stun_port.h +++ b/p2p/base/stun_port.h @@ -46,8 +46,8 @@ class RTC_EXPORT UDPPort : public Port { const webrtc::FieldTrialsView* field_trials = nullptr) { // Using `new` to access a non-public constructor. auto port = absl::WrapUnique( - new UDPPort(thread, factory, network, socket, username, password, - emit_local_for_anyaddress, field_trials)); + new UDPPort(thread, LOCAL_PORT_TYPE, factory, network, socket, username, + password, emit_local_for_anyaddress, field_trials)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -67,9 +67,9 @@ class RTC_EXPORT UDPPort : public Port { absl::optional stun_keepalive_interval, const webrtc::FieldTrialsView* field_trials = nullptr) { // Using `new` to access a non-public constructor. - auto port = absl::WrapUnique( - new UDPPort(thread, factory, network, min_port, max_port, username, - password, emit_local_for_anyaddress, field_trials)); + auto port = absl::WrapUnique(new UDPPort( + thread, LOCAL_PORT_TYPE, factory, network, min_port, max_port, username, + password, emit_local_for_anyaddress, field_trials)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -120,6 +120,7 @@ class RTC_EXPORT UDPPort : public Port { protected: UDPPort(rtc::Thread* thread, + absl::string_view type, rtc::PacketSocketFactory* factory, const rtc::Network* network, uint16_t min_port, @@ -130,6 +131,7 @@ class RTC_EXPORT UDPPort : public Port { const webrtc::FieldTrialsView* field_trials); UDPPort(rtc::Thread* thread, + absl::string_view type, rtc::PacketSocketFactory* factory, const rtc::Network* network, rtc::AsyncPacketSocket* socket, diff --git a/p2p/base/stun_request.cc b/p2p/base/stun_request.cc index 25d387cc3a..15c1e6a269 100644 --- a/p2p/base/stun_request.cc +++ b/p2p/base/stun_request.cc @@ -133,31 +133,39 @@ bool StunRequestManager::CheckResponse(StunMessage* msg) { } } - bool success = true; - if (!msg->GetNonComprehendedAttributes().empty()) { // If a response contains unknown comprehension-required attributes, it's // simply discarded and the transaction is considered failed. See RFC5389 // sections 7.3.3 and 7.3.4. RTC_LOG(LS_ERROR) << ": Discarding response due to unknown " "comprehension-required attribute."; - success = false; + requests_.erase(iter); + return false; } else if (msg->type() == GetStunSuccessResponseType(request->type())) { if (!msg->IntegrityOk() && !skip_integrity_checking) { return false; } - request->OnResponse(msg); + // Erase element from hash before calling callback. This ensures + // that the callback can modify the StunRequestManager any way it + // sees fit. + std::unique_ptr owned_request = std::move(iter->second); + requests_.erase(iter); + owned_request->OnResponse(msg); + return true; } else if (msg->type() == GetStunErrorResponseType(request->type())) { - request->OnErrorResponse(msg); + // Erase element from hash before calling callback. This ensures + // that the callback can modify the StunRequestManager any way it + // sees fit. + std::unique_ptr owned_request = std::move(iter->second); + requests_.erase(iter); + owned_request->OnErrorResponse(msg); + return true; } else { RTC_LOG(LS_ERROR) << "Received response with wrong type: " << msg->type() << " (expecting " << GetStunSuccessResponseType(request->type()) << ")"; return false; } - - requests_.erase(iter); - return success; } bool StunRequestManager::empty() const { diff --git a/p2p/base/stun_request_unittest.cc b/p2p/base/stun_request_unittest.cc index 6831d9ffa2..2f88ab1fd3 100644 --- a/p2p/base/stun_request_unittest.cc +++ b/p2p/base/stun_request_unittest.cc @@ -54,15 +54,15 @@ class StunRequestTest : public ::testing::Test { request_count_++; } - void OnResponse(StunMessage* res) { + virtual void OnResponse(StunMessage* res) { response_ = res; success_ = true; } - void OnErrorResponse(StunMessage* res) { + virtual void OnErrorResponse(StunMessage* res) { response_ = res; failure_ = true; } - void OnTimeout() { timeout_ = true; } + virtual void OnTimeout() { timeout_ = true; } protected: rtc::AutoThread main_thread_; @@ -216,4 +216,42 @@ TEST_F(StunRequestTest, TestUnrecognizedComprehensionRequiredAttribute) { EXPECT_FALSE(timeout_); } +class StunRequestReentranceTest : public StunRequestTest { + public: + void OnResponse(StunMessage* res) override { + manager_.Clear(); + StunRequestTest::OnResponse(res); + } + void OnErrorResponse(StunMessage* res) override { + manager_.Clear(); + StunRequestTest::OnErrorResponse(res); + } +}; + +TEST_F(StunRequestReentranceTest, TestSuccess) { + auto* request = new StunRequestThunker(manager_, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_RESPONSE); + manager_.Send(request); + EXPECT_TRUE(manager_.CheckResponse(res.get())); + + EXPECT_TRUE(response_ == res.get()); + EXPECT_TRUE(success_); + EXPECT_FALSE(failure_); + EXPECT_FALSE(timeout_); +} + +TEST_F(StunRequestReentranceTest, TestError) { + auto* request = new StunRequestThunker(manager_, this); + std::unique_ptr res = + request->CreateResponseMessage(STUN_BINDING_ERROR_RESPONSE); + manager_.Send(request); + EXPECT_TRUE(manager_.CheckResponse(res.get())); + + EXPECT_TRUE(response_ == res.get()); + EXPECT_FALSE(success_); + EXPECT_TRUE(failure_); + EXPECT_FALSE(timeout_); +} + } // namespace cricket diff --git a/p2p/base/turn_port.cc b/p2p/base/turn_port.cc index b9bb756e7b..bab9428686 100644 --- a/p2p/base/turn_port.cc +++ b/p2p/base/turn_port.cc @@ -956,11 +956,6 @@ bool TurnPort::AllowedTurnPort(int port, if (port == 53 || port == 80 || port == 443 || port >= 1024) { return true; } - // Allow any port if relevant field trial is set. This allows disabling the - // check. - if (field_trials && field_trials->IsEnabled("WebRTC-Turn-AllowSystemPorts")) { - return true; - } return false; } diff --git a/p2p/base/turn_port.h b/p2p/base/turn_port.h index ac660d6599..8fa4607e51 100644 --- a/p2p/base/turn_port.h +++ b/p2p/base/turn_port.h @@ -267,7 +267,7 @@ class TurnPort : public Port { void HandleRefreshError(); bool SetAlternateServer(const rtc::SocketAddress& address); void ResolveTurnAddress(const rtc::SocketAddress& address); - void OnResolveResult(rtc::AsyncResolverInterface* resolver); + void OnResolveResult(const webrtc::AsyncDnsResolverResult& result); void AddRequestAuthInfo(StunMessage* msg); void OnSendStunPacket(const void* data, size_t size, StunRequest* request); diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc index 3314302229..69cd69207c 100644 --- a/p2p/base/turn_port_unittest.cc +++ b/p2p/base/turn_port_unittest.cc @@ -216,19 +216,7 @@ class TurnPortTest : public ::testing::Test, bool /*port_muxed*/) { turn_unknown_address_ = true; } - void OnTurnReadPacket(Connection* conn, - const char* data, - size_t size, - int64_t packet_time_us) { - turn_packets_.push_back(rtc::Buffer(data, size)); - } void OnUdpPortComplete(Port* port) { udp_ready_ = true; } - void OnUdpReadPacket(Connection* conn, - const char* data, - size_t size, - int64_t packet_time_us) { - udp_packets_.push_back(rtc::Buffer(data, size)); - } void OnSocketReadPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, @@ -248,6 +236,10 @@ class TurnPortTest : public ::testing::Test, } void OnTurnPortClosed() override { turn_port_closed_ = true; } + void OnConnectionSignalDestroyed(Connection* connection) { + connection->DeregisterReceivedPacketCallback(); + } + rtc::Socket* CreateServerSocket(const SocketAddress addr) { rtc::Socket* socket = ss_->CreateSocket(AF_INET, SOCK_STREAM); EXPECT_GE(socket->Bind(addr), 0); @@ -727,10 +719,20 @@ class TurnPortTest : public ::testing::Test, Port::ORIGIN_MESSAGE); ASSERT_TRUE(conn1 != NULL); ASSERT_TRUE(conn2 != NULL); - conn1->SignalReadPacket.connect(static_cast(this), - &TurnPortTest::OnTurnReadPacket); - conn2->SignalReadPacket.connect(static_cast(this), - &TurnPortTest::OnUdpReadPacket); + conn1->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + turn_packets_.push_back( + rtc::Buffer(packet.payload().data(), packet.payload().size())); + }); + conn1->SignalDestroyed.connect(this, + &TurnPortTest::OnConnectionSignalDestroyed); + conn2->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + udp_packets_.push_back( + rtc::Buffer(packet.payload().data(), packet.payload().size())); + }); + conn2->SignalDestroyed.connect(this, + &TurnPortTest::OnConnectionSignalDestroyed); conn1->Ping(0); EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kSimulatedRtt * 2, fake_clock_); @@ -780,10 +782,21 @@ class TurnPortTest : public ::testing::Test, Port::ORIGIN_MESSAGE); ASSERT_TRUE(conn1 != NULL); ASSERT_TRUE(conn2 != NULL); - conn1->SignalReadPacket.connect(static_cast(this), - &TurnPortTest::OnTurnReadPacket); - conn2->SignalReadPacket.connect(static_cast(this), - &TurnPortTest::OnUdpReadPacket); + conn1->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + turn_packets_.push_back( + rtc::Buffer(packet.payload().data(), packet.payload().size())); + }); + conn1->SignalDestroyed.connect(this, + &TurnPortTest::OnConnectionSignalDestroyed); + conn2->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + udp_packets_.push_back( + rtc::Buffer(packet.payload().data(), packet.payload().size())); + }); + conn2->SignalDestroyed.connect(this, + &TurnPortTest::OnConnectionSignalDestroyed); + conn1->Ping(0); EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kSimulatedRtt * 2, fake_clock_); @@ -1507,10 +1520,15 @@ TEST_F(TurnPortTest, TestChannelBindGetErrorResponse) { kSimulatedRtt, fake_clock_); // Verify that packets are allowed to be sent after a bind request error. // They'll just use a send indication instead. - conn2->SignalReadPacket.connect(static_cast(this), - &TurnPortTest::OnUdpReadPacket); + + conn2->RegisterReceivedPacketCallback( + [&](Connection* connection, const rtc::ReceivedPacket& packet) { + udp_packets_.push_back( + rtc::Buffer(packet.payload().data(), packet.payload().size())); + }); conn1->Send(data.data(), data.length(), options); EXPECT_TRUE_SIMULATED_WAIT(!udp_packets_.empty(), kSimulatedRtt, fake_clock_); + conn2->DeregisterReceivedPacketCallback(); } // Do a TURN allocation, establish a UDP connection, and send some data. @@ -1880,13 +1898,6 @@ TEST_F(TurnPortTest, TestTurnDangerousAlternateServer) { ASSERT_EQ(0U, turn_port_->Candidates().size()); } -TEST_F(TurnPortTest, TestTurnDangerousServerAllowedWithFieldTrial) { - webrtc::test::ScopedKeyValueConfig override_field_trials( - field_trials_, "WebRTC-Turn-AllowSystemPorts/Enabled/"); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnDangerousProtoAddr); - ASSERT_TRUE(turn_port_); -} - class TurnPortWithMockDnsResolverTest : public TurnPortTest { public: TurnPortWithMockDnsResolverTest() diff --git a/p2p/stunprober/stun_prober.cc b/p2p/stunprober/stun_prober.cc index 977ead4d72..f5abf43beb 100644 --- a/p2p/stunprober/stun_prober.cc +++ b/p2p/stunprober/stun_prober.cc @@ -329,13 +329,12 @@ bool StunProber::Start(StunProber::Observer* observer) { } bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) { - rtc::AsyncResolverInterface* resolver = - socket_factory_->CreateAsyncResolver(); - if (!resolver) { + RTC_DCHECK(!resolver_); + resolver_ = socket_factory_->CreateAsyncDnsResolver(); + if (!resolver_) { return false; } - resolver->SignalDone.connect(this, &StunProber::OnServerResolved); - resolver->Start(addr); + resolver_->Start(addr, [this] { OnServerResolved(resolver_->result()); }); return true; } @@ -347,20 +346,17 @@ void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket, } } -void StunProber::OnServerResolved(rtc::AsyncResolverInterface* resolver) { +void StunProber::OnServerResolved( + const webrtc::AsyncDnsResolverResult& result) { RTC_DCHECK(thread_checker_.IsCurrent()); - - if (resolver->GetError() == 0) { - rtc::SocketAddress addr(resolver->address().ipaddr(), - resolver->address().port()); + rtc::SocketAddress received_address; + if (result.GetResolvedAddress(AF_INET, &received_address)) { + // Construct an address without the name in it. + rtc::SocketAddress addr(received_address.ipaddr(), received_address.port()); all_servers_addrs_.push_back(addr); } - - // Deletion of AsyncResolverInterface can't be done in OnResolveResult which - // handles SignalDone. - thread_->PostTask([resolver] { resolver->Destroy(false); }); + resolver_.reset(); servers_.pop_back(); - if (servers_.size()) { if (!ResolveServerName(servers_.back())) { ReportOnPrepared(RESOLVE_FAILED); diff --git a/p2p/stunprober/stun_prober.h b/p2p/stunprober/stun_prober.h index 7d5094a3b9..3f0f4a2476 100644 --- a/p2p/stunprober/stun_prober.h +++ b/p2p/stunprober/stun_prober.h @@ -11,10 +11,12 @@ #ifndef P2P_STUNPROBER_STUN_PROBER_H_ #define P2P_STUNPROBER_STUN_PROBER_H_ +#include #include #include #include +#include "api/async_dns_resolver.h" #include "api/sequence_checker.h" #include "api/task_queue/pending_task_safety_flag.h" #include "rtc_base/byte_buffer.h" @@ -166,7 +168,7 @@ class RTC_EXPORT StunProber : public sigslot::has_slots<> { }; bool ResolveServerName(const rtc::SocketAddress& addr); - void OnServerResolved(rtc::AsyncResolverInterface* resolver); + void OnServerResolved(const webrtc::AsyncDnsResolverResult& resolver); void OnSocketReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& addr); @@ -241,6 +243,7 @@ class RTC_EXPORT StunProber : public sigslot::has_slots<> { ObserverAdapter observer_adapter_; const std::vector networks_; + std::unique_ptr resolver_; webrtc::ScopedTaskSafety task_safety_; }; diff --git a/p2p/stunprober/stun_prober_unittest.cc b/p2p/stunprober/stun_prober_unittest.cc index b57f93b634..ca20fccb6b 100644 --- a/p2p/stunprober/stun_prober_unittest.cc +++ b/p2p/stunprober/stun_prober_unittest.cc @@ -51,16 +51,23 @@ class StunProberTest : public ::testing::Test { rtc::InitializeSSL(); } + static constexpr int pings_per_ip = 3; + void set_expected_result(int result) { result_ = result; } + void CreateProber(rtc::PacketSocketFactory* socket_factory, + std::vector networks) { + prober_ = std::make_unique( + socket_factory, rtc::Thread::Current(), std::move(networks)); + } + void StartProbing(rtc::PacketSocketFactory* socket_factory, const std::vector& addrs, std::vector networks, bool shared_socket, uint16_t interval, uint16_t pings_per_ip) { - prober_ = std::make_unique( - socket_factory, rtc::Thread::Current(), std::move(networks)); + CreateProber(socket_factory, networks); prober_->Start(addrs, shared_socket, interval, pings_per_ip, 100 /* timeout_ms */, [this](StunProber* prober, int result) { @@ -69,13 +76,17 @@ class StunProberTest : public ::testing::Test { } void RunProber(bool shared_mode) { - const int pings_per_ip = 3; std::vector addrs; addrs.push_back(kStunAddr1); addrs.push_back(kStunAddr2); // Add a non-existing server. This shouldn't pollute the result. addrs.push_back(kFailedStunAddr); + RunProber(shared_mode, addrs, /* check_results= */ true); + } + void RunProber(bool shared_mode, + const std::vector& addrs, + bool check_results) { rtc::Network ipv4_network1("test_eth0", "Test Network Adapter 1", rtc::IPAddress(0x12345600U), 24); ipv4_network1.AddIP(rtc::IPAddress(0x12345678)); @@ -100,17 +111,21 @@ class StunProberTest : public ::testing::Test { WAIT(stopped_, 1000); - StunProber::Stats stats; - EXPECT_TRUE(prober_->GetStats(&stats)); - EXPECT_EQ(stats.success_percent, 100); - EXPECT_TRUE(stats.nat_type > stunprober::NATTYPE_NONE); - EXPECT_EQ(stats.srflx_addrs, srflx_addresses); - EXPECT_EQ(static_cast(stats.num_request_sent), - total_pings_reported); - EXPECT_EQ(static_cast(stats.num_response_received), - total_pings_reported); + EXPECT_TRUE(prober_->GetStats(&stats_)); + if (check_results) { + EXPECT_EQ(stats_.success_percent, 100); + EXPECT_TRUE(stats_.nat_type > stunprober::NATTYPE_NONE); + EXPECT_EQ(stats_.srflx_addrs, srflx_addresses); + EXPECT_EQ(static_cast(stats_.num_request_sent), + total_pings_reported); + EXPECT_EQ(static_cast(stats_.num_response_received), + total_pings_reported); + } } + StunProber* prober() { return prober_.get(); } + StunProber::Stats& stats() { return stats_; } + private: void StopCallback(StunProber* prober, int result) { EXPECT_EQ(result, result_); @@ -124,6 +139,7 @@ class StunProberTest : public ::testing::Test { bool stopped_ = false; std::unique_ptr stun_server_1_; std::unique_ptr stun_server_2_; + StunProber::Stats stats_; }; TEST_F(StunProberTest, NonSharedMode) { @@ -134,4 +150,26 @@ TEST_F(StunProberTest, SharedMode) { RunProber(true); } +TEST_F(StunProberTest, ResolveNonexistentHostname) { + std::vector addrs; + addrs.push_back(kStunAddr1); + // Add a non-existing server by name. This should cause a failed lookup. + addrs.push_back(rtc::SocketAddress("nonexistent.test", 3478)); + RunProber(false, addrs, false); + // One server is pinged + EXPECT_EQ(stats().raw_num_request_sent, pings_per_ip); +} + +TEST_F(StunProberTest, ResolveExistingHostname) { + std::vector addrs; + addrs.push_back(kStunAddr1); + // Add a non-existing server by name. This should cause a failed lookup. + addrs.push_back(rtc::SocketAddress("localhost", 3478)); + RunProber(false, addrs, false); + // Two servers are pinged, only one responds. + // TODO(bugs.webrtc.org/15559): Figure out why this doesn't always work + // EXPECT_EQ(stats().raw_num_request_sent, pings_per_ip * 2); + EXPECT_EQ(stats().num_request_sent, pings_per_ip); +} + } // namespace stunprober diff --git a/pc/BUILD.gn b/pc/BUILD.gn index b2e448e96a..7c22a26d12 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -105,6 +105,7 @@ rtc_source_set("channel") { "../rtc_base/third_party/sigslot", ] absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -764,11 +765,11 @@ rtc_source_set("peerconnection") { ":rtp_transmission_manager", ":sctp_data_channel", ":sdp_offer_answer", - ":sdp_serializer", ":sdp_state_provider", ":sdp_utils", ":session_description", ":simulcast_description", + ":simulcast_sdp_serializer", ":stream_collection", ":track_media_info_map", ":transceiver_list", @@ -1108,6 +1109,7 @@ rtc_source_set("sdp_offer_answer") { ":stream_collection", ":transceiver_list", ":usage_pattern", + ":used_ids", ":webrtc_session_description_factory", "../api:array_view", "../api:audio_options_api", @@ -1259,11 +1261,11 @@ rtc_source_set("peer_connection") { ] } -rtc_source_set("sdp_serializer") { +rtc_source_set("simulcast_sdp_serializer") { visibility = [ ":*" ] sources = [ - "sdp_serializer.cc", - "sdp_serializer.h", + "simulcast_sdp_serializer.cc", + "simulcast_sdp_serializer.h", ] deps = [ ":session_description", @@ -1383,9 +1385,9 @@ rtc_source_set("webrtc_sdp") { deps = [ ":media_protocol_names", ":media_session", - ":sdp_serializer", ":session_description", ":simulcast_description", + ":simulcast_sdp_serializer", "../api:candidate", "../api:libjingle_peerconnection_api", "../api:rtc_error", @@ -2104,6 +2106,7 @@ if (rtc_include_tests && !build_with_chromium) { ":rtc_pc", ":rtcp_mux_filter", ":rtp_media_utils", + ":rtp_parameters_conversion", ":rtp_transport", ":rtp_transport_internal", ":sctp_transport", @@ -2341,7 +2344,7 @@ if (rtc_include_tests && !build_with_chromium) { "rtp_transceiver_unittest.cc", "sctp_utils_unittest.cc", "sdp_offer_answer_unittest.cc", - "sdp_serializer_unittest.cc", + "simulcast_sdp_serializer_unittest.cc", "test/fake_audio_capture_module_unittest.cc", "test/test_sdp_strings.h", "track_media_info_map_unittest.cc", @@ -2383,10 +2386,10 @@ if (rtc_include_tests && !build_with_chromium) { ":sctp_data_channel", ":sctp_transport", ":sctp_utils", - ":sdp_serializer", ":sdp_utils", ":session_description", ":simulcast_description", + ":simulcast_sdp_serializer", ":stream_collection", ":track_media_info_map", ":transport_stats", diff --git a/pc/channel.cc b/pc/channel.cc index 035223680e..3f5678be9d 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -16,6 +16,7 @@ #include #include +#include "absl/algorithm/container.h" #include "absl/strings/string_view.h" #include "api/rtp_parameters.h" #include "api/sequence_checker.h" @@ -77,12 +78,13 @@ struct StreamFinder { } // namespace -template void MediaChannelParametersFromMediaDescription( - const MediaContentDescriptionImpl* desc, + const RtpMediaContentDescription* desc, const RtpHeaderExtensions& extensions, bool is_stream_active, MediaChannelParameters* params) { + RTC_DCHECK(desc->type() == MEDIA_TYPE_AUDIO || + desc->type() == MEDIA_TYPE_VIDEO); params->is_stream_active = is_stream_active; params->codecs = desc->codecs(); // TODO(bugs.webrtc.org/11513): See if we really need @@ -94,9 +96,8 @@ void MediaChannelParametersFromMediaDescription( params->rtcp.remote_estimate = desc->remote_estimate(); } -template void RtpSendParametersFromMediaDescription( - const MediaContentDescriptionImpl* desc, + const RtpMediaContentDescription* desc, webrtc::RtpExtension::Filter extensions_filter, SenderParameters* send_params) { RtpHeaderExtensions extensions = @@ -111,9 +112,9 @@ void RtpSendParametersFromMediaDescription( } BaseChannel::BaseChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr send_media_channel_impl, std::unique_ptr receive_media_channel_impl, absl::string_view mid, @@ -818,9 +819,9 @@ void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) { } VoiceChannel::VoiceChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr media_send_channel, std::unique_ptr media_receive_channel, absl::string_view mid, @@ -843,19 +844,6 @@ VoiceChannel::~VoiceChannel() { DisableMedia_w(); } -void VoiceChannel::InitCallback() { - RTC_DCHECK_RUN_ON(worker_thread()); - // TODO(bugs.webrtc.org/13931): Remove when values are set - // in a more sensible fashion - send_channel()->SetSendCodecChangedCallback([this]() { - RTC_DCHECK_RUN_ON(worker_thread()); - // Adjust receive streams based on send codec. - receive_channel()->SetReceiveNackEnabled( - send_channel()->SendCodecHasNack()); - receive_channel()->SetReceiveNonSenderRttEnabled( - send_channel()->SenderNonSenderRttEnabled()); - }); -} void VoiceChannel::UpdateMediaSendRecvState_w() { // Render incoming data if we're the active call, and we have the local // content. We receive data on the default channel and multiplexed streams. @@ -901,7 +889,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content, bool criteria_modified = false; if (webrtc::RtpTransceiverDirectionHasRecv(content->direction())) { - for (const AudioCodec& codec : content->as_audio()->codecs()) { + for (const Codec& codec : content->codecs()) { if (MaybeAddHandledPayloadType(codec.id)) { criteria_modified = true; } @@ -910,7 +898,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content, last_recv_params_ = recv_params; - if (!UpdateLocalStreams_w(content->as_audio()->streams(), type, error_desc)) { + if (!UpdateLocalStreams_w(content->streams(), type, error_desc)) { RTC_DCHECK(!error_desc.empty()); return false; } @@ -990,9 +978,9 @@ void VoiceChannel::SetIncomingAudioMuted(uint32_t ssrc, bool muted) { } VideoChannel::VideoChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr media_send_channel, std::unique_ptr media_receive_channel, absl::string_view mid, @@ -1060,22 +1048,53 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content, VideoSenderParameters send_params = last_send_params_; + // Ensure that there is a matching packetization for each send codec. If the + // other peer offered to exclusively send non-standard packetization but we + // only accept to receive standard packetization we effectively amend their + // offer by ignoring the packetiztion and fall back to standard packetization + // instead. bool needs_send_params_update = false; if (type == SdpType::kAnswer || type == SdpType::kPrAnswer) { - for (auto& send_codec : send_params.codecs) { - auto* recv_codec = FindMatchingCodec(recv_params.codecs, send_codec); - if (recv_codec) { - if (!recv_codec->packetization && send_codec.packetization) { - send_codec.packetization.reset(); - needs_send_params_update = true; - } else if (recv_codec->packetization != send_codec.packetization) { - error_desc = StringFormat( - "Failed to set local answer due to invalid codec packetization " - "specified in m-section with mid='%s'.", - mid().c_str()); - return false; + webrtc::flat_set matched_codecs; + for (VideoCodec& send_codec : send_params.codecs) { + if (absl::c_any_of(matched_codecs, [&](const VideoCodec* c) { + return send_codec.Matches(*c); + })) { + continue; + } + + std::vector recv_codecs = + FindAllMatchingCodecs(recv_params.codecs, send_codec); + if (recv_codecs.empty()) { + continue; + } + + bool may_ignore_packetization = false; + bool has_matching_packetization = false; + for (const VideoCodec* recv_codec : recv_codecs) { + if (!recv_codec->packetization.has_value() && + send_codec.packetization.has_value()) { + may_ignore_packetization = true; + } else if (recv_codec->packetization == send_codec.packetization) { + has_matching_packetization = true; + break; } } + + if (may_ignore_packetization) { + send_codec.packetization = absl::nullopt; + needs_send_params_update = true; + } else if (!has_matching_packetization) { + error_desc = StringFormat( + "Failed to set local answer due to incompatible codec " + "packetization for pt='%d' specified in m-section with mid='%s'.", + send_codec.id, mid().c_str()); + return false; + } + + if (has_matching_packetization) { + matched_codecs.insert(&send_codec); + } } } @@ -1089,7 +1108,7 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content, bool criteria_modified = false; if (webrtc::RtpTransceiverDirectionHasRecv(content->direction())) { - for (const VideoCodec& codec : content->as_video()->codecs()) { + for (const Codec& codec : content->codecs()) { if (MaybeAddHandledPayloadType(codec.id)) criteria_modified = true; } @@ -1145,22 +1164,53 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content, VideoReceiverParameters recv_params = last_recv_params_; + // Ensure that there is a matching packetization for each receive codec. If we + // offered to exclusively receive a non-standard packetization but the other + // peer only accepts to send standard packetization we effectively amend our + // offer by ignoring the packetiztion and fall back to standard packetization + // instead. bool needs_recv_params_update = false; if (type == SdpType::kAnswer || type == SdpType::kPrAnswer) { - for (auto& recv_codec : recv_params.codecs) { - auto* send_codec = FindMatchingCodec(send_params.codecs, recv_codec); - if (send_codec) { - if (!send_codec->packetization && recv_codec.packetization) { - recv_codec.packetization.reset(); - needs_recv_params_update = true; - } else if (send_codec->packetization != recv_codec.packetization) { - error_desc = StringFormat( - "Failed to set remote answer due to invalid codec packetization " - "specifid in m-section with mid='%s'.", - mid().c_str()); - return false; + webrtc::flat_set matched_codecs; + for (VideoCodec& recv_codec : recv_params.codecs) { + if (absl::c_any_of(matched_codecs, [&](const VideoCodec* c) { + return recv_codec.Matches(*c); + })) { + continue; + } + + std::vector send_codecs = + FindAllMatchingCodecs(send_params.codecs, recv_codec); + if (send_codecs.empty()) { + continue; + } + + bool may_ignore_packetization = false; + bool has_matching_packetization = false; + for (const VideoCodec* send_codec : send_codecs) { + if (!send_codec->packetization.has_value() && + recv_codec.packetization.has_value()) { + may_ignore_packetization = true; + } else if (send_codec->packetization == recv_codec.packetization) { + has_matching_packetization = true; + break; } } + + if (may_ignore_packetization) { + recv_codec.packetization = absl::nullopt; + needs_recv_params_update = true; + } else if (!has_matching_packetization) { + error_desc = StringFormat( + "Failed to set remote answer due to incompatible codec " + "packetization for pt='%d' specified in m-section with mid='%s'.", + recv_codec.id, mid().c_str()); + return false; + } + + if (has_matching_packetization) { + matched_codecs.insert(&recv_codec); + } } } diff --git a/pc/channel.h b/pc/channel.h index f5528c3326..7423106fe9 100644 --- a/pc/channel.h +++ b/pc/channel.h @@ -82,9 +82,9 @@ class BaseChannel : public ChannelInterface, // Constructor for use when the MediaChannels are split BaseChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr media_send_channel, std::unique_ptr media_receive_channel, absl::string_view mid, @@ -93,7 +93,7 @@ class BaseChannel : public ChannelInterface, rtc::UniqueRandomIdGenerator* ssrc_generator); virtual ~BaseChannel(); - rtc::Thread* worker_thread() const { return worker_thread_; } + webrtc::TaskQueueBase* worker_thread() const { return worker_thread_; } rtc::Thread* network_thread() const { return network_thread_; } const std::string& mid() const override { return demuxer_criteria_.mid(); } // TODO(deadbeef): This is redundant; remove this. @@ -206,7 +206,7 @@ class BaseChannel : public ChannelInterface, } bool enabled() const RTC_RUN_ON(worker_thread()) { return enabled_; } - rtc::Thread* signaling_thread() const { return signaling_thread_; } + webrtc::TaskQueueBase* signaling_thread() const { return signaling_thread_; } // Call to verify that: // * The required content description directions have been set. @@ -311,9 +311,9 @@ class BaseChannel : public ChannelInterface, void DisconnectFromRtpTransport_n() RTC_RUN_ON(network_thread()); void SignalSentPacket_n(const rtc::SentPacket& sent_packet); - rtc::Thread* const worker_thread_; + webrtc::TaskQueueBase* const worker_thread_; rtc::Thread* const network_thread_; - rtc::Thread* const signaling_thread_; + webrtc::TaskQueueBase* const signaling_thread_; rtc::scoped_refptr alive_; std::function on_first_packet_received_ @@ -367,9 +367,9 @@ class BaseChannel : public ChannelInterface, class VoiceChannel : public BaseChannel { public: VoiceChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr send_channel_impl, std::unique_ptr receive_channel_impl, absl::string_view mid, @@ -424,7 +424,6 @@ class VoiceChannel : public BaseChannel { absl::optional GetReceivedAudioLevel(); private: - void InitCallback(); // overrides from BaseChannel void UpdateMediaSendRecvState_w() RTC_RUN_ON(worker_thread()) override; bool SetLocalContent_w(const MediaContentDescription* content, @@ -448,9 +447,9 @@ class VoiceChannel : public BaseChannel { class VideoChannel : public BaseChannel { public: VideoChannel( - rtc::Thread* worker_thread, + webrtc::TaskQueueBase* worker_thread, rtc::Thread* network_thread, - rtc::Thread* signaling_thread, + webrtc::TaskQueueBase* signaling_thread, std::unique_ptr media_send_channel, std::unique_ptr media_receive_channel, absl::string_view mid, diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc index 0d7f0b0cd0..c675cd0446 100644 --- a/pc/channel_unittest.cc +++ b/pc/channel_unittest.cc @@ -48,25 +48,28 @@ #include "test/gtest.h" #include "test/scoped_key_value_config.h" -using cricket::DtlsTransportInternal; -using cricket::FakeVoiceMediaReceiveChannel; -using cricket::FakeVoiceMediaSendChannel; -using cricket::RidDescription; -using cricket::RidDirection; -using cricket::StreamParams; -using webrtc::RtpTransceiverDirection; -using webrtc::SdpType; - namespace { -const cricket::AudioCodec kPcmuCodec = + +using ::cricket::DtlsTransportInternal; +using ::cricket::FakeVoiceMediaReceiveChannel; +using ::cricket::FakeVoiceMediaSendChannel; +using ::cricket::RidDescription; +using ::cricket::RidDirection; +using ::cricket::StreamParams; +using ::testing::AllOf; +using ::testing::ElementsAre; +using ::testing::Field; +using ::webrtc::RtpTransceiverDirection; +using ::webrtc::SdpType; + +const cricket::Codec kPcmuCodec = cricket::CreateAudioCodec(0, "PCMU", 64000, 1); -const cricket::AudioCodec kPcmaCodec = +const cricket::Codec kPcmaCodec = cricket::CreateAudioCodec(8, "PCMA", 64000, 1); -const cricket::AudioCodec kIsacCodec = +const cricket::Codec kIsacCodec = cricket::CreateAudioCodec(103, "ISAC", 40000, 1); -const cricket::VideoCodec kH264Codec = cricket::CreateVideoCodec(97, "H264"); -const cricket::VideoCodec kH264SvcCodec = - cricket::CreateVideoCodec(99, "H264-SVC"); +const cricket::Codec kH264Codec = cricket::CreateVideoCodec(97, "H264"); +const cricket::Codec kH264SvcCodec = cricket::CreateVideoCodec(99, "H264-SVC"); const uint32_t kSsrc1 = 0x1111; const uint32_t kSsrc2 = 0x2222; const uint32_t kSsrc3 = 0x3333; @@ -75,7 +78,6 @@ const int kAudioPts[] = {0, 8}; const int kVideoPts[] = {97, 99}; enum class NetworkIsWorker { Yes, No }; -} // namespace template class Traits { @@ -94,7 +95,6 @@ class Traits { typedef MediaSendChannelInterfaceT MediaSendChannelInterface; typedef MediaReceiveChannelInterfaceT MediaReceiveChannelInterface; typedef ContentT Content; - typedef CodecT Codec; typedef MediaInfoT MediaInfo; typedef OptionsT Options; }; @@ -105,7 +105,6 @@ class VoiceTraits : public Traits {}; @@ -115,7 +114,6 @@ class VideoTraits : public Traits {}; @@ -504,8 +502,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> { bool CheckNoRtp2() { return media_send_channel2_impl()->CheckNoRtp(); } void CreateContent(int flags, - const cricket::AudioCodec& audio_codec, - const cricket::VideoCodec& video_codec, + const cricket::Codec& audio_codec, + const cricket::Codec& video_codec, typename T::Content* content) { // overridden in specialized classes } @@ -541,10 +539,6 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> { std::unique_ptr thread_; }; - bool CodecMatches(const typename T::Codec& c1, const typename T::Codec& c2) { - return false; // overridden in specialized classes - } - cricket::CandidatePairInterface* last_selected_candidate_pair() { return last_selected_candidate_pair_; } @@ -610,8 +604,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> { EXPECT_EQ(0U, media_send_channel1_impl()->send_codecs().size()); EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, err)); ASSERT_EQ(1U, media_send_channel1_impl()->send_codecs().size()); - EXPECT_TRUE(CodecMatches(content.codecs()[0], - media_send_channel1_impl()->send_codecs()[0])); + EXPECT_EQ(content.codecs()[0], + media_send_channel1_impl()->send_codecs()[0]); } // Test that SetLocalContent and SetRemoteContent properly configure @@ -658,8 +652,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> { EXPECT_EQ(0U, media_send_channel1_impl()->send_codecs().size()); EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, err)); ASSERT_EQ(1U, media_send_channel1_impl()->send_codecs().size()); - EXPECT_TRUE(CodecMatches(content.codecs()[0], - media_send_channel1_impl()->send_codecs()[0])); + EXPECT_EQ(content.codecs()[0], + media_send_channel1_impl()->send_codecs()[0]); } // Test that SetLocalContent and SetRemoteContent properly set RTCP @@ -1559,8 +1553,8 @@ std::unique_ptr ChannelTest::CreateChannel( template <> void ChannelTest::CreateContent( int flags, - const cricket::AudioCodec& audio_codec, - const cricket::VideoCodec& video_codec, + const cricket::Codec& audio_codec, + const cricket::Codec& video_codec, cricket::AudioContentDescription* audio) { audio->AddCodec(audio_codec); audio->set_rtcp_mux((flags & RTCP_MUX) != 0); @@ -1573,13 +1567,6 @@ void ChannelTest::CopyContent( *audio = source; } -template <> -bool ChannelTest::CodecMatches(const cricket::AudioCodec& c1, - const cricket::AudioCodec& c2) { - return c1.name == c2.name && c1.clockrate == c2.clockrate && - c1.bitrate == c2.bitrate && c1.channels == c2.channels; -} - template <> void ChannelTest::AddLegacyStreamInContent( uint32_t ssrc, @@ -1646,8 +1633,8 @@ std::unique_ptr ChannelTest::CreateChannel( template <> void ChannelTest::CreateContent( int flags, - const cricket::AudioCodec& audio_codec, - const cricket::VideoCodec& video_codec, + const cricket::Codec& audio_codec, + const cricket::Codec& video_codec, cricket::VideoContentDescription* video) { video->AddCodec(video_codec); video->set_rtcp_mux((flags & RTCP_MUX) != 0); @@ -1660,12 +1647,6 @@ void ChannelTest::CopyContent( *video = source; } -template <> -bool ChannelTest::CodecMatches(const cricket::VideoCodec& c1, - const cricket::VideoCodec& c2) { - return c1.name == c2.name; -} - template <> void ChannelTest::AddLegacyStreamInContent( uint32_t ssrc, @@ -2274,6 +2255,142 @@ TEST_F(VideoChannelSingleThreadTest, absl::nullopt); } +TEST_F(VideoChannelSingleThreadTest, + StopsPacketizationVerificationWhenMatchIsFoundInRemoteAnswer) { + cricket::VideoCodec vp8_foo = cricket::CreateVideoCodec(96, "VP8"); + vp8_foo.packetization = "foo"; + cricket::VideoCodec vp8_bar = cricket::CreateVideoCodec(97, "VP8"); + vp8_bar.packetization = "bar"; + cricket::VideoCodec vp9 = cricket::CreateVideoCodec(98, "VP9"); + cricket::VideoCodec vp9_foo = cricket::CreateVideoCodec(99, "VP9"); + vp9_foo.packetization = "bar"; + cricket::VideoContentDescription local; + local.set_codecs({vp8_foo, vp8_bar, vp9_foo}); + cricket::VideoContentDescription remote; + remote.set_codecs({vp8_foo, vp9}); + + CreateChannels(0, 0); + std::string err; + ASSERT_TRUE(channel1_->SetLocalContent(&local, SdpType::kOffer, err)) << err; + ASSERT_TRUE(channel1_->SetRemoteContent(&remote, SdpType::kAnswer, err)) + << err; + + EXPECT_THAT( + media_receive_channel1_impl()->recv_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, "foo")), + AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, "bar")), + AllOf(Field(&cricket::Codec::id, 99), + Field(&cricket::Codec::packetization, absl::nullopt)))); + EXPECT_THAT( + media_send_channel1_impl()->send_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, "foo")), + AllOf(Field(&cricket::Codec::id, 98), + Field(&cricket::Codec::packetization, absl::nullopt)))); +} + +TEST_F(VideoChannelSingleThreadTest, + StopsPacketizationVerificationWhenMatchIsFoundInLocalAnswer) { + cricket::VideoCodec vp8_foo = cricket::CreateVideoCodec(96, "VP8"); + vp8_foo.packetization = "foo"; + cricket::VideoCodec vp8_bar = cricket::CreateVideoCodec(97, "VP8"); + vp8_bar.packetization = "bar"; + cricket::VideoCodec vp9 = cricket::CreateVideoCodec(98, "VP9"); + cricket::VideoCodec vp9_foo = cricket::CreateVideoCodec(99, "VP9"); + vp9_foo.packetization = "bar"; + cricket::VideoContentDescription local; + local.set_codecs({vp8_foo, vp9}); + cricket::VideoContentDescription remote; + remote.set_codecs({vp8_foo, vp8_bar, vp9_foo}); + + CreateChannels(0, 0); + std::string err; + ASSERT_TRUE(channel1_->SetRemoteContent(&remote, SdpType::kOffer, err)) + << err; + ASSERT_TRUE(channel1_->SetLocalContent(&local, SdpType::kAnswer, err)) << err; + + EXPECT_THAT( + media_receive_channel1_impl()->recv_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, "foo")), + AllOf(Field(&cricket::Codec::id, 98), + Field(&cricket::Codec::packetization, absl::nullopt)))); + EXPECT_THAT( + media_send_channel1_impl()->send_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, "foo")), + AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, "bar")), + AllOf(Field(&cricket::Codec::id, 99), + Field(&cricket::Codec::packetization, absl::nullopt)))); +} + +TEST_F(VideoChannelSingleThreadTest, + ConsidersAllCodecsWithDiffrentPacketizationsInRemoteAnswer) { + cricket::VideoCodec vp8 = cricket::CreateVideoCodec(96, "VP8"); + cricket::VideoCodec vp8_raw = cricket::CreateVideoCodec(97, "VP8"); + vp8_raw.packetization = cricket::kPacketizationParamRaw; + cricket::VideoContentDescription local; + local.set_codecs({vp8, vp8_raw}); + cricket::VideoContentDescription remote; + remote.set_codecs({vp8_raw, vp8}); + + CreateChannels(0, 0); + std::string err; + ASSERT_TRUE(channel1_->SetLocalContent(&local, SdpType::kOffer, err)) << err; + ASSERT_TRUE(channel1_->SetRemoteContent(&remote, SdpType::kAnswer, err)) + << err; + + EXPECT_THAT( + media_receive_channel1_impl()->recv_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, absl::nullopt)), + AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, + cricket::kPacketizationParamRaw)))); + EXPECT_THAT( + media_send_channel1_impl()->send_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, + cricket::kPacketizationParamRaw)), + AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, absl::nullopt)))); +} + +TEST_F(VideoChannelSingleThreadTest, + ConsidersAllCodecsWithDiffrentPacketizationsInLocalAnswer) { + cricket::VideoCodec vp8 = cricket::CreateVideoCodec(96, "VP8"); + cricket::VideoCodec vp8_raw = cricket::CreateVideoCodec(97, "VP8"); + vp8_raw.packetization = cricket::kPacketizationParamRaw; + cricket::VideoContentDescription local; + local.set_codecs({vp8_raw, vp8}); + cricket::VideoContentDescription remote; + remote.set_codecs({vp8, vp8_raw}); + + CreateChannels(0, 0); + std::string err; + ASSERT_TRUE(channel1_->SetRemoteContent(&remote, SdpType::kOffer, err)) + << err; + ASSERT_TRUE(channel1_->SetLocalContent(&local, SdpType::kAnswer, err)) << err; + + EXPECT_THAT( + media_receive_channel1_impl()->recv_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, + cricket::kPacketizationParamRaw)), + AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, absl::nullopt)))); + EXPECT_THAT( + media_send_channel1_impl()->send_codecs(), + ElementsAre(AllOf(Field(&cricket::Codec::id, 96), + Field(&cricket::Codec::packetization, absl::nullopt)), + AllOf(Field(&cricket::Codec::id, 97), + Field(&cricket::Codec::packetization, + cricket::kPacketizationParamRaw)))); +} + // VideoChannelDoubleThreadTest TEST_F(VideoChannelDoubleThreadTest, TestInit) { Base::TestInit(); @@ -2409,4 +2526,4 @@ TEST_F(VideoChannelDoubleThreadTest, SocketOptionsMergedOnSetTransport) { Base::SocketOptionsMergedOnSetTransport(); } -// TODO(pthatcher): TestSetReceiver? +} // namespace diff --git a/pc/connection_context.cc b/pc/connection_context.cc index 661550e2d4..f436e27c0a 100644 --- a/pc/connection_context.cc +++ b/pc/connection_context.cc @@ -174,15 +174,8 @@ ConnectionContext::ConnectionContext( ConnectionContext::~ConnectionContext() { RTC_DCHECK_RUN_ON(signaling_thread_); - worker_thread_->BlockingCall([&] { - RTC_DCHECK_RUN_ON(worker_thread()); - // While `media_engine_` is const throughout the ConnectionContext's - // lifetime, it requires destruction to happen on the worker thread. Instead - // of marking the pointer as non-const, we live with this const_cast<> in - // the destructor. - const_cast&>(media_engine_) - .reset(); - }); + // `media_engine_` requires destruction to happen on the worker thread. + worker_thread_->PostTask([media_engine = std::move(media_engine_)] {}); // Make sure `worker_thread()` and `signaling_thread()` outlive // `default_socket_factory_` and `default_network_manager_`. diff --git a/pc/connection_context.h b/pc/connection_context.h index 38a6f8e514..399e7c2b45 100644 --- a/pc/connection_context.h +++ b/pc/connection_context.h @@ -125,7 +125,9 @@ class ConnectionContext final // Accessed both on signaling thread and worker thread. std::unique_ptr const trials_; - const std::unique_ptr media_engine_; + // This object is const over the lifetime of the ConnectionContext, and is + // only altered in the destructor. + std::unique_ptr media_engine_; // This object should be used to generate any SSRC that is not explicitly // specified by the user (or by the remote party). diff --git a/pc/jsep_transport.cc b/pc/jsep_transport.cc index c7d41c8a4c..2398a0ad2d 100644 --- a/pc/jsep_transport.cc +++ b/pc/jsep_transport.cc @@ -704,6 +704,8 @@ bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport, &substats.ice_transport_stats)) { return false; } + substats.ssl_peer_signature_algorithm = + dtls_transport->GetSslPeerSignatureAlgorithm(); stats->channel_stats.push_back(substats); return true; } diff --git a/pc/jsep_transport_controller.cc b/pc/jsep_transport_controller.cc index 1cac90ac1b..2401fddbf0 100644 --- a/pc/jsep_transport_controller.cc +++ b/pc/jsep_transport_controller.cc @@ -397,11 +397,6 @@ bool JsepTransportController::GetStats(const std::string& transport_name, void JsepTransportController::SetActiveResetSrtpParams( bool active_reset_srtp_params) { - if (!network_thread_->IsCurrent()) { - network_thread_->BlockingCall( - [=] { SetActiveResetSrtpParams(active_reset_srtp_params); }); - return; - } RTC_DCHECK_RUN_ON(network_thread_); RTC_LOG(LS_INFO) << "Updating the active_reset_srtp_params for JsepTransportController: " @@ -678,7 +673,12 @@ RTCError JsepTransportController::ApplyDescription_n( cricket::JsepTransport* transport = GetJsepTransportForMid(content_info.name); - RTC_DCHECK(transport); + if (!transport) { + LOG_AND_RETURN_ERROR( + RTCErrorType::INVALID_PARAMETER, + "Could not find transport for m= section with mid='" + + content_info.name + "'"); + } SetIceRole_n(DetermineIceRole(transport, transport_info, type, local)); diff --git a/pc/media_session.cc b/pc/media_session.cc index 6e6a27dcd4..1558c3dfc1 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -43,6 +43,8 @@ namespace { using rtc::UniqueRandomIdGenerator; +using webrtc::RTCError; +using webrtc::RTCErrorType; using webrtc::RtpTransceiverDirection; const char kInline[] = "inline:"; @@ -113,15 +115,17 @@ cricket::RtpHeaderExtensions UnstoppedOrPresentRtpHeaderExtensions( namespace cricket { -static bool IsRtxCodec(const Codec& codec) { +namespace { + +bool IsRtxCodec(const Codec& codec) { return absl::EqualsIgnoreCase(codec.name, kRtxCodecName); } -static bool IsRtxCodec(const webrtc::RtpCodecCapability& capability) { +bool IsRtxCodec(const webrtc::RtpCodecCapability& capability) { return absl::EqualsIgnoreCase(capability.name, kRtxCodecName); } -static bool ContainsRtxCodec(const std::vector& codecs) { +bool ContainsRtxCodec(const std::vector& codecs) { for (const auto& codec : codecs) { if (IsRtxCodec(codec)) { return true; @@ -130,19 +134,19 @@ static bool ContainsRtxCodec(const std::vector& codecs) { return false; } -static bool IsRedCodec(const Codec& codec) { +bool IsRedCodec(const Codec& codec) { return absl::EqualsIgnoreCase(codec.name, kRedCodecName); } -static bool IsRedCodec(const webrtc::RtpCodecCapability& capability) { +bool IsRedCodec(const webrtc::RtpCodecCapability& capability) { return absl::EqualsIgnoreCase(capability.name, kRedCodecName); } -static bool IsFlexfecCodec(const Codec& codec) { +bool IsFlexfecCodec(const Codec& codec) { return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName); } -static bool ContainsFlexfecCodec(const std::vector& codecs) { +bool ContainsFlexfecCodec(const std::vector& codecs) { for (const auto& codec : codecs) { if (IsFlexfecCodec(codec)) { return true; @@ -151,15 +155,15 @@ static bool ContainsFlexfecCodec(const std::vector& codecs) { return false; } -static bool IsUlpfecCodec(const Codec& codec) { +bool IsUlpfecCodec(const Codec& codec) { return absl::EqualsIgnoreCase(codec.name, kUlpfecCodecName); } -static bool IsComfortNoiseCodec(const Codec& codec) { +bool IsComfortNoiseCodec(const Codec& codec) { return absl::EqualsIgnoreCase(codec.name, kComfortNoiseCodecName); } -static RtpTransceiverDirection NegotiateRtpTransceiverDirection( +RtpTransceiverDirection NegotiateRtpTransceiverDirection( RtpTransceiverDirection offer, RtpTransceiverDirection wants) { bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer); @@ -170,17 +174,16 @@ static RtpTransceiverDirection NegotiateRtpTransceiverDirection( offer_send && wants_recv); } -static bool IsMediaContentOfType(const ContentInfo* content, - MediaType media_type) { +bool IsMediaContentOfType(const ContentInfo* content, MediaType media_type) { if (!content || !content->media_description()) { return false; } return content->media_description()->type() == media_type; } -static bool CreateCryptoParams(int tag, - const std::string& cipher, - CryptoParams* crypto_out) { +bool CreateCryptoParams(int tag, + const std::string& cipher, + CryptoParams* crypto_out) { int key_len; int salt_len; if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher), @@ -204,8 +207,8 @@ static bool CreateCryptoParams(int tag, return true; } -static bool AddCryptoParams(const std::string& crypto_suite, - CryptoParamsVec* cryptos_out) { +bool AddCryptoParams(const std::string& crypto_suite, + CryptoParamsVec* cryptos_out) { int size = static_cast(cryptos_out->size()); cryptos_out->resize(size + 1); @@ -289,31 +292,14 @@ void GetSupportedVideoSdesCryptoSuiteNames( crypto_options, crypto_suite_names); } -void GetSupportedDataSdesCryptoSuites( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suites) { - crypto_suites->push_back(rtc::kSrtpAes128CmSha1_80); - if (crypto_options.srtp.enable_gcm_crypto_suites) { - crypto_suites->push_back(rtc::kSrtpAeadAes256Gcm); - crypto_suites->push_back(rtc::kSrtpAeadAes128Gcm); - } -} - -void GetSupportedDataSdesCryptoSuiteNames( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suite_names) { - GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites, - crypto_options, crypto_suite_names); -} - // Support any GCM cipher (if enabled through options). For video support only // 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless // bundle is enabled because it is low overhead. // Pick the crypto in the list that is supported. -static bool SelectCrypto(const MediaContentDescription* offer, - bool bundle, - const webrtc::CryptoOptions& crypto_options, - CryptoParams* crypto_out) { +bool SelectCrypto(const MediaContentDescription* offer, + bool bundle, + const webrtc::CryptoOptions& crypto_options, + CryptoParams* crypto_out) { bool audio = offer->type() == MEDIA_TYPE_AUDIO; const CryptoParamsVec& cryptos = offer->cryptos(); @@ -330,7 +316,7 @@ static bool SelectCrypto(const MediaContentDescription* offer, } // Finds all StreamParams of all media types and attach them to stream_params. -static StreamParamsVec GetCurrentStreamParams( +StreamParamsVec GetCurrentStreamParams( const std::vector& active_local_contents) { StreamParamsVec stream_params; for (const ContentInfo* content : active_local_contents) { @@ -341,7 +327,7 @@ static StreamParamsVec GetCurrentStreamParams( return stream_params; } -static StreamParams CreateStreamParamsForNewSenderWithSsrcs( +StreamParams CreateStreamParamsForNewSenderWithSsrcs( const SenderOptions& sender, const std::string& rtcp_cname, bool include_rtx_streams, @@ -374,9 +360,8 @@ static StreamParams CreateStreamParamsForNewSenderWithSsrcs( return result; } -static bool ValidateSimulcastLayers( - const std::vector& rids, - const SimulcastLayerList& simulcast_layers) { +bool ValidateSimulcastLayers(const std::vector& rids, + const SimulcastLayerList& simulcast_layers) { return absl::c_all_of( simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) { return absl::c_any_of(rids, [&layer](const RidDescription& rid) { @@ -385,7 +370,7 @@ static bool ValidateSimulcastLayers( }); } -static StreamParams CreateStreamParamsForNewSenderWithRids( +StreamParams CreateStreamParamsForNewSenderWithRids( const SenderOptions& sender, const std::string& rtcp_cname) { RTC_DCHECK(!sender.rids.empty()); @@ -407,7 +392,7 @@ static StreamParams CreateStreamParamsForNewSenderWithRids( // Adds SimulcastDescription if indicated by the media description options. // MediaContentDescription should already be set up with the send rids. -static void AddSimulcastToMediaDescription( +void AddSimulcastToMediaDescription( const MediaDescriptionOptions& media_description_options, MediaContentDescription* description) { RTC_DCHECK(description); @@ -440,13 +425,12 @@ static void AddSimulcastToMediaDescription( // Adds a StreamParams for each SenderOptions in `sender_options` to // content_description. // `current_params` - All currently known StreamParams of any media type. -template -static bool AddStreamParams(const std::vector& sender_options, - const std::string& rtcp_cname, - UniqueRandomIdGenerator* ssrc_generator, - StreamParamsVec* current_streams, - MediaContentDescriptionImpl* content_description, - const webrtc::FieldTrialsView& field_trials) { +bool AddStreamParams(const std::vector& sender_options, + const std::string& rtcp_cname, + UniqueRandomIdGenerator* ssrc_generator, + StreamParamsVec* current_streams, + MediaContentDescription* content_description, + const webrtc::FieldTrialsView& field_trials) { // SCTP streams are not negotiated using SDP/ContentDescriptions. if (IsSctpProtocol(content_description->protocol())) { return true; @@ -493,8 +477,8 @@ static bool AddStreamParams(const std::vector& sender_options, // `bundle_group`. The transport infos of the content names within the // `bundle_group` should be updated to use the ufrag, pwd and DTLS role of the // first content within the `bundle_group`. -static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group, - SessionDescription* sdesc) { +bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group, + SessionDescription* sdesc) { // The bundle should not be empty. if (!sdesc || !bundle_group.FirstContentName()) { return false; @@ -528,9 +512,9 @@ static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group, // Gets the CryptoParamsVec of the given `content_name` from `sdesc`, and // sets it to `cryptos`. -static bool GetCryptosByName(const SessionDescription* sdesc, - const std::string& content_name, - CryptoParamsVec* cryptos) { +bool GetCryptosByName(const SessionDescription* sdesc, + const std::string& content_name, + CryptoParamsVec* cryptos) { if (!sdesc || !cryptos) { return false; } @@ -544,8 +528,8 @@ static bool GetCryptosByName(const SessionDescription* sdesc, // Prunes the `target_cryptos` by removing the crypto params (crypto_suite) // which are not available in `filter`. -static void PruneCryptos(const CryptoParamsVec& filter, - CryptoParamsVec* target_cryptos) { +void PruneCryptos(const CryptoParamsVec& filter, + CryptoParamsVec* target_cryptos) { if (!target_cryptos) { return; } @@ -564,8 +548,7 @@ static void PruneCryptos(const CryptoParamsVec& filter, target_cryptos->end()); } -static bool IsRtpContent(SessionDescription* sdesc, - const std::string& content_name) { +bool IsRtpContent(SessionDescription* sdesc, const std::string& content_name) { bool is_rtp = false; ContentInfo* content = sdesc->GetContentByName(content_name); if (content && content->media_description()) { @@ -578,8 +561,8 @@ static bool IsRtpContent(SessionDescription* sdesc, // `bundle_group`. The crypto parameters of all the contents within the // `bundle_group` should be updated to use the common subset of the // available cryptos. -static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group, - SessionDescription* sdesc) { +bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group, + SessionDescription* sdesc) { // The bundle should not be empty. if (!sdesc || !bundle_group.FirstContentName()) { return false; @@ -639,7 +622,7 @@ static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group, return true; } -static std::vector GetActiveContents( +std::vector GetActiveContents( const SessionDescription& description, const MediaSessionOptions& session_options) { std::vector active_contents; @@ -662,7 +645,7 @@ static std::vector GetActiveContents( // crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is // created (according to crypto_suites). The created content is added to the // offer. -static bool CreateContentOffer( +RTCError CreateContentOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const SecurePolicy& secure_policy, @@ -702,34 +685,37 @@ static bool CreateContentOffer( } if (offer->cryptos().empty()) { if (!CreateMediaCryptos(crypto_suites, offer)) { - return false; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to create crypto parameters"); } } } if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) { - return false; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to create crypto parameters"); } - return true; + return RTCError::OK(); } -template -static bool CreateMediaContentOffer( + +RTCError CreateMediaContentOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, - const std::vector& codecs, + const std::vector& codecs, const SecurePolicy& secure_policy, const CryptoParamsVec* current_cryptos, const std::vector& crypto_suites, const RtpHeaderExtensions& rtp_extensions, UniqueRandomIdGenerator* ssrc_generator, StreamParamsVec* current_streams, - MediaContentDescriptionImpl* offer, + MediaContentDescription* offer, const webrtc::FieldTrialsView& field_trials) { offer->AddCodecs(codecs); if (!AddStreamParams(media_description_options.sender_options, session_options.rtcp_cname, ssrc_generator, current_streams, offer, field_trials)) { - return false; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to add stream parameters"); } return CreateContentOffer(media_description_options, session_options, @@ -738,110 +724,41 @@ static bool CreateMediaContentOffer( offer); } -template -static bool ReferencedCodecsMatch(const std::vector& codecs1, - const int codec1_id, - const std::vector& codecs2, - const int codec2_id, - const webrtc::FieldTrialsView* field_trials) { - const C* codec1 = FindCodecById(codecs1, codec1_id); - const C* codec2 = FindCodecById(codecs2, codec2_id); +bool ReferencedCodecsMatch(const std::vector& codecs1, + const int codec1_id, + const std::vector& codecs2, + const int codec2_id, + const webrtc::FieldTrialsView* field_trials) { + const Codec* codec1 = FindCodecById(codecs1, codec1_id); + const Codec* codec2 = FindCodecById(codecs2, codec2_id); return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2, field_trials); } -template -static void NegotiatePacketization(const C& local_codec, - const C& remote_codec, - C* negotiated_codec) {} - -template <> -void NegotiatePacketization(const VideoCodec& local_codec, - const VideoCodec& remote_codec, - VideoCodec* negotiated_codec) { +void NegotiatePacketization(const Codec& local_codec, + const Codec& remote_codec, + Codec* negotiated_codec) { negotiated_codec->packetization = (local_codec.packetization == remote_codec.packetization) ? local_codec.packetization : absl::nullopt; } -template -static void NegotiateCodecs(const std::vector& local_codecs, - const std::vector& offered_codecs, - std::vector* negotiated_codecs, - bool keep_offer_order, - const webrtc::FieldTrialsView* field_trials) { - for (const C& ours : local_codecs) { - absl::optional theirs = - FindMatchingCodec(local_codecs, offered_codecs, ours, field_trials); - // Note that we intentionally only find one matching codec for each of our - // local codecs, in case the remote offer contains duplicate codecs. - if (theirs) { - C negotiated = ours; - NegotiatePacketization(ours, *theirs, &negotiated); - negotiated.IntersectFeedbackParams(*theirs); - if (IsRtxCodec(negotiated)) { - const auto apt_it = - theirs->params.find(kCodecParamAssociatedPayloadType); - // FindMatchingCodec shouldn't return something with no apt value. - RTC_DCHECK(apt_it != theirs->params.end()); - negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second); - - // We support parsing the declarative rtx-time parameter. - const auto rtx_time_it = theirs->params.find(kCodecParamRtxTime); - if (rtx_time_it != theirs->params.end()) { - negotiated.SetParam(kCodecParamRtxTime, rtx_time_it->second); - } - } else if (IsRedCodec(negotiated)) { - const auto red_it = - theirs->params.find(kCodecParamNotInNameValueFormat); - if (red_it != theirs->params.end()) { - negotiated.SetParam(kCodecParamNotInNameValueFormat, red_it->second); - } - } - if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) { - webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs->params, - &negotiated.params); - } - negotiated.id = theirs->id; - negotiated.name = theirs->name; - negotiated_codecs->push_back(std::move(negotiated)); - } - } - if (keep_offer_order) { - // RFC3264: Although the answerer MAY list the formats in their desired - // order of preference, it is RECOMMENDED that unless there is a - // specific reason, the answerer list formats in the same relative order - // they were present in the offer. - // This can be skipped when the transceiver has any codec preferences. - std::unordered_map payload_type_preferences; - int preference = static_cast(offered_codecs.size() + 1); - for (const C& codec : offered_codecs) { - payload_type_preferences[codec.id] = preference--; - } - absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a, - const C& b) { - return payload_type_preferences[a.id] > payload_type_preferences[b.id]; - }); - } -} - // Finds a codec in `codecs2` that matches `codec_to_match`, which is // a member of `codecs1`. If `codec_to_match` is an RED or RTX codec, both // the codecs themselves and their associated codecs must match. -template -static absl::optional FindMatchingCodec( - const std::vector& codecs1, - const std::vector& codecs2, - const C& codec_to_match, +absl::optional FindMatchingCodec( + const std::vector& codecs1, + const std::vector& codecs2, + const Codec& codec_to_match, const webrtc::FieldTrialsView* field_trials) { // `codec_to_match` should be a member of `codecs1`, in order to look up // RED/RTX codecs' associated codecs correctly. If not, that's a programming // error. - RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) { + RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const Codec& codec) { return &codec == &codec_to_match; })); - for (const C& potential_match : codecs2) { + for (const Codec& potential_match : codecs2) { if (potential_match.Matches(codec_to_match, field_trials)) { if (IsRtxCodec(codec_to_match)) { int apt_value_1 = 0; @@ -912,14 +829,73 @@ static absl::optional FindMatchingCodec( return absl::nullopt; } +void NegotiateCodecs(const std::vector& local_codecs, + const std::vector& offered_codecs, + std::vector* negotiated_codecs, + bool keep_offer_order, + const webrtc::FieldTrialsView* field_trials) { + for (const Codec& ours : local_codecs) { + absl::optional theirs = + FindMatchingCodec(local_codecs, offered_codecs, ours, field_trials); + // Note that we intentionally only find one matching codec for each of our + // local codecs, in case the remote offer contains duplicate codecs. + if (theirs) { + Codec negotiated = ours; + NegotiatePacketization(ours, *theirs, &negotiated); + negotiated.IntersectFeedbackParams(*theirs); + if (IsRtxCodec(negotiated)) { + const auto apt_it = + theirs->params.find(kCodecParamAssociatedPayloadType); + // FindMatchingCodec shouldn't return something with no apt value. + RTC_DCHECK(apt_it != theirs->params.end()); + negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second); + + // We support parsing the declarative rtx-time parameter. + const auto rtx_time_it = theirs->params.find(kCodecParamRtxTime); + if (rtx_time_it != theirs->params.end()) { + negotiated.SetParam(kCodecParamRtxTime, rtx_time_it->second); + } + } else if (IsRedCodec(negotiated)) { + const auto red_it = + theirs->params.find(kCodecParamNotInNameValueFormat); + if (red_it != theirs->params.end()) { + negotiated.SetParam(kCodecParamNotInNameValueFormat, red_it->second); + } + } + if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) { + webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs->params, + &negotiated.params); + } + negotiated.id = theirs->id; + negotiated.name = theirs->name; + negotiated_codecs->push_back(std::move(negotiated)); + } + } + if (keep_offer_order) { + // RFC3264: Although the answerer MAY list the formats in their desired + // order of preference, it is RECOMMENDED that unless there is a + // specific reason, the answerer list formats in the same relative order + // they were present in the offer. + // This can be skipped when the transceiver has any codec preferences. + std::unordered_map payload_type_preferences; + int preference = static_cast(offered_codecs.size() + 1); + for (const Codec& codec : offered_codecs) { + payload_type_preferences[codec.id] = preference--; + } + absl::c_sort(*negotiated_codecs, [&payload_type_preferences]( + const Codec& a, const Codec& b) { + return payload_type_preferences[a.id] > payload_type_preferences[b.id]; + }); + } +} + // Find the codec in `codec_list` that `rtx_codec` is associated with. -template -static const C* GetAssociatedCodecForRtx(const std::vector& codec_list, - const C& rtx_codec) { +const Codec* GetAssociatedCodecForRtx(const std::vector& codec_list, + const Codec& rtx_codec) { std::string associated_pt_str; if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType, &associated_pt_str)) { - RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name + RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.id << " is missing an associated payload type."; return nullptr; } @@ -927,30 +903,29 @@ static const C* GetAssociatedCodecForRtx(const std::vector& codec_list, int associated_pt; if (!rtc::FromString(associated_pt_str, &associated_pt)) { RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str - << " of RTX codec " << rtx_codec.name + << " of RTX codec " << rtx_codec.id << " to an integer."; return nullptr; } // Find the associated codec for the RTX codec. - const C* associated_codec = FindCodecById(codec_list, associated_pt); + const Codec* associated_codec = FindCodecById(codec_list, associated_pt); if (!associated_codec) { RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " - << associated_pt << " for RTX codec " << rtx_codec.name + << associated_pt << " for RTX codec " << rtx_codec.id << "."; } return associated_codec; } // Find the codec in `codec_list` that `red_codec` is associated with. -template -static const C* GetAssociatedCodecForRed(const std::vector& codec_list, - const C& red_codec) { +const Codec* GetAssociatedCodecForRed(const std::vector& codec_list, + const Codec& red_codec) { std::string fmtp; if (!red_codec.GetParam(kCodecParamNotInNameValueFormat, &fmtp)) { - // Normal for video/RED. - if constexpr (std::is_same_v) { - RTC_LOG(LS_WARNING) << "RED codec " << red_codec.name + // Don't log for video/RED where this is normal. + if (red_codec.type == Codec::Type::kAudio) { + RTC_LOG(LS_WARNING) << "RED codec " << red_codec.id << " is missing an associated payload type."; } return nullptr; @@ -965,16 +940,16 @@ static const C* GetAssociatedCodecForRed(const std::vector& codec_list, int associated_pt; if (!rtc::FromString(associated_pt_str, &associated_pt)) { RTC_LOG(LS_WARNING) << "Couldn't convert first payload type " - << associated_pt_str << " of RED codec " - << red_codec.name << " to an integer."; + << associated_pt_str << " of RED codec " << red_codec.id + << " to an integer."; return nullptr; } // Find the associated codec for the RED codec. - const C* associated_codec = FindCodecById(codec_list, associated_pt); + const Codec* associated_codec = FindCodecById(codec_list, associated_pt); if (!associated_codec) { RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type " - << associated_pt << " for RED codec " << red_codec.name + << associated_pt << " for RED codec " << red_codec.id << "."; } return associated_codec; @@ -983,38 +958,37 @@ static const C* GetAssociatedCodecForRed(const std::vector& codec_list, // Adds all codecs from `reference_codecs` to `offered_codecs` that don't // already exist in `offered_codecs` and ensure the payload types don't // collide. -template -static void MergeCodecs(const std::vector& reference_codecs, - std::vector* offered_codecs, - UsedPayloadTypes* used_pltypes, - const webrtc::FieldTrialsView* field_trials) { +void MergeCodecs(const std::vector& reference_codecs, + std::vector* offered_codecs, + UsedPayloadTypes* used_pltypes, + const webrtc::FieldTrialsView* field_trials) { // Add all new codecs that are not RTX/RED codecs. // The two-pass splitting of the loops means preferring payload types // of actual codecs with respect to collisions. - for (const C& reference_codec : reference_codecs) { + for (const Codec& reference_codec : reference_codecs) { if (!IsRtxCodec(reference_codec) && !IsRedCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, field_trials)) { - C codec = reference_codec; + !FindMatchingCodec(reference_codecs, *offered_codecs, reference_codec, + field_trials)) { + Codec codec = reference_codec; used_pltypes->FindAndSetIdUsed(&codec); offered_codecs->push_back(codec); } } // Add all new RTX or RED codecs. - for (const C& reference_codec : reference_codecs) { + for (const Codec& reference_codec : reference_codecs) { if (IsRtxCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, field_trials)) { - C rtx_codec = reference_codec; - const C* associated_codec = + !FindMatchingCodec(reference_codecs, *offered_codecs, reference_codec, + field_trials)) { + Codec rtx_codec = reference_codec; + const Codec* associated_codec = GetAssociatedCodecForRtx(reference_codecs, rtx_codec); if (!associated_codec) { continue; } // Find a codec in the offered list that matches the reference codec. // Its payload type may be different than the reference codec. - absl::optional matching_codec = FindMatchingCodec( + absl::optional matching_codec = FindMatchingCodec( reference_codecs, *offered_codecs, *associated_codec, field_trials); if (!matching_codec) { RTC_LOG(LS_WARNING) @@ -1027,13 +1001,13 @@ static void MergeCodecs(const std::vector& reference_codecs, used_pltypes->FindAndSetIdUsed(&rtx_codec); offered_codecs->push_back(rtx_codec); } else if (IsRedCodec(reference_codec) && - !FindMatchingCodec(reference_codecs, *offered_codecs, - reference_codec, field_trials)) { - C red_codec = reference_codec; - const C* associated_codec = + !FindMatchingCodec(reference_codecs, *offered_codecs, + reference_codec, field_trials)) { + Codec red_codec = reference_codec; + const Codec* associated_codec = GetAssociatedCodecForRed(reference_codecs, red_codec); if (associated_codec) { - absl::optional matching_codec = FindMatchingCodec( + absl::optional matching_codec = FindMatchingCodec( reference_codecs, *offered_codecs, *associated_codec, field_trials); if (!matching_codec) { RTC_LOG(LS_WARNING) << "Couldn't find matching " @@ -1055,13 +1029,12 @@ static void MergeCodecs(const std::vector& reference_codecs, // don't conflict with mappings of the other media type; `supported_codecs` is // a list filtered for the media section`s direction but with default payload // types. -template -static Codecs MatchCodecPreference( +std::vector MatchCodecPreference( const std::vector& codec_preferences, - const Codecs& codecs, - const Codecs& supported_codecs, + const std::vector& codecs, + const std::vector& supported_codecs, const webrtc::FieldTrialsView* field_trials) { - Codecs filtered_codecs; + std::vector filtered_codecs; bool want_rtx = false; bool want_red = false; @@ -1072,10 +1045,10 @@ static Codecs MatchCodecPreference( want_red = true; } } + bool red_was_added = false; for (const auto& codec_preference : codec_preferences) { auto found_codec = absl::c_find_if( - supported_codecs, - [&codec_preference](const typename Codecs::value_type& codec) { + supported_codecs, [&codec_preference](const Codec& codec) { webrtc::RtpCodecParameters codec_parameters = codec.ToCodecParameters(); return codec_parameters.name == codec_preference.name && @@ -1087,11 +1060,16 @@ static Codecs MatchCodecPreference( }); if (found_codec != supported_codecs.end()) { - absl::optional found_codec_with_correct_pt = - FindMatchingCodec(supported_codecs, codecs, *found_codec, - field_trials); + absl::optional found_codec_with_correct_pt = FindMatchingCodec( + supported_codecs, codecs, *found_codec, field_trials); if (found_codec_with_correct_pt) { - filtered_codecs.push_back(*found_codec_with_correct_pt); + // RED may already have been added if its primary codec is before RED + // in the codec list. + bool is_red_codec = IsRedCodec(*found_codec_with_correct_pt); + if (!is_red_codec || !red_was_added) { + filtered_codecs.push_back(*found_codec_with_correct_pt); + red_was_added = is_red_codec ? true : red_was_added; + } std::string id = rtc::ToString(found_codec_with_correct_pt->id); // Search for the matching rtx or red codec. if (want_red || want_rtx) { @@ -1112,11 +1090,11 @@ static Codecs MatchCodecPreference( if (fmtp != codec.params.end()) { std::vector redundant_payloads = rtc::split(fmtp->second, '/'); - if (redundant_payloads.size() > 0 && + if (!redundant_payloads.empty() && redundant_payloads[0] == id) { - if (std::find(filtered_codecs.begin(), filtered_codecs.end(), - codec) == filtered_codecs.end()) { + if (!red_was_added) { filtered_codecs.push_back(codec); + red_was_added = true; } break; } @@ -1132,21 +1110,21 @@ static Codecs MatchCodecPreference( } // Compute the union of `codecs1` and `codecs2`. -template -std::vector ComputeCodecsUnion(const std::vector& codecs1, - const std::vector& codecs2, - const webrtc::FieldTrialsView* field_trials) { - std::vector all_codecs; +std::vector ComputeCodecsUnion( + const std::vector& codecs1, + const std::vector& codecs2, + const webrtc::FieldTrialsView* field_trials) { + std::vector all_codecs; UsedPayloadTypes used_payload_types; - for (const C& codec : codecs1) { - C codec_mutable = codec; + for (const Codec& codec : codecs1) { + Codec codec_mutable = codec; used_payload_types.FindAndSetIdUsed(&codec_mutable); all_codecs.push_back(codec_mutable); } // Use MergeCodecs to merge the second half of our list as it already checks // and fixes problems with duplicate payload types. - MergeCodecs(codecs2, &all_codecs, &used_payload_types, field_trials); + MergeCodecs(codecs2, &all_codecs, &used_payload_types, field_trials); return all_codecs; } @@ -1159,11 +1137,11 @@ std::vector ComputeCodecsUnion(const std::vector& codecs1, // `offered_extensions` is for either audio or video while `regular_extensions` // and `encrypted_extensions` are used for both audio and video. There could be // overlap between audio extensions and video extensions. -static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions, - RtpHeaderExtensions* offered_extensions, - RtpHeaderExtensions* regular_extensions, - RtpHeaderExtensions* encrypted_extensions, - UsedRtpHeaderExtensionIds* used_ids) { +void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions, + RtpHeaderExtensions* offered_extensions, + RtpHeaderExtensions* regular_extensions, + RtpHeaderExtensions* encrypted_extensions, + UsedRtpHeaderExtensionIds* used_ids) { for (auto reference_extension : reference_extensions) { if (!webrtc::RtpExtension::FindHeaderExtensionByUriAndEncryption( *offered_extensions, reference_extension.uri, @@ -1197,10 +1175,9 @@ static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions, } } -static void AddEncryptedVersionsOfHdrExts( - RtpHeaderExtensions* offered_extensions, - RtpHeaderExtensions* encrypted_extensions, - UsedRtpHeaderExtensionIds* used_ids) { +void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* offered_extensions, + RtpHeaderExtensions* encrypted_extensions, + UsedRtpHeaderExtensionIds* used_ids) { RtpHeaderExtensions encrypted_extensions_to_add; for (const auto& extension : *offered_extensions) { // Skip existing encrypted offered extension @@ -1249,7 +1226,7 @@ static void AddEncryptedVersionsOfHdrExts( // Mostly identical to RtpExtension::FindHeaderExtensionByUri but discards any // encrypted extensions that this implementation cannot encrypt. -static const webrtc::RtpExtension* FindHeaderExtensionByUriDiscardUnsupported( +const webrtc::RtpExtension* FindHeaderExtensionByUriDiscardUnsupported( const std::vector& extensions, absl::string_view uri, webrtc::RtpExtension::Filter filter) { @@ -1273,11 +1250,10 @@ static const webrtc::RtpExtension* FindHeaderExtensionByUriDiscardUnsupported( filter); } -static void NegotiateRtpHeaderExtensions( - const RtpHeaderExtensions& local_extensions, - const RtpHeaderExtensions& offered_extensions, - webrtc::RtpExtension::Filter filter, - RtpHeaderExtensions* negotiated_extensions) { +void NegotiateRtpHeaderExtensions(const RtpHeaderExtensions& local_extensions, + const RtpHeaderExtensions& offered_extensions, + webrtc::RtpExtension::Filter filter, + RtpHeaderExtensions* negotiated_extensions) { // TransportSequenceNumberV2 is not offered by default. The special logic for // the TransportSequenceNumber extensions works as follows: // Offer Answer @@ -1357,7 +1333,7 @@ static void NegotiateRtpHeaderExtensions( } } -static void StripCNCodecs(AudioCodecs* audio_codecs) { +void StripCNCodecs(AudioCodecs* audio_codecs) { audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(), [](const AudioCodec& codec) { return IsComfortNoiseCodec(codec); @@ -1365,17 +1341,17 @@ static void StripCNCodecs(AudioCodecs* audio_codecs) { audio_codecs->end()); } -template -static bool SetCodecsInAnswer( - const MediaContentDescriptionImpl* offer, - const std::vector& local_codecs, - const MediaDescriptionOptions& media_description_options, - const MediaSessionOptions& session_options, - UniqueRandomIdGenerator* ssrc_generator, - StreamParamsVec* current_streams, - MediaContentDescriptionImpl* answer, - const webrtc::FieldTrialsView& field_trials) { - std::vector negotiated_codecs; +bool SetCodecsInAnswer(const MediaContentDescription* offer, + const std::vector& local_codecs, + const MediaDescriptionOptions& media_description_options, + const MediaSessionOptions& session_options, + UniqueRandomIdGenerator* ssrc_generator, + StreamParamsVec* current_streams, + MediaContentDescription* answer, + const webrtc::FieldTrialsView& field_trials) { + RTC_DCHECK(offer->type() == MEDIA_TYPE_AUDIO || + offer->type() == MEDIA_TYPE_VIDEO); + std::vector negotiated_codecs; NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs, media_description_options.codec_preferences.empty(), &field_trials); @@ -1396,7 +1372,7 @@ static bool SetCodecsInAnswer( // (according to crypto_suites). The codecs, rtcp_mux, and crypto are all // negotiated with the offer. If the negotiation fails, this method returns // false. The created content is added to the offer. -static bool CreateMediaContentAnswer( +bool CreateMediaContentAnswer( const MediaContentDescription* offer, const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, @@ -1465,9 +1441,9 @@ static bool CreateMediaContentAnswer( return true; } -static bool IsMediaProtocolSupported(MediaType type, - const std::string& protocol, - bool secure_transport) { +bool IsMediaProtocolSupported(MediaType type, + const std::string& protocol, + bool secure_transport) { // Since not all applications serialize and deserialize the media protocol, // we will have to accept `protocol` to be empty. if (protocol.empty()) { @@ -1494,8 +1470,7 @@ static bool IsMediaProtocolSupported(MediaType type, } } -static void SetMediaProtocol(bool secure_transport, - MediaContentDescription* desc) { +void SetMediaProtocol(bool secure_transport, MediaContentDescription* desc) { if (!desc->cryptos().empty()) desc->set_protocol(kMediaProtocolSavpf); else if (secure_transport) @@ -1506,7 +1481,7 @@ static void SetMediaProtocol(bool secure_transport, // Gets the TransportInfo of the given `content_name` from the // `current_description`. If doesn't exist, returns a new one. -static const TransportDescription* GetTransportDescription( +const TransportDescription* GetTransportDescription( const std::string& content_name, const SessionDescription* current_description) { const TransportDescription* desc = NULL; @@ -1521,8 +1496,8 @@ static const TransportDescription* GetTransportDescription( } // Gets the current DTLS state from the transport description. -static bool IsDtlsActive(const ContentInfo* content, - const SessionDescription* current_description) { +bool IsDtlsActive(const ContentInfo* content, + const SessionDescription* current_description) { if (!content) { return false; } @@ -1537,6 +1512,8 @@ static bool IsDtlsActive(const ContentInfo* content, .description.secure(); } +} // namespace + void MediaDescriptionOptions::AddAudioSender( const std::string& track_id, const std::vector& stream_ids) { @@ -1581,18 +1558,14 @@ bool MediaSessionOptions::HasMediaDescription(MediaType type) const { [type](const MediaDescriptionOptions& t) { return t.type == type; }); } -MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( - const TransportDescriptionFactory* transport_desc_factory, - rtc::UniqueRandomIdGenerator* ssrc_generator) - : ssrc_generator_(ssrc_generator), - transport_desc_factory_(transport_desc_factory) {} - MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( cricket::MediaEngineInterface* media_engine, bool rtx_enabled, rtc::UniqueRandomIdGenerator* ssrc_generator, const TransportDescriptionFactory* transport_desc_factory) - : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) { + : ssrc_generator_(ssrc_generator), + transport_desc_factory_(transport_desc_factory) { + RTC_CHECK(transport_desc_factory_); if (media_engine) { audio_send_codecs_ = media_engine->voice().send_codecs(); audio_recv_codecs_ = media_engine->voice().recv_codecs(); @@ -1645,30 +1618,26 @@ void MediaSessionDescriptionFactory::set_video_codecs( ComputeVideoCodecsIntersectionAndUnion(); } -static void RemoveUnifiedPlanExtensions(RtpHeaderExtensions* extensions) { - RTC_DCHECK(extensions); - - extensions->erase( - std::remove_if(extensions->begin(), extensions->end(), - [](auto extension) { - return extension.uri == webrtc::RtpExtension::kMidUri || - extension.uri == webrtc::RtpExtension::kRidUri || - extension.uri == - webrtc::RtpExtension::kRepairedRidUri; - }), - extensions->end()); -} - RtpHeaderExtensions MediaSessionDescriptionFactory::filtered_rtp_header_extensions( RtpHeaderExtensions extensions) const { if (!is_unified_plan_) { - RemoveUnifiedPlanExtensions(&extensions); + // Remove extensions only supported with unified-plan. + extensions.erase( + std::remove_if( + extensions.begin(), extensions.end(), + [](const webrtc::RtpExtension& extension) { + return extension.uri == webrtc::RtpExtension::kMidUri || + extension.uri == webrtc::RtpExtension::kRidUri || + extension.uri == webrtc::RtpExtension::kRepairedRidUri; + }), + extensions.end()); } return extensions; } -std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( +webrtc::RTCErrorOr> +MediaSessionDescriptionFactory::CreateOfferOrError( const MediaSessionOptions& session_options, const SessionDescription* current_description) const { // Must have options for each existing section. @@ -1710,47 +1679,38 @@ std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( msection_index < current_description->contents().size()) { current_content = ¤t_description->contents()[msection_index]; // Media type must match unless this media section is being recycled. - RTC_DCHECK(current_content->name != media_description_options.mid || - IsMediaContentOfType(current_content, - media_description_options.type)); } + RTCError error; switch (media_description_options.type) { case MEDIA_TYPE_AUDIO: - if (!AddAudioContentForOffer(media_description_options, session_options, - current_content, current_description, - extensions_with_ids.audio, - offer_audio_codecs, ¤t_streams, - offer.get(), &ice_credentials)) { - return nullptr; - } + error = AddAudioContentForOffer( + media_description_options, session_options, current_content, + current_description, extensions_with_ids.audio, offer_audio_codecs, + ¤t_streams, offer.get(), &ice_credentials); break; case MEDIA_TYPE_VIDEO: - if (!AddVideoContentForOffer(media_description_options, session_options, - current_content, current_description, - extensions_with_ids.video, - offer_video_codecs, ¤t_streams, - offer.get(), &ice_credentials)) { - return nullptr; - } + error = AddVideoContentForOffer( + media_description_options, session_options, current_content, + current_description, extensions_with_ids.video, offer_video_codecs, + ¤t_streams, offer.get(), &ice_credentials); break; case MEDIA_TYPE_DATA: - if (!AddDataContentForOffer(media_description_options, session_options, - current_content, current_description, - ¤t_streams, offer.get(), - &ice_credentials)) { - return nullptr; - } + error = AddDataContentForOffer(media_description_options, + session_options, current_content, + current_description, ¤t_streams, + offer.get(), &ice_credentials); break; case MEDIA_TYPE_UNSUPPORTED: - if (!AddUnsupportedContentForOffer( - media_description_options, session_options, current_content, - current_description, offer.get(), &ice_credentials)) { - return nullptr; - } + error = AddUnsupportedContentForOffer( + media_description_options, session_options, current_content, + current_description, offer.get(), &ice_credentials); break; default: RTC_DCHECK_NOTREACHED(); } + if (!error.ok()) { + return error; + } ++msection_index; } @@ -1772,14 +1732,14 @@ std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( if (!offer_bundle.content_names().empty()) { offer->AddGroup(offer_bundle); if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) { - RTC_LOG(LS_ERROR) - << "CreateOffer failed to UpdateTransportInfoForBundle."; - return nullptr; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "CreateOffer failed to UpdateTransportInfoForBundle"); } if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) { - RTC_LOG(LS_ERROR) - << "CreateOffer failed to UpdateCryptoParamsForBundle."; - return nullptr; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "CreateOffer failed to UpdateCryptoParamsForBundle."); } } } @@ -1802,13 +1762,13 @@ std::unique_ptr MediaSessionDescriptionFactory::CreateOffer( return offer; } -std::unique_ptr -MediaSessionDescriptionFactory::CreateAnswer( +webrtc::RTCErrorOr> +MediaSessionDescriptionFactory::CreateAnswerOrError( const SessionDescription* offer, const MediaSessionOptions& session_options, const SessionDescription* current_description) const { if (!offer) { - return nullptr; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Called without offer."); } // Must have options for exactly as many sections as in the offer. @@ -1889,44 +1849,40 @@ MediaSessionDescriptionFactory::CreateAnswer( RtpHeaderExtensions header_extensions = RtpHeaderExtensionsFromCapabilities( UnstoppedRtpHeaderExtensionCapabilities( media_description_options.header_extensions)); + RTCError error; switch (media_description_options.type) { case MEDIA_TYPE_AUDIO: - if (!AddAudioContentForAnswer( - media_description_options, session_options, offer_content, - offer, current_content, current_description, bundle_transport, - answer_audio_codecs, header_extensions, ¤t_streams, - answer.get(), &ice_credentials)) { - return nullptr; - } + error = AddAudioContentForAnswer( + media_description_options, session_options, offer_content, offer, + current_content, current_description, bundle_transport, + answer_audio_codecs, header_extensions, ¤t_streams, + answer.get(), &ice_credentials); break; case MEDIA_TYPE_VIDEO: - if (!AddVideoContentForAnswer( - media_description_options, session_options, offer_content, - offer, current_content, current_description, bundle_transport, - answer_video_codecs, header_extensions, ¤t_streams, - answer.get(), &ice_credentials)) { - return nullptr; - } + error = AddVideoContentForAnswer( + media_description_options, session_options, offer_content, offer, + current_content, current_description, bundle_transport, + answer_video_codecs, header_extensions, ¤t_streams, + answer.get(), &ice_credentials); break; case MEDIA_TYPE_DATA: - if (!AddDataContentForAnswer( - media_description_options, session_options, offer_content, - offer, current_content, current_description, bundle_transport, - ¤t_streams, answer.get(), &ice_credentials)) { - return nullptr; - } + error = AddDataContentForAnswer( + media_description_options, session_options, offer_content, offer, + current_content, current_description, bundle_transport, + ¤t_streams, answer.get(), &ice_credentials); break; case MEDIA_TYPE_UNSUPPORTED: - if (!AddUnsupportedContentForAnswer( - media_description_options, session_options, offer_content, - offer, current_content, current_description, bundle_transport, - answer.get(), &ice_credentials)) { - return nullptr; - } + error = AddUnsupportedContentForAnswer( + media_description_options, session_options, offer_content, offer, + current_content, current_description, bundle_transport, + answer.get(), &ice_credentials); break; default: RTC_DCHECK_NOTREACHED(); } + if (!error.ok()) { + return error; + } ++msection_index; // See if we can add the newly generated m= section to the BUNDLE group in // the answer. @@ -1955,15 +1911,15 @@ MediaSessionDescriptionFactory::CreateAnswer( // Share the same ICE credentials and crypto params across all contents, // as BUNDLE requires. if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) { - RTC_LOG(LS_ERROR) - << "CreateAnswer failed to UpdateTransportInfoForBundle."; - return NULL; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "CreateAnswer failed to UpdateTransportInfoForBundle."); } if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) { - RTC_LOG(LS_ERROR) - << "CreateAnswer failed to UpdateCryptoParamsForBundle."; - return NULL; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "CreateAnswer failed to UpdateCryptoParamsForBundle."); } } } @@ -2083,15 +2039,11 @@ void MergeCodecsFromDescription( const webrtc::FieldTrialsView* field_trials) { for (const ContentInfo* content : current_active_contents) { if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) { - const AudioContentDescription* audio = - content->media_description()->as_audio(); - MergeCodecs(audio->codecs(), audio_codecs, used_pltypes, - field_trials); + MergeCodecs(content->media_description()->codecs(), audio_codecs, + used_pltypes, field_trials); } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) { - const VideoContentDescription* video = - content->media_description()->as_video(); - MergeCodecs(video->codecs(), video_codecs, used_pltypes, - field_trials); + MergeCodecs(content->media_description()->codecs(), video_codecs, + used_pltypes, field_trials); } } } @@ -2116,10 +2068,8 @@ void MediaSessionDescriptionFactory::GetCodecsForOffer( video_codecs, &used_pltypes, field_trials); // Add our codecs that are not in the current description. - MergeCodecs(all_audio_codecs_, audio_codecs, &used_pltypes, - field_trials); - MergeCodecs(all_video_codecs_, video_codecs, &used_pltypes, - field_trials); + MergeCodecs(all_audio_codecs_, audio_codecs, &used_pltypes, field_trials); + MergeCodecs(all_video_codecs_, video_codecs, &used_pltypes, field_trials); } // Getting codecs for an answer involves these steps: @@ -2148,26 +2098,22 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( VideoCodecs filtered_offered_video_codecs; for (const ContentInfo& content : remote_offer.contents()) { if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) { - const AudioContentDescription* audio = - content.media_description()->as_audio(); - for (const AudioCodec& offered_audio_codec : audio->codecs()) { - if (!FindMatchingCodec(audio->codecs(), - filtered_offered_audio_codecs, - offered_audio_codec, field_trials) && - FindMatchingCodec(audio->codecs(), all_audio_codecs_, - offered_audio_codec, field_trials)) { + std::vector offered_codecs = content.media_description()->codecs(); + for (const Codec& offered_audio_codec : offered_codecs) { + if (!FindMatchingCodec(offered_codecs, filtered_offered_audio_codecs, + offered_audio_codec, field_trials) && + FindMatchingCodec(offered_codecs, all_audio_codecs_, + offered_audio_codec, field_trials)) { filtered_offered_audio_codecs.push_back(offered_audio_codec); } } } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) { - const VideoContentDescription* video = - content.media_description()->as_video(); - for (const VideoCodec& offered_video_codec : video->codecs()) { - if (!FindMatchingCodec(video->codecs(), - filtered_offered_video_codecs, - offered_video_codec, field_trials) && - FindMatchingCodec(video->codecs(), all_video_codecs_, - offered_video_codec, field_trials)) { + std::vector offered_codecs = content.media_description()->codecs(); + for (const Codec& offered_video_codec : offered_codecs) { + if (!FindMatchingCodec(offered_codecs, filtered_offered_video_codecs, + offered_video_codec, field_trials) && + FindMatchingCodec(offered_codecs, all_video_codecs_, + offered_video_codec, field_trials)) { filtered_offered_video_codecs.push_back(offered_video_codec); } } @@ -2176,10 +2122,10 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer( // Add codecs that are not in the current description but were in // `remote_offer`. - MergeCodecs(filtered_offered_audio_codecs, audio_codecs, - &used_pltypes, field_trials); - MergeCodecs(filtered_offered_video_codecs, video_codecs, - &used_pltypes, field_trials); + MergeCodecs(filtered_offered_audio_codecs, audio_codecs, &used_pltypes, + field_trials); + MergeCodecs(filtered_offered_video_codecs, video_codecs, &used_pltypes, + field_trials); } MediaSessionDescriptionFactory::AudioVideoRtpHeaderExtensions @@ -2208,17 +2154,13 @@ MediaSessionDescriptionFactory::GetOfferedRtpHeaderExtensionsWithIds( // type is added. for (const ContentInfo* content : current_active_contents) { if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) { - const AudioContentDescription* audio = - content->media_description()->as_audio(); - MergeRtpHdrExts(audio->rtp_header_extensions(), &offered_extensions.audio, - &all_regular_extensions, &all_encrypted_extensions, - &used_ids); + MergeRtpHdrExts(content->media_description()->rtp_header_extensions(), + &offered_extensions.audio, &all_regular_extensions, + &all_encrypted_extensions, &used_ids); } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) { - const VideoContentDescription* video = - content->media_description()->as_video(); - MergeRtpHdrExts(video->rtp_header_extensions(), &offered_extensions.video, - &all_regular_extensions, &all_encrypted_extensions, - &used_ids); + MergeRtpHdrExts(content->media_description()->rtp_header_extensions(), + &offered_extensions.video, &all_regular_extensions, + &all_encrypted_extensions, &used_ids); } } @@ -2251,14 +2193,12 @@ MediaSessionDescriptionFactory::GetOfferedRtpHeaderExtensionsWithIds( return offered_extensions; } -bool MediaSessionDescriptionFactory::AddTransportOffer( +RTCError MediaSessionDescriptionFactory::AddTransportOffer( const std::string& content_name, const TransportOptions& transport_options, const SessionDescription* current_desc, SessionDescription* offer_desc, IceCredentialsIterator* ice_credentials) const { - if (!transport_desc_factory_) - return false; const TransportDescription* current_tdesc = GetTransportDescription(content_name, current_desc); std::unique_ptr new_tdesc( @@ -2269,7 +2209,7 @@ bool MediaSessionDescriptionFactory::AddTransportOffer( << content_name; } offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)); - return true; + return RTCError::OK(); } std::unique_ptr @@ -2280,8 +2220,6 @@ MediaSessionDescriptionFactory::CreateTransportAnswer( const SessionDescription* current_desc, bool require_transport_attributes, IceCredentialsIterator* ice_credentials) const { - if (!transport_desc_factory_) - return NULL; const TransportDescription* offer_tdesc = GetTransportDescription(content_name, offer_desc); const TransportDescription* current_tdesc = @@ -2291,12 +2229,12 @@ MediaSessionDescriptionFactory::CreateTransportAnswer( current_tdesc, ice_credentials); } -bool MediaSessionDescriptionFactory::AddTransportAnswer( +RTCError MediaSessionDescriptionFactory::AddTransportAnswer( const std::string& content_name, const TransportDescription& transport_desc, SessionDescription* answer_desc) const { answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc)); - return true; + return RTCError::OK(); } // `audio_codecs` = set of all possible codecs that can be used, with correct @@ -2305,13 +2243,13 @@ bool MediaSessionDescriptionFactory::AddTransportAnswer( // `supported_audio_codecs` = set of codecs that are supported for the direction // of this m= section // -// acd->codecs() = set of previously negotiated codecs for this m= section +// mcd->codecs() = set of previously negotiated codecs for this m= section // // The payload types should come from audio_codecs, but the order should come -// from acd->codecs() and then supported_codecs, to ensure that re-offers don't +// from mcd->codecs() and then supported_codecs, to ensure that re-offers don't // change existing codec priority, and that new codecs are added with the right // priority. -bool MediaSessionDescriptionFactory::AddAudioContentForOffer( +RTCError MediaSessionDescriptionFactory::AddAudioContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -2341,24 +2279,28 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer( // recycled. if (current_content && !current_content->rejected && current_content->name == media_description_options.mid) { - RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)); - const AudioContentDescription* acd = - current_content->media_description()->as_audio(); - for (const AudioCodec& codec : acd->codecs()) { - if (FindMatchingCodec(acd->codecs(), audio_codecs, codec, - field_trials)) { + if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) { + // Can happen if the remote side re-uses a MID while recycling. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Media type for content with mid='" + + current_content->name + + "' does not match previous type."); + } + const MediaContentDescription* mcd = current_content->media_description(); + for (const Codec& codec : mcd->codecs()) { + if (FindMatchingCodec(mcd->codecs(), audio_codecs, codec, + field_trials)) { filtered_codecs.push_back(codec); } } } // Add other supported audio codecs. - - for (const AudioCodec& codec : supported_audio_codecs) { - absl::optional found_codec = FindMatchingCodec( + for (const Codec& codec : supported_audio_codecs) { + absl::optional found_codec = FindMatchingCodec( supported_audio_codecs, audio_codecs, codec, field_trials); if (found_codec && - !FindMatchingCodec( - supported_audio_codecs, filtered_codecs, codec, field_trials)) { + !FindMatchingCodec(supported_audio_codecs, filtered_codecs, codec, + field_trials)) { // Use the `found_codec` from `audio_codecs` because it has the // correctly mapped payload type. filtered_codecs.push_back(*found_codec); @@ -2378,12 +2320,13 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer( std::vector crypto_suites; GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options, &crypto_suites); - if (!CreateMediaContentOffer( - media_description_options, session_options, filtered_codecs, - sdes_policy, GetCryptos(current_content), crypto_suites, - audio_rtp_extensions, ssrc_generator(), current_streams, audio.get(), - transport_desc_factory_->trials())) { - return false; + auto error = CreateMediaContentOffer( + media_description_options, session_options, filtered_codecs, sdes_policy, + GetCryptos(current_content), crypto_suites, audio_rtp_extensions, + ssrc_generator(), current_streams, audio.get(), + transport_desc_factory_->trials()); + if (!error.ok()) { + return error; } bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); @@ -2393,18 +2336,19 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer( desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, media_description_options.stopped, std::move(audio)); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; + error = AddTransportOffer(media_description_options.mid, + media_description_options.transport_options, + current_description, desc, ice_credentials); + if (!error.ok()) { + return error; } - return true; + return RTCError::OK(); } // TODO(kron): This function is very similar to AddAudioContentForOffer. // Refactor to reuse shared code. -bool MediaSessionDescriptionFactory::AddVideoContentForOffer( +RTCError MediaSessionDescriptionFactory::AddVideoContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -2434,23 +2378,28 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( // recycled. if (current_content && !current_content->rejected && current_content->name == media_description_options.mid) { - RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)); - const VideoContentDescription* vcd = - current_content->media_description()->as_video(); - for (const VideoCodec& codec : vcd->codecs()) { - if (FindMatchingCodec(vcd->codecs(), video_codecs, codec, - field_trials)) { + if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) { + // Can happen if the remote side re-uses a MID while recycling. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Media type for content with mid='" + + current_content->name + + "' does not match previous type."); + } + const MediaContentDescription* mcd = current_content->media_description(); + for (const Codec& codec : mcd->codecs()) { + if (FindMatchingCodec(mcd->codecs(), video_codecs, codec, + field_trials)) { filtered_codecs.push_back(codec); } } } // Add other supported video codecs. - for (const VideoCodec& codec : supported_video_codecs) { - absl::optional found_codec = FindMatchingCodec( + for (const Codec& codec : supported_video_codecs) { + absl::optional found_codec = FindMatchingCodec( supported_video_codecs, video_codecs, codec, field_trials); if (found_codec && - !FindMatchingCodec( - supported_video_codecs, filtered_codecs, codec, field_trials)) { + !FindMatchingCodec(supported_video_codecs, filtered_codecs, codec, + field_trials)) { // Use the `found_codec` from `video_codecs` because it has the // correctly mapped payload type. if (IsRtxCodec(codec)) { @@ -2461,10 +2410,9 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( RTC_DCHECK(referenced_codec); // Find the codec we should be referencing and point to it. - absl::optional changed_referenced_codec = - FindMatchingCodec(supported_video_codecs, - filtered_codecs, *referenced_codec, - field_trials); + absl::optional changed_referenced_codec = + FindMatchingCodec(supported_video_codecs, filtered_codecs, + *referenced_codec, field_trials); if (changed_referenced_codec) { found_codec->SetParam(kCodecParamAssociatedPayloadType, changed_referenced_codec->id); @@ -2476,7 +2424,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( } if (session_options.raw_packetization_for_video) { - for (VideoCodec& codec : filtered_codecs) { + for (Codec& codec : filtered_codecs) { if (codec.IsMediaCodec()) { codec.packetization = kPacketizationParamRaw; } @@ -2490,12 +2438,13 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( std::vector crypto_suites; GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options, &crypto_suites); - if (!CreateMediaContentOffer( - media_description_options, session_options, filtered_codecs, - sdes_policy, GetCryptos(current_content), crypto_suites, - video_rtp_extensions, ssrc_generator(), current_streams, video.get(), - transport_desc_factory_->trials())) { - return false; + auto error = CreateMediaContentOffer( + media_description_options, session_options, filtered_codecs, sdes_policy, + GetCryptos(current_content), crypto_suites, video_rtp_extensions, + ssrc_generator(), current_streams, video.get(), + transport_desc_factory_->trials()); + if (!error.ok()) { + return error; } video->set_bandwidth(kAutoBandwidth); @@ -2507,16 +2456,12 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, media_description_options.stopped, std::move(video)); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; - } - - return true; + return AddTransportOffer(media_description_options.mid, + media_description_options.transport_options, + current_description, desc, ice_credentials); } -bool MediaSessionDescriptionFactory::AddDataContentForOffer( +RTCError MediaSessionDescriptionFactory::AddDataContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -2544,24 +2489,22 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer( data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp); data->set_max_message_size(kSctpSendBufferSize); - if (!CreateContentOffer(media_description_options, session_options, - sdes_policy, GetCryptos(current_content), - crypto_suites, RtpHeaderExtensions(), - ssrc_generator(), current_streams, data.get())) { - return false; + auto error = CreateContentOffer( + media_description_options, session_options, sdes_policy, + GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(), + ssrc_generator(), current_streams, data.get()); + if (!error.ok()) { + return error; } desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp, media_description_options.stopped, std::move(data)); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; - } - return true; + return AddTransportOffer(media_description_options.mid, + media_description_options.transport_options, + current_description, desc, ice_credentials); } -bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer( +RTCError MediaSessionDescriptionFactory::AddUnsupportedContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -2578,12 +2521,9 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer( desc->AddContent(media_description_options.mid, MediaProtocolType::kOther, /*rejected=*/true, std::move(unsupported)); - if (!AddTransportOffer(media_description_options.mid, - media_description_options.transport_options, - current_description, desc, ice_credentials)) { - return false; - } - return true; + return AddTransportOffer(media_description_options.mid, + media_description_options.transport_options, + current_description, desc, ice_credentials); } // `audio_codecs` = set of all possible codecs that can be used, with correct @@ -2592,13 +2532,13 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer( // `supported_audio_codecs` = set of codecs that are supported for the direction // of this m= section // -// acd->codecs() = set of previously negotiated codecs for this m= section +// mcd->codecs() = set of previously negotiated codecs for this m= section // // The payload types should come from audio_codecs, but the order should come -// from acd->codecs() and then supported_codecs, to ensure that re-offers don't +// from mcd->codecs() and then supported_codecs, to ensure that re-offers don't // change existing codec priority, and that new codecs are added with the right // priority. -bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( +RTCError MediaSessionDescriptionFactory::AddAudioContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -2622,7 +2562,9 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( media_description_options.transport_options, current_description, bundle_transport != nullptr, ice_credentials); if (!audio_transport) { - return false; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "Failed to create transport answer, audio transport is missing"); } // Pick codecs based on the requested communications direction in the offer @@ -2645,22 +2587,27 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( // recycled. if (current_content && !current_content->rejected && current_content->name == media_description_options.mid) { - RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)); - const AudioContentDescription* acd = - current_content->media_description()->as_audio(); - for (const AudioCodec& codec : acd->codecs()) { - if (FindMatchingCodec(acd->codecs(), audio_codecs, codec, - field_trials)) { + if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) { + // Can happen if the remote side re-uses a MID while recycling. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Media type for content with mid='" + + current_content->name + + "' does not match previous type."); + } + const MediaContentDescription* mcd = current_content->media_description(); + for (const Codec& codec : mcd->codecs()) { + if (FindMatchingCodec(mcd->codecs(), audio_codecs, codec, + field_trials)) { filtered_codecs.push_back(codec); } } } // Add other supported audio codecs. - for (const AudioCodec& codec : supported_audio_codecs) { - if (FindMatchingCodec(supported_audio_codecs, audio_codecs, - codec, field_trials) && - !FindMatchingCodec( - supported_audio_codecs, filtered_codecs, codec, field_trials)) { + for (const Codec& codec : supported_audio_codecs) { + if (FindMatchingCodec(supported_audio_codecs, audio_codecs, codec, + field_trials) && + !FindMatchingCodec(supported_audio_codecs, filtered_codecs, codec, + field_trials)) { // We should use the local codec with local parameters and the codec id // would be correctly mapped in `NegotiateCodecs`. filtered_codecs.push_back(codec); @@ -2689,7 +2636,8 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( media_description_options, session_options, ssrc_generator(), current_streams, audio_answer.get(), transport_desc_factory_->trials())) { - return false; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to set codecs in answer"); } if (!CreateMediaContentAnswer( offer_audio_description, media_description_options, session_options, @@ -2697,7 +2645,8 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( filtered_rtp_header_extensions(rtp_header_extensions), ssrc_generator(), enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, audio_answer.get())) { - return false; // Fails the session setup. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to create answer"); } bool secure = bundle_transport ? bundle_transport->description.secure() @@ -2706,9 +2655,10 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( offer_content->rejected || !has_common_media_codecs || !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, audio_answer->protocol(), secure); - if (!AddTransportAnswer(media_description_options.mid, - *(audio_transport.get()), answer)) { - return false; + auto error = AddTransportAnswer(media_description_options.mid, + *(audio_transport.get()), answer); + if (!error.ok()) { + return error; } if (rejected) { @@ -2718,12 +2668,12 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( answer->AddContent(media_description_options.mid, offer_content->type, rejected, std::move(audio_answer)); - return true; + return RTCError::OK(); } // TODO(kron): This function is very similar to AddAudioContentForAnswer. // Refactor to reuse shared code. -bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( +RTCError MediaSessionDescriptionFactory::AddVideoContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -2747,7 +2697,9 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( media_description_options.transport_options, current_description, bundle_transport != nullptr, ice_credentials); if (!video_transport) { - return false; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "Failed to create transport answer, video transport is missing"); } // Pick codecs based on the requested communications direction in the offer @@ -2770,12 +2722,17 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( // recycled. if (current_content && !current_content->rejected && current_content->name == media_description_options.mid) { - RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)); - const VideoContentDescription* vcd = - current_content->media_description()->as_video(); - for (const VideoCodec& codec : vcd->codecs()) { - if (FindMatchingCodec(vcd->codecs(), video_codecs, codec, - field_trials)) { + if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) { + // Can happen if the remote side re-uses a MID while recycling. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Media type for content with mid='" + + current_content->name + + "' does not match previous type."); + } + const MediaContentDescription* mcd = current_content->media_description(); + for (const Codec& codec : mcd->codecs()) { + if (FindMatchingCodec(mcd->codecs(), video_codecs, codec, + field_trials)) { filtered_codecs.push_back(codec); } } @@ -2783,11 +2740,11 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( // Add other supported video codecs. VideoCodecs other_video_codecs; - for (const VideoCodec& codec : supported_video_codecs) { - if (FindMatchingCodec(supported_video_codecs, video_codecs, - codec, field_trials) && - !FindMatchingCodec( - supported_video_codecs, filtered_codecs, codec, field_trials)) { + for (const Codec& codec : supported_video_codecs) { + if (FindMatchingCodec(supported_video_codecs, video_codecs, codec, + field_trials) && + !FindMatchingCodec(supported_video_codecs, filtered_codecs, codec, + field_trials)) { // We should use the local codec with local parameters and the codec id // would be correctly mapped in `NegotiateCodecs`. other_video_codecs.push_back(codec); @@ -2795,19 +2752,18 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( } // Use ComputeCodecsUnion to avoid having duplicate payload IDs - filtered_codecs = ComputeCodecsUnion( - filtered_codecs, other_video_codecs, field_trials); + filtered_codecs = + ComputeCodecsUnion(filtered_codecs, other_video_codecs, field_trials); } // Determine if we have media codecs in common. bool has_common_media_codecs = std::find_if( - filtered_codecs.begin(), filtered_codecs.end(), - [](const VideoCodec& c) { + filtered_codecs.begin(), filtered_codecs.end(), [](const Codec& c) { return !(IsRedCodec(c) || IsUlpfecCodec(c) || IsFlexfecCodec(c)); }) != filtered_codecs.end(); if (session_options.raw_packetization_for_video) { - for (VideoCodec& codec : filtered_codecs) { + for (Codec& codec : filtered_codecs) { if (codec.IsMediaCodec()) { codec.packetization = kPacketizationParamRaw; } @@ -2824,7 +2780,8 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( media_description_options, session_options, ssrc_generator(), current_streams, video_answer.get(), transport_desc_factory_->trials())) { - return false; + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to set codecs in answer"); } if (!CreateMediaContentAnswer( offer_video_description, media_description_options, session_options, @@ -2832,7 +2789,8 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( filtered_rtp_header_extensions(default_video_rtp_header_extensions), ssrc_generator(), enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, video_answer.get())) { - return false; // Failed the session setup. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to create answer"); } bool secure = bundle_transport ? bundle_transport->description.secure() : video_transport->secure(); @@ -2840,9 +2798,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( offer_content->rejected || !has_common_media_codecs || !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, video_answer->protocol(), secure); - if (!AddTransportAnswer(media_description_options.mid, - *(video_transport.get()), answer)) { - return false; + auto error = AddTransportAnswer(media_description_options.mid, + *(video_transport.get()), answer); + if (!error.ok()) { + return error; } if (!rejected) { @@ -2853,10 +2812,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( } answer->AddContent(media_description_options.mid, offer_content->type, rejected, std::move(video_answer)); - return true; + return RTCError::OK(); } -bool MediaSessionDescriptionFactory::AddDataContentForAnswer( +RTCError MediaSessionDescriptionFactory::AddDataContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -2872,7 +2831,9 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( media_description_options.transport_options, current_description, bundle_transport != nullptr, ice_credentials); if (!data_transport) { - return false; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "Failed to create transport answer, data transport is missing"); } // Do not require or create SDES cryptos if DTLS is used. @@ -2905,7 +2866,8 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), ssrc_generator(), enable_encrypted_rtp_header_extensions_, current_streams, bundle_enabled, data_answer.get())) { - return false; // Fails the session setup. + LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, + "Failed to create answer"); } // Respond with sctpmap if the offer uses sctpmap. bool offer_uses_sctpmap = offer_data_description->use_sctpmap(); @@ -2921,17 +2883,17 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( offer_content->rejected || !IsMediaProtocolSupported(MEDIA_TYPE_DATA, data_answer->protocol(), secure); - if (!AddTransportAnswer(media_description_options.mid, - *(data_transport.get()), answer)) { - return false; + auto error = AddTransportAnswer(media_description_options.mid, + *(data_transport.get()), answer); + if (!error.ok()) { + return error; } - answer->AddContent(media_description_options.mid, offer_content->type, rejected, std::move(data_answer)); - return true; + return RTCError::OK(); } -bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( +RTCError MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -2947,7 +2909,9 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( current_description, bundle_transport != nullptr, ice_credentials); if (!unsupported_transport) { - return false; + LOG_AND_RETURN_ERROR( + RTCErrorType::INTERNAL_ERROR, + "Failed to create transport answer, unsupported transport is missing"); } RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_UNSUPPORTED)); @@ -2958,13 +2922,15 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( offer_unsupported_description->media_type()); unsupported_answer->set_protocol(offer_unsupported_description->protocol()); - if (!AddTransportAnswer(media_description_options.mid, - *(unsupported_transport.get()), answer)) { - return false; + auto error = AddTransportAnswer(media_description_options.mid, + *(unsupported_transport.get()), answer); + if (!error.ok()) { + return error; } + answer->AddContent(media_description_options.mid, offer_content->type, /*rejected=*/true, std::move(unsupported_answer)); - return true; + return RTCError::OK(); } void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() { @@ -2973,18 +2939,18 @@ void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() { audio_sendrecv_codecs_.clear(); all_audio_codecs_.clear(); // Compute the audio codecs union. - for (const AudioCodec& send : audio_send_codecs_) { + for (const Codec& send : audio_send_codecs_) { all_audio_codecs_.push_back(send); - if (!FindMatchingCodec(audio_send_codecs_, audio_recv_codecs_, - send, field_trials)) { + if (!FindMatchingCodec(audio_send_codecs_, audio_recv_codecs_, send, + field_trials)) { // It doesn't make sense to have an RTX codec we support sending but not // receiving. RTC_DCHECK(!IsRtxCodec(send)); } } - for (const AudioCodec& recv : audio_recv_codecs_) { - if (!FindMatchingCodec(audio_recv_codecs_, audio_send_codecs_, - recv, field_trials)) { + for (const Codec& recv : audio_recv_codecs_) { + if (!FindMatchingCodec(audio_recv_codecs_, audio_send_codecs_, recv, + field_trials)) { all_audio_codecs_.push_back(recv); } } diff --git a/pc/media_session.h b/pc/media_session.h index 6766507aa3..6a445d6f96 100644 --- a/pc/media_session.h +++ b/pc/media_session.h @@ -140,16 +140,11 @@ struct MediaSessionOptions { // of the various fields to determine the proper result. class MediaSessionDescriptionFactory { public: - // Simple constructor that does not set any configuration for the factory. - // When using this constructor, the methods below can be used to set the - // configuration. + // This constructor automatically sets up the factory to get its configuration + // from the specified MediaEngine (when provided). // The TransportDescriptionFactory and the UniqueRandomIdGenerator are not // owned by MediaSessionDescriptionFactory, so they must be kept alive by the // user of this class. - MediaSessionDescriptionFactory(const TransportDescriptionFactory* factory, - rtc::UniqueRandomIdGenerator* ssrc_generator); - // This helper automatically sets up the factory to get its configuration - // from the specified MediaEngine MediaSessionDescriptionFactory(cricket::MediaEngineInterface* media_engine, bool rtx_enabled, rtc::UniqueRandomIdGenerator* ssrc_generator, @@ -178,10 +173,10 @@ class MediaSessionDescriptionFactory { is_unified_plan_ = is_unified_plan; } - std::unique_ptr CreateOffer( + webrtc::RTCErrorOr> CreateOfferOrError( const MediaSessionOptions& options, const SessionDescription* current_description) const; - std::unique_ptr CreateAnswer( + webrtc::RTCErrorOr> CreateAnswerOrError( const SessionDescription* offer, const MediaSessionOptions& options, const SessionDescription* current_description) const; @@ -216,11 +211,12 @@ class MediaSessionDescriptionFactory { bool extmap_allow_mixed, const std::vector& media_description_options) const; - bool AddTransportOffer(const std::string& content_name, - const TransportOptions& transport_options, - const SessionDescription* current_desc, - SessionDescription* offer, - IceCredentialsIterator* ice_credentials) const; + webrtc::RTCError AddTransportOffer( + const std::string& content_name, + const TransportOptions& transport_options, + const SessionDescription* current_desc, + SessionDescription* offer, + IceCredentialsIterator* ice_credentials) const; std::unique_ptr CreateTransportAnswer( const std::string& content_name, @@ -230,15 +226,16 @@ class MediaSessionDescriptionFactory { bool require_transport_attributes, IceCredentialsIterator* ice_credentials) const; - bool AddTransportAnswer(const std::string& content_name, - const TransportDescription& transport_desc, - SessionDescription* answer_desc) const; + webrtc::RTCError AddTransportAnswer( + const std::string& content_name, + const TransportDescription& transport_desc, + SessionDescription* answer_desc) const; // Helpers for adding media contents to the SessionDescription. Returns true // it succeeds or the media content is not needed, or false if there is any // error. - bool AddAudioContentForOffer( + webrtc::RTCError AddAudioContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -249,7 +246,7 @@ class MediaSessionDescriptionFactory { SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; - bool AddVideoContentForOffer( + webrtc::RTCError AddVideoContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -260,7 +257,7 @@ class MediaSessionDescriptionFactory { SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; - bool AddDataContentForOffer( + webrtc::RTCError AddDataContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -269,7 +266,7 @@ class MediaSessionDescriptionFactory { SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; - bool AddUnsupportedContentForOffer( + webrtc::RTCError AddUnsupportedContentForOffer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* current_content, @@ -277,7 +274,7 @@ class MediaSessionDescriptionFactory { SessionDescription* desc, IceCredentialsIterator* ice_credentials) const; - bool AddAudioContentForAnswer( + webrtc::RTCError AddAudioContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -291,7 +288,7 @@ class MediaSessionDescriptionFactory { SessionDescription* answer, IceCredentialsIterator* ice_credentials) const; - bool AddVideoContentForAnswer( + webrtc::RTCError AddVideoContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -305,7 +302,7 @@ class MediaSessionDescriptionFactory { SessionDescription* answer, IceCredentialsIterator* ice_credentials) const; - bool AddDataContentForAnswer( + webrtc::RTCError AddDataContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -317,7 +314,7 @@ class MediaSessionDescriptionFactory { SessionDescription* answer, IceCredentialsIterator* ice_credentials) const; - bool AddUnsupportedContentForAnswer( + webrtc::RTCError AddUnsupportedContentForAnswer( const MediaDescriptionOptions& media_description_options, const MediaSessionOptions& session_options, const ContentInfo* offer_content, @@ -399,26 +396,6 @@ VideoContentDescription* GetFirstVideoContentDescription( SctpDataContentDescription* GetFirstSctpDataContentDescription( SessionDescription* sdesc); -// Helper functions to return crypto suites used for SDES. -void GetSupportedAudioSdesCryptoSuites( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suites); -void GetSupportedVideoSdesCryptoSuites( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suites); -void GetSupportedDataSdesCryptoSuites( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suites); -void GetSupportedAudioSdesCryptoSuiteNames( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suite_names); -void GetSupportedVideoSdesCryptoSuiteNames( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suite_names); -void GetSupportedDataSdesCryptoSuiteNames( - const webrtc::CryptoOptions& crypto_options, - std::vector* crypto_suite_names); - } // namespace cricket #endif // PC_MEDIA_SESSION_H_ diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc index a4979b86fe..a1770c18c5 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -26,6 +26,7 @@ #include "absl/types/optional.h" #include "api/candidate.h" #include "api/crypto_params.h" +#include "api/rtp_parameters.h" #include "media/base/codec.h" #include "media/base/media_constants.h" #include "media/base/test_utils.h" @@ -35,6 +36,7 @@ #include "p2p/base/transport_info.h" #include "pc/media_protocol_names.h" #include "pc/rtp_media_utils.h" +#include "pc/rtp_parameters_conversion.h" #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" #include "rtc_base/fake_ssl_identity.h" @@ -111,8 +113,16 @@ using ::testing::SizeIs; using webrtc::RtpExtension; using webrtc::RtpTransceiverDirection; +static AudioCodec createRedAudioCodec(absl::string_view encoding_id) { + AudioCodec red = cricket::CreateAudioCodec(63, "red", 48000, 2); + red.SetParam(cricket::kCodecParamNotInNameValueFormat, + std::string(encoding_id) + '/' + std::string(encoding_id)); + return red; +} + static const AudioCodec kAudioCodecs1[] = { - cricket::CreateAudioCodec(103, "ISAC", 16000, 1), + cricket::CreateAudioCodec(111, "opus", 48000, 2), + createRedAudioCodec("111"), cricket::CreateAudioCodec(102, "iLBC", 8000, 1), cricket::CreateAudioCodec(0, "PCMU", 8000, 1), cricket::CreateAudioCodec(8, "PCMA", 8000, 1), @@ -284,6 +294,7 @@ static const char* kMediaProtocolsDtls[] = { // default changes. static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80; static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm; +static const uint8_t kDefaultCryptoSuiteSize = 3U; // These constants are used to make the code using "AddMediaDescriptionOptions" // more readable. @@ -307,8 +318,8 @@ static void AddRtxCodec(const VideoCodec& rtx_codec, codecs->push_back(rtx_codec); } -template -static std::vector GetCodecNames(const std::vector& codecs) { +static std::vector GetCodecNames( + const std::vector& codecs) { std::vector codec_names; codec_names.reserve(codecs.size()); for (const auto& codec : codecs) { @@ -438,8 +449,8 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { MediaSessionDescriptionFactoryTest() : tdf1_(field_trials), tdf2_(field_trials), - f1_(&tdf1_, &ssrc_generator1), - f2_(&tdf2_, &ssrc_generator2) { + f1_(nullptr, false, &ssrc_generator1, &tdf1_), + f2_(nullptr, false, &ssrc_generator2, &tdf2_) { f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1), MAKE_VECTOR(kAudioCodecs1)); f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1), @@ -523,16 +534,16 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { "data", TransportDescription(current_data_ufrag, current_data_pwd))); } if (offer) { - desc = f1_.CreateOffer(options, current_desc.get()); + desc = f1_.CreateOfferOrError(options, current_desc.get()).MoveValue(); } else { std::unique_ptr offer; - offer = f1_.CreateOffer(options, NULL); - desc = f1_.CreateAnswer(offer.get(), options, current_desc.get()); + offer = f1_.CreateOfferOrError(options, nullptr).MoveValue(); + desc = f1_.CreateAnswerOrError(offer.get(), options, current_desc.get()) + .MoveValue(); } - ASSERT_TRUE(desc.get() != NULL); + ASSERT_TRUE(desc); const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio"); if (options.has_audio()) { - EXPECT_TRUE(ti_audio != NULL); if (has_current_desc) { EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag); EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd); @@ -547,12 +558,9 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { EXPECT_EQ( media_desc_options_it->transport_options.enable_ice_renomination, GetIceRenomination(ti_audio)); - } else { - EXPECT_TRUE(ti_audio == NULL); } const TransportInfo* ti_video = desc->GetTransportInfoByName("video"); if (options.has_video()) { - EXPECT_TRUE(ti_video != NULL); auto media_desc_options_it = FindFirstMediaDescriptionByMid("video", options); if (options.bundle_enabled) { @@ -573,12 +581,9 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { EXPECT_EQ( media_desc_options_it->transport_options.enable_ice_renomination, GetIceRenomination(ti_video)); - } else { - EXPECT_TRUE(ti_video == NULL); } const TransportInfo* ti_data = desc->GetTransportInfoByName("data"); if (options.has_data()) { - EXPECT_TRUE(ti_data != NULL); if (options.bundle_enabled) { EXPECT_EQ(ti_audio->description.ice_ufrag, ti_data->description.ice_ufrag); @@ -599,9 +604,6 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { EXPECT_EQ( media_desc_options_it->transport_options.enable_ice_renomination, GetIceRenomination(ti_data)); - - } else { - EXPECT_TRUE(ti_data == NULL); } } @@ -613,13 +615,14 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { std::unique_ptr desc; if (offer) { options.bundle_enabled = false; - ref_desc = f1_.CreateOffer(options, NULL); + ref_desc = f1_.CreateOfferOrError(options, nullptr).MoveValue(); options.bundle_enabled = true; - desc = f1_.CreateOffer(options, ref_desc.get()); + desc = f1_.CreateOfferOrError(options, ref_desc.get()).MoveValue(); } else { options.bundle_enabled = true; - ref_desc = f1_.CreateOffer(options, NULL); - desc = f1_.CreateAnswer(ref_desc.get(), options, NULL); + ref_desc = f1_.CreateOfferOrError(options, nullptr).MoveValue(); + desc = + f1_.CreateAnswerOrError(ref_desc.get(), options, nullptr).MoveValue(); } ASSERT_TRUE(desc); const cricket::MediaContentDescription* audio_media_desc = @@ -630,9 +633,8 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { ASSERT_TRUE(video_media_desc); EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(), video_media_desc->cryptos())); - EXPECT_EQ(1u, audio_media_desc->cryptos().size()); - EXPECT_EQ(kDefaultSrtpCryptoSuite, - audio_media_desc->cryptos()[0].crypto_suite); + ASSERT_CRYPTO(audio_media_desc, offer ? kDefaultCryptoSuiteSize : 1U, + kDefaultSrtpCryptoSuite); // Verify the selected crypto is one from the reference audio // media content. @@ -659,17 +661,17 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { AddAudioVideoSections(direction_in_offer, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* ac_offer = offer->GetContentByName("audio"); - ASSERT_TRUE(ac_offer != NULL); + ASSERT_TRUE(ac_offer); ContentInfo* vc_offer = offer->GetContentByName("video"); - ASSERT_TRUE(vc_offer != NULL); + ASSERT_TRUE(vc_offer); MediaSessionOptions answer_opts; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, NULL); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); const AudioContentDescription* acd_answer = GetFirstAudioContentDescription(answer.get()); EXPECT_EQ(expected_direction_in_answer, acd_answer->direction()); @@ -681,10 +683,7 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { bool VerifyNoCNCodecs(const cricket::ContentInfo* content) { RTC_DCHECK(content); RTC_CHECK(content->media_description()); - const cricket::AudioContentDescription* audio_desc = - content->media_description()->as_audio(); - RTC_CHECK(audio_desc); - for (const cricket::AudioCodec& codec : audio_desc->codecs()) { + for (const cricket::Codec& codec : content->media_description()->codecs()) { if (codec.name == "CN") { return false; } @@ -704,8 +703,8 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); if (gcm_offer && gcm_answer) { for (cricket::ContentInfo& content : offer->contents()) { auto cryptos = content.media_description()->cryptos(); @@ -714,11 +713,11 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { } } std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, NULL); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, vc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); @@ -752,11 +751,12 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); SetAudioVideoRtpHeaderExtensions(offered, offered, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); SetAudioVideoRtpHeaderExtensions(local, local, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( expectedAnswer, @@ -812,12 +812,13 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test { TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) { f1_.set_secure(SEC_ENABLED); std::unique_ptr offer = - f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(CreatePlanBMediaSessionOptions(), nullptr) + .MoveValue(); + ASSERT_TRUE(offer.get()); const ContentInfo* ac = offer->GetContentByName("audio"); const ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc == NULL); + ASSERT_TRUE(ac); + EXPECT_FALSE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); @@ -825,21 +826,81 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) { EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached. EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto) EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on - ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(acd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol()); } +// Create an offer with just Opus and RED. +TEST_F(MediaSessionDescriptionFactoryTest, + TestCreateAudioOfferWithJustOpusAndRed) { + f1_.set_secure(SEC_ENABLED); + // First, prefer to only use opus and red. + std::vector preferences; + preferences.push_back( + webrtc::ToRtpCodecCapability(f1_.audio_sendrecv_codecs()[0])); + preferences.push_back( + webrtc::ToRtpCodecCapability(f1_.audio_sendrecv_codecs()[1])); + EXPECT_EQ("opus", preferences[0].name); + EXPECT_EQ("red", preferences[1].name); + + auto opts = CreatePlanBMediaSessionOptions(); + opts.media_description_options.at(0).codec_preferences = preferences; + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); + const ContentInfo* ac = offer->GetContentByName("audio"); + const ContentInfo* vc = offer->GetContentByName("video"); + ASSERT_TRUE(ac != NULL); + ASSERT_TRUE(vc == NULL); + EXPECT_EQ(MediaProtocolType::kRtp, ac->type); + const AudioContentDescription* acd = ac->media_description()->as_audio(); + EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); + EXPECT_EQ(2U, acd->codecs().size()); + EXPECT_EQ("opus", acd->codecs()[0].name); + EXPECT_EQ("red", acd->codecs()[1].name); +} + +// Create an offer with RED before Opus, which enables RED with Opus encoding. +TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOfferWithRedForOpus) { + f1_.set_secure(SEC_ENABLED); + // First, prefer to only use opus and red. + std::vector preferences; + preferences.push_back( + webrtc::ToRtpCodecCapability(f1_.audio_sendrecv_codecs()[1])); + preferences.push_back( + webrtc::ToRtpCodecCapability(f1_.audio_sendrecv_codecs()[0])); + EXPECT_EQ("red", preferences[0].name); + EXPECT_EQ("opus", preferences[1].name); + + auto opts = CreatePlanBMediaSessionOptions(); + opts.media_description_options.at(0).codec_preferences = preferences; + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); + const ContentInfo* ac = offer->GetContentByName("audio"); + const ContentInfo* vc = offer->GetContentByName("video"); + ASSERT_TRUE(ac != NULL); + ASSERT_TRUE(vc == NULL); + EXPECT_EQ(MediaProtocolType::kRtp, ac->type); + const AudioContentDescription* acd = ac->media_description()->as_audio(); + EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); + EXPECT_EQ(2U, acd->codecs().size()); + EXPECT_EQ("red", acd->codecs()[0].name); + EXPECT_EQ("opus", acd->codecs()[1].name); +} + // Create a typical video offer, and ensure it matches what we expect. TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); f1_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); const ContentInfo* ac = offer->GetContentByName("audio"); const ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, vc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); @@ -849,14 +910,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) { EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto) EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on - ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(acd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol()); EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type()); EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs()); EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto) EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on - ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(vcd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol()); } @@ -871,13 +932,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); opts.bundle_enabled = true; - std::unique_ptr offer = f2_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f2_.CreateOfferOrError(opts, nullptr).MoveValue(); const VideoContentDescription* vcd = GetFirstVideoContentDescription(offer.get()); const AudioContentDescription* acd = GetFirstAudioContentDescription(offer.get()); - ASSERT_TRUE(NULL != vcd); - ASSERT_TRUE(NULL != acd); + ASSERT_TRUE(vcd); + ASSERT_TRUE(acd); EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id); EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name); EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name); @@ -897,22 +959,23 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kInactive, kStopped, &opts); opts.bundle_enabled = true; - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); MediaSessionOptions updated_opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts); updated_opts.bundle_enabled = true; std::unique_ptr updated_offer( - f1_.CreateOffer(updated_opts, answer.get())); + f1_.CreateOfferOrError(updated_opts, answer.get()).MoveValue()); const AudioContentDescription* acd = GetFirstAudioContentDescription(updated_offer.get()); const VideoContentDescription* vcd = GetFirstVideoContentDescription(updated_offer.get()); - EXPECT_TRUE(NULL != vcd); - EXPECT_TRUE(NULL != acd); + EXPECT_TRUE(vcd); + EXPECT_TRUE(acd); ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol()); @@ -926,9 +989,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) { opts.bundle_enabled = true; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); f1_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - EXPECT_TRUE(offer.get() != NULL); - EXPECT_TRUE(offer->GetContentByName("data") != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + EXPECT_TRUE(offer.get()); + EXPECT_TRUE(offer->GetContentByName("data")); auto dcd = GetFirstSctpDataContentDescription(offer.get()); ASSERT_TRUE(dcd); // Since this transport is insecure, the protocol should be "SCTP". @@ -942,9 +1006,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) { AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); f1_.set_secure(SEC_ENABLED); tdf1_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - EXPECT_TRUE(offer.get() != NULL); - EXPECT_TRUE(offer->GetContentByName("data") != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + EXPECT_TRUE(offer.get()); + EXPECT_TRUE(offer->GetContentByName("data")); auto dcd = GetFirstSctpDataContentDescription(offer.get()); ASSERT_TRUE(dcd); // The protocol should now be "UDP/DTLS/SCTP" @@ -957,16 +1022,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) { opts.bundle_enabled = true; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); f1_.set_secure(SEC_ENABLED); - std::unique_ptr offer1(f1_.CreateOffer(opts, NULL)); - ASSERT_TRUE(offer1.get() != NULL); + std::unique_ptr offer1( + f1_.CreateOfferOrError(opts, nullptr).MoveValue()); + ASSERT_TRUE(offer1.get()); const ContentInfo* data = offer1->GetContentByName("data"); - ASSERT_TRUE(data != NULL); + ASSERT_TRUE(data); ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol()); std::unique_ptr offer2( - f1_.CreateOffer(opts, offer1.get())); + f1_.CreateOfferOrError(opts, offer1.get()).MoveValue()); data = offer2->GetContentByName("data"); - ASSERT_TRUE(data != NULL); + ASSERT_TRUE(data); EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol()); } @@ -978,11 +1044,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) { AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); opts.media_description_options[0].stopped = true; std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)); } @@ -996,15 +1063,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) { AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); opts.media_description_options[0].stopped = true; std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); std::unique_ptr reanswer = - f2_.CreateAnswer(reoffer.get(), opts, answer.get()); + f2_.CreateAnswerOrError(reoffer.get(), opts, answer.get()).MoveValue(); EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)); } @@ -1018,7 +1086,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) { AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); // Reject the audio m= section and add a video m= section. opts.media_description_options[0].stopped = true; @@ -1026,7 +1095,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) { RtpTransceiverDirection::kSendRecv, kActive, &opts); std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); const cricket::ContentGroup* bundle_group = reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); @@ -1044,9 +1113,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) { AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Reject the audio m= section and add a video m= section. opts.media_description_options[0].stopped = true; @@ -1054,9 +1124,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) { RtpTransceiverDirection::kSendRecv, kActive, &opts); std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); std::unique_ptr reanswer = - f2_.CreateAnswer(reoffer.get(), opts, answer.get()); + f2_.CreateAnswerOrError(reoffer.get(), opts, answer.get()).MoveValue(); const cricket::ContentGroup* bundle_group = reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); @@ -1082,7 +1152,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer->groups().empty()); // Munge the offer to have two groups. Offers like these cannot be generated @@ -1101,7 +1172,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, // groups. opts.bundle_enabled = true; std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); std::vector answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE); @@ -1116,7 +1187,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE // groups. opts.bundle_enabled = false; - answer = f2_.CreateAnswer(offer.get(), opts, nullptr); + answer = f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE); // Rejected groups are still listed, but they are empty. @@ -1134,14 +1205,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; opts.bundle_enabled = true; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Reject the audio m= section. opts.media_description_options[0].stopped = true; std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); const TransportDescription* offer_tagged = offer->GetTransportDescriptionByName("audio"); @@ -1162,16 +1234,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; opts.bundle_enabled = true; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Reject the audio m= section. opts.media_description_options[0].stopped = true; std::unique_ptr reoffer = - f1_.CreateOffer(opts, offer.get()); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); std::unique_ptr reanswer = - f2_.CreateAnswer(reoffer.get(), opts, answer.get()); + f2_.CreateAnswerOrError(reoffer.get(), opts, answer.get()).MoveValue(); const TransportDescription* answer_tagged = answer->GetTransportDescriptionByName("audio"); @@ -1188,12 +1261,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferWithoutLegacyStreams) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); const ContentInfo* ac = offer->GetContentByName("audio"); const ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); @@ -1210,8 +1284,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) { AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); EXPECT_EQ(2u, offer->contents().size()); EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO)); EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO)); @@ -1228,8 +1303,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) { MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer1(f1_.CreateOffer(opts, NULL)); - ASSERT_TRUE(offer1.get() != NULL); + std::unique_ptr offer1( + f1_.CreateOfferOrError(opts, nullptr).MoveValue()); + ASSERT_TRUE(offer1.get()); EXPECT_EQ(1u, offer1->contents().size()); EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA)); @@ -1237,8 +1313,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) { RtpTransceiverDirection::kRecvOnly, kActive, &opts); std::unique_ptr offer2( - f1_.CreateOffer(opts, offer1.get())); - ASSERT_TRUE(offer2.get() != NULL); + f1_.CreateOfferOrError(opts, offer1.get()).MoveValue()); + ASSERT_TRUE(offer2.get()); EXPECT_EQ(2u, offer2->contents().size()); EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA)); EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO)); @@ -1247,8 +1323,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) { RtpTransceiverDirection::kRecvOnly, kActive, &opts); std::unique_ptr offer3( - f1_.CreateOffer(opts, offer2.get())); - ASSERT_TRUE(offer3.get() != NULL); + f1_.CreateOfferOrError(opts, offer2.get()).MoveValue()); + ASSERT_TRUE(offer3.get()); EXPECT_EQ(3u, offer3->contents().size()); EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA)); EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO)); @@ -1260,14 +1336,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) { f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); std::unique_ptr offer = - f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(CreatePlanBMediaSessionOptions(), nullptr) + .MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL); + f2_.CreateAnswerOrError(offer.get(), CreatePlanBMediaSessionOptions(), + nullptr) + .MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc == NULL); + ASSERT_TRUE(ac); + EXPECT_FALSE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); @@ -1285,20 +1364,20 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) { f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); MediaSessionOptions opts = CreatePlanBMediaSessionOptions(); - opts.crypto_options.srtp.enable_gcm_crypto_suites = true; - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); for (cricket::ContentInfo& content : offer->contents()) { auto cryptos = content.media_description()->cryptos(); PreferGcmCryptoParameters(&cryptos); content.media_description()->set_cryptos(cryptos); } std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc == NULL); + ASSERT_TRUE(ac); + EXPECT_FALSE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); @@ -1323,11 +1402,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, std::vector f2_codecs = {cricket::CreateAudioCodec(0, "PCMU", 8000, 1)}; f2_.set_audio_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); - ASSERT_TRUE(ac != NULL); + ASSERT_TRUE(ac); EXPECT_TRUE(ac->rejected); } @@ -1337,14 +1417,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) { AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); EXPECT_EQ(MediaProtocolType::kRtp, vc->type); const AudioContentDescription* acd = ac->media_description()->as_audio(); @@ -1394,11 +1475,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, std::vector f2_codecs = {cricket::CreateVideoCodec(97, "VP8")}; f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(vc); EXPECT_TRUE(vc->rejected); } @@ -1418,11 +1500,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, cricket::CreateVideoCodec(118, "flexfec-03")}; f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(vc); EXPECT_TRUE(vc->rejected); } @@ -1431,18 +1514,19 @@ TEST_F(MediaSessionDescriptionFactoryTest, TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) { MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* dc_offer = offer->GetContentByName("data"); - ASSERT_TRUE(dc_offer != NULL); + ASSERT_TRUE(dc_offer); SctpDataContentDescription* dcd_offer = dc_offer->media_description()->as_sctp(); EXPECT_TRUE(dcd_offer->use_sctpmap()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* dc_answer = answer->GetContentByName("data"); - ASSERT_TRUE(dc_answer != NULL); + ASSERT_TRUE(dc_answer); const SctpDataContentDescription* dcd_answer = dc_answer->media_description()->as_sctp(); EXPECT_TRUE(dcd_answer->use_sctpmap()); @@ -1452,18 +1536,19 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) { TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) { MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* dc_offer = offer->GetContentByName("data"); - ASSERT_TRUE(dc_offer != NULL); + ASSERT_TRUE(dc_offer); SctpDataContentDescription* dcd_offer = dc_offer->media_description()->as_sctp(); dcd_offer->set_use_sctpmap(false); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* dc_answer = answer->GetContentByName("data"); - ASSERT_TRUE(dc_answer != NULL); + ASSERT_TRUE(dc_answer); const SctpDataContentDescription* dcd_answer = dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dcd_answer->use_sctpmap()); @@ -1482,10 +1567,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* dc_offer = offer->GetContentByName("data"); - ASSERT_TRUE(dc_offer != nullptr); + ASSERT_TRUE(dc_offer); SctpDataContentDescription* dcd_offer = dc_offer->media_description()->as_sctp(); ASSERT_TRUE(dcd_offer); @@ -1495,9 +1581,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, for (const std::string& proto : protos) { dcd_offer->set_protocol(proto); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* dc_answer = answer->GetContentByName("data"); - ASSERT_TRUE(dc_answer != nullptr); + ASSERT_TRUE(dc_answer); const SctpDataContentDescription* dcd_answer = dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dc_answer->rejected); @@ -1516,18 +1602,19 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* dc_offer = offer->GetContentByName("data"); - ASSERT_TRUE(dc_offer != nullptr); + ASSERT_TRUE(dc_offer); SctpDataContentDescription* dcd_offer = dc_offer->media_description()->as_sctp(); ASSERT_TRUE(dcd_offer); dcd_offer->set_max_message_size(1234); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* dc_answer = answer->GetContentByName("data"); - ASSERT_TRUE(dc_answer != nullptr); + ASSERT_TRUE(dc_answer); const SctpDataContentDescription* dcd_answer = dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dc_answer->rejected); @@ -1545,18 +1632,19 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* dc_offer = offer->GetContentByName("data"); - ASSERT_TRUE(dc_offer != nullptr); + ASSERT_TRUE(dc_offer); SctpDataContentDescription* dcd_offer = dc_offer->media_description()->as_sctp(); ASSERT_TRUE(dcd_offer); dcd_offer->set_max_message_size(0); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* dc_answer = answer->GetContentByName("data"); - ASSERT_TRUE(dc_answer != nullptr); + ASSERT_TRUE(dc_answer); const SctpDataContentDescription* dcd_answer = dc_answer->media_description()->as_sctp(); EXPECT_FALSE(dc_answer->rejected); @@ -1570,28 +1658,29 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) { // Creates a data only offer. AddDataSection(RtpTransceiverDirection::kSendRecv, &opts); - std::unique_ptr offer1(f1_.CreateOffer(opts, NULL)); - ASSERT_TRUE(offer1.get() != NULL); + std::unique_ptr offer1( + f1_.CreateOfferOrError(opts, nullptr).MoveValue()); + ASSERT_TRUE(offer1.get()); // Appends audio to the offer. AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly, kActive, &opts); std::unique_ptr offer2( - f1_.CreateOffer(opts, offer1.get())); - ASSERT_TRUE(offer2.get() != NULL); + f1_.CreateOfferOrError(opts, offer1.get()).MoveValue()); + ASSERT_TRUE(offer2.get()); // Appends video to the offer. AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly, kActive, &opts); std::unique_ptr offer3( - f1_.CreateOffer(opts, offer2.get())); - ASSERT_TRUE(offer3.get() != NULL); + f1_.CreateOfferOrError(opts, offer2.get()).MoveValue()); + ASSERT_TRUE(offer3.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer3.get(), opts, NULL); - ASSERT_TRUE(answer.get() != NULL); + f2_.CreateAnswerOrError(offer3.get(), opts, nullptr).MoveValue(); + ASSERT_TRUE(answer.get()); EXPECT_EQ(3u, answer->contents().size()); EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA)); EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO)); @@ -1637,22 +1726,23 @@ TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) { tdf1_.set_secure(SEC_DISABLED); tdf2_.set_secure(SEC_DISABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); const AudioContentDescription* offer_acd = GetFirstAudioContentDescription(offer.get()); - ASSERT_TRUE(offer_acd != NULL); + ASSERT_TRUE(offer_acd); EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac_answer = answer->GetContentByName("audio"); - ASSERT_TRUE(ac_answer != NULL); + ASSERT_TRUE(ac_answer); EXPECT_FALSE(ac_answer->rejected); const AudioContentDescription* answer_acd = GetFirstAudioContentDescription(answer.get()); - ASSERT_TRUE(answer_acd != NULL); + ASSERT_TRUE(answer_acd); EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol()); } @@ -1664,12 +1754,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) { SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1), MAKE_VECTOR(kVideoRtpExtension1), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2), MAKE_VECTOR(kVideoRtpExtension2), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtension1), @@ -1719,12 +1810,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions( MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions( MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(), ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00)); @@ -1741,9 +1833,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions( MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(), ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00)); @@ -1759,11 +1852,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7); SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5); SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(), ElementsAre(offer_dd)); @@ -1777,10 +1871,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7); RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5); SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(), ElementsAre(offer_dd)); @@ -1797,10 +1892,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)}; SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(), ElementsAreArray(offered_extensions)); @@ -1820,10 +1916,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)}; SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(), ElementsAreArray(offered_extensions)); @@ -1843,10 +1940,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)}; SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(), IsEmpty()); @@ -1874,7 +1972,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kStopped), webrtc::RtpHeaderExtensionCapability("uri3", 7, RtpTransceiverDirection::kSendOnly)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); EXPECT_THAT( offer->contents(), ElementsAre( @@ -1907,7 +2005,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv), webrtc::RtpHeaderExtensionCapability("uri3", 7, RtpTransceiverDirection::kSendOnly)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); EXPECT_THAT( offer->contents(), ElementsAre( @@ -1942,7 +2040,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv), webrtc::RtpHeaderExtensionCapability("uri3", 7, RtpTransceiverDirection::kStopped)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); EXPECT_THAT( offer->contents(), ElementsAre( @@ -1972,7 +2070,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) { RtpTransceiverDirection::kRecvOnly), webrtc::RtpHeaderExtensionCapability("uri4", 1, RtpTransceiverDirection::kSendRecv)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); opts.media_description_options.back().header_extensions = { webrtc::RtpHeaderExtensionCapability("uri1", 4, RtpTransceiverDirection::kSendOnly), @@ -1982,7 +2080,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) { RtpTransceiverDirection::kStopped), webrtc::RtpHeaderExtensionCapability("uri4", 1, RtpTransceiverDirection::kSendRecv)}; - auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr); + auto answer = f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( answer->contents(), ElementsAre(Property( @@ -2001,7 +2099,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, opts.media_description_options.back().header_extensions = { webrtc::RtpHeaderExtensionCapability("uri1", 1, RtpTransceiverDirection::kSendRecv)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); opts.media_description_options.back().header_extensions = { webrtc::RtpHeaderExtensionCapability("uri1", 2, RtpTransceiverDirection::kSendRecv), @@ -2011,7 +2109,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kStopped), webrtc::RtpHeaderExtensionCapability("uri4", 6, RtpTransceiverDirection::kSendRecv)}; - auto offer2 = f1_.CreateOffer(opts, offer.get()); + auto offer2 = f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); EXPECT_THAT( offer2->contents(), ElementsAre(Property( @@ -2033,7 +2131,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv), webrtc::RtpHeaderExtensionCapability("uri2", 2, RtpTransceiverDirection::kSendRecv)}; - auto offer = f1_.CreateOffer(opts, nullptr); + auto offer = f1_.CreateOfferOrError(opts, nullptr).MoveValue(); // Check that a subsequent offer after setting "uri2" to stopped no longer // contains the extension. @@ -2042,7 +2140,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv), webrtc::RtpHeaderExtensionCapability("uri2", 2, RtpTransceiverDirection::kStopped)}; - auto offer2 = f1_.CreateOffer(opts, offer.get()); + auto offer2 = f1_.CreateOfferOrError(opts, offer.get()).MoveValue(); EXPECT_THAT( offer2->contents(), ElementsAre(Property( @@ -2061,12 +2159,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1), MAKE_VECTOR(kVideoRtpExtension1), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2), MAKE_VECTOR(kVideoRtpExtension2), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtensionEncrypted1), @@ -2091,12 +2190,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1), MAKE_VECTOR(kVideoRtpExtension1), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2), MAKE_VECTOR(kVideoRtpExtension2), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtensionEncrypted1), @@ -2121,12 +2221,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1), MAKE_VECTOR(kVideoRtpExtension1), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2), MAKE_VECTOR(kVideoRtpExtension2), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtension1), @@ -2147,14 +2248,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerWithoutLegacyStreams) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); @@ -2175,12 +2277,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { offer_opts.rtcp_mux_enabled = true; answer_opts.rtcp_mux_enabled = true; - offer = f1_.CreateOffer(offer_opts, NULL); - answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); + offer = f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + answer = + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); + ASSERT_TRUE(GetFirstAudioContentDescription(offer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(offer.get())); + ASSERT_TRUE(GetFirstAudioContentDescription(answer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(answer.get())); EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); @@ -2188,12 +2291,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { offer_opts.rtcp_mux_enabled = true; answer_opts.rtcp_mux_enabled = false; - offer = f1_.CreateOffer(offer_opts, NULL); - answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); + offer = f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + answer = + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); + ASSERT_TRUE(GetFirstAudioContentDescription(offer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(offer.get())); + ASSERT_TRUE(GetFirstAudioContentDescription(answer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(answer.get())); EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); @@ -2201,12 +2305,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { offer_opts.rtcp_mux_enabled = false; answer_opts.rtcp_mux_enabled = true; - offer = f1_.CreateOffer(offer_opts, NULL); - answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); + offer = f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + answer = + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); + ASSERT_TRUE(GetFirstAudioContentDescription(offer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(offer.get())); + ASSERT_TRUE(GetFirstAudioContentDescription(answer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(answer.get())); EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); @@ -2214,12 +2319,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) { offer_opts.rtcp_mux_enabled = false; answer_opts.rtcp_mux_enabled = false; - offer = f1_.CreateOffer(offer_opts, NULL); - answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get())); - ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get())); - ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get())); + offer = f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + answer = + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); + ASSERT_TRUE(GetFirstAudioContentDescription(offer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(offer.get())); + ASSERT_TRUE(GetFirstAudioContentDescription(answer.get())); + ASSERT_TRUE(GetFirstVideoContentDescription(answer.get())); EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux()); EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux()); @@ -2235,17 +2341,18 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) { AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); opts.media_description_options[1].stopped = true; std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); - ASSERT_TRUE(vc->media_description() != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); + ASSERT_TRUE(vc->media_description()); EXPECT_TRUE(vc->rejected); } @@ -2254,20 +2361,21 @@ TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToOfferWithRejectedMedia) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* ac = offer->GetContentByName("audio"); ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); ac->rejected = true; vc->rejected = true; std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ac = answer->GetContentByName("audio"); vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_TRUE(ac->rejected); EXPECT_TRUE(vc->rejected); } @@ -2276,11 +2384,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) { MediaSessionOptions opts; std::unique_ptr offer = - f1_.CreateOffer(opts, /*current_description=*/nullptr); + f1_.CreateOfferOrError(opts, /*current_description=*/nullptr).MoveValue(); offer->set_extmap_allow_mixed(false); std::unique_ptr answer( - f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr)); + f2_.CreateAnswerOrError(offer.get(), opts, + /*current_description=*/nullptr) + .MoveValue()); EXPECT_FALSE(answer->extmap_allow_mixed()); } @@ -2289,11 +2399,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, OfferAndAnswerHaveMixedByteSessionAttribute) { MediaSessionOptions opts; std::unique_ptr offer = - f1_.CreateOffer(opts, /*current_description=*/nullptr); + f1_.CreateOfferOrError(opts, /*current_description=*/nullptr).MoveValue(); offer->set_extmap_allow_mixed(true); std::unique_ptr answer_support( - f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr)); + f2_.CreateAnswerOrError(offer.get(), opts, + /*current_description=*/nullptr) + .MoveValue()); EXPECT_TRUE(answer_support->extmap_allow_mixed()); } @@ -2303,7 +2415,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts); std::unique_ptr offer = - f1_.CreateOffer(opts, /*current_description=*/nullptr); + f1_.CreateOfferOrError(opts, /*current_description=*/nullptr).MoveValue(); offer->set_extmap_allow_mixed(false); MediaContentDescription* audio_offer = offer->GetContentDescriptionByName("audio"); @@ -2315,7 +2427,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, video_offer->extmap_allow_mixed_enum()); std::unique_ptr answer( - f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr)); + f2_.CreateAnswerOrError(offer.get(), opts, + /*current_description=*/nullptr) + .MoveValue()); MediaContentDescription* audio_answer = answer->GetContentDescriptionByName("audio"); @@ -2332,7 +2446,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts); std::unique_ptr offer = - f1_.CreateOffer(opts, /*current_description=*/nullptr); + f1_.CreateOfferOrError(opts, /*current_description=*/nullptr).MoveValue(); offer->set_extmap_allow_mixed(false); MediaContentDescription* audio_offer = offer->GetContentDescriptionByName("audio"); @@ -2342,7 +2456,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia); std::unique_ptr answer( - f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr)); + f2_.CreateAnswerOrError(offer.get(), opts, + /*current_description=*/nullptr) + .MoveValue()); MediaContentDescription* audio_answer = answer->GetContentDescriptionByName("audio"); @@ -2359,7 +2475,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts); std::unique_ptr offer = - f1_.CreateOffer(opts, /*current_description=*/nullptr); + f1_.CreateOfferOrError(opts, /*current_description=*/nullptr).MoveValue(); offer->set_extmap_allow_mixed(false); MediaContentDescription* audio_offer = offer->GetContentDescriptionByName("audio"); @@ -2369,7 +2485,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia); std::unique_ptr answer( - f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr)); + f2_.CreateAnswerOrError(offer.get(), opts, + /*current_description=*/nullptr) + .MoveValue()); MediaContentDescription* audio_answer = answer->GetContentDescriptionByName("audio"); @@ -2397,13 +2515,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { {kMediaStream1}, 1, &opts); f1_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); - ASSERT_TRUE(offer.get() != NULL); + ASSERT_TRUE(offer.get()); const ContentInfo* ac = offer->GetContentByName("audio"); const ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type()); @@ -2421,11 +2540,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto) EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on - ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(acd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type()); EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs()); - ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(vcd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); const StreamParamsVec& video_streams = vcd->streams(); ASSERT_EQ(1U, video_streams.size()); @@ -2442,13 +2561,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3, {kMediaStream1}, 1, &opts); std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); - ASSERT_TRUE(updated_offer.get() != NULL); + ASSERT_TRUE(updated_offer.get()); ac = updated_offer->GetContentByName("audio"); vc = updated_offer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* updated_acd = ac->media_description()->as_audio(); const VideoContentDescription* updated_vcd = @@ -2458,9 +2577,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) { EXPECT_EQ(acd->codecs(), updated_acd->codecs()); EXPECT_EQ(vcd->type(), updated_vcd->type()); EXPECT_EQ(vcd->codecs(), updated_vcd->codecs()); - ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(updated_acd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos())); - ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite); + ASSERT_CRYPTO(updated_vcd, kDefaultCryptoSuiteSize, kDefaultSrtpCryptoSuite); EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos())); const StreamParamsVec& updated_audio_streams = updated_acd->streams(); @@ -2491,11 +2610,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) { const int num_sim_layers = 3; AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, num_sim_layers, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); - ASSERT_TRUE(offer.get() != NULL); + ASSERT_TRUE(offer.get()); const ContentInfo* vc = offer->GetContentByName("video"); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(vc); const VideoContentDescription* vcd = vc->media_description()->as_video(); const StreamParamsVec& video_streams = vcd->streams(); @@ -2503,7 +2623,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) { EXPECT_EQ(kVideoTrack1, video_streams[0].id); const SsrcGroup* sim_ssrc_group = video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics); - ASSERT_TRUE(sim_ssrc_group != NULL); + ASSERT_TRUE(sim_ssrc_group); EXPECT_EQ(static_cast(num_sim_layers), sim_ssrc_group->ssrcs.size()); } @@ -2557,7 +2677,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) { AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, send_rids, simulcast_layers, 0, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); CheckSimulcastInSessionDescription(offer.get(), "video", send_rids, simulcast_layers); @@ -2574,7 +2695,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) { AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, {rid}, SimulcastLayerList(), 0, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_NE(offer.get(), nullptr); const ContentInfo* content = offer->GetContentByName("video"); @@ -2599,7 +2721,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) { AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, nullptr); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); MediaSessionOptions answer_opts; AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", @@ -2619,7 +2741,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) { {kMediaStream1}, rid_descriptions, simulcast_layers, 0, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions, simulcast_layers); @@ -2638,7 +2760,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) { {kMediaStream1}, {rid_offer}, SimulcastLayerList(), 0, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, nullptr); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); MediaSessionOptions answer_opts; AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", @@ -2650,7 +2772,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) { {kMediaStream1}, {rid_answer}, SimulcastLayerList(), 0, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); ASSERT_NE(answer.get(), nullptr); const ContentInfo* content = offer->GetContentByName("video"); @@ -2681,7 +2803,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) { &offer_opts); f1_.set_secure(SEC_ENABLED); f2_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(offer_opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); MediaSessionOptions answer_opts; AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", @@ -2698,13 +2821,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) { {kMediaStream1}, 1, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, NULL); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); - ASSERT_TRUE(answer.get() != NULL); + ASSERT_TRUE(answer.get()); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* acd = ac->media_description()->as_audio(); const VideoContentDescription* vcd = vc->media_description()->as_video(); ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite); @@ -2742,13 +2865,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) { {kMediaStream2}, 1, &answer_opts); DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts); std::unique_ptr updated_answer( - f2_.CreateAnswer(offer.get(), answer_opts, answer.get())); + f2_.CreateAnswerOrError(offer.get(), answer_opts, answer.get()) + .MoveValue()); - ASSERT_TRUE(updated_answer.get() != NULL); + ASSERT_TRUE(updated_answer.get()); ac = updated_answer->GetContentByName("audio"); vc = updated_answer->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); const AudioContentDescription* updated_acd = ac->media_description()->as_audio(); const VideoContentDescription* updated_vcd = @@ -2784,9 +2908,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const AudioContentDescription* acd = GetFirstAudioContentDescription(answer.get()); @@ -2797,7 +2922,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer)); std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); // The expected audio codecs are the common audio codecs from the first // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in @@ -2838,14 +2963,15 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Recycle the media section by changing its mid. opts.media_description_options[0].mid = "a1"; std::unique_ptr reoffer = - f2_.CreateOffer(opts, answer.get()); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue(); // Expect that the results of the first negotiation are ignored. If the m= // section was not recycled the payload types would match the initial offerer. @@ -2865,13 +2991,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + auto answer = f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Recycle the media section by changing its mid. opts.media_description_options[0].mid = "v1"; std::unique_ptr reoffer = - f2_.CreateOffer(opts, answer.get()); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue(); // Expect that the results of the first negotiation are ignored. If the m= // section was not recycled the payload types would match the initial offerer. @@ -2893,16 +3020,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f2_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f2_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f1_.CreateAnswer(offer.get(), opts, nullptr); + f1_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Recycle the media section by changing its mid. opts.media_description_options[0].mid = "a1"; std::unique_ptr reoffer = - f1_.CreateOffer(opts, answer.get()); + f1_.CreateOfferOrError(opts, answer.get()).MoveValue(); std::unique_ptr reanswer = - f2_.CreateAnswer(reoffer.get(), opts, offer.get()); + f2_.CreateAnswerOrError(reoffer.get(), opts, offer.get()).MoveValue(); // Expect that the results of the first negotiation are ignored. If the m= // section was not recycled the payload types would match the initial offerer. @@ -2924,16 +3052,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f2_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f2_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f1_.CreateAnswer(offer.get(), opts, nullptr); + f1_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Recycle the media section by changing its mid. opts.media_description_options[0].mid = "v1"; std::unique_ptr reoffer = - f1_.CreateOffer(opts, answer.get()); + f1_.CreateOfferOrError(opts, answer.get()).MoveValue(); std::unique_ptr reanswer = - f2_.CreateAnswer(reoffer.get(), opts, offer.get()); + f2_.CreateAnswerOrError(reoffer.get(), opts, offer.get()).MoveValue(); // Expect that the results of the first negotiation are ignored. If the m= // section was not recycled the payload types would match the initial offerer. @@ -2963,10 +3092,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const VideoContentDescription* vcd = GetFirstVideoContentDescription(answer.get()); @@ -2981,10 +3111,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, // an updated offer even though the default payload types between `f1_` and // `f2_` are different. std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); ASSERT_TRUE(updated_offer); std::unique_ptr updated_answer( - f1_.CreateAnswer(updated_offer.get(), opts, answer.get())); + f1_.CreateAnswerOrError(updated_offer.get(), opts, answer.get()) + .MoveValue()); const VideoContentDescription* updated_vcd = GetFirstVideoContentDescription(updated_answer.get()); @@ -3027,15 +3158,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, f2_.set_audio_codecs(audio_codecs, audio_codecs); // Offer will be {VP8, RTX for VP8}. Answer will be the same. - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}. // But if the bug is triggered, RTX for VP8 ends up last. std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); const VideoContentDescription* vcd = GetFirstVideoContentDescription(updated_offer.get()); @@ -3064,9 +3196,10 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kRecvOnly, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const AudioContentDescription* acd = GetFirstAudioContentDescription(answer.get()); @@ -3085,10 +3218,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); ASSERT_TRUE(updated_offer); std::unique_ptr updated_answer( - f1_.CreateAnswer(updated_offer.get(), opts, answer.get())); + f1_.CreateAnswerOrError(updated_offer.get(), opts, answer.get()) + .MoveValue()); const AudioContentDescription* updated_acd = GetFirstAudioContentDescription(answer.get()); @@ -3121,10 +3255,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const VideoContentDescription* vcd = GetFirstVideoContentDescription(answer.get()); @@ -3136,7 +3271,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, // updated offer, even though the default payload types are different from // those of `f1_`. std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); ASSERT_TRUE(updated_offer); const VideoContentDescription* updated_vcd = @@ -3167,8 +3302,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) { &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); // kCodecParamAssociatedPayloadType will always be added to the offer when RTX // is selected. Manually remove kCodecParamAssociatedPayloadType so that it // is possible to test that that RTX is dropped when @@ -3186,7 +3322,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) { desc->set_codecs(codecs); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()), @@ -3212,12 +3348,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) { &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); // Associated payload type doesn't match, therefore, RTX codec is removed in // the answer. std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_THAT( GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()), @@ -3251,10 +3388,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, // H264-SVC codec is removed in the answer, therefore, associated RTX codec // for H264-SVC should also be removed. - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const VideoContentDescription* vcd = GetFirstVideoContentDescription(answer.get()); std::vector expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer); @@ -3277,7 +3415,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) { &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); const VideoContentDescription* vcd = GetFirstVideoContentDescription(offer.get()); @@ -3293,7 +3432,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) { f1_.set_video_codecs(f1_codecs, f1_codecs); std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); ASSERT_TRUE(updated_offer); vcd = GetFirstVideoContentDescription(updated_offer.get()); @@ -3321,8 +3460,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) { // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there // is a FID ssrc + grouping for each. - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); MediaContentDescription* media_desc = offer->GetContentDescriptionByName(cricket::CN_VIDEO); ASSERT_TRUE(media_desc); @@ -3365,8 +3505,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) { // Ensure that the offer has a single FlexFEC ssrc and that // there is no FEC-FR ssrc + grouping for each. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); MediaContentDescription* media_desc = offer->GetContentDescriptionByName(cricket::CN_VIDEO); ASSERT_TRUE(media_desc); @@ -3408,8 +3549,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) { // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that // there is no FEC-FR ssrc + grouping for each. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); MediaContentDescription* media_desc = offer->GetContentDescriptionByName(cricket::CN_VIDEO); ASSERT_TRUE(media_desc); @@ -3442,11 +3584,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1), MAKE_VECTOR(kVideoRtpExtension1), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2), MAKE_VECTOR(kVideoRtpExtension2), &opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, NULL); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtensionAnswer), @@ -3456,7 +3599,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, GetFirstVideoContentDescription(answer.get())->rtp_header_extensions()); std::unique_ptr updated_offer( - f2_.CreateOffer(opts, answer.get())); + f2_.CreateOfferOrError(opts, answer.get()).MoveValue()); // The expected RTP header extensions in the new offer are the resulting // extensions from the first offer/answer exchange plus the extensions only @@ -3497,7 +3640,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) { SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3), MAKE_VECTOR(kVideoRtpExtension3), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); // Since the audio extensions used ID 3 for "both_audio_and_video", so should // the video extensions. @@ -3515,7 +3659,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) { // Nothing should change when creating a new offer std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3), GetFirstAudioContentDescription(updated_offer.get()) @@ -3536,7 +3680,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) { SetAudioVideoRtpHeaderExtensions( MAKE_VECTOR(kAudioRtpExtension3ForEncryption), MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); EXPECT_EQ( MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer), @@ -3547,7 +3692,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) { // Nothing should change when creating a new offer std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer), GetFirstAudioContentDescription(updated_offer.get()) @@ -3573,12 +3718,12 @@ TEST(MediaSessionDescription, CopySessionDescription) { source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone()); std::unique_ptr copy = source.Clone(); - ASSERT_TRUE(copy.get() != NULL); + ASSERT_TRUE(copy.get()); EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO)); const ContentInfo* ac = copy->GetContentByName("audio"); const ContentInfo* vc = copy->GetContentByName("video"); - ASSERT_TRUE(ac != NULL); - ASSERT_TRUE(vc != NULL); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_EQ(MediaProtocolType::kRtp, ac->type); const AudioContentDescription* acd_copy = ac->media_description()->as_audio(); EXPECT_EQ(acd->codecs(), acd_copy->codecs()); @@ -3725,19 +3870,22 @@ TEST_F(MediaSessionDescriptionFactoryTest, tdf2_.set_secure(SEC_DISABLED); std::unique_ptr offer = - f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(CreatePlanBMediaSessionOptions(), nullptr) + .MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* offer_content = offer->GetContentByName("audio"); - ASSERT_TRUE(offer_content != NULL); + ASSERT_TRUE(offer_content); AudioContentDescription* offer_audio_desc = offer_content->media_description()->as_audio(); offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(answer != NULL); + f2_.CreateAnswerOrError(offer.get(), CreatePlanBMediaSessionOptions(), + nullptr) + .MoveValue(); + ASSERT_TRUE(answer); ContentInfo* answer_content = answer->GetContentByName("audio"); - ASSERT_TRUE(answer_content != NULL); + ASSERT_TRUE(answer_content); ASSERT_TRUE(answer_content->rejected); } @@ -3751,20 +3899,23 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) { tdf2_.set_secure(SEC_ENABLED); std::unique_ptr offer = - f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(offer.get() != NULL); + f1_.CreateOfferOrError(CreatePlanBMediaSessionOptions(), nullptr) + .MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* offer_content = offer->GetContentByName("audio"); - ASSERT_TRUE(offer_content != NULL); + ASSERT_TRUE(offer_content); AudioContentDescription* offer_audio_desc = offer_content->media_description()->as_audio(); offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL); - ASSERT_TRUE(answer != NULL); + f2_.CreateAnswerOrError(offer.get(), CreatePlanBMediaSessionOptions(), + nullptr) + .MoveValue(); + ASSERT_TRUE(answer); const ContentInfo* answer_content = answer->GetContentByName("audio"); - ASSERT_TRUE(answer_content != NULL); + ASSERT_TRUE(answer_content); ASSERT_FALSE(answer_content->rejected); const AudioContentDescription* answer_audio_desc = @@ -3788,79 +3939,79 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) { const cricket::TransportDescription* video_trans_desc; // Generate an offer with SDES and DTLS support. - offer = f1_.CreateOffer(options, NULL); - ASSERT_TRUE(offer.get() != NULL); + offer = f1_.CreateOfferOrError(options, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); audio_media_desc = offer->GetContentDescriptionByName("audio"); - ASSERT_TRUE(audio_media_desc != NULL); + ASSERT_TRUE(audio_media_desc); video_media_desc = offer->GetContentDescriptionByName("video"); - ASSERT_TRUE(video_media_desc != NULL); - EXPECT_EQ(1u, audio_media_desc->cryptos().size()); - EXPECT_EQ(1u, video_media_desc->cryptos().size()); + ASSERT_TRUE(video_media_desc); + EXPECT_EQ(kDefaultCryptoSuiteSize, audio_media_desc->cryptos().size()); + EXPECT_EQ(kDefaultCryptoSuiteSize, video_media_desc->cryptos().size()); audio_trans_desc = offer->GetTransportDescriptionByName("audio"); - ASSERT_TRUE(audio_trans_desc != NULL); + ASSERT_TRUE(audio_trans_desc); video_trans_desc = offer->GetTransportDescriptionByName("video"); - ASSERT_TRUE(video_trans_desc != NULL); - ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL); - ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL); + ASSERT_TRUE(video_trans_desc); + ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get()); + ASSERT_TRUE(video_trans_desc->identity_fingerprint.get()); // Generate an answer with only SDES support, since tdf2 has crypto disabled. - answer = f2_.CreateAnswer(offer.get(), options, NULL); - ASSERT_TRUE(answer.get() != NULL); + answer = f2_.CreateAnswerOrError(offer.get(), options, nullptr).MoveValue(); + ASSERT_TRUE(answer.get()); audio_media_desc = answer->GetContentDescriptionByName("audio"); - ASSERT_TRUE(audio_media_desc != NULL); + ASSERT_TRUE(audio_media_desc); video_media_desc = answer->GetContentDescriptionByName("video"); - ASSERT_TRUE(video_media_desc != NULL); + ASSERT_TRUE(video_media_desc); EXPECT_EQ(1u, audio_media_desc->cryptos().size()); EXPECT_EQ(1u, video_media_desc->cryptos().size()); audio_trans_desc = answer->GetTransportDescriptionByName("audio"); - ASSERT_TRUE(audio_trans_desc != NULL); + ASSERT_TRUE(audio_trans_desc); video_trans_desc = answer->GetTransportDescriptionByName("video"); - ASSERT_TRUE(video_trans_desc != NULL); - ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL); - ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL); + ASSERT_TRUE(video_trans_desc); + ASSERT_FALSE(audio_trans_desc->identity_fingerprint.get()); + ASSERT_FALSE(video_trans_desc->identity_fingerprint.get()); // Enable DTLS; the answer should now only have DTLS support. tdf2_.set_secure(SEC_ENABLED); - answer = f2_.CreateAnswer(offer.get(), options, NULL); - ASSERT_TRUE(answer.get() != NULL); + answer = f2_.CreateAnswerOrError(offer.get(), options, nullptr).MoveValue(); + ASSERT_TRUE(answer.get()); audio_media_desc = answer->GetContentDescriptionByName("audio"); - ASSERT_TRUE(audio_media_desc != NULL); + ASSERT_TRUE(audio_media_desc); video_media_desc = answer->GetContentDescriptionByName("video"); - ASSERT_TRUE(video_media_desc != NULL); + ASSERT_TRUE(video_media_desc); EXPECT_TRUE(audio_media_desc->cryptos().empty()); EXPECT_TRUE(video_media_desc->cryptos().empty()); EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol()); EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol()); audio_trans_desc = answer->GetTransportDescriptionByName("audio"); - ASSERT_TRUE(audio_trans_desc != NULL); + ASSERT_TRUE(audio_trans_desc); video_trans_desc = answer->GetTransportDescriptionByName("video"); - ASSERT_TRUE(video_trans_desc != NULL); - ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL); - ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL); + ASSERT_TRUE(video_trans_desc); + ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get()); + ASSERT_TRUE(video_trans_desc->identity_fingerprint.get()); // Try creating offer again. DTLS enabled now, crypto's should be empty // in new offer. - offer = f1_.CreateOffer(options, offer.get()); - ASSERT_TRUE(offer.get() != NULL); + offer = f1_.CreateOfferOrError(options, offer.get()).MoveValue(); + ASSERT_TRUE(offer.get()); audio_media_desc = offer->GetContentDescriptionByName("audio"); - ASSERT_TRUE(audio_media_desc != NULL); + ASSERT_TRUE(audio_media_desc); video_media_desc = offer->GetContentDescriptionByName("video"); - ASSERT_TRUE(video_media_desc != NULL); + ASSERT_TRUE(video_media_desc); EXPECT_TRUE(audio_media_desc->cryptos().empty()); EXPECT_TRUE(video_media_desc->cryptos().empty()); audio_trans_desc = offer->GetTransportDescriptionByName("audio"); - ASSERT_TRUE(audio_trans_desc != NULL); + ASSERT_TRUE(audio_trans_desc); video_trans_desc = offer->GetTransportDescriptionByName("video"); - ASSERT_TRUE(video_trans_desc != NULL); - ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL); - ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL); + ASSERT_TRUE(video_trans_desc); + ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get()); + ASSERT_TRUE(video_trans_desc->identity_fingerprint.get()); } // Test that an answer can't be created if cryptos are required but the offer is @@ -3872,11 +4023,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) { f2_.set_secure(SEC_REQUIRED); tdf1_.set_secure(SEC_ENABLED); - std::unique_ptr offer = f1_.CreateOffer(options, NULL); - ASSERT_TRUE(offer.get() != NULL); - std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), options, NULL); - EXPECT_TRUE(answer.get() == NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(options, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); + + auto error = f2_.CreateAnswerOrError(offer.get(), options, nullptr); + EXPECT_FALSE(error.ok()); } // Test that we accept a DTLS offer without SDES and create an appropriate @@ -3890,8 +4042,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) { AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options); // Generate an offer with DTLS but without SDES. - std::unique_ptr offer = f1_.CreateOffer(options, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(options, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); const AudioContentDescription* audio_offer = GetFirstAudioContentDescription(offer.get()); @@ -3902,22 +4055,22 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) { const cricket::TransportDescription* audio_offer_trans_desc = offer->GetTransportDescriptionByName("audio"); - ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL); + ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get()); const cricket::TransportDescription* video_offer_trans_desc = offer->GetTransportDescriptionByName("video"); - ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL); + ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get()); // Generate an answer with DTLS. std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), options, NULL); - ASSERT_TRUE(answer.get() != NULL); + f2_.CreateAnswerOrError(offer.get(), options, nullptr).MoveValue(); + ASSERT_TRUE(answer.get()); const cricket::TransportDescription* audio_answer_trans_desc = answer->GetTransportDescriptionByName("audio"); - EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL); + EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get()); const cricket::TransportDescription* video_answer_trans_desc = answer->GetTransportDescriptionByName("video"); - EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL); + EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get()); } // Verifies if vad_enabled option is set to false, CN codecs are not present in @@ -3925,19 +4078,20 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) { TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) { MediaSessionOptions options; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options); - std::unique_ptr offer = f1_.CreateOffer(options, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + f1_.CreateOfferOrError(options, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); const ContentInfo* audio_content = offer->GetContentByName("audio"); EXPECT_FALSE(VerifyNoCNCodecs(audio_content)); options.vad_enabled = false; - offer = f1_.CreateOffer(options, NULL); - ASSERT_TRUE(offer.get() != NULL); + offer = f1_.CreateOfferOrError(options, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); audio_content = offer->GetContentByName("audio"); EXPECT_TRUE(VerifyNoCNCodecs(audio_content)); std::unique_ptr answer = - f1_.CreateAnswer(offer.get(), options, NULL); - ASSERT_TRUE(answer.get() != NULL); + f1_.CreateAnswerOrError(offer.get(), options, nullptr).MoveValue(); + ASSERT_TRUE(answer.get()); audio_content = answer->GetContentByName("audio"); EXPECT_TRUE(VerifyNoCNCodecs(audio_content)); } @@ -3955,16 +4109,17 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) { RtpTransceiverDirection::kSendRecv, kActive, &opts); // Create offer. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get()); const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get()); const ContentInfo* data_content = GetFirstDataContent(updated_offer.get()); - ASSERT_TRUE(audio_content != nullptr); - ASSERT_TRUE(video_content != nullptr); - ASSERT_TRUE(data_content != nullptr); + ASSERT_TRUE(audio_content); + ASSERT_TRUE(video_content); + ASSERT_TRUE(data_content); EXPECT_EQ("audio_modified", audio_content->name); EXPECT_EQ("video_modified", video_content->name); EXPECT_EQ("data_modified", data_content->name); @@ -3999,7 +4154,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, &opts); AttachSenderToMediaDescriptionOptions( "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(4u, offer->contents().size()); @@ -4059,10 +4215,11 @@ TEST_F(MediaSessionDescriptionFactoryTest, AttachSenderToMediaDescriptionOptions( "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_EQ(4u, answer->contents().size()); EXPECT_FALSE(answer->contents()[0].rejected); @@ -4105,7 +4262,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kInactive, kStopped, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, nullptr); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); EXPECT_FALSE(offer->contents()[0].rejected); @@ -4125,7 +4282,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kInactive, kStopped, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, nullptr); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); EXPECT_FALSE(offer->contents()[0].rejected); @@ -4140,7 +4297,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); ASSERT_EQ(2u, answer->contents().size()); EXPECT_FALSE(answer->contents()[0].rejected); EXPECT_TRUE(answer->contents()[1].rejected); @@ -4159,7 +4316,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &offer_opts); std::unique_ptr offer = - f1_.CreateOffer(offer_opts, nullptr); + f1_.CreateOfferOrError(offer_opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); ASSERT_FALSE(offer->contents()[0].rejected); @@ -4174,7 +4331,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kInactive, kStopped, &answer_opts); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), answer_opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), answer_opts, nullptr).MoveValue(); ASSERT_EQ(2u, answer->contents().size()); EXPECT_FALSE(answer->contents()[0].rejected); EXPECT_TRUE(answer->contents()[1].rejected); @@ -4197,7 +4354,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); @@ -4217,7 +4375,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &opts); // Create an offer with two video sections using same codecs. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); const VideoContentDescription* vcd1 = @@ -4233,7 +4392,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, // Create answer and negotiate the codecs. std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_TRUE(answer); ASSERT_EQ(2u, answer->contents().size()); vcd1 = answer->contents()[0].media_description()->as_video(); @@ -4261,7 +4420,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsEqual) { &opts); // Create an offer with two video sections using same codecs. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(1u, offer->contents().size()); const VideoContentDescription* vcd1 = @@ -4271,7 +4431,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsEqual) { // Create answer and negotiate the codecs. std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_TRUE(answer); ASSERT_EQ(1u, answer->contents().size()); vcd1 = answer->contents()[0].media_description()->as_video(); @@ -4296,7 +4456,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsDifferent) { &opts); // Create an offer with two video sections using same codecs. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(1u, offer->contents().size()); const VideoContentDescription* vcd1 = @@ -4306,7 +4467,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsDifferent) { // Create answer and negotiate the codecs. std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_TRUE(answer); ASSERT_EQ(1u, answer->contents().size()); vcd1 = answer->contents()[0].media_description()->as_video(); @@ -4326,7 +4487,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &opts); // Create an offer with two video sections using same codecs. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); VideoContentDescription* vcd1 = @@ -4342,7 +4504,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse); vcd1->set_codecs(video_codecs_reverse); std::unique_ptr updated_offer( - f1_.CreateOffer(opts, offer.get())); + f1_.CreateOfferOrError(opts, offer.get()).MoveValue()); vcd1 = updated_offer->contents()[0].media_description()->as_video(); vcd2 = updated_offer->contents()[1].media_description()->as_video(); // The video codec preference order should be respected. @@ -4362,7 +4524,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &opts); // Create an offer with two video sections using same codecs. - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); ASSERT_EQ(2u, offer->contents().size()); VideoContentDescription* vcd1 = @@ -4378,7 +4541,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse); vcd1->set_codecs(video_codecs_reverse); std::unique_ptr answer = - f1_.CreateAnswer(offer.get(), opts, nullptr); + f1_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); vcd1 = answer->contents()[0].media_description()->as_video(); vcd2 = answer->contents()[1].media_description()->as_video(); // The video codec preference order should be respected. @@ -4420,7 +4583,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) { RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); auto offer_acd = offer->contents()[0].media_description()->as_audio(); auto offer_vcd = offer->contents()[1].media_description()->as_video(); @@ -4431,7 +4595,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) { EXPECT_EQ(video_value1, value); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_TRUE(answer); auto answer_acd = answer->contents()[0].media_description()->as_audio(); auto answer_vcd = answer->contents()[1].media_description()->as_video(); @@ -4468,11 +4632,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtpTransceiverDirection::kSendRecv, kActive, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); ASSERT_TRUE(offer); std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); ASSERT_TRUE(answer); // Answer should have one negotiated codec with packetization-mode=1 using the @@ -4489,8 +4654,8 @@ class MediaProtocolTest : public ::testing::TestWithParam { MediaProtocolTest() : tdf1_(field_trials_), tdf2_(field_trials_), - f1_(&tdf1_, &ssrc_generator1), - f2_(&tdf2_, &ssrc_generator2) { + f1_(nullptr, false, &ssrc_generator1, &tdf1_), + f2_(nullptr, false, &ssrc_generator2, &tdf2_) { f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1), MAKE_VECTOR(kAudioCodecs1)); f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1), @@ -4522,18 +4687,19 @@ class MediaProtocolTest : public ::testing::TestWithParam { TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) { MediaSessionOptions opts; AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts); - std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); - ASSERT_TRUE(offer.get() != nullptr); + std::unique_ptr offer = + f1_.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); // Set the protocol for all the contents. for (auto& content : offer.get()->contents()) { content.media_description()->set_protocol(GetParam()); } std::unique_ptr answer = - f2_.CreateAnswer(offer.get(), opts, nullptr); + f2_.CreateAnswerOrError(offer.get(), opts, nullptr).MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); const ContentInfo* vc = answer->GetContentByName("video"); - ASSERT_TRUE(ac != nullptr); - ASSERT_TRUE(vc != nullptr); + ASSERT_TRUE(ac); + ASSERT_TRUE(vc); EXPECT_FALSE(ac->rejected); // the offer is accepted EXPECT_FALSE(vc->rejected); const AudioContentDescription* acd = ac->media_description()->as_audio(); @@ -4553,7 +4719,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) { webrtc::test::ScopedKeyValueConfig field_trials; TransportDescriptionFactory tdf(field_trials); UniqueRandomIdGenerator ssrc_generator; - MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator); + MediaSessionDescriptionFactory sf(nullptr, false, &ssrc_generator, &tdf); std::vector send_codecs = MAKE_VECTOR(kAudioCodecs1); std::vector recv_codecs = MAKE_VECTOR(kAudioCodecs2); @@ -4566,13 +4732,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) { MAKE_VECTOR(kAudioCodecsAnswer); const std::vector no_codecs; - RTC_CHECK_EQ(send_codecs[1].name, "iLBC") + RTC_CHECK_EQ(send_codecs[2].name, "iLBC") << "Please don't change shared test data!"; RTC_CHECK_EQ(recv_codecs[2].name, "iLBC") << "Please don't change shared test data!"; // Alter iLBC send codec to have zero channels, to test that that is handled // properly. - send_codecs[1].channels = 0; + send_codecs[2].channels = 0; // Alter iLBC receive codec to be lowercase, to test that case conversions // are handled properly. @@ -4605,9 +4771,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) { namespace { // Compare the two vectors of codecs ignoring the payload type. -template -bool CodecsMatch(const std::vector& codecs1, - const std::vector& codecs2, +bool CodecsMatch(const std::vector& codecs1, + const std::vector& codecs2, const webrtc::FieldTrialsView* field_trials) { if (codecs1.size() != codecs2.size()) { return false; @@ -4625,7 +4790,7 @@ void TestAudioCodecsOffer(RtpTransceiverDirection direction) { webrtc::test::ScopedKeyValueConfig field_trials; TransportDescriptionFactory tdf(field_trials); UniqueRandomIdGenerator ssrc_generator; - MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator); + MediaSessionDescriptionFactory sf(nullptr, false, &ssrc_generator, &tdf); const std::vector send_codecs = MAKE_VECTOR(kAudioCodecs1); const std::vector recv_codecs = MAKE_VECTOR(kAudioCodecs2); const std::vector sendrecv_codecs = @@ -4642,8 +4807,9 @@ void TestAudioCodecsOffer(RtpTransceiverDirection direction) { "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts); } - std::unique_ptr offer = sf.CreateOffer(opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + std::unique_ptr offer = + sf.CreateOfferOrError(opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); ContentInfo* ac = offer->GetContentByName("audio"); // If the factory didn't add any audio content to the offer, we cannot check @@ -4657,14 +4823,11 @@ void TestAudioCodecsOffer(RtpTransceiverDirection direction) { // might eventually be used anything, but we don't know more at this // moment. if (acd->direction() == RtpTransceiverDirection::kSendOnly) { - EXPECT_TRUE( - CodecsMatch(send_codecs, acd->codecs(), &field_trials)); + EXPECT_TRUE(CodecsMatch(send_codecs, acd->codecs(), &field_trials)); } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) { - EXPECT_TRUE( - CodecsMatch(recv_codecs, acd->codecs(), &field_trials)); + EXPECT_TRUE(CodecsMatch(recv_codecs, acd->codecs(), &field_trials)); } else { - EXPECT_TRUE(CodecsMatch(sendrecv_codecs, acd->codecs(), - &field_trials)); + EXPECT_TRUE(CodecsMatch(sendrecv_codecs, acd->codecs(), &field_trials)); } } } @@ -4727,8 +4890,10 @@ void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction, TransportDescriptionFactory offer_tdf(field_trials); TransportDescriptionFactory answer_tdf(field_trials); UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2; - MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1); - MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2); + MediaSessionDescriptionFactory offer_factory(nullptr, false, &ssrc_generator1, + &offer_tdf); + MediaSessionDescriptionFactory answer_factory(nullptr, false, + &ssrc_generator2, &answer_tdf); offer_factory.set_audio_codecs( VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs), @@ -4748,8 +4913,8 @@ void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction, } std::unique_ptr offer = - offer_factory.CreateOffer(offer_opts, NULL); - ASSERT_TRUE(offer.get() != NULL); + offer_factory.CreateOfferOrError(offer_opts, nullptr).MoveValue(); + ASSERT_TRUE(offer.get()); MediaSessionOptions answer_opts; AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction, @@ -4761,7 +4926,8 @@ void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction, &answer_opts); } std::unique_ptr answer = - answer_factory.CreateAnswer(offer.get(), answer_opts, NULL); + answer_factory.CreateAnswerOrError(offer.get(), answer_opts, nullptr) + .MoveValue(); const ContentInfo* ac = answer->GetContentByName("audio"); // If the factory didn't add any audio content to the answer, we cannot diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index d2860080da..61da2a06eb 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -266,6 +266,86 @@ RTCError ValidateConfiguration( ParseIceConfig(config)); } +// Checks for valid pool size range and if a previous value has already been +// set, which is done via SetLocalDescription. +RTCError ValidateIceCandidatePoolSize( + int ice_candidate_pool_size, + absl::optional previous_ice_candidate_pool_size) { + // Note that this isn't possible through chromium, since it's an unsigned + // short in WebIDL. + if (ice_candidate_pool_size < 0 || + ice_candidate_pool_size > static_cast(UINT16_MAX)) { + return RTCError(RTCErrorType::INVALID_RANGE); + } + + // According to JSEP, after setLocalDescription, changing the candidate pool + // size is not allowed, and changing the set of ICE servers will not result + // in new candidates being gathered. + if (previous_ice_candidate_pool_size.has_value() && + ice_candidate_pool_size != previous_ice_candidate_pool_size.value()) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, + "Can't change candidate pool size after calling " + "SetLocalDescription."); + } + + return RTCError::OK(); +} + +// The simplest (and most future-compatible) way to tell if a config was +// modified in an invalid way is to copy each property we do support modifying, +// then use operator==. There are far more properties we don't support modifying +// than those we do, and more could be added. +// This helper function accepts a proposed new `configuration` object, an +// existing configuration and returns a valid, modified, configuration that's +// based on the existing configuration, with modified properties copied from +// `configuration`. +// If the result of creating a modified configuration doesn't pass the above +// `operator==` test or a call to `ValidateConfiguration()`, then the function +// will return an error. Otherwise, the return value will be the new config. +RTCErrorOr ApplyConfiguration( + const PeerConnectionInterface::RTCConfiguration& configuration, + const PeerConnectionInterface::RTCConfiguration& existing_configuration) { + PeerConnectionInterface::RTCConfiguration modified_config = + existing_configuration; + modified_config.servers = configuration.servers; + modified_config.type = configuration.type; + modified_config.ice_candidate_pool_size = + configuration.ice_candidate_pool_size; + modified_config.prune_turn_ports = configuration.prune_turn_ports; + modified_config.turn_port_prune_policy = configuration.turn_port_prune_policy; + modified_config.surface_ice_candidates_on_ice_transport_type_changed = + configuration.surface_ice_candidates_on_ice_transport_type_changed; + modified_config.ice_check_min_interval = configuration.ice_check_min_interval; + modified_config.ice_check_interval_strong_connectivity = + configuration.ice_check_interval_strong_connectivity; + modified_config.ice_check_interval_weak_connectivity = + configuration.ice_check_interval_weak_connectivity; + modified_config.ice_unwritable_timeout = configuration.ice_unwritable_timeout; + modified_config.ice_unwritable_min_checks = + configuration.ice_unwritable_min_checks; + modified_config.ice_inactive_timeout = configuration.ice_inactive_timeout; + modified_config.stun_candidate_keepalive_interval = + configuration.stun_candidate_keepalive_interval; + modified_config.turn_customizer = configuration.turn_customizer; + modified_config.network_preference = configuration.network_preference; + modified_config.active_reset_srtp_params = + configuration.active_reset_srtp_params; + modified_config.turn_logging_id = configuration.turn_logging_id; + modified_config.stable_writable_connection_ping_interval_ms = + configuration.stable_writable_connection_ping_interval_ms; + if (configuration != modified_config) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, + "Modifying the configuration in an unsupported way."); + } + + RTCError err = ValidateConfiguration(modified_config); + if (!err.ok()) { + return err; + } + + return modified_config; +} + bool HasRtcpMuxEnabled(const cricket::ContentInfo* content) { return content->media_description()->rtcp_mux(); } @@ -277,6 +357,46 @@ bool DtlsEnabled(const PeerConnectionInterface::RTCConfiguration& configuration, return false; } +// Calls `ParseIceServersOrError` to extract ice server information from the +// `configuration` and then validates the extracted configuration. For a +// non-empty list of servers, usage gets recorded via `usage_pattern`. +RTCError ParseAndValidateIceServersFromConfiguration( + const PeerConnectionInterface::RTCConfiguration& configuration, + cricket::ServerAddresses& stun_servers, + std::vector& turn_servers, + UsagePattern& usage_pattern) { + RTC_DCHECK(stun_servers.empty()); + RTC_DCHECK(turn_servers.empty()); + RTCError err = ParseIceServersOrError(configuration.servers, &stun_servers, + &turn_servers); + if (!err.ok()) { + return err; + } + + // Restrict number of TURN servers. + if (turn_servers.size() > cricket::kMaxTurnServers) { + RTC_LOG(LS_WARNING) << "Number of configured TURN servers is " + << turn_servers.size() + << " which exceeds the maximum allowed number of " + << cricket::kMaxTurnServers; + turn_servers.resize(cricket::kMaxTurnServers); + } + + // Add the turn logging id to all turn servers + for (cricket::RelayServerConfig& turn_server : turn_servers) { + turn_server.turn_logging_id = configuration.turn_logging_id; + } + + // Note if STUN or TURN servers were supplied. + if (!stun_servers.empty()) { + usage_pattern.NoteUsageEvent(UsageEvent::STUN_SERVER_ADDED); + } + if (!turn_servers.empty()) { + usage_pattern.NoteUsageEvent(UsageEvent::TURN_SERVER_ADDED); + } + return RTCError::OK(); +} + } // namespace bool PeerConnectionInterface::RTCConfiguration::operator==( @@ -328,7 +448,6 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( bool offer_extmap_allow_mixed; std::string turn_logging_id; bool enable_implicit_rollback; - absl::optional allow_codec_switching; absl::optional report_usage_pattern_delay_ms; absl::optional stable_writable_connection_ping_interval_ms; webrtc::VpnPreference vpn_preference; @@ -392,7 +511,6 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( offer_extmap_allow_mixed == o.offer_extmap_allow_mixed && turn_logging_id == o.turn_logging_id && enable_implicit_rollback == o.enable_implicit_rollback && - allow_codec_switching == o.allow_codec_switching && report_usage_pattern_delay_ms == o.report_usage_pattern_delay_ms && stable_writable_connection_ping_interval_ms == o.stable_writable_connection_ping_interval_ms && @@ -509,6 +627,9 @@ PeerConnection::PeerConnection( ice_transport_factory_(std::move(dependencies.ice_transport_factory)), tls_cert_verifier_(std::move(dependencies.tls_cert_verifier)), call_(std::move(call)), + worker_thread_safety_(PendingTaskSafetyFlag::CreateAttachedToTaskQueue( + /*alive=*/call_ != nullptr, + worker_thread())), call_ptr_(call_.get()), // RFC 3264: The numeric value of the session id and version in the // o line MUST be representable with a "64 bit signed integer". @@ -518,14 +639,7 @@ PeerConnection::PeerConnection( dtls_enabled_(dtls_enabled), data_channel_controller_(this), message_handler_(signaling_thread()), - weak_factory_(this) { - worker_thread()->BlockingCall([this] { - RTC_DCHECK_RUN_ON(worker_thread()); - worker_thread_safety_ = PendingTaskSafetyFlag::Create(); - if (!call_) - worker_thread_safety_->SetNotAlive(); - }); -} + weak_factory_(this) {} PeerConnection::~PeerConnection() { TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection"); @@ -557,10 +671,8 @@ PeerConnection::~PeerConnection() { if (sdp_handler_) { // Don't destroy BaseChannels until after stats has been cleaned up so that // the last stats request can still read from the channels. - sdp_handler_->DestroyAllChannels(); - + sdp_handler_->DestroyMediaChannels(); RTC_LOG(LS_INFO) << "Session: " << session_id() << " is destroyed."; - sdp_handler_->ResetSessionDescFactory(); } @@ -575,6 +687,8 @@ PeerConnection::~PeerConnection() { if (network_thread_safety_) network_thread_safety_->SetNotAlive(); }); + sctp_mid_s_.reset(); + SetSctpTransportName(""); // call_ and event_log_ must be destroyed on the worker thread. worker_thread()->BlockingCall([this] { @@ -596,35 +710,12 @@ RTCError PeerConnection::Initialize( cricket::ServerAddresses stun_servers; std::vector turn_servers; - - RTCError parse_error = ParseIceServersOrError(configuration.servers, - &stun_servers, &turn_servers); + RTCError parse_error = ParseAndValidateIceServersFromConfiguration( + configuration, stun_servers, turn_servers, usage_pattern_); if (!parse_error.ok()) { return parse_error; } - // Restrict number of TURN servers. - if (turn_servers.size() > cricket::kMaxTurnServers) { - RTC_LOG(LS_WARNING) << "Number of configured TURN servers is " - << turn_servers.size() - << " which exceeds the maximum allowed number of " - << cricket::kMaxTurnServers; - turn_servers.resize(cricket::kMaxTurnServers); - } - - // Add the turn logging id to all turn servers - for (cricket::RelayServerConfig& turn_server : turn_servers) { - turn_server.turn_logging_id = configuration.turn_logging_id; - } - - // Note if STUN or TURN servers were supplied. - if (!stun_servers.empty()) { - NoteUsageEvent(UsageEvent::STUN_SERVER_ADDED); - } - if (!turn_servers.empty()) { - NoteUsageEvent(UsageEvent::TURN_SERVER_ADDED); - } - // Network thread initialization. transport_controller_copy_ = network_thread()->BlockingCall([&] { RTC_DCHECK_RUN_ON(network_thread()); @@ -676,10 +767,6 @@ RTCError PeerConnection::Initialize( }, delay_ms); - // Record the number of configured ICE servers for all connections. - RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.PeerConnection.IceServers.Configured", - configuration_.servers.size(), 0, 31, 32); - return RTCError::OK(); } @@ -1500,106 +1587,42 @@ RTCError PeerConnection::SetConfiguration( "SetConfiguration: PeerConnection is closed."); } - // According to JSEP, after setLocalDescription, changing the candidate pool - // size is not allowed, and changing the set of ICE servers will not result - // in new candidates being gathered. - if (local_description() && configuration.ice_candidate_pool_size != - configuration_.ice_candidate_pool_size) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, - "Can't change candidate pool size after calling " - "SetLocalDescription."); + const bool has_local_description = local_description() != nullptr; + + RTCError validate_error = ValidateIceCandidatePoolSize( + configuration.ice_candidate_pool_size, + has_local_description + ? absl::optional(configuration_.ice_candidate_pool_size) + : absl::nullopt); + if (!validate_error.ok()) { + return validate_error; } - if (local_description() && + if (has_local_description && configuration.crypto_options != configuration_.crypto_options) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, "Can't change crypto_options after calling " "SetLocalDescription."); } - // The simplest (and most future-compatible) way to tell if the config was - // modified in an invalid way is to copy each property we do support - // modifying, then use operator==. There are far more properties we don't - // support modifying than those we do, and more could be added. - RTCConfiguration modified_config = configuration_; - modified_config.servers = configuration.servers; - modified_config.type = configuration.type; - modified_config.ice_candidate_pool_size = - configuration.ice_candidate_pool_size; - modified_config.prune_turn_ports = configuration.prune_turn_ports; - modified_config.turn_port_prune_policy = configuration.turn_port_prune_policy; - modified_config.surface_ice_candidates_on_ice_transport_type_changed = - configuration.surface_ice_candidates_on_ice_transport_type_changed; - modified_config.ice_check_min_interval = configuration.ice_check_min_interval; - modified_config.ice_check_interval_strong_connectivity = - configuration.ice_check_interval_strong_connectivity; - modified_config.ice_check_interval_weak_connectivity = - configuration.ice_check_interval_weak_connectivity; - modified_config.ice_unwritable_timeout = configuration.ice_unwritable_timeout; - modified_config.ice_unwritable_min_checks = - configuration.ice_unwritable_min_checks; - modified_config.ice_inactive_timeout = configuration.ice_inactive_timeout; - modified_config.stun_candidate_keepalive_interval = - configuration.stun_candidate_keepalive_interval; - modified_config.turn_customizer = configuration.turn_customizer; - modified_config.network_preference = configuration.network_preference; - modified_config.active_reset_srtp_params = - configuration.active_reset_srtp_params; - modified_config.turn_logging_id = configuration.turn_logging_id; - modified_config.allow_codec_switching = configuration.allow_codec_switching; - modified_config.stable_writable_connection_ping_interval_ms = - configuration.stable_writable_connection_ping_interval_ms; - if (configuration != modified_config) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, - "Modifying the configuration in an unsupported way."); - } - - // Validate the modified configuration. - RTCError validate_error = ValidateConfiguration(modified_config); - if (!validate_error.ok()) { - return validate_error; - } - - // Note that this isn't possible through chromium, since it's an unsigned - // short in WebIDL. - if (configuration.ice_candidate_pool_size < 0 || - configuration.ice_candidate_pool_size > static_cast(UINT16_MAX)) { - return RTCError(RTCErrorType::INVALID_RANGE); + // Create a new, configuration object whose Ice config will have been + // validated.. + RTCErrorOr validated_config = + ApplyConfiguration(configuration, configuration_); + if (!validated_config.ok()) { + return validated_config.error(); } // Parse ICE servers before hopping to network thread. cricket::ServerAddresses stun_servers; std::vector turn_servers; - RTCError parse_error = ParseIceServersOrError(configuration.servers, - &stun_servers, &turn_servers); - if (!parse_error.ok()) { - return parse_error; + validate_error = ParseAndValidateIceServersFromConfiguration( + configuration, stun_servers, turn_servers, usage_pattern_); + if (!validate_error.ok()) { + return validate_error; } - // Restrict number of TURN servers. - if (turn_servers.size() > cricket::kMaxTurnServers) { - RTC_LOG(LS_WARNING) << "Number of configured TURN servers is " - << turn_servers.size() - << " which exceeds the maximum allowed number of " - << cricket::kMaxTurnServers; - turn_servers.resize(cricket::kMaxTurnServers); - } - - // Add the turn logging id to all turn servers - for (cricket::RelayServerConfig& turn_server : turn_servers) { - turn_server.turn_logging_id = configuration.turn_logging_id; - } - - // Note if STUN or TURN servers were supplied. - if (!stun_servers.empty()) { - NoteUsageEvent(UsageEvent::STUN_SERVER_ADDED); - } - if (!turn_servers.empty()) { - NoteUsageEvent(UsageEvent::TURN_SERVER_ADDED); - } - - const bool has_local_description = local_description() != nullptr; - + const RTCConfiguration& modified_config = validated_config.value(); const bool needs_ice_restart = modified_config.servers != configuration_.servers || NeedIceRestart( @@ -1623,6 +1646,8 @@ RTCError PeerConnection::SetConfiguration( transport_controller_->SetNeedsIceRestartFlag(); transport_controller_->SetIceConfig(ice_config); + transport_controller_->SetActiveResetSrtpParams( + modified_config.active_reset_srtp_params); return ReconfigurePortAllocator_n( stun_servers, turn_servers, modified_config.type, modified_config.ice_candidate_pool_size, @@ -1635,37 +1660,6 @@ RTCError PeerConnection::SetConfiguration( "Failed to apply configuration to PortAllocator."); } - if (configuration_.active_reset_srtp_params != - modified_config.active_reset_srtp_params) { - // TODO(tommi): merge BlockingCalls - network_thread()->BlockingCall([this, &modified_config] { - RTC_DCHECK_RUN_ON(network_thread()); - transport_controller_->SetActiveResetSrtpParams( - modified_config.active_reset_srtp_params); - }); - } - - if (modified_config.allow_codec_switching.has_value()) { - std::vector channels; - for (const auto& transceiver : rtp_manager()->transceivers()->List()) { - if (transceiver->media_type() != cricket::MEDIA_TYPE_VIDEO) - continue; - - auto* video_channel = transceiver->internal()->channel(); - if (video_channel) - channels.push_back( - static_cast( - video_channel->media_send_channel())); - } - - worker_thread()->BlockingCall( - [channels = std::move(channels), - allow_codec_switching = *modified_config.allow_codec_switching]() { - for (auto* ch : channels) - ch->SetVideoCodecSwitchingEnabled(allow_codec_switching); - }); - } - configuration_ = modified_config; return RTCError::OK(); } @@ -1909,7 +1903,12 @@ void PeerConnection::Close() { // Don't destroy BaseChannels until after stats has been cleaned up so that // the last stats request can still read from the channels. - sdp_handler_->DestroyAllChannels(); + // TODO(tommi): The voice/video channels will be partially uninitialized on + // the network thread (see `RtpTransceiver::ClearChannel`), partially on the + // worker thread (see `PushNewMediaChannelAndDeleteChannel`) and then + // eventually freed on the signaling thread. + // It would be good to combine those steps with the teardown steps here. + sdp_handler_->DestroyMediaChannels(); // The event log is used in the transport controller, which must be outlived // by the former. CreateOffer by the peer connection is implemented @@ -1925,11 +1924,6 @@ void PeerConnection::Close() { RtpPacketSinkInterface* sink = Observer(); network_thread()->BlockingCall([this, sink] { - // Data channels will already have been unset via the DestroyAllChannels() - // call above, which triggers a call to TeardownDataChannelTransport_n(). - // TODO(tommi): ^^ That's not exactly optimal since this is yet another - // blocking hop to the network thread during Close(). Further still, the - // voice/video/data channels will be cleared on the worker thread. RTC_DCHECK_RUN_ON(network_thread()); // RingRTC change to receive RTP data @@ -1939,6 +1933,7 @@ void PeerConnection::Close() { rtp_transport->UnregisterRtpDemuxerSink(sink); } + TeardownDataChannelTransport_n({}); transport_controller_.reset(); port_allocator_->DiscardCandidatePool(); if (network_thread_safety_) { @@ -1946,6 +1941,9 @@ void PeerConnection::Close() { } }); + sctp_mid_s_.reset(); + SetSctpTransportName(""); + worker_thread()->BlockingCall([this] { RTC_DCHECK_RUN_ON(worker_thread()); worker_thread_safety_->SetNotAlive(); @@ -2136,20 +2134,31 @@ void PeerConnection::OnSelectedCandidatePairChanged( Observer()->OnIceSelectedCandidatePairChanged(event); } -absl::optional PeerConnection::GetDataMid() const { +bool PeerConnection::CreateDataChannelTransport(absl::string_view mid) { RTC_DCHECK_RUN_ON(signaling_thread()); - return sctp_mid_s_; -} + RTC_DCHECK(!sctp_mid().has_value() || mid == sctp_mid().value()); + RTC_LOG(LS_INFO) << "Creating data channel, mid=" << mid; + + absl::optional transport_name = + network_thread()->BlockingCall([&] { + RTC_DCHECK_RUN_ON(network_thread()); + return SetupDataChannelTransport_n(mid); + }); + if (!transport_name) + return false; -void PeerConnection::SetSctpDataInfo(absl::string_view mid, - absl::string_view transport_name) { - RTC_DCHECK_RUN_ON(signaling_thread()); sctp_mid_s_ = std::string(mid); - SetSctpTransportName(std::string(transport_name)); + SetSctpTransportName(transport_name.value()); + + return true; } -void PeerConnection::ResetSctpDataInfo() { +void PeerConnection::DestroyDataChannelTransport(RTCError error) { RTC_DCHECK_RUN_ON(signaling_thread()); + network_thread()->BlockingCall([&] { + RTC_DCHECK_RUN_ON(network_thread()); + TeardownDataChannelTransport_n(error); + }); sctp_mid_s_.reset(); SetSctpTransportName(""); } @@ -2241,12 +2250,6 @@ bool PeerConnection::ReconfigurePortAllocator_n( RTC_DCHECK_RUN_ON(network_thread()); port_allocator_->SetCandidateFilter( ConvertIceTransportTypeToCandidateFilter(type)); - // According to JSEP, after setLocalDescription, changing the candidate pool - // size is not allowed, and changing the set of ICE servers will not result - // in new candidates being gathered. - if (have_local_description) { - port_allocator_->FreezeCandidatePool(); - } // Add the custom tls turn servers if they exist. auto turn_servers_copy = turn_servers; for (auto& turn_server : turn_servers_copy) { @@ -2911,6 +2914,36 @@ void PeerConnection::ReportNegotiatedCiphers( } } } + + uint16_t ssl_peer_signature_algorithm = + stats.channel_stats[0].ssl_peer_signature_algorithm; + if (ssl_peer_signature_algorithm != rtc::kSslSignatureAlgorithmUnknown) { + for (cricket::MediaType media_type : media_types) { + switch (media_type) { + case cricket::MEDIA_TYPE_AUDIO: + RTC_HISTOGRAM_ENUMERATION_SPARSE( + "WebRTC.PeerConnection.SslPeerSignatureAlgorithm.Audio", + ssl_peer_signature_algorithm, + rtc::kSslSignatureAlgorithmMaxValue); + break; + case cricket::MEDIA_TYPE_VIDEO: + RTC_HISTOGRAM_ENUMERATION_SPARSE( + "WebRTC.PeerConnection.SslPeerSignatureAlgorithm.Video", + ssl_peer_signature_algorithm, + rtc::kSslSignatureAlgorithmMaxValue); + break; + case cricket::MEDIA_TYPE_DATA: + RTC_HISTOGRAM_ENUMERATION_SPARSE( + "WebRTC.PeerConnection.SslPeerSignatureAlgorithm.Data", + ssl_peer_signature_algorithm, + rtc::kSslSignatureAlgorithmMaxValue); + break; + default: + RTC_DCHECK_NOTREACHED(); + continue; + } + } + } } bool PeerConnection::OnTransportChanged( diff --git a/pc/peer_connection.h b/pc/peer_connection.h index 04450f18b1..cdc458ace8 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h @@ -416,15 +416,8 @@ class PeerConnection : public PeerConnectionInternal, const std::map& bundle_groups_by_mid) override; - // Returns the MID for the data section associated with the - // SCTP data channel, if it has been set. If no data - // channels are configured this will return nullopt. - absl::optional GetDataMid() const override; - - void SetSctpDataInfo(absl::string_view mid, - absl::string_view transport_name) override; - - void ResetSctpDataInfo() override; + bool CreateDataChannelTransport(absl::string_view mid) override; + void DestroyDataChannelTransport(RTCError error) override; // Asynchronously calls SctpTransport::Start() on the network thread for // `sctp_mid()` if set. Called as part of setting the local description. @@ -452,9 +445,9 @@ class PeerConnection : public PeerConnectionInternal, // this session. bool SrtpRequired() const override; - absl::optional SetupDataChannelTransport_n( - absl::string_view mid) override RTC_RUN_ON(network_thread()); - void TeardownDataChannelTransport_n(RTCError error) override + absl::optional SetupDataChannelTransport_n(absl::string_view mid) + RTC_RUN_ON(network_thread()); + void TeardownDataChannelTransport_n(RTCError error) RTC_RUN_ON(network_thread()); const FieldTrialsView& trials() const override { return *trials_; } diff --git a/pc/peer_connection_bundle_unittest.cc b/pc/peer_connection_bundle_unittest.cc index e5ef16ff8a..0db401276a 100644 --- a/pc/peer_connection_bundle_unittest.cc +++ b/pc/peer_connection_bundle_unittest.cc @@ -60,6 +60,7 @@ #include "pc/rtp_transport_internal.h" #include "pc/sdp_utils.h" #include "pc/session_description.h" +#include "pc/test/integration_test_helpers.h" #include "pc/test/mock_peer_connection_observers.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -90,8 +91,6 @@ using ::testing::ElementsAre; using ::testing::UnorderedElementsAre; using ::testing::Values; -constexpr int kDefaultTimeout = 10000; - // TODO(steveanton): These tests should be rewritten to use the standard // RtpSenderInterface/DtlsTransportInterface objects once they're available in // the API. The RtpSender can be used to determine which transport a given media @@ -743,18 +742,18 @@ TEST_P(PeerConnectionBundleTest, ApplyDescriptionWithSameSsrcsBundledFails) { caller->SetLocalDescription(CloneSessionDescription(offer.get()))); // Modify the remote SDP to make two m= sections have the same SSRC. ASSERT_GE(offer->description()->contents().size(), 2U); - offer->description() - ->contents()[0] - .media_description() - ->mutable_streams()[0] - .ssrcs[0] = 1111222; - offer->description() - ->contents()[1] - .media_description() - ->mutable_streams()[0] - .ssrcs[0] = 1111222; - EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer))); + ReplaceFirstSsrc(offer->description() + ->contents()[0] + .media_description() + ->mutable_streams()[0], + 1111222); + ReplaceFirstSsrc(offer->description() + ->contents()[1] + .media_description() + ->mutable_streams()[0], + 1111222); + EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer))); // When BUNDLE is enabled, applying the description is expected to fail // because the demuxing criteria can not be satisfied. auto answer = callee->CreateAnswer(options); @@ -774,16 +773,16 @@ TEST_P(PeerConnectionBundleTest, caller->SetLocalDescription(CloneSessionDescription(offer.get()))); // Modify the remote SDP to make two m= sections have the same SSRC. ASSERT_GE(offer->description()->contents().size(), 2U); - offer->description() - ->contents()[0] - .media_description() - ->mutable_streams()[0] - .ssrcs[0] = 1111222; - offer->description() - ->contents()[1] - .media_description() - ->mutable_streams()[0] - .ssrcs[0] = 1111222; + ReplaceFirstSsrc(offer->description() + ->contents()[0] + .media_description() + ->mutable_streams()[0], + 1111222); + ReplaceFirstSsrc(offer->description() + ->contents()[1] + .media_description() + ->mutable_streams()[0], + 1111222); EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer))); // Without BUNDLE, demuxing is done per-transport. diff --git a/pc/peer_connection_encodings_integrationtest.cc b/pc/peer_connection_encodings_integrationtest.cc index 5b25e293cd..c7181c53ae 100644 --- a/pc/peer_connection_encodings_integrationtest.cc +++ b/pc/peer_connection_encodings_integrationtest.cc @@ -924,6 +924,47 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_TargetBitrate_StandardL1T3) { EXPECT_LE(target_bitrate.kbps(), kVp9ExpectedMaxBitrateForL1T3.kbps()); } +TEST_F(PeerConnectionEncodingsIntegrationTest, + SimulcastProducesUniqueSsrcAndRtxSsrcs) { + rtc::scoped_refptr local_pc_wrapper = CreatePc(); + rtc::scoped_refptr remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + std::vector layers = + CreateLayers({"f", "h", "q"}, /*active=*/true); + rtc::scoped_refptr transceiver = + AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, + layers); + std::vector codecs = + GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8"); + transceiver->SetCodecPreferences(codecs); + + NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper); + local_pc_wrapper->WaitForConnection(); + remote_pc_wrapper->WaitForConnection(); + + // Wait until media is flowing on all three layers. + // Ramp up time is needed before all three layers are sending. + ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), + kLongTimeoutForRampingUp.ms()); + // Verify SSRCs and RTX SSRCs. + rtc::scoped_refptr report = GetStats(local_pc_wrapper); + std::vector outbound_rtps = + report->GetStatsOfType(); + ASSERT_THAT(outbound_rtps, SizeIs(3u)); + + std::set ssrcs; + std::set rtx_ssrcs; + for (const auto& outbound_rtp : outbound_rtps) { + ASSERT_TRUE(outbound_rtp->ssrc.has_value()); + ASSERT_TRUE(outbound_rtp->rtx_ssrc.has_value()); + ssrcs.insert(*outbound_rtp->ssrc); + rtx_ssrcs.insert(*outbound_rtp->rtx_ssrc); + } + EXPECT_EQ(ssrcs.size(), 3u); + EXPECT_EQ(rtx_ssrcs.size(), 3u); +} + TEST_F(PeerConnectionEncodingsIntegrationTest, EncodingParameterCodecIsEmptyWhenCreatedAudio) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); @@ -1422,6 +1463,69 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION); } +TEST_F(PeerConnectionEncodingsIntegrationTest, + SetParametersRejectsNonRemotelyNegotiatedCodecParameterAudio) { + rtc::scoped_refptr local_pc_wrapper = CreatePc(); + rtc::scoped_refptr remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + absl::optional opus = + local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO, + "opus"); + ASSERT_TRUE(opus); + + std::vector not_opus_codecs = + local_pc_wrapper->pc_factory() + ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO) + .codecs; + not_opus_codecs.erase( + std::remove_if(not_opus_codecs.begin(), not_opus_codecs.end(), + [&](const auto& codec) { + return absl::EqualsIgnoreCase(codec.name, opus->name); + }), + not_opus_codecs.end()); + + auto transceiver_or_error = + local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO); + ASSERT_TRUE(transceiver_or_error.ok()); + rtc::scoped_refptr audio_transceiver = + transceiver_or_error.MoveValue(); + + // Negotiation, create offer and apply it + std::unique_ptr offer = + CreateOffer(local_pc_wrapper); + rtc::scoped_refptr p1 = + SetLocalDescription(local_pc_wrapper, offer.get()); + rtc::scoped_refptr p2 = + SetRemoteDescription(remote_pc_wrapper, offer.get()); + EXPECT_TRUE(Await({p1, p2})); + + // Update the remote transceiver to reject Opus + std::vector> remote_transceivers = + remote_pc_wrapper->pc()->GetTransceivers(); + ASSERT_TRUE(!remote_transceivers.empty()); + rtc::scoped_refptr remote_audio_transceiver = + remote_transceivers[0]; + ASSERT_TRUE( + remote_audio_transceiver->SetCodecPreferences(not_opus_codecs).ok()); + + // Create answer and apply it + std::unique_ptr answer = + CreateAnswer(remote_pc_wrapper); + p1 = SetLocalDescription(remote_pc_wrapper, answer.get()); + p2 = SetRemoteDescription(local_pc_wrapper, answer.get()); + EXPECT_TRUE(Await({p1, p2})); + + local_pc_wrapper->WaitForConnection(); + remote_pc_wrapper->WaitForConnection(); + + webrtc::RtpParameters parameters = + audio_transceiver->sender()->GetParameters(); + parameters.encodings[0].codec = opus; + RTCError error = audio_transceiver->sender()->SetParameters(parameters); + EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION); +} + TEST_F(PeerConnectionEncodingsIntegrationTest, SetParametersRejectsNonNegotiatedCodecParameterVideo) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); @@ -1462,6 +1566,69 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION); } +TEST_F(PeerConnectionEncodingsIntegrationTest, + SetParametersRejectsNonRemotelyNegotiatedCodecParameterVideo) { + rtc::scoped_refptr local_pc_wrapper = CreatePc(); + rtc::scoped_refptr remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + absl::optional vp8 = + local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_VIDEO, + "vp8"); + ASSERT_TRUE(vp8); + + std::vector not_vp8_codecs = + local_pc_wrapper->pc_factory() + ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO) + .codecs; + not_vp8_codecs.erase( + std::remove_if(not_vp8_codecs.begin(), not_vp8_codecs.end(), + [&](const auto& codec) { + return absl::EqualsIgnoreCase(codec.name, vp8->name); + }), + not_vp8_codecs.end()); + + auto transceiver_or_error = + local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO); + ASSERT_TRUE(transceiver_or_error.ok()); + rtc::scoped_refptr video_transceiver = + transceiver_or_error.MoveValue(); + + // Negotiation, create offer and apply it + std::unique_ptr offer = + CreateOffer(local_pc_wrapper); + rtc::scoped_refptr p1 = + SetLocalDescription(local_pc_wrapper, offer.get()); + rtc::scoped_refptr p2 = + SetRemoteDescription(remote_pc_wrapper, offer.get()); + EXPECT_TRUE(Await({p1, p2})); + + // Update the remote transceiver to reject VP8 + std::vector> remote_transceivers = + remote_pc_wrapper->pc()->GetTransceivers(); + ASSERT_TRUE(!remote_transceivers.empty()); + rtc::scoped_refptr remote_video_transceiver = + remote_transceivers[0]; + ASSERT_TRUE( + remote_video_transceiver->SetCodecPreferences(not_vp8_codecs).ok()); + + // Create answer and apply it + std::unique_ptr answer = + CreateAnswer(remote_pc_wrapper); + p1 = SetLocalDescription(remote_pc_wrapper, answer.get()); + p2 = SetRemoteDescription(local_pc_wrapper, answer.get()); + EXPECT_TRUE(Await({p1, p2})); + + local_pc_wrapper->WaitForConnection(); + remote_pc_wrapper->WaitForConnection(); + + webrtc::RtpParameters parameters = + video_transceiver->sender()->GetParameters(); + parameters.encodings[0].codec = vp8; + RTCError error = video_transceiver->sender()->SetParameters(parameters); + EXPECT_EQ(error.type(), RTCErrorType::INVALID_MODIFICATION); +} + TEST_F(PeerConnectionEncodingsIntegrationTest, EncodingParametersCodecRemovedAfterNegotiationAudio) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); @@ -1511,6 +1678,67 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_FALSE(parameters.encodings[0].codec); } +TEST_F(PeerConnectionEncodingsIntegrationTest, + EncodingParametersRedEnabledBeforeNegotiationAudio) { + rtc::scoped_refptr local_pc_wrapper = CreatePc(); + rtc::scoped_refptr remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + std::vector send_codecs = + local_pc_wrapper->pc_factory() + ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO) + .codecs; + + absl::optional opus = + local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO, + "opus"); + ASSERT_TRUE(opus); + + absl::optional red = + local_pc_wrapper->FindFirstSendCodecWithName(cricket::MEDIA_TYPE_AUDIO, + "red"); + ASSERT_TRUE(red); + + webrtc::RtpTransceiverInit init; + init.direction = webrtc::RtpTransceiverDirection::kSendOnly; + webrtc::RtpEncodingParameters encoding_parameters; + encoding_parameters.codec = opus; + init.send_encodings.push_back(encoding_parameters); + + auto transceiver_or_error = + local_pc_wrapper->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init); + ASSERT_TRUE(transceiver_or_error.ok()); + rtc::scoped_refptr audio_transceiver = + transceiver_or_error.MoveValue(); + + // Preferring RED over Opus should enable RED with Opus encoding. + send_codecs[0] = red.value(); + send_codecs[1] = opus.value(); + + ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok()); + NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper); + local_pc_wrapper->WaitForConnection(); + remote_pc_wrapper->WaitForConnection(); + + webrtc::RtpParameters parameters = + audio_transceiver->sender()->GetParameters(); + EXPECT_EQ(parameters.encodings[0].codec, opus); + EXPECT_EQ(parameters.codecs[0].payload_type, red->preferred_payload_type); + EXPECT_EQ(parameters.codecs[0].name, red->name); + + // Check that it's possible to switch back to Opus without RED. + send_codecs[0] = opus.value(); + send_codecs[1] = red.value(); + + ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok()); + NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper); + + parameters = audio_transceiver->sender()->GetParameters(); + EXPECT_EQ(parameters.encodings[0].codec, opus); + EXPECT_EQ(parameters.codecs[0].payload_type, opus->preferred_payload_type); + EXPECT_EQ(parameters.codecs[0].name, opus->name); +} + TEST_F(PeerConnectionEncodingsIntegrationTest, SetParametersRejectsScalabilityModeForSelectedCodec) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc index dc458761d3..3ceb08c6ac 100644 --- a/pc/peer_connection_factory.cc +++ b/pc/peer_connection_factory.cc @@ -308,7 +308,7 @@ std::unique_ptr PeerConnectionFactory::CreateCall_w( const PeerConnectionInterface::RTCConfiguration& configuration) { RTC_DCHECK_RUN_ON(worker_thread()); - webrtc::Call::Config call_config(event_log, network_thread()); + CallConfig call_config(event_log, network_thread()); if (!media_engine() || !context_->call_factory()) { return nullptr; } @@ -350,8 +350,7 @@ std::unique_ptr PeerConnectionFactory::CreateCall_w( transport_controller_send_factory_.get(); call_config.metronome = metronome_.get(); call_config.pacer_burst_interval = configuration.pacer_burst_interval; - return std::unique_ptr( - context_->call_factory()->CreateCall(call_config)); + return context_->call_factory()->CreateCall(call_config); } bool PeerConnectionFactory::IsTrialEnabled(absl::string_view key) const { diff --git a/pc/peer_connection_interface_unittest.cc b/pc/peer_connection_interface_unittest.cc index 3023be1493..1f5ab2f449 100644 --- a/pc/peer_connection_interface_unittest.cc +++ b/pc/peer_connection_interface_unittest.cc @@ -3004,21 +3004,20 @@ TEST_P(PeerConnectionInterfaceTest, EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0])); // Change the ssrc of the audio and video track. - cricket::MediaContentDescription* desc = - cricket::GetFirstAudioContentDescription(modified_offer->description()); - ASSERT_TRUE(desc != nullptr); - for (StreamParams& stream : desc->mutable_streams()) { - for (unsigned int& ssrc : stream.ssrcs) { - ++ssrc; - } - } - - desc = - cricket::GetFirstVideoContentDescription(modified_offer->description()); - ASSERT_TRUE(desc != nullptr); - for (StreamParams& stream : desc->mutable_streams()) { - for (unsigned int& ssrc : stream.ssrcs) { - ++ssrc; + for (auto content : modified_offer->description()->contents()) { + cricket::MediaContentDescription* desc = content.media_description(); + ASSERT_TRUE(desc); + for (StreamParams& stream : desc->mutable_streams()) { + for (unsigned int& ssrc : stream.ssrcs) { + unsigned int old_ssrc = ssrc++; + for (auto& group : stream.ssrc_groups) { + for (unsigned int& secondary_ssrc : group.ssrcs) { + if (secondary_ssrc == old_ssrc) { + secondary_ssrc = ssrc; + } + } + } + } } } diff --git a/pc/peer_connection_internal.h b/pc/peer_connection_internal.h index 28ea640548..fa18fd5d7b 100644 --- a/pc/peer_connection_internal.h +++ b/pc/peer_connection_internal.h @@ -95,7 +95,6 @@ class PeerConnectionSdpMethods { const std::map& bundle_groups_by_mid) = 0; - virtual absl::optional GetDataMid() const = 0; // Internal implementation for AddTransceiver family of methods. If // `fire_callback` is set, fires OnRenegotiationNeeded callback if successful. virtual RTCErrorOr> @@ -117,19 +116,18 @@ class PeerConnectionSdpMethods { // Returns true if SRTP (either using DTLS-SRTP or SDES) is required by // this session. virtual bool SrtpRequired() const = 0; - // Configures the data channel transport on the network thread. - // The return value will be unset if an error occurs. If the setup succeeded - // the return value will be set and contain the name of the transport - // (empty string if a name isn't available). - virtual absl::optional SetupDataChannelTransport_n( - absl::string_view mid) = 0; - virtual void TeardownDataChannelTransport_n(RTCError error) = 0; - virtual void SetSctpDataInfo(absl::string_view mid, - absl::string_view transport_name) = 0; - virtual void ResetSctpDataInfo() = 0; + // Initializes the data channel transport for the peerconnection instance. + // This will have the effect that `sctp_mid()` and `sctp_transport_name()` + // will return a set value (even though it might be an empty string) and the + // dc transport will be initialized on the network thread. + virtual bool CreateDataChannelTransport(absl::string_view mid) = 0; + // Tears down the data channel transport state and clears the `sctp_mid()` and + // `sctp_transport_name()` properties. + virtual void DestroyDataChannelTransport(RTCError error) = 0; + // RingRTC change for ICE forking. virtual rtc::scoped_refptr shared_ice_gatherer() { - return nullptr; + return nullptr; } virtual const FieldTrialsView& trials() const = 0; diff --git a/pc/peer_connection_rtp_unittest.cc b/pc/peer_connection_rtp_unittest.cc index 4bdb7f1ea6..b93e5923bb 100644 --- a/pc/peer_connection_rtp_unittest.cc +++ b/pc/peer_connection_rtp_unittest.cc @@ -53,6 +53,7 @@ #include "pc/sdp_utils.h" #include "pc/session_description.h" #include "pc/test/fake_audio_capture_module.h" +#include "pc/test/integration_test_helpers.h" #include "pc/test/mock_peer_connection_observers.h" #include "rtc_base/checks.h" #include "rtc_base/gunit.h" @@ -73,8 +74,6 @@ using ::testing::Pair; using ::testing::UnorderedElementsAre; using ::testing::Values; -const uint32_t kDefaultTimeout = 10000u; - template class OnSuccessObserver : public webrtc::SetRemoteDescriptionObserverInterface { public: @@ -826,7 +825,8 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan, TracksDoNotEndWhenSsrcChanges) { for (size_t i = 0; i < contents.size(); ++i) { auto& mutable_streams = contents[i].media_description()->mutable_streams(); ASSERT_EQ(mutable_streams.size(), 1u); - mutable_streams[0].ssrcs[0] = kFirstMungedSsrc + static_cast(i); + ReplaceFirstSsrc(mutable_streams[0], + kFirstMungedSsrc + static_cast(i)); } ASSERT_TRUE( callee->SetLocalDescription(CloneSessionDescription(answer.get()))); diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index c191f4d65e..0797ba2a76 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -839,7 +839,8 @@ CreateOutboundRTPStreamStatsFromVideoSenderInfo( } for (const auto& ssrc_group : video_sender_info.ssrc_groups) { if (ssrc_group.semantics == cricket::kFidSsrcGroupSemantics && - ssrc_group.ssrcs.size() == 2) { + ssrc_group.ssrcs.size() == 2 && + video_sender_info.ssrc() == ssrc_group.ssrcs[0]) { outbound_video->rtx_ssrc = ssrc_group.ssrcs[1]; } } diff --git a/pc/rtp_transport.h b/pc/rtp_transport.h index 8e9fc6738c..74275c2513 100644 --- a/pc/rtp_transport.h +++ b/pc/rtp_transport.h @@ -145,8 +145,8 @@ class RtpTransport : public RtpTransportInternal { bool processing_ready_to_send_ = false; ScopedTaskSafety safety_; - // If false, drop all RTP and RTCP packets before processing them. // RingRTC change to drop all incoming packets until explicitly allowed + // If false, drop all RTP and RTCP packets before processing them. bool incoming_rtp_enabled_ = false; }; diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc index e0acc950fb..4163d76e24 100644 --- a/pc/sdp_offer_answer.cc +++ b/pc/sdp_offer_answer.cc @@ -53,6 +53,7 @@ #include "pc/rtp_sender_proxy.h" #include "pc/simulcast_description.h" #include "pc/usage_pattern.h" +#include "pc/used_ids.h" #include "pc/webrtc_session_description_factory.h" #include "rtc_base/helpers.h" #include "rtc_base/logging.h" @@ -433,18 +434,9 @@ RTCError ValidateBundledPayloadTypes( continue; } const auto type = media_description->type(); - if (type == cricket::MEDIA_TYPE_AUDIO) { - RTC_DCHECK(media_description->as_audio()); - for (const auto& c : media_description->as_audio()->codecs()) { - auto error = FindDuplicateCodecParameters( - c.ToCodecParameters(), payload_to_codec_parameters); - if (!error.ok()) { - return error; - } - } - } else if (type == cricket::MEDIA_TYPE_VIDEO) { - RTC_DCHECK(media_description->as_video()); - for (const auto& c : media_description->as_video()->codecs()) { + if (type == cricket::MEDIA_TYPE_AUDIO || + type == cricket::MEDIA_TYPE_VIDEO) { + for (const auto& c : media_description->codecs()) { auto error = FindDuplicateCodecParameters( c.ToCodecParameters(), payload_to_codec_parameters); if (!error.ok()) { @@ -563,6 +555,49 @@ RTCError ValidateSsrcGroups(const cricket::SessionDescription& description) { return RTCError::OK(); } +RTCError ValidatePayloadTypes(const cricket::SessionDescription& description) { + for (const ContentInfo& content : description.contents()) { + if (content.type != MediaProtocolType::kRtp) { + continue; + } + const auto media_description = content.media_description(); + RTC_DCHECK(media_description); + if (content.rejected || !media_description || + !media_description->has_codecs()) { + continue; + } + const auto type = media_description->type(); + if (type == cricket::MEDIA_TYPE_AUDIO) { + RTC_DCHECK(media_description->as_audio()); + for (const auto& codec : media_description->as_audio()->codecs()) { + if (!cricket::UsedPayloadTypes::IsIdValid( + codec, media_description->rtcp_mux())) { + LOG_AND_RETURN_ERROR( + RTCErrorType::INVALID_PARAMETER, + "The media section with MID='" + content.mid() + + "' used an invalid payload type " + rtc::ToString(codec.id) + + " for codec '" + codec.name + ", rtcp-mux:" + + (media_description->rtcp_mux() ? "enabled" : "disabled")); + } + } + } else if (type == cricket::MEDIA_TYPE_VIDEO) { + RTC_DCHECK(media_description->as_video()); + for (const auto& codec : media_description->as_video()->codecs()) { + if (!cricket::UsedPayloadTypes::IsIdValid( + codec, media_description->rtcp_mux())) { + LOG_AND_RETURN_ERROR( + RTCErrorType::INVALID_PARAMETER, + "The media section with MID='" + content.mid() + + "' used an invalid payload type " + rtc::ToString(codec.id) + + " for codec '" + codec.name + ", rtcp-mux:" + + (media_description->rtcp_mux() ? "enabled" : "disabled")); + } + } + } + } + return RTCError::OK(); +} + bool IsValidOfferToReceiveMedia(int value) { typedef PeerConnectionInterface::RTCOfferAnswerOptions Options; return (value >= Options::kUndefined) && @@ -2330,7 +2365,7 @@ void SdpOfferAnswerHandler::DoSetLocalDescription( cricket::CS_LOCAL, desc->GetType(), error); RTC_LOG(LS_ERROR) << error_message; observer->OnSetLocalDescriptionComplete( - RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message))); + RTCError(error.type(), std::move(error_message))); return; } @@ -3572,11 +3607,7 @@ RTCError SdpOfferAnswerHandler::ValidateSessionDescription( // Validate that there are no collisions of bundled header extensions ids. error = ValidateBundledRtpHeaderExtensions(*sdesc->description()); - RTC_HISTOGRAM_BOOLEAN("WebRTC.PeerConnection.ValidBundledExtensionIds", - error.ok()); - // TODO(bugs.webrtc.org/14782): remove killswitch after rollout. - if (!error.ok() && !pc_->trials().IsDisabled( - "WebRTC-PreventBundleHeaderExtensionIdCollision")) { + if (!error.ok()) { return error; } @@ -3593,6 +3624,11 @@ RTCError SdpOfferAnswerHandler::ValidateSessionDescription( kBundleWithoutRtcpMux); } + error = ValidatePayloadTypes(*sdesc->description()); + if (!error.ok()) { + return error; + } + // TODO(skvlad): When the local rtcp-mux policy is Require, reject any // m-lines that do not rtcp-mux enabled. @@ -3761,13 +3797,15 @@ RTCError SdpOfferAnswerHandler::UpdateTransceiversAndDataChannels( return error; } } else if (media_type == cricket::MEDIA_TYPE_DATA) { - if (pc_->GetDataMid() && new_content.name != *(pc_->GetDataMid())) { + const auto data_mid = pc_->sctp_mid(); + if (data_mid && new_content.name != data_mid.value()) { // Ignore all but the first data section. RTC_LOG(LS_INFO) << "Ignoring data media section with MID=" << new_content.name; continue; } - RTCError error = UpdateDataChannel(source, new_content, bundle_group); + RTCError error = + UpdateDataChannelTransport(source, new_content, bundle_group); if (!error.ok()) { return error; } @@ -3949,7 +3987,7 @@ RTCError SdpOfferAnswerHandler::UpdateTransceiverChannel( return RTCError::OK(); } -RTCError SdpOfferAnswerHandler::UpdateDataChannel( +RTCError SdpOfferAnswerHandler::UpdateDataChannelTransport( cricket::ContentSource source, const cricket::ContentInfo& content, const cricket::ContentGroup* bundle_group) { @@ -3961,8 +3999,8 @@ RTCError SdpOfferAnswerHandler::UpdateDataChannel( sb << "Rejected data channel transport with mid=" << content.mid(); RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA, sb.Release()); error.set_error_detail(RTCErrorDetailType::DATA_CHANNEL_FAILURE); - DestroyDataChannelTransport(error); - } else if (!CreateDataChannel(content.name)) { + pc_->DestroyDataChannelTransport(error); + } else if (!pc_->CreateDataChannelTransport(content.name)) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create data channel."); } @@ -4301,8 +4339,9 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( session_options->media_description_options.push_back( GetMediaDescriptionOptionsForRejectedData(mid)); } else { - RTC_CHECK(pc_->GetDataMid()); - if (mid == *(pc_->GetDataMid())) { + const auto data_mid = pc_->sctp_mid(); + RTC_CHECK(data_mid); + if (mid == data_mid.value()) { session_options->media_description_options.push_back( GetMediaDescriptionOptionsForActiveData(mid)); } else { @@ -4343,9 +4382,9 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( } // Lastly, add a m-section if we have requested local data channels and an // m section does not already exist. - if (!pc_->GetDataMid() && data_channel_controller()->HasDataChannels()) { + if (!pc_->sctp_mid() && data_channel_controller()->HasDataChannels()) { // Attempt to recycle a stopped m-line. - // TODO(crbug.com/1442604): GetDataMid() should return the mid if one was + // TODO(crbug.com/1442604): sctp_mid() should return the mid if one was // ever created but rejected. bool recycled = false; for (size_t i = 0; i < session_options->media_description_options.size(); @@ -4496,7 +4535,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer( // Reject all data sections if data channels are disabled. // Reject a data section if it has already been rejected. // Reject all data sections except for the first one. - if (content.rejected || content.name != *(pc_->GetDataMid())) { + if (content.rejected || content.name != *(pc_->sctp_mid())) { session_options->media_description_options.push_back( GetMediaDescriptionOptionsForRejectedData(content.name)); } else { @@ -4989,14 +5028,14 @@ void SdpOfferAnswerHandler::RemoveUnusedChannels( RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA, "No data channel section in the description."); error.set_error_detail(RTCErrorDetailType::DATA_CHANNEL_FAILURE); - DestroyDataChannelTransport(error); + pc_->DestroyDataChannelTransport(error); } else if (data_info->rejected) { rtc::StringBuilder sb; sb << "Rejected data channel with mid=" << data_info->name << "."; RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA, sb.Release()); error.set_error_detail(RTCErrorDetailType::DATA_CHANNEL_FAILURE); - DestroyDataChannelTransport(error); + pc_->DestroyDataChannelTransport(error); } } @@ -5179,7 +5218,7 @@ RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) { } const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc); - if (data && !data->rejected && !CreateDataChannel(data->name)) { + if (data && !data->rejected && !pc_->CreateDataChannelTransport(data->name)) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create data channel."); } @@ -5187,34 +5226,7 @@ RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) { return RTCError::OK(); } -bool SdpOfferAnswerHandler::CreateDataChannel(const std::string& mid) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!pc_->sctp_mid().has_value() || mid == pc_->sctp_mid().value()); - RTC_LOG(LS_INFO) << "Creating data channel, mid=" << mid; - - absl::optional transport_name = - context_->network_thread()->BlockingCall([&] { - RTC_DCHECK_RUN_ON(context_->network_thread()); - return pc_->SetupDataChannelTransport_n(mid); - }); - if (!transport_name) - return false; - - pc_->SetSctpDataInfo(mid, *transport_name); - return true; -} - -void SdpOfferAnswerHandler::DestroyDataChannelTransport(RTCError error) { - RTC_DCHECK_RUN_ON(signaling_thread()); - context_->network_thread()->BlockingCall( - [&, data_channel_controller = data_channel_controller()] { - RTC_DCHECK_RUN_ON(context_->network_thread()); - pc_->TeardownDataChannelTransport_n(error); - }); - pc_->ResetSctpDataInfo(); -} - -void SdpOfferAnswerHandler::DestroyAllChannels() { +void SdpOfferAnswerHandler::DestroyMediaChannels() { RTC_DCHECK_RUN_ON(signaling_thread()); if (!transceivers()) { return; @@ -5237,8 +5249,6 @@ void SdpOfferAnswerHandler::DestroyAllChannels() { transceiver->internal()->ClearChannel(); } } - - DestroyDataChannelTransport({}); } void SdpOfferAnswerHandler::GenerateMediaDescriptionOptions( diff --git a/pc/sdp_offer_answer.h b/pc/sdp_offer_answer.h index 80a21391b9..8aa7040b16 100644 --- a/pc/sdp_offer_answer.h +++ b/pc/sdp_offer_answer.h @@ -166,8 +166,8 @@ class SdpOfferAnswerHandler : public SdpStateProvider { // See also `InternalDataChannelInit::fallback_ssl_role`. absl::optional GuessSslRole() const; - // Destroys all BaseChannels and destroys the SCTP data channel, if present. - void DestroyAllChannels(); + // Destroys all media BaseChannels. + void DestroyMediaChannels(); rtc::scoped_refptr local_streams(); rtc::scoped_refptr remote_streams(); @@ -359,9 +359,9 @@ class SdpOfferAnswerHandler : public SdpStateProvider { // Either creates or destroys the local data channel according to the given // media section. - RTCError UpdateDataChannel(cricket::ContentSource source, - const cricket::ContentInfo& content, - const cricket::ContentGroup* bundle_group) + RTCError UpdateDataChannelTransport(cricket::ContentSource source, + const cricket::ContentInfo& content, + const cricket::ContentGroup* bundle_group) RTC_RUN_ON(signaling_thread()); // Check if a call to SetLocalDescription is acceptable with a session // description of the given type. @@ -526,12 +526,6 @@ class SdpOfferAnswerHandler : public SdpStateProvider { // This method will also delete any existing media channels before creating. RTCError CreateChannels(const cricket::SessionDescription& desc); - bool CreateDataChannel(const std::string& mid); - - // Destroys the RTP data channel transport and/or the SCTP data channel - // transport and clears it. - void DestroyDataChannelTransport(RTCError error); - // Generates MediaDescriptionOptions for the `session_opts` based on existing // local description or remote description. void GenerateMediaDescriptionOptions( diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc index 03bea2a23e..94ceff10ac 100644 --- a/pc/sdp_offer_answer_unittest.cc +++ b/pc/sdp_offer_answer_unittest.cc @@ -304,9 +304,6 @@ TEST_F(SdpOfferAnswerTest, BundleMeasuresHeaderExtensionIdCollision) { RTCError error; pc->SetRemoteDescription(std::move(desc), &error); EXPECT_TRUE(error.ok()); - EXPECT_METRIC_EQ(1, - webrtc::metrics::NumEvents( - "WebRTC.PeerConnection.ValidBundledExtensionIds", true)); } // extmap:3 is used with two different URIs which is not allowed. @@ -345,9 +342,6 @@ TEST_F(SdpOfferAnswerTest, BundleRejectsHeaderExtensionIdCollision) { pc->SetRemoteDescription(std::move(desc), &error); EXPECT_FALSE(error.ok()); EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER); - EXPECT_METRIC_EQ( - 1, webrtc::metrics::NumEvents( - "WebRTC.PeerConnection.ValidBundledExtensionIds", false)); } // transport-wide cc is negotiated with two different ids 3 and 4. @@ -388,9 +382,6 @@ TEST_F(SdpOfferAnswerTest, BundleAcceptsDifferentIdsForSameExtension) { RTCError error; pc->SetRemoteDescription(std::move(desc), &error); EXPECT_TRUE(error.ok()); - EXPECT_METRIC_EQ(1, - webrtc::metrics::NumEvents( - "WebRTC.PeerConnection.ValidBundledExtensionIds", true)); } TEST_F(SdpOfferAnswerTest, LargeMidsAreRejected) { @@ -959,4 +950,151 @@ TEST_F(SdpOfferAnswerTest, OfferWithRtxAndNoMsidIsNotRejected) { EXPECT_TRUE(pc->SetRemoteDescription(std::move(offer))); } +TEST_F(SdpOfferAnswerTest, RejectsAnswerWithInvalidTransport) { + auto pc1 = CreatePeerConnection(); + pc1->AddAudioTrack("audio_track", {}); + auto pc2 = CreatePeerConnection(); + pc2->AddAudioTrack("anotheraudio_track", {}); + + auto initial_offer = pc1->CreateOfferAndSetAsLocal(); + ASSERT_EQ(initial_offer->description()->contents().size(), 1u); + auto mid = initial_offer->description()->contents()[0].mid(); + + EXPECT_TRUE(pc2->SetRemoteDescription(std::move(initial_offer))); + auto initial_answer = pc2->CreateAnswerAndSetAsLocal(); + + std::string sdp; + initial_answer->ToString(&sdp); + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(initial_answer))); + + auto transceivers = pc1->pc()->GetTransceivers(); + ASSERT_EQ(transceivers.size(), 1u); + // This stops the only transport. + transceivers[0]->StopStandard(); + + auto subsequent_offer = pc1->CreateOfferAndSetAsLocal(); + // But the remote answers with a non-rejected m-line which is not valid. + auto bad_answer = CreateSessionDescription( + SdpType::kAnswer, + absl::StrReplaceAll(sdp, {{"a=group:BUNDLE " + mid + "\r\n", ""}})); + + RTCError error; + pc1->SetRemoteDescription(std::move(bad_answer), &error); + EXPECT_FALSE(error.ok()); + EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER); +} + +TEST_F(SdpOfferAnswerTest, SdpMungingWithInvalidPayloadTypeIsRejected) { + auto pc = CreatePeerConnection(); + pc->AddAudioTrack("audio_track", {}); + + auto offer = pc->CreateOffer(); + ASSERT_EQ(offer->description()->contents().size(), 1u); + auto* audio = + offer->description()->contents()[0].media_description()->as_audio(); + ASSERT_GT(audio->codecs().size(), 0u); + EXPECT_TRUE(audio->rtcp_mux()); + auto codecs = audio->codecs(); + for (int invalid_payload_type = 64; invalid_payload_type < 96; + invalid_payload_type++) { + codecs[0].id = + invalid_payload_type; // The range [64-95] is disallowed with rtcp_mux. + audio->set_codecs(codecs); + // ASSERT to avoid getting into a bad state. + ASSERT_FALSE(pc->SetLocalDescription(offer->Clone())); + ASSERT_FALSE(pc->SetRemoteDescription(offer->Clone())); + } +} + +// Test variant with boolean order for audio-video and video-audio. +class SdpOfferAnswerShuffleMediaTypes + : public SdpOfferAnswerTest, + public testing::WithParamInterface { + public: + SdpOfferAnswerShuffleMediaTypes() : SdpOfferAnswerTest() {} +}; + +TEST_P(SdpOfferAnswerShuffleMediaTypes, + RecyclingWithDifferentKindAndSameMidFailsAnswer) { + bool audio_first = GetParam(); + auto pc1 = CreatePeerConnection(); + auto pc2 = CreatePeerConnection(); + if (audio_first) { + pc1->AddAudioTrack("audio_track", {}); + pc2->AddVideoTrack("video_track", {}); + } else { + pc2->AddAudioTrack("audio_track", {}); + pc1->AddVideoTrack("video_track", {}); + } + + auto initial_offer = pc1->CreateOfferAndSetAsLocal(); + ASSERT_EQ(initial_offer->description()->contents().size(), 1u); + auto mid1 = initial_offer->description()->contents()[0].mid(); + std::string rejected_answer_sdp = + "v=0\r\n" + "o=- 8621259572628890423 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "m=" + + std::string(audio_first ? "audio" : "video") + + " 0 UDP/TLS/RTP/SAVPF 111\r\n" + "c=IN IP4 0.0.0.0\r\n"; + auto rejected_answer = + CreateSessionDescription(SdpType::kAnswer, rejected_answer_sdp); + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(rejected_answer))); + + auto offer = + pc2->CreateOfferAndSetAsLocal(); // This will generate a mid=0 too + ASSERT_EQ(offer->description()->contents().size(), 1u); + auto mid2 = offer->description()->contents()[0].mid(); + EXPECT_EQ(mid1, mid2); // Check that the mids collided. + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(offer))); + auto answer = pc1->CreateAnswer(); + EXPECT_FALSE(pc1->SetLocalDescription(std::move(answer))); +} + +// Similar to the previous test but with implicit rollback and creating +// an offer, triggering a different codepath. +TEST_P(SdpOfferAnswerShuffleMediaTypes, + RecyclingWithDifferentKindAndSameMidFailsOffer) { + bool audio_first = GetParam(); + auto pc1 = CreatePeerConnection(); + auto pc2 = CreatePeerConnection(); + if (audio_first) { + pc1->AddAudioTrack("audio_track", {}); + pc2->AddVideoTrack("video_track", {}); + } else { + pc2->AddAudioTrack("audio_track", {}); + pc1->AddVideoTrack("video_track", {}); + } + + auto initial_offer = pc1->CreateOfferAndSetAsLocal(); + ASSERT_EQ(initial_offer->description()->contents().size(), 1u); + auto mid1 = initial_offer->description()->contents()[0].mid(); + std::string rejected_answer_sdp = + "v=0\r\n" + "o=- 8621259572628890423 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "m=" + + std::string(audio_first ? "audio" : "video") + + " 0 UDP/TLS/RTP/SAVPF 111\r\n" + "c=IN IP4 0.0.0.0\r\n"; + auto rejected_answer = + CreateSessionDescription(SdpType::kAnswer, rejected_answer_sdp); + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(rejected_answer))); + + auto offer = + pc2->CreateOfferAndSetAsLocal(); // This will generate a mid=0 too + ASSERT_EQ(offer->description()->contents().size(), 1u); + auto mid2 = offer->description()->contents()[0].mid(); + EXPECT_EQ(mid1, mid2); // Check that the mids collided. + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(offer))); + EXPECT_FALSE(pc1->CreateOffer()); +} + +INSTANTIATE_TEST_SUITE_P(SdpOfferAnswerShuffleMediaTypes, + SdpOfferAnswerShuffleMediaTypes, + ::testing::Values(true, false)); + } // namespace webrtc diff --git a/pc/session_description.h b/pc/session_description.h index 31992be083..403e46529f 100644 --- a/pc/session_description.h +++ b/pc/session_description.h @@ -43,10 +43,8 @@ namespace cricket { -typedef std::vector AudioCodecs; -typedef std::vector VideoCodecs; -typedef std::vector CryptoParamsVec; -typedef std::vector RtpHeaderExtensions; +using CryptoParamsVec = std::vector; +using RtpHeaderExtensions = std::vector; // Options to control how session descriptions are generated. const int kAutoBandwidth = -1; @@ -83,8 +81,6 @@ class MediaContentDescription { return nullptr; } - virtual bool has_codecs() const = 0; - // Copy operator that returns an unique_ptr. // Not a virtual function. // If a type-specific variant of Clone() is desired, override it, or @@ -234,54 +230,14 @@ class MediaContentDescription { receive_rids_ = rids; } - protected: - bool rtcp_mux_ = false; - bool rtcp_reduced_size_ = false; - bool remote_estimate_ = false; - int bandwidth_ = kAutoBandwidth; - std::string bandwidth_type_ = kApplicationSpecificBandwidth; - std::string protocol_; - std::vector cryptos_; - std::vector rtp_header_extensions_; - bool rtp_header_extensions_set_ = false; - StreamParamsVec send_streams_; - bool conference_mode_ = false; - webrtc::RtpTransceiverDirection direction_ = - webrtc::RtpTransceiverDirection::kSendRecv; - rtc::SocketAddress connection_address_; - ExtmapAllowMixed extmap_allow_mixed_enum_ = kMedia; - - SimulcastDescription simulcast_; - std::vector receive_rids_; - - private: - // Copy function that returns a raw pointer. Caller will assert ownership. - // Should only be called by the Clone() function. Must be implemented - // by each final subclass. - virtual MediaContentDescription* CloneInternal() const = 0; -}; - -template -class MediaContentDescriptionImpl : public MediaContentDescription { - public: - void set_protocol(absl::string_view protocol) override { - RTC_DCHECK(IsRtpProtocol(protocol)); - protocol_ = std::string(protocol); - } - // Codecs should be in preference order (most preferred codec first). const std::vector& codecs() const { return codecs_; } void set_codecs(const std::vector& codecs) { codecs_ = codecs; } - bool has_codecs() const override { return !codecs_.empty(); } + virtual bool has_codecs() const { return !codecs_.empty(); } bool HasCodec(int id) { - bool found = false; - for (auto it = codecs_.begin(); it != codecs_.end(); ++it) { - if (it->id == id) { - found = true; - break; - } - } - return found; + return absl::c_find_if(codecs_, [id](const cricket::Codec codec) { + return codec.id == id; + }) != codecs_.end(); } void AddCodec(const Codec& codec) { codecs_.push_back(codec); } void AddOrReplaceCodec(const Codec& codec) { @@ -299,32 +255,70 @@ class MediaContentDescriptionImpl : public MediaContentDescription { } } + protected: + // TODO(bugs.webrtc.org/15214): move all RTP related things to + // RtpMediaDescription that the SCTP content description does + // not inherit from. + std::string protocol_; + private: + bool rtcp_mux_ = false; + bool rtcp_reduced_size_ = false; + bool remote_estimate_ = false; + int bandwidth_ = kAutoBandwidth; + std::string bandwidth_type_ = kApplicationSpecificBandwidth; + + std::vector cryptos_; + std::vector rtp_header_extensions_; + bool rtp_header_extensions_set_ = false; + StreamParamsVec send_streams_; + bool conference_mode_ = false; + webrtc::RtpTransceiverDirection direction_ = + webrtc::RtpTransceiverDirection::kSendRecv; + rtc::SocketAddress connection_address_; + ExtmapAllowMixed extmap_allow_mixed_enum_ = kMedia; + + SimulcastDescription simulcast_; + std::vector receive_rids_; + + // Copy function that returns a raw pointer. Caller will assert ownership. + // Should only be called by the Clone() function. Must be implemented + // by each final subclass. + virtual MediaContentDescription* CloneInternal() const = 0; + std::vector codecs_; }; -class AudioContentDescription : public MediaContentDescriptionImpl { - public: - AudioContentDescription() {} +class RtpMediaContentDescription : public MediaContentDescription {}; - virtual MediaType type() const { return MEDIA_TYPE_AUDIO; } - virtual AudioContentDescription* as_audio() { return this; } - virtual const AudioContentDescription* as_audio() const { return this; } +class AudioContentDescription : public RtpMediaContentDescription { + public: + void set_protocol(absl::string_view protocol) override { + RTC_DCHECK(IsRtpProtocol(protocol)); + protocol_ = std::string(protocol); + } + MediaType type() const override { return MEDIA_TYPE_AUDIO; } + AudioContentDescription* as_audio() override { return this; } + const AudioContentDescription* as_audio() const override { return this; } private: - virtual AudioContentDescription* CloneInternal() const { + AudioContentDescription* CloneInternal() const override { return new AudioContentDescription(*this); } }; -class VideoContentDescription : public MediaContentDescriptionImpl { +class VideoContentDescription : public RtpMediaContentDescription { public: - virtual MediaType type() const { return MEDIA_TYPE_VIDEO; } - virtual VideoContentDescription* as_video() { return this; } - virtual const VideoContentDescription* as_video() const { return this; } + void set_protocol(absl::string_view protocol) override { + RTC_DCHECK(IsRtpProtocol(protocol)); + protocol_ = std::string(protocol); + } + MediaType type() const override { return MEDIA_TYPE_VIDEO; } + VideoContentDescription* as_video() override { return this; } + const VideoContentDescription* as_video() const override { return this; } private: - virtual VideoContentDescription* CloneInternal() const { + VideoContentDescription* CloneInternal() const override { return new VideoContentDescription(*this); } }; diff --git a/pc/sdp_serializer.cc b/pc/simulcast_sdp_serializer.cc similarity index 97% rename from pc/sdp_serializer.cc rename to pc/simulcast_sdp_serializer.cc index 31c624b12c..ceb2881550 100644 --- a/pc/sdp_serializer.cc +++ b/pc/simulcast_sdp_serializer.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "pc/sdp_serializer.h" +#include "pc/simulcast_sdp_serializer.h" #include #include @@ -181,7 +181,7 @@ webrtc::RTCError ParseRidPayloadList(const std::string& payload_list, } // namespace -std::string SdpSerializer::SerializeSimulcastDescription( +std::string SimulcastSdpSerializer::SerializeSimulcastDescription( const cricket::SimulcastDescription& simulcast) const { rtc::StringBuilder sb; std::string delimiter; @@ -210,7 +210,8 @@ std::string SdpSerializer::SerializeSimulcastDescription( // sc-id-paused = "~" // sc-id = [sc-id-paused] rid-id // rid-id = 1*(alpha-numeric / "-" / "_") ; see: I-D.ietf-mmusic-rid -RTCErrorOr SdpSerializer::DeserializeSimulcastDescription( +RTCErrorOr +SimulcastSdpSerializer::DeserializeSimulcastDescription( absl::string_view string) const { std::vector tokens; rtc::tokenize(std::string(string), kDelimiterSpaceChar, &tokens); @@ -264,7 +265,7 @@ RTCErrorOr SdpSerializer::DeserializeSimulcastDescription( return std::move(simulcast); } -std::string SdpSerializer::SerializeRidDescription( +std::string SimulcastSdpSerializer::SerializeRidDescription( const RidDescription& rid_description) const { RTC_DCHECK(!rid_description.rid.empty()); RTC_DCHECK(rid_description.direction == RidDirection::kSend || @@ -319,7 +320,7 @@ std::string SdpSerializer::SerializeRidDescription( // rid-param = 1*(alpha-numeric / "-") [ "=" param-val ] // param-val = *( %x20-58 / %x60-7E ) // ; Any printable character except semicolon -RTCErrorOr SdpSerializer::DeserializeRidDescription( +RTCErrorOr SimulcastSdpSerializer::DeserializeRidDescription( absl::string_view string) const { std::vector tokens; rtc::tokenize(std::string(string), kDelimiterSpaceChar, &tokens); diff --git a/pc/sdp_serializer.h b/pc/simulcast_sdp_serializer.h similarity index 86% rename from pc/sdp_serializer.h rename to pc/simulcast_sdp_serializer.h index 559fac0e37..4811e5272d 100644 --- a/pc/sdp_serializer.h +++ b/pc/simulcast_sdp_serializer.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef PC_SDP_SERIALIZER_H_ -#define PC_SDP_SERIALIZER_H_ +#ifndef PC_SIMULCAST_SDP_SERIALIZER_H_ +#define PC_SIMULCAST_SDP_SERIALIZER_H_ #include @@ -21,19 +21,19 @@ namespace webrtc { -// This class should serialize components of the SDP (and not the SDP itself). +// This class serializes simulcast components of the SDP. // Example: // SimulcastDescription can be serialized and deserialized by this class. // The serializer will know how to translate the data to spec-compliant // format without knowing about the SDP attribute details (a=simulcast:) // Usage: // Consider the SDP attribute for simulcast a=simulcast:. -// The SDP serializtion code (webrtcsdp.h) should use `SdpSerializer` to +// The SDP serializtion code (webrtc_sdp.h) should use `SdpSerializer` to // serialize and deserialize the section. // This class will allow testing the serialization of components without // having to serialize the entire SDP while hiding implementation details -// from callers of sdp serialization (webrtcsdp.h). -class SdpSerializer { +// from callers of sdp serialization (webrtc_sdp.h). +class SimulcastSdpSerializer { public: // Serialization for the Simulcast description according to // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-13#section-5.1 @@ -58,4 +58,4 @@ class SdpSerializer { } // namespace webrtc -#endif // PC_SDP_SERIALIZER_H_ +#endif // PC_SIMULCAST_SDP_SERIALIZER_H_ diff --git a/pc/sdp_serializer_unittest.cc b/pc/simulcast_sdp_serializer_unittest.cc similarity index 98% rename from pc/sdp_serializer_unittest.cc rename to pc/simulcast_sdp_serializer_unittest.cc index c907ecbd6c..50c89c8742 100644 --- a/pc/sdp_serializer_unittest.cc +++ b/pc/simulcast_sdp_serializer_unittest.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "pc/sdp_serializer.h" +#include "pc/simulcast_sdp_serializer.h" #include @@ -102,7 +102,7 @@ class SimulcastSdpSerializerTest : public TestWithParam { // `expected` - The expected output Simulcast to compare to. void TestDeserialization(const std::string& str, const SimulcastDescription& expected) const { - SdpSerializer deserializer; + SimulcastSdpSerializer deserializer; auto result = deserializer.DeserializeSimulcastDescription(str); EXPECT_TRUE(result.ok()); ExpectEqual(expected, result.value()); @@ -113,7 +113,7 @@ class SimulcastSdpSerializerTest : public TestWithParam { // `expected` - The expected output string to compare to. void TestSerialization(const SimulcastDescription& simulcast, const std::string& expected) const { - SdpSerializer serializer; + SimulcastSdpSerializer serializer; auto result = serializer.SerializeSimulcastDescription(simulcast); EXPECT_EQ(expected, result); } @@ -214,7 +214,7 @@ TEST_F(SimulcastSdpSerializerTest, Deserialize_PausedStreams) { // Parameterized negative test case for deserialization with invalid inputs. TEST_P(SimulcastSdpSerializerTest, SimulcastDeserializationFailed) { - SdpSerializer deserializer; + SimulcastSdpSerializer deserializer; auto result = deserializer.DeserializeSimulcastDescription(GetParam()); EXPECT_FALSE(result.ok()); } @@ -286,7 +286,7 @@ class RidDescriptionSdpSerializerTest : public TestWithParam { // `expected` - The expected output RidDescription to compare to. void TestDeserialization(const std::string& str, const RidDescription& expected) const { - SdpSerializer deserializer; + SimulcastSdpSerializer deserializer; auto result = deserializer.DeserializeRidDescription(str); EXPECT_TRUE(result.ok()); ExpectEqual(expected, result.value()); @@ -297,7 +297,7 @@ class RidDescriptionSdpSerializerTest : public TestWithParam { // `expected` - The expected output string to compare to. void TestSerialization(const RidDescription& rid_description, const std::string& expected) const { - SdpSerializer serializer; + SimulcastSdpSerializer serializer; auto result = serializer.SerializeRidDescription(rid_description); EXPECT_EQ(expected, result); } @@ -447,7 +447,7 @@ TEST_F(RidDescriptionSdpSerializerTest, Deserialize_AmbiguousCase) { // Parameterized negative test case for deserialization with invalid inputs. TEST_P(RidDescriptionSdpSerializerTest, RidDescriptionDeserializationFailed) { - SdpSerializer deserializer; + SimulcastSdpSerializer deserializer; auto result = deserializer.DeserializeRidDescription(GetParam()); EXPECT_FALSE(result.ok()); } diff --git a/pc/test/fake_peer_connection_base.h b/pc/test/fake_peer_connection_base.h index e51c687cc7..454a67ef5a 100644 --- a/pc/test/fake_peer_connection_base.h +++ b/pc/test/fake_peer_connection_base.h @@ -362,9 +362,6 @@ class FakePeerConnectionBase : public PeerConnectionInternal { return false; } - absl::optional GetDataMid() const override { - return absl::nullopt; - } RTCErrorOr> AddTransceiver( cricket::MediaType media_type, rtc::scoped_refptr track, @@ -381,14 +378,10 @@ class FakePeerConnectionBase : public PeerConnectionInternal { Call* call_ptr() override { return nullptr; } bool SrtpRequired() const override { return false; } - absl::optional SetupDataChannelTransport_n( - absl::string_view mid) override { - return absl::nullopt; + bool CreateDataChannelTransport(absl::string_view mid) override { + return false; } - void TeardownDataChannelTransport_n(RTCError error) override {} - void SetSctpDataInfo(absl::string_view mid, - absl::string_view transport_name) override {} - void ResetSctpDataInfo() override {} + void DestroyDataChannelTransport(RTCError error) override {} const FieldTrialsView& trials() const override { return field_trials_; } diff --git a/pc/test/integration_test_helpers.cc b/pc/test/integration_test_helpers.cc index 3f07c9e826..ede159d744 100644 --- a/pc/test/integration_test_helpers.cc +++ b/pc/test/integration_test_helpers.cc @@ -55,6 +55,13 @@ int FindFirstMediaStatsIndexByKind( return -1; } +void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc) { + stream.ssrcs[0] = ssrc; + for (auto& group : stream.ssrc_groups) { + group.ssrcs[0] = ssrc; + } +} + TaskQueueMetronome::TaskQueueMetronome(TimeDelta tick_period) : tick_period_(tick_period) {} diff --git a/pc/test/integration_test_helpers.h b/pc/test/integration_test_helpers.h index 43033d2a5c..36b2111324 100644 --- a/pc/test/integration_test_helpers.h +++ b/pc/test/integration_test_helpers.h @@ -173,6 +173,10 @@ void RemoveSsrcsAndMsids(cricket::SessionDescription* desc); // endpoint that only signals a=msid lines to convey stream_ids. void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc); +// Replaces the stream's primary SSRC and updates the first SSRC of all +// ssrc-groups. +void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc); + int FindFirstMediaStatsIndexByKind( const std::string& kind, const std::vector& inbound_rtps); diff --git a/pc/test/mock_peer_connection_internal.h b/pc/test/mock_peer_connection_internal.h index 58d13ede2f..5fd7a50b4f 100644 --- a/pc/test/mock_peer_connection_internal.h +++ b/pc/test/mock_peer_connection_internal.h @@ -248,7 +248,6 @@ class MockPeerConnectionInternal : public PeerConnectionInternal { (const cricket::SessionDescription*, (const std::map&)), (override)); - MOCK_METHOD(absl::optional, GetDataMid, (), (const, override)); MOCK_METHOD(RTCErrorOr>, AddTransceiver, (cricket::MediaType, @@ -263,16 +262,11 @@ class MockPeerConnectionInternal : public PeerConnectionInternal { (override)); MOCK_METHOD(Call*, call_ptr, (), (override)); MOCK_METHOD(bool, SrtpRequired, (), (const, override)); - MOCK_METHOD(absl::optional, - SetupDataChannelTransport_n, - (absl::string_view mid), + MOCK_METHOD(bool, + CreateDataChannelTransport, + (absl::string_view), (override)); - MOCK_METHOD(void, TeardownDataChannelTransport_n, (RTCError), (override)); - MOCK_METHOD(void, - SetSctpDataInfo, - (absl::string_view, absl::string_view), - (override)); - MOCK_METHOD(void, ResetSctpDataInfo, (), (override)); + MOCK_METHOD(void, DestroyDataChannelTransport, (RTCError error), (override)); MOCK_METHOD(const FieldTrialsView&, trials, (), (const, override)); // PeerConnectionInternal diff --git a/pc/transport_stats.h b/pc/transport_stats.h index e554385954..46dccc97f8 100644 --- a/pc/transport_stats.h +++ b/pc/transport_stats.h @@ -34,6 +34,7 @@ struct TransportChannelStats { absl::optional dtls_role; webrtc::DtlsTransportState dtls_state = webrtc::DtlsTransportState::kNew; IceTransportStats ice_transport_stats; + uint16_t ssl_peer_signature_algorithm = rtc::kSslSignatureAlgorithmUnknown; }; // Information about all the channels of a transport. diff --git a/pc/used_ids.h b/pc/used_ids.h index 1236a786df..6b342cbea8 100644 --- a/pc/used_ids.h +++ b/pc/used_ids.h @@ -96,6 +96,16 @@ class UsedPayloadTypes : public UsedIds { : UsedIds(kFirstDynamicPayloadTypeLowerRange, kLastDynamicPayloadTypeUpperRange) {} + // Check if a payload type is valid. The range [64-95] is forbidden + // when rtcp-mux is used. + static bool IsIdValid(Codec codec, bool rtcp_mux) { + if (rtcp_mux && (codec.id > kLastDynamicPayloadTypeLowerRange && + codec.id < kFirstDynamicPayloadTypeUpperRange)) { + return false; + } + return codec.id >= 0 && codec.id <= kLastDynamicPayloadTypeUpperRange; + } + protected: bool IsIdUsed(int new_id) override { // Range marked for RTCP avoidance is "used". diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc index 71cd18cfb6..2a3173cb02 100644 --- a/pc/webrtc_sdp.cc +++ b/pc/webrtc_sdp.cc @@ -54,9 +54,9 @@ #include "p2p/base/transport_info.h" #include "pc/media_protocol_names.h" #include "pc/media_session.h" -#include "pc/sdp_serializer.h" #include "pc/session_description.h" #include "pc/simulcast_description.h" +#include "pc/simulcast_sdp_serializer.h" #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" #include "rtc_base/helpers.h" @@ -1438,17 +1438,11 @@ void BuildMediaLine(const cricket::MediaType media_type, // fmt is a list of payload type numbers that MAY be used in the session. std::string type; std::string fmt; - if (media_type == cricket::MEDIA_TYPE_VIDEO) { - type = kMediaTypeVideo; - const VideoContentDescription* video_desc = media_desc->as_video(); - for (const cricket::VideoCodec& codec : video_desc->codecs()) { - fmt.append(" "); - fmt.append(rtc::ToString(codec.id)); - } - } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { - type = kMediaTypeAudio; - const AudioContentDescription* audio_desc = media_desc->as_audio(); - for (const cricket::AudioCodec& codec : audio_desc->codecs()) { + if (media_type == cricket::MEDIA_TYPE_AUDIO || + media_type == cricket::MEDIA_TYPE_VIDEO) { + type = media_type == cricket::MEDIA_TYPE_AUDIO ? kMediaTypeAudio + : kMediaTypeVideo; + for (const cricket::Codec& codec : media_desc->codecs()) { fmt.append(" "); fmt.append(rtc::ToString(codec.id)); } @@ -1601,7 +1595,7 @@ void BuildRtpContentAttributes(const MediaContentDescription* media_desc, const cricket::MediaType media_type, int msid_signaling, std::string* message) { - SdpSerializer serializer; + SimulcastSdpSerializer serializer; rtc::StringBuilder os; // RFC 8285 // a=extmap-allow-mixed @@ -1867,8 +1861,7 @@ bool WriteFmtpParameters(const cricket::CodecParameterMap& parameters, return !empty; } -template -void AddFmtpLine(const T& codec, std::string* message) { +void AddFmtpLine(const cricket::Codec& codec, std::string* message) { rtc::StringBuilder os; WriteFmtpHeader(codec.id, &os); os << kSdpDelimiterSpace; @@ -1879,8 +1872,7 @@ void AddFmtpLine(const T& codec, std::string* message) { return; } -template -void AddPacketizationLine(const T& codec, std::string* message) { +void AddPacketizationLine(const cricket::Codec& codec, std::string* message) { if (!codec.packetization) { return; } @@ -1890,8 +1882,7 @@ void AddPacketizationLine(const T& codec, std::string* message) { AddLine(os.str(), message); } -template -void AddRtcpFbLines(const T& codec, std::string* message) { +void AddRtcpFbLines(const cricket::Codec& codec, std::string* message) { for (const cricket::FeedbackParam& param : codec.feedback_params.params()) { rtc::StringBuilder os; WriteRtcpFbHeader(codec.id, &os); @@ -1932,7 +1923,7 @@ void BuildRtpmap(const MediaContentDescription* media_desc, RTC_DCHECK(media_desc != NULL); rtc::StringBuilder os; if (media_type == cricket::MEDIA_TYPE_VIDEO) { - for (const cricket::VideoCodec& codec : media_desc->as_video()->codecs()) { + for (const cricket::Codec& codec : media_desc->codecs()) { // RFC 4566 // a=rtpmap: / // [/] @@ -1950,7 +1941,7 @@ void BuildRtpmap(const MediaContentDescription* media_desc, std::vector ptimes; std::vector maxptimes; int max_minptime = 0; - for (const cricket::AudioCodec& codec : media_desc->as_audio()->codecs()) { + for (const cricket::Codec& codec : media_desc->codecs()) { RTC_DCHECK(!codec.name.empty()); // RFC 4566 // a=rtpmap: / @@ -2607,7 +2598,7 @@ static const StaticPayloadAudioCodec kStaticPayloadAudioCodecs[] = { }; void MaybeCreateStaticPayloadAudioCodecs(const std::vector& fmts, - AudioContentDescription* media_desc) { + MediaContentDescription* media_desc) { if (!media_desc) { return; } @@ -2625,8 +2616,7 @@ void MaybeCreateStaticPayloadAudioCodecs(const std::vector& fmts, } } -template -static std::unique_ptr ParseContentDescription( +static std::unique_ptr ParseContentDescription( absl::string_view message, const cricket::MediaType media_type, int mline_index, @@ -2639,7 +2629,16 @@ static std::unique_ptr ParseContentDescription( TransportDescription* transport, std::vector>* candidates, webrtc::SdpParseError* error) { - auto media_desc = std::make_unique(); + std::unique_ptr media_desc; + if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) { + media_desc = std::make_unique(); + } else if (media_type == cricket::MediaType::MEDIA_TYPE_VIDEO) { + media_desc = std::make_unique(); + } else { + RTC_DCHECK_NOTREACHED(); + return nullptr; + } + media_desc->set_extmap_allow_mixed_enum(MediaContentDescription::kNo); if (!ParseContent(message, media_type, mline_index, protocol, payload_types, pos, content_name, bundle_only, msid_signaling, @@ -2734,12 +2733,12 @@ bool ParseMediaDescription( return ParseFailed(*mline, "Unsupported protocol for media type", error); } if (media_type == kMediaTypeVideo) { - content = ParseContentDescription( + content = ParseContentDescription( message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol, payload_types, pos, &content_name, &bundle_only, §ion_msid_signaling, &transport, candidates, error); } else if (media_type == kMediaTypeAudio) { - content = ParseContentDescription( + content = ParseContentDescription( message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol, payload_types, pos, &content_name, &bundle_only, §ion_msid_signaling, &transport, candidates, error); @@ -2857,21 +2856,6 @@ bool ParseMediaDescription( return true; } -bool VerifyCodec(const cricket::Codec& codec) { - // Codec has not been populated correctly unless the name has been set. This - // can happen if an SDP has an fmtp or rtcp-fb with a payload type but doesn't - // have a corresponding "rtpmap" line. - return !codec.name.empty(); -} - -bool VerifyAudioCodecs(const AudioContentDescription* audio_desc) { - return absl::c_all_of(audio_desc->codecs(), &VerifyCodec); -} - -bool VerifyVideoCodecs(const VideoContentDescription* video_desc) { - return absl::c_all_of(video_desc->codecs(), &VerifyCodec); -} - void AddParameters(const cricket::CodecParameterMap& parameters, cricket::Codec* codec) { for (const auto& entry : parameters) { @@ -2896,11 +2880,11 @@ void AddFeedbackParameters(const cricket::FeedbackParams& feedback_params, // Gets the current codec setting associated with `payload_type`. If there // is no Codec associated with that payload type it returns an empty codec // with that payload type. -template -T GetCodecWithPayloadType(cricket::MediaType type, - const std::vector& codecs, - int payload_type) { - const T* codec = FindCodecById(codecs, payload_type); +cricket::Codec GetCodecWithPayloadType( + cricket::MediaType type, + const std::vector& codecs, + int payload_type) { + const cricket::Codec* codec = FindCodecById(codecs, payload_type); if (codec) return *codec; // Return empty codec with `payload_type`. @@ -2912,12 +2896,11 @@ T GetCodecWithPayloadType(cricket::MediaType type, } // Updates or creates a new codec entry in the media description. -template -void AddOrReplaceCodec(MediaContentDescription* content_desc, const U& codec) { - T* desc = static_cast(content_desc); - std::vector codecs = desc->codecs(); +void AddOrReplaceCodec(MediaContentDescription* content_desc, + const cricket::Codec& codec) { + std::vector codecs = content_desc->codecs(); bool found = false; - for (U& existing_codec : codecs) { + for (cricket::Codec& existing_codec : codecs) { if (codec.id == existing_codec.id) { // Overwrite existing codec with the new codec. existing_codec = codec; @@ -2926,43 +2909,39 @@ void AddOrReplaceCodec(MediaContentDescription* content_desc, const U& codec) { } } if (!found) { - desc->AddCodec(codec); + content_desc->AddCodec(codec); return; } - desc->set_codecs(codecs); + content_desc->set_codecs(codecs); } // Adds or updates existing codec corresponding to `payload_type` according // to `parameters`. -template void UpdateCodec(MediaContentDescription* content_desc, int payload_type, const cricket::CodecParameterMap& parameters) { // Codec might already have been populated (from rtpmap). - U new_codec = GetCodecWithPayloadType(content_desc->type(), - static_cast(content_desc)->codecs(), - payload_type); + cricket::Codec new_codec = GetCodecWithPayloadType( + content_desc->type(), content_desc->codecs(), payload_type); AddParameters(parameters, &new_codec); - AddOrReplaceCodec(content_desc, new_codec); + AddOrReplaceCodec(content_desc, new_codec); } // Adds or updates existing codec corresponding to `payload_type` according // to `feedback_param`. -template void UpdateCodec(MediaContentDescription* content_desc, int payload_type, const cricket::FeedbackParam& feedback_param) { // Codec might already have been populated (from rtpmap). - U new_codec = GetCodecWithPayloadType(content_desc->type(), - static_cast(content_desc)->codecs(), - payload_type); + cricket::Codec new_codec = GetCodecWithPayloadType( + content_desc->type(), content_desc->codecs(), payload_type); AddFeedbackParameter(feedback_param, &new_codec); - AddOrReplaceCodec(content_desc, new_codec); + AddOrReplaceCodec(content_desc, new_codec); } // Adds or updates existing video codec corresponding to `payload_type` // according to `packetization`. -void UpdateVideoCodecPacketization(VideoContentDescription* video_desc, +void UpdateVideoCodecPacketization(MediaContentDescription* desc, int payload_type, absl::string_view packetization) { if (packetization != cricket::kPacketizationParamRaw) { @@ -2971,18 +2950,18 @@ void UpdateVideoCodecPacketization(VideoContentDescription* video_desc, } // Codec might already have been populated (from rtpmap). - cricket::VideoCodec codec = GetCodecWithPayloadType( - video_desc->type(), video_desc->codecs(), payload_type); + cricket::Codec codec = + GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type); codec.packetization = std::string(packetization); - AddOrReplaceCodec(video_desc, - codec); + AddOrReplaceCodec(desc, codec); } -template -absl::optional PopWildcardCodec(std::vector* codecs) { +absl::optional PopWildcardCodec( + std::vector* codecs) { + RTC_DCHECK(codecs); for (auto iter = codecs->begin(); iter != codecs->end(); ++iter) { if (iter->id == kWildcardPayloadType) { - T wildcard_codec = *iter; + cricket::Codec wildcard_codec = *iter; codecs->erase(iter); return wildcard_codec; } @@ -2990,10 +2969,10 @@ absl::optional PopWildcardCodec(std::vector* codecs) { return absl::nullopt; } -template -void UpdateFromWildcardCodecs(cricket::MediaContentDescriptionImpl* desc) { +void UpdateFromWildcardCodecs(cricket::MediaContentDescription* desc) { + RTC_DCHECK(desc); auto codecs = desc->codecs(); - absl::optional wildcard_codec = PopWildcardCodec(&codecs); + absl::optional wildcard_codec = PopWildcardCodec(&codecs); if (!wildcard_codec) { return; } @@ -3005,15 +2984,16 @@ void UpdateFromWildcardCodecs(cricket::MediaContentDescriptionImpl* desc) { void AddAudioAttribute(const std::string& name, absl::string_view value, - AudioContentDescription* audio_desc) { + MediaContentDescription* desc) { + RTC_DCHECK(desc); if (value.empty()) { return; } - std::vector codecs = audio_desc->codecs(); - for (cricket::AudioCodec& codec : codecs) { + std::vector codecs = desc->codecs(); + for (cricket::Codec& codec : codecs) { codec.params[name] = std::string(value); } - audio_desc->set_codecs(codecs); + desc->set_codecs(codecs); } bool ParseContent(absl::string_view message, @@ -3034,7 +3014,7 @@ bool ParseContent(absl::string_view message, RTC_DCHECK(transport != NULL); if (media_type == cricket::MEDIA_TYPE_AUDIO) { - MaybeCreateStaticPayloadAudioCodecs(payload_types, media_desc->as_audio()); + MaybeCreateStaticPayloadAudioCodecs(payload_types, media_desc); } // The media level "ice-ufrag" and "ice-pwd". @@ -3049,7 +3029,7 @@ bool ParseContent(absl::string_view message, std::string ptime_as_string; std::vector stream_ids; std::string track_id; - SdpSerializer deserializer; + SimulcastSdpSerializer deserializer; std::vector rids; SimulcastDescription simulcast; @@ -3415,27 +3395,18 @@ bool ParseContent(absl::string_view message, media_desc->AddStream(track); } - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - AudioContentDescription* audio_desc = media_desc->as_audio(); - UpdateFromWildcardCodecs(audio_desc); - - // Verify audio codec ensures that no audio codec has been populated with - // only fmtp. - if (!VerifyAudioCodecs(audio_desc)) { - return ParseFailed("Failed to parse audio codecs correctly.", error); - } - AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, audio_desc); - AddAudioAttribute(kCodecParamPTime, ptime_as_string, audio_desc); + UpdateFromWildcardCodecs(media_desc); + // Codec has not been populated correctly unless the name has been set. This + // can happen if an SDP has an fmtp or rtcp-fb with a payload type but doesn't + // have a corresponding "rtpmap" line. This should lead to a parse error. + if (!absl::c_all_of(media_desc->codecs(), [](const cricket::Codec codec) { + return !codec.name.empty(); + })) { + return ParseFailed("Failed to parse codecs correctly.", error); } - - if (media_type == cricket::MEDIA_TYPE_VIDEO) { - VideoContentDescription* video_desc = media_desc->as_video(); - UpdateFromWildcardCodecs(video_desc); - // Verify video codec ensures that no video codec has been populated with - // only rtcp-fb. - if (!VerifyVideoCodecs(video_desc)) { - return ParseFailed("Failed to parse video codecs correctly.", error); - } + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, media_desc); + AddAudioAttribute(kCodecParamPTime, ptime_as_string, media_desc); } // RFC 5245 @@ -3598,31 +3569,29 @@ void UpdateCodec(int payload_type, int clockrate, int bitrate, size_t channels, - AudioContentDescription* audio_desc) { + MediaContentDescription* desc) { // Codec may already be populated with (only) optional parameters // (from an fmtp). - cricket::AudioCodec codec = GetCodecWithPayloadType( - audio_desc->type(), audio_desc->codecs(), payload_type); + cricket::Codec codec = + GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type); codec.name = std::string(name); codec.clockrate = clockrate; codec.bitrate = bitrate; codec.channels = channels; - AddOrReplaceCodec(audio_desc, - codec); + AddOrReplaceCodec(desc, codec); } // Updates or creates a new codec entry in the video description according to // `name`, `width`, `height`, and `framerate`. void UpdateCodec(int payload_type, absl::string_view name, - VideoContentDescription* video_desc) { + MediaContentDescription* desc) { // Codec may already be populated with (only) optional parameters // (from an fmtp). - cricket::VideoCodec codec = GetCodecWithPayloadType( - video_desc->type(), video_desc->codecs(), payload_type); + cricket::Codec codec = + GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type); codec.name = std::string(name); - AddOrReplaceCodec(video_desc, - codec); + AddOrReplaceCodec(desc, codec); } bool ParseRtpmapAttribute(absl::string_view line, @@ -3671,8 +3640,7 @@ bool ParseRtpmapAttribute(absl::string_view line, } if (media_type == cricket::MEDIA_TYPE_VIDEO) { - VideoContentDescription* video_desc = media_desc->as_video(); - for (const cricket::VideoCodec& existing_codec : video_desc->codecs()) { + for (const cricket::VideoCodec& existing_codec : media_desc->codecs()) { if (!existing_codec.name.empty() && payload_type == existing_codec.id && (!absl::EqualsIgnoreCase(encoding_name, existing_codec.name) || clock_rate != existing_codec.clockrate)) { @@ -3686,7 +3654,7 @@ bool ParseRtpmapAttribute(absl::string_view line, return ParseFailed(line, description.Release(), error); } } - UpdateCodec(payload_type, encoding_name, video_desc); + UpdateCodec(payload_type, encoding_name, media_desc); } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { // RFC 4566 // For audio streams, indicates the number @@ -3703,8 +3671,7 @@ bool ParseRtpmapAttribute(absl::string_view line, return ParseFailed(line, "At most 24 channels are supported.", error); } - AudioContentDescription* audio_desc = media_desc->as_audio(); - for (const cricket::AudioCodec& existing_codec : audio_desc->codecs()) { + for (const cricket::AudioCodec& existing_codec : media_desc->codecs()) { // TODO(crbug.com/1338902) re-add checks for clockrate and number of // channels. if (!existing_codec.name.empty() && payload_type == existing_codec.id && @@ -3720,7 +3687,7 @@ bool ParseRtpmapAttribute(absl::string_view line, } } UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels, - audio_desc); + media_desc); } return true; } @@ -3791,12 +3758,9 @@ bool ParseFmtpAttributes(absl::string_view line, codec_params[name] = value; } - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - UpdateCodec( - media_desc, payload_type, codec_params); - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - UpdateCodec( - media_desc, payload_type, codec_params); + if (media_type == cricket::MEDIA_TYPE_AUDIO || + media_type == cricket::MEDIA_TYPE_VIDEO) { + UpdateCodec(media_desc, payload_type, codec_params); } return true; } @@ -3824,8 +3788,7 @@ bool ParsePacketizationAttribute(absl::string_view line, return false; } absl::string_view packetization = packetization_fields[1]; - UpdateVideoCodecPacketization(media_desc->as_video(), payload_type, - packetization); + UpdateVideoCodecPacketization(media_desc, payload_type, packetization); return true; } @@ -3862,12 +3825,9 @@ bool ParseRtcpFbAttribute(absl::string_view line, } const cricket::FeedbackParam feedback_param(id, param); - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - UpdateCodec( - media_desc, payload_type, feedback_param); - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - UpdateCodec( - media_desc, payload_type, feedback_param); + if (media_type == cricket::MEDIA_TYPE_AUDIO || + media_type == cricket::MEDIA_TYPE_VIDEO) { + UpdateCodec(media_desc, payload_type, feedback_param); } return true; } diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc index 1c0c4dde94..2c43c35d15 100644 --- a/pc/webrtc_sdp_unittest.cc +++ b/pc/webrtc_sdp_unittest.cc @@ -55,7 +55,6 @@ #endif #include "pc/webrtc_sdp.h" -using cricket::AudioCodec; using cricket::AudioContentDescription; using cricket::Candidate; using cricket::ContentGroup; @@ -77,7 +76,6 @@ using cricket::StreamParams; using cricket::STUN_PORT_TYPE; using cricket::TransportDescription; using cricket::TransportInfo; -using cricket::VideoCodec; using cricket::VideoContentDescription; using ::testing::ElementsAre; using ::testing::Field; @@ -91,9 +89,6 @@ using webrtc::SdpParseError; using webrtc::SdpType; using webrtc::SessionDescriptionInterface; -typedef std::vector AudioCodecs; -typedef std::vector Candidates; - static const uint32_t kDefaultSctpPort = 5000; static const uint16_t kUnusualSctpPort = 9556; static const char kSessionTime[] = "t=0 0\r\n"; @@ -1885,7 +1880,7 @@ class WebRtcSdpTest : public ::testing::Test { GetFirstAudioContentDescription(jdesc_output->description()); ASSERT_TRUE(acd); ASSERT_FALSE(acd->codecs().empty()); - cricket::AudioCodec opus = acd->codecs()[0]; + cricket::Codec opus = acd->codecs()[0]; EXPECT_EQ("opus", opus.name); EXPECT_EQ(111, opus.id); VerifyCodecParameter(opus.params, "minptime", params.min_ptime); @@ -1894,13 +1889,12 @@ class WebRtcSdpTest : public ::testing::Test { VerifyCodecParameter(opus.params, "useinbandfec", params.useinband); VerifyCodecParameter(opus.params, "maxaveragebitrate", params.maxaveragebitrate); - for (size_t i = 0; i < acd->codecs().size(); ++i) { - cricket::AudioCodec codec = acd->codecs()[i]; + for (const auto& codec : acd->codecs()) { VerifyCodecParameter(codec.params, "ptime", params.ptime); VerifyCodecParameter(codec.params, "maxptime", params.max_ptime); } - cricket::AudioCodec dtmf = acd->codecs()[3]; + cricket::Codec dtmf = acd->codecs()[3]; EXPECT_EQ("telephone-event", dtmf.name); EXPECT_EQ(105, dtmf.id); EXPECT_EQ(3u, @@ -1958,7 +1952,7 @@ class WebRtcSdpTest : public ::testing::Test { GetFirstAudioContentDescription(jdesc_output->description()); ASSERT_TRUE(acd); ASSERT_FALSE(acd->codecs().empty()); - cricket::AudioCodec opus = acd->codecs()[0]; + cricket::Codec opus = acd->codecs()[0]; EXPECT_EQ(111, opus.id); EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam( cricket::kRtcpFbParamNack, cricket::kParamValueEmpty))); @@ -2013,7 +2007,7 @@ class WebRtcSdpTest : public ::testing::Test { AudioContentDescription* audio_desc_; VideoContentDescription* video_desc_; SctpDataContentDescription* sctp_desc_; - Candidates candidates_; + std::vector candidates_; std::unique_ptr jcandidate_; JsepSessionDescription jdesc_; }; @@ -2432,7 +2426,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) { EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc)); cricket::AudioContentDescription* audio = cricket::GetFirstAudioContentDescription(jdesc.description()); - AudioCodecs ref_codecs; + cricket::AudioCodecs ref_codecs; // The codecs in the AudioContentDescription should be in the same order as // the payload types (s) on the m= line. ref_codecs.push_back(cricket::CreateAudioCodec(0, "PCMU", 8000, 1)); @@ -2456,7 +2450,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) { cricket::AudioContentDescription* audio = cricket::GetFirstAudioContentDescription(jdesc.description()); - cricket::AudioCodec g729 = audio->codecs()[0]; + cricket::Codec g729 = audio->codecs()[0]; EXPECT_EQ("G729", g729.name); EXPECT_EQ(8000, g729.clockrate); EXPECT_EQ(18, g729.id); @@ -2464,7 +2458,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) { ASSERT_TRUE(found != g729.params.end()); EXPECT_EQ(found->second, "yes"); - cricket::AudioCodec isac = audio->codecs()[1]; + cricket::Codec isac = audio->codecs()[1]; EXPECT_EQ("ISAC", isac.name); EXPECT_EQ(103, isac.id); EXPECT_EQ(16000, isac.clockrate); @@ -3405,7 +3399,7 @@ TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) { GetFirstAudioContentDescription(jdesc_output.description()); ASSERT_TRUE(acd); ASSERT_THAT(acd->codecs(), testing::SizeIs(1)); - cricket::AudioCodec opus = acd->codecs()[0]; + cricket::Codec opus = acd->codecs()[0]; EXPECT_EQ(opus.name, "opus"); EXPECT_EQ(opus.id, 111); @@ -3483,7 +3477,7 @@ TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) { AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_); cricket::AudioCodecs codecs = acd->codecs(); - cricket::AudioCodec dtmf = + cricket::Codec dtmf = cricket::CreateAudioCodec(105, "telephone-event", 8000, 1); dtmf.params[""] = "0-15"; codecs.push_back(dtmf); @@ -5083,3 +5077,27 @@ TEST_F(WebRtcSdpTest, RejectDuplicateSsrcInSsrcGroup) { JsepSessionDescription jdesc(kDummyType); EXPECT_FALSE(SdpDeserialize(sdp, &jdesc)); } + +TEST_F(WebRtcSdpTest, ExpectsTLineBeforeAttributeLine) { + // https://www.rfc-editor.org/rfc/rfc4566#page-9 + // says a= attributes must come last. + std::string sdp = + "v=0\r\n" + "o=- 0 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "a=thisisnottherightplace\r\n" + "t=0 0\r\n"; + JsepSessionDescription jdesc(kDummyType); + EXPECT_FALSE(SdpDeserialize(sdp, &jdesc)); +} + +TEST_F(WebRtcSdpTest, IgnoresUnknownAttributeLines) { + std::string sdp = + "v=0\r\n" + "o=- 0 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=somethingthatisnotunderstood\r\n"; + JsepSessionDescription jdesc(kDummyType); + EXPECT_TRUE(SdpDeserialize(sdp, &jdesc)); +} diff --git a/pc/webrtc_session_description_factory.cc b/pc/webrtc_session_description_factory.cc index 3d398e3b6e..42a8da3e70 100644 --- a/pc/webrtc_session_description_factory.cc +++ b/pc/webrtc_session_description_factory.cc @@ -194,15 +194,15 @@ void WebRtcSessionDescriptionFactory::CreateOffer( std::string error = "CreateOffer"; if (certificate_request_state_ == CERTIFICATE_FAILED) { error += kFailedDueToIdentityFailed; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } if (!ValidMediaSessionOptions(session_options)) { error += " called with invalid session options"; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } @@ -223,27 +223,27 @@ void WebRtcSessionDescriptionFactory::CreateAnswer( std::string error = "CreateAnswer"; if (certificate_request_state_ == CERTIFICATE_FAILED) { error += kFailedDueToIdentityFailed; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } if (!sdp_info_->remote_description()) { error += " can't be called before SetRemoteDescription."; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } if (sdp_info_->remote_description()->GetType() != SdpType::kOffer) { error += " failed because remote_description is not an offer."; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } if (!ValidMediaSessionOptions(session_options)) { error += " called with invalid session options."; - RTC_LOG(LS_ERROR) << error; - PostCreateSessionDescriptionFailed(observer, error); + PostCreateSessionDescriptionFailed( + observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); return; } @@ -280,16 +280,16 @@ void WebRtcSessionDescriptionFactory::InternalCreateOffer( } } - std::unique_ptr desc = - session_desc_factory_.CreateOffer( - request.options, sdp_info_->local_description() - ? sdp_info_->local_description()->description() - : nullptr); - if (!desc) { - PostCreateSessionDescriptionFailed(request.observer.get(), - "Failed to initialize the offer."); + auto result = session_desc_factory_.CreateOfferOrError( + request.options, sdp_info_->local_description() + ? sdp_info_->local_description()->description() + : nullptr); + if (!result.ok()) { + PostCreateSessionDescriptionFailed(request.observer.get(), result.error()); return; } + std::unique_ptr desc = std::move(result.value()); + RTC_CHECK(desc); // RFC 3264 // When issuing an offer that modifies the session, @@ -338,20 +338,20 @@ void WebRtcSessionDescriptionFactory::InternalCreateAnswer( } } - std::unique_ptr desc = - session_desc_factory_.CreateAnswer( - sdp_info_->remote_description() - ? sdp_info_->remote_description()->description() - : nullptr, - request.options, - sdp_info_->local_description() - ? sdp_info_->local_description()->description() - : nullptr); - if (!desc) { - PostCreateSessionDescriptionFailed(request.observer.get(), - "Failed to initialize the answer."); + auto result = session_desc_factory_.CreateAnswerOrError( + sdp_info_->remote_description() + ? sdp_info_->remote_description()->description() + : nullptr, + request.options, + sdp_info_->local_description() + ? sdp_info_->local_description()->description() + : nullptr); + if (!result.ok()) { + PostCreateSessionDescriptionFailed(request.observer.get(), result.error()); return; } + std::unique_ptr desc = std::move(result.value()); + RTC_CHECK(desc); // RFC 3264 // If the answer is different from the offer in any way (different IP @@ -387,24 +387,22 @@ void WebRtcSessionDescriptionFactory::FailPendingRequests( create_session_description_requests_.front(); PostCreateSessionDescriptionFailed( request.observer.get(), - ((request.type == CreateSessionDescriptionRequest::kOffer) - ? "CreateOffer" - : "CreateAnswer") + - reason); + RTCError(RTCErrorType::INTERNAL_ERROR, + ((request.type == CreateSessionDescriptionRequest::kOffer) + ? "CreateOffer" + : "CreateAnswer") + + reason)); create_session_description_requests_.pop(); } } void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed( CreateSessionDescriptionObserver* observer, - const std::string& error) { + RTCError error) { Post([observer = rtc::scoped_refptr(observer), - error]() mutable { - observer->OnFailure( - RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error))); - }); - RTC_LOG(LS_ERROR) << "Create SDP failed: " << error; + error]() mutable { observer->OnFailure(error); }); + RTC_LOG(LS_ERROR) << "CreateSessionDescription failed: " << error.message(); } void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded( diff --git a/pc/webrtc_session_description_factory.h b/pc/webrtc_session_description_factory.h index 122a720162..22ead41d9b 100644 --- a/pc/webrtc_session_description_factory.h +++ b/pc/webrtc_session_description_factory.h @@ -119,7 +119,7 @@ class WebRtcSessionDescriptionFactory { void FailPendingRequests(const std::string& reason); void PostCreateSessionDescriptionFailed( CreateSessionDescriptionObserver* observer, - const std::string& error); + RTCError error); void PostCreateSessionDescriptionSucceeded( CreateSessionDescriptionObserver* observer, std::unique_ptr description); diff --git a/pylintrc b/pylintrc index 852445a1ce..5f82b2c9ac 100644 --- a/pylintrc +++ b/pylintrc @@ -93,13 +93,13 @@ ignore-docstrings=yes [FORMAT] # Maximum number of characters on a single line. -max-line-length=80 +max-line-length=79 # Maximum number of lines in a module max-module-lines=1000 -# We use two spaces for indents, instead of the usual four spaces or tab. -indent-string=' ' +# Use four spaces for indents. +indent-string=' ' [BASIC] @@ -107,43 +107,29 @@ indent-string=' ' # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input -# Regular expression which should only match correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# Naming style matching correct module names. +module-naming-style=snake_case -# Regular expression which should only match correct module level names -# (CAPS_WITH_UNDER) -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE -# Regular expression which should only match correct class names -# (CapWords) -class-rgx=[A-Z_][a-zA-Z0-9]+$ +# Naming style matching correct class names. +class-naming-style=PascalCase -# Regular expression which should only match correct function names -# The Chromium standard is different than PEP-8, so we need to redefine this to -# only allow: -# - CapWords -# - main: Standard for main function. -function-rgx=([A-Z_][a-zA-Z0-9]{2,60}|main)$ +# Naming style matching correct function names. +function-naming-style=snake_case -# Regular expression which should only match correct method names -# The Chromium standard is different than PEP-8, so we need to redefine this to -# only allow: -# - CapWords, starting with a capital letter. No underscores in function -# names. Can also have a "_" prefix (private method) or a "test" prefix -# (unit test). -# - Methods that look like __xyz__, which are used to do things like -# __init__, __del__, etc. -# - setUp, tearDown: For unit tests. -method-rgx=((_|test)?[A-Z][a-zA-Z0-9]{2,60}|__[a-z]+__|setUp|tearDown)$ +# Regular expression matching correct method names. +method-rgx=([a-z_][a-z0-9_]{2,}|setUp|tearDown)$ -# Regular expression which should only match correct instance attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ +# Naming style matching correct attribute names. +attr-naming-style=snake_case -# Regular expression which should only match correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ +# Naming style matching correct argument names. +argument-naming-style=snake_case -# Regular expression which should only match correct variable names -variable-rgx=[a-z_][a-z0-9_]{0,30}$ +# Naming style matching correct variable names. +variable-naming-style=snake_case # Regular expression which should only match correct list comprehension / # generator expression variable names diff --git a/pylintrc_old_style b/pylintrc_old_style new file mode 100644 index 0000000000..69b599b2f6 --- /dev/null +++ b/pylintrc_old_style @@ -0,0 +1,216 @@ +# 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. + +# This file is mostly based on the contents of +# https://cs.chromium.org/chromium/tools/depot_tools/pylintrc +# and (since the above doesn't properly support naming style checks) +# https://cs.chromium.org/chromium/src/third_party/chromite/pylintrc + +[MESSAGES CONTROL] + +# Disable the message, report, category or checker with the given id(s). +# TODO(kjellander): Reduce this list to as small as possible. +disable= + E0611, + I0010, + I0011, + W0232, + C0413, + bad-continuation, + broad-except, + duplicate-code, + eval-used, + exec-used, + fixme, + import-error, + import-outside-toplevel, + missing-docstring, + no-init, + no-member, + too-few-public-methods, + too-many-ancestors, + too-many-arguments, + too-many-branches, + too-many-function-args, + too-many-instance-attributes, + too-many-lines, + too-many-locals, + too-many-public-methods, + too-many-return-statements, + too-many-statements, + + +[REPORTS] + +# Don't write out full reports, just messages. +reports=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=hashlib,numpy + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# Use four spaces for indents. +# indent-string=' ' + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +# (CAPS_WITH_UNDER) +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +# (CapWords) +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +# The Chromium standard is different than PEP-8, so we need to redefine this to +# only allow: +# - CapWords +# - main: Standard for main function. +function-rgx=([A-Z_][a-zA-Z0-9]{2,60}|main)$ + +# Regular expression which should only match correct method names +# The Chromium standard is different than PEP-8, so we need to redefine this to +# only allow: +# - CapWords, starting with a capital letter. No underscores in function +# names. Can also have a "_" prefix (private method) or a "test" prefix +# (unit test). +# - Methods that look like __xyz__, which are used to do things like +# __init__, __del__, etc. +# - setUp, tearDown: For unit tests. +method-rgx=((_|test)?[A-Z][a-zA-Z0-9]{2,60}|__[a-z]+__|setUp|tearDown)$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{0,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/resources/.gitignore b/resources/.gitignore index 1f729ae457..80580705f9 100644 --- a/resources/.gitignore +++ b/resources/.gitignore @@ -1,5 +1,6 @@ **/*.aecdump **/*.bin +**/*.binarypb **/*.byte **/*.chn **/*.dat diff --git a/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 b/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 new file mode 100644 index 0000000000..b190e48733 --- /dev/null +++ b/resources/rtc_event_log/rtc_event_log_500kbps.binarypb.sha1 @@ -0,0 +1 @@ +56e4ff9ea2b0fb92e88c7126f1df1283787ae0e5 \ No newline at end of file diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index 80ab5a6fe9..6abae807fe 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -525,7 +525,6 @@ rtc_library("rate_limiter") { ":macromagic", ":rate_statistics", "../system_wrappers", - "../system_wrappers:field_trial", "synchronization:mutex", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] @@ -856,8 +855,8 @@ config("rtc_json_suppressions") { } rtc_library("rtc_json") { + testonly = true public_configs = [ ":rtc_json_suppressions" ] - poisonous = [ "rtc_json" ] defines = [] sources = [ "strings/json.cc", @@ -940,6 +939,7 @@ rtc_library("async_dns_resolver") { "../api:make_ref_counted", "../api:sequence_checker", "../api/task_queue:pending_task_safety_flag", + "system:rtc_export", ] } @@ -1045,6 +1045,7 @@ rtc_library("threading") { "//third_party/abseil-cpp/absl/strings", ] deps = [ + ":async_dns_resolver", ":async_resolver_interface", ":byte_order", ":checks", @@ -1060,9 +1061,11 @@ rtc_library("threading") { ":refcount", ":rtc_event", ":rtc_task_queue", + ":socket", ":socket_address", ":socket_server", ":timeutils", + "../api:async_dns_resolver", "../api:function_view", "../api:location", "../api:refcountedbase", @@ -1960,7 +1963,6 @@ if (rtc_include_tests) { "../api/units:time_delta", "../api/units:timestamp", "../system_wrappers", - "../test:field_trial", "../test:fileutils", "../test:test_main", "../test:test_support", @@ -2138,7 +2140,7 @@ if (rtc_include_tests) { sources += [ "win32_unittest.cc" ] deps += [ ":win32" ] } - if (is_posix || is_fuchsia) { + if (is_posix || is_fuchsia || is_win) { sources += [ "openssl_adapter_unittest.cc", "openssl_session_cache_unittest.cc", diff --git a/rtc_base/async_dns_resolver.h b/rtc_base/async_dns_resolver.h index c15af7a1cb..288751efa4 100644 --- a/rtc_base/async_dns_resolver.h +++ b/rtc_base/async_dns_resolver.h @@ -16,6 +16,7 @@ #include "api/sequence_checker.h" #include "api/task_queue/pending_task_safety_flag.h" #include "rtc_base/ref_counted_object.h" +#include "rtc_base/system/rtc_export.h" #include "rtc_base/thread_annotations.h" namespace webrtc { @@ -37,7 +38,7 @@ class AsyncDnsResolverResultImpl : public AsyncDnsResolverResult { int error_ RTC_GUARDED_BY(sequence_checker_); }; -class AsyncDnsResolver : public AsyncDnsResolverInterface { +class RTC_EXPORT AsyncDnsResolver : public AsyncDnsResolverInterface { public: AsyncDnsResolver(); ~AsyncDnsResolver(); diff --git a/rtc_base/async_resolver.h b/rtc_base/async_resolver.h index 46be43860e..9de4d12fed 100644 --- a/rtc_base/async_resolver.h +++ b/rtc_base/async_resolver.h @@ -39,7 +39,12 @@ namespace rtc { // happen from the same rtc::Thread, except for Destroy which is allowed to // happen on another context provided it's not happening concurrently to another // public API call, and is the last access to the object. -class RTC_EXPORT AsyncResolver : public AsyncResolverInterface { +// TODO(bugs.webrtc.org/12598): Deprecate and remove +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-aliasing" +class [[deprecated("Use AsyncDnsResolver")]] RTC_EXPORT AsyncResolver + : public AsyncResolverInterface { +#pragma clang diagnostic pop public: AsyncResolver(); ~AsyncResolver() override; diff --git a/rtc_base/async_resolver_interface.h b/rtc_base/async_resolver_interface.h index 851fa38ce1..a0bda2774a 100644 --- a/rtc_base/async_resolver_interface.h +++ b/rtc_base/async_resolver_interface.h @@ -20,7 +20,7 @@ namespace rtc { // This interface defines the methods to resolve the address asynchronously. // TODO(bugs.webrtc.org/12598): Deprecate and remove. -class RTC_EXPORT AsyncResolverInterface { +class [[deprecated("Use AsyncDnsResolver")]] RTC_EXPORT AsyncResolverInterface { public: AsyncResolverInterface(); virtual ~AsyncResolverInterface(); diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn index ac542cc301..185d5931f7 100644 --- a/rtc_base/experiments/BUILD.gn +++ b/rtc_base/experiments/BUILD.gn @@ -75,8 +75,6 @@ rtc_library("quality_scaler_settings") { ":field_trial_parser", "..:logging", "../../api:field_trials_view", - "../../api/transport:field_trial_based_config", - "../../system_wrappers:field_trial", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -103,10 +101,14 @@ rtc_library("quality_scaling_experiment") { ] deps = [ "..:logging", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", "../../api/video_codecs:video_codecs_api", - "../../system_wrappers:field_trial", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] } rtc_library("normalize_simulcast_size_experiment") { diff --git a/rtc_base/experiments/balanced_degradation_settings.cc b/rtc_base/experiments/balanced_degradation_settings.cc index 1652e31704..1a269b4fa6 100644 --- a/rtc_base/experiments/balanced_degradation_settings.cc +++ b/rtc_base/experiments/balanced_degradation_settings.cc @@ -159,6 +159,8 @@ absl::optional GetThresholds( low = config.vp9.GetQpLow(); high = config.vp9.GetQpHigh(); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now. case kVideoCodecH264: low = config.h264.GetQpLow(); high = config.h264.GetQpHigh(); @@ -194,6 +196,8 @@ int GetFps(VideoCodecType type, case kVideoCodecVP8: fps = config->vp8.GetFps(); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. case kVideoCodecVP9: fps = config->vp9.GetFps(); break; @@ -226,6 +230,8 @@ absl::optional GetKbps( case kVideoCodecVP8: kbps = config->vp8.GetKbps(); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. case kVideoCodecVP9: kbps = config->vp9.GetKbps(); break; @@ -259,6 +265,8 @@ absl::optional GetKbpsRes( case kVideoCodecVP8: kbps_res = config->vp8.GetKbpsRes(); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. case kVideoCodecVP9: kbps_res = config->vp9.GetKbpsRes(); break; diff --git a/rtc_base/experiments/encoder_info_settings.cc b/rtc_base/experiments/encoder_info_settings.cc index 00974838ae..136201d261 100644 --- a/rtc_base/experiments/encoder_info_settings.cc +++ b/rtc_base/experiments/encoder_info_settings.cc @@ -38,9 +38,26 @@ constexpr float kDefaultMinBitratebps = 30000; std::vector EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( VideoCodecType codec_type) { - // Specific limits for VP9. Determining specific limits for AV1 via - // field trial experiment is a work in progress. Other codecs use VP8 limits. + if (codec_type == kVideoCodecAV1) { + // AV1 singlecast max bitrate limits are higher than AV1 SVC max limits. + // This is because in singlecast we normally have just one receiver, BWE is + // known end-to-end and the encode target bitrate guarantees delivery of + // video. + // The min bitrate limits are not used in singlecast (used in SVC/simulcast + // to de-/activate spatial layers) and are set to zero. Send resolution in + // singlecast is assumed to be regulated by QP-based quality scaler. + return {{320 * 180, 0, 0, 256000}, + {480 * 270, 176000, 0, 384000}, + {640 * 360, 256000, 0, 512000}, + {960 * 540, 384000, 0, 1024000}, + {1280 * 720, 576000, 0, 1536000}}; + } + if (codec_type == kVideoCodecVP9) { + // VP9 singlecast bitrate limits are derived ~directly from VP9 SVC bitrate + // limits. The current max limits are unnecessarily too strict for + // singlecast, where BWE is known end-to-end, especially for low + // resolutions. return {{320 * 180, 0, 30000, 150000}, {480 * 270, 120000, 30000, 300000}, {640 * 360, 190000, 30000, 420000}, @@ -48,6 +65,7 @@ EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( {1280 * 720, 480000, 30000, 1500000}}; } + // VP8 and other codecs. return {{320 * 180, 0, 30000, 300000}, {480 * 270, 200000, 30000, 500000}, {640 * 360, 300000, 30000, 800000}, diff --git a/rtc_base/experiments/min_video_bitrate_experiment.cc b/rtc_base/experiments/min_video_bitrate_experiment.cc index f37c4e9c76..f9e7613a15 100644 --- a/rtc_base/experiments/min_video_bitrate_experiment.cc +++ b/rtc_base/experiments/min_video_bitrate_experiment.cc @@ -94,6 +94,8 @@ absl::optional GetExperimentalMinVideoBitrate(VideoCodecType type) { switch (type) { case kVideoCodecVP8: return min_bitrate_vp8.GetOptional(); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. case kVideoCodecVP9: return min_bitrate_vp9.GetOptional(); case kVideoCodecAV1: diff --git a/rtc_base/experiments/quality_scaler_settings.cc b/rtc_base/experiments/quality_scaler_settings.cc index 85c99255ab..24da211d89 100644 --- a/rtc_base/experiments/quality_scaler_settings.cc +++ b/rtc_base/experiments/quality_scaler_settings.cc @@ -10,7 +10,7 @@ #include "rtc_base/experiments/quality_scaler_settings.h" -#include "api/transport/field_trial_based_config.h" +#include "api/field_trials_view.h" #include "rtc_base/logging.h" namespace webrtc { @@ -20,7 +20,7 @@ const double kMinScaleFactor = 0.01; } // namespace QualityScalerSettings::QualityScalerSettings( - const FieldTrialsView* const key_value_config) + const FieldTrialsView& field_trials) : sampling_period_ms_("sampling_period_ms"), average_qp_window_("average_qp_window"), min_frames_("min_frames"), @@ -28,16 +28,10 @@ QualityScalerSettings::QualityScalerSettings( scale_factor_("scale_factor"), initial_bitrate_interval_ms_("initial_bitrate_interval_ms"), initial_bitrate_factor_("initial_bitrate_factor") { - ParseFieldTrial( - {&sampling_period_ms_, &average_qp_window_, &min_frames_, - &initial_scale_factor_, &scale_factor_, &initial_bitrate_interval_ms_, - &initial_bitrate_factor_}, - key_value_config->Lookup("WebRTC-Video-QualityScalerSettings")); -} - -QualityScalerSettings QualityScalerSettings::ParseFromFieldTrials() { - FieldTrialBasedConfig field_trial_config; - return QualityScalerSettings(&field_trial_config); + ParseFieldTrial({&sampling_period_ms_, &average_qp_window_, &min_frames_, + &initial_scale_factor_, &scale_factor_, + &initial_bitrate_interval_ms_, &initial_bitrate_factor_}, + field_trials.Lookup("WebRTC-Video-QualityScalerSettings")); } absl::optional QualityScalerSettings::SamplingPeriodMs() const { diff --git a/rtc_base/experiments/quality_scaler_settings.h b/rtc_base/experiments/quality_scaler_settings.h index 99827aac6b..1085816697 100644 --- a/rtc_base/experiments/quality_scaler_settings.h +++ b/rtc_base/experiments/quality_scaler_settings.h @@ -19,7 +19,7 @@ namespace webrtc { class QualityScalerSettings final { public: - static QualityScalerSettings ParseFromFieldTrials(); + explicit QualityScalerSettings(const FieldTrialsView& field_trials); absl::optional SamplingPeriodMs() const; absl::optional AverageQpWindow() const; @@ -30,8 +30,6 @@ class QualityScalerSettings final { absl::optional InitialBitrateFactor() const; private: - explicit QualityScalerSettings(const FieldTrialsView* const key_value_config); - FieldTrialOptional sampling_period_ms_; FieldTrialOptional average_qp_window_; FieldTrialOptional min_frames_; diff --git a/rtc_base/experiments/quality_scaler_settings_unittest.cc b/rtc_base/experiments/quality_scaler_settings_unittest.cc index 9da770c1b5..578fe97b03 100644 --- a/rtc_base/experiments/quality_scaler_settings_unittest.cc +++ b/rtc_base/experiments/quality_scaler_settings_unittest.cc @@ -10,14 +10,15 @@ #include "rtc_base/experiments/quality_scaler_settings.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace { TEST(QualityScalerSettingsTest, ValuesNotSetByDefault) { - const auto settings = QualityScalerSettings::ParseFromFieldTrials(); + webrtc::test::ScopedKeyValueConfig field_trials(""); + const auto settings = QualityScalerSettings(field_trials); EXPECT_FALSE(settings.MinFrames()); EXPECT_FALSE(settings.InitialScaleFactor()); EXPECT_FALSE(settings.ScaleFactor()); @@ -26,46 +27,42 @@ TEST(QualityScalerSettingsTest, ValuesNotSetByDefault) { } TEST(QualityScalerSettingsTest, ParseMinFrames) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/min_frames:100/"); - EXPECT_EQ(100, QualityScalerSettings::ParseFromFieldTrials().MinFrames()); + EXPECT_EQ(100, QualityScalerSettings(field_trials).MinFrames()); } TEST(QualityScalerSettingsTest, ParseInitialScaleFactor) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/initial_scale_factor:1.5/"); - EXPECT_EQ(1.5, - QualityScalerSettings::ParseFromFieldTrials().InitialScaleFactor()); + EXPECT_EQ(1.5, QualityScalerSettings(field_trials).InitialScaleFactor()); } TEST(QualityScalerSettingsTest, ParseScaleFactor) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/scale_factor:1.1/"); - EXPECT_EQ(1.1, QualityScalerSettings::ParseFromFieldTrials().ScaleFactor()); + EXPECT_EQ(1.1, QualityScalerSettings(field_trials).ScaleFactor()); } TEST(QualityScalerSettingsTest, ParseInitialBitrateInterval) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/initial_bitrate_interval_ms:1000/"); - EXPECT_EQ( - 1000, - QualityScalerSettings::ParseFromFieldTrials().InitialBitrateIntervalMs()); + EXPECT_EQ(1000, + QualityScalerSettings(field_trials).InitialBitrateIntervalMs()); } TEST(QualityScalerSettingsTest, ParseInitialBitrateFactor) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/initial_bitrate_factor:0.75/"); - EXPECT_EQ( - 0.75, - QualityScalerSettings::ParseFromFieldTrials().InitialBitrateFactor()); + EXPECT_EQ(0.75, QualityScalerSettings(field_trials).InitialBitrateFactor()); } TEST(QualityScalerSettingsTest, ParseAll) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/" "min_frames:100,initial_scale_factor:1.5,scale_factor:0.9," "initial_bitrate_interval_ms:5500,initial_bitrate_factor:0.7/"); - const auto settings = QualityScalerSettings::ParseFromFieldTrials(); + const auto settings = QualityScalerSettings(field_trials); EXPECT_EQ(100, settings.MinFrames()); EXPECT_EQ(1.5, settings.InitialScaleFactor()); EXPECT_EQ(0.9, settings.ScaleFactor()); @@ -74,11 +71,11 @@ TEST(QualityScalerSettingsTest, ParseAll) { } TEST(QualityScalerSettingsTest, DoesNotParseIncorrectValue) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/" "min_frames:a,initial_scale_factor:b,scale_factor:c," "initial_bitrate_interval_ms:d,initial_bitrate_factor:e/"); - const auto settings = QualityScalerSettings::ParseFromFieldTrials(); + const auto settings = QualityScalerSettings(field_trials); EXPECT_FALSE(settings.MinFrames()); EXPECT_FALSE(settings.InitialScaleFactor()); EXPECT_FALSE(settings.ScaleFactor()); @@ -87,11 +84,11 @@ TEST(QualityScalerSettingsTest, DoesNotParseIncorrectValue) { } TEST(QualityScalerSettingsTest, DoesNotReturnTooSmallValue) { - test::ScopedFieldTrials field_trials( + test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScalerSettings/" "min_frames:0,initial_scale_factor:0.0,scale_factor:0.0," "initial_bitrate_interval_ms:-1,initial_bitrate_factor:0.0/"); - const auto settings = QualityScalerSettings::ParseFromFieldTrials(); + const auto settings = QualityScalerSettings(field_trials); EXPECT_FALSE(settings.MinFrames()); EXPECT_FALSE(settings.InitialScaleFactor()); EXPECT_FALSE(settings.ScaleFactor()); diff --git a/rtc_base/experiments/quality_scaling_experiment.cc b/rtc_base/experiments/quality_scaling_experiment.cc index 7d5722bbe3..ee3d7c0320 100644 --- a/rtc_base/experiments/quality_scaling_experiment.cc +++ b/rtc_base/experiments/quality_scaling_experiment.cc @@ -13,8 +13,10 @@ #include +#include "absl/strings/match.h" +#include "api/field_trials_view.h" +#include "api/transport/field_trial_based_config.h" #include "rtc_base/logging.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { namespace { @@ -42,17 +44,17 @@ absl::optional GetThresholds(int low, } } // namespace -bool QualityScalingExperiment::Enabled() { +bool QualityScalingExperiment::Enabled(const FieldTrialsView& field_trials) { #if defined(WEBRTC_IOS) - return webrtc::field_trial::IsEnabled(kFieldTrial); + return absl::StartsWith(field_trials.Lookup(kFieldTrial), "Enabled"); #else - return !webrtc::field_trial::IsDisabled(kFieldTrial); + return !absl::StartsWith(field_trials.Lookup(kFieldTrial), "Disabled"); #endif } absl::optional -QualityScalingExperiment::ParseSettings() { - std::string group = webrtc::field_trial::FindFullName(kFieldTrial); +QualityScalingExperiment::ParseSettings(const FieldTrialsView& field_trials) { + std::string group = field_trials.Lookup(kFieldTrial); // TODO(http://crbug.com/webrtc/12401): Completely remove the experiment code // after few releases. #if !defined(WEBRTC_IOS) @@ -71,8 +73,9 @@ QualityScalingExperiment::ParseSettings() { } absl::optional -QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) { - const auto settings = ParseSettings(); +QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type, + const FieldTrialsView& field_trials) { + const auto settings = ParseSettings(field_trials); if (!settings) return absl::nullopt; @@ -81,6 +84,8 @@ QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) { return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp); case kVideoCodecVP9: return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now. case kVideoCodecH264: return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp); case kVideoCodecGeneric: @@ -91,8 +96,9 @@ QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) { } } -QualityScalingExperiment::Config QualityScalingExperiment::GetConfig() { - const auto settings = ParseSettings(); +QualityScalingExperiment::Config QualityScalingExperiment::GetConfig( + const FieldTrialsView& field_trials) { + const auto settings = ParseSettings(field_trials); if (!settings) return Config(); diff --git a/rtc_base/experiments/quality_scaling_experiment.h b/rtc_base/experiments/quality_scaling_experiment.h index 31d8292b5c..bd24c06e55 100644 --- a/rtc_base/experiments/quality_scaling_experiment.h +++ b/rtc_base/experiments/quality_scaling_experiment.h @@ -11,6 +11,7 @@ #define RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_ #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/video_codecs/video_encoder.h" namespace webrtc { @@ -40,17 +41,19 @@ class QualityScalingExperiment { }; // Returns true if the experiment is enabled. - static bool Enabled(); + static bool Enabled(const FieldTrialsView& field_trials); // Returns settings from field trial. - static absl::optional ParseSettings(); + static absl::optional ParseSettings( + const FieldTrialsView& field_trials); // Returns QpThresholds for the `codec_type`. static absl::optional GetQpThresholds( - VideoCodecType codec_type); + VideoCodecType codec_type, + const FieldTrialsView& field_trials); // Returns parsed values. If the parsing fails, default values are returned. - static Config GetConfig(); + static Config GetConfig(const FieldTrialsView& field_trials); }; } // namespace webrtc diff --git a/rtc_base/experiments/quality_scaling_experiment_unittest.cc b/rtc_base/experiments/quality_scaling_experiment_unittest.cc index 4507f1514f..0c1450557a 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 "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace { @@ -41,28 +41,28 @@ void ExpectEqualConfig(QualityScalingExperiment::Config a, #if !defined(WEBRTC_IOS) // TODO(bugs.webrtc.org/12401): investigate why QualityScaler kicks in on iOS. TEST(QualityScalingExperimentTest, DefaultEnabledWithoutFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials(""); - EXPECT_TRUE(QualityScalingExperiment::Enabled()); + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_TRUE(QualityScalingExperiment::Enabled(field_trials)); } #else TEST(QualityScalingExperimentTest, DefaultDisabledWithoutFieldTrialIOS) { - webrtc::test::ScopedFieldTrials field_trials(""); - EXPECT_FALSE(QualityScalingExperiment::Enabled()); + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_FALSE(QualityScalingExperiment::Enabled(field_trials)); } #endif TEST(QualityScalingExperimentTest, EnabledWithFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled/"); - EXPECT_TRUE(QualityScalingExperiment::Enabled()); + EXPECT_TRUE(QualityScalingExperiment::Enabled(field_trials)); } TEST(QualityScalingExperimentTest, ParseSettings) { const QualityScalingExperiment::Settings kExpected = {1, 2, 3, 4, 5, 6, 7, 8, 0.9f, 0.99f, 1}; - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/"); - const auto settings = QualityScalingExperiment::ParseSettings(); + const auto settings = QualityScalingExperiment::ParseSettings(field_trials); EXPECT_TRUE(settings); ExpectEqualSettings(kExpected, *settings); } @@ -70,117 +70,117 @@ TEST(QualityScalingExperimentTest, ParseSettings) { #if !defined(WEBRTC_IOS) // TODO(bugs.webrtc.org/12401): investigate why QualityScaler kicks in on iOS. TEST(QualityScalingExperimentTest, ParseSettingsUsesDefaultsWithoutFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials(""); + webrtc::test::ScopedKeyValueConfig field_trials(""); // Uses some default hard coded values. - EXPECT_TRUE(QualityScalingExperiment::ParseSettings()); + EXPECT_TRUE(QualityScalingExperiment::ParseSettings(field_trials)); } #else TEST(QualityScalingExperimentTest, ParseSettingsFailsWithoutFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials(""); - EXPECT_FALSE(QualityScalingExperiment::ParseSettings()); + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_FALSE(QualityScalingExperiment::ParseSettings(field_trials)); } #endif TEST(QualityScalingExperimentTest, ParseSettingsFailsWithInvalidFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-invalid/"); - EXPECT_FALSE(QualityScalingExperiment::ParseSettings()); + EXPECT_FALSE(QualityScalingExperiment::ParseSettings(field_trials)); } TEST(QualityScalingExperimentTest, GetConfig) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,0/"); - const auto config = QualityScalingExperiment::GetConfig(); + const auto config = QualityScalingExperiment::GetConfig(field_trials); EXPECT_EQ(0.9f, config.alpha_high); EXPECT_EQ(0.99f, config.alpha_low); EXPECT_FALSE(config.use_all_drop_reasons); } TEST(QualityScalingExperimentTest, GetsDefaultConfigForInvalidFieldTrial) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-invalid/"); - const auto config = QualityScalingExperiment::GetConfig(); + const auto config = QualityScalingExperiment::GetConfig(field_trials); ExpectEqualConfig(config, QualityScalingExperiment::Config()); } TEST(QualityScalingExperimentTest, GetsDefaultAlphaForInvalidValue) { QualityScalingExperiment::Config expected_config; expected_config.use_all_drop_reasons = true; - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.99,0.9,1/"); - const auto config = QualityScalingExperiment::GetConfig(); + const auto config = QualityScalingExperiment::GetConfig(field_trials); ExpectEqualConfig(config, expected_config); } TEST(QualityScalingExperimentTest, GetVp8Thresholds) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8); + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8, field_trials); EXPECT_TRUE(thresholds); EXPECT_EQ(1, thresholds->low); EXPECT_EQ(2, thresholds->high); } TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidVp8Value) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-0,0,3,4,5,6,7,8,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8); + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8, field_trials); EXPECT_FALSE(thresholds); } TEST(QualityScalingExperimentTest, GetVp9Thresholds) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9); + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9, field_trials); EXPECT_TRUE(thresholds); EXPECT_EQ(3, thresholds->low); EXPECT_EQ(4, thresholds->high); } TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidVp9Value) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,0,0,5,6,7,8,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9); + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9, field_trials); EXPECT_FALSE(thresholds); } TEST(QualityScalingExperimentTest, GetH264Thresholds) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecH264); + QualityScalingExperiment::GetQpThresholds(kVideoCodecH264, field_trials); EXPECT_TRUE(thresholds); EXPECT_EQ(5, thresholds->low); EXPECT_EQ(6, thresholds->high); } TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidH264Value) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,0,0,7,8,0.9,0.99,1/"); const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecH264); + QualityScalingExperiment::GetQpThresholds(kVideoCodecH264, field_trials); EXPECT_FALSE(thresholds); } TEST(QualityScalingExperimentTest, GetGenericThresholds) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,0,0,7,8,0.9,0.99,1/"); - const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecGeneric); + const auto thresholds = QualityScalingExperiment::GetQpThresholds( + kVideoCodecGeneric, field_trials); EXPECT_TRUE(thresholds); EXPECT_EQ(7, thresholds->low); EXPECT_EQ(8, thresholds->high); } TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidGenericValue) { - webrtc::test::ScopedFieldTrials field_trials( + webrtc::test::ScopedKeyValueConfig field_trials( "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); - const auto thresholds = - QualityScalingExperiment::GetQpThresholds(kVideoCodecGeneric); + const auto thresholds = QualityScalingExperiment::GetQpThresholds( + kVideoCodecGeneric, field_trials); EXPECT_FALSE(thresholds); } } // namespace webrtc diff --git a/rtc_base/ip_address_unittest.cc b/rtc_base/ip_address_unittest.cc index 9ca05c95fe..aee9b93dd9 100644 --- a/rtc_base/ip_address_unittest.cc +++ b/rtc_base/ip_address_unittest.cc @@ -61,10 +61,6 @@ static const std::string kIPv6PublicAddrAnonymizedString = "2401:fa00:4:x:x:x:x:x"; static const std::string kIPv6PublicAddr2AnonymizedString = "2401:0:0:x:x:x:x:x"; -static const std::string kIPv4MappedAnyAddrString = "::ffff:0:0"; -static const std::string kIPv4MappedRFC1918AddrString = "::ffff:c0a8:701"; -static const std::string kIPv4MappedLoopbackAddrString = "::ffff:7f00:1"; -static const std::string kIPv4MappedPublicAddrString = "::ffff:102:0304"; static const std::string kIPv4MappedV4StyleAddrString = "::ffff:192.168.7.1"; static const std::string kIPv4BrokenString1 = "192.168.7."; diff --git a/rtc_base/network/BUILD.gn b/rtc_base/network/BUILD.gn index 35ae3d45f7..a42745a4c0 100644 --- a/rtc_base/network/BUILD.gn +++ b/rtc_base/network/BUILD.gn @@ -16,3 +16,18 @@ rtc_library("sent_packet") { deps = [ "../system:rtc_export" ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } + +rtc_library("received_packet") { + sources = [ + "received_packet.cc", + "received_packet.h", + ] + deps = [ + "../../api:array_view", + "../../api/units:timestamp", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/types:optional", + ] +} diff --git a/rtc_base/network/received_packet.cc b/rtc_base/network/received_packet.cc new file mode 100644 index 0000000000..9612c3dab4 --- /dev/null +++ b/rtc_base/network/received_packet.cc @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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/network/received_packet.h" + +#include + +#include "absl/types/optional.h" + +namespace rtc { + +ReceivedPacket::ReceivedPacket(rtc::ArrayView payload, + absl::optional arrival_time) + : payload_(payload), arrival_time_(std::move(arrival_time)) {} + +} // namespace rtc diff --git a/rtc_base/network/received_packet.h b/rtc_base/network/received_packet.h new file mode 100644 index 0000000000..7f8b2f934c --- /dev/null +++ b/rtc_base/network/received_packet.h @@ -0,0 +1,47 @@ +/* + * Copyright 2023 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_NETWORK_RECEIVED_PACKET_H_ +#define RTC_BASE_NETWORK_RECEIVED_PACKET_H_ + +#include + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/units/timestamp.h" + +namespace rtc { + +// ReceivedPacket repressent a received IP packet. +// It contains a payload and metadata. +// ReceivedPacket itself does not put constraints on what payload contains. For +// example it may contains STUN, SCTP, SRTP, RTP, RTCP.... etc. +class ReceivedPacket { + public: + // Caller must keep memory pointed to by payload valid for the lifetime of + // this ReceivedPacket. + ReceivedPacket( + rtc::ArrayView payload, + absl::optional arrival_time = absl::nullopt); + + rtc::ArrayView payload() const { return payload_; } + + // Timestamp when this packet was received. Not available on all socket + // implementations. + absl::optional arrival_time() const { + return arrival_time_; + } + + private: + rtc::ArrayView payload_; + absl::optional arrival_time_; +}; + +} // namespace rtc +#endif // RTC_BASE_NETWORK_RECEIVED_PACKET_H_ diff --git a/rtc_base/numerics/sample_counter.cc b/rtc_base/numerics/sample_counter.cc index 16a8e25098..78e35fdb5b 100644 --- a/rtc_base/numerics/sample_counter.cc +++ b/rtc_base/numerics/sample_counter.cc @@ -31,6 +31,9 @@ void SampleCounter::Add(int sample) { if (!max_ || sample > *max_) { max_ = sample; } + if (!min_ || sample < *min_) { + min_ = sample; + } } void SampleCounter::Add(const SampleCounter& other) { @@ -45,6 +48,8 @@ void SampleCounter::Add(const SampleCounter& other) { num_samples_ += other.num_samples_; if (other.max_ && (!max_ || *max_ < *other.max_)) max_ = other.max_; + if (other.min_ && (!min_ || *min_ > *other.min_)) + min_ = other.min_; } absl::optional SampleCounter::Avg(int64_t min_required_samples) const { @@ -58,6 +63,10 @@ absl::optional SampleCounter::Max() const { return max_; } +absl::optional SampleCounter::Min() const { + return min_; +} + absl::optional SampleCounter::Sum(int64_t min_required_samples) const { RTC_DCHECK_GT(min_required_samples, 0); if (num_samples_ < min_required_samples) diff --git a/rtc_base/numerics/sample_counter.h b/rtc_base/numerics/sample_counter.h index 717a1afbcf..2b41f95fc0 100644 --- a/rtc_base/numerics/sample_counter.h +++ b/rtc_base/numerics/sample_counter.h @@ -26,6 +26,7 @@ class SampleCounter { void Add(int sample); absl::optional Avg(int64_t min_required_samples) const; absl::optional Max() const; + absl::optional Min() const; absl::optional Sum(int64_t min_required_samples) const; int64_t NumSamples() const; void Reset(); @@ -37,6 +38,7 @@ class SampleCounter { int64_t sum_ = 0; int64_t num_samples_ = 0; absl::optional max_; + absl::optional min_; }; class SampleCounterWithVariance : public SampleCounter { diff --git a/rtc_base/numerics/sample_counter_unittest.cc b/rtc_base/numerics/sample_counter_unittest.cc index 14b0573de9..ffc8b89f6f 100644 --- a/rtc_base/numerics/sample_counter_unittest.cc +++ b/rtc_base/numerics/sample_counter_unittest.cc @@ -24,6 +24,7 @@ TEST(SampleCounterTest, ProcessesNoSamples) { SampleCounter counter; EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt)); EXPECT_THAT(counter.Max(), Eq(absl::nullopt)); + EXPECT_THAT(counter.Min(), Eq(absl::nullopt)); } TEST(SampleCounterTest, NotEnoughSamples) { @@ -35,6 +36,7 @@ TEST(SampleCounterTest, NotEnoughSamples) { EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt)); EXPECT_THAT(counter.Sum(kMinSamples), Eq(absl::nullopt)); EXPECT_THAT(counter.Max(), Eq(5)); + EXPECT_THAT(counter.Min(), Eq(1)); } TEST(SampleCounterTest, EnoughSamples) { @@ -46,6 +48,7 @@ TEST(SampleCounterTest, EnoughSamples) { EXPECT_THAT(counter.Avg(kMinSamples), Eq(3)); EXPECT_THAT(counter.Sum(kMinSamples), Eq(15)); EXPECT_THAT(counter.Max(), Eq(5)); + EXPECT_THAT(counter.Min(), Eq(1)); } TEST(SampleCounterTest, ComputesVariance) { @@ -74,6 +77,7 @@ TEST(SampleCounterTest, AggregatesTwoCounters) { counter1.Add(counter2); EXPECT_THAT(counter1.Avg(kMinSamples), Eq(3)); EXPECT_THAT(counter1.Max(), Eq(5)); + EXPECT_THAT(counter1.Min(), Eq(1)); EXPECT_THAT(counter1.Variance(kMinSamples), Eq(2)); } diff --git a/rtc_base/openssl_stream_adapter.cc b/rtc_base/openssl_stream_adapter.cc index d462f77ce4..353cbbe681 100644 --- a/rtc_base/openssl_stream_adapter.cc +++ b/rtc_base/openssl_stream_adapter.cc @@ -469,6 +469,17 @@ bool OpenSSLStreamAdapter::ExportKeyingMaterial(absl::string_view label, return true; } +uint16_t OpenSSLStreamAdapter::GetPeerSignatureAlgorithm() const { + if (state_ != SSL_CONNECTED) { + return 0; + } +#ifdef OPENSSL_IS_BORINGSSL + return SSL_get_peer_signature_algorithm(ssl_); +#else + return kSslSignatureAlgorithmUnknown; +#endif +} + bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites( const std::vector& ciphers) { if (state_ != SSL_NONE) { @@ -1098,6 +1109,11 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() { } } +#ifdef OPENSSL_IS_BORINGSSL + SSL_CTX_set_permute_extensions( + ctx, webrtc::field_trial::IsEnabled("WebRTC-PermuteTlsClientHello")); +#endif + return ctx; } diff --git a/rtc_base/openssl_stream_adapter.h b/rtc_base/openssl_stream_adapter.h index 579ca2a1f8..42fdb08aae 100644 --- a/rtc_base/openssl_stream_adapter.h +++ b/rtc_base/openssl_stream_adapter.h @@ -124,6 +124,8 @@ class OpenSSLStreamAdapter final : public SSLStreamAdapter, uint8_t* result, size_t result_len) override; + uint16_t GetPeerSignatureAlgorithm() const override; + // DTLS-SRTP interface bool SetDtlsSrtpCryptoSuites(const std::vector& crypto_suites) override; bool GetDtlsSrtpCryptoSuite(int* crypto_suite) override; diff --git a/rtc_base/physical_socket_server.cc b/rtc_base/physical_socket_server.cc index bc5c3a339e..b5b4443eb4 100644 --- a/rtc_base/physical_socket_server.cc +++ b/rtc_base/physical_socket_server.cc @@ -10,6 +10,7 @@ #include "rtc_base/physical_socket_server.h" #include +#include #if defined(_MSC_VER) && _MSC_VER < 1300 #pragma warning(disable : 4786) @@ -21,7 +22,6 @@ #if defined(WEBRTC_POSIX) #include -#include #if defined(WEBRTC_USE_EPOLL) // "poll" will be used to wait for the signal dispatcher. #include @@ -30,7 +30,6 @@ #endif #include #include -#include #include #endif @@ -38,20 +37,18 @@ #include #include #include + #undef SetPort #endif #include -#include -#include - -#include "rtc_base/arraysize.h" -#include "rtc_base/byte_order.h" +#include "rtc_base/async_dns_resolver.h" #include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/ip_address.h" #include "rtc_base/logging.h" #include "rtc_base/network_monitor.h" -#include "rtc_base/null_socket_server.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/time_utils.h" #include "system_wrappers/include/field_trial.h" @@ -70,6 +67,7 @@ #if defined(WEBRTC_POSIX) #include // for TCP_NODELAY + #define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h typedef void* SockOptArg; @@ -252,9 +250,8 @@ int PhysicalSocket::Connect(const SocketAddress& addr) { } if (addr.IsUnresolvedIP()) { RTC_LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; - resolver_ = new AsyncResolver(); - resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult); - resolver_->Start(addr); + resolver_ = std::make_unique(); + resolver_->Start(addr, [this] { OnResolveResult(resolver_->result()); }); state_ = CS_CONNECTING; return 0; } @@ -564,8 +561,7 @@ int PhysicalSocket::Close() { state_ = CS_CLOSED; SetEnabledEvents(0); if (resolver_) { - resolver_->Destroy(false); - resolver_ = nullptr; + resolver_.reset(); } return err; } @@ -589,14 +585,16 @@ int PhysicalSocket::DoSendTo(SOCKET socket, return ::sendto(socket, buf, len, flags, dest_addr, addrlen); } -void PhysicalSocket::OnResolveResult(AsyncResolverInterface* resolver) { - if (resolver != resolver_) { - return; - } - - int error = resolver_->GetError(); +void PhysicalSocket::OnResolveResult( + const webrtc::AsyncDnsResolverResult& result) { + int error = result.GetError(); if (error == 0) { - error = DoConnect(resolver_->address()); + SocketAddress address; + if (result.GetResolvedAddress(AF_INET, &address)) { + error = DoConnect(address); + } else { + Close(); + } } else { Close(); } diff --git a/rtc_base/physical_socket_server.h b/rtc_base/physical_socket_server.h index 650db80931..ea449ff121 100644 --- a/rtc_base/physical_socket_server.h +++ b/rtc_base/physical_socket_server.h @@ -11,17 +11,23 @@ #ifndef RTC_BASE_PHYSICAL_SOCKET_SERVER_H_ #define RTC_BASE_PHYSICAL_SOCKET_SERVER_H_ +#include "api/async_dns_resolver.h" #include "api/units/time_delta.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/third_party/sigslot/sigslot.h" #if defined(WEBRTC_POSIX) #if defined(WEBRTC_LINUX) // On Linux, use epoll. #include + #define WEBRTC_USE_EPOLL 1 #elif defined(WEBRTC_FUCHSIA) // Fuchsia implements select and poll but not epoll, and testing shows that poll // is faster than select. #include + #define WEBRTC_USE_POLL 1 #else // On other POSIX systems, use select by default. @@ -29,7 +35,9 @@ #endif // WEBRTC_POSIX #include +#include #include +#include #include #include @@ -218,7 +226,7 @@ class PhysicalSocket : public Socket, public sigslot::has_slots<> { SocketAddress* out_addr, int64_t* timestamp); - void OnResolveResult(AsyncResolverInterface* resolver); + void OnResolveResult(const webrtc::AsyncDnsResolverResult& resolver); void UpdateLastError(); void MaybeRemapSendError(); @@ -237,7 +245,7 @@ class PhysicalSocket : public Socket, public sigslot::has_slots<> { mutable webrtc::Mutex mutex_; int error_ RTC_GUARDED_BY(mutex_); ConnState state_; - AsyncResolver* resolver_; + std::unique_ptr resolver_; #if !defined(NDEBUG) std::string dbg_addr_; diff --git a/rtc_base/rate_limiter.cc b/rtc_base/rate_limiter.cc index 4740b26f81..0f3f343aed 100644 --- a/rtc_base/rate_limiter.cc +++ b/rtc_base/rate_limiter.cc @@ -14,7 +14,6 @@ #include "absl/types/optional.h" #include "system_wrappers/include/clock.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -35,8 +34,7 @@ bool RateLimiter::TryUseRate(size_t packet_size_bytes) { MutexLock lock(&lock_); int64_t now_ms = clock_->TimeInMilliseconds(); absl::optional current_rate = current_rate_.Rate(now_ms); - if (!webrtc::field_trial::IsEnabled("WebRTC-DisableRtxRateLimiter") && - current_rate) { + if (current_rate) { // If there is a current rate, check if adding bytes would cause maximum // bitrate target to be exceeded. If there is NOT a valid current rate, // allow allocating rate even if target is exceeded. This prevents diff --git a/rtc_base/rate_limiter_unittest.cc b/rtc_base/rate_limiter_unittest.cc index a830446d60..07dda5609e 100644 --- a/rtc_base/rate_limiter_unittest.cc +++ b/rtc_base/rate_limiter_unittest.cc @@ -15,7 +15,6 @@ #include "rtc_base/event.h" #include "rtc_base/platform_thread.h" #include "system_wrappers/include/clock.h" -#include "test/field_trial.h" #include "test/gtest.h" namespace webrtc { @@ -107,19 +106,6 @@ TEST_F(RateLimitTest, WindowSizeLimits) { EXPECT_FALSE(rate_limiter->SetWindowSize(kWindowSizeMs + 1)); } -TEST_F(RateLimitTest, DiablesRtxRateLimiterByFieldTrial) { - webrtc::test::ScopedFieldTrials trial( - "WebRTC-DisableRtxRateLimiter/Enabled/"); - - // Fill rate, extend window to full size. - EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); - clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1); - EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); - - // Does not limit rate even when all rate consumed. - EXPECT_TRUE(rate_limiter->TryUseRate(1)); -} - static constexpr TimeDelta kMaxTimeout = TimeDelta::Seconds(30); class ThreadTask { diff --git a/rtc_base/ssl_stream_adapter.h b/rtc_base/ssl_stream_adapter.h index d8b66f11e8..701cc4437b 100644 --- a/rtc_base/ssl_stream_adapter.h +++ b/rtc_base/ssl_stream_adapter.h @@ -39,6 +39,10 @@ constexpr int kSrtpAeadAes128Gcm = 0x0007; constexpr int kSrtpAeadAes256Gcm = 0x0008; constexpr int kSrtpCryptoSuiteMaxValue = 0xFFFF; +// Constants for SSL signature algorithms. +constexpr int kSslSignatureAlgorithmUnknown = 0; +constexpr int kSslSignatureAlgorithmMaxValue = 0xFFFF; + // Names of SRTP profiles listed above. // 128-bit AES with 80-bit SHA-1 HMAC. extern const char kCsAesCm128HmacSha1_80[]; @@ -218,6 +222,9 @@ class SSLStreamAdapter : public StreamInterface { uint8_t* result, size_t result_len); + // Returns the signature algorithm or 0 if not applicable. + virtual uint16_t GetPeerSignatureAlgorithm() const = 0; + // DTLS-SRTP interface virtual bool SetDtlsSrtpCryptoSuites(const std::vector& crypto_suites); virtual bool GetDtlsSrtpCryptoSuite(int* crypto_suite); diff --git a/rtc_base/ssl_stream_adapter_unittest.cc b/rtc_base/ssl_stream_adapter_unittest.cc index 8417314a3a..0a99d9b1f0 100644 --- a/rtc_base/ssl_stream_adapter_unittest.cc +++ b/rtc_base/ssl_stream_adapter_unittest.cc @@ -1808,3 +1808,46 @@ TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); TestHandshake(false); } + +// These tests are a no-op under OpenSSL. +#ifdef OPENSSL_IS_BORINGSSL +// TODO(https://bugs.webrtc.org/10261): when removing +// SSLStreamAdapterTestDTLSLegacyProtocols that this class +// inherits from move the code to this class. +class SSLStreamAdapterTestDTLSExtensionPermutation + : public SSLStreamAdapterTestDTLSLegacyProtocols { + public: + SSLStreamAdapterTestDTLSExtensionPermutation() + : SSLStreamAdapterTestDTLSLegacyProtocols() {} +}; + +// Tests for enabling the (D)TLS extension permutation which randomizes the +// order of extensions in the client hello. +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientDefaultServerDefault) { + ConfigureClient(""); + ConfigureServer(""); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientDefaultServerPermute) { + ConfigureClient(""); + ConfigureServer("WebRTC-PermuteTlsClientHello/Enabled/"); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientPermuteServerDefault) { + ConfigureClient("WebRTC-PermuteTlsClientHello/Enabled/"); + ConfigureServer(""); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientPermuteServerPermute) { + ConfigureClient("WebRTC-PermuteTlsClientHello/Enabled/"); + ConfigureServer("WebRTC-PermuteTlsClientHello/Enabled/"); + TestHandshake(); +} +#endif // OPENSSL_IS_BORINGSSL diff --git a/rtc_base/synchronization/sequence_checker_internal.cc b/rtc_base/synchronization/sequence_checker_internal.cc index 3e205b91d5..4b9583deb2 100644 --- a/rtc_base/synchronization/sequence_checker_internal.cc +++ b/rtc_base/synchronization/sequence_checker_internal.cc @@ -22,6 +22,11 @@ SequenceCheckerImpl::SequenceCheckerImpl(bool attach_to_current_thread) valid_thread_(rtc::CurrentThreadRef()), valid_queue_(TaskQueueBase::Current()) {} +SequenceCheckerImpl::SequenceCheckerImpl(TaskQueueBase* attached_queue) + : attached_(attached_queue != nullptr), + valid_thread_(rtc::PlatformThreadRef()), + valid_queue_(attached_queue) {} + bool SequenceCheckerImpl::IsCurrent() const { const TaskQueueBase* const current_queue = TaskQueueBase::Current(); const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); diff --git a/rtc_base/synchronization/sequence_checker_internal.h b/rtc_base/synchronization/sequence_checker_internal.h index 22503027a5..a23ac08885 100644 --- a/rtc_base/synchronization/sequence_checker_internal.h +++ b/rtc_base/synchronization/sequence_checker_internal.h @@ -31,6 +31,7 @@ namespace webrtc_sequence_checker_internal { class RTC_EXPORT SequenceCheckerImpl { public: explicit SequenceCheckerImpl(bool attach_to_current_thread); + explicit SequenceCheckerImpl(TaskQueueBase* attached_queue); ~SequenceCheckerImpl() = default; bool IsCurrent() const; @@ -59,6 +60,7 @@ class RTC_EXPORT SequenceCheckerImpl { class SequenceCheckerDoNothing { public: explicit SequenceCheckerDoNothing(bool attach_to_current_thread) {} + explicit SequenceCheckerDoNothing(TaskQueueBase* attached_queue) {} bool IsCurrent() const { return true; } void Detach() {} }; diff --git a/rtc_base/system/file_wrapper.cc b/rtc_base/system/file_wrapper.cc index f7befc6dc5..af34d0e411 100644 --- a/rtc_base/system/file_wrapper.cc +++ b/rtc_base/system/file_wrapper.cc @@ -10,15 +10,19 @@ #include "rtc_base/system/file_wrapper.h" +#include + #include +#include +#include #include "absl/strings/string_view.h" +#include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" #ifdef _WIN32 #include #else -#include #endif #include diff --git a/rtc_base/system/file_wrapper.h b/rtc_base/system/file_wrapper.h index 5e1e3d6a16..92a552cfd9 100644 --- a/rtc_base/system/file_wrapper.h +++ b/rtc_base/system/file_wrapper.h @@ -12,6 +12,7 @@ #define RTC_BASE_SYSTEM_FILE_WRAPPER_H_ #include +#include #include #include diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index 5ead8a0506..7765cf522b 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -379,28 +379,38 @@ if (!build_with_chromium) { ] deps = [ ":chart_proto", + "../api:dtls_transport_interface", "../api:function_view", + "../api:make_ref_counted", "../api:network_state_predictor_api", - "../modules/audio_coding:neteq_input_audio_tools", - "../modules/audio_coding:neteq_tools_minimal", - "../rtc_base:ignore_wundef", - "../rtc_base:logging", - "../rtc_base:macromagic", - "../rtc_base:rate_statistics", - "../rtc_base:refcount", - - # TODO(kwiberg): Remove this dependency. - "../api/audio_codecs:audio_codecs_api", + "../api:rtp_headers", + "../api:rtp_parameters", + "../api:scoped_refptr", + "../api/audio_codecs:audio_codecs_api", # TODO(kwiberg): Remove this + # dependency. + "../api/neteq:neteq_api", + "../api/rtc_event_log:rtc_event_log", "../api/transport:field_trial_based_config", "../api/transport:goog_cc", "../api/transport:network_control", + "../api/units:data_rate", + "../api/units:time_delta", + "../api/units:timestamp", "../call:call_interfaces", "../call:video_stream_api", + "../logging:ice_log", + "../logging:rtc_event_audio", + "../logging:rtc_event_audio", + "../logging:rtc_event_bwe", + "../logging:rtc_event_generic_packet_events", "../logging:rtc_event_log_parser", + "../logging:rtc_event_rtp_rtcp", "../logging:rtc_stream_config", "../modules/audio_coding:ana_debug_dump_proto", "../modules/audio_coding:audio_network_adaptor", + "../modules/audio_coding:neteq_input_audio_tools", "../modules/audio_coding:neteq_tools", + "../modules/audio_coding:neteq_tools_minimal", "../modules/congestion_controller", "../modules/congestion_controller/goog_cc:delay_based_bwe", "../modules/congestion_controller/goog_cc:estimators", @@ -410,8 +420,14 @@ if (!build_with_chromium) { "../modules/rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", + "../rtc_base:ignore_wundef", + "../rtc_base:logging", + "../rtc_base:macromagic", + "../rtc_base:rate_statistics", + "../rtc_base:refcount", "../rtc_base:rtc_numerics", "../rtc_base:stringutils", + "../rtc_base/network:sent_packet", "../system_wrappers", "../test:explicit_key_value_config", ] @@ -423,6 +439,36 @@ if (!build_with_chromium) { "//third_party/abseil-cpp/absl/types:optional", ] } + + rtc_library("event_log_visualizer_bindings") { + visibility = [ "*" ] + sources = [ + "rtc_event_log_visualizer/analyzer_bindings.cc", + "rtc_event_log_visualizer/analyzer_bindings.h", + ] + deps = [ + ":chart_proto", + ":event_log_visualizer_utils", + "//api/units:time_delta", + "//logging:rtc_event_log_parser", + "//rtc_base:protobuf_utils", + "//rtc_base:safe_conversions", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } + + rtc_library("event_log_visualizer_bindings_unittest") { + testonly = true + sources = [ "rtc_event_log_visualizer/analyzer_bindings_unittest.cc" ] + deps = [ + ":chart_proto", + ":event_log_visualizer_bindings", + "//rtc_base:protobuf_utils", + "//rtc_base/system:file_wrapper", + "//test:fileutils", + "//test:test_support", + ] + } } rtc_executable("video_encoder") { @@ -439,6 +485,7 @@ if (!build_with_chromium) { "//api/video:builtin_video_bitrate_allocator_factory", "//api/video_codecs:builtin_video_encoder_factory", "//api/video_codecs:video_codecs_api", + "//media:media_constants", "//modules/video_coding:video_codec_interface", "//modules/video_coding:video_coding_utility", "//modules/video_coding/codecs/av1:av1_svc_config", @@ -521,6 +568,7 @@ if (rtc_include_tests) { "../resources/foreman_128x96.yuv", "../resources/foreman_cif.yuv", "../resources/reference_less_video_test_file.y4m", + "../resources/rtc_event_log/rtc_event_log_500kbps.binarypb", ] if (is_ios) { @@ -572,7 +620,10 @@ if (rtc_include_tests) { } if (rtc_enable_protobuf) { - deps += [ "network_tester:network_tester_unittests" ] + deps += [ + ":event_log_visualizer_bindings_unittest", + "network_tester:network_tester_unittests", + ] } data = tools_unittests_resources diff --git a/rtc_tools/network_tester/BUILD.gn b/rtc_tools/network_tester/BUILD.gn index e33a3c000f..efe2123510 100644 --- a/rtc_tools/network_tester/BUILD.gn +++ b/rtc_tools/network_tester/BUILD.gn @@ -86,6 +86,7 @@ if (rtc_enable_protobuf) { deps = [ ":network_tester", "../../rtc_base:gunit_helpers", + "../../rtc_base:random", "../../rtc_base:threading", "../../test:fileutils", "../../test:test_support", diff --git a/rtc_tools/network_tester/network_tester_unittest.cc b/rtc_tools/network_tester/network_tester_unittest.cc index 60b34e4e9f..ea0ebf98f8 100644 --- a/rtc_tools/network_tester/network_tester_unittest.cc +++ b/rtc_tools/network_tester/network_tester_unittest.cc @@ -13,6 +13,7 @@ #include #include "rtc_base/gunit.h" +#include "rtc_base/random.h" #include "rtc_tools/network_tester/test_controller.h" #include "test/gtest.h" #include "test/testsupport/file_utils.h" @@ -20,15 +21,22 @@ namespace webrtc { TEST(NetworkTesterTest, ServerClient) { + // Use a unique port rather than a hard-coded one to avoid collision when + // running the test in parallel in stress runs. Skipping all reserved ports. + const int MIN_PORT = 49152; + const int MAX_PORT = 65535; + int port = webrtc::Random(rtc::TimeMicros()).Rand(MIN_PORT, MAX_PORT); + rtc::AutoThread main_thread; + TestController client( 0, 0, webrtc::test::ResourcePath("network_tester/client_config", "dat"), webrtc::test::OutputPath() + "client_packet_log.dat"); TestController server( - 9090, 9090, + port, port, webrtc::test::ResourcePath("network_tester/server_config", "dat"), webrtc::test::OutputPath() + "server_packet_log.dat"); - client.SendConnectTo("127.0.0.1", 9090); + client.SendConnectTo("127.0.0.1", port); EXPECT_TRUE_WAIT(server.IsTestDone() && client.IsTestDone(), 2000); } diff --git a/rtc_tools/network_tester/test_controller.cc b/rtc_tools/network_tester/test_controller.cc index 6fe83fd430..3d9af380f1 100644 --- a/rtc_tools/network_tester/test_controller.cc +++ b/rtc_tools/network_tester/test_controller.cc @@ -43,6 +43,7 @@ TestController::TestController(int min_port, udp_socket_ = std::unique_ptr(socket_factory_.CreateUdpSocket( rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0), min_port, max_port)); + RTC_CHECK(udp_socket_ != nullptr); udp_socket_->SignalReadPacket.connect(this, &TestController::OnReadPacket); }); } diff --git a/rtc_tools/rtc_event_log_to_text/converter.cc b/rtc_tools/rtc_event_log_to_text/converter.cc index f171260a4e..90d568f30f 100644 --- a/rtc_tools/rtc_event_log_to_text/converter.cc +++ b/rtc_tools/rtc_event_log_to_text/converter.cc @@ -430,7 +430,8 @@ bool Convert(std::string inputfile, {VideoCodecType::kVideoCodecVP9, "VP9"}, {VideoCodecType::kVideoCodecAV1, "AV1"}, {VideoCodecType::kVideoCodecH264, "H264"}, - {VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"}}; + {VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"}, + {VideoCodecType::kVideoCodecH265, "H265"}}; fprintf(output, "FRAME_DECODED %" PRId64 " render_time=%" PRId64 diff --git a/rtc_tools/rtc_event_log_visualizer/alerts.cc b/rtc_tools/rtc_event_log_visualizer/alerts.cc index a9f50cdd5c..98ffbd372e 100644 --- a/rtc_tools/rtc_event_log_visualizer/alerts.cc +++ b/rtc_tools/rtc_event_log_visualizer/alerts.cc @@ -13,15 +13,18 @@ #include #include -#include +#include +#include +#include #include #include -#include "logging/rtc_event_log/rtc_event_processor.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" +#include "absl/types/optional.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/logged_rtp_rtcp.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" -#include "rtc_base/strings/string_builder.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" namespace webrtc { diff --git a/rtc_tools/rtc_event_log_visualizer/alerts.h b/rtc_tools/rtc_event_log_visualizer/alerts.h index 72f1241d50..d421ceb95f 100644 --- a/rtc_tools/rtc_event_log_visualizer/alerts.h +++ b/rtc_tools/rtc_event_log_visualizer/alerts.h @@ -13,6 +13,7 @@ #include +#include #include #include #include diff --git a/rtc_tools/rtc_event_log_visualizer/analyze_audio.cc b/rtc_tools/rtc_event_log_visualizer/analyze_audio.cc index 29dc26c22f..af6e2ee124 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyze_audio.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyze_audio.cc @@ -10,18 +10,39 @@ #include "rtc_tools/rtc_event_log_visualizer/analyze_audio.h" +#include +#include #include #include +#include #include #include +#include "absl/strings/string_view.h" +#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_decoder_factory.h" +#include "api/audio_codecs/audio_format.h" +#include "api/function_view.h" +#include "api/make_ref_counted.h" +#include "api/neteq/neteq.h" +#include "api/scoped_refptr.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/audio_coding/neteq/tools/audio_sink.h" #include "modules/audio_coding/neteq/tools/fake_decode_from_file.h" #include "modules/audio_coding/neteq/tools/neteq_delay_analyzer.h" #include "modules/audio_coding/neteq/tools/neteq_event_log_input.h" +#include "modules/audio_coding/neteq/tools/neteq_input.h" #include "modules/audio_coding/neteq/tools/neteq_replacement_input.h" +#include "modules/audio_coding/neteq/tools/neteq_stats_getter.h" #include "modules/audio_coding/neteq/tools/neteq_test.h" #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" +#include "rtc_base/checks.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" +#include "rtc_tools/rtc_event_log_visualizer/plot_base.h" namespace webrtc { diff --git a/rtc_tools/rtc_event_log_visualizer/analyze_audio.h b/rtc_tools/rtc_event_log_visualizer/analyze_audio.h index 726e84492d..586d6ce0ea 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyze_audio.h +++ b/rtc_tools/rtc_event_log_visualizer/analyze_audio.h @@ -17,6 +17,7 @@ #include #include "api/function_view.h" +#include "api/neteq/neteq.h" #include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/audio_coding/neteq/tools/neteq_stats_getter.h" #include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.cc b/rtc_tools/rtc_event_log_visualizer/analyzer.cc index 9907a367e9..1d8d5f12c0 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.cc @@ -12,48 +12,64 @@ #include #include +#include +#include +#include #include #include #include #include +#include #include +#include #include "absl/algorithm/container.h" #include "absl/functional/bind_front.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/dtls_transport_interface.h" #include "api/function_view.h" +#include "api/media_types.h" #include "api/network_state_predictor.h" -#include "api/transport/field_trial_based_config.h" +#include "api/rtc_event_log/rtc_event_log.h" +#include "api/rtp_headers.h" #include "api/transport/goog_cc_factory.h" -#include "call/audio_receive_stream.h" -#include "call/audio_send_stream.h" -#include "call/call.h" -#include "call/video_receive_stream.h" -#include "call/video_send_stream.h" +#include "api/transport/network_control.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/logged_rtp_rtcp.h" +#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h" +#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "logging/rtc_event_log/rtc_event_processor.h" -#include "logging/rtc_event_log/rtc_stream_config.h" -#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" -#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" -#include "modules/congestion_controller/goog_cc/bitrate_estimator.h" -#include "modules/congestion_controller/goog_cc/delay_based_bwe.h" +#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h" #include "modules/congestion_controller/include/receive_side_congestion_controller.h" #include "modules/congestion_controller/rtp/transport_feedback_adapter.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.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/rtcp_packet.h" -#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h" #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.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_interface.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/network/sent_packet.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" #include "rtc_base/rate_statistics.h" #include "rtc_base/strings/string_builder.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" #include "rtc_tools/rtc_event_log_visualizer/log_simulation.h" +#include "rtc_tools/rtc_event_log_visualizer/plot_base.h" +#include "system_wrappers/include/clock.h" #include "test/explicit_key_value_config.h" namespace webrtc { @@ -406,6 +422,12 @@ RtpPacketReceived RtpPacketForBWEFromHeader(const RTPHeader& header) { return rtp_packet; } +struct PacketLossSummary { + size_t num_packets = 0; + size_t num_lost_packets = 0; + Timestamp base_time = Timestamp::MinusInfinity(); +}; + } // namespace EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log, @@ -1298,6 +1320,100 @@ void EventLogAnalyzer::CreateGoogCcSimulationGraph(Plot* plot) { plot->SetTitle("Simulated BWE behavior"); } +void EventLogAnalyzer::CreateOutgoingTWCCLossRateGraph(Plot* plot) { + TimeSeries loss_rate_series("Loss rate (from packet feedback)", + LineStyle::kLine, PointStyle::kHighlight); + TimeSeries average_loss_rate_series("Average loss rate last 5s", + LineStyle::kLine, PointStyle::kHighlight); + TimeSeries missing_feedback_series("Missing feedback", LineStyle::kNone, + PointStyle::kHighlight); + PacketLossSummary window_summary; + Timestamp last_observation_receive_time = Timestamp::Zero(); + + // Use loss based bwe 2 observation duration and observation window size. + constexpr TimeDelta kObservationDuration = TimeDelta::Millis(250); + constexpr uint32_t kObservationWindowSize = 20; + std::deque observations; + SeqNumUnwrapper unwrapper; + int64_t last_acked = 1; + if (!parsed_log_.transport_feedbacks(kIncomingPacket).empty()) { + last_acked = + unwrapper.Unwrap(parsed_log_.transport_feedbacks(kIncomingPacket)[0] + .transport_feedback.GetBaseSequence()); + } + for (auto& feedback : parsed_log_.transport_feedbacks(kIncomingPacket)) { + const rtcp::TransportFeedback& transport_feedback = + feedback.transport_feedback; + size_t base_seq_num = + unwrapper.Unwrap(transport_feedback.GetBaseSequence()); + // Collect packets that do not have feedback, which are from the last acked + // packet, to the current base packet. + for (size_t seq_num = last_acked; seq_num < base_seq_num; ++seq_num) { + missing_feedback_series.points.emplace_back( + config_.GetCallTimeSec(feedback.timestamp), + 100 + seq_num - last_acked); + } + last_acked = base_seq_num + transport_feedback.GetPacketStatusCount(); + + // Compute loss rate from the transport feedback. + auto loss_rate = + static_cast((transport_feedback.GetPacketStatusCount() - + transport_feedback.GetReceivedPackets().size()) * + 100.0 / transport_feedback.GetPacketStatusCount()); + loss_rate_series.points.emplace_back( + config_.GetCallTimeSec(feedback.timestamp), loss_rate); + + // Compute loss rate in a window of kObservationWindowSize. + if (window_summary.num_packets == 0) { + window_summary.base_time = feedback.log_time(); + } + window_summary.num_packets += transport_feedback.GetPacketStatusCount(); + window_summary.num_lost_packets += + transport_feedback.GetPacketStatusCount() - + transport_feedback.GetReceivedPackets().size(); + + const Timestamp last_received_time = feedback.log_time(); + const TimeDelta observation_duration = + window_summary.base_time == Timestamp::Zero() + ? TimeDelta::Zero() + : last_received_time - window_summary.base_time; + if (observation_duration > kObservationDuration) { + last_observation_receive_time = last_received_time; + observations.push_back(window_summary); + if (observations.size() > kObservationWindowSize) { + observations.pop_front(); + } + + // Compute average loss rate in a number of windows. + int total_packets = 0; + int total_loss = 0; + for (const auto& observation : observations) { + total_loss += observation.num_lost_packets; + total_packets += observation.num_packets; + } + if (total_packets > 0) { + float average_loss_rate = total_loss * 100.0 / total_packets; + average_loss_rate_series.points.emplace_back( + config_.GetCallTimeSec(feedback.timestamp), average_loss_rate); + } else { + average_loss_rate_series.points.emplace_back( + config_.GetCallTimeSec(feedback.timestamp), 0); + } + window_summary = PacketLossSummary(); + } + } + // Add the data set to the plot. + plot->AppendTimeSeriesIfNotEmpty(std::move(loss_rate_series)); + plot->AppendTimeSeriesIfNotEmpty(std::move(average_loss_rate_series)); + plot->AppendTimeSeriesIfNotEmpty(std::move(missing_feedback_series)); + + plot->SetXAxis(config_.CallBeginTimeSec(), config_.CallEndTimeSec(), + "Time (s)", kLeftMargin, kRightMargin); + plot->SetSuggestedYAxis(0, 100, "Loss rate (percent)", kBottomMargin, + kTopMargin); + plot->SetTitle("Outgoing loss rate (from TWCC feedback)"); +} + void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { using RtpPacketType = LoggedRtpPacketOutgoing; using TransportFeedbackType = LoggedRtcpPacketTransportFeedback; @@ -1364,16 +1480,15 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { RateStatistics raw_acked_bitrate(750, 8000); test::ExplicitKeyValueConfig throughput_config( - "WebRTC-Bwe-RobustThroughputEstimatorSettings/" - "enabled:true,required_packets:10," - "window_packets:25,window_duration:1000ms,unacked_weight:1.0/"); + "WebRTC-Bwe-RobustThroughputEstimatorSettings/enabled:true/"); std::unique_ptr robust_throughput_estimator( AcknowledgedBitrateEstimatorInterface::Create(&throughput_config)); - FieldTrialBasedConfig field_trial_config; + test::ExplicitKeyValueConfig acked_bitrate_config( + "WebRTC-Bwe-RobustThroughputEstimatorSettings/enabled:false/"); std::unique_ptr acknowledged_bitrate_estimator( - AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config)); + AcknowledgedBitrateEstimatorInterface::Create(&acked_bitrate_config)); int64_t time_us = std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()}); int64_t last_update_us = 0; diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.h b/rtc_tools/rtc_event_log_visualizer/analyzer.h index e58a4823f7..3dfd5de616 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.h +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.h @@ -11,16 +11,15 @@ #ifndef RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_H_ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_H_ +#include +#include #include -#include -#include #include -#include #include +#include "api/function_view.h" #include "logging/rtc_event_log/rtc_event_log_parser.h" -#include "modules/audio_coding/neteq/tools/neteq_stats_getter.h" -#include "rtc_base/strings/string_builder.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" #include "rtc_tools/rtc_event_log_visualizer/plot_base.h" @@ -67,6 +66,7 @@ class EventLogAnalyzer { void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot); void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot); + void CreateOutgoingTWCCLossRateGraph(Plot* plot); void CreateGoogCcSimulationGraph(Plot* plot); void CreateSendSideBweSimulationGraph(Plot* plot); void CreateReceiveSideBweSimulationGraph(Plot* plot); diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc new file mode 100644 index 0000000000..829591323f --- /dev/null +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2023 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_tools/rtc_event_log_visualizer/analyzer_bindings.h" + +#include +#include +#include +#include + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "api/units/time_delta.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/protobuf_utils.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer.h" +#include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" +#include "rtc_tools/rtc_event_log_visualizer/plot_base.h" + +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#else +#include "rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#endif + +using webrtc::PacketDirection; + +void analyze_rtc_event_log(const char* log_contents, + size_t log_size, + const char* selection, + size_t selection_size, + char* output, + uint32_t* output_size) { + webrtc::ParsedRtcEventLog parsed_log( + webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions::kDontParse, + /*allow_incomplete_logs*/ false); + + absl::string_view log_view(log_contents, log_size); + auto status = parsed_log.ParseString(log_view); + if (!status.ok()) { + std::cerr << "Failed to parse log: " << status.message() << std::endl; + *output_size = 0; + return; + } + + webrtc::AnalyzerConfig config; + config.window_duration_ = webrtc::TimeDelta::Millis(250); + config.step_ = webrtc::TimeDelta::Millis(10); + if (!parsed_log.start_log_events().empty()) { + config.rtc_to_utc_offset_ = parsed_log.start_log_events()[0].utc_time() - + parsed_log.start_log_events()[0].log_time(); + } + config.normalize_time_ = true; + config.begin_time_ = parsed_log.first_timestamp(); + config.end_time_ = parsed_log.last_timestamp(); + if (config.end_time_ < config.begin_time_) { + std::cerr << "Log end time " << config.end_time_.ms() + << " not after begin time " << config.begin_time_.ms() + << ". Nothing to analyze. Is the log broken?"; + *output_size = 0; + return; + } + + absl::string_view selection_view(selection, selection_size); + webrtc::EventLogAnalyzer analyzer(parsed_log, config); + webrtc::PlotCollection collection; + collection.SetCallTimeToUtcOffsetMs(config.CallTimeToUtcOffsetMs()); + + // Outgoing + if (absl::StrContains(selection_view, "outgoing_packet_sizes")) { + analyzer.CreatePacketGraph( + PacketDirection::kOutgoingPacket, + collection.AppendNewPlot("outgoing_packet_sizes")); + } + if (absl::StrContains(selection_view, "outgoing_stream_bitrate")) { + analyzer.CreateStreamBitrateGraph( + PacketDirection::kOutgoingPacket, + collection.AppendNewPlot("outgoing_stream_bitrate")); + } + if (absl::StrContains(selection_view, "outgoing_bitrate")) { + analyzer.CreateTotalOutgoingBitrateGraph( + collection.AppendNewPlot("outgoing_bitrate"), + /*show_detector_state*/ true, + /*show_alr_state*/ false, + /*show_link_capacity*/ true); + } + if (absl::StrContains(selection_view, "network_delay_feedback")) { + analyzer.CreateNetworkDelayFeedbackGraph( + collection.AppendNewPlot("network_delay_feedback")); + } + if (absl::StrContains(selection_view, "fraction_loss_feedback")) { + analyzer.CreateFractionLossGraph( + collection.AppendNewPlot("fraction_loss_feedback")); + } + + // Incoming + if (absl::StrContains(selection_view, "incoming_packet_sizes")) { + analyzer.CreatePacketGraph( + PacketDirection::kIncomingPacket, + collection.AppendNewPlot("incoming_packet_sizes")); + } + if (absl::StrContains(selection_view, "incoming_stream_bitrate")) { + analyzer.CreateStreamBitrateGraph( + PacketDirection::kIncomingPacket, + collection.AppendNewPlot("incoming_stream_bitrate")); + } + if (absl::StrContains(selection_view, "incoming_bitrate")) { + analyzer.CreateTotalIncomingBitrateGraph( + collection.AppendNewPlot("incoming_bitrate")); + } + if (absl::StrContains(selection_view, "incoming_delay")) { + analyzer.CreateIncomingDelayGraph( + collection.AppendNewPlot("incoming_delay")); + } + if (absl::StrContains(selection_view, "incoming_loss_rate")) { + analyzer.CreateIncomingPacketLossGraph( + collection.AppendNewPlot("incoming_loss_rate")); + } + + webrtc::analytics::ChartCollection proto_charts; + collection.ExportProtobuf(&proto_charts); + std::string serialized_charts = proto_charts.SerializeAsString(); + if (rtc::checked_cast(serialized_charts.size()) > *output_size) { + std::cerr << "Serialized charts larger than available output buffer: " + << serialized_charts.size() << " vs " << *output_size; + *output_size = 0; + return; + } + + memcpy(output, serialized_charts.data(), serialized_charts.size()); + *output_size = rtc::checked_cast(serialized_charts.size()); +} diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h new file mode 100644 index 0000000000..6662d9bc0e --- /dev/null +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 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_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_BINDINGS_H_ +#define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_BINDINGS_H_ + +#include +#include + +void analyze_rtc_event_log(const char* log_contents, + size_t log_size, + const char* selection, + size_t selection_size, + char* output, + uint32_t* output_size); + +#endif // RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_BINDINGS_H_ diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc new file mode 100644 index 0000000000..feb8104297 --- /dev/null +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_bindings_unittest.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 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_tools/rtc_event_log_visualizer/analyzer_bindings.h" + +#include +#include +#include + +#include "rtc_base/protobuf_utils.h" +#include "rtc_base/system/file_wrapper.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" + +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#else +#include "rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h" +#endif + +TEST(RtcEventLogAnalyzerBindingsTest, ProducesCharts) { + constexpr int kInputBufferSize = 1'000'000; + constexpr int kOutputBufferSize = 1'000'000; + std::unique_ptr input = std::make_unique(kInputBufferSize); + std::unique_ptr output = std::make_unique(kOutputBufferSize); + + // Read an RTC event log to a char buffer. + std::string file_name = webrtc::test::ResourcePath( + "rtc_event_log/rtc_event_log_500kbps", "binarypb"); + webrtc::FileWrapper file = webrtc::FileWrapper::OpenReadOnly(file_name); + ASSERT_TRUE(file.is_open()); + int64_t file_size = file.FileSize(); + ASSERT_LE(file_size, kInputBufferSize); + ASSERT_GT(file_size, 0); + size_t input_size = file.Read(input.get(), static_cast(file_size)); + ASSERT_EQ(static_cast(file_size), input_size); + + // Call analyzer. + uint32_t output_size = kOutputBufferSize; + char selection[] = "outgoing_bitrate,network_delay_feedback"; + size_t selection_size = strlen(selection); + analyze_rtc_event_log(input.get(), input_size, selection, selection_size, + output.get(), &output_size); + ASSERT_GT(output_size, 0u); + + // Parse output as charts. + webrtc::analytics::ChartCollection collection; + bool success = + collection.ParseFromArray(output.get(), static_cast(output_size)); + ASSERT_TRUE(success); + EXPECT_EQ(collection.charts().size(), 2); + std::vector chart_titles; + for (const auto& chart : collection.charts()) { + chart_titles.push_back(chart.title()); + } + EXPECT_THAT(chart_titles, + ::testing::UnorderedElementsAre( + "Outgoing RTP bitrate", + "Outgoing network delay (based on per-packet feedback)")); + std::vector chart_ids; + for (const auto& chart : collection.charts()) { + chart_ids.push_back(chart.id()); + } + EXPECT_THAT(chart_ids, ::testing::UnorderedElementsAre( + "outgoing_bitrate", "network_delay_feedback")); +} diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_common.cc b/rtc_tools/rtc_event_log_visualizer/analyzer_common.cc index 3d3ce5a4ac..be635fb48c 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer_common.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_common.cc @@ -11,6 +11,12 @@ #include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" +#include +#include + +#include "logging/rtc_event_log/rtc_event_log_parser.h" +#include "rtc_base/strings/string_builder.h" + namespace webrtc { bool IsRtxSsrc(const ParsedRtcEventLog& parsed_log, diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer_common.h b/rtc_tools/rtc_event_log_visualizer/analyzer_common.h index b0b556aa62..5f778cb156 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer_common.h +++ b/rtc_tools/rtc_event_log_visualizer/analyzer_common.h @@ -11,11 +11,14 @@ #ifndef RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_COMMON_H_ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_ANALYZER_COMMON_H_ +#include #include #include #include "absl/types/optional.h" #include "api/function_view.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "logging/rtc_event_log/rtc_event_log_parser.h" #include "rtc_tools/rtc_event_log_visualizer/plot_base.h" diff --git a/rtc_tools/rtc_event_log_visualizer/log_simulation.cc b/rtc_tools/rtc_event_log_visualizer/log_simulation.cc index 4c6c329c97..a32c800b70 100644 --- a/rtc_tools/rtc_event_log_visualizer/log_simulation.cc +++ b/rtc_tools/rtc_event_log_visualizer/log_simulation.cc @@ -10,10 +10,24 @@ #include "rtc_tools/rtc_event_log_visualizer/log_simulation.h" #include +#include +#include +#include #include +#include "api/transport/network_control.h" +#include "api/transport/network_types.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/logged_rtp_rtcp.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" +#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "logging/rtc_event_log/rtc_event_processor.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/network/sent_packet.h" #include "system_wrappers/include/clock.h" namespace webrtc { @@ -72,7 +86,7 @@ void LogBasedNetworkControllerSimulation::OnPacketSent( packet.media_type == LoggedMediaType::kVideo) { auto& probe = pending_probes_.front(); probe_info.probe_cluster_id = probe.event.id; - probe_info.send_bitrate_bps = probe.event.bitrate_bps; + probe_info.send_bitrate = DataRate::BitsPerSec(probe.event.bitrate_bps); probe_info.probe_cluster_min_bytes = probe.event.min_bytes; probe_info.probe_cluster_min_probes = probe.event.min_packets; probe.packets_sent++; diff --git a/rtc_tools/rtc_event_log_visualizer/log_simulation.h b/rtc_tools/rtc_event_log_visualizer/log_simulation.h index 15ed25388c..dbb0a1c798 100644 --- a/rtc_tools/rtc_event_log_visualizer/log_simulation.h +++ b/rtc_tools/rtc_event_log_visualizer/log_simulation.h @@ -10,15 +10,23 @@ #ifndef RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_LOG_SIMULATION_H_ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_LOG_SIMULATION_H_ +#include +#include #include #include #include #include -#include +#include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/network_control.h" +#include "api/transport/network_types.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/events/logged_rtp_rtcp.h" +#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" +#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/congestion_controller/rtp/transport_feedback_adapter.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" namespace webrtc { diff --git a/rtc_tools/rtc_event_log_visualizer/main.cc b/rtc_tools/rtc_event_log_visualizer/main.cc index aa52527903..e9a747ceb7 100644 --- a/rtc_tools/rtc_event_log_visualizer/main.cc +++ b/rtc_tools/rtc_event_log_visualizer/main.cc @@ -227,7 +227,7 @@ int main(int argc, char* argv[]) { {"sendside_bwe", {"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate", "simulated_sendside_bwe", "network_delay_feedback", - "fraction_loss_feedback"}}, + "fraction_loss_feedback", "outgoing_twcc_loss"}}, {"receiveside_bwe", {"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate", "incoming_bitrate", "incoming_stream_bitrate", @@ -377,6 +377,9 @@ int main(int argc, char* argv[]) { plots.RegisterPlot("simulated_goog_cc", [&](Plot* plot) { analyzer.CreateGoogCcSimulationGraph(plot); }); + plots.RegisterPlot("outgoing_twcc_loss", [&](Plot* plot) { + analyzer.CreateOutgoingTWCCLossRateGraph(plot); + }); plots.RegisterPlot("network_delay_feedback", [&](Plot* plot) { analyzer.CreateNetworkDelayFeedbackGraph(plot); }); @@ -610,9 +613,8 @@ int main(int argc, char* argv[]) { for (const auto& plot : plots) { if (plot.enabled) { - Plot* output = collection.AppendNewPlot(); + Plot* output = collection.AppendNewPlot(plot.label); plot.plot_func(output); - output->SetId(plot.label); } } diff --git a/rtc_tools/rtc_event_log_visualizer/plot_base.cc b/rtc_tools/rtc_event_log_visualizer/plot_base.cc index 294500ccf1..597a22c822 100644 --- a/rtc_tools/rtc_event_log_visualizer/plot_base.cc +++ b/rtc_tools/rtc_event_log_visualizer/plot_base.cc @@ -11,8 +11,14 @@ #include "rtc_tools/rtc_event_log_visualizer/plot_base.h" #include +#include +#include #include +#include +#include +#include +#include "absl/strings/string_view.h" #include "rtc_base/checks.h" namespace webrtc { @@ -80,6 +86,10 @@ void Plot::SetId(const std::string& id) { id_ = id; } +void Plot::SetId(absl::string_view id) { + id_ = id; +} + void Plot::AppendTimeSeries(TimeSeries&& time_series) { series_list_.emplace_back(std::move(time_series)); } @@ -338,4 +348,10 @@ Plot* PlotCollection::AppendNewPlot() { return plots_.back().get(); } +Plot* PlotCollection::AppendNewPlot(absl::string_view chart_id) { + plots_.push_back(std::make_unique()); + plots_.back()->SetId(chart_id); + return plots_.back().get(); +} + } // namespace webrtc diff --git a/rtc_tools/rtc_event_log_visualizer/plot_base.h b/rtc_tools/rtc_event_log_visualizer/plot_base.h index bc753e320c..e970a6eeb8 100644 --- a/rtc_tools/rtc_event_log_visualizer/plot_base.h +++ b/rtc_tools/rtc_event_log_visualizer/plot_base.h @@ -10,6 +10,7 @@ #ifndef RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_PLOT_BASE_H_ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_PLOT_BASE_H_ +#include #include #include #include @@ -156,6 +157,7 @@ class Plot { // the title might change in future releases whereas the ID should be stable // over time. void SetId(const std::string& id); + void SetId(absl::string_view id); // Add a new TimeSeries to the plot. void AppendTimeSeries(TimeSeries&& time_series); @@ -197,6 +199,8 @@ class PlotCollection { virtual Plot* AppendNewPlot(); + virtual Plot* AppendNewPlot(absl::string_view); + void SetCallTimeToUtcOffsetMs(int64_t calltime_to_utc_ms) { calltime_to_utc_ms_ = calltime_to_utc_ms; } diff --git a/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto b/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto index 985ad0ad7d..8df7770e53 100644 --- a/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto +++ b/rtc_tools/rtc_event_log_visualizer/proto/chart_enums.proto @@ -1,5 +1,6 @@ syntax = "proto3"; // Contains enums used as part of chart.proto +option optimize_for = LITE_RUNTIME; package webrtc.analytics; message ChartStyle { diff --git a/rtc_tools/video_encoder/video_encoder.cc b/rtc_tools/video_encoder/video_encoder.cc index a2eeef8d5f..9436910ed3 100644 --- a/rtc_tools/video_encoder/video_encoder.cc +++ b/rtc_tools/video_encoder/video_encoder.cc @@ -16,6 +16,7 @@ #include "api/test/frame_generator_interface.h" #include "api/video/builtin_video_bitrate_allocator_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" +#include "media/base/media_constants.h" #include "modules/video_coding/codecs/av1/av1_svc_config.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/svc/scalability_mode_util.h" @@ -72,9 +73,6 @@ ABSL_FLAG(bool, verbose, false, "Verbose logs to stderr"); namespace webrtc { namespace { -// See `WebRtcVideoSendChannel::kDefaultQpMax`. -constexpr unsigned int kDefaultQpMax = 56; - [[maybe_unused]] const char* InterLayerPredModeToString( const InterLayerPredMode& inter_layer_pred_mode) { switch (inter_layer_pred_mode) { @@ -95,7 +93,7 @@ std::string ToString(const EncodedImage& encoded_image) { ss << VideoFrameTypeToString(encoded_image._frameType) << ", size=" << encoded_image.size() << ", qp=" << encoded_image.qp_ - << ", timestamp=" << encoded_image.Timestamp(); + << ", timestamp=" << encoded_image.RtpTimestamp(); if (encoded_image.SimulcastIndex()) { ss << ", SimulcastIndex=" << *encoded_image.SimulcastIndex(); @@ -257,8 +255,6 @@ class TestVideoEncoderFactoryWrapper final { video_codec.active = true; - video_codec.qpMax = kDefaultQpMax; - // Simulcast is not implemented at this moment. video_codec.numberOfSimulcastStreams = 0; @@ -270,6 +266,7 @@ class TestVideoEncoderFactoryWrapper final { *(video_codec.VP8()) = VideoEncoder::GetDefaultVp8Settings(); video_codec.VP8()->numberOfTemporalLayers = temporal_layers; + video_codec.qpMax = cricket::kDefaultVideoMaxQpVpx; break; case kVideoCodecVP9: @@ -277,6 +274,7 @@ class TestVideoEncoderFactoryWrapper final { video_codec.VP9()->numberOfSpatialLayers = spatial_layers; video_codec.VP9()->numberOfTemporalLayers = temporal_layers; video_codec.VP9()->interLayerPred = inter_layer_pred_mode; + video_codec.qpMax = cricket::kDefaultVideoMaxQpVpx; break; case kVideoCodecH264: @@ -284,6 +282,7 @@ class TestVideoEncoderFactoryWrapper final { *(video_codec.H264()) = VideoEncoder::GetDefaultH264Settings(); video_codec.H264()->numberOfTemporalLayers = temporal_layers; + video_codec.qpMax = cricket::kDefaultVideoMaxQpH26x; break; case kVideoCodecAV1: @@ -294,8 +293,12 @@ class TestVideoEncoderFactoryWrapper final { } else { RTC_LOG(LS_WARNING) << "Failed to configure svc bitrates for av1."; } + video_codec.qpMax = cricket::kDefaultVideoMaxQpVpx; + break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + video_codec.qpMax = cricket::kDefaultVideoMaxQpH26x; break; - default: RTC_CHECK_NOTREACHED(); break; diff --git a/rtc_tools/video_replay.cc b/rtc_tools/video_replay.cc index 242ce1b2b8..b19850ed57 100644 --- a/rtc_tools/video_replay.cc +++ b/rtc_tools/video_replay.cc @@ -267,6 +267,8 @@ class DecoderIvfFileWriter : public test::FakeDecoder { video_codec_type_ = VideoCodecType::kVideoCodecH264; } else if (codec == "AV1") { video_codec_type_ = VideoCodecType::kVideoCodecAV1; + } else if (codec == "H265") { + video_codec_type_ = VideoCodecType::kVideoCodecH265; } else { RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec; RTC_DCHECK_NOTREACHED(); @@ -492,10 +494,10 @@ class RtpReplayer final { "worker_thread", TaskQueueFactory::Priority::NORMAL)); rtc::Event event; worker_thread_->PostTask([&]() { - Call::Config call_config(&event_log_); + CallConfig call_config(&event_log_); call_config.trials = field_trials_.get(); call_config.task_queue_factory = task_queue_factory; - call_.reset(Call::Create(call_config)); + call_ = Call::Create(call_config); // Creation of the streams must happen inside a task queue because it is // resued as a worker thread. diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 5f494052e2..b0598b4d4e 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -9,6 +9,7 @@ if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") + import("//third_party/jni_zero/jni_zero.gni") import("../../webrtc.gni") group("android") { @@ -220,6 +221,7 @@ if (is_android) { "api/org/webrtc/GlTextureFrameBuffer.java", "api/org/webrtc/GlUtil.java", "api/org/webrtc/JavaI420Buffer.java", + "api/org/webrtc/RenderSynchronizer.java", "api/org/webrtc/RendererCommon.java", "api/org/webrtc/SurfaceTextureHelper.java", "api/org/webrtc/TextureBufferImpl.java", @@ -1475,7 +1477,7 @@ if (is_android) { apk_name = "android_instrumentation_test_apk" android_manifest = "instrumentationtests/AndroidManifest.xml" min_sdk_version = 21 - target_sdk_version = 21 + target_sdk_version = 23 sources = [ "instrumentationtests/src/org/webrtc/AndroidVideoDecoderInstrumentationTest.java", diff --git a/sdk/android/api/org/webrtc/EglRenderer.java b/sdk/android/api/org/webrtc/EglRenderer.java index 5ab0868ef3..f222e6e931 100644 --- a/sdk/android/api/org/webrtc/EglRenderer.java +++ b/sdk/android/api/org/webrtc/EglRenderer.java @@ -591,6 +591,32 @@ public class EglRenderer implements VideoSink { } } + private void swapBuffersOnRenderThread(final VideoFrame frame, long swapBuffersStartTimeNs) { + synchronized (threadLock) { + if (eglThread != null) { + eglThread.scheduleRenderUpdate( + runsInline -> { + if (!runsInline) { + if (eglBase == null || !eglBase.hasSurface()) { + return; + } + eglBase.makeCurrent(); + } + + if (usePresentationTimeStamp) { + eglBase.swapBuffers(frame.getTimestampNs()); + } else { + eglBase.swapBuffers(); + } + + synchronized (statisticsLock) { + renderSwapBufferTimeNs += (System.nanoTime() - swapBuffersStartTimeNs); + } + }); + } + } + } + /** * Renders and releases `pendingFrame`. */ @@ -665,17 +691,11 @@ public class EglRenderer implements VideoSink { eglBase.surfaceWidth(), eglBase.surfaceHeight()); final long swapBuffersStartTimeNs = System.nanoTime(); - if (usePresentationTimeStamp) { - eglBase.swapBuffers(frame.getTimestampNs()); - } else { - eglBase.swapBuffers(); - } + swapBuffersOnRenderThread(frame, swapBuffersStartTimeNs); - final long currentTimeNs = System.nanoTime(); synchronized (statisticsLock) { ++framesRendered; - renderTimeNs += (currentTimeNs - startTimeNs); - renderSwapBufferTimeNs += (currentTimeNs - swapBuffersStartTimeNs); + renderTimeNs += (swapBuffersStartTimeNs - startTimeNs); } } @@ -690,8 +710,8 @@ public class EglRenderer implements VideoSink { drawer.release(); frameDrawer.release(); bitmapTextureFramebuffer.release(); - // Continue here on purpose and retry again for next frame. In worst case, this is a continous - // problem and no more frames will be drawn. + // Continue here on purpose and retry again for next frame. In worst case, this is a + // continuous problem and no more frames will be drawn. } finally { frame.release(); } diff --git a/sdk/android/api/org/webrtc/EglThread.java b/sdk/android/api/org/webrtc/EglThread.java index 47f7810b7c..73323d59c8 100644 --- a/sdk/android/api/org/webrtc/EglThread.java +++ b/sdk/android/api/org/webrtc/EglThread.java @@ -21,7 +21,7 @@ import java.util.List; import org.webrtc.EglBase.EglConnection; /** EGL graphics thread that allows multiple clients to share the same underlying EGLContext. */ -public class EglThread { +public class EglThread implements RenderSynchronizer.Listener { /** Callback for externally managed reference count. */ public interface ReleaseMonitor { /** @@ -31,8 +31,21 @@ public class EglThread { boolean onRelease(EglThread eglThread); } - public static EglThread create(@Nullable ReleaseMonitor releaseMonitor, - @Nullable final EglBase.Context sharedContext, final int[] configAttributes) { + /** Interface for clients to schedule rendering updates that will run synchronized. */ + public interface RenderUpdate { + + /** + * Called by EglThread when the rendering window is open. `runsInline` is true when the update + * is executed directly while the client schedules the update. + */ + void update(boolean runsInline); + } + + public static EglThread create( + @Nullable ReleaseMonitor releaseMonitor, + @Nullable final EglBase.Context sharedContext, + final int[] configAttributes, + @Nullable RenderSynchronizer renderSynchronizer) { final HandlerThread renderThread = new HandlerThread("EglThread"); renderThread.start(); HandlerWithExceptionCallbacks handler = @@ -53,7 +66,17 @@ public class EglThread { }); return new EglThread( - releaseMonitor != null ? releaseMonitor : eglThread -> true, handler, eglConnection); + releaseMonitor != null ? releaseMonitor : eglThread -> true, + handler, + eglConnection, + renderSynchronizer); + } + + public static EglThread create( + @Nullable ReleaseMonitor releaseMonitor, + @Nullable final EglBase.Context sharedContext, + final int[] configAttributes) { + return create(releaseMonitor, sharedContext, configAttributes, /* renderSynchronizer= */ null); } /** @@ -98,12 +121,22 @@ public class EglThread { private final ReleaseMonitor releaseMonitor; private final HandlerWithExceptionCallbacks handler; private final EglConnection eglConnection; + private final RenderSynchronizer renderSynchronizer; + private final List pendingRenderUpdates = new ArrayList<>(); + private boolean renderWindowOpen = true; - private EglThread(ReleaseMonitor releaseMonitor, HandlerWithExceptionCallbacks handler, - EglConnection eglConnection) { + private EglThread( + ReleaseMonitor releaseMonitor, + HandlerWithExceptionCallbacks handler, + EglConnection eglConnection, + RenderSynchronizer renderSynchronizer) { this.releaseMonitor = releaseMonitor; this.handler = handler; this.eglConnection = eglConnection; + this.renderSynchronizer = renderSynchronizer; + if (renderSynchronizer != null) { + renderSynchronizer.registerListener(this); + } } public void release() { @@ -112,6 +145,10 @@ public class EglThread { return; } + if (renderSynchronizer != null) { + renderSynchronizer.removeListener(this); + } + handler.post(eglConnection::release); handler.getLooper().quitSafely(); } @@ -146,4 +183,34 @@ public class EglThread { public void removeExceptionCallback(Runnable callback) { handler.removeExceptionCallback(callback); } + + /** + * Schedules a render update (like swapBuffers) to be run in sync with other updates on the next + * open render window. If the render window is currently open the update will run immediately. + * This method must be called on the EglThread during a render pass. + */ + public void scheduleRenderUpdate(RenderUpdate update) { + if (renderWindowOpen) { + update.update(/* runsInline = */true); + } else { + pendingRenderUpdates.add(update); + } + } + + @Override + public void onRenderWindowOpen() { + handler.post( + () -> { + renderWindowOpen = true; + for (RenderUpdate update : pendingRenderUpdates) { + update.update(/* runsInline = */false); + } + pendingRenderUpdates.clear(); + }); + } + + @Override + public void onRenderWindowClose() { + handler.post(() -> renderWindowOpen = false); + } } diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index db26034be8..bc3491993e 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -542,11 +542,6 @@ public class PeerConnection { // every offer/answer negotiation.This is only intended to be a workaround for crbug.com/835958 public boolean activeResetSrtpParams; - // Whether this client is allowed to switch encoding codec mid-stream. This is a workaround for - // a WebRTC bug where the receiver could get confussed if a codec switch happened mid-call. - // Null indicates no change to currently configured value. - @Nullable public Boolean allowCodecSwitching; - /** * Defines advanced optional cryptographic settings related to SRTP and * frame encryption for native WebRTC. Setting this will overwrite any @@ -615,7 +610,6 @@ public class PeerConnection { activeResetSrtpParams = false; cryptoOptions = null; turnLoggingId = null; - allowCodecSwitching = null; enableImplicitRollback = false; offerExtmapAllowMixed = true; } @@ -811,12 +805,6 @@ public class PeerConnection { return activeResetSrtpParams; } - @Nullable - @CalledByNative("RTCConfiguration") - Boolean getAllowCodecSwitching() { - return allowCodecSwitching; - } - @Nullable @CalledByNative("RTCConfiguration") CryptoOptions getCryptoOptions() { diff --git a/sdk/android/api/org/webrtc/RenderSynchronizer.java b/sdk/android/api/org/webrtc/RenderSynchronizer.java new file mode 100644 index 0000000000..b1ade84298 --- /dev/null +++ b/sdk/android/api/org/webrtc/RenderSynchronizer.java @@ -0,0 +1,116 @@ +/* + * Copyright 2023 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. + */ + +package org.webrtc; + +import android.os.Handler; +import android.os.Looper; +import android.view.Choreographer; +import androidx.annotation.GuardedBy; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; + +/** + * Class to synchronize rendering updates with display refresh cycles and save power by blocking + * updates that exceeds the target frame rate. + */ +public final class RenderSynchronizer { + + /** Interface for listening to render window updates. */ + public interface Listener { + void onRenderWindowOpen(); + + void onRenderWindowClose(); + } + + private static final String TAG = "RenderSynchronizer"; + private static final float DEFAULT_TARGET_FPS = 30f; + private final Object lock = new Object(); + private final List listeners = new CopyOnWriteArrayList<>(); + private final long targetFrameIntervalNanos; + private final Handler mainThreadHandler; + private Choreographer choreographer; + + @GuardedBy("lock") + private boolean isListening; + + private boolean renderWindowOpen; + private long lastRefreshTimeNanos; + private long lastOpenedTimeNanos; + + public RenderSynchronizer(float targetFrameRateFps) { + this.targetFrameIntervalNanos = Math.round(TimeUnit.SECONDS.toNanos(1) / targetFrameRateFps); + this.mainThreadHandler = new Handler(Looper.getMainLooper()); + mainThreadHandler.post(() -> this.choreographer = Choreographer.getInstance()); + Logging.d(TAG, "Created"); + } + + public RenderSynchronizer() { + this(DEFAULT_TARGET_FPS); + } + + public void registerListener(Listener listener) { + listeners.add(listener); + + synchronized (lock) { + if (!isListening) { + Logging.d(TAG, "First listener, subscribing to frame callbacks"); + isListening = true; + mainThreadHandler.post( + () -> choreographer.postFrameCallback(this::onDisplayRefreshCycleBegin)); + } + } + } + + public void removeListener(Listener listener) { + listeners.remove(listener); + } + + private void onDisplayRefreshCycleBegin(long refreshTimeNanos) { + synchronized (lock) { + if (listeners.isEmpty()) { + Logging.d(TAG, "No listeners, unsubscribing to frame callbacks"); + isListening = false; + return; + } + } + choreographer.postFrameCallback(this::onDisplayRefreshCycleBegin); + + long lastOpenDeltaNanos = refreshTimeNanos - lastOpenedTimeNanos; + long refreshDeltaNanos = refreshTimeNanos - lastRefreshTimeNanos; + lastRefreshTimeNanos = refreshTimeNanos; + + // Make a greedy choice whether to open (or keep open) the render window. If the current time + // since the render window was last opened is closer to the target than what we predict it would + // be in the next refresh cycle then we open the window. + if (Math.abs(lastOpenDeltaNanos - targetFrameIntervalNanos) + < Math.abs(lastOpenDeltaNanos - targetFrameIntervalNanos + refreshDeltaNanos)) { + lastOpenedTimeNanos = refreshTimeNanos; + openRenderWindow(); + } else if (renderWindowOpen) { + closeRenderWindow(); + } + } + + private void openRenderWindow() { + renderWindowOpen = true; + for (Listener listener : listeners) { + listener.onRenderWindowOpen(); + } + } + + private void closeRenderWindow() { + renderWindowOpen = false; + for (Listener listener : listeners) { + listener.onRenderWindowClose(); + } + } +} diff --git a/sdk/android/api/org/webrtc/audio/AudioDeviceModule.java b/sdk/android/api/org/webrtc/audio/AudioDeviceModule.java index c4bb45f419..5a0bf5c74d 100644 --- a/sdk/android/api/org/webrtc/audio/AudioDeviceModule.java +++ b/sdk/android/api/org/webrtc/audio/AudioDeviceModule.java @@ -43,4 +43,14 @@ public interface AudioDeviceModule { default boolean setNoiseSuppressorEnabled(boolean enabled) { return false; } + + /** + * Sets the preferred field dimension for the built-in microphone. Returns + * true if setting was successful, otherwise false is returned. + * This functionality can be implemented with + * {@code android.media.MicrophoneDirection.setPreferredMicrophoneFieldDimension}. + */ + default boolean setPreferredMicrophoneFieldDimension(float dimension) { + return false; + } } diff --git a/sdk/android/api/org/webrtc/audio/LegacyAudioDeviceModule.java b/sdk/android/api/org/webrtc/audio/LegacyAudioDeviceModule.java deleted file mode 100644 index de0d0d61f9..0000000000 --- a/sdk/android/api/org/webrtc/audio/LegacyAudioDeviceModule.java +++ /dev/null @@ -1,46 +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. - */ - -package org.webrtc.audio; - -import org.webrtc.voiceengine.WebRtcAudioRecord; -import org.webrtc.voiceengine.WebRtcAudioTrack; - -/** - * This class represents the legacy AudioDeviceModule that is currently hardcoded into C++ WebRTC. - * It will return a null native AudioDeviceModule pointer, leading to an internal object being - * created inside WebRTC that is controlled by static calls to the classes under the voiceengine - * package. Please use the new JavaAudioDeviceModule instead of this class. - */ -@Deprecated -public class LegacyAudioDeviceModule implements AudioDeviceModule { - @Override - public long getNativeAudioDeviceModulePointer() { - // Returning a null pointer will make WebRTC construct the built-in legacy AudioDeviceModule for - // Android internally. - return 0; - } - - @Override - public void release() { - // All control for this ADM goes through static global methods and the C++ object is owned - // internally by WebRTC. - } - - @Override - public void setSpeakerMute(boolean mute) { - WebRtcAudioTrack.setSpeakerMute(mute); - } - - @Override - public void setMicrophoneMute(boolean mute) { - WebRtcAudioRecord.setMicrophoneMute(mute); - } -} diff --git a/sdk/android/instrumentationtests/AndroidManifest.xml b/sdk/android/instrumentationtests/AndroidManifest.xml index 55028da703..445752df05 100644 --- a/sdk/android/instrumentationtests/AndroidManifest.xml +++ b/sdk/android/instrumentationtests/AndroidManifest.xml @@ -16,7 +16,7 @@ - + diff --git a/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java b/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java index 3748cc3f3a..5b3749afba 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java @@ -26,12 +26,18 @@ import androidx.test.filters.SmallTest; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.concurrent.CountDownLatch; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; // EmptyActivity is needed for the surface. +@RunWith(Parameterized.class) public class EglRendererTest { private final static String TAG = "EglRendererTest"; private final static int RENDER_WAIT_MS = 1000; @@ -100,21 +106,37 @@ public class EglRendererTest { } } + @Parameter(0) + public boolean useRenderSynchronizer; + final TestFrameListener testFrameListener = new TestFrameListener(); EglRenderer eglRenderer; + EglThread eglThread; CountDownLatch surfaceReadyLatch = new CountDownLatch(1); int oesTextureId; SurfaceTexture surfaceTexture; + @Parameters + public static Collection data() { + return Arrays.asList(new Object[] {true}, new Object[] {false}); + } + @Before public void setUp() throws Exception { PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions .builder(InstrumentationRegistry.getTargetContext()) .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) .createInitializationOptions()); + RenderSynchronizer renderSynchronizer = useRenderSynchronizer ? new RenderSynchronizer() : null; + eglThread = + EglThread.create( + null /* releaseMonitor */, + null /* sharedContext */, + EglBase.CONFIG_RGBA, + renderSynchronizer); eglRenderer = new EglRenderer("TestRenderer: "); - eglRenderer.init(null /* sharedContext */, EglBase.CONFIG_RGBA, new GlRectDrawer()); + eglRenderer.init(eglThread, new GlRectDrawer(), false /* usePresentationTimeStamp */); oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); surfaceTexture = new SurfaceTexture(oesTextureId); surfaceTexture.setDefaultBufferSize(1 /* width */, 1 /* height */); @@ -244,6 +266,12 @@ public class EglRendererTest { } } + private void drainRenderThread() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + eglThread.getHandler().post(() -> latch.countDown()); + latch.await(); + } + /** Tells eglRenderer to render test frame with given index. */ private void feedFrame(int i) { final VideoFrame.I420Buffer buffer = JavaI420Buffer.wrap(TEST_FRAME_WIDTH, TEST_FRAME_HEIGHT, @@ -350,6 +378,22 @@ public class EglRendererTest { assertFalse(testFrameListener.waitForBitmap(RENDER_WAIT_MS)); } + @Test + @SmallTest + public void testRecreateSurface() throws Exception { + // Make sure the EGLSurface has been created. + drainRenderThread(); + + // Relase the surface and wait for completion. + CountDownLatch latch = new CountDownLatch(1); + eglRenderer.releaseEglSurface(() -> latch.countDown()); + latch.await(); + + // Recreate the surface. + eglRenderer.createEglSurface(surfaceTexture); + drainRenderThread(); + } + private static ByteBuffer[][] copyTestDataToDirectByteBuffers(byte[][][] testData) { final ByteBuffer[][] result = new ByteBuffer[testData.length][]; diff --git a/sdk/android/native_unittests/audio_device/audio_device_unittest.cc b/sdk/android/native_unittests/audio_device/audio_device_unittest.cc index 601f710d22..90476413a2 100644 --- a/sdk/android/native_unittests/audio_device/audio_device_unittest.cc +++ b/sdk/android/native_unittests/audio_device/audio_device_unittest.cc @@ -1154,7 +1154,8 @@ TEST_F(AudioDeviceTest, DISABLED_MeasureLoopbackLatency) { latency_audio_stream->PrintResults(); } -TEST(JavaAudioDeviceTest, TestRunningTwoAdmsSimultaneously) { +// TODO(https://crbug.com/webrtc/15537): test randomly fails. +TEST(JavaAudioDeviceTest, DISABLED_TestRunningTwoAdmsSimultaneously) { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedJavaLocalRef context = GetAppContext(jni); diff --git a/sdk/android/src/java/org/webrtc/EglBase10Impl.java b/sdk/android/src/java/org/webrtc/EglBase10Impl.java index 5f3cd82e13..caa10e7e51 100644 --- a/sdk/android/src/java/org/webrtc/EglBase10Impl.java +++ b/sdk/android/src/java/org/webrtc/EglBase10Impl.java @@ -94,6 +94,7 @@ class EglBase10Impl implements EglBase10 { private final EGLDisplay eglDisplay; private final EGLConfig eglConfig; private final RefCountDelegate refCountDelegate; + private EGLSurface currentSurface = EGL10.EGL_NO_SURFACE; public EglConnection(EGLContext sharedContext, int[] configAttributes) { egl = (EGL10) EGLContext.getEGL(); @@ -111,6 +112,7 @@ class EglBase10Impl implements EglBase10 { } egl.eglDestroyContext(eglDisplay, eglContext); egl.eglTerminate(eglDisplay); + currentSurface = EGL10.EGL_NO_SURFACE; }); } @@ -152,6 +154,31 @@ class EglBase10Impl implements EglBase10 { public EGLConfig getConfig() { return eglConfig; } + + public void makeCurrent(EGLSurface eglSurface) { + if (egl.eglGetCurrentContext() == eglContext && currentSurface == eglSurface) { + return; + } + + synchronized (EglBase.lock) { + if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + throw new GLException(egl.eglGetError(), + "eglMakeCurrent failed: 0x" + Integer.toHexString(egl.eglGetError())); + } + } + currentSurface = eglSurface; + } + + public void detachCurrent() { + synchronized (EglBase.lock) { + if (!egl.eglMakeCurrent( + eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { + throw new GLException(egl.eglGetError(), + "eglDetachCurrent failed: 0x" + Integer.toHexString(egl.eglGetError())); + } + } + currentSurface = EGL10.EGL_NO_SURFACE; + } } // Create a new context with the specified config type, sharing data with sharedContext. @@ -339,27 +366,13 @@ class EglBase10Impl implements EglBase10 { if (eglSurface == EGL10.EGL_NO_SURFACE) { throw new RuntimeException("No EGLSurface - can't make current"); } - synchronized (EglBase.lock) { - EGL10 egl = eglConnection.getEgl(); - if (!egl.eglMakeCurrent( - eglConnection.getDisplay(), eglSurface, eglSurface, eglConnection.getContext())) { - throw new GLException(egl.eglGetError(), - "eglMakeCurrent failed: 0x" + Integer.toHexString(egl.eglGetError())); - } - } + eglConnection.makeCurrent(eglSurface); } // Detach the current EGL context, so that it can be made current on another thread. @Override public void detachCurrent() { - synchronized (EglBase.lock) { - EGL10 egl = eglConnection.getEgl(); - if (!egl.eglMakeCurrent(eglConnection.getDisplay(), EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { - throw new GLException(egl.eglGetError(), - "eglDetachCurrent failed: 0x" + Integer.toHexString(egl.eglGetError())); - } - } + eglConnection.detachCurrent(); } @Override diff --git a/sdk/android/src/java/org/webrtc/EglBase14Impl.java b/sdk/android/src/java/org/webrtc/EglBase14Impl.java index 4c0a3e9dfa..22cee8668b 100644 --- a/sdk/android/src/java/org/webrtc/EglBase14Impl.java +++ b/sdk/android/src/java/org/webrtc/EglBase14Impl.java @@ -56,6 +56,7 @@ class EglBase14Impl implements EglBase14 { private final EGLDisplay eglDisplay; private final EGLConfig eglConfig; private final RefCountDelegate refCountDelegate; + private EGLSurface currentSurface = EGL14.EGL_NO_SURFACE; public EglConnection(EGLContext sharedContext, int[] configAttributes) { eglDisplay = getEglDisplay(); @@ -73,6 +74,7 @@ class EglBase14Impl implements EglBase14 { } EGL14.eglReleaseThread(); EGL14.eglTerminate(eglDisplay); + currentSurface = EGL14.EGL_NO_SURFACE; }); } @@ -108,6 +110,31 @@ class EglBase14Impl implements EglBase14 { public EGLConfig getConfig() { return eglConfig; } + + public void makeCurrent(EGLSurface eglSurface) { + if (EGL14.eglGetCurrentContext() == eglContext && currentSurface == eglSurface) { + return; + } + + synchronized (EglBase.lock) { + if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + throw new GLException(EGL14.eglGetError(), + "eglMakeCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); + } + } + currentSurface = eglSurface; + } + + public void detachCurrent() { + synchronized (EglBase.lock) { + if (!EGL14.eglMakeCurrent( + eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { + throw new GLException(EGL14.eglGetError(), + "eglDetachCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); + } + } + currentSurface = EGL14.EGL_NO_SURFACE; + } } // Create a new context with the specified config type, sharing data with sharedContext. // `sharedContext` may be null. @@ -224,25 +251,13 @@ class EglBase14Impl implements EglBase14 { if (eglSurface == EGL14.EGL_NO_SURFACE) { throw new RuntimeException("No EGLSurface - can't make current"); } - synchronized (EglBase.lock) { - if (!EGL14.eglMakeCurrent( - eglConnection.getDisplay(), eglSurface, eglSurface, eglConnection.getContext())) { - throw new GLException(EGL14.eglGetError(), - "eglMakeCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); - } - } + eglConnection.makeCurrent(eglSurface); } // Detach the current EGL context, so that it can be made current on another thread. @Override public void detachCurrent() { - synchronized (EglBase.lock) { - if (!EGL14.eglMakeCurrent(eglConnection.getDisplay(), EGL14.EGL_NO_SURFACE, - EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { - throw new GLException(EGL14.eglGetError(), - "eglDetachCurrent failed: 0x" + Integer.toHexString(EGL14.eglGetError())); - } - } + eglConnection.detachCurrent(); } @Override diff --git a/sdk/android/src/jni/audio_device/audio_device_module.cc b/sdk/android/src/jni/audio_device/audio_device_module.cc index 1abf598c92..f9deae203b 100644 --- a/sdk/android/src/jni/audio_device/audio_device_module.cc +++ b/sdk/android/src/jni/audio_device/audio_device_module.cc @@ -585,6 +585,12 @@ class AndroidAudioDeviceModule : public AudioDeviceModule { return output_->GetPlayoutUnderrunCount(); } + absl::optional GetStats() const override { + if (!initialized_) + return absl::nullopt; + return output_->GetStats(); + } + int32_t AttachAudioBuffer() { RTC_DLOG(LS_INFO) << __FUNCTION__; output_->AttachAudioBuffer(audio_device_buffer_.get()); diff --git a/sdk/android/src/jni/audio_device/audio_device_module.h b/sdk/android/src/jni/audio_device/audio_device_module.h index 90a9172c7b..f1b00f638e 100644 --- a/sdk/android/src/jni/audio_device/audio_device_module.h +++ b/sdk/android/src/jni/audio_device/audio_device_module.h @@ -66,6 +66,9 @@ class AudioOutput { virtual absl::optional MinSpeakerVolume() const = 0; virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0; virtual int GetPlayoutUnderrunCount() = 0; + virtual absl::optional GetStats() const { + return absl::nullopt; + } }; // Extract an android.media.AudioManager from an android.content.Context. diff --git a/sdk/android/src/jni/pc/peer_connection.cc b/sdk/android/src/jni/pc/peer_connection.cc index 176501be02..77aaa868e2 100644 --- a/sdk/android/src/jni/pc/peer_connection.cc +++ b/sdk/android/src/jni/pc/peer_connection.cc @@ -269,10 +269,6 @@ void JavaToNativeRTCConfiguration( Java_RTCConfiguration_getActiveResetSrtpParams(jni, j_rtc_config); rtc_config->crypto_options = JavaToNativeOptionalCryptoOptions(jni, j_crypto_options); - - rtc_config->allow_codec_switching = JavaToNativeOptionalBool( - jni, Java_RTCConfiguration_getAllowCodecSwitching(jni, j_rtc_config)); - rtc_config->offer_extmap_allow_mixed = Java_RTCConfiguration_getOfferExtmapAllowMixed(jni, j_rtc_config); rtc_config->enable_implicit_rollback = diff --git a/sdk/android/src/jni/video_decoder_wrapper.cc b/sdk/android/src/jni/video_decoder_wrapper.cc index 22bfe77944..0c0358d8d6 100644 --- a/sdk/android/src/jni/video_decoder_wrapper.cc +++ b/sdk/android/src/jni/video_decoder_wrapper.cc @@ -100,12 +100,12 @@ int32_t VideoDecoderWrapper::Decode(const EncodedImage& image_param, EncodedImage input_image(image_param); // We use RTP timestamp for capture time because capture_time_ms_ is always 0. input_image.capture_time_ms_ = - input_image.Timestamp() / kNumRtpTicksPerMillisec; + input_image.RtpTimestamp() / kNumRtpTicksPerMillisec; FrameExtraInfo frame_extra_info; frame_extra_info.timestamp_ns = input_image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec; - frame_extra_info.timestamp_rtp = input_image.Timestamp(); + frame_extra_info.timestamp_rtp = input_image.RtpTimestamp(); frame_extra_info.timestamp_ntp = input_image.ntp_time_ms_; frame_extra_info.qp = qp_parsing_enabled_ ? ParseQP(input_image) : absl::nullopt; @@ -255,6 +255,13 @@ absl::optional VideoDecoderWrapper::ParseQP( qp = h264_bitstream_parser_.GetLastSliceQp(); break; } +#ifdef RTC_ENABLE_H265 + case kVideoCodecH265: + h265_bitstream_parser_.ParseBitstream(buffer); + qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1); + success = (qp >= 0); + break; +#endif default: break; // Default is to not provide QP. } diff --git a/sdk/android/src/jni/video_decoder_wrapper.h b/sdk/android/src/jni/video_decoder_wrapper.h index 04b083cf53..53246f380e 100644 --- a/sdk/android/src/jni/video_decoder_wrapper.h +++ b/sdk/android/src/jni/video_decoder_wrapper.h @@ -19,6 +19,9 @@ #include "api/sequence_checker.h" #include "api/video_codecs/video_decoder.h" #include "common_video/h264/h264_bitstream_parser.h" +#ifdef RTC_ENABLE_H265 +#include "common_video/h265/h265_bitstream_parser.h" +#endif #include "rtc_base/race_checker.h" #include "rtc_base/synchronization/mutex.h" #include "sdk/android/src/jni/jni_helpers.h" @@ -96,6 +99,10 @@ class VideoDecoderWrapper : public VideoDecoder { bool initialized_ RTC_GUARDED_BY(decoder_thread_checker_); H264BitstreamParser h264_bitstream_parser_ RTC_GUARDED_BY(decoder_thread_checker_); +#ifdef RTC_ENABLE_H265 + H265BitstreamParser h265_bitstream_parser_ + RTC_GUARDED_BY(decoder_thread_checker_); +#endif DecodedImageCallback* callback_ RTC_GUARDED_BY(callback_race_checker_); diff --git a/sdk/android/src/jni/video_encoder_wrapper.cc b/sdk/android/src/jni/video_encoder_wrapper.cc index 3912ede048..8458ba6c3e 100644 --- a/sdk/android/src/jni/video_encoder_wrapper.cc +++ b/sdk/android/src/jni/video_encoder_wrapper.cc @@ -227,6 +227,8 @@ VideoEncoderWrapper::GetScalingSettingsInternal(JNIEnv* jni) const { return VideoEncoder::ScalingSettings(kLowVp9QpThreshold, kHighVp9QpThreshold); } + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now. case kVideoCodecH264: { // Same as in h264_encoder_impl.cc. static const int kLowH264QpThreshold = 24; @@ -303,7 +305,7 @@ void VideoEncoderWrapper::OnEncodedFrame( // CopyOnWriteBuffer. EncodedImage frame_copy = frame; - frame_copy.SetTimestamp(frame_extra_info.timestamp_rtp); + frame_copy.SetRtpTimestamp(frame_extra_info.timestamp_rtp); frame_copy.capture_time_ms_ = capture_time_ns / rtc::kNumNanosecsPerMillisec; if (frame_copy.qp_ < 0) @@ -355,6 +357,13 @@ int VideoEncoderWrapper::ParseQp(rtc::ArrayView buffer) { qp = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); success = (qp >= 0); break; +#ifdef RTC_ENABLE_H265 + case kVideoCodecH265: + h265_bitstream_parser_.ParseBitstream(buffer); + qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1); + success = (qp >= 0); + break; +#endif default: // Default is to not provide QP. success = false; break; diff --git a/sdk/android/src/jni/video_encoder_wrapper.h b/sdk/android/src/jni/video_encoder_wrapper.h index d3eb2203f0..04d70f3e28 100644 --- a/sdk/android/src/jni/video_encoder_wrapper.h +++ b/sdk/android/src/jni/video_encoder_wrapper.h @@ -21,6 +21,9 @@ #include "absl/types/optional.h" #include "api/video_codecs/video_encoder.h" #include "common_video/h264/h264_bitstream_parser.h" +#ifdef RTC_ENABLE_H265 +#include "common_video/h265/h265_bitstream_parser.h" +#endif #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "modules/video_coding/svc/scalable_video_controller_no_layering.h" #include "rtc_base/synchronization/mutex.h" @@ -103,6 +106,9 @@ class VideoEncoderWrapper : public VideoEncoder { VideoCodec codec_settings_; EncoderInfo encoder_info_; H264BitstreamParser h264_bitstream_parser_; +#ifdef RTC_ENABLE_H265 + H265BitstreamParser h265_bitstream_parser_; +#endif // Fills frame dependencies in codec-agnostic format. ScalableVideoControllerNoLayering svc_controller_; diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.h b/sdk/objc/api/peerconnection/RTCConfiguration.h index 7d2d08fd60..737bcda22e 100644 --- a/sdk/objc/api/peerconnection/RTCConfiguration.h +++ b/sdk/objc/api/peerconnection/RTCConfiguration.h @@ -186,12 +186,6 @@ RTC_OBJC_EXPORT */ @property(nonatomic, assign) BOOL activeResetSrtpParams; -/** If the remote side support mid-stream codec switches then allow encoder - * switching to be performed. - */ - -@property(nonatomic, assign) BOOL allowCodecSwitching; - /** * Defines advanced optional cryptographic settings related to SRTP and * frame encryption for native WebRTC. Setting this will overwrite any diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.mm b/sdk/objc/api/peerconnection/RTCConfiguration.mm index 6944a23564..54a00277d9 100644 --- a/sdk/objc/api/peerconnection/RTCConfiguration.mm +++ b/sdk/objc/api/peerconnection/RTCConfiguration.mm @@ -53,7 +53,6 @@ @synthesize sdpSemantics = _sdpSemantics; @synthesize turnCustomizer = _turnCustomizer; @synthesize activeResetSrtpParams = _activeResetSrtpParams; -@synthesize allowCodecSwitching = _allowCodecSwitching; @synthesize cryptoOptions = _cryptoOptions; @synthesize turnLoggingId = _turnLoggingId; @synthesize rtcpAudioReportIntervalMs = _rtcpAudioReportIntervalMs; @@ -143,7 +142,6 @@ _turnLoggingId = [NSString stringWithUTF8String:config.turn_logging_id.c_str()]; _rtcpAudioReportIntervalMs = config.audio_rtcp_report_interval_ms(); _rtcpVideoReportIntervalMs = config.video_rtcp_report_interval_ms(); - _allowCodecSwitching = config.allow_codec_switching.value_or(false); _enableImplicitRollback = config.enable_implicit_rollback; _offerExtmapAllowMixed = config.offer_extmap_allow_mixed; _iceCheckIntervalStrongConnectivity = @@ -292,7 +290,6 @@ nativeConfig->turn_logging_id = [_turnLoggingId UTF8String]; nativeConfig->set_audio_rtcp_report_interval_ms(_rtcpAudioReportIntervalMs); nativeConfig->set_video_rtcp_report_interval_ms(_rtcpVideoReportIntervalMs); - nativeConfig->allow_codec_switching = _allowCodecSwitching; nativeConfig->enable_implicit_rollback = _enableImplicitRollback; nativeConfig->offer_extmap_allow_mixed = _offerExtmapAllowMixed; if (_iceCheckIntervalStrongConnectivity != nil) { diff --git a/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm index 7f8ae739e0..c8936d3ad5 100644 --- a/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm +++ b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm @@ -83,7 +83,7 @@ class ObjCEncodedImageBuffer : public webrtc::EncodedImageBufferInterface { freeWhenDone:NO]; self.encodedWidth = rtc::dchecked_cast(encodedImage._encodedWidth); self.encodedHeight = rtc::dchecked_cast(encodedImage._encodedHeight); - self.timeStamp = encodedImage.Timestamp(); + self.timeStamp = encodedImage.RtpTimestamp(); self.captureTimeMs = encodedImage.capture_time_ms_; self.ntpTimeMs = encodedImage.ntp_time_ms_; self.flags = encodedImage.timing_.flags; @@ -111,7 +111,7 @@ class ObjCEncodedImageBuffer : public webrtc::EncodedImageBufferInterface { encodedImage.set_size(self.buffer.length); encodedImage._encodedWidth = rtc::dchecked_cast(self.encodedWidth); encodedImage._encodedHeight = rtc::dchecked_cast(self.encodedHeight); - encodedImage.SetTimestamp(self.timeStamp); + encodedImage.SetRtpTimestamp(self.timeStamp); encodedImage.capture_time_ms_ = self.captureTimeMs; encodedImage.ntp_time_ms_ = self.ntpTimeMs; encodedImage.timing_.flags = self.flags; diff --git a/sdk/objc/unittests/RTCAudioSessionTest.mm b/sdk/objc/unittests/RTCAudioSessionTest.mm index 2a00909abe..d7cfc9ed04 100644 --- a/sdk/objc/unittests/RTCAudioSessionTest.mm +++ b/sdk/objc/unittests/RTCAudioSessionTest.mm @@ -212,19 +212,8 @@ EXPECT_EQ(0, audioSession.activationCount); } -// Hack - fixes OCMVerify link error -// Link error is: Undefined symbols for architecture i386: -// "OCMMakeLocation(objc_object*, char const*, int)", referenced from: -// -[RTCAudioSessionTest testConfigureWebRTCSession] in RTCAudioSessionTest.o -// ld: symbol(s) not found for architecture i386 -// REASON: https://github.com/erikdoe/ocmock/issues/238 -OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){ - return [OCMLocation locationWithTestCase:testCase - file:[NSString stringWithUTF8String:fileCString] - line:line]; -} - -- (void)testConfigureWebRTCSession { +// TODO(b/298960678): Fix crash when running the test on simulators. +- (void)DISABLED_testConfigureWebRTCSession { NSError *error = nil; void (^setActiveBlock)(NSInvocation *invocation) = ^(NSInvocation *invocation) { @@ -264,15 +253,19 @@ OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){ EXPECT_EQ(NO, [mockAVAudioSession setActive:YES withOptions:0 error:&error]); [audioSession unlockForConfiguration]; + // The -Wunused-value is a workaround for https://bugs.llvm.org/show_bug.cgi?id=45245 + _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-value\""); OCMVerify([mockAudioSession session]); OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES withOptions:0 error:&error]); OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:NO withOptions:0 error:&error]); + _Pragma("clang diagnostic pop"); [mockAVAudioSession stopMocking]; [mockAudioSession stopMocking]; } -- (void)testConfigureWebRTCSessionWithoutLocking { +// TODO(b/298960678): Fix crash when running the test on simulators. +- (void)DISABLED_testConfigureWebRTCSessionWithoutLocking { NSError *error = nil; id mockAVAudioSession = OCMPartialMock([AVAudioSession sharedInstance]); diff --git a/sdk/objc/unittests/RTCMTLVideoView_xctest.m b/sdk/objc/unittests/RTCMTLVideoView_xctest.m index f152eeec91..587a6b588f 100644 --- a/sdk/objc/unittests/RTCMTLVideoView_xctest.m +++ b/sdk/objc/unittests/RTCMTLVideoView_xctest.m @@ -282,7 +282,8 @@ static size_t kBufferHeight = 200; OCMVerifyAllWithDelay(delegateMock, 1); } -- (void)testSetContentMode { +// TODO(b/298960678): Fix test expectations. +- (void)DISABLED_testSetContentMode { OCMStub([self.classMock isMetalAvailable]).andReturn(YES); id metalKitView = OCMClassMock([MTKView class]); [[[[self.classMock stub] ignoringNonObjectArgs] andReturn:metalKitView] @@ -292,7 +293,7 @@ static size_t kBufferHeight = 200; RTC_OBJC_TYPE(RTCMTLVideoView) *realView = [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] init]; [realView setVideoContentMode:UIViewContentModeScaleAspectFill]; - OCMVerify(metalKitView); + OCMVerifyAll(metalKitView); } @end diff --git a/test/BUILD.gn b/test/BUILD.gn index e8d4fdbc04..be8ee1684e 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -588,16 +588,6 @@ if (rtc_include_tests) { absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] } - rtc_library("test_flags") { - visibility = [ "*" ] - testonly = true - sources = [ - "test_flags.cc", - "test_flags.h", - ] - absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] - } - rtc_library("test_main_lib") { visibility = [ "*" ] testonly = true @@ -1245,6 +1235,15 @@ if (!build_with_chromium) { ] } + rtc_library("test_flags") { + testonly = true + sources = [ + "test_flags.cc", + "test_flags.h", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ] + } + rtc_library("test_common") { testonly = true sources = [ @@ -1266,6 +1265,7 @@ if (!build_with_chromium) { ":mock_transport", ":run_loop", ":scoped_key_value_config", + ":test_flags", ":test_support", ":test_video_capturer", ":video_test_common", @@ -1312,7 +1312,10 @@ if (!build_with_chromium) { "../system_wrappers:field_trial", "../video/config:encoder_config", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/flags:flag", + "//third_party/abseil-cpp/absl/types:optional", + ] if (!is_android && !build_with_chromium) { deps += [ "../modules/video_capture:video_capture_internal_impl" ] } @@ -1334,6 +1337,8 @@ if (!build_with_chromium && is_android) { } rtc_library("call_config_utils") { + testonly = true + # TODO(bugs.webrtc.org/10814): Remove rtc_json_suppressions as soon as it # gets removed upstream. public_configs = [ "../rtc_base:rtc_json_suppressions" ] diff --git a/test/call_test.cc b/test/call_test.cc index b8a1cd76b8..2b71608ac6 100644 --- a/test/call_test.cc +++ b/test/call_test.cc @@ -97,7 +97,7 @@ void CallTest::RunBaseTest(BaseTest* test) { num_audio_streams_ = test->GetNumAudioStreams(); num_flexfec_streams_ = test->GetNumFlexfecStreams(); RTC_DCHECK(num_video_streams_ > 0 || num_audio_streams_ > 0); - Call::Config send_config(send_event_log_.get()); + CallConfig send_config(send_event_log_.get()); test->ModifySenderBitrateConfig(&send_config.bitrate_config); if (num_audio_streams_ > 0) { CreateFakeAudioDevices(test->CreateCapturer(), test->CreateRenderer()); @@ -117,7 +117,7 @@ void CallTest::RunBaseTest(BaseTest* test) { } CreateSenderCall(send_config); if (test->ShouldCreateReceivers()) { - Call::Config recv_config(recv_event_log_.get()); + CallConfig recv_config(recv_event_log_.get()); test->ModifyReceiverBitrateConfig(&recv_config.bitrate_config); if (num_audio_streams_ > 0) { AudioState::Config audio_state_config; @@ -207,35 +207,35 @@ void CallTest::RunBaseTest(BaseTest* test) { } void CallTest::CreateCalls() { - CreateCalls(Call::Config(send_event_log_.get()), - Call::Config(recv_event_log_.get())); + CreateCalls(CallConfig(send_event_log_.get()), + CallConfig(recv_event_log_.get())); } -void CallTest::CreateCalls(const Call::Config& sender_config, - const Call::Config& receiver_config) { +void CallTest::CreateCalls(const CallConfig& sender_config, + const CallConfig& receiver_config) { CreateSenderCall(sender_config); CreateReceiverCall(receiver_config); } void CallTest::CreateSenderCall() { - CreateSenderCall(Call::Config(send_event_log_.get())); + CreateSenderCall(CallConfig(send_event_log_.get())); } -void CallTest::CreateSenderCall(const Call::Config& config) { +void CallTest::CreateSenderCall(const CallConfig& config) { auto sender_config = config; sender_config.task_queue_factory = task_queue_factory_.get(); sender_config.network_state_predictor_factory = network_state_predictor_factory_.get(); sender_config.network_controller_factory = network_controller_factory_.get(); sender_config.trials = &field_trials_; - sender_call_.reset(Call::Create(sender_config)); + sender_call_ = Call::Create(sender_config); } -void CallTest::CreateReceiverCall(const Call::Config& config) { +void CallTest::CreateReceiverCall(const CallConfig& config) { auto receiver_config = config; receiver_config.task_queue_factory = task_queue_factory_.get(); receiver_config.trials = &field_trials_; - receiver_call_.reset(Call::Create(receiver_config)); + receiver_call_ = Call::Create(receiver_config); } void CallTest::DestroyCalls() { diff --git a/test/call_test.h b/test/call_test.h index 08d0e49a68..8d2b001f72 100644 --- a/test/call_test.h +++ b/test/call_test.h @@ -63,11 +63,11 @@ class CallTest : public ::testing::Test, public RtpPacketSinkInterface { void RunBaseTest(BaseTest* test); void CreateCalls(); - void CreateCalls(const Call::Config& sender_config, - const Call::Config& receiver_config); + void CreateCalls(const CallConfig& sender_config, + const CallConfig& receiver_config); void CreateSenderCall(); - void CreateSenderCall(const Call::Config& config); - void CreateReceiverCall(const Call::Config& config); + void CreateSenderCall(const CallConfig& config); + void CreateReceiverCall(const CallConfig& config); void DestroyCalls(); void CreateVideoSendConfig(VideoSendStream::Config* video_config, diff --git a/test/configurable_frame_size_encoder.cc b/test/configurable_frame_size_encoder.cc index 44a00bcacc..2d5f097398 100644 --- a/test/configurable_frame_size_encoder.cc +++ b/test/configurable_frame_size_encoder.cc @@ -53,7 +53,7 @@ int32_t ConfigurableFrameSizeEncoder::Encode( encodedImage._encodedHeight = inputImage.height(); encodedImage._encodedWidth = inputImage.width(); encodedImage._frameType = VideoFrameType::kVideoFrameKey; - encodedImage.SetTimestamp(inputImage.timestamp()); + encodedImage.SetRtpTimestamp(inputImage.timestamp()); encodedImage.capture_time_ms_ = inputImage.render_time_ms(); CodecSpecificInfo specific{}; specific.codecType = codec_type_; diff --git a/test/fake_decoder.cc b/test/fake_decoder.cc index b5fd15bf39..01d95bfeb4 100644 --- a/test/fake_decoder.cc +++ b/test/fake_decoder.cc @@ -54,7 +54,7 @@ int32_t FakeDecoder::Decode(const EncodedImage& input, .set_rotation(webrtc::kVideoRotation_0) .set_timestamp_ms(render_time_ms) .build(); - frame.set_timestamp(input.Timestamp()); + frame.set_timestamp(input.RtpTimestamp()); frame.set_ntp_time_ms(input.ntp_time_ms_); if (decode_delay_ms_ == 0 || !task_queue_) { diff --git a/test/fake_encoded_frame.cc b/test/fake_encoded_frame.cc index 32fa5d8ccf..7ab63cbc76 100644 --- a/test/fake_encoded_frame.cc +++ b/test/fake_encoded_frame.cc @@ -18,8 +18,9 @@ namespace webrtc { void PrintTo(const EncodedFrame& frame, std::ostream* os) /* no-presubmit-check TODO(webrtc:8982) */ { - *os << "EncodedFrame with id=" << frame.Id() << " rtp=" << frame.Timestamp() - << " size=" << frame.size() << " refs=["; + *os << "EncodedFrame with id=" << frame.Id() + << " rtp=" << frame.RtpTimestamp() << " size=" << frame.size() + << " refs=["; for (size_t ref = 0; ref < frame.num_references; ++ref) { *os << frame.references[ref] << ","; } @@ -94,7 +95,7 @@ std::unique_ptr FakeFrameBuilder::Build() { frame->SetEncodedData(EncodedImageBuffer::Create(size_)); if (rtp_timestamp_) - frame->SetTimestamp(*rtp_timestamp_); + frame->SetRtpTimestamp(*rtp_timestamp_); if (frame_id_) frame->SetId(*frame_id_); if (playout_delay_) diff --git a/test/fake_encoded_frame.h b/test/fake_encoded_frame.h index a5b2aca4a1..b4f120bfd9 100644 --- a/test/fake_encoded_frame.h +++ b/test/fake_encoded_frame.h @@ -51,7 +51,7 @@ MATCHER_P(FrameWithSize, id, "") { } MATCHER_P(RtpTimestamp, ts, "") { - return ts == arg.Timestamp(); + return ts == arg.RtpTimestamp(); } class FakeFrameBuilder { diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc index 1afe1f8a0b..009af7b843 100644 --- a/test/fake_encoder.cc +++ b/test/fake_encoder.cc @@ -141,7 +141,7 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, EncodedImage encoded; encoded.SetEncodedData(buffer); - encoded.SetTimestamp(input_image.timestamp()); + encoded.SetRtpTimestamp(input_image.timestamp()); encoded._frameType = frame_info.keyframe ? VideoFrameType::kVideoFrameKey : VideoFrameType::kVideoFrameDelta; encoded._encodedWidth = simulcast_streams[i].width; diff --git a/test/fake_vp8_decoder.cc b/test/fake_vp8_decoder.cc index db18b9b77a..4ed2523c82 100644 --- a/test/fake_vp8_decoder.cc +++ b/test/fake_vp8_decoder.cc @@ -57,7 +57,7 @@ int32_t FakeVp8Decoder::Decode(const EncodedImage& input, .set_rotation(webrtc::kVideoRotation_0) .set_timestamp_ms(render_time_ms) .build(); - frame.set_timestamp(input.Timestamp()); + frame.set_timestamp(input.RtpTimestamp()); frame.set_ntp_time_ms(input.ntp_time_ms_); callback_->Decoded(frame, /*decode_time_ms=*/absl::nullopt, diff --git a/test/fake_vp8_encoder.cc b/test/fake_vp8_encoder.cc index dcafd420a6..c16d7c351e 100644 --- a/test/fake_vp8_encoder.cc +++ b/test/fake_vp8_encoder.cc @@ -96,10 +96,10 @@ CodecSpecificInfo FakeVp8Encoder::EncodeHook( RTC_DCHECK_RUN_ON(&sequence_checker_); uint8_t simulcast_index = encoded_image.SimulcastIndex().value_or(0); frame_buffer_controller_->NextFrameConfig(simulcast_index, - encoded_image.Timestamp()); + encoded_image.RtpTimestamp()); CodecSpecificInfo codec_specific = PopulateCodecSpecific(encoded_image.size(), encoded_image._frameType, - simulcast_index, encoded_image.Timestamp()); + simulcast_index, encoded_image.RtpTimestamp()); // Write width and height to the payload the same way as the real encoder // does. diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn index 114deb03c3..3d2ac7a7e7 100644 --- a/test/fuzzers/BUILD.gn +++ b/test/fuzzers/BUILD.gn @@ -519,7 +519,7 @@ webrtc_fuzzer_test("aec3_config_json_fuzzer") { deps = [ ":fuzz_data_helper", "../../api/audio:aec3_config", - "../../api/audio:aec3_config_json", + "../../modules/audio_processing:aec3_config_json", ] dict = "//testing/libfuzzer/fuzzers/dicts/json.dict" seed_corpus = "corpora/aec3-config-json-corpus" diff --git a/test/fuzzers/aec3_config_json_fuzzer.cc b/test/fuzzers/aec3_config_json_fuzzer.cc index 626350c52c..b2ded1b5b0 100644 --- a/test/fuzzers/aec3_config_json_fuzzer.cc +++ b/test/fuzzers/aec3_config_json_fuzzer.cc @@ -11,7 +11,7 @@ #include #include "api/audio/echo_canceller3_config.h" -#include "api/audio/echo_canceller3_config_json.h" +#include "modules/audio_processing/test/echo_canceller3_config_json.h" #include "test/fuzzers/fuzz_data_helper.h" namespace webrtc { diff --git a/test/fuzzers/frame_buffer_fuzzer.cc b/test/fuzzers/frame_buffer_fuzzer.cc index e58d5e9f98..6b69453b4d 100644 --- a/test/fuzzers/frame_buffer_fuzzer.cc +++ b/test/fuzzers/frame_buffer_fuzzer.cc @@ -64,7 +64,7 @@ void FuzzOneInput(const uint8_t* data, size_t size) { } case 5: { auto frame = std::make_unique(); - frame->SetTimestamp(helper.ReadOrDefaultValue(0)); + frame->SetRtpTimestamp(helper.ReadOrDefaultValue(0)); int64_t wire_id = helper.ReadOrDefaultValue(0) & (kFrameIdLength - 1); frame->SetId(unwrapper.Unwrap(wire_id)); diff --git a/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc b/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc index b1cabc31ac..ea66c4a1c8 100644 --- a/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc +++ b/test/fuzzers/rtp_frame_reference_finder_fuzzer.cc @@ -120,6 +120,9 @@ void FuzzOneInput(const uint8_t* data, size_t size) { reader.CopyTo( &video_header.video_type_header.emplace()); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485) + break; default: break; } diff --git a/test/fuzzers/utils/rtp_replayer.cc b/test/fuzzers/utils/rtp_replayer.cc index 83f894dc28..f6d7119338 100644 --- a/test/fuzzers/utils/rtp_replayer.cc +++ b/test/fuzzers/utils/rtp_replayer.cc @@ -76,7 +76,7 @@ void RtpReplayer::Replay( webrtc::RtcEventLogNull event_log; std::unique_ptr task_queue_factory = CreateDefaultTaskQueueFactory(); - Call::Config call_config(&event_log); + CallConfig call_config(&event_log); call_config.task_queue_factory = task_queue_factory.get(); FieldTrialBasedConfig field_trials; call_config.trials = &field_trials; diff --git a/test/mock_transformable_frame.h b/test/mock_transformable_frame.h index 35b8d92d22..26eb6b7030 100644 --- a/test/mock_transformable_frame.h +++ b/test/mock_transformable_frame.h @@ -23,12 +23,17 @@ class MockTransformableAudioFrame : public TransformableAudioFrameInterface { GetContributingSources, (), (const, override)); + MOCK_METHOD(absl::optional, + AbsoluteCaptureTimestamp, + (), + (const, override)); MOCK_METHOD(void, SetData, (rtc::ArrayView), (override)); MOCK_METHOD(uint8_t, GetPayloadType, (), (const, override)); MOCK_METHOD(uint32_t, GetSsrc, (), (const, override)); MOCK_METHOD(uint32_t, GetTimestamp, (), (const, override)); MOCK_METHOD(void, SetRTPTimestamp, (uint32_t), (override)); MOCK_METHOD(Direction, GetDirection, (), (const, override)); + MOCK_METHOD(std::string, GetMimeType, (), (const, override)); }; } // namespace webrtc diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index 75db40eef5..86a9110f58 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -226,6 +226,7 @@ if (!build_with_chromium) { "../..:field_trial", "../..:fileutils", "../..:perf_test", + "../..:test_flags", "../../../api:audio_quality_analyzer_api", "../../../api:libjingle_peerconnection_api", "../../../api:media_stream_interface", @@ -260,7 +261,10 @@ if (!build_with_chromium) { "analyzer/video:video_quality_analyzer_injection_helper", "analyzer/video:video_quality_metrics_reporter", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/flags:flag", + "//third_party/abseil-cpp/absl/strings", + ] } peer_connection_e2e_smoke_test_resources = [ diff --git a/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc b/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc index 4d19c912f7..e17b5d5d83 100644 --- a/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc +++ b/test/pc/e2e/analyzer/video/quality_analyzing_video_decoder.cc @@ -75,19 +75,20 @@ int32_t QualityAnalyzingVideoDecoder::Decode(const EncodedImage& input_image, // // For more details see QualityAnalyzingVideoEncoder. return analyzing_callback_->IrrelevantSimulcastStreamDecoded( - out.id.value_or(VideoFrame::kNotSetId), input_image.Timestamp()); + out.id.value_or(VideoFrame::kNotSetId), input_image.RtpTimestamp()); } EncodedImage* origin_image; { MutexLock lock(&mutex_); // Store id to be able to retrieve it in analyzing callback. - timestamp_to_frame_id_.insert({input_image.Timestamp(), out.id}); + timestamp_to_frame_id_.insert({input_image.RtpTimestamp(), out.id}); // Store encoded image to prevent its destruction while it is used in // decoder. - origin_image = &( - decoding_images_.insert({input_image.Timestamp(), std::move(out.image)}) - .first->second); + origin_image = + &(decoding_images_ + .insert({input_image.RtpTimestamp(), std::move(out.image)}) + .first->second); } // We can safely dereference `origin_image`, because it can be removed from // the map only after `delegate_` Decode method will be invoked. Image will @@ -101,8 +102,8 @@ int32_t QualityAnalyzingVideoDecoder::Decode(const EncodedImage& input_image, VideoQualityAnalyzerInterface::DecoderStats stats; { MutexLock lock(&mutex_); - timestamp_to_frame_id_.erase(input_image.Timestamp()); - decoding_images_.erase(input_image.Timestamp()); + timestamp_to_frame_id_.erase(input_image.RtpTimestamp()); + decoding_images_.erase(input_image.RtpTimestamp()); stats.decoder_name = codec_name_; } analyzer_->OnDecoderError( diff --git a/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc b/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc index 7a2b3165d6..d7ef0b0c10 100644 --- a/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc +++ b/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc @@ -252,7 +252,7 @@ EncodedImageCallback::Result QualityAnalyzingVideoEncoder::OnEncodedImage( std::pair timestamp_frame_id; while (!timestamp_to_frame_id_list_.empty()) { timestamp_frame_id = timestamp_to_frame_id_list_.front(); - if (timestamp_frame_id.first == encoded_image.Timestamp()) { + if (timestamp_frame_id.first == encoded_image.RtpTimestamp()) { break; } timestamp_to_frame_id_list_.pop_front(); @@ -271,7 +271,7 @@ EncodedImageCallback::Result QualityAnalyzingVideoEncoder::OnEncodedImage( // posting frame to it, but then call the callback for this frame. RTC_LOG(LS_ERROR) << "QualityAnalyzingVideoEncoder::OnEncodedImage: No " "frame id for encoded_image.Timestamp()=" - << encoded_image.Timestamp(); + << encoded_image.RtpTimestamp(); return EncodedImageCallback::Result( EncodedImageCallback::Result::Error::OK); } diff --git a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc index f6fa40455a..8e802f137a 100644 --- a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc +++ b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc @@ -49,7 +49,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, InjectExtractDiscardFalse) { EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImageExtractionResult out = injector.ExtractData(injector.InjectData(512, false, source)); @@ -68,7 +68,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, InjectExtractDiscardTrue) { EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImageExtractionResult out = injector.ExtractData(injector.InjectData(512, true, source)); @@ -85,7 +85,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImage intermediate = injector.InjectData(512, false, source); intermediate.SetSpatialIndex(2); @@ -110,7 +110,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImage intermediate = injector.InjectData(512, false, source); intermediate.SetSpatialIndex(2); @@ -138,15 +138,15 @@ TEST(SingleProcessEncodedImageDataInjectorTest, Inject3Extract3) { // 1st frame EncodedImage source1 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source1.SetTimestamp(123456710); + source1.SetRtpTimestamp(123456710); // 2nd frame 1st spatial layer EncodedImage source2 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/11); - source2.SetTimestamp(123456720); + source2.SetRtpTimestamp(123456720); // 2nd frame 2nd spatial layer EncodedImage source3 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/21); - source3.SetTimestamp(123456720); + source3.SetRtpTimestamp(123456720); EncodedImage intermediate1 = injector.InjectData(510, false, source1); EncodedImage intermediate2 = injector.InjectData(520, true, source2); @@ -183,13 +183,13 @@ TEST(SingleProcessEncodedImageDataInjectorTest, InjectExtractFromConcatenated) { EncodedImage source1 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source1.SetTimestamp(123456710); + source1.SetRtpTimestamp(123456710); EncodedImage source2 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/11); - source2.SetTimestamp(123456710); + source2.SetRtpTimestamp(123456710); EncodedImage source3 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/21); - source3.SetTimestamp(123456710); + source3.SetRtpTimestamp(123456710); // Inject id into 3 images with same frame id. EncodedImage intermediate1 = injector.InjectData(512, false, source1); @@ -235,13 +235,13 @@ TEST(SingleProcessEncodedImageDataInjector, EncodedImage source1 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source1.SetTimestamp(123456710); + source1.SetRtpTimestamp(123456710); EncodedImage source2 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/11); - source2.SetTimestamp(123456710); + source2.SetRtpTimestamp(123456710); EncodedImage source3 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/21); - source3.SetTimestamp(123456710); + source3.SetRtpTimestamp(123456710); // Inject id into 3 images with same frame id. EncodedImage intermediate1 = injector.InjectData(512, true, source1); @@ -282,7 +282,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, InjectOnceExtractTwice) { EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImageExtractionResult out = injector.ExtractData( injector.InjectData(/*id=*/512, /*discard=*/false, source)); @@ -310,7 +310,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, Add1stReceiverAfterStart) { EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImage modified_image = injector.InjectData( /*id=*/512, /*discard=*/false, source); @@ -332,7 +332,7 @@ TEST(SingleProcessEncodedImageDataInjectorTest, Add3rdReceiverAfterStart) { EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImage modified_image = injector.InjectData( /*id=*/512, /*discard=*/false, source); injector.ExtractData(modified_image); @@ -357,10 +357,10 @@ TEST(SingleProcessEncodedImageDataInjectorTest, EncodedImage source1 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source1.SetTimestamp(10); + source1.SetRtpTimestamp(10); EncodedImage source2 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source2.SetTimestamp(20); + source2.SetRtpTimestamp(20); EncodedImage modified_image1 = injector.InjectData( /*id=*/512, /*discard=*/false, source1); @@ -399,7 +399,7 @@ TEST(SingleProcessEncodedImageDataInjectorTestDeathTest, EncodedImage source = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source.SetTimestamp(123456789); + source.SetRtpTimestamp(123456789); EncodedImage modified = injector.InjectData(/*id=*/512, /*discard=*/false, source); @@ -417,10 +417,10 @@ TEST(SingleProcessEncodedImageDataInjectorTestDeathTest, EncodedImage source1 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source1.SetTimestamp(10); + source1.SetRtpTimestamp(10); EncodedImage source2 = CreateEncodedImageOfSizeNFilledWithValuesFromX(/*n=*/10, /*x=*/1); - source2.SetTimestamp(20); + source2.SetRtpTimestamp(20); EncodedImage modified_image1 = injector.InjectData( /*id=*/512, /*discard=*/false, source1); diff --git a/test/pc/e2e/peer_connection_quality_test.cc b/test/pc/e2e/peer_connection_quality_test.cc index 83613118f9..5eb47b4682 100644 --- a/test/pc/e2e/peer_connection_quality_test.cc +++ b/test/pc/e2e/peer_connection_quality_test.cc @@ -14,6 +14,7 @@ #include #include +#include "absl/flags/flag.h" #include "absl/strings/string_view.h" #include "api/jsep.h" #include "api/media_stream_interface.h" @@ -44,6 +45,7 @@ #include "test/pc/e2e/peer_params_preprocessor.h" #include "test/pc/e2e/stats_poller.h" #include "test/pc/e2e/test_peer_factory.h" +#include "test/test_flags.h" #include "test/testsupport/file_utils.h" namespace webrtc { @@ -384,7 +386,7 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { executor_->Start(task_queue_.get()); Timestamp start_time = Now(); - bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest"); + bool is_quick_test_enabled = absl::GetFlag(FLAGS_webrtc_quick_perf_test); if (is_quick_test_enabled) { time_controller_.AdvanceTime(kQuickTestModeRunDuration); } else { diff --git a/test/pc/e2e/test_peer_factory.cc b/test/pc/e2e/test_peer_factory.cc index 9b2f2d6953..41f7533c3a 100644 --- a/test/pc/e2e/test_peer_factory.cc +++ b/test/pc/e2e/test_peer_factory.cc @@ -50,18 +50,10 @@ void SetMandatoryEntities(InjectableComponents* components, RTC_DCHECK(components->pc_dependencies); // Setup required peer connection factory dependencies. - if (components->pcf_dependencies->task_queue_factory == nullptr) { - components->pcf_dependencies->task_queue_factory = - time_controller.CreateTaskQueueFactory(); - } - if (components->pcf_dependencies->call_factory == nullptr) { - components->pcf_dependencies->call_factory = - CreateTimeControllerBasedCallFactory(&time_controller); - } if (components->pcf_dependencies->event_log_factory == nullptr) { components->pcf_dependencies->event_log_factory = std::make_unique( - components->pcf_dependencies->task_queue_factory.get()); + time_controller.GetTaskQueueFactory()); } if (!components->pcf_dependencies->trials) { components->pcf_dependencies->trials = @@ -155,10 +147,11 @@ rtc::scoped_refptr CreateAudioDeviceModule( } std::unique_ptr CreateMediaEngine( + TaskQueueFactory* task_queue_factory, PeerConnectionFactoryComponents* pcf_dependencies, rtc::scoped_refptr audio_device_module) { cricket::MediaEngineDependencies media_deps; - media_deps.task_queue_factory = pcf_dependencies->task_queue_factory.get(); + media_deps.task_queue_factory = task_queue_factory; media_deps.adm = audio_device_module; media_deps.audio_processing = pcf_dependencies->audio_processing; media_deps.audio_mixer = pcf_dependencies->audio_mixer; @@ -212,6 +205,7 @@ void WrapVideoDecoderFactory( // from InjectableComponents::PeerConnectionFactoryComponents. PeerConnectionFactoryDependencies CreatePCFDependencies( std::unique_ptr pcf_dependencies, + TimeController& time_controller, std::unique_ptr media_engine, rtc::Thread* signaling_thread, rtc::Thread* worker_thread, @@ -222,9 +216,10 @@ PeerConnectionFactoryDependencies CreatePCFDependencies( pcf_deps.network_thread = network_thread; pcf_deps.media_engine = std::move(media_engine); - pcf_deps.call_factory = std::move(pcf_dependencies->call_factory); + pcf_deps.call_factory = + CreateTimeControllerBasedCallFactory(&time_controller); pcf_deps.event_log_factory = std::move(pcf_dependencies->event_log_factory); - pcf_deps.task_queue_factory = std::move(pcf_dependencies->task_queue_factory); + pcf_deps.task_queue_factory = time_controller.CreateTaskQueueFactory(); if (pcf_dependencies->fec_controller_factory != nullptr) { pcf_deps.fec_controller_factory = @@ -318,9 +313,9 @@ std::unique_ptr TestPeerFactory::CreateTestPeer( *params->aec_dump_path, -1, task_queue_); } rtc::scoped_refptr audio_device_module = - CreateAudioDeviceModule( - params->audio_config, remote_audio_config, echo_emulation_config, - components->pcf_dependencies->task_queue_factory.get()); + CreateAudioDeviceModule(params->audio_config, remote_audio_config, + echo_emulation_config, + time_controller_.GetTaskQueueFactory()); WrapVideoEncoderFactory( params->name.value(), params->video_encoder_bitrate_multiplier, CalculateRequiredSpatialIndexPerStream( @@ -330,7 +325,8 @@ std::unique_ptr TestPeerFactory::CreateTestPeer( components->pcf_dependencies.get(), video_analyzer_helper_); std::unique_ptr media_engine = - CreateMediaEngine(components->pcf_dependencies.get(), + CreateMediaEngine(time_controller_.GetTaskQueueFactory(), + components->pcf_dependencies.get(), audio_device_module); std::unique_ptr owned_worker_thread = @@ -346,8 +342,9 @@ std::unique_ptr TestPeerFactory::CreateTestPeer( rtc::scoped_refptr audio_processing = components->pcf_dependencies->audio_processing; PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies( - std::move(components->pcf_dependencies), std::move(media_engine), - signaling_thread_, components->worker_thread, components->network_thread); + std::move(components->pcf_dependencies), time_controller_, + std::move(media_engine), signaling_thread_, components->worker_thread, + components->network_thread); rtc::scoped_refptr peer_connection_factory = CreateModularPeerConnectionFactory(std::move(pcf_deps)); diff --git a/test/rtp_rtcp_observer.h b/test/rtp_rtcp_observer.h index cbbff1abfc..14c5ce3641 100644 --- a/test/rtp_rtcp_observer.h +++ b/test/rtp_rtcp_observer.h @@ -15,6 +15,7 @@ #include #include +#include "absl/flags/flag.h" #include "api/array_view.h" #include "api/test/simulated_network.h" #include "api/units/time_delta.h" @@ -25,10 +26,7 @@ #include "system_wrappers/include/field_trial.h" #include "test/direct_transport.h" #include "test/gtest.h" - -namespace { -constexpr webrtc::TimeDelta kShortTimeout = webrtc::TimeDelta::Millis(500); -} +#include "test/test_flags.h" namespace webrtc { namespace test { @@ -45,8 +43,8 @@ class RtpRtcpObserver { virtual ~RtpRtcpObserver() {} virtual bool Wait() { - if (field_trial::IsEnabled("WebRTC-QuickPerfTest")) { - observation_complete_.Wait(kShortTimeout); + if (absl::GetFlag(FLAGS_webrtc_quick_perf_test)) { + observation_complete_.Wait(TimeDelta::Millis(500)); return true; } return observation_complete_.Wait(timeout_); diff --git a/test/scenario/call_client.cc b/test/scenario/call_client.cc index d2019aebc7..fdf36dee08 100644 --- a/test/scenario/call_client.cc +++ b/test/scenario/call_client.cc @@ -59,11 +59,12 @@ CallClientFakeAudio InitAudio(TimeController* time_controller) { return setup; } -Call* CreateCall(TimeController* time_controller, - RtcEventLog* event_log, - CallClientConfig config, - LoggingNetworkControllerFactory* network_controller_factory, - rtc::scoped_refptr audio_state) { +std::unique_ptr CreateCall( + TimeController* time_controller, + RtcEventLog* event_log, + CallClientConfig config, + LoggingNetworkControllerFactory* network_controller_factory, + rtc::scoped_refptr audio_state) { CallConfig call_config(event_log); call_config.bitrate_config.max_bitrate_bps = config.transport.rates.max_rate.bps_or(-1); @@ -230,9 +231,9 @@ CallClient::CallClient( log_writer_factory_.get()); fake_audio_setup_ = InitAudio(time_controller_); - call_.reset(CreateCall(time_controller_, event_log_.get(), config, - &network_controller_factory_, - fake_audio_setup_.audio_state)); + call_ = + CreateCall(time_controller_, event_log_.get(), config, + &network_controller_factory_, fake_audio_setup_.audio_state); transport_ = std::make_unique(clock_, call_.get()); }); } diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc index e082aa37c6..38e42c88e0 100644 --- a/test/scenario/video_stream.cc +++ b/test/scenario/video_stream.cc @@ -40,7 +40,6 @@ enum : int { // The first valid value is 1. kVideoRotationRtpExtensionId, }; -constexpr int kDefaultMaxQp = cricket::WebRtcVideoSendChannel::kDefaultQpMax; uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) { switch (codec_type) { case VideoCodecType::kVideoCodecGeneric: @@ -51,6 +50,8 @@ uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) { return VideoTestConstants::kPayloadTypeVP9; case VideoCodecType::kVideoCodecH264: return VideoTestConstants::kPayloadTypeH264; + case VideoCodecType::kVideoCodecH265: + return VideoTestConstants::kPayloadTypeH265; default: RTC_DCHECK_NOTREACHED(); } @@ -66,6 +67,8 @@ std::string CodecTypeToCodecName(VideoCodecType codec_type) { return cricket::kVp9CodecName; case VideoCodecType::kVideoCodecH264: return cricket::kH264CodecName; + case VideoCodecType::kVideoCodecH265: + return cricket::kH265CodecName; default: RTC_DCHECK_NOTREACHED(); } @@ -203,6 +206,7 @@ CreateEncoderSpecificSettings(VideoStreamConfig config) { return CreateVp9SpecificSettings(config); case Codec::kVideoCodecGeneric: case Codec::kVideoCodecAV1: + case Codec::kVideoCodecH265: return nullptr; case Codec::kVideoCodecMultiplex: RTC_DCHECK_NOTREACHED(); @@ -229,8 +233,8 @@ VideoEncoderConfig CreateVideoEncoderConfig(VideoStreamConfig config) { VideoStreamConfig::Encoder::ContentType::kScreen; encoder_config.video_stream_factory = rtc::make_ref_counted( - cricket_codec, kDefaultMaxQp, screenshare, screenshare, - encoder_info); + cricket_codec, cricket::kDefaultVideoMaxQpVpx, screenshare, + screenshare, encoder_info); } else { encoder_config.video_stream_factory = rtc::make_ref_counted(); diff --git a/test/test_flags.cc b/test/test_flags.cc index a0fff747fe..4df2583672 100644 --- a/test/test_flags.cc +++ b/test/test_flags.cc @@ -49,3 +49,8 @@ ABSL_FLAG(bool, export_perf_results_new_api, false, "Tells to initialize new API for exporting performance metrics"); + +ABSL_FLAG(bool, + webrtc_quick_perf_test, + false, + "Runs webrtc perfomance tests in quick mode."); diff --git a/test/test_flags.h b/test/test_flags.h index 30f918fc7d..84f1c29503 100644 --- a/test/test_flags.h +++ b/test/test_flags.h @@ -20,5 +20,6 @@ ABSL_DECLARE_FLAG(std::vector, plot); ABSL_DECLARE_FLAG(std::string, isolated_script_test_perf_output); ABSL_DECLARE_FLAG(std::string, webrtc_test_metrics_output_path); ABSL_DECLARE_FLAG(bool, export_perf_results_new_api); +ABSL_DECLARE_FLAG(bool, webrtc_quick_perf_test); #endif // TEST_TEST_FLAGS_H_ diff --git a/test/testsupport/ivf_video_frame_generator.cc b/test/testsupport/ivf_video_frame_generator.cc index ec3c948fa4..0dec1135f0 100644 --- a/test/testsupport/ivf_video_frame_generator.cc +++ b/test/testsupport/ivf_video_frame_generator.cc @@ -148,6 +148,9 @@ std::unique_ptr IvfVideoFrameGenerator::CreateVideoDecoder( if (codec_type == VideoCodecType::kVideoCodecAV1) { return CreateDav1dDecoder(); } + if (codec_type == VideoCodecType::kVideoCodecH265) { + // TODO(bugs.webrtc.org/13485): implement H265 decoder + } return nullptr; } diff --git a/test/testsupport/yuv_frame_reader.cc b/test/testsupport/yuv_frame_reader.cc index 02c1a68008..db4ba23269 100644 --- a/test/testsupport/yuv_frame_reader.cc +++ b/test/testsupport/yuv_frame_reader.cc @@ -36,7 +36,7 @@ int WrapFrameNum(int frame_num, int num_frames, RepeatMode mode) { } RTC_CHECK_EQ(RepeatMode::kPingPong, mode); - int cycle_len = 2 * (num_frames - 1); + int cycle_len = std::max(1, 2 * (num_frames - 1)); int wrapped_num = frame_num % cycle_len; if (wrapped_num >= num_frames) { return cycle_len - wrapped_num; diff --git a/test/testsupport/yuv_frame_reader_unittest.cc b/test/testsupport/yuv_frame_reader_unittest.cc index b9ea2d0c46..b8f902bb88 100644 --- a/test/testsupport/yuv_frame_reader_unittest.cc +++ b/test/testsupport/yuv_frame_reader_unittest.cc @@ -29,8 +29,7 @@ using Ratio = FrameReader::Ratio; using RepeatMode = YuvFrameReaderImpl::RepeatMode; constexpr Resolution kResolution({.width = 1, .height = 1}); -constexpr char kFrameContent[3][3] = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; -constexpr int kNumFrames = sizeof(kFrameContent) / sizeof(kFrameContent[0]); +constexpr int kDefaultNumFrames = 3; } // namespace class YuvFrameReaderTest : public ::testing::Test { @@ -41,39 +40,48 @@ class YuvFrameReaderTest : public ::testing::Test { void SetUp() override { filepath_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), "yuv_frame_reader_unittest"); - FILE* file = fopen(filepath_.c_str(), "wb"); - fwrite(kFrameContent, 1, sizeof(kFrameContent), file); - fclose(file); - - reader_ = CreateYuvFrameReader(filepath_, kResolution); + CreateYuvFileAndReader(/*num_frames=*/3, RepeatMode::kSingle); } void TearDown() override { remove(filepath_.c_str()); } + void CreateYuvFileAndReader(int num_frames, RepeatMode repeat_mode) { + FILE* file = fopen(filepath_.c_str(), "wb"); + for (int i = 0; i < num_frames; ++i) { + uint8_t y = static_cast(i & 255); + uint8_t u = static_cast((i + 1) & 255); + uint8_t v = static_cast((i + 2) & 255); + fwrite(&y, 1, 1, file); + fwrite(&u, 1, 1, file); + fwrite(&v, 1, 1, file); + } + fclose(file); + + reader_ = CreateYuvFrameReader(filepath_, kResolution, repeat_mode); + } + std::string filepath_; std::unique_ptr reader_; }; TEST_F(YuvFrameReaderTest, num_frames) { - EXPECT_EQ(kNumFrames, reader_->num_frames()); + EXPECT_EQ(kDefaultNumFrames, reader_->num_frames()); } TEST_F(YuvFrameReaderTest, PullFrame_frameContent) { rtc::scoped_refptr buffer = reader_->PullFrame(); - EXPECT_EQ(kFrameContent[0][0], *buffer->DataY()); - EXPECT_EQ(kFrameContent[0][1], *buffer->DataU()); - EXPECT_EQ(kFrameContent[0][2], *buffer->DataV()); + EXPECT_EQ(0u, *buffer->DataY()); + EXPECT_EQ(1u, *buffer->DataU()); + EXPECT_EQ(2u, *buffer->DataV()); } TEST_F(YuvFrameReaderTest, ReadFrame_randomOrder) { - std::vector expected_frames = {2, 0, 1}; - std::vector actual_frames; - for (int frame_num : expected_frames) { - rtc::scoped_refptr buffer = - reader_->ReadFrame(frame_num); - actual_frames.push_back(*buffer->DataY()); - } - EXPECT_EQ(expected_frames, actual_frames); + rtc::scoped_refptr buffer = reader_->ReadFrame(2); + EXPECT_EQ(2u, *buffer->DataY()); + buffer = reader_->ReadFrame(0); + EXPECT_EQ(0u, *buffer->DataY()); + buffer = reader_->ReadFrame(1); + EXPECT_EQ(1u, *buffer->DataY()); } TEST_F(YuvFrameReaderTest, PullFrame_scale) { @@ -87,30 +95,31 @@ TEST_F(YuvFrameReaderTest, PullFrame_scale) { class YuvFrameReaderRepeatModeTest : public YuvFrameReaderTest, public ::testing::WithParamInterface< - std::tuple>> {}; + std::tuple>> {}; TEST_P(YuvFrameReaderRepeatModeTest, PullFrame) { - RepeatMode mode = std::get<0>(GetParam()); - std::vector expected_frames = std::get<1>(GetParam()); - - reader_ = CreateYuvFrameReader(filepath_, kResolution, mode); - std::vector read_frames; - for (size_t i = 0; i < expected_frames.size(); ++i) { + auto [num_frames, repeat_mode, expected_frames] = GetParam(); + CreateYuvFileAndReader(num_frames, repeat_mode); + for (auto expected_frame : expected_frames) { rtc::scoped_refptr buffer = reader_->PullFrame(); - read_frames.push_back(*buffer->DataY()); + EXPECT_EQ(expected_frame, *buffer->DataY()); } - EXPECT_EQ(expected_frames, read_frames); } INSTANTIATE_TEST_SUITE_P( YuvFrameReaderTest, YuvFrameReaderRepeatModeTest, ::testing::ValuesIn( - {std::make_tuple(RepeatMode::kSingle, std::vector{0, 1, 2}), - std::make_tuple(RepeatMode::kRepeat, - std::vector{0, 1, 2, 0, 1, 2}), - std::make_tuple(RepeatMode::kPingPong, - std::vector{0, 1, 2, 1, 0, 1, 2})})); + {std::make_tuple(3, RepeatMode::kSingle, std::vector{0, 1, 2}), + std::make_tuple(3, + RepeatMode::kRepeat, + std::vector{0, 1, 2, 0, 1, 2}), + std::make_tuple(3, + RepeatMode::kPingPong, + std::vector{0, 1, 2, 1, 0, 1, 2}), + std::make_tuple(1, + RepeatMode::kPingPong, + std::vector{0, 0})})); class YuvFrameReaderFramerateScaleTest : public YuvFrameReaderTest, @@ -118,17 +127,13 @@ class YuvFrameReaderFramerateScaleTest std::tuple>> {}; TEST_P(YuvFrameReaderFramerateScaleTest, PullFrame) { - Ratio framerate_scale = std::get<0>(GetParam()); - std::vector expected_frames = std::get<1>(GetParam()); - - std::vector actual_frames; - for (size_t i = 0; i < expected_frames.size(); ++i) { + auto [framerate_scale, expected_frames] = GetParam(); + for (auto expected_frame : expected_frames) { int pulled_frame; rtc::scoped_refptr buffer = reader_->PullFrame(&pulled_frame, kResolution, framerate_scale); - actual_frames.push_back(pulled_frame); + EXPECT_EQ(pulled_frame, expected_frame); } - EXPECT_EQ(expected_frames, actual_frames); } INSTANTIATE_TEST_SUITE_P(YuvFrameReaderTest, diff --git a/test/video_test_constants.h b/test/video_test_constants.h index 732d4f0056..b9083987ed 100644 --- a/test/video_test_constants.h +++ b/test/video_test_constants.h @@ -31,6 +31,7 @@ class VideoTestConstants { kRtxRedPayloadType = 99, kVideoSendPayloadType = 100, kAudioSendPayloadType = 103, + kPayloadTypeH265 = 117, kRedPayloadType = 118, kUlpfecPayloadType = 119, kFlexfecPayloadType = 120, diff --git a/tools_webrtc/autoroller/roll_deps.py b/tools_webrtc/autoroller/roll_deps.py index c57ba9c040..8e3b760c43 100755 --- a/tools_webrtc/autoroller/roll_deps.py +++ b/tools_webrtc/autoroller/roll_deps.py @@ -22,11 +22,11 @@ import urllib.request def FindSrcDirPath(): - """Returns the abs path to the src/ dir of the project.""" - src_dir = os.path.dirname(os.path.abspath(__file__)) - while os.path.basename(src_dir) != 'src': - src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) - return src_dir + """Returns the abs path to the src/ dir of the project.""" + src_dir = os.path.dirname(os.path.abspath(__file__)) + while os.path.basename(src_dir) != 'src': + src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) + return src_dir # Skip these dependencies (list without solution name prefix). @@ -101,42 +101,42 @@ ChromiumRevisionUpdate = collections.namedtuple('ChromiumRevisionUpdate', class RollError(Exception): - pass + pass def StrExpansion(): - return lambda str_value: str_value + return lambda str_value: str_value def VarLookup(local_scope): - return lambda var_name: local_scope['vars'][var_name] + return lambda var_name: local_scope['vars'][var_name] def ParseDepsDict(deps_content): - local_scope = {} - global_scope = { - 'Str': StrExpansion(), - 'Var': VarLookup(local_scope), - 'deps_os': {}, - } - exec(deps_content, global_scope, local_scope) - return local_scope + local_scope = {} + global_scope = { + 'Str': StrExpansion(), + 'Var': VarLookup(local_scope), + 'deps_os': {}, + } + exec(deps_content, global_scope, local_scope) + return local_scope def ParseLocalDepsFile(filename): - with open(filename, 'rb') as f: - deps_content = f.read().decode('utf-8') - return ParseDepsDict(deps_content) + with open(filename, 'rb') as f: + deps_content = f.read().decode('utf-8') + return ParseDepsDict(deps_content) def ParseCommitPosition(commit_message): - for line in reversed(commit_message.splitlines()): - m = COMMIT_POSITION_RE.match(line.strip()) - if m: - return int(m.group(1)) - logging.error('Failed to parse commit position id from:\n%s\n', - commit_message) - sys.exit(-1) + for line in reversed(commit_message.splitlines()): + m = COMMIT_POSITION_RE.match(line.strip()) + if m: + return int(m.group(1)) + logging.error('Failed to parse commit position id from:\n%s\n', + commit_message) + sys.exit(-1) def _RunCommand(command, @@ -144,68 +144,69 @@ def _RunCommand(command, ignore_exit_code=False, extra_env=None, input_data=None): - """Runs a command and returns the output from that command. + """Runs a command and returns the output from that command. If the command fails (exit code != 0), the function will exit the process. Returns: A tuple containing the stdout and stderr outputs as strings. """ - working_dir = working_dir or CHECKOUT_SRC_DIR - logging.debug('CMD: %s CWD: %s', ' '.join(command), working_dir) - env = os.environ.copy() - if extra_env: - assert all(isinstance(value, str) for value in extra_env.values()) - logging.debug('extra env: %s', extra_env) - env.update(extra_env) - p = subprocess.Popen(command, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env, - cwd=working_dir, - universal_newlines=True) - std_output, err_output = p.communicate(input_data) - p.stdout.close() - p.stderr.close() - if not ignore_exit_code and p.returncode != 0: - logging.error('Command failed: %s\n' - 'stdout:\n%s\n' - 'stderr:\n%s\n', ' '.join(command), std_output, err_output) - sys.exit(p.returncode) - return std_output, err_output + working_dir = working_dir or CHECKOUT_SRC_DIR + logging.debug('CMD: %s CWD: %s', ' '.join(command), working_dir) + env = os.environ.copy() + if extra_env: + assert all(isinstance(value, str) for value in extra_env.values()) + logging.debug('extra env: %s', extra_env) + env.update(extra_env) + p = subprocess.Popen(command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + cwd=working_dir, + universal_newlines=True) + std_output, err_output = p.communicate(input_data) + p.stdout.close() + p.stderr.close() + if not ignore_exit_code and p.returncode != 0: + logging.error('Command failed: %s\n' + 'stdout:\n%s\n' + 'stderr:\n%s\n', ' '.join(command), std_output, + err_output) + sys.exit(p.returncode) + return std_output, err_output def _GetBranches(): - """Returns a tuple of active,branches. + """Returns a tuple of active,branches. The 'active' is the name of the currently active branch and 'branches' is a list of all branches. """ - lines = _RunCommand(['git', 'branch'])[0].split('\n') - branches = [] - active = '' - for line in lines: - if '*' in line: - # The assumption is that the first char will always be the '*'. - active = line[1:].strip() - branches.append(active) - else: - branch = line.strip() - if branch: - branches.append(branch) - return active, branches + lines = _RunCommand(['git', 'branch'])[0].split('\n') + branches = [] + active = '' + for line in lines: + if '*' in line: + # The assumption is that the first char will always be the '*'. + active = line[1:].strip() + branches.append(active) + else: + branch = line.strip() + if branch: + branches.append(branch) + return active, branches def _ReadGitilesContent(url): - # Download and decode BASE64 content until - # https://code.google.com/p/gitiles/issues/detail?id=7 is fixed. - base64_content = ReadUrlContent(url + '?format=TEXT') - return base64.b64decode(base64_content[0]).decode('utf-8') + # Download and decode BASE64 content until + # https://code.google.com/p/gitiles/issues/detail?id=7 is fixed. + base64_content = ReadUrlContent(url + '?format=TEXT') + return base64.b64decode(base64_content[0]).decode('utf-8') def ReadRemoteCrFile(path_below_src, revision): - """Reads a remote Chromium file of a specific revision. + """Reads a remote Chromium file of a specific revision. Args: path_below_src: A path to the target file relative to src dir. @@ -213,35 +214,35 @@ def ReadRemoteCrFile(path_below_src, revision): Returns: A string with file content. """ - return _ReadGitilesContent(CHROMIUM_FILE_TEMPLATE % - (revision, path_below_src)) + return _ReadGitilesContent(CHROMIUM_FILE_TEMPLATE % + (revision, path_below_src)) def ReadRemoteCrCommit(revision): - """Reads a remote Chromium commit message. Returns a string.""" - return _ReadGitilesContent(CHROMIUM_COMMIT_TEMPLATE % revision) + """Reads a remote Chromium commit message. Returns a string.""" + return _ReadGitilesContent(CHROMIUM_COMMIT_TEMPLATE % revision) def ReadUrlContent(url): - """Connect to a remote host and read the contents. + """Connect to a remote host and read the contents. Args: url: URL to connect to. Returns: A list of lines. """ - conn = urllib.request.urlopen(url) - try: - return conn.readlines() - except IOError as e: - logging.exception('Error connecting to %s. Error: %s', url, e) - raise - finally: - conn.close() + conn = urllib.request.urlopen(url) + try: + return conn.readlines() + except IOError as e: + logging.exception('Error connecting to %s. Error: %s', url, e) + raise + finally: + conn.close() def GetMatchingDepsEntries(depsentry_dict, dir_path): - """Gets all deps entries matching the provided path. + """Gets all deps entries matching the provided path. This list may contain more than one DepsEntry object. Example: dir_path='src/testing' would give results containing both @@ -253,94 +254,95 @@ def GetMatchingDepsEntries(depsentry_dict, dir_path): Returns: A list of DepsEntry objects. """ - result = [] - for path, depsentry in depsentry_dict.items(): - if path == dir_path: - result.append(depsentry) - else: - parts = path.split('/') - if all(part == parts[i] for i, part in enumerate(dir_path.split('/'))): - result.append(depsentry) - return result + result = [] + for path, depsentry in depsentry_dict.items(): + if path == dir_path: + result.append(depsentry) + else: + parts = path.split('/') + if all(part == parts[i] + for i, part in enumerate(dir_path.split('/'))): + result.append(depsentry) + return result def BuildDepsentryDict(deps_dict): - """Builds a dict of paths to DepsEntry objects from a raw deps dict.""" - result = {} + """Builds a dict of paths to DepsEntry objects from a raw deps dict.""" + result = {} - def AddDepsEntries(deps_subdict): - for path, dep in deps_subdict.items(): - if path in result: - continue - if not isinstance(dep, dict): - dep = {'url': dep} - if dep.get('dep_type') == 'cipd': - result[path] = CipdDepsEntry(path, dep['packages']) - else: - if '@' not in dep['url']: - url, revision = dep['url'], 'HEAD' - else: - url, revision = dep['url'].split('@') - result[path] = DepsEntry(path, url, revision) + def AddDepsEntries(deps_subdict): + for path, dep in deps_subdict.items(): + if path in result: + continue + if not isinstance(dep, dict): + dep = {'url': dep} + if dep.get('dep_type') == 'cipd': + result[path] = CipdDepsEntry(path, dep['packages']) + else: + if '@' not in dep['url']: + url, revision = dep['url'], 'HEAD' + else: + url, revision = dep['url'].split('@') + result[path] = DepsEntry(path, url, revision) - def AddVersionEntry(vars_subdict): - for key, value in vars_subdict.items(): - if key in result: - continue - if not key.endswith('_version'): - continue - key = re.sub('_version$', '', key) - result[key] = VersionEntry(value) + def AddVersionEntry(vars_subdict): + for key, value in vars_subdict.items(): + if key in result: + continue + if not key.endswith('_version'): + continue + key = re.sub('_version$', '', key) + result[key] = VersionEntry(value) - AddDepsEntries(deps_dict['deps']) - for deps_os in ['win', 'mac', 'linux', 'android', 'ios', 'unix']: - AddDepsEntries(deps_dict.get('deps_os', {}).get(deps_os, {})) - AddVersionEntry(deps_dict.get('vars', {})) - return result + AddDepsEntries(deps_dict['deps']) + for deps_os in ['win', 'mac', 'linux', 'android', 'ios', 'unix']: + AddDepsEntries(deps_dict.get('deps_os', {}).get(deps_os, {})) + AddVersionEntry(deps_dict.get('vars', {})) + return result def _FindChangedCipdPackages(path, old_pkgs, new_pkgs): - old_pkgs_names = {p['package'] for p in old_pkgs} - new_pkgs_names = {p['package'] for p in new_pkgs} - pkgs_equal = (old_pkgs_names == new_pkgs_names) - added_pkgs = [p for p in new_pkgs_names if p not in old_pkgs_names] - removed_pkgs = [p for p in old_pkgs_names if p not in new_pkgs_names] + old_pkgs_names = {p['package'] for p in old_pkgs} + new_pkgs_names = {p['package'] for p in new_pkgs} + pkgs_equal = (old_pkgs_names == new_pkgs_names) + added_pkgs = [p for p in new_pkgs_names if p not in old_pkgs_names] + removed_pkgs = [p for p in old_pkgs_names if p not in new_pkgs_names] - assert pkgs_equal, ('Old: %s\n New: %s.\nYou need to do a manual roll ' - 'and remove/add entries in DEPS so the old and new ' - 'list match.\nMost likely, you should add \"%s\" and ' - 'remove \"%s\"' % - (old_pkgs, new_pkgs, added_pkgs, removed_pkgs)) + assert pkgs_equal, ('Old: %s\n New: %s.\nYou need to do a manual roll ' + 'and remove/add entries in DEPS so the old and new ' + 'list match.\nMost likely, you should add \"%s\" and ' + 'remove \"%s\"' % + (old_pkgs, new_pkgs, added_pkgs, removed_pkgs)) - for old_pkg in old_pkgs: - for new_pkg in new_pkgs: - old_version = old_pkg['version'] - new_version = new_pkg['version'] - if (old_pkg['package'] == new_pkg['package'] - and old_version != new_version): - logging.debug('Roll dependency %s to %s', path, new_version) - yield ChangedCipdPackage(path, old_pkg['package'], old_version, - new_version) + for old_pkg in old_pkgs: + for new_pkg in new_pkgs: + old_version = old_pkg['version'] + new_version = new_pkg['version'] + if (old_pkg['package'] == new_pkg['package'] + and old_version != new_version): + logging.debug('Roll dependency %s to %s', path, new_version) + yield ChangedCipdPackage(path, old_pkg['package'], old_version, + new_version) def _FindChangedVars(name, old_version, new_version): - if old_version != new_version: - logging.debug('Roll dependency %s to %s', name, new_version) - yield ChangedVersionEntry(name, old_version, new_version) + if old_version != new_version: + logging.debug('Roll dependency %s to %s', name, new_version) + yield ChangedVersionEntry(name, old_version, new_version) def _FindNewDeps(old, new): - """ Gather dependencies only in `new` and return corresponding paths. """ - old_entries = set(BuildDepsentryDict(old)) - new_entries = set(BuildDepsentryDict(new)) - return [ - path for path in new_entries - old_entries - if path not in DONT_AUTOROLL_THESE - ] + """ Gather dependencies only in `new` and return corresponding paths. """ + old_entries = set(BuildDepsentryDict(old)) + new_entries = set(BuildDepsentryDict(new)) + return [ + path for path in new_entries - old_entries + if path not in DONT_AUTOROLL_THESE + ] def FindAddedDeps(webrtc_deps, new_cr_deps): - """ + """ Calculate new deps entries of interest. Ideally, that would mean: only appearing in chromium DEPS @@ -361,18 +363,18 @@ def FindAddedDeps(webrtc_deps, new_cr_deps): A list of paths added dependencies sitting in `ANDROID_DEPS_PATH`. A list of paths for other added dependencies. """ - all_added_deps = _FindNewDeps(webrtc_deps, new_cr_deps) - generated_android_deps = [ - path for path in all_added_deps if path.startswith(ANDROID_DEPS_PATH) - ] - other_deps = [ - path for path in all_added_deps if path not in generated_android_deps - ] - return generated_android_deps, other_deps + all_added_deps = _FindNewDeps(webrtc_deps, new_cr_deps) + generated_android_deps = [ + path for path in all_added_deps if path.startswith(ANDROID_DEPS_PATH) + ] + other_deps = [ + path for path in all_added_deps if path not in generated_android_deps + ] + return generated_android_deps, other_deps def FindRemovedDeps(webrtc_deps, new_cr_deps): - """ + """ Calculate obsolete deps entries. Ideally, that would mean: no more appearing in chromium DEPS @@ -395,19 +397,20 @@ def FindRemovedDeps(webrtc_deps, new_cr_deps): A list of paths of dependencies removed from `ANDROID_DEPS_PATH`. A list of paths of unexpected disappearing dependencies. """ - all_removed_deps = _FindNewDeps(new_cr_deps, webrtc_deps) - generated_android_deps = sorted( - [path for path in all_removed_deps if path.startswith(ANDROID_DEPS_PATH)]) - # Webrtc-only dependencies are handled in CalculateChangedDeps. - other_deps = sorted([ - path for path in all_removed_deps - if path not in generated_android_deps and path not in WEBRTC_ONLY_DEPS - ]) - return generated_android_deps, other_deps + all_removed_deps = _FindNewDeps(new_cr_deps, webrtc_deps) + generated_android_deps = sorted([ + path for path in all_removed_deps if path.startswith(ANDROID_DEPS_PATH) + ]) + # Webrtc-only dependencies are handled in CalculateChangedDeps. + other_deps = sorted([ + path for path in all_removed_deps + if path not in generated_android_deps and path not in WEBRTC_ONLY_DEPS + ]) + return generated_android_deps, other_deps def CalculateChangedDeps(webrtc_deps, new_cr_deps): - """ + """ Calculate changed deps entries based on entries defined in the WebRTC DEPS file: - If a shared dependency with the Chromium DEPS file: roll it to the same @@ -421,70 +424,71 @@ def CalculateChangedDeps(webrtc_deps, new_cr_deps): Returns: A list of ChangedDep objects representing the changed deps. """ - result = [] - webrtc_entries = BuildDepsentryDict(webrtc_deps) - new_cr_entries = BuildDepsentryDict(new_cr_deps) - for path, webrtc_deps_entry in webrtc_entries.items(): - if path in DONT_AUTOROLL_THESE: - continue - cr_deps_entry = new_cr_entries.get(path) - if cr_deps_entry: - assert type(cr_deps_entry) is type(webrtc_deps_entry) + result = [] + webrtc_entries = BuildDepsentryDict(webrtc_deps) + new_cr_entries = BuildDepsentryDict(new_cr_deps) + for path, webrtc_deps_entry in webrtc_entries.items(): + if path in DONT_AUTOROLL_THESE: + continue + cr_deps_entry = new_cr_entries.get(path) + if cr_deps_entry: + assert type(cr_deps_entry) is type(webrtc_deps_entry) - if isinstance(cr_deps_entry, CipdDepsEntry): - result.extend( - _FindChangedCipdPackages(path, webrtc_deps_entry.packages, - cr_deps_entry.packages)) - continue + if isinstance(cr_deps_entry, CipdDepsEntry): + result.extend( + _FindChangedCipdPackages(path, webrtc_deps_entry.packages, + cr_deps_entry.packages)) + continue - if isinstance(cr_deps_entry, VersionEntry): - result.extend( - _FindChangedVars(path, webrtc_deps_entry.version, - cr_deps_entry.version)) - continue + if isinstance(cr_deps_entry, VersionEntry): + result.extend( + _FindChangedVars(path, webrtc_deps_entry.version, + cr_deps_entry.version)) + continue - # Use the revision from Chromium's DEPS file. - new_rev = cr_deps_entry.revision - assert webrtc_deps_entry.url == cr_deps_entry.url, ( - 'WebRTC DEPS entry %s has a different URL %s than Chromium %s.' % - (path, webrtc_deps_entry.url, cr_deps_entry.url)) - else: - if isinstance(webrtc_deps_entry, DepsEntry): - # Use the HEAD of the deps repo. - stdout, _ = _RunCommand( - ['git', 'ls-remote', webrtc_deps_entry.url, 'HEAD']) - new_rev = stdout.strip().split('\t')[0] - else: - # The dependency has been removed from chromium. - # This is handled by FindRemovedDeps. - continue + # Use the revision from Chromium's DEPS file. + new_rev = cr_deps_entry.revision + assert webrtc_deps_entry.url == cr_deps_entry.url, ( + 'WebRTC DEPS entry %s has a different URL %s than Chromium %s.' + % (path, webrtc_deps_entry.url, cr_deps_entry.url)) + else: + if isinstance(webrtc_deps_entry, DepsEntry): + # Use the HEAD of the deps repo. + stdout, _ = _RunCommand( + ['git', 'ls-remote', webrtc_deps_entry.url, 'HEAD']) + new_rev = stdout.strip().split('\t')[0] + else: + # The dependency has been removed from chromium. + # This is handled by FindRemovedDeps. + continue - # Check if an update is necessary. - if webrtc_deps_entry.revision != new_rev: - logging.debug('Roll dependency %s to %s', path, new_rev) - result.append( - ChangedDep(path, webrtc_deps_entry.url, webrtc_deps_entry.revision, - new_rev)) - return sorted(result) + # Check if an update is necessary. + if webrtc_deps_entry.revision != new_rev: + logging.debug('Roll dependency %s to %s', path, new_rev) + result.append( + ChangedDep(path, webrtc_deps_entry.url, + webrtc_deps_entry.revision, new_rev)) + return sorted(result) def CalculateChangedClang(new_cr_rev): - def GetClangRev(lines): - for line in lines: - match = CLANG_REVISION_RE.match(line) - if match: - return match.group(1) - raise RollError('Could not parse Clang revision!') + def GetClangRev(lines): + for line in lines: + match = CLANG_REVISION_RE.match(line) + if match: + return match.group(1) + raise RollError('Could not parse Clang revision!') - with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH, 'r') as f: - current_lines = f.readlines() - current_rev = GetClangRev(current_lines) + with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH, 'r') as f: + current_lines = f.readlines() + current_rev = GetClangRev(current_lines) - new_clang_update_py = ReadRemoteCrFile(CLANG_UPDATE_SCRIPT_URL_PATH, - new_cr_rev).splitlines() - new_rev = GetClangRev(new_clang_update_py) - return ChangedDep(CLANG_UPDATE_SCRIPT_LOCAL_PATH, None, current_rev, new_rev) + new_clang_update_py = ReadRemoteCrFile(CLANG_UPDATE_SCRIPT_URL_PATH, + new_cr_rev).splitlines() + new_rev = GetClangRev(new_clang_update_py) + return ChangedDep(CLANG_UPDATE_SCRIPT_LOCAL_PATH, None, current_rev, + new_rev) def GenerateCommitMessage( @@ -496,181 +500,186 @@ def GenerateCommitMessage( removed_deps_paths=None, clang_change=None, ): - current_cr_rev = rev_update.current_chromium_rev[0:10] - new_cr_rev = rev_update.new_chromium_rev[0:10] - rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev) - git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos) + current_cr_rev = rev_update.current_chromium_rev[0:10] + new_cr_rev = rev_update.new_chromium_rev[0:10] + rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev) + git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos) - commit_msg = [ - 'Roll chromium_revision %s (%s)\n' % (rev_interval, git_number_interval), - 'Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval), - 'Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE % rev_interval) - ] + commit_msg = [ + 'Roll chromium_revision %s (%s)\n' % + (rev_interval, git_number_interval), + 'Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval), + 'Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE % rev_interval) + ] - def Section(adjective, deps): - noun = 'dependency' if len(deps) == 1 else 'dependencies' - commit_msg.append('%s %s' % (adjective, noun)) + def Section(adjective, deps): + noun = 'dependency' if len(deps) == 1 else 'dependencies' + commit_msg.append('%s %s' % (adjective, noun)) - if changed_deps_list: - Section('Changed', changed_deps_list) + if changed_deps_list: + Section('Changed', changed_deps_list) - for c in changed_deps_list: - if isinstance(c, ChangedCipdPackage): - commit_msg.append('* %s: %s..%s' % - (c.path, c.current_version, c.new_version)) - elif isinstance(c, ChangedVersionEntry): - commit_msg.append('* %s_version: %s..%s' % - (c.path, c.current_version, c.new_version)) - else: - commit_msg.append('* %s: %s/+log/%s..%s' % - (c.path, c.url, c.current_rev[0:10], c.new_rev[0:10])) + for c in changed_deps_list: + if isinstance(c, ChangedCipdPackage): + commit_msg.append('* %s: %s..%s' % + (c.path, c.current_version, c.new_version)) + elif isinstance(c, ChangedVersionEntry): + commit_msg.append('* %s_version: %s..%s' % + (c.path, c.current_version, c.new_version)) + else: + commit_msg.append( + '* %s: %s/+log/%s..%s' % + (c.path, c.url, c.current_rev[0:10], c.new_rev[0:10])) - if added_deps_paths: - Section('Added', added_deps_paths) - commit_msg.extend('* %s' % p for p in added_deps_paths) + if added_deps_paths: + Section('Added', added_deps_paths) + commit_msg.extend('* %s' % p for p in added_deps_paths) - if removed_deps_paths: - Section('Removed', removed_deps_paths) - commit_msg.extend('* %s' % p for p in removed_deps_paths) + if removed_deps_paths: + Section('Removed', removed_deps_paths) + commit_msg.extend('* %s' % p for p in removed_deps_paths) - if any([changed_deps_list, added_deps_paths, removed_deps_paths]): - change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS') - commit_msg.append('DEPS diff: %s\n' % change_url) - else: - commit_msg.append('No dependencies changed.') + if any([changed_deps_list, added_deps_paths, removed_deps_paths]): + change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS') + commit_msg.append('DEPS diff: %s\n' % change_url) + else: + commit_msg.append('No dependencies changed.') - if clang_change and clang_change.current_rev != clang_change.new_rev: - commit_msg.append('Clang version changed %s:%s' % - (clang_change.current_rev, clang_change.new_rev)) - change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, - CLANG_UPDATE_SCRIPT_URL_PATH) - commit_msg.append('Details: %s\n' % change_url) - else: - commit_msg.append('No update to Clang.\n') + if clang_change and clang_change.current_rev != clang_change.new_rev: + commit_msg.append('Clang version changed %s:%s' % + (clang_change.current_rev, clang_change.new_rev)) + change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, + CLANG_UPDATE_SCRIPT_URL_PATH) + commit_msg.append('Details: %s\n' % change_url) + else: + commit_msg.append('No update to Clang.\n') - commit_msg.append('BUG=None') - return '\n'.join(commit_msg) + commit_msg.append('BUG=None') + return '\n'.join(commit_msg) def UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content): - """Update the DEPS file with the new revision.""" + """Update the DEPS file with the new revision.""" - with open(deps_filename, 'rb') as deps_file: - deps_content = deps_file.read().decode('utf-8') + with open(deps_filename, 'rb') as deps_file: + deps_content = deps_file.read().decode('utf-8') - # Update the chromium_revision variable. - deps_content = deps_content.replace(rev_update.current_chromium_rev, - rev_update.new_chromium_rev) + # Update the chromium_revision variable. + deps_content = deps_content.replace(rev_update.current_chromium_rev, + rev_update.new_chromium_rev) - # Add and remove dependencies. For now: only generated android deps. - # Since gclient cannot add or remove deps, we on the fact that - # these android deps are located in one place we can copy/paste. - deps_re = re.compile(ANDROID_DEPS_START + '.*' + ANDROID_DEPS_END, re.DOTALL) - new_deps = deps_re.search(new_cr_content) - old_deps = deps_re.search(deps_content) - if not new_deps or not old_deps: - faulty = 'Chromium' if not new_deps else 'WebRTC' - raise RollError('Was expecting to find "%s" and "%s"\n' - 'in %s DEPS' % - (ANDROID_DEPS_START, ANDROID_DEPS_END, faulty)) - deps_content = deps_re.sub(new_deps.group(0), deps_content) + # Add and remove dependencies. For now: only generated android deps. + # Since gclient cannot add or remove deps, we on the fact that + # these android deps are located in one place we can copy/paste. + deps_re = re.compile(ANDROID_DEPS_START + '.*' + ANDROID_DEPS_END, + re.DOTALL) + new_deps = deps_re.search(new_cr_content) + old_deps = deps_re.search(deps_content) + if not new_deps or not old_deps: + faulty = 'Chromium' if not new_deps else 'WebRTC' + raise RollError('Was expecting to find "%s" and "%s"\n' + 'in %s DEPS' % + (ANDROID_DEPS_START, ANDROID_DEPS_END, faulty)) + deps_content = deps_re.sub(new_deps.group(0), deps_content) - for dep in changed_deps: - if isinstance(dep, ChangedVersionEntry): - deps_content = deps_content.replace(dep.current_version, dep.new_version) + for dep in changed_deps: + if isinstance(dep, ChangedVersionEntry): + deps_content = deps_content.replace(dep.current_version, + dep.new_version) - with open(deps_filename, 'wb') as deps_file: - deps_file.write(deps_content.encode('utf-8')) + with open(deps_filename, 'wb') as deps_file: + deps_file.write(deps_content.encode('utf-8')) - # Update each individual DEPS entry. - for dep in changed_deps: - # ChangedVersionEntry types are already been processed. - if isinstance(dep, ChangedVersionEntry): - continue - local_dep_dir = os.path.join(CHECKOUT_ROOT_DIR, dep.path) - if not os.path.isdir(local_dep_dir): - raise RollError( - 'Cannot find local directory %s. Either run\n' - 'gclient sync --deps=all\n' - 'or make sure the .gclient file for your solution contains all ' - 'platforms in the target_os list, i.e.\n' - 'target_os = ["android", "unix", "mac", "ios", "win"];\n' - 'Then run "gclient sync" again.' % local_dep_dir) - if isinstance(dep, ChangedCipdPackage): - package = dep.package.format() # Eliminate double curly brackets - update = '%s:%s@%s' % (dep.path, package, dep.new_version) - else: - update = '%s@%s' % (dep.path, dep.new_rev) - _RunCommand(['gclient', 'setdep', '--revision', update], - working_dir=CHECKOUT_SRC_DIR) + # Update each individual DEPS entry. + for dep in changed_deps: + # ChangedVersionEntry types are already been processed. + if isinstance(dep, ChangedVersionEntry): + continue + local_dep_dir = os.path.join(CHECKOUT_ROOT_DIR, dep.path) + if not os.path.isdir(local_dep_dir): + raise RollError( + 'Cannot find local directory %s. Either run\n' + 'gclient sync --deps=all\n' + 'or make sure the .gclient file for your solution contains all ' + 'platforms in the target_os list, i.e.\n' + 'target_os = ["android", "unix", "mac", "ios", "win"];\n' + 'Then run "gclient sync" again.' % local_dep_dir) + if isinstance(dep, ChangedCipdPackage): + package = dep.package.format() # Eliminate double curly brackets + update = '%s:%s@%s' % (dep.path, package, dep.new_version) + else: + update = '%s@%s' % (dep.path, dep.new_rev) + _RunCommand(['gclient', 'setdep', '--revision', update], + working_dir=CHECKOUT_SRC_DIR) def _IsTreeClean(): - stdout, _ = _RunCommand(['git', 'status', '--porcelain']) - if len(stdout) == 0: - return True + stdout, _ = _RunCommand(['git', 'status', '--porcelain']) + if len(stdout) == 0: + return True - logging.error('Dirty/unversioned files:\n%s', stdout) - return False + logging.error('Dirty/unversioned files:\n%s', stdout) + return False def _EnsureUpdatedMainBranch(dry_run): - current_branch = _RunCommand(['git', 'rev-parse', '--abbrev-ref', - 'HEAD'])[0].splitlines()[0] - if current_branch != 'main': - logging.error('Please checkout the main branch and re-run this script.') - if not dry_run: - sys.exit(-1) + current_branch = _RunCommand(['git', 'rev-parse', '--abbrev-ref', + 'HEAD'])[0].splitlines()[0] + if current_branch != 'main': + logging.error( + 'Please checkout the main branch and re-run this script.') + if not dry_run: + sys.exit(-1) - logging.info('Updating main branch...') - _RunCommand(['git', 'pull']) + logging.info('Updating main branch...') + _RunCommand(['git', 'pull']) def _CreateRollBranch(dry_run): - logging.info('Creating roll branch: %s', ROLL_BRANCH_NAME) - if not dry_run: - _RunCommand(['git', 'checkout', '-b', ROLL_BRANCH_NAME]) + logging.info('Creating roll branch: %s', ROLL_BRANCH_NAME) + if not dry_run: + _RunCommand(['git', 'checkout', '-b', ROLL_BRANCH_NAME]) def _RemovePreviousRollBranch(dry_run): - active_branch, branches = _GetBranches() - if active_branch == ROLL_BRANCH_NAME: - active_branch = 'main' - if ROLL_BRANCH_NAME in branches: - logging.info('Removing previous roll branch (%s)', ROLL_BRANCH_NAME) - if not dry_run: - _RunCommand(['git', 'checkout', active_branch]) - _RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME]) + active_branch, branches = _GetBranches() + if active_branch == ROLL_BRANCH_NAME: + active_branch = 'main' + if ROLL_BRANCH_NAME in branches: + logging.info('Removing previous roll branch (%s)', ROLL_BRANCH_NAME) + if not dry_run: + _RunCommand(['git', 'checkout', active_branch]) + _RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME]) def _LocalCommit(commit_msg, dry_run): - logging.info('Committing changes locally.') - if not dry_run: - _RunCommand(['git', 'add', '--update', '.']) - _RunCommand(['git', 'commit', '-m', commit_msg]) + logging.info('Committing changes locally.') + if not dry_run: + _RunCommand(['git', 'add', '--update', '.']) + _RunCommand(['git', 'commit', '-m', commit_msg]) def ChooseCQMode(skip_cq, cq_over, current_commit_pos, new_commit_pos): - if skip_cq: - return 0 - if (new_commit_pos - current_commit_pos) < cq_over: - return 1 - return 2 + if skip_cq: + return 0 + if (new_commit_pos - current_commit_pos) < cq_over: + return 1 + return 2 def _GetCcRecipients(changed_deps_list): - """Returns a list of emails to notify based on the changed deps list. + """Returns a list of emails to notify based on the changed deps list. """ - cc_recipients = [] - for c in changed_deps_list: - if 'libvpx' in c.path or 'libaom' in c.path: - cc_recipients.append('marpan@webrtc.org') - cc_recipients.append('jianj@chromium.org') - return cc_recipients + cc_recipients = [] + for c in changed_deps_list: + if 'libvpx' in c.path or 'libaom' in c.path: + cc_recipients.append('marpan@webrtc.org') + cc_recipients.append('jianj@chromium.org') + return cc_recipients def _UploadCL(commit_queue_mode, add_cc=None): - """Upload the committed changes as a changelist to Gerrit. + """Upload the committed changes as a changelist to Gerrit. commit_queue_mode: - 2: Submit to commit queue. @@ -679,139 +688,143 @@ def _UploadCL(commit_queue_mode, add_cc=None): add_cc: A list of email addresses to add as CC recipients. """ - cc_recipients = [NOTIFY_EMAIL] - if add_cc: - cc_recipients.extend(add_cc) - cmd = ['git', 'cl', 'upload', '--force', '--bypass-hooks'] - if commit_queue_mode >= 2: - logging.info('Sending the CL to the CQ...') - cmd.extend(['-o', 'label=Bot-Commit+1']) - cmd.extend(['-o', 'label=Commit-Queue+2']) - cmd.extend(['--send-mail', '--cc', ','.join(cc_recipients)]) - elif commit_queue_mode >= 1: - logging.info('Starting CQ dry run...') - cmd.extend(['-o', 'label=Commit-Queue+1']) - extra_env = { - 'EDITOR': 'true', - 'SKIP_GCE_AUTH_FOR_GIT': '1', - } - stdout, stderr = _RunCommand(cmd, extra_env=extra_env) - logging.debug('Output from "git cl upload":\nstdout:\n%s\n\nstderr:\n%s', - stdout, stderr) + cc_recipients = [NOTIFY_EMAIL] + if add_cc: + cc_recipients.extend(add_cc) + cmd = ['git', 'cl', 'upload', '--force', '--bypass-hooks'] + if commit_queue_mode >= 2: + logging.info('Sending the CL to the CQ...') + cmd.extend(['-o', 'label=Bot-Commit+1']) + cmd.extend(['-o', 'label=Commit-Queue+2']) + cmd.extend(['--send-mail', '--cc', ','.join(cc_recipients)]) + elif commit_queue_mode >= 1: + logging.info('Starting CQ dry run...') + cmd.extend(['-o', 'label=Commit-Queue+1']) + extra_env = { + 'EDITOR': 'true', + 'SKIP_GCE_AUTH_FOR_GIT': '1', + } + stdout, stderr = _RunCommand(cmd, extra_env=extra_env) + logging.debug('Output from "git cl upload":\nstdout:\n%s\n\nstderr:\n%s', + stdout, stderr) def GetRollRevisionRanges(opts, webrtc_deps): - current_cr_rev = webrtc_deps['vars']['chromium_revision'] - new_cr_rev = opts.revision - if not new_cr_rev: - stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD']) - head_rev = stdout.strip().split('\t')[0] - logging.info('No revision specified. Using HEAD: %s', head_rev) - new_cr_rev = head_rev + current_cr_rev = webrtc_deps['vars']['chromium_revision'] + new_cr_rev = opts.revision + if not new_cr_rev: + stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD']) + head_rev = stdout.strip().split('\t')[0] + logging.info('No revision specified. Using HEAD: %s', head_rev) + new_cr_rev = head_rev - return ChromiumRevisionUpdate(current_cr_rev, new_cr_rev) + return ChromiumRevisionUpdate(current_cr_rev, new_cr_rev) def main(): - p = argparse.ArgumentParser() - p.add_argument('--clean', - action='store_true', - default=False, - help='Removes any previous local roll branch.') - p.add_argument('-r', - '--revision', - help=('Chromium Git revision to roll to. Defaults to the ' - 'Chromium HEAD revision if omitted.')) - p.add_argument('--dry-run', - action='store_true', - default=False, - help=('Calculate changes and modify DEPS, but don\'t create ' - 'any local branch, commit, upload CL or send any ' - 'tryjobs.')) - p.add_argument('-i', - '--ignore-unclean-workdir', - action='store_true', - default=False, - help=('Ignore if the current branch is not main or if there ' - 'are uncommitted changes (default: %(default)s).')) - grp = p.add_mutually_exclusive_group() - grp.add_argument('--skip-cq', + p = argparse.ArgumentParser() + p.add_argument('--clean', action='store_true', default=False, - help='Skip sending the CL to the CQ (default: %(default)s)') - grp.add_argument('--cq-over', - type=int, - default=1, - help=('Commit queue dry run if the revision difference ' - 'is below this number (default: %(default)s)')) - p.add_argument('-v', - '--verbose', - action='store_true', - default=False, - help='Be extra verbose in printing of log messages.') - opts = p.parse_args() + help='Removes any previous local roll branch.') + p.add_argument('-r', + '--revision', + help=('Chromium Git revision to roll to. Defaults to the ' + 'Chromium HEAD revision if omitted.')) + p.add_argument( + '--dry-run', + action='store_true', + default=False, + help=('Calculate changes and modify DEPS, but don\'t create ' + 'any local branch, commit, upload CL or send any ' + 'tryjobs.')) + p.add_argument( + '-i', + '--ignore-unclean-workdir', + action='store_true', + default=False, + help=('Ignore if the current branch is not main or if there ' + 'are uncommitted changes (default: %(default)s).')) + grp = p.add_mutually_exclusive_group() + grp.add_argument( + '--skip-cq', + action='store_true', + default=False, + help='Skip sending the CL to the CQ (default: %(default)s)') + grp.add_argument('--cq-over', + type=int, + default=1, + help=('Commit queue dry run if the revision difference ' + 'is below this number (default: %(default)s)')) + p.add_argument('-v', + '--verbose', + action='store_true', + default=False, + help='Be extra verbose in printing of log messages.') + opts = p.parse_args() - if opts.verbose: - logging.basicConfig(level=logging.DEBUG) - else: - logging.basicConfig(level=logging.INFO) + if opts.verbose: + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) - if not opts.ignore_unclean_workdir and not _IsTreeClean(): - logging.error('Please clean your local checkout first.') - return 1 + if not opts.ignore_unclean_workdir and not _IsTreeClean(): + logging.error('Please clean your local checkout first.') + return 1 - if opts.clean: - _RemovePreviousRollBranch(opts.dry_run) + if opts.clean: + _RemovePreviousRollBranch(opts.dry_run) - if not opts.ignore_unclean_workdir: - _EnsureUpdatedMainBranch(opts.dry_run) + if not opts.ignore_unclean_workdir: + _EnsureUpdatedMainBranch(opts.dry_run) - deps_filename = os.path.join(CHECKOUT_SRC_DIR, 'DEPS') - webrtc_deps = ParseLocalDepsFile(deps_filename) + deps_filename = os.path.join(CHECKOUT_SRC_DIR, 'DEPS') + webrtc_deps = ParseLocalDepsFile(deps_filename) - rev_update = GetRollRevisionRanges(opts, webrtc_deps) + rev_update = GetRollRevisionRanges(opts, webrtc_deps) - current_commit_pos = ParseCommitPosition( - ReadRemoteCrCommit(rev_update.current_chromium_rev)) - new_commit_pos = ParseCommitPosition( - ReadRemoteCrCommit(rev_update.new_chromium_rev)) + current_commit_pos = ParseCommitPosition( + ReadRemoteCrCommit(rev_update.current_chromium_rev)) + new_commit_pos = ParseCommitPosition( + ReadRemoteCrCommit(rev_update.new_chromium_rev)) - new_cr_content = ReadRemoteCrFile('DEPS', rev_update.new_chromium_rev) - new_cr_deps = ParseDepsDict(new_cr_content) - changed_deps = CalculateChangedDeps(webrtc_deps, new_cr_deps) - # Discard other deps, assumed to be chromium-only dependencies. - new_generated_android_deps, _ = FindAddedDeps(webrtc_deps, new_cr_deps) - removed_generated_android_deps, other_deps = FindRemovedDeps( - webrtc_deps, new_cr_deps) - if other_deps: - raise RollError('WebRTC DEPS entries are missing from Chromium: %s.\n' - 'Remove them or add them to either ' - 'WEBRTC_ONLY_DEPS or DONT_AUTOROLL_THESE.' % other_deps) - clang_change = CalculateChangedClang(rev_update.new_chromium_rev) - commit_msg = GenerateCommitMessage( - rev_update, - current_commit_pos, - new_commit_pos, - changed_deps, - added_deps_paths=new_generated_android_deps, - removed_deps_paths=removed_generated_android_deps, - clang_change=clang_change) - logging.debug('Commit message:\n%s', commit_msg) + new_cr_content = ReadRemoteCrFile('DEPS', rev_update.new_chromium_rev) + new_cr_deps = ParseDepsDict(new_cr_content) + changed_deps = CalculateChangedDeps(webrtc_deps, new_cr_deps) + # Discard other deps, assumed to be chromium-only dependencies. + new_generated_android_deps, _ = FindAddedDeps(webrtc_deps, new_cr_deps) + removed_generated_android_deps, other_deps = FindRemovedDeps( + webrtc_deps, new_cr_deps) + if other_deps: + raise RollError('WebRTC DEPS entries are missing from Chromium: %s.\n' + 'Remove them or add them to either ' + 'WEBRTC_ONLY_DEPS or DONT_AUTOROLL_THESE.' % + other_deps) + clang_change = CalculateChangedClang(rev_update.new_chromium_rev) + commit_msg = GenerateCommitMessage( + rev_update, + current_commit_pos, + new_commit_pos, + changed_deps, + added_deps_paths=new_generated_android_deps, + removed_deps_paths=removed_generated_android_deps, + clang_change=clang_change) + logging.debug('Commit message:\n%s', commit_msg) - _CreateRollBranch(opts.dry_run) - if not opts.dry_run: - UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content) - if _IsTreeClean(): - logging.info("No DEPS changes detected, skipping CL creation.") - else: - _LocalCommit(commit_msg, opts.dry_run) - commit_queue_mode = ChooseCQMode(opts.skip_cq, opts.cq_over, - current_commit_pos, new_commit_pos) - logging.info('Uploading CL...') + _CreateRollBranch(opts.dry_run) if not opts.dry_run: - _UploadCL(commit_queue_mode, _GetCcRecipients(changed_deps)) - return 0 + UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content) + if _IsTreeClean(): + logging.info("No DEPS changes detected, skipping CL creation.") + else: + _LocalCommit(commit_msg, opts.dry_run) + commit_queue_mode = ChooseCQMode(opts.skip_cq, opts.cq_over, + current_commit_pos, new_commit_pos) + logging.info('Uploading CL...') + if not opts.dry_run: + _UploadCL(commit_queue_mode, _GetCcRecipients(changed_deps)) + return 0 if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) diff --git a/tools_webrtc/mb/mb_config.pyl b/tools_webrtc/mb/mb_config.pyl index cb52f9124a..6aea3c9cba 100644 --- a/tools_webrtc/mb/mb_config.pyl +++ b/tools_webrtc/mb/mb_config.pyl @@ -397,10 +397,10 @@ 'gn_args': 'is_debug=true', }, 'debug_bot': { - 'mixins': ['debug', 'reclient'], + 'mixins': ['debug', 'reclient', 'strict_field_trials'], }, 'debug_static_bot': { - 'mixins': ['debug', 'minimal_symbols', 'reclient'], + 'mixins': ['debug', 'minimal_symbols', 'reclient', 'strict_field_trials'], }, 'dummy_audio_file_devices': { 'gn_args': 'rtc_use_dummy_audio_file_devices=true', @@ -465,7 +465,7 @@ 'gn_args': 'is_debug=false', }, 'release_bot': { - 'mixins': ['pure_release_bot', 'dcheck_always_on'], + 'mixins': ['pure_release_bot', 'dcheck_always_on', 'strict_field_trials'], }, 'rtc_objc_test_prefix': { 'gn_args': 'rtc_objc_prefix="RTC_TESTING"', @@ -473,6 +473,9 @@ 'rtti': { 'gn_args': 'use_rtti=true', }, + 'strict_field_trials': { + 'gn_args': 'rtc_strict_field_trials="dcheck"', + }, 'tsan': { 'gn_args': 'is_tsan=true', }, diff --git a/tools_webrtc/sanitizers/lsan_suppressions_webrtc.cc b/tools_webrtc/sanitizers/lsan_suppressions_webrtc.cc index 064b2804ab..eb9f6a4761 100644 --- a/tools_webrtc/sanitizers/lsan_suppressions_webrtc.cc +++ b/tools_webrtc/sanitizers/lsan_suppressions_webrtc.cc @@ -74,8 +74,6 @@ char kLSanDefaultSuppressions[] = // peerconnection_unittests // https://code.google.com/p/webrtc/issues/detail?id=2528 "leak:cricket::FakeVideoMediaChannel::~FakeVideoMediaChannel\n" - "leak:cricket::MediaSessionDescriptionFactory::CreateAnswer\n" - "leak:cricket::MediaSessionDescriptionFactory::CreateOffer\n" "leak:DtmfSenderTest_InsertEmptyTonesToCancelPreviousTask_Test::TestBody\n" "leak:sigslot::_signal_base2*::~_signal_base2\n" "leak:testing::internal::CmpHelperEQ\n" @@ -83,8 +81,6 @@ char kLSanDefaultSuppressions[] = "leak:webrtc::AudioDeviceLinuxALSA::InitSpeaker\n" "leak:webrtc::CreateIceCandidate\n" "leak:webrtc::WebRtcIdentityRequestObserver::OnSuccess\n" - "leak:webrtc::WebRtcSessionDescriptionFactory::InternalCreateAnswer\n" - "leak:webrtc::WebRtcSessionDescriptionFactory::InternalCreateOffer\n" "leak:PeerConnectionInterfaceTest_SsrcInOfferAnswer_Test::TestBody\n" "leak:PeerConnectionInterfaceTest_CloseAndTestMethods_Test::TestBody\n" "leak:WebRtcSdpTest::TestDeserializeRtcpFb\n" diff --git a/video/BUILD.gn b/video/BUILD.gn index d696445db2..1722ad4f6e 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -244,6 +244,7 @@ rtc_library("frame_cadence_adapter") { "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/system:no_unique_address", + "../rtc_base/system:unused", "../rtc_base/task_utils:repeating_task", "../system_wrappers", "../system_wrappers:field_trial", @@ -561,6 +562,7 @@ if (rtc_include_tests) { "../test:platform_video_capturer", "../test:rtp_test_utils", "../test:test_common", + "../test:test_flags", "../test:test_renderer", "../test:test_support", "../test:test_support_test_artifacts", @@ -661,6 +663,7 @@ if (rtc_include_tests) { "../test:run_test", "../test:run_test_interface", "../test:test_common", + "../test:test_flags", "../test:test_renderer", "../test:test_support", "//testing/gtest", @@ -706,6 +709,7 @@ if (rtc_include_tests) { "../test:run_test", "../test:run_test_interface", "../test:test_common", + "../test:test_flags", "../test:test_renderer", "../test:test_support", "//third_party/abseil-cpp/absl/flags:flag", @@ -732,6 +736,7 @@ if (rtc_include_tests) { "../test:run_test", "../test:run_test_interface", "../test:test_common", + "../test:test_flags", "../test:test_renderer", "../test:test_support", "//testing/gtest", diff --git a/video/adaptation/overuse_frame_detector.cc b/video/adaptation/overuse_frame_detector.cc index e5c2c7d379..56fe71af41 100644 --- a/video/adaptation/overuse_frame_detector.cc +++ b/video/adaptation/overuse_frame_detector.cc @@ -25,6 +25,7 @@ #include "rtc_base/logging.h" #include "rtc_base/numerics/exp_filter.h" #include "rtc_base/time_utils.h" +#include "rtc_base/trace_event.h" #include "system_wrappers/include/field_trial.h" #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) @@ -587,6 +588,7 @@ void OveruseFrameDetector::CheckForOveruse( return; int64_t now_ms = rtc::TimeMillis(); + const char* action = "NoAction"; if (IsOverusing(*encode_usage_percent_)) { // If the last thing we did was going up, and now have to back down, we need @@ -612,21 +614,24 @@ void OveruseFrameDetector::CheckForOveruse( ++num_overuse_detections_; observer->AdaptDown(); + action = "AdaptDown"; } else if (IsUnderusing(*encode_usage_percent_, now_ms)) { last_rampup_time_ms_ = now_ms; in_quick_rampup_ = true; observer->AdaptUp(); + action = "AdaptUp"; } + TRACE_EVENT2("webrtc", "OveruseFrameDetector::CheckForOveruse", + "encode_usage_percent", *encode_usage_percent_, "action", + TRACE_STR_COPY(action)); int rampup_delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; - RTC_LOG(LS_VERBOSE) << " Frame stats: " - " encode usage " - << *encode_usage_percent_ << " overuse detections " - << num_overuse_detections_ << " rampup delay " - << rampup_delay; + RTC_LOG(LS_INFO) << "CheckForOveruse: encode usage " << *encode_usage_percent_ + << " overuse detections " << num_overuse_detections_ + << " rampup delay " << rampup_delay << " action " << action; } void OveruseFrameDetector::SetOptions(const CpuOveruseOptions& options) { diff --git a/video/adaptation/quality_scaler_resource.cc b/video/adaptation/quality_scaler_resource.cc index 68d56fe29e..a24a3e88ff 100644 --- a/video/adaptation/quality_scaler_resource.cc +++ b/video/adaptation/quality_scaler_resource.cc @@ -12,6 +12,7 @@ #include +#include "api/field_trials_view.h" #include "rtc_base/checks.h" #include "rtc_base/experiments/balanced_degradation_settings.h" #include "rtc_base/time_utils.h" @@ -37,11 +38,12 @@ bool QualityScalerResource::is_started() const { } void QualityScalerResource::StartCheckForOveruse( - VideoEncoder::QpThresholds qp_thresholds) { + VideoEncoder::QpThresholds qp_thresholds, + const FieldTrialsView& field_trials) { RTC_DCHECK_RUN_ON(encoder_queue()); RTC_DCHECK(!is_started()); - quality_scaler_ = - std::make_unique(this, std::move(qp_thresholds)); + quality_scaler_ = std::make_unique( + this, std::move(qp_thresholds), field_trials); } void QualityScalerResource::StopCheckForOveruse() { diff --git a/video/adaptation/quality_scaler_resource.h b/video/adaptation/quality_scaler_resource.h index cbb6d3d06f..a1ed34a1ce 100644 --- a/video/adaptation/quality_scaler_resource.h +++ b/video/adaptation/quality_scaler_resource.h @@ -16,6 +16,7 @@ #include #include "absl/types/optional.h" +#include "api/field_trials_view.h" #include "api/scoped_refptr.h" #include "api/video/video_adaptation_reason.h" #include "api/video_codecs/video_encoder.h" @@ -37,7 +38,8 @@ class QualityScalerResource : public VideoStreamEncoderResource, bool is_started() const; - void StartCheckForOveruse(VideoEncoder::QpThresholds qp_thresholds); + void StartCheckForOveruse(VideoEncoder::QpThresholds qp_thresholds, + const FieldTrialsView& field_trials); void StopCheckForOveruse(); void SetQpThresholds(VideoEncoder::QpThresholds qp_thresholds); bool QpFastFilterLow(); diff --git a/video/adaptation/video_stream_encoder_resource_manager.cc b/video/adaptation/video_stream_encoder_resource_manager.cc index 46db686703..eaeb0d5a46 100644 --- a/video/adaptation/video_stream_encoder_resource_manager.cc +++ b/video/adaptation/video_stream_encoder_resource_manager.cc @@ -21,6 +21,7 @@ #include "absl/algorithm/container.h" #include "absl/base/macros.h" #include "api/adaptation/resource.h" +#include "api/field_trials_view.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_base.h" #include "api/video/video_adaptation_reason.h" @@ -116,9 +117,10 @@ absl::optional GetSingleActiveLayerMaxBitrate( class VideoStreamEncoderResourceManager::InitialFrameDropper { public: explicit InitialFrameDropper( - rtc::scoped_refptr quality_scaler_resource) + rtc::scoped_refptr quality_scaler_resource, + const FieldTrialsView& field_trials) : quality_scaler_resource_(quality_scaler_resource), - quality_scaler_settings_(QualityScalerSettings::ParseFromFieldTrials()), + quality_scaler_settings_(field_trials), has_seen_first_bwe_drop_(false), set_start_bitrate_(DataRate::Zero()), set_start_bitrate_time_ms_(0), @@ -289,8 +291,10 @@ VideoStreamEncoderResourceManager::VideoStreamEncoderResourceManager( clock_(clock), experiment_cpu_load_estimator_(experiment_cpu_load_estimator), initial_frame_dropper_( - std::make_unique(quality_scaler_resource_)), - quality_scaling_experiment_enabled_(QualityScalingExperiment::Enabled()), + std::make_unique(quality_scaler_resource_, + field_trials)), + quality_scaling_experiment_enabled_( + QualityScalingExperiment::Enabled(field_trials_)), pixel_limit_resource_experiment_enabled_( field_trials.IsEnabled(kPixelLimitResourceFieldTrialName)), encoder_target_bitrate_bps_(absl::nullopt), @@ -507,7 +511,7 @@ void VideoStreamEncoderResourceManager::OnEncodeCompleted( DataSize frame_size) { RTC_DCHECK_RUN_ON(encoder_queue_); // Inform `encode_usage_resource_` of the encode completed event. - uint32_t timestamp = encoded_image.Timestamp(); + uint32_t timestamp = encoded_image.RtpTimestamp(); int64_t capture_time_us = encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec; encode_usage_resource_->OnEncodeCompleted( @@ -561,7 +565,8 @@ void VideoStreamEncoderResourceManager::UpdateQualityScalerSettings( if (quality_scaler_resource_->is_started()) { quality_scaler_resource_->SetQpThresholds(qp_thresholds.value()); } else { - quality_scaler_resource_->StartCheckForOveruse(qp_thresholds.value()); + quality_scaler_resource_->StartCheckForOveruse(qp_thresholds.value(), + field_trials_); AddResource(quality_scaler_resource_, VideoAdaptationReason::kQuality); } } else if (quality_scaler_resource_->is_started()) { @@ -615,7 +620,7 @@ void VideoStreamEncoderResourceManager::ConfigureQualityScaler( absl::optional experimental_thresholds; if (quality_scaling_experiment_enabled_) { experimental_thresholds = QualityScalingExperiment::GetQpThresholds( - GetVideoCodecTypeOrGeneric(encoder_settings_)); + GetVideoCodecTypeOrGeneric(encoder_settings_), field_trials_); } UpdateQualityScalerSettings(experimental_thresholds.has_value() ? experimental_thresholds diff --git a/video/config/video_encoder_config.cc b/video/config/video_encoder_config.cc index 6ea2052138..84442aeddf 100644 --- a/video/config/video_encoder_config.cc +++ b/video/config/video_encoder_config.cc @@ -68,8 +68,7 @@ VideoEncoderConfig::~VideoEncoderConfig() = default; std::string VideoEncoderConfig::ToString() const { char buf[1024]; rtc::SimpleStringBuilder ss(buf); - ss << "{codec_type: "; - ss << CodecTypeToPayloadString(codec_type); + ss << "{codec_type: " << CodecTypeToPayloadString(codec_type); ss << ", content_type: "; switch (content_type) { case ContentType::kRealtimeVideo: @@ -96,6 +95,8 @@ void VideoEncoderConfig::EncoderSpecificSettings::FillEncoderSpecificSettings( FillVideoCodecVp8(codec->VP8()); } else if (codec->codecType == kVideoCodecVP9) { FillVideoCodecVp9(codec->VP9()); + } else if (codec->codecType == kVideoCodecAV1) { + FillVideoCodecAv1(codec->AV1()); } else { RTC_DCHECK_NOTREACHED() << "Encoder specifics set/used for unknown codec type."; @@ -112,6 +113,11 @@ void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecVp9( RTC_DCHECK_NOTREACHED(); } +void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecAv1( + VideoCodecAV1* av1_settings) const { + RTC_DCHECK_NOTREACHED(); +} + VideoEncoderConfig::Vp8EncoderSpecificSettings::Vp8EncoderSpecificSettings( const VideoCodecVP8& specifics) : specifics_(specifics) {} @@ -130,4 +136,13 @@ void VideoEncoderConfig::Vp9EncoderSpecificSettings::FillVideoCodecVp9( *vp9_settings = specifics_; } +VideoEncoderConfig::Av1EncoderSpecificSettings::Av1EncoderSpecificSettings( + const VideoCodecAV1& specifics) + : specifics_(specifics) {} + +void VideoEncoderConfig::Av1EncoderSpecificSettings::FillVideoCodecAv1( + VideoCodecAV1* av1_settings) const { + *av1_settings = specifics_; +} + } // namespace webrtc diff --git a/video/config/video_encoder_config.h b/video/config/video_encoder_config.h index 59c9a39f82..cb0644a7fd 100644 --- a/video/config/video_encoder_config.h +++ b/video/config/video_encoder_config.h @@ -99,6 +99,7 @@ class VideoEncoderConfig { virtual void FillVideoCodecVp8(VideoCodecVP8* vp8_settings) const; virtual void FillVideoCodecVp9(VideoCodecVP9* vp9_settings) const; + virtual void FillVideoCodecAv1(VideoCodecAV1* av1_settings) const; private: ~EncoderSpecificSettings() override {} @@ -123,6 +124,15 @@ class VideoEncoderConfig { VideoCodecVP9 specifics_; }; + class Av1EncoderSpecificSettings : public EncoderSpecificSettings { + public: + explicit Av1EncoderSpecificSettings(const VideoCodecAV1& specifics); + void FillVideoCodecAv1(VideoCodecAV1* av1_settings) const override; + + private: + VideoCodecAV1 specifics_; + }; + enum class ContentType { kRealtimeVideo, kScreen, diff --git a/video/encoder_bitrate_adjuster.cc b/video/encoder_bitrate_adjuster.cc index 465d517d21..02468cb0b3 100644 --- a/video/encoder_bitrate_adjuster.cc +++ b/video/encoder_bitrate_adjuster.cc @@ -14,6 +14,7 @@ #include #include +#include "api/field_trials_view.h" #include "rtc_base/experiments/rate_control_settings.h" #include "rtc_base/logging.h" #include "rtc_base/time_utils.h" @@ -43,11 +44,15 @@ constexpr int64_t EncoderBitrateAdjuster::kWindowSizeMs; constexpr size_t EncoderBitrateAdjuster::kMinFramesSinceLayoutChange; constexpr double EncoderBitrateAdjuster::kDefaultUtilizationFactor; -EncoderBitrateAdjuster::EncoderBitrateAdjuster(const VideoCodec& codec_settings) - : utilize_bandwidth_headroom_(RateControlSettings::ParseFromFieldTrials() - .BitrateAdjusterCanUseNetworkHeadroom()), +EncoderBitrateAdjuster::EncoderBitrateAdjuster( + const VideoCodec& codec_settings, + const FieldTrialsView& field_trials) + : utilize_bandwidth_headroom_( + RateControlSettings::ParseFromKeyValueConfig(&field_trials) + .BitrateAdjusterCanUseNetworkHeadroom()), frames_since_layout_change_(0), min_bitrates_bps_{}, + frame_size_pixels_{}, codec_(codec_settings.codecType), codec_mode_(codec_settings.mode) { // TODO(https://crbug.com/webrtc/14891): If we want to support simulcast of @@ -60,6 +65,8 @@ EncoderBitrateAdjuster::EncoderBitrateAdjuster(const VideoCodec& codec_settings) min_bitrates_bps_[si] = std::max(codec_settings.minBitrate * 1000, codec_settings.spatialLayers[si].minBitrate * 1000); + frame_size_pixels_[si] = codec_settings.spatialLayers[si].width * + codec_settings.spatialLayers[si].height; } } } else { @@ -68,6 +75,8 @@ EncoderBitrateAdjuster::EncoderBitrateAdjuster(const VideoCodec& codec_settings) min_bitrates_bps_[si] = std::max(codec_settings.minBitrate * 1000, codec_settings.simulcastStream[si].minBitrate * 1000); + frame_size_pixels_[si] = codec_settings.spatialLayers[si].width * + codec_settings.spatialLayers[si].height; } } } @@ -314,6 +323,12 @@ void EncoderBitrateAdjuster::OnEncoderInfo( // Copy allocation into current state and re-allocate. for (size_t si = 0; si < kMaxSpatialLayers; ++si) { current_fps_allocation_[si] = encoder_info.fps_allocation[si]; + if (frame_size_pixels_[si] > 0) { + if (auto bwlimit = encoder_info.GetEncoderBitrateLimitsForResolution( + frame_size_pixels_[si])) { + min_bitrates_bps_[si] = bwlimit->min_bitrate_bps; + } + } } // Trigger re-allocation so that overshoot detectors have correct targets. diff --git a/video/encoder_bitrate_adjuster.h b/video/encoder_bitrate_adjuster.h index 6b35186b98..0ddd20b9b3 100644 --- a/video/encoder_bitrate_adjuster.h +++ b/video/encoder_bitrate_adjuster.h @@ -13,6 +13,7 @@ #include +#include "api/field_trials_view.h" #include "api/video/encoded_image.h" #include "api/video/video_bitrate_allocation.h" #include "api/video_codecs/video_encoder.h" @@ -34,7 +35,8 @@ class EncoderBitrateAdjuster { // build too much queue at the very start. static constexpr double kDefaultUtilizationFactor = 1.2; - explicit EncoderBitrateAdjuster(const VideoCodec& codec_settings); + EncoderBitrateAdjuster(const VideoCodec& codec_settings, + const FieldTrialsView& field_trials); ~EncoderBitrateAdjuster(); // Adjusts the given rate allocation to make it paceable within the target @@ -74,6 +76,9 @@ class EncoderBitrateAdjuster { // Minimum bitrates allowed, per spatial layer. uint32_t min_bitrates_bps_[kMaxSpatialLayers]; + // Size in pixels of each spatial layer. + uint32_t frame_size_pixels_[kMaxSpatialLayers]; + // Codec type used for encoding. VideoCodecType codec_; diff --git a/video/encoder_bitrate_adjuster_unittest.cc b/video/encoder_bitrate_adjuster_unittest.cc index 4ec223a208..e0f6de3120 100644 --- a/video/encoder_bitrate_adjuster_unittest.cc +++ b/video/encoder_bitrate_adjuster_unittest.cc @@ -13,11 +13,12 @@ #include #include +#include "api/field_trials_view.h" #include "api/units/data_rate.h" #include "rtc_base/fake_clock.h" #include "rtc_base/numerics/safe_conversions.h" -#include "test/field_trial.h" #include "test/gtest.h" +#include "test/scoped_key_value_config.h" namespace webrtc { namespace test { @@ -67,6 +68,8 @@ class EncoderBitrateAdjusterTest : public ::testing::Test { codec_.simulcastStream[si].maxBitrate = 300 * (1 << si); codec_.simulcastStream[si].active = true; codec_.simulcastStream[si].numberOfTemporalLayers = num_temporal_layers; + codec_.spatialLayers[si].width = 320 * (1<(codec_); + adjuster_ = + std::make_unique(codec_, scoped_field_trial_); adjuster_->OnEncoderInfo(encoder_info_); current_adjusted_allocation_ = adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters( @@ -232,6 +236,7 @@ class EncoderBitrateAdjusterTest : public ::testing::Test { double target_framerate_fps_; int tl_pattern_idx_[kMaxSpatialLayers]; int sequence_idx_[kMaxSpatialLayers][kMaxTemporalStreams]; + test::ScopedKeyValueConfig scoped_field_trial_; const std::vector kTlPatterns[kMaxTemporalStreams] = { {0}, @@ -420,7 +425,8 @@ TEST_F(EncoderBitrateAdjusterTest, DifferentSpatialOvershoots) { TEST_F(EncoderBitrateAdjusterTest, HeadroomAllowsOvershootToMediaRate) { // Two streams, both with three temporal layers. // Media rate is 1.0, but network rate is higher. - ScopedFieldTrials field_trial( + test::ScopedKeyValueConfig field_trial( + scoped_field_trial_, "WebRTC-VideoRateControl/adjuster_use_headroom:true/"); const uint32_t kS0Bitrate = 300000; @@ -462,7 +468,8 @@ TEST_F(EncoderBitrateAdjusterTest, HeadroomAllowsOvershootToMediaRate) { TEST_F(EncoderBitrateAdjusterTest, DontExceedMediaRateEvenWithHeadroom) { // Two streams, both with three temporal layers. // Media rate is 1.1, but network rate is higher. - ScopedFieldTrials field_trial( + test::ScopedKeyValueConfig field_trial( + scoped_field_trial_, "WebRTC-VideoRateControl/adjuster_use_headroom:true/"); const uint32_t kS0Bitrate = 300000; @@ -502,5 +509,33 @@ TEST_F(EncoderBitrateAdjusterTest, DontExceedMediaRateEvenWithHeadroom) { } } +TEST_F(EncoderBitrateAdjusterTest, HonorMinBitrateSettingFromEncoderInfo) { + // Single layer, well behaved encoder. + const int high_bitrate = 20000; + const int a_lower_min_bitrate = 12000; + current_input_allocation_.SetBitrate(0, 0, high_bitrate); + VideoBitrateAllocation expected_input_allocation; + expected_input_allocation.SetBitrate(0, 0, a_lower_min_bitrate); + + target_framerate_fps_ = 30; + + SetUpAdjuster(1, 1, false); + + auto new_resolution_limit = VideoEncoder::ResolutionBitrateLimits( + codec_.spatialLayers[0].width * codec_.spatialLayers[0].height, 15000, + a_lower_min_bitrate, 2000000); + encoder_info_.resolution_bitrate_limits.push_back(new_resolution_limit); + adjuster_->OnEncoderInfo(encoder_info_); + + InsertFrames({{2.0}}, kWindowSizeMs); + + current_adjusted_allocation_ = + adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters( + current_input_allocation_, target_framerate_fps_)); + // Adjusted allocation near input. Allow 1% error margin due to rounding + // errors etc. + ExpectNear(expected_input_allocation, current_adjusted_allocation_, 0.01); +} + } // namespace test } // namespace webrtc diff --git a/video/encoder_overshoot_detector.cc b/video/encoder_overshoot_detector.cc index 2c4efdb5a6..d5c1f91575 100644 --- a/video/encoder_overshoot_detector.cc +++ b/video/encoder_overshoot_detector.cc @@ -266,6 +266,12 @@ void EncoderOvershootDetector::UpdateHistograms() { RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H264", average_overshoot_percent); break; + case VideoCodecType::kVideoCodecH265: + RTC_HISTOGRAMS_COUNTS_10000(index, rmse_histogram_prefix + "H265", + bitrate_rmse); + RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H265", + average_overshoot_percent); + break; case VideoCodecType::kVideoCodecGeneric: case VideoCodecType::kVideoCodecMultiplex: break; diff --git a/video/encoder_overshoot_detector_unittest.cc b/video/encoder_overshoot_detector_unittest.cc index bdc2676281..2178957889 100644 --- a/video/encoder_overshoot_detector_unittest.cc +++ b/video/encoder_overshoot_detector_unittest.cc @@ -35,6 +35,8 @@ static std::string CodecTypeToHistogramSuffix(VideoCodecType codec) { return "Av1"; case kVideoCodecH264: return "H264"; + case kVideoCodecH265: + return "H265"; case kVideoCodecGeneric: return "Generic"; case kVideoCodecMultiplex: @@ -275,6 +277,8 @@ INSTANTIATE_TEST_SUITE_P( {VideoCodecType::kVideoCodecAV1, false}, {VideoCodecType::kVideoCodecAV1, true}, {VideoCodecType::kVideoCodecH264, false}, - {VideoCodecType::kVideoCodecH264, true}})); + {VideoCodecType::kVideoCodecH264, true}, + {VideoCodecType::kVideoCodecH265, false}, + {VideoCodecType::kVideoCodecH265, true}})); } // namespace webrtc diff --git a/video/end_to_end_tests/multi_stream_tester.cc b/video/end_to_end_tests/multi_stream_tester.cc index 8d99329194..1eb388cc76 100644 --- a/video/end_to_end_tests/multi_stream_tester.cc +++ b/video/end_to_end_tests/multi_stream_tester.cc @@ -14,7 +14,6 @@ #include #include -#include "absl/memory/memory.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/task_queue/default_task_queue_factory.h" #include "api/task_queue/task_queue_base.h" @@ -50,7 +49,7 @@ void MultiStreamTester::RunTest() { // to make test more stable. auto task_queue = task_queue_factory->CreateTaskQueue( "TaskQueue", TaskQueueFactory::Priority::HIGH); - Call::Config config(&event_log); + CallConfig config(&event_log); test::ScopedKeyValueConfig field_trials; config.trials = &field_trials; config.task_queue_factory = task_queue_factory.get(); @@ -69,8 +68,8 @@ void MultiStreamTester::RunTest() { InternalDecoderFactory decoder_factory; SendTask(task_queue.get(), [&]() { - sender_call = absl::WrapUnique(Call::Create(config)); - receiver_call = absl::WrapUnique(Call::Create(config)); + sender_call = Call::Create(config); + receiver_call = Call::Create(config); sender_transport = CreateSendTransport(task_queue.get(), sender_call.get()); receiver_transport = CreateReceiveTransport(task_queue.get(), receiver_call.get()); diff --git a/video/end_to_end_tests/network_state_tests.cc b/video/end_to_end_tests/network_state_tests.cc index 4d43f7609c..7bc9f1493e 100644 --- a/video/end_to_end_tests/network_state_tests.cc +++ b/video/end_to_end_tests/network_state_tests.cc @@ -94,7 +94,7 @@ void NetworkStateEndToEndTest::VerifyNewVideoSendStreamsRespectNetworkState( SendTask(task_queue(), [this, network_to_bring_up, &encoder_factory, transport]() { - CreateSenderCall(Call::Config(send_event_log_.get())); + CreateSenderCall(CallConfig(send_event_log_.get())); sender_call_->SignalChannelNetworkState(network_to_bring_up, kNetworkUp); CreateSendConfig(1, 0, 0, transport); diff --git a/video/end_to_end_tests/stats_tests.cc b/video/end_to_end_tests/stats_tests.cc index 475a6cd2da..cc0b328b2b 100644 --- a/video/end_to_end_tests/stats_tests.cc +++ b/video/end_to_end_tests/stats_tests.cc @@ -518,9 +518,9 @@ TEST_F(StatsEndToEndTest, MAYBE_ContentTypeSwitches) { metrics::Reset(); - Call::Config send_config(send_event_log_.get()); + CallConfig send_config(send_event_log_.get()); test.ModifySenderBitrateConfig(&send_config.bitrate_config); - Call::Config recv_config(recv_event_log_.get()); + CallConfig recv_config(recv_event_log_.get()); test.ModifyReceiverBitrateConfig(&recv_config.bitrate_config); VideoEncoderConfig encoder_config_with_screenshare; diff --git a/video/frame_cadence_adapter.cc b/video/frame_cadence_adapter.cc index ef76038ef0..b09986847b 100644 --- a/video/frame_cadence_adapter.cc +++ b/video/frame_cadence_adapter.cc @@ -31,6 +31,7 @@ #include "rtc_base/rate_statistics.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/system/no_unique_address.h" +#include "rtc_base/system/unused.h" #include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/time_utils.h" @@ -373,13 +374,22 @@ void ZeroHertzAdapterMode::OnFrame(Timestamp post_time, // Store the frame in the queue and schedule deferred processing. queued_frames_.push_back(frame); + int frame_id = current_frame_id_; current_frame_id_++; scheduled_repeat_ = absl::nullopt; TimeDelta time_spent_since_post = clock_->CurrentTime() - post_time; + TRACE_EVENT_ASYNC_BEGIN0(TRACE_DISABLED_BY_DEFAULT("webrtc"), "QueueToEncode", + frame_id); queue_->PostDelayedHighPrecisionTask( SafeTask(safety_.flag(), - [this] { + [this, frame_id, frame] { + RTC_UNUSED(frame_id); RTC_DCHECK_RUN_ON(&sequence_checker_); + TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "QueueToEncode", frame_id); + TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "OnFrameToEncode", + frame.video_frame_buffer().get()); ProcessOnDelayedCadence(); }), std::max(frame_delay_ - time_spent_since_post, TimeDelta::Zero())); @@ -647,8 +657,14 @@ void FrameCadenceAdapterImpl::OnFrame(const VideoFrame& frame) { // Local time in webrtc time base. Timestamp post_time = clock_->CurrentTime(); frames_scheduled_for_processing_.fetch_add(1, std::memory_order_relaxed); + TRACE_EVENT_ASYNC_BEGIN0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "OnFrameToEncode", frame.video_frame_buffer().get()); + TRACE_EVENT_ASYNC_BEGIN0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "OnFrameToQueue", frame.video_frame_buffer().get()); queue_->PostTask(SafeTask(safety_.flag(), [this, post_time, frame] { RTC_DCHECK_RUN_ON(queue_); + TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc"), + "OnFrameToQueue", frame.video_frame_buffer().get()); if (zero_hertz_adapter_created_timestamp_.has_value()) { TimeDelta time_until_first_frame = clock_->CurrentTime() - *zero_hertz_adapter_created_timestamp_; diff --git a/video/frame_encode_metadata_writer.cc b/video/frame_encode_metadata_writer.cc index d6095a090b..e921a93457 100644 --- a/video/frame_encode_metadata_writer.cc +++ b/video/frame_encode_metadata_writer.cc @@ -236,7 +236,7 @@ FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata( // Because some hardware encoders don't preserve capture timestamp we // use RTP timestamps here. while (!metadata_list->empty() && - IsNewerTimestamp(encoded_image->Timestamp(), + IsNewerTimestamp(encoded_image->RtpTimestamp(), metadata_list->front().rtp_timestamp)) { frame_drop_callback_->OnDroppedFrame( EncodedImageCallback::DropReason::kDroppedByEncoder); @@ -249,7 +249,7 @@ FrameEncodeMetadataWriter::ExtractEncodeStartTimeAndFillMetadata( : VideoContentType::UNSPECIFIED; if (!metadata_list->empty() && - metadata_list->front().rtp_timestamp == encoded_image->Timestamp()) { + metadata_list->front().rtp_timestamp == encoded_image->RtpTimestamp()) { result.emplace(metadata_list->front().encode_start_time_ms); encoded_image->capture_time_ms_ = metadata_list->front().timestamp_us / 1000; diff --git a/video/frame_encode_metadata_writer_unittest.cc b/video/frame_encode_metadata_writer_unittest.cc index e151282b77..5106e0e16d 100644 --- a/video/frame_encode_metadata_writer_unittest.cc +++ b/video/frame_encode_metadata_writer_unittest.cc @@ -105,7 +105,7 @@ std::vector> GetTimingFrames( image.SetEncodedData(EncodedImageBuffer::Create(max_frame_size)); image.set_size(FrameSize(min_frame_size, max_frame_size, si, i)); image.capture_time_ms_ = current_timestamp; - image.SetTimestamp(static_cast(current_timestamp * 90)); + image.SetRtpTimestamp(static_cast(current_timestamp * 90)); image.SetSpatialIndex(si); if (dropped) { @@ -198,7 +198,7 @@ TEST(FrameEncodeMetadataWriterTest, NoTimingFrameIfNoEncodeStartTime) { EncodedImage image; image.SetEncodedData(EncodedImageBuffer::Create(kFrameSize)); image.capture_time_ms_ = timestamp; - image.SetTimestamp(static_cast(timestamp * 90)); + image.SetRtpTimestamp(static_cast(timestamp * 90)); FakeEncodedImageCallback sink; FrameEncodeMetadataWriter encode_timer(&sink); @@ -222,7 +222,7 @@ TEST(FrameEncodeMetadataWriterTest, NoTimingFrameIfNoEncodeStartTime) { // New frame, now skip OnEncodeStarted. Should not result in timing frame. image.capture_time_ms_ = ++timestamp; - image.SetTimestamp(static_cast(timestamp * 90)); + image.SetRtpTimestamp(static_cast(timestamp * 90)); image.timing_ = EncodedImage::Timing(); encode_timer.FillTimingInfo(0, &image); EXPECT_FALSE(IsTimingFrame(image)); @@ -250,7 +250,7 @@ TEST(FrameEncodeMetadataWriterTest, NotifiesAboutDroppedFrames) { .build(); image.capture_time_ms_ = kTimestampMs1; - image.SetTimestamp(static_cast(image.capture_time_ms_ * 90)); + image.SetRtpTimestamp(static_cast(image.capture_time_ms_ * 90)); frame.set_timestamp(image.capture_time_ms_ * 90); frame.set_timestamp_us(image.capture_time_ms_ * 1000); encode_timer.OnEncodeStarted(frame); @@ -259,7 +259,7 @@ TEST(FrameEncodeMetadataWriterTest, NotifiesAboutDroppedFrames) { encode_timer.FillTimingInfo(0, &image); image.capture_time_ms_ = kTimestampMs2; - image.SetTimestamp(static_cast(image.capture_time_ms_ * 90)); + image.SetRtpTimestamp(static_cast(image.capture_time_ms_ * 90)); image.timing_ = EncodedImage::Timing(); frame.set_timestamp(image.capture_time_ms_ * 90); frame.set_timestamp_us(image.capture_time_ms_ * 1000); @@ -269,7 +269,7 @@ TEST(FrameEncodeMetadataWriterTest, NotifiesAboutDroppedFrames) { EXPECT_EQ(0u, sink.GetNumFramesDropped()); image.capture_time_ms_ = kTimestampMs3; - image.SetTimestamp(static_cast(image.capture_time_ms_ * 90)); + image.SetRtpTimestamp(static_cast(image.capture_time_ms_ * 90)); image.timing_ = EncodedImage::Timing(); frame.set_timestamp(image.capture_time_ms_ * 90); frame.set_timestamp_us(image.capture_time_ms_ * 1000); @@ -278,7 +278,7 @@ TEST(FrameEncodeMetadataWriterTest, NotifiesAboutDroppedFrames) { EXPECT_EQ(1u, sink.GetNumFramesDropped()); image.capture_time_ms_ = kTimestampMs4; - image.SetTimestamp(static_cast(image.capture_time_ms_ * 90)); + image.SetRtpTimestamp(static_cast(image.capture_time_ms_ * 90)); image.timing_ = EncodedImage::Timing(); frame.set_timestamp(image.capture_time_ms_ * 90); frame.set_timestamp_us(image.capture_time_ms_ * 1000); @@ -300,7 +300,7 @@ TEST(FrameEncodeMetadataWriterTest, RestoresCaptureTimestamps) { encode_timer.OnSetRates(bitrate_allocation, 30); image.capture_time_ms_ = kTimestampMs; // Correct timestamp. - image.SetTimestamp(static_cast(image.capture_time_ms_ * 90)); + image.SetRtpTimestamp(static_cast(image.capture_time_ms_ * 90)); VideoFrame frame = VideoFrame::Builder() .set_timestamp_ms(image.capture_time_ms_) .set_timestamp_rtp(image.capture_time_ms_ * 90) @@ -324,7 +324,7 @@ TEST(FrameEncodeMetadataWriterTest, CopiesRotation) { bitrate_allocation.SetBitrate(0, 0, 500000); encode_timer.OnSetRates(bitrate_allocation, 30); - image.SetTimestamp(static_cast(kTimestampMs * 90)); + image.SetRtpTimestamp(static_cast(kTimestampMs * 90)); VideoFrame frame = VideoFrame::Builder() .set_timestamp_ms(kTimestampMs) .set_timestamp_rtp(kTimestampMs * 90) @@ -350,7 +350,7 @@ TEST(FrameEncodeMetadataWriterTest, SetsContentType) { bitrate_allocation.SetBitrate(0, 0, 500000); encode_timer.OnSetRates(bitrate_allocation, 30); - image.SetTimestamp(static_cast(kTimestampMs * 90)); + image.SetRtpTimestamp(static_cast(kTimestampMs * 90)); VideoFrame frame = VideoFrame::Builder() .set_timestamp_ms(kTimestampMs) .set_timestamp_rtp(kTimestampMs * 90) @@ -376,7 +376,7 @@ TEST(FrameEncodeMetadataWriterTest, CopiesColorSpace) { webrtc::ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/true); - image.SetTimestamp(static_cast(kTimestampMs * 90)); + image.SetRtpTimestamp(static_cast(kTimestampMs * 90)); VideoFrame frame = VideoFrame::Builder() .set_timestamp_ms(kTimestampMs) .set_timestamp_rtp(kTimestampMs * 90) @@ -402,7 +402,7 @@ TEST(FrameEncodeMetadataWriterTest, CopiesPacketInfos) { encode_timer.OnSetRates(bitrate_allocation, 30); RtpPacketInfos packet_infos = CreatePacketInfos(3); - image.SetTimestamp(static_cast(kTimestampMs * 90)); + image.SetRtpTimestamp(static_cast(kTimestampMs * 90)); VideoFrame frame = VideoFrame::Builder() .set_timestamp_ms(kTimestampMs) .set_timestamp_rtp(kTimestampMs * 90) diff --git a/video/pc_full_stack_tests.cc b/video/pc_full_stack_tests.cc index 83b06830e0..d7e7a4b3f5 100644 --- a/video/pc_full_stack_tests.cc +++ b/video/pc_full_stack_tests.cc @@ -182,9 +182,7 @@ TEST(PCGenericDescriptorTest, } // VP9 2nd profile isn't supported on android arm and arm 64. -#if (defined(WEBRTC_ANDROID) && \ - (defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM))) || \ - (defined(WEBRTC_IOS) && defined(WEBRTC_ARCH_ARM64)) +#if defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) #define MAYBE_Pc_Generator_Net_Delay_0_0_Plr_0_VP9Profile2 \ DISABLED_Pc_Generator_Net_Delay_0_0_Plr_0_VP9Profile2 #else diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc index 70c11e5868..9a38097a93 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -562,7 +562,13 @@ void RtpVideoStreamReceiver2::OnReceivedPayloadData( // Assume frequency is the same one for all video frames. kVideoPayloadTypeFrequency, rtp_packet.GetExtension())); - + if (packet_info.absolute_capture_time().has_value()) { + packet_info.set_local_capture_clock_offset( + capture_clock_offset_updater_.ConvertsToTimeDela( + capture_clock_offset_updater_.AdjustEstimatedCaptureClockOffset( + packet_info.absolute_capture_time() + ->estimated_capture_clock_offset))); + } RTPVideoHeader& video_header = packet->video_header; video_header.rotation = kVideoRotation_0; video_header.content_type = VideoContentType::UNSPECIFIED; @@ -875,7 +881,7 @@ void RtpVideoStreamReceiver2::OnAssembledFrame( // Reset `reference_finder_` if `frame` is new and the codec have changed. if (current_codec_) { bool frame_is_newer = - AheadOf(frame->Timestamp(), last_assembled_frame_rtp_timestamp_); + AheadOf(frame->RtpTimestamp(), last_assembled_frame_rtp_timestamp_); if (frame->codec_type() != current_codec_) { if (frame_is_newer) { @@ -893,11 +899,11 @@ void RtpVideoStreamReceiver2::OnAssembledFrame( } if (frame_is_newer) { - last_assembled_frame_rtp_timestamp_ = frame->Timestamp(); + last_assembled_frame_rtp_timestamp_ = frame->RtpTimestamp(); } } else { current_codec_ = frame->codec_type(); - last_assembled_frame_rtp_timestamp_ = frame->Timestamp(); + last_assembled_frame_rtp_timestamp_ = frame->RtpTimestamp(); } if (buffered_frame_decryptor_ != nullptr) { diff --git a/video/screenshare_loopback.cc b/video/screenshare_loopback.cc index 239e472f6e..40bf9ee496 100644 --- a/video/screenshare_loopback.cc +++ b/video/screenshare_loopback.cc @@ -28,6 +28,7 @@ #include "test/field_trial.h" #include "test/gtest.h" #include "test/run_test.h" +#include "test/test_flags.h" #include "video/video_quality_test.h" using ::webrtc::BitrateConstraints; @@ -256,15 +257,6 @@ ABSL_FLAG(bool, generic_descriptor, false, "Use the generic frame descriptor."); ABSL_FLAG(bool, allow_reordering, false, "Allow packet reordering to occur"); -ABSL_FLAG( - std::string, - force_fieldtrials, - "", - "Field trials control experimental feature code which can be forced. " - "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/" - " will assign the group Enable to field trial WebRTC-FooFeature. Multiple " - "trials are separated by \"/\""); - // Screenshare-specific flags. ABSL_FLAG(int, min_transmit_bitrate, diff --git a/video/send_delay_stats.h b/video/send_delay_stats.h index f5781bba02..ac224279ba 100644 --- a/video/send_delay_stats.h +++ b/video/send_delay_stats.h @@ -32,10 +32,10 @@ namespace webrtc { // TODO(bugs.webrtc.org/11993): OnSendPacket and OnSentPacket will eventually // be called consistently on the same thread. Once we're there, we should be // able to avoid locking (at least for the fast path). -class SendDelayStats : public SendPacketObserver { +class SendDelayStats { public: explicit SendDelayStats(Clock* clock); - ~SendDelayStats() override; + ~SendDelayStats(); // Adds the configured ssrcs for the rtp streams. // Stats will be calculated for these streams. @@ -44,12 +44,8 @@ class SendDelayStats : public SendPacketObserver { // Called when a packet is sent (leaving socket). bool OnSentPacket(int packet_id, Timestamp time); - protected: - // From SendPacketObserver. // Called when a packet is sent to the transport. - void OnSendPacket(uint16_t packet_id, - Timestamp capture_time, - uint32_t ssrc) override; + void OnSendPacket(uint16_t packet_id, Timestamp capture_time, uint32_t ssrc); private: // Map holding sent packets (mapped by sequence number). diff --git a/video/send_delay_stats_unittest.cc b/video/send_delay_stats_unittest.cc index 288bc5fd8d..e23467e71c 100644 --- a/video/send_delay_stats_unittest.cc +++ b/video/send_delay_stats_unittest.cc @@ -11,6 +11,7 @@ #include "video/send_delay_stats.h" #include +#include #include #include "call/rtp_config.h" @@ -54,8 +55,7 @@ class SendDelayStatsTest : public ::testing::Test { } void OnSendPacket(uint16_t id, uint32_t ssrc, Timestamp capture) { - SendPacketObserver* observer = stats_.get(); - observer->OnSendPacket(id, capture, ssrc); + stats_->OnSendPacket(id, capture, ssrc); } bool OnSentPacket(uint16_t id) { diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc index b857c0535b..f8ba31beff 100644 --- a/video/send_statistics_proxy.cc +++ b/video/send_statistics_proxy.cc @@ -47,6 +47,7 @@ enum HistogramCodecType { kVideoVp9 = 2, kVideoH264 = 3, kVideoAv1 = 4, + kVideoH265 = 5, kVideoMax = 64, }; @@ -76,6 +77,8 @@ HistogramCodecType PayloadNameToHistogramCodecType( return kVideoH264; case kVideoCodecAV1: return kVideoAv1; + case kVideoCodecH265: + return kVideoH265; default: return kVideoUnknown; } @@ -129,8 +132,6 @@ absl::optional GetFallbackMaxPixelsIfFieldTrialDisabled( } } // namespace -const int SendStatisticsProxy::kStatsTimeoutMs = 5000; - SendStatisticsProxy::SendStatisticsProxy( Clock* clock, const VideoSendStream::Config& config, @@ -172,6 +173,9 @@ SendStatisticsProxy::~SendStatisticsProxy() { SendStatisticsProxy::FallbackEncoderInfo::FallbackEncoderInfo() = default; +SendStatisticsProxy::Trackers::Trackers() + : encoded_frame_rate(kBucketSizeMs, kBucketCount) {} + SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( const char* prefix, const VideoSendStream::Stats& stats, @@ -267,7 +271,7 @@ bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame( // Check for jump in timestamp. if (!encoded_frames_.empty()) { uint32_t oldest_timestamp = encoded_frames_.begin()->first; - if (ForwardDiff(oldest_timestamp, encoded_frame.Timestamp()) > + if (ForwardDiff(oldest_timestamp, encoded_frame.RtpTimestamp()) > kMaxEncodedFrameTimestampDiff) { // Gap detected, clear frames to have a sequence where newest timestamp // is not too far away from oldest in order to distinguish old and new. @@ -275,11 +279,11 @@ bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame( } } - auto it = encoded_frames_.find(encoded_frame.Timestamp()); + auto it = encoded_frames_.find(encoded_frame.RtpTimestamp()); if (it == encoded_frames_.end()) { // First frame with this timestamp. encoded_frames_.insert( - std::make_pair(encoded_frame.Timestamp(), + std::make_pair(encoded_frame.RtpTimestamp(), Frame(now_ms, encoded_frame._encodedWidth, encoded_frame._encodedHeight, simulcast_idx))); sent_fps_counter_.Add(1); @@ -753,25 +757,20 @@ VideoSendStream::Stats SendStatisticsProxy::GetStats() { stats_.quality_limitation_durations_ms = quality_limitation_reason_tracker_.DurationsMs(); - for (auto& substream : stats_.substreams) { - uint32_t ssrc = substream.first; - if (encoded_frame_rate_trackers_.count(ssrc) > 0) { - substream.second.encode_frame_rate = - encoded_frame_rate_trackers_[ssrc]->ComputeRate(); + for (auto& [ssrc, substream] : stats_.substreams) { + if (auto it = trackers_.find(ssrc); it != trackers_.end()) { + substream.encode_frame_rate = it->second.encoded_frame_rate.ComputeRate(); } } return stats_; } void SendStatisticsProxy::PurgeOldStats() { - int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs; - for (std::map::iterator it = - stats_.substreams.begin(); - it != stats_.substreams.end(); ++it) { - uint32_t ssrc = it->first; - if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) { - it->second.width = 0; - it->second.height = 0; + Timestamp now = clock_->CurrentTime(); + for (auto& [ssrc, substream] : stats_.substreams) { + if (now - trackers_[ssrc].resolution_update >= kStatsTimeout) { + substream.width = 0; + substream.height = 0; } } } @@ -969,10 +968,7 @@ void SendStatisticsProxy::OnSendEncodedImage( if (!stats) return; - if (encoded_frame_rate_trackers_.count(ssrc) == 0) { - encoded_frame_rate_trackers_[ssrc] = - std::make_unique(kBucketSizeMs, kBucketCount); - } + Trackers& track = trackers_[ssrc]; stats->frames_encoded++; stats->total_encode_time_ms += encoded_image.timing_.encode_finish_ms - @@ -986,7 +982,7 @@ void SendStatisticsProxy::OnSendEncodedImage( if (!stats->width || !stats->height || is_top_spatial_layer) { stats->width = encoded_image._encodedWidth; stats->height = encoded_image._encodedHeight; - update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds(); + track.resolution_update = clock_->CurrentTime(); } uma_container_->key_frame_counter_.Add(encoded_image._frameType == @@ -1036,8 +1032,9 @@ void SendStatisticsProxy::OnSendEncodedImage( } // is_top_spatial_layer pertains only to SVC, will always be true for // simulcast. - if (is_top_spatial_layer) - encoded_frame_rate_trackers_[ssrc]->AddSamples(1); + if (is_top_spatial_layer) { + track.encoded_frame_rate.AddSamples(1); + } absl::optional downscales = adaptation_limitations_.MaskedQualityCounts().resolution_adaptations; @@ -1388,13 +1385,52 @@ void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts, stats->frame_counts = frame_counts; } -void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms, - int max_delay_ms, - uint32_t ssrc) { +void SendStatisticsProxy::Trackers::AddSendDelay(Timestamp now, + TimeDelta send_delay) { + // Add the new measurement. + send_delays.push_back({.when = now, .send_delay = send_delay}); + send_delay_sum += send_delay; + if (send_delay_max == nullptr || *send_delay_max <= send_delay) { + send_delay_max = &send_delays.back().send_delay; + } + + // Remove old. No need to check for emptiness because newly added entry would + // never be too old. + while (now - send_delays.front().when > TimeDelta::Seconds(1)) { + send_delay_sum -= send_delays.front().send_delay; + if (send_delay_max == &send_delays.front().send_delay) { + send_delay_max = nullptr; + } + send_delays.pop_front(); + } + + // Check if max value was pushed out from the queue as too old. + if (send_delay_max == nullptr) { + send_delay_max = &send_delays.front().send_delay; + for (const SendDelayEntry& entry : send_delays) { + // Use '>=' rather than '>' to prefer latest maximum as it would be pushed + // out later and thus trigger less recalculations. + if (entry.send_delay >= *send_delay_max) { + send_delay_max = &entry.send_delay; + } + } + } +} + +void SendStatisticsProxy::OnSendPacket(uint32_t ssrc, Timestamp capture_time) { + Timestamp now = clock_->CurrentTime(); + MutexLock lock(&mutex_); VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); if (!stats) return; + + Trackers& track = trackers_[ssrc]; + track.AddSendDelay(now, now - capture_time); + + int64_t avg_delay_ms = (track.send_delay_sum / track.send_delays.size()).ms(); + int64_t max_delay_ms = track.send_delay_max->ms(); + stats->avg_delay_ms = avg_delay_ms; stats->max_delay_ms = max_delay_ms; diff --git a/video/send_statistics_proxy.h b/video/send_statistics_proxy.h index 4203b1c873..e9ac24391e 100644 --- a/video/send_statistics_proxy.h +++ b/video/send_statistics_proxy.h @@ -12,6 +12,7 @@ #define VIDEO_SEND_STATISTICS_PROXY_H_ #include +#include #include #include #include @@ -42,10 +43,9 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, public RtcpPacketTypeCounterObserver, public StreamDataCountersCallback, public BitrateStatisticsObserver, - public FrameCountObserver, - public SendSideDelayObserver { + public FrameCountObserver { public: - static const int kStatsTimeoutMs; + static constexpr TimeDelta kStatsTimeout = TimeDelta::Seconds(5); // Number of required samples to be collected before a metric is added // to a rtc histogram. static const int kMinRequiredMetricsSamples = 200; @@ -103,6 +103,8 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, void OnEncodedFrameTimeMeasured(int encode_time_ms, int encode_usage_percent) override; + void OnSendPacket(uint32_t ssrc, Timestamp capture_time); + int GetInputFrameRate() const override; int GetSendFrameRate() const; @@ -126,11 +128,6 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, void FrameCountUpdated(const FrameCounts& frame_counts, uint32_t ssrc) override; - // From SendSideDelayObserver. - void SendSideDelayUpdated(int avg_delay_ms, - int max_delay_ms, - uint32_t ssrc) override; - private: class SampleCounter { public: @@ -157,11 +154,6 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, int64_t sum; int64_t num_samples; }; - struct StatsUpdateTimes { - StatsUpdateTimes() : resolution_update_ms(0), bitrate_update_ms(0) {} - int64_t resolution_update_ms; - int64_t bitrate_update_ms; - }; struct TargetRateUpdates { TargetRateUpdates() : pause_resume_events(0), last_paused_or_resumed(false), last_ms(-1) {} @@ -253,6 +245,31 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, MaskedAdaptationCounts Mask(const VideoAdaptationCounters& counters, const AdaptationSettings& settings) const; }; + // Collection of various stats that are tracked per ssrc. + struct Trackers { + struct SendDelayEntry { + Timestamp when; + TimeDelta send_delay; + }; + + Trackers(); + Trackers(const Trackers&) = delete; + Trackers& operator=(const Trackers&) = delete; + + void AddSendDelay(Timestamp now, TimeDelta send_delay); + + Timestamp resolution_update = Timestamp::MinusInfinity(); + rtc::RateTracker encoded_frame_rate; + + std::deque send_delays; + + // The sum of `send_delay` in `send_delays`. + TimeDelta send_delay_sum = TimeDelta::Zero(); + + // Pointer to the maximum `send_delay` in `send_delays` or nullptr if + // `send_delays.empty()` + const TimeDelta* send_delay_max = nullptr; + }; void SetAdaptTimer(const MaskedAdaptationCounts& counts, StatsTimer* timer) RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); @@ -280,15 +297,13 @@ class SendStatisticsProxy : public VideoStreamEncoderObserver, VideoEncoderConfig::ContentType content_type_ RTC_GUARDED_BY(mutex_); const int64_t start_ms_; VideoSendStream::Stats stats_ RTC_GUARDED_BY(mutex_); - std::map update_times_ RTC_GUARDED_BY(mutex_); rtc::ExpFilter encode_time_ RTC_GUARDED_BY(mutex_); QualityLimitationReasonTracker quality_limitation_reason_tracker_ RTC_GUARDED_BY(mutex_); rtc::RateTracker media_byte_rate_tracker_ RTC_GUARDED_BY(mutex_); rtc::RateTracker encoded_frame_rate_tracker_ RTC_GUARDED_BY(mutex_); - // Rate trackers mapped by ssrc. - std::map> - encoded_frame_rate_trackers_ RTC_GUARDED_BY(mutex_); + // Trackers mapped by ssrc. + std::map trackers_ RTC_GUARDED_BY(mutex_); absl::optional last_outlier_timestamp_ RTC_GUARDED_BY(mutex_); diff --git a/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc index 9db774145e..f743299060 100644 --- a/video/send_statistics_proxy_unittest.cc +++ b/video/send_statistics_proxy_unittest.cc @@ -69,7 +69,7 @@ class SendStatisticsProxyTest : public ::testing::Test { SendStatisticsProxyTest() : SendStatisticsProxyTest("") {} explicit SendStatisticsProxyTest(const std::string& field_trials) : override_field_trials_(field_trials), - fake_clock_(1234), + fake_clock_(Timestamp::Seconds(1234)), config_(GetTestConfig()) {} virtual ~SendStatisticsProxyTest() {} @@ -320,24 +320,29 @@ TEST_F(SendStatisticsProxyTest, Bitrate) { } TEST_F(SendStatisticsProxyTest, SendSideDelay) { - SendSideDelayObserver* observer = statistics_proxy_.get(); - for (const auto& ssrc : config_.rtp.ssrcs) { + for (uint32_t ssrc : config_.rtp.ssrcs) { // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each // stream. - int avg_delay_ms = ssrc; - int max_delay_ms = ssrc + 1; - observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc); - expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms; - expected_.substreams[ssrc].max_delay_ms = max_delay_ms; + expected_.substreams[ssrc].avg_delay_ms = ssrc; + expected_.substreams[ssrc].max_delay_ms = ssrc + 1; + statistics_proxy_->OnSendPacket(ssrc, + /*capture_time=*/fake_clock_.CurrentTime() - + TimeDelta::Millis(ssrc + 1)); + statistics_proxy_->OnSendPacket(ssrc, + /*capture_time=*/fake_clock_.CurrentTime() - + TimeDelta::Millis(ssrc - 1)); } - for (const auto& ssrc : config_.rtp.rtx.ssrcs) { + for (uint32_t ssrc : config_.rtp.rtx.ssrcs) { // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each // stream. - int avg_delay_ms = ssrc; - int max_delay_ms = ssrc + 1; - observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc); - expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms; - expected_.substreams[ssrc].max_delay_ms = max_delay_ms; + expected_.substreams[ssrc].avg_delay_ms = ssrc; + expected_.substreams[ssrc].max_delay_ms = ssrc + 1; + statistics_proxy_->OnSendPacket(ssrc, + /*capture_time=*/fake_clock_.CurrentTime() - + TimeDelta::Millis(ssrc + 1)); + statistics_proxy_->OnSendPacket(ssrc, + /*capture_time=*/fake_clock_.CurrentTime() - + TimeDelta::Millis(ssrc - 1)); } VideoSendStream::Stats stats = statistics_proxy_->GetStats(); ExpectEqual(expected_, stats); @@ -466,8 +471,8 @@ TEST_F(SendStatisticsProxyTest, fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs); fake_global_clock.SetTime( Timestamp::Millis(fake_clock_.TimeInMilliseconds())); - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); auto stats = statistics_proxy_->GetStats(); @@ -493,8 +498,8 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStream) { fake_global_clock.SetTime( Timestamp::Millis(fake_clock_.TimeInMilliseconds())); // Second frame - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs); fake_global_clock.SetTime( @@ -514,8 +519,8 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp8Simulcast) { codec_info.codecType = kVideoCodecVP8; for (int i = 0; i < 10; ++i) { - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); encoded_image.SetSimulcastIndex(0); statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info); encoded_image.SetSimulcastIndex(1); @@ -532,8 +537,8 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp8Simulcast) { // Stop encoding second stream, expect framerate to be zero. for (int i = 0; i < 10; ++i) { - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); encoded_image.SetSimulcastIndex(0); statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info); fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs); @@ -548,8 +553,8 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp8Simulcast) { // Start encoding second stream. for (int i = 0; i < 10; ++i) { - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); encoded_image.SetSimulcastIndex(0); statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info); encoded_image.SetSimulcastIndex(1); @@ -575,8 +580,8 @@ TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp9Svc) { codec_info.codecType = kVideoCodecVP9; for (int i = 0; i < 10; ++i) { - encoded_image.SetTimestamp(encoded_image.Timestamp() + - 90 * kInterframeDelayMs); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * kInterframeDelayMs); encoded_image.SetSpatialIndex(0); codec_info.end_of_picture = false; statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info); @@ -1648,7 +1653,8 @@ TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) { // Not enough samples, stats should not be updated. for (int i = 0; i < kMinSamples - 1; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * 1000 / kFps); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); } SetUp(); // Reset stats proxy also causes histograms to be reported. @@ -1656,10 +1662,11 @@ TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) { EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.SentHeightInPixels")); // Enough samples, max resolution per frame should be reported. - encoded_image.SetTimestamp(0xffff0000); // Will wrap. + encoded_image.SetRtpTimestamp(0xffff0000); // Will wrap. for (int i = 0; i < kMinSamples; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + 90 * 1000 / kFps); encoded_image._encodedWidth = kWidth; encoded_image._encodedHeight = kHeight; statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); @@ -1698,7 +1705,7 @@ TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) { int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1; for (int i = 0; i < frames; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + 1); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + 1); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); // Frame with same timestamp should not be counted. statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); @@ -1741,7 +1748,7 @@ TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) { int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000; for (int i = 0; i < frames; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(i + 1); + encoded_image.SetRtpTimestamp(i + 1); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); } // Suspend. @@ -1750,7 +1757,7 @@ TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) { for (int i = 0; i < frames; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(i + 1); + encoded_image.SetRtpTimestamp(i + 1); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); } // Suspended time interval should not affect the framerate. @@ -2062,8 +2069,8 @@ TEST_F(SendStatisticsProxyTest, encoded_image._encodedHeight = kHeight; for (int i = 0; i < kMinSamples; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + - (kRtpClockRateHz / kFps)); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + (kRtpClockRateHz / kFps)); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); } @@ -2098,8 +2105,8 @@ TEST_F(SendStatisticsProxyTest, EncodedImage encoded_image; for (int i = 0; i < kMinSamples; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + - (kRtpClockRateHz / kFps)); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + (kRtpClockRateHz / kFps)); encoded_image._encodedWidth = kWidth; encoded_image._encodedHeight = kHeight; statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); @@ -2145,8 +2152,8 @@ TEST_F(SendStatisticsProxyTest, encoded_image._encodedHeight = kHeight / 2; for (int i = 0; i < kMinSamples; ++i) { fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); - encoded_image.SetTimestamp(encoded_image.Timestamp() + - (kRtpClockRateHz / kFps)); + encoded_image.SetRtpTimestamp(encoded_image.RtpTimestamp() + + (kRtpClockRateHz / kFps)); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); } @@ -2353,7 +2360,8 @@ TEST_F(SendStatisticsProxyTest, EncodedResolutionTimesOut) { EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height); // Forward almost to timeout, this should not have removed stats. - fake_clock_.AdvanceTimeMilliseconds(SendStatisticsProxy::kStatsTimeoutMs - 1); + fake_clock_.AdvanceTime(SendStatisticsProxy::kStatsTimeout - + TimeDelta::Millis(1)); stats = statistics_proxy_->GetStats(); EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width); EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height); diff --git a/video/sv_loopback.cc b/video/sv_loopback.cc index af475ae4eb..2a8f9743e8 100644 --- a/video/sv_loopback.cc +++ b/video/sv_loopback.cc @@ -28,6 +28,7 @@ #include "test/field_trial.h" #include "test/gtest.h" #include "test/run_test.h" +#include "test/test_flags.h" #include "video/video_quality_test.h" // Flags for video. @@ -311,15 +312,6 @@ ABSL_FLAG(bool, ABSL_FLAG(bool, video, true, "Add video stream"); -ABSL_FLAG( - std::string, - force_fieldtrials, - "", - "Field trials control experimental feature code which can be forced. " - "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/" - " will assign the group Enable to field trial WebRTC-FooFeature. Multiple " - "trials are separated by \"/\""); - // Video-specific flags. ABSL_FLAG(std::string, vclip, diff --git a/video/video_loopback.cc b/video/video_loopback.cc index ba0a0e5745..b02184a685 100644 --- a/video/video_loopback.cc +++ b/video/video_loopback.cc @@ -28,6 +28,7 @@ #include "test/field_trial.h" #include "test/gtest.h" #include "test/run_test.h" +#include "test/test_flags.h" #include "video/video_quality_test.h" // Flags common with screenshare loopback, with different default values. @@ -199,15 +200,6 @@ ABSL_FLAG(bool, ABSL_FLAG(bool, video, true, "Add video stream"); -ABSL_FLAG( - std::string, - force_fieldtrials, - "", - "Field trials control experimental feature code which can be forced. " - "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enabled/" - " will assign the group Enable to field trial WebRTC-FooFeature. Multiple " - "trials are separated by \"/\""); - // Video-specific flags. ABSL_FLAG(std::string, clip, diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc index 010e2ed325..971c129329 100644 --- a/video/video_quality_test.cc +++ b/video/video_quality_test.cc @@ -48,6 +48,7 @@ #include "rtc_base/strings/string_builder.h" #include "rtc_base/task_queue_for_test.h" #include "test/platform_video_capturer.h" +#include "test/test_flags.h" #include "test/testsupport/file_utils.h" #include "test/video_renderer.h" #include "video/frame_dumping_decoder.h" @@ -76,8 +77,6 @@ constexpr int kFramesSentInQuickTest = 1; constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000; constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000; -constexpr int kDefaultMaxQp = cricket::WebRtcVideoSendChannel::kDefaultQpMax; - const VideoEncoder::Capabilities kCapabilities(false); std::pair GetMinMaxBitratesBps(const VideoCodec& codec, @@ -246,7 +245,7 @@ class QualityTestVideoEncoder : public VideoEncoder, RTC_DCHECK_GE(simulcast_index, 0); if (analyzer_) { analyzer_->PostEncodeOnFrame(simulcast_index, - encoded_image.Timestamp()); + encoded_image.RtpTimestamp()); } if (static_cast(simulcast_index) < writers_.size()) { writers_[simulcast_index]->WriteFrame(encoded_image, @@ -578,7 +577,7 @@ VideoStream VideoQualityTest::DefaultVideoStream(const Params& params, stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps; stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps; stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps; - stream.max_qp = kDefaultMaxQp; + stream.max_qp = cricket::kDefaultVideoMaxQpVpx; stream.num_temporal_layers = params.video[video_idx].num_temporal_layers; stream.active = true; return stream; @@ -593,7 +592,7 @@ VideoStream VideoQualityTest::DefaultThumbnailStream() { stream.min_bitrate_bps = 7500; stream.target_bitrate_bps = 37500; stream.max_bitrate_bps = 50000; - stream.max_qp = kDefaultMaxQp; + stream.max_qp = cricket::kDefaultVideoMaxQpVpx; return stream; } @@ -626,7 +625,7 @@ void VideoQualityTest::FillScalabilitySettings( encoder_config.simulcast_layers = std::vector(num_streams); encoder_config.video_stream_factory = rtc::make_ref_counted( - params->video[video_idx].codec, kDefaultMaxQp, + params->video[video_idx].codec, cricket::kDefaultVideoMaxQpVpx, params->screenshare[video_idx].enabled, true, encoder_info); params->ss[video_idx].streams = encoder_config.video_stream_factory->CreateEncoderStreams( @@ -1246,8 +1245,8 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { } SendTask(task_queue(), [this, ¶ms, &send_transport, &recv_transport]() { - Call::Config send_call_config(send_event_log_.get()); - Call::Config recv_call_config(recv_event_log_.get()); + CallConfig send_call_config(send_event_log_.get()); + CallConfig recv_call_config(recv_event_log_.get()); send_call_config.bitrate_config = params.call.call_bitrate_config; recv_call_config.bitrate_config = params.call.call_bitrate_config; if (params_.audio.enabled) @@ -1262,7 +1261,7 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { std::string graph_title = params_.analyzer.graph_title; if (graph_title.empty()) graph_title = VideoQualityTest::GenerateGraphTitle(); - bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest"); + bool is_quick_test_enabled = absl::GetFlag(FLAGS_webrtc_quick_perf_test); analyzer_ = std::make_unique( send_transport.get(), params_.analyzer.test_label, params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold, @@ -1365,8 +1364,8 @@ rtc::scoped_refptr VideoQualityTest::CreateAudioDevice() { #endif } -void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config, - Call::Config* recv_call_config, +void VideoQualityTest::InitializeAudioDevice(CallConfig* send_call_config, + CallConfig* recv_call_config, bool use_real_adm) { rtc::scoped_refptr audio_device; if (use_real_adm) { @@ -1472,11 +1471,11 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { params_ = params; CheckParamsAndInjectionComponents(); - // TODO(ivica): Remove bitrate_config and use the default Call::Config(), to + // TODO(ivica): Remove bitrate_config and use the default CallConfig(), to // match the full stack tests. - Call::Config send_call_config(send_event_log_.get()); + CallConfig send_call_config(send_event_log_.get()); send_call_config.bitrate_config = params_.call.call_bitrate_config; - Call::Config recv_call_config(recv_event_log_.get()); + CallConfig recv_call_config(recv_event_log_.get()); if (params_.audio.enabled) InitializeAudioDevice(&send_call_config, &recv_call_config, diff --git a/video/video_quality_test.h b/video/video_quality_test.h index f66256e94c..63fa4813f0 100644 --- a/video/video_quality_test.h +++ b/video/video_quality_test.h @@ -90,8 +90,8 @@ class VideoQualityTest : public test::CallTest, void DestroyThumbnailStreams(); // Helper method for creating a real ADM (using hardware) for all platforms. rtc::scoped_refptr CreateAudioDevice(); - void InitializeAudioDevice(Call::Config* send_call_config, - Call::Config* recv_call_config, + void InitializeAudioDevice(CallConfig* send_call_config, + CallConfig* recv_call_config, bool use_real_adm); void SetupAudio(Transport* transport); diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc index 9111c3e6ed..b99b08eefb 100644 --- a/video/video_send_stream.cc +++ b/video/video_send_stream.cc @@ -91,7 +91,7 @@ RtpSenderFrameEncryptionConfig CreateFrameEncryptionConfig( RtpSenderObservers CreateObservers(RtcpRttStats* call_stats, EncoderRtcpFeedback* encoder_feedback, SendStatisticsProxy* stats_proxy, - SendDelayStats* send_delay_stats) { + SendPacketObserver* send_packet_observer) { RtpSenderObservers observers; observers.rtcp_rtt_stats = call_stats; observers.intra_frame_callback = encoder_feedback; @@ -101,8 +101,7 @@ RtpSenderObservers CreateObservers(RtcpRttStats* call_stats, observers.bitrate_observer = stats_proxy; observers.frame_count_observer = stats_proxy; observers.rtcp_type_observer = stats_proxy; - observers.send_delay_observer = stats_proxy; - observers.send_packet_observer = send_delay_stats; + observers.send_packet_observer = send_packet_observer; return observers; } @@ -151,6 +150,7 @@ VideoSendStream::VideoSendStream( const FieldTrialsView& field_trials) : transport_(transport), stats_proxy_(clock, config, encoder_config.content_type, field_trials), + send_packet_observer_(&stats_proxy_, send_delay_stats), config_(std::move(config)), content_type_(encoder_config.content_type), video_stream_encoder_(CreateVideoStreamEncoder( @@ -169,20 +169,20 @@ VideoSendStream::VideoSendStream( [this](uint32_t ssrc, const std::vector& seq_nums) { return rtp_video_sender_->GetSentRtpPacketInfos(ssrc, seq_nums); }), - rtp_video_sender_( - transport->CreateRtpVideoSender(suspended_ssrcs, - suspended_payload_states, - config_.rtp, - config_.rtcp_report_interval_ms, - config_.send_transport, - CreateObservers(call_stats, - &encoder_feedback_, - &stats_proxy_, - send_delay_stats), - event_log, - std::move(fec_controller), - CreateFrameEncryptionConfig(&config_), - config_.frame_transformer)), + rtp_video_sender_(transport->CreateRtpVideoSender( + suspended_ssrcs, + suspended_payload_states, + config_.rtp, + config_.rtcp_report_interval_ms, + config_.send_transport, + CreateObservers(call_stats, + &encoder_feedback_, + &stats_proxy_, + &send_packet_observer_), + event_log, + std::move(fec_controller), + CreateFrameEncryptionConfig(&config_), + config_.frame_transformer)), send_stream_(clock, &stats_proxy_, transport, @@ -281,6 +281,8 @@ void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config, SetParametersCallback callback) { RTC_DCHECK_RUN_ON(&thread_checker_); RTC_DCHECK_EQ(content_type_, config.content_type); + RTC_LOG(LS_VERBOSE) << "Encoder config: " << config.ToString() + << " VideoSendStream config: " << config_.ToString(); video_stream_encoder_->ConfigureEncoder( std::move(config), config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp), diff --git a/video/video_send_stream.h b/video/video_send_stream.h index 1f4717fbec..05970d619e 100644 --- a/video/video_send_stream.h +++ b/video/video_send_stream.h @@ -99,6 +99,25 @@ class VideoSendStream : public webrtc::VideoSendStream { private: friend class test::VideoSendStreamPeer; + class OnSendPacketObserver : public SendPacketObserver { + public: + OnSendPacketObserver(SendStatisticsProxy* stats_proxy, + SendDelayStats* send_delay_stats) + : stats_proxy_(*stats_proxy), send_delay_stats_(*send_delay_stats) {} + + void OnSendPacket(absl::optional packet_id, + Timestamp capture_time, + uint32_t ssrc) override { + stats_proxy_.OnSendPacket(ssrc, capture_time); + if (packet_id.has_value()) { + send_delay_stats_.OnSendPacket(*packet_id, capture_time, ssrc); + } + } + + private: + SendStatisticsProxy& stats_proxy_; + SendDelayStats& send_delay_stats_; + }; absl::optional GetPacingFactorOverride() const; @@ -106,6 +125,7 @@ class VideoSendStream : public webrtc::VideoSendStream { RtpTransportControllerSendInterface* const transport_; SendStatisticsProxy stats_proxy_; + OnSendPacketObserver send_packet_observer_; const VideoSendStream::Config config_; const VideoEncoderConfig::ContentType content_type_; std::unique_ptr video_stream_encoder_; diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index d0a96ce06c..ee023d9fec 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -165,7 +165,8 @@ bool SameStreamsEnabled(const VideoBitrateAllocation& lhs, absl::optional GetConfiguredPacingFactor( const VideoSendStream::Config& config, VideoEncoderConfig::ContentType content_type, - const PacingConfig& default_pacing_config) { + const PacingConfig& default_pacing_config, + const FieldTrialsView& field_trials) { if (!TransportSeqNumExtensionConfigured(config)) return absl::nullopt; @@ -175,7 +176,7 @@ absl::optional GetConfiguredPacingFactor( return alr_settings->pacing_factor; RateControlSettings rate_control_settings = - RateControlSettings::ParseFromFieldTrials(); + RateControlSettings::ParseFromKeyValueConfig(&field_trials); return rate_control_settings.GetPacingFactor().value_or( default_pacing_config.pacing_factor); } @@ -246,8 +247,10 @@ VideoSendStreamImpl::VideoSendStreamImpl( encoder_bitrate_priority_(initial_encoder_bitrate_priority), video_stream_encoder_(video_stream_encoder), rtp_video_sender_(rtp_video_sender), - configured_pacing_factor_( - GetConfiguredPacingFactor(*config_, content_type, pacing_config_)) { + configured_pacing_factor_(GetConfiguredPacingFactor(*config_, + content_type, + pacing_config_, + field_trials)) { RTC_DCHECK_GE(config_->rtp.payload_type, 0); RTC_DCHECK_LE(config_->rtp.payload_type, 127); RTC_DCHECK(!config_->rtp.ssrcs.empty()); @@ -281,7 +284,7 @@ VideoSendStreamImpl::VideoSendStreamImpl( queue_time_limit_ms = alr_settings->max_paced_queue_time; } else { RateControlSettings rate_control_settings = - RateControlSettings::ParseFromFieldTrials(); + RateControlSettings::ParseFromKeyValueConfig(&field_trials); enable_alr_bw_probing = rate_control_settings.UseAlrProbing(); queue_time_limit_ms = pacing_config_.max_pacing_delay.Get().ms(); } diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index bdff1cf824..3241740d95 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -2915,7 +2915,7 @@ TEST_F(VideoSendStreamTest, ReportsSentResolution) { auto buffer = EncodedImageBuffer::Create(16); memset(buffer->data(), 0, 16); encoded.SetEncodedData(buffer); - encoded.SetTimestamp(input_image.timestamp()); + encoded.SetRtpTimestamp(input_image.timestamp()); encoded.capture_time_ms_ = input_image.render_time_ms(); for (size_t i = 0; i < kNumStreams; ++i) { diff --git a/video/video_stream_buffer_controller.cc b/video/video_stream_buffer_controller.cc index 455f064b01..59c07ddaab 100644 --- a/video/video_stream_buffer_controller.cc +++ b/video/video_stream_buffer_controller.cc @@ -56,7 +56,7 @@ struct FrameMetadata { size(frame.size()), contentType(frame.contentType()), delayed_by_retransmission(frame.delayed_by_retransmission()), - rtp_timestamp(frame.Timestamp()), + rtp_timestamp(frame.RtpTimestamp()), receive_time(frame.ReceivedTimestamp()) {} const bool is_last_spatial_layer; @@ -224,10 +224,10 @@ void VideoStreamBufferController::OnFrameReady( TargetVideoDelayIsTooLarge(timing_->TargetVideoDelay())) { RTC_LOG(LS_WARNING) << "Resetting jitter estimator and timing module due " "to bad render timing for rtp_timestamp=" - << first_frame.Timestamp(); + << first_frame.RtpTimestamp(); jitter_estimator_.Reset(); timing_->Reset(); - render_time = timing_->RenderTime(first_frame.Timestamp(), now); + render_time = timing_->RenderTime(first_frame.RtpTimestamp(), now); } for (std::unique_ptr& frame : frames) { @@ -241,7 +241,8 @@ void VideoStreamBufferController::OnFrameReady( if (!superframe_delayed_by_retransmission) { absl::optional inter_frame_delay_variation = - ifdv_calculator_.Calculate(first_frame.Timestamp(), max_receive_time); + ifdv_calculator_.Calculate(first_frame.RtpTimestamp(), + max_receive_time); if (inter_frame_delay_variation) { jitter_estimator_.UpdateEstimate(*inter_frame_delay_variation, superframe_size); @@ -380,7 +381,7 @@ void VideoStreamBufferController::ForceKeyFrameReleaseImmediately() } // Found keyframe - decode right away. if (next_frame.front()->is_keyframe()) { - auto render_time = timing_->RenderTime(next_frame.front()->Timestamp(), + auto render_time = timing_->RenderTime(next_frame.front()->RtpTimestamp(), clock_->CurrentTime()); OnFrameReady(std::move(next_frame), render_time); return; diff --git a/video/video_stream_buffer_controller_unittest.cc b/video/video_stream_buffer_controller_unittest.cc index 3224b20d83..d2f2f732e4 100644 --- a/video/video_stream_buffer_controller_unittest.cc +++ b/video/video_stream_buffer_controller_unittest.cc @@ -69,11 +69,11 @@ auto Frame(testing::Matcher m) { std::unique_ptr WithReceiveTimeFromRtpTimestamp( std::unique_ptr frame) { - if (frame->Timestamp() == 0) { + if (frame->RtpTimestamp() == 0) { frame->SetReceivedTime(kClockStart.ms()); } else { frame->SetReceivedTime( - TimeDelta::Seconds(frame->Timestamp() / 90000.0).ms() + + TimeDelta::Seconds(frame->RtpTimestamp() / 90000.0).ms() + kClockStart.ms()); } return frame; diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index c367510b21..2e5a120eed 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -135,7 +135,9 @@ bool RequiresEncoderReset(const VideoCodec& prev_send_codec, return true; } break; - + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Implement new send codec H265 + [[fallthrough]]; default: break; } @@ -648,7 +650,8 @@ VideoStreamEncoder::VideoStreamEncoder( sink_(nullptr), settings_(settings), allocation_cb_type_(allocation_cb_type), - rate_control_settings_(RateControlSettings::ParseFromFieldTrials()), + rate_control_settings_( + RateControlSettings::ParseFromKeyValueConfig(&field_trials)), encoder_selector_from_constructor_(encoder_selector), encoder_selector_from_factory_( encoder_selector_from_constructor_ @@ -1351,6 +1354,7 @@ void VideoStreamEncoder::ReconfigureEncoder() { // TODO(sprang): Add a better way to disable frame dropping. num_layers = codec.simulcastStream[0].numberOfTemporalLayers; } else { + // TODO(bugs.webrtc.org/13485): Implement H265 temporal layer num_layers = 1; } @@ -1365,7 +1369,8 @@ void VideoStreamEncoder::ReconfigureEncoder() { const VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo(); if (rate_control_settings_.UseEncoderBitrateAdjuster()) { - bitrate_adjuster_ = std::make_unique(codec); + bitrate_adjuster_ = + std::make_unique(codec, field_trials_); bitrate_adjuster_->OnEncoderInfo(info); } @@ -2130,7 +2135,7 @@ EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage( const EncodedImage& encoded_image, const CodecSpecificInfo* codec_specific_info) { TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded", - "timestamp", encoded_image.Timestamp()); + "timestamp", encoded_image.RtpTimestamp()); const size_t simulcast_index = encoded_image.SimulcastIndex().value_or(0); const VideoCodecType codec_type = codec_specific_info diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index 44fc53f90d..fa28368d68 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -1492,7 +1492,7 @@ class VideoStreamEncoderTest : public ::testing::Test { last_encoded_image_ = EncodedImage(encoded_image); last_encoded_image_data_ = std::vector( encoded_image.data(), encoded_image.data() + encoded_image.size()); - uint32_t timestamp = encoded_image.Timestamp(); + uint32_t timestamp = encoded_image.RtpTimestamp(); if (last_timestamp_ != timestamp) { num_received_layers_ = 1; last_width_ = encoded_image._encodedWidth; @@ -8822,6 +8822,9 @@ class VideoStreamEncoderWithRealEncoderTest mock_encoder_factory_for_multiplex_.get(), SdpVideoFormat("VP8"), false); break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use a fake encoder + break; default: RTC_DCHECK_NOTREACHED(); } diff --git a/webrtc.gni b/webrtc.gni index 80b4367fcc..cd84739178 100644 --- a/webrtc.gni +++ b/webrtc.gni @@ -482,9 +482,6 @@ all_poison_types = [ # Default echo detector implementation. "default_echo_detector", - # JSON parsing should not be needed in the "slim and modular" WebRTC. - "rtc_json", - # Software video codecs (VP8 and VP9 through libvpx). "software_video_codecs", ]