diff options
Diffstat (limited to 'third_party/libwebrtc/webrtc/test')
328 files changed, 17511 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/test/BUILD.gn b/third_party/libwebrtc/webrtc/test/BUILD.gn new file mode 100644 index 0000000000..f7bd8144be --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/BUILD.gn @@ -0,0 +1,729 @@ +# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import("../webrtc.gni") +import("//build/config/ui.gni") +if (is_android) { + import("//build/config/android/rules.gni") +} +if (rtc_use_memcheck) { + import("//tools_webrtc/valgrind/valgrind-webrtc.gni") +} + +group("test") { + testonly = true + + deps = [ + ":field_trial", + ":rtp_test_utils", + ":test_common", + ":test_renderer", + ":test_support", + ":video_test_common", + ] + + if (rtc_include_tests) { + deps += [ + ":test_main", + ":test_support_unittests", + ] + } +} + +rtc_source_set("video_test_common") { + testonly = true + sources = [ + "fake_texture_frame.cc", + "fake_texture_frame.h", + "frame_generator.cc", + "frame_generator.h", + "frame_generator_capturer.cc", + "frame_generator_capturer.h", + "frame_utils.cc", + "frame_utils.h", + "vcm_capturer.cc", + "vcm_capturer.h", + "video_capturer.cc", + "video_capturer.h", + "video_codec_settings.h", + ] + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + deps = [ + "..:webrtc_common", + "../api:optional", + "../api:video_frame_api_i420", + "../api/video_codecs:video_codecs_api", + "../call:video_stream_api", + "../common_video", + "../media:rtc_media_base", + "../modules/video_capture:video_capture_module", + "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_task_queue", + "../system_wrappers", + ] +} + +rtc_source_set("rtp_test_utils") { + testonly = true + sources = [ + "rtcp_packet_parser.cc", + "rtcp_packet_parser.h", + "rtp_file_reader.cc", + "rtp_file_reader.h", + "rtp_file_writer.cc", + "rtp_file_writer.h", + ] + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + deps = [ + "..:webrtc_common", + "../api:array_view", + "../modules/rtp_rtcp", + "../rtc_base:rtc_base_approved", + "//testing/gtest", + ] +} + +rtc_source_set("field_trial") { + testonly = true + sources = [ + "field_trial.cc", + "field_trial.h", + ] + + deps = [ + "..:webrtc_common", + "../system_wrappers", + "../system_wrappers:field_trial_default", + ] +} + +if (is_ios) { + rtc_source_set("test_support_objc") { + testonly = true + visibility = [ ":test_support" ] + sources = [ + "ios/test_support.h", + "ios/test_support.mm", + ] + deps = [ + "../sdk:common_objc", + ] + } +} + +rtc_source_set("test_support") { + testonly = true + + sources = [ + "gmock.h", + "gtest.h", + "testsupport/packet_reader.cc", + "testsupport/packet_reader.h", + "testsupport/perf_test.cc", + "testsupport/perf_test.h", + "testsupport/unittest_utils.h", + ] + + public_deps = [ + ":fileutils", + ] + if (is_ios) { + public_deps += [ ":test_support_objc" ] + } + + deps = [ + "..:webrtc_common", + "../common_video", + "../rtc_base:gtest_prod", + "../rtc_base:rtc_base_approved", + "../system_wrappers", + "//testing/gmock", + "//testing/gtest", + ] + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + if (!build_with_mozilla && is_android) { + deps += [ "//base:base" ] + } + + if (is_ios && !build_with_chromium) { + deps += [ "../sdk:common_objc" ] + } + + if (rtc_use_memcheck) { + data = valgrind_webrtc_dependencies + } +} + +if (rtc_include_tests) { + rtc_source_set("test_main") { + testonly = true + sources = [ + "test_main.cc", + ] + + public_deps = [ + ":test_support", + ] + deps = [ + ":field_trial", + "../rtc_base:rtc_base_approved", + "../system_wrappers:metrics_default", + "//testing/gmock", + "//testing/gtest", + ] + } + + rtc_source_set("video_test_support") { + testonly = true + + sources = [ + "testsupport/frame_reader.h", + "testsupport/frame_writer.h", + "testsupport/metrics/video_metrics.cc", + "testsupport/metrics/video_metrics.h", + "testsupport/mock/mock_frame_reader.h", + "testsupport/y4m_frame_writer.cc", + "testsupport/yuv_frame_reader.cc", + "testsupport/yuv_frame_writer.cc", + ] + + deps = [ + ":test_support", + ":video_test_common", + "..:webrtc_common", + "../api:video_frame_api", + "../api:video_frame_api_i420", + "../common_video", + "../rtc_base:rtc_base_approved", + "../system_wrappers", + "//testing/gmock", + "//testing/gtest", + ] + + if (!is_ios) { + deps += [ "//third_party:jpeg" ] + sources += [ "testsupport/jpeg_frame_writer.cc" ] + } else { + sources += [ "testsupport/jpeg_frame_writer_ios.cc" ] + } + + public_deps = [ + ":fileutils", + ] + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + if (is_android) { + deps += [ "//base:base" ] + } + + if (is_ios) { + deps += [ "../sdk:common_objc" ] + } + + if (rtc_use_memcheck) { + data = valgrind_webrtc_dependencies + } + } + + rtc_source_set("test_support_test_artifacts") { + testonly = true + sources = [ + "testsupport/test_artifacts.cc", + "testsupport/test_artifacts.h", + ] + deps = [ + ":fileutils", + "../rtc_base:rtc_base_approved", + ] + } + + test_support_unittests_resources = [ + "../resources/foreman_cif_short.yuv", + "../resources/video_coding/frame-ethernet-ii.pcap", + "../resources/video_coding/frame-loopback.pcap", + "../resources/video_coding/pltype103.rtp", + "../resources/video_coding/pltype103_header_only.rtp", + "../resources/video_coding/ssrcs-2.pcap", + "../resources/video_coding/ssrcs-3.pcap", + ] + + if (is_ios) { + bundle_data("test_support_unittests_bundle_data") { + testonly = true + sources = test_support_unittests_resources + outputs = [ + "{{bundle_resources_dir}}/{{source_file_part}}", + ] + } + } + + rtc_test("test_support_unittests") { + deps = [ + ":fake_audio_device", + ":rtp_test_utils", + "../api:video_frame_api", + "../api:video_frame_api_i420", + "../call:call_interfaces", + "../common_audio", + "../modules/rtp_rtcp", + "../rtc_base:rtc_base_approved", + "../system_wrappers", + ] + sources = [ + "fake_audio_device_unittest.cc", + "fake_network_pipe_unittest.cc", + "frame_generator_unittest.cc", + "rtp_file_reader_unittest.cc", + "rtp_file_writer_unittest.cc", + "single_threaded_task_queue_unittest.cc", + "testsupport/always_passing_unittest.cc", + "testsupport/metrics/video_metrics_unittest.cc", + "testsupport/packet_reader_unittest.cc", + "testsupport/perf_test_unittest.cc", + "testsupport/test_artifacts_unittest.cc", + "testsupport/y4m_frame_writer_unittest.cc", + "testsupport/yuv_frame_reader_unittest.cc", + "testsupport/yuv_frame_writer_unittest.cc", + ] + + # TODO(jschuh): Bug 1348: fix this warning. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + if (is_win) { + # virtual override w/different const/volatile signature. + cflags = [ "/wd4373" ] + } + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + data = test_support_unittests_resources + if (is_android) { + deps += [ "//testing/android/native_test:native_test_support" ] + shard_timeout = 900 + } + + if (is_ios) { + deps += [ ":test_support_unittests_bundle_data" ] + } + + deps += [ + ":direct_transport", + ":fileutils_unittests", + ":test_common", + ":test_main", + ":test_support_test_artifacts", + ":video_test_common", + ":video_test_support", + "../modules/video_capture", + "../rtc_base:rtc_base_approved", + "//testing/gmock", + "//testing/gtest", + ] + } +} + +if (is_ios) { + rtc_source_set("fileutils_objc") { + visibility = [ ":fileutils" ] + sources = [ + "testsupport/iosfileutils.mm", + ] + deps = [ + "..:webrtc_common", + "../rtc_base:rtc_base_approved", + "../sdk:common_objc", + ] + } +} + +rtc_source_set("fileutils") { + testonly = true + visibility = [ + ":fileutils_unittests", + ":test_support_test_artifacts", + ":test_support", + ":video_test_support", + ] + sources = [ + "testsupport/fileutils.cc", + "testsupport/fileutils.h", + ] + deps = [ + "..:webrtc_common", + "../api:optional", + "../rtc_base:rtc_base_approved", + ] + if (is_ios) { + deps += [ ":fileutils_objc" ] + } + if (is_win) { + deps += [ "../rtc_base:rtc_base" ] + } +} + +rtc_source_set("run_test") { + testonly = true + if (is_mac) { + public_deps = [ + ":run_test_objc", + ] + } else { + public_deps = [ + ":run_test_generic", + ] + } +} + +rtc_source_set("run_test_interface") { + sources = [ + "run_test.h", + ] +} + +if (is_mac) { + rtc_source_set("run_test_objc") { + testonly = true + visibility = [ ":run_test" ] + sources = [ + "mac/run_test.mm", + ] + deps = [ + ":run_test_interface", + ] + } +} + +rtc_source_set("run_test_generic") { + testonly = true + visibility = [ ":run_test" ] + sources = [ + "run_test.cc", + ] + deps = [ + ":run_test_interface", + ] +} + +rtc_source_set("fileutils_unittests") { + testonly = true + visibility = [ ":*" ] # Only targets in this file can depend on this. + sources = [ + "testsupport/fileutils_unittest.cc", + ] + deps = [ + ":fileutils", + ":test_support", + "../api:optional", + "../rtc_base:rtc_base_approved", + "//testing/gmock", + "//testing/gtest", + ] +} + +rtc_source_set("direct_transport") { + testonly = true + sources = [ + "direct_transport.cc", + "direct_transport.h", + "fake_network_pipe.cc", + "fake_network_pipe.h", + ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + deps = [ + "..:webrtc_common", + "../api:transport_api", + "../call", + "../modules/rtp_rtcp", + "../rtc_base:rtc_base_approved", + "../rtc_base:sequenced_task_checker", + "../system_wrappers", + ] + public_deps = [ + ":single_threaded_task_queue", + ] +} + +rtc_source_set("single_threaded_task_queue") { + testonly = true + sources = [ + "single_threaded_task_queue.cc", + "single_threaded_task_queue.h", + ] + deps = [ + "../rtc_base:rtc_base_approved", + ] +} + +rtc_source_set("fake_audio_device") { + testonly = true + sources = [ + "fake_audio_device.cc", + "fake_audio_device.h", + ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + deps = [ + "..:webrtc_common", + "../api:array_view", + "../common_audio:common_audio", + "../modules/audio_device:audio_device", + "../rtc_base:rtc_base_approved", + "../system_wrappers:system_wrappers", + ] +} + +rtc_source_set("test_common") { + testonly = true + sources = [ + "call_test.cc", + "call_test.h", + "configurable_frame_size_encoder.cc", + "configurable_frame_size_encoder.h", + "constants.cc", + "constants.h", + "drifting_clock.cc", + "drifting_clock.h", + "encoder_settings.cc", + "encoder_settings.h", + "fake_decoder.cc", + "fake_decoder.h", + "fake_encoder.cc", + "fake_encoder.h", + "fake_videorenderer.h", + "layer_filtering_transport.cc", + "layer_filtering_transport.h", + "mock_transport.h", + "mock_voe_channel_proxy.h", + "mock_voice_engine.h", + "null_transport.cc", + "null_transport.h", + "rtp_rtcp_observer.h", + "statistics.cc", + "statistics.h", + "win/run_loop_win.cc", + ] + if (!is_win) { + sources += [ + "run_loop.cc", + "run_loop.h", + ] + } + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + deps = [ + ":direct_transport", + ":fake_audio_device", + ":rtp_test_utils", + ":test_support", + ":video_test_common", + "..:webrtc_common", + "../api:transport_api", + "../api:video_frame_api", + "../api:video_frame_api_i420", + "../api/audio_codecs:builtin_audio_decoder_factory", + "../api/audio_codecs:builtin_audio_encoder_factory", + "../api/video_codecs:video_codecs_api", + "../audio", + "../call", + "../call:rtp_sender", + "../call:video_stream_api", + "../common_video", + "../logging:rtc_event_log_api", + "../modules/audio_device:mock_audio_device", + "../modules/audio_mixer:audio_mixer_impl", + "../modules/audio_processing", + "../modules/rtp_rtcp", + "../modules/rtp_rtcp:mock_rtp_rtcp", + "../modules/video_coding:video_coding_utility", + "../modules/video_coding:webrtc_h264", + "../modules/video_coding:webrtc_vp8", + "../modules/video_coding:webrtc_vp9", + "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_task_queue", + "../rtc_base:sequenced_task_checker", + "../system_wrappers", + "../video", + "../voice_engine", + "//testing/gmock", + "//testing/gtest", + ] + if (!is_android && !build_with_chromium) { + deps += [ "../modules/video_capture:video_capture_internal_impl" ] + } +} + +config("test_renderer_exported_config") { + if (is_win && is_clang) { + # GN orders flags on a target before flags from configs. The default config + # adds -Wall, and this flag have to be after -Wall -- so they need to + # come from a config and cannot be on the target directly. + cflags = [ + "-Wno-bool-conversion", + "-Wno-comment", + "-Wno-delete-non-virtual-dtor", + ] + } +} + +rtc_source_set("test_renderer") { + public_deps = [ + ":test_renderer_generic", + ] + testonly = true + if (is_mac) { + public_deps += [ ":test_renderer_objc" ] + } +} + +if (is_mac) { + rtc_source_set("test_renderer_objc") { + testonly = true + visibility = [ ":test_renderer" ] + sources = [ + "mac/video_renderer_mac.h", + "mac/video_renderer_mac.mm", + ] + deps = [ + ":test_renderer_generic", + "../rtc_base:rtc_base_approved", + ] + libs = [ + "Cocoa.framework", + "OpenGL.framework", + "CoreVideo.framework", + ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + } +} + +rtc_source_set("test_renderer_generic") { + testonly = true + visibility = [ + ":test_renderer", + ":test_renderer_objc", + ] + libs = [] + sources = [ + "video_renderer.cc", + "video_renderer.h", + "win/d3d_renderer.cc", + "win/d3d_renderer.h", + ] + deps = [ + ":test_support", + "..:webrtc_common", + "../common_video", + "../modules/media_file", + "../rtc_base:rtc_base_approved", + "//testing/gtest", + ] + if (!(is_linux && use_x11) && !is_mac && !is_win) { + sources += [ "null_platform_renderer.cc" ] + } + if ((is_linux && use_x11) || is_mac) { + sources += [ + "gl/gl_renderer.cc", + "gl/gl_renderer.h", + ] + } + + if (is_linux && use_x11) { + sources += [ + "linux/glx_renderer.cc", + "linux/glx_renderer.h", + "linux/video_renderer_linux.cc", + ] + libs += [ + "Xext", + "X11", + "GL", + ] + } + if (is_android) { + libs += [ + "GLESv2", + "log", + ] + } + + public_configs = [ ":test_renderer_exported_config" ] + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } +} + +rtc_source_set("audio_codec_mocks") { + testonly = true + sources = [ + "mock_audio_decoder.cc", + "mock_audio_decoder.h", + "mock_audio_decoder_factory.h", + "mock_audio_encoder.cc", + "mock_audio_encoder.h", + "mock_audio_encoder_factory.h", + ] + + deps = [ + ":test_support", + "../api:array_view", + "../api/audio_codecs:audio_codecs_api", + "../api/audio_codecs:builtin_audio_decoder_factory", + "../rtc_base:rtc_base_approved", + "//testing/gmock", + ] +} + +if (!build_with_chromium && !build_with_mozilla && is_android) { + rtc_android_library("native_test_java") { + testonly = true + java_files = [ + "android/org/webrtc/native_test/RTCNativeUnitTest.java", + "android/org/webrtc/native_test/RTCNativeUnitTestActivity.java", + ] + deps = [ + "../rtc_base:base_java", + "//testing/android/native_test:native_test_java", + ] + } +} diff --git a/third_party/libwebrtc/webrtc/test/DEPS b/third_party/libwebrtc/webrtc/test/DEPS new file mode 100644 index 0000000000..39f107b9b2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/DEPS @@ -0,0 +1,43 @@ +include_rules = [ + "+third_party/libjpeg", + "+third_party/libjpeg_turbo", + "+call", + "+common_audio", + "+common_video", + "+logging/rtc_event_log", + "+media/base", + "+modules/audio_coding", + "+modules/audio_device", + "+modules/audio_mixer", + "+modules/audio_processing", + "+modules/media_file", + "+modules/rtp_rtcp", + "+modules/video_capture", + "+modules/video_coding", + "+sdk", + "+system_wrappers", + "+voice_engine", +] + +specific_include_rules = { + "gmock\.h": [ + "+testing/gmock/include/gmock", + ], + "gtest\.h": [ + "+testing/gtest/include/gtest", + ], + ".*congestion_controller_feedback_fuzzer\.cc": [ + "+modules/congestion_controller/include/receive_side_congestion_controller.h", + "+modules/pacing/packet_router.h", + "+modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h", + ], + ".*pseudotcp_parser_fuzzer\.cc": [ + "+p2p/base/pseudotcp.h", + ], + ".*stun_parser_fuzzer\.cc": [ + "+p2p/base/stun.h", + ], + ".*stun_validator_fuzzer\.cc": [ + "+p2p/base/stun.h", + ], +} diff --git a/third_party/libwebrtc/webrtc/test/OWNERS b/third_party/libwebrtc/webrtc/test/OWNERS new file mode 100644 index 0000000000..c58c863e16 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/OWNERS @@ -0,0 +1,2 @@ +phoglund@webrtc.org +stefan@webrtc.org diff --git a/third_party/libwebrtc/webrtc/test/android/AndroidManifest.xml b/third_party/libwebrtc/webrtc/test/android/AndroidManifest.xml new file mode 100644 index 0000000000..b5157a75df --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/android/AndroidManifest.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2017 The WebRTC project authors. All Rights Reserved. + +Use of this source code is governed by a BSD-style license +that can be found in the LICENSE file in the root of the source +tree. An additional intellectual property rights grant can be found +in the file PATENTS. All contributing project authors may +be found in the AUTHORS file in the root of the source tree. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.webrtc.native_test" + android:versionCode="1" + android:versionName="1.0"> + + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.BLUETOOTH"/> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> + <uses-permission android:name="android.permission.RECORD_AUDIO"/> + <uses-permission android:name="android.permission.WAKE_LOCK"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + + <application android:label="NativeTests" + android:name="org.chromium.base.BaseChromiumApplication"> + <uses-library android:name="android.test.runner"/> + <activity android:name=".RTCNativeUnitTestActivity" + android:label="NativeTest" + android:configChanges="orientation|keyboardHidden" + android:process=":test_process"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="org.chromium.native_test.NativeTestInstrumentationTestRunner" + android:targetPackage="org.webrtc.native_test" + android:label="Instrumentation entry point for org.webrtc.native_test"/> + +</manifest> diff --git a/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTest.java b/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTest.java new file mode 100644 index 0000000000..dede7edd1f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTest.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc.native_test; + +import android.app.Activity; +import org.chromium.native_test.NativeUnitTest; +import org.webrtc.ContextUtils; + +/** + * Native unit test that calls ContextUtils.initialize for WebRTC. + */ +public class RTCNativeUnitTest extends NativeUnitTest { + @Override + public void preCreate(Activity activity) { + super.preCreate(activity); + ContextUtils.initialize(activity.getApplicationContext()); + } +} diff --git a/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTestActivity.java b/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTestActivity.java new file mode 100644 index 0000000000..2a413682fe --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/android/org/webrtc/native_test/RTCNativeUnitTestActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc.native_test; + +import android.app.Activity; +import android.os.Bundle; + +/** + * Activity that uses RTCNativeUnitTest to run the tests. + */ +public class RTCNativeUnitTestActivity extends Activity { + private RTCNativeUnitTest mTest = new RTCNativeUnitTest(); + + @Override + public void onCreate(Bundle savedInstanceState) { + mTest.preCreate(this); + super.onCreate(savedInstanceState); + mTest.postCreate(this); + } + + @Override + public void onStart() { + super.onStart(); + mTest.postStart(this, false); + } +} diff --git a/third_party/libwebrtc/webrtc/test/call_test.cc b/third_party/libwebrtc/webrtc/test/call_test.cc new file mode 100644 index 0000000000..3210e6460d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/call_test.cc @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/call_test.h" + +#include <algorithm> + +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "call/rtp_transport_controller_send.h" +#include "call/video_config.h" +#include "modules/audio_mixer/audio_mixer_impl.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/ptr_util.h" +#include "test/testsupport/fileutils.h" +#include "voice_engine/include/voe_base.h" + +namespace webrtc { +namespace test { + +namespace { +const int kVideoRotationRtpExtensionId = 4; +} + +CallTest::CallTest() + : clock_(Clock::GetRealTimeClock()), + event_log_(RtcEventLog::CreateNull()), + sender_call_transport_controller_(nullptr), + video_send_config_(nullptr), + video_send_stream_(nullptr), + audio_send_config_(nullptr), + audio_send_stream_(nullptr), + fake_encoder_(clock_), + num_video_streams_(1), + num_audio_streams_(0), + num_flexfec_streams_(0), + decoder_factory_(CreateBuiltinAudioDecoderFactory()), + encoder_factory_(CreateBuiltinAudioEncoderFactory()), + task_queue_("CallTestTaskQueue"), + fake_send_audio_device_(nullptr), + fake_recv_audio_device_(nullptr) {} + +CallTest::~CallTest() { + task_queue_.SendTask([this]() { + fake_send_audio_device_.reset(); + fake_recv_audio_device_.reset(); + frame_generator_capturer_.reset(); + }); +} + +void CallTest::RunBaseTest(BaseTest* test) { + task_queue_.SendTask([this, test]() { + num_video_streams_ = test->GetNumVideoStreams(); + num_audio_streams_ = test->GetNumAudioStreams(); + num_flexfec_streams_ = test->GetNumFlexfecStreams(); + RTC_DCHECK(num_video_streams_ > 0 || num_audio_streams_ > 0); + Call::Config send_config(test->GetSenderCallConfig()); + if (num_audio_streams_ > 0) { + CreateFakeAudioDevices(test->CreateCapturer(), test->CreateRenderer()); + test->OnFakeAudioDevicesCreated(fake_send_audio_device_.get(), + fake_recv_audio_device_.get()); + apm_send_ = AudioProcessing::Create(); + apm_recv_ = AudioProcessing::Create(); + CreateVoiceEngines(); + AudioState::Config audio_state_config; + audio_state_config.voice_engine = voe_send_.voice_engine; + audio_state_config.audio_mixer = AudioMixerImpl::Create(); + audio_state_config.audio_processing = apm_send_; + send_config.audio_state = AudioState::Create(audio_state_config); + fake_send_audio_device_->RegisterAudioCallback( + send_config.audio_state->audio_transport()); + } + CreateSenderCall(send_config); + if (sender_call_transport_controller_ != nullptr) { + test->OnRtpTransportControllerSendCreated( + sender_call_transport_controller_); + } + if (test->ShouldCreateReceivers()) { + Call::Config recv_config(test->GetReceiverCallConfig()); + if (num_audio_streams_ > 0) { + AudioState::Config audio_state_config; + audio_state_config.voice_engine = voe_recv_.voice_engine; + audio_state_config.audio_mixer = AudioMixerImpl::Create(); + audio_state_config.audio_processing = apm_recv_; + recv_config.audio_state = AudioState::Create(audio_state_config); + fake_recv_audio_device_->RegisterAudioCallback( + recv_config.audio_state->audio_transport()); } + CreateReceiverCall(recv_config); + } + test->OnCallsCreated(sender_call_.get(), receiver_call_.get()); + receive_transport_.reset(test->CreateReceiveTransport(&task_queue_)); + send_transport_.reset( + test->CreateSendTransport(&task_queue_, sender_call_.get())); + + if (test->ShouldCreateReceivers()) { + send_transport_->SetReceiver(receiver_call_->Receiver()); + receive_transport_->SetReceiver(sender_call_->Receiver()); + if (num_video_streams_ > 0) + receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp); + if (num_audio_streams_ > 0) + receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp); + } else { + // Sender-only call delivers to itself. + send_transport_->SetReceiver(sender_call_->Receiver()); + receive_transport_->SetReceiver(nullptr); + } + + CreateSendConfig(num_video_streams_, num_audio_streams_, + num_flexfec_streams_, send_transport_.get()); + if (test->ShouldCreateReceivers()) { + CreateMatchingReceiveConfigs(receive_transport_.get()); + } + if (num_video_streams_ > 0) { + test->ModifyVideoConfigs(&video_send_config_, &video_receive_configs_, + &video_encoder_config_); + } + if (num_audio_streams_ > 0) { + test->ModifyAudioConfigs(&audio_send_config_, &audio_receive_configs_); + } + if (num_flexfec_streams_ > 0) { + test->ModifyFlexfecConfigs(&flexfec_receive_configs_); + } + + if (num_flexfec_streams_ > 0) { + CreateFlexfecStreams(); + test->OnFlexfecStreamsCreated(flexfec_receive_streams_); + } + if (num_video_streams_ > 0) { + CreateVideoStreams(); + test->OnVideoStreamsCreated(video_send_stream_, video_receive_streams_); + } + if (num_audio_streams_ > 0) { + CreateAudioStreams(); + test->OnAudioStreamsCreated(audio_send_stream_, audio_receive_streams_); + } + + if (num_video_streams_ > 0) { + int width = kDefaultWidth; + int height = kDefaultHeight; + int frame_rate = kDefaultFramerate; + test->ModifyVideoCaptureStartResolution(&width, &height, &frame_rate); + CreateFrameGeneratorCapturer(frame_rate, width, height); + test->OnFrameGeneratorCapturerCreated(frame_generator_capturer_.get()); + } + + Start(); + }); + + test->PerformTest(); + + task_queue_.SendTask([this, test]() { + Stop(); + test->OnStreamsStopped(); + DestroyStreams(); + send_transport_.reset(); + receive_transport_.reset(); + DestroyCalls(); + if (num_audio_streams_ > 0) + DestroyVoiceEngines(); + }); +} + +void CallTest::CreateCalls(const Call::Config& sender_config, + const Call::Config& receiver_config) { + CreateSenderCall(sender_config); + CreateReceiverCall(receiver_config); +} + +void CallTest::CreateSenderCall(const Call::Config& config) { + sender_call_transport_controller_ = new RtpTransportControllerSend( + Clock::GetRealTimeClock(), config.event_log); + + sender_call_.reset( + Call::Create(config, std::unique_ptr<RtpTransportControllerSend>( + sender_call_transport_controller_))); +} + +void CallTest::CreateReceiverCall(const Call::Config& config) { + receiver_call_.reset(Call::Create(config)); +} + +void CallTest::DestroyCalls() { + sender_call_.reset(); + receiver_call_.reset(); +} + +void CallTest::CreateSendConfig(size_t num_video_streams, + size_t num_audio_streams, + size_t num_flexfec_streams, + Transport* send_transport) { + RTC_DCHECK(num_video_streams <= kNumSsrcs); + RTC_DCHECK_LE(num_audio_streams, 1); + RTC_DCHECK_LE(num_flexfec_streams, 1); + RTC_DCHECK(num_audio_streams == 0 || voe_send_.channel_id >= 0); + if (num_video_streams > 0) { + video_send_config_ = VideoSendStream::Config(send_transport); + video_send_config_.encoder_settings.encoder = &fake_encoder_; + video_send_config_.encoder_settings.payload_name = "FAKE"; + video_send_config_.encoder_settings.payload_type = + kFakeVideoSendPayloadType; + video_send_config_.rtp.extensions.push_back( + RtpExtension(RtpExtension::kTransportSequenceNumberUri, + kTransportSequenceNumberExtensionId)); + video_send_config_.rtp.extensions.push_back(RtpExtension( + RtpExtension::kVideoContentTypeUri, kVideoContentTypeExtensionId)); + FillEncoderConfiguration(num_video_streams, &video_encoder_config_); + + for (size_t i = 0; i < num_video_streams; ++i) + video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[i]); + video_send_config_.rtp.extensions.push_back(RtpExtension( + RtpExtension::kVideoRotationUri, kVideoRotationRtpExtensionId)); + } + + if (num_audio_streams > 0) { + audio_send_config_ = AudioSendStream::Config(send_transport); + audio_send_config_.voe_channel_id = voe_send_.channel_id; + audio_send_config_.rtp.ssrc = kAudioSendSsrc; + audio_send_config_.send_codec_spec = + rtc::Optional<AudioSendStream::Config::SendCodecSpec>( + {kAudioSendPayloadType, {"opus", 48000, 2, {{"stereo", "1"}}}}); + audio_send_config_.encoder_factory = encoder_factory_; + } + + // TODO(brandtr): Update this when we support multistream protection. + if (num_flexfec_streams > 0) { + video_send_config_.rtp.flexfec.payload_type = kFlexfecPayloadType; + video_send_config_.rtp.flexfec.ssrc = kFlexfecSendSsrc; + video_send_config_.rtp.flexfec.protected_media_ssrcs = {kVideoSendSsrcs[0]}; + } +} + +void CallTest::CreateMatchingReceiveConfigs(Transport* rtcp_send_transport) { + video_receive_configs_.clear(); + allocated_decoders_.clear(); + if (num_video_streams_ > 0) { + RTC_DCHECK(!video_send_config_.rtp.ssrcs.empty()); + VideoReceiveStream::Config video_config(rtcp_send_transport); + video_config.rtp.remb = false; + video_config.rtp.transport_cc = true; + video_config.rtp.local_ssrc = kReceiverLocalVideoSsrc; + for (const RtpExtension& extension : video_send_config_.rtp.extensions) + video_config.rtp.extensions.push_back(extension); + video_config.renderer = &fake_renderer_; + for (size_t i = 0; i < video_send_config_.rtp.ssrcs.size(); ++i) { + VideoReceiveStream::Decoder decoder = + test::CreateMatchingDecoder(video_send_config_.encoder_settings); + allocated_decoders_.push_back( + std::unique_ptr<VideoDecoder>(decoder.decoder)); + video_config.decoders.clear(); + video_config.decoders.push_back(decoder); + video_config.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[i]; + video_receive_configs_.push_back(video_config.Copy()); + } + video_receive_configs_[0].rtp.protected_by_flexfec = + (num_flexfec_streams_ == 1); + } + + RTC_DCHECK_GE(1, num_audio_streams_); + if (num_audio_streams_ == 1) { + RTC_DCHECK_LE(0, voe_send_.channel_id); + AudioReceiveStream::Config audio_config; + audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc; + audio_config.rtcp_send_transport = rtcp_send_transport; + audio_config.voe_channel_id = voe_recv_.channel_id; + audio_config.rtp.remote_ssrc = audio_send_config_.rtp.ssrc; + audio_config.decoder_factory = decoder_factory_; + audio_config.decoder_map = {{kAudioSendPayloadType, {"opus", 48000, 2}}}; + audio_receive_configs_.push_back(audio_config); + } + + // TODO(brandtr): Update this when we support multistream protection. + RTC_DCHECK(num_flexfec_streams_ <= 1); + if (num_flexfec_streams_ == 1) { + FlexfecReceiveStream::Config config(rtcp_send_transport); + config.payload_type = kFlexfecPayloadType; + config.remote_ssrc = kFlexfecSendSsrc; + config.protected_media_ssrcs = {kVideoSendSsrcs[0]}; + config.local_ssrc = kReceiverLocalVideoSsrc; + for (const RtpExtension& extension : video_send_config_.rtp.extensions) + config.rtp_header_extensions.push_back(extension); + flexfec_receive_configs_.push_back(config); + } +} + +void CallTest::CreateFrameGeneratorCapturerWithDrift(Clock* clock, + float speed, + int framerate, + int width, + int height) { + frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( + width, height, framerate * speed, clock)); + video_send_stream_->SetSource( + frame_generator_capturer_.get(), + VideoSendStream::DegradationPreference::kMaintainFramerate); +} + +void CallTest::CreateFrameGeneratorCapturer(int framerate, + int width, + int height) { + frame_generator_capturer_.reset( + test::FrameGeneratorCapturer::Create(width, height, framerate, clock_)); + video_send_stream_->SetSource( + frame_generator_capturer_.get(), + VideoSendStream::DegradationPreference::kMaintainFramerate); +} + +void CallTest::CreateFakeAudioDevices( + std::unique_ptr<FakeAudioDevice::Capturer> capturer, + std::unique_ptr<FakeAudioDevice::Renderer> renderer) { + fake_send_audio_device_.reset(new FakeAudioDevice( + std::move(capturer), nullptr, 1.f)); + fake_recv_audio_device_.reset(new FakeAudioDevice( + nullptr, std::move(renderer), 1.f)); +} + +void CallTest::CreateVideoStreams() { + RTC_DCHECK(video_send_stream_ == nullptr); + RTC_DCHECK(video_receive_streams_.empty()); + RTC_DCHECK(audio_send_stream_ == nullptr); + RTC_DCHECK(audio_receive_streams_.empty()); + + video_send_stream_ = sender_call_->CreateVideoSendStream( + video_send_config_.Copy(), video_encoder_config_.Copy()); + for (size_t i = 0; i < video_receive_configs_.size(); ++i) { + video_receive_streams_.push_back(receiver_call_->CreateVideoReceiveStream( + video_receive_configs_[i].Copy())); + } + + AssociateFlexfecStreamsWithVideoStreams(); +} + +void CallTest::CreateAudioStreams() { + audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_); + for (size_t i = 0; i < audio_receive_configs_.size(); ++i) { + audio_receive_streams_.push_back( + receiver_call_->CreateAudioReceiveStream(audio_receive_configs_[i])); + } +} + +void CallTest::CreateFlexfecStreams() { + for (size_t i = 0; i < flexfec_receive_configs_.size(); ++i) { + flexfec_receive_streams_.push_back( + receiver_call_->CreateFlexfecReceiveStream( + flexfec_receive_configs_[i])); + } + + AssociateFlexfecStreamsWithVideoStreams(); +} + +void CallTest::AssociateFlexfecStreamsWithVideoStreams() { + // All FlexFEC streams protect all of the video streams. + for (FlexfecReceiveStream* flexfec_recv_stream : flexfec_receive_streams_) { + for (VideoReceiveStream* video_recv_stream : video_receive_streams_) { + video_recv_stream->AddSecondarySink(flexfec_recv_stream); + } + } +} + +void CallTest::DissociateFlexfecStreamsFromVideoStreams() { + for (FlexfecReceiveStream* flexfec_recv_stream : flexfec_receive_streams_) { + for (VideoReceiveStream* video_recv_stream : video_receive_streams_) { + video_recv_stream->RemoveSecondarySink(flexfec_recv_stream); + } + } +} + +void CallTest::Start() { + if (video_send_stream_) + video_send_stream_->Start(); + for (VideoReceiveStream* video_recv_stream : video_receive_streams_) + video_recv_stream->Start(); + if (audio_send_stream_) { + audio_send_stream_->Start(); + } + for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_) + audio_recv_stream->Start(); + if (frame_generator_capturer_.get() != NULL) + frame_generator_capturer_->Start(); +} + +void CallTest::Stop() { + if (frame_generator_capturer_.get() != NULL) + frame_generator_capturer_->Stop(); + for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_) + audio_recv_stream->Stop(); + if (audio_send_stream_) { + audio_send_stream_->Stop(); + } + for (VideoReceiveStream* video_recv_stream : video_receive_streams_) + video_recv_stream->Stop(); + if (video_send_stream_) + video_send_stream_->Stop(); +} + +void CallTest::DestroyStreams() { + DissociateFlexfecStreamsFromVideoStreams(); + + if (audio_send_stream_) + sender_call_->DestroyAudioSendStream(audio_send_stream_); + audio_send_stream_ = nullptr; + for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_) + receiver_call_->DestroyAudioReceiveStream(audio_recv_stream); + + if (video_send_stream_) + sender_call_->DestroyVideoSendStream(video_send_stream_); + video_send_stream_ = nullptr; + + for (VideoReceiveStream* video_recv_stream : video_receive_streams_) + receiver_call_->DestroyVideoReceiveStream(video_recv_stream); + + for (FlexfecReceiveStream* flexfec_recv_stream : flexfec_receive_streams_) + receiver_call_->DestroyFlexfecReceiveStream(flexfec_recv_stream); + + video_receive_streams_.clear(); + allocated_decoders_.clear(); +} + +void CallTest::SetFakeVideoCaptureRotation(VideoRotation rotation) { + frame_generator_capturer_->SetFakeRotation(rotation); +} + +void CallTest::CreateVoiceEngines() { + voe_send_.voice_engine = VoiceEngine::Create(); + voe_send_.base = VoEBase::GetInterface(voe_send_.voice_engine); + EXPECT_EQ(0, fake_send_audio_device_->Init()); + EXPECT_EQ(0, voe_send_.base->Init(fake_send_audio_device_.get(), + apm_send_.get(), decoder_factory_)); + VoEBase::ChannelConfig config; + config.enable_voice_pacing = true; + voe_send_.channel_id = voe_send_.base->CreateChannel(config); + EXPECT_GE(voe_send_.channel_id, 0); + + voe_recv_.voice_engine = VoiceEngine::Create(); + voe_recv_.base = VoEBase::GetInterface(voe_recv_.voice_engine); + EXPECT_EQ(0, fake_recv_audio_device_->Init()); + EXPECT_EQ(0, voe_recv_.base->Init(fake_recv_audio_device_.get(), + apm_recv_.get(), decoder_factory_)); + voe_recv_.channel_id = voe_recv_.base->CreateChannel(); + EXPECT_GE(voe_recv_.channel_id, 0); +} + +void CallTest::DestroyVoiceEngines() { + voe_recv_.base->DeleteChannel(voe_recv_.channel_id); + voe_recv_.channel_id = -1; + voe_recv_.base->Release(); + voe_recv_.base = nullptr; + + voe_send_.base->DeleteChannel(voe_send_.channel_id); + voe_send_.channel_id = -1; + voe_send_.base->Release(); + voe_send_.base = nullptr; + + VoiceEngine::Delete(voe_send_.voice_engine); + voe_send_.voice_engine = nullptr; + VoiceEngine::Delete(voe_recv_.voice_engine); + voe_recv_.voice_engine = nullptr; +} + +const int CallTest::kDefaultWidth; +const int CallTest::kDefaultHeight; +const int CallTest::kDefaultFramerate; +const int CallTest::kDefaultTimeoutMs = 30 * 1000; +const int CallTest::kLongTimeoutMs = 120 * 1000; +const uint8_t CallTest::kVideoSendPayloadType = 100; +const uint8_t CallTest::kFakeVideoSendPayloadType = 125; +const uint8_t CallTest::kSendRtxPayloadType = 98; +const uint8_t CallTest::kRedPayloadType = 118; +const uint8_t CallTest::kRtxRedPayloadType = 99; +const uint8_t CallTest::kUlpfecPayloadType = 119; +const uint8_t CallTest::kFlexfecPayloadType = 120; +const uint8_t CallTest::kAudioSendPayloadType = 103; +const uint8_t CallTest::kPayloadTypeH264 = 122; +const uint8_t CallTest::kPayloadTypeVP8 = 123; +const uint8_t CallTest::kPayloadTypeVP9 = 124; +const uint32_t CallTest::kSendRtxSsrcs[kNumSsrcs] = {0xBADCAFD, 0xBADCAFE, + 0xBADCAFF}; +const uint32_t CallTest::kVideoSendSsrcs[kNumSsrcs] = {0xC0FFED, 0xC0FFEE, + 0xC0FFEF}; +const uint32_t CallTest::kAudioSendSsrc = 0xDEADBEEF; +const uint32_t CallTest::kFlexfecSendSsrc = 0xBADBEEF; +const uint32_t CallTest::kReceiverLocalVideoSsrc = 0x123456; +const uint32_t CallTest::kReceiverLocalAudioSsrc = 0x1234567; +const int CallTest::kNackRtpHistoryMs = 1000; + +const uint8_t CallTest::kDefaultKeepalivePayloadType = + RtpKeepAliveConfig().payload_type; + +const std::map<uint8_t, MediaType> CallTest::payload_type_map_ = { + {CallTest::kVideoSendPayloadType, MediaType::VIDEO}, + {CallTest::kFakeVideoSendPayloadType, MediaType::VIDEO}, + {CallTest::kSendRtxPayloadType, MediaType::VIDEO}, + {CallTest::kRedPayloadType, MediaType::VIDEO}, + {CallTest::kRtxRedPayloadType, MediaType::VIDEO}, + {CallTest::kUlpfecPayloadType, MediaType::VIDEO}, + {CallTest::kFlexfecPayloadType, MediaType::VIDEO}, + {CallTest::kAudioSendPayloadType, MediaType::AUDIO}, + {CallTest::kDefaultKeepalivePayloadType, MediaType::ANY}}; + +BaseTest::BaseTest() : event_log_(RtcEventLog::CreateNull()) {} + +BaseTest::BaseTest(unsigned int timeout_ms) + : RtpRtcpObserver(timeout_ms), event_log_(RtcEventLog::CreateNull()) {} + +BaseTest::~BaseTest() { +} + +std::unique_ptr<FakeAudioDevice::Capturer> BaseTest::CreateCapturer() { + return FakeAudioDevice::CreatePulsedNoiseCapturer(256, 48000); +} + +std::unique_ptr<FakeAudioDevice::Renderer> BaseTest::CreateRenderer() { + return FakeAudioDevice::CreateDiscardRenderer(48000); +} + +void BaseTest::OnFakeAudioDevicesCreated(FakeAudioDevice* send_audio_device, + FakeAudioDevice* recv_audio_device) { +} + +Call::Config BaseTest::GetSenderCallConfig() { + return Call::Config(event_log_.get()); +} + +Call::Config BaseTest::GetReceiverCallConfig() { + return Call::Config(event_log_.get()); +} + +void BaseTest::OnRtpTransportControllerSendCreated( + RtpTransportControllerSend* controller) {} + +void BaseTest::OnCallsCreated(Call* sender_call, Call* receiver_call) { +} + +test::PacketTransport* BaseTest::CreateSendTransport( + SingleThreadedTaskQueueForTesting* task_queue, + Call* sender_call) { + return new PacketTransport( + task_queue, sender_call, this, test::PacketTransport::kSender, + CallTest::payload_type_map_, FakeNetworkPipe::Config()); +} + +test::PacketTransport* BaseTest::CreateReceiveTransport( + SingleThreadedTaskQueueForTesting* task_queue) { + return new PacketTransport( + task_queue, nullptr, this, test::PacketTransport::kReceiver, + CallTest::payload_type_map_, FakeNetworkPipe::Config()); +} + +size_t BaseTest::GetNumVideoStreams() const { + return 1; +} + +size_t BaseTest::GetNumAudioStreams() const { + return 0; +} + +size_t BaseTest::GetNumFlexfecStreams() const { + return 0; +} + +void BaseTest::ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config) {} + +void BaseTest::ModifyVideoCaptureStartResolution(int* width, + int* heigt, + int* frame_rate) {} + +void BaseTest::OnVideoStreamsCreated( + VideoSendStream* send_stream, + const std::vector<VideoReceiveStream*>& receive_streams) {} + +void BaseTest::ModifyAudioConfigs( + AudioSendStream::Config* send_config, + std::vector<AudioReceiveStream::Config>* receive_configs) {} + +void BaseTest::OnAudioStreamsCreated( + AudioSendStream* send_stream, + const std::vector<AudioReceiveStream*>& receive_streams) {} + +void BaseTest::ModifyFlexfecConfigs( + std::vector<FlexfecReceiveStream::Config>* receive_configs) {} + +void BaseTest::OnFlexfecStreamsCreated( + const std::vector<FlexfecReceiveStream*>& receive_streams) {} + +void BaseTest::OnFrameGeneratorCapturerCreated( + FrameGeneratorCapturer* frame_generator_capturer) { +} + +void BaseTest::OnStreamsStopped() { +} + +SendTest::SendTest(unsigned int timeout_ms) : BaseTest(timeout_ms) { +} + +bool SendTest::ShouldCreateReceivers() const { + return false; +} + +EndToEndTest::EndToEndTest() {} + +EndToEndTest::EndToEndTest(unsigned int timeout_ms) : BaseTest(timeout_ms) { +} + +bool EndToEndTest::ShouldCreateReceivers() const { + return true; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/call_test.h b/third_party/libwebrtc/webrtc/test/call_test.h new file mode 100644 index 0000000000..cf15aacf11 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/call_test.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_CALL_TEST_H_ +#define TEST_CALL_TEST_H_ + +#include <memory> +#include <vector> + +#include "call/call.h" +#include "call/rtp_transport_controller_send.h" +#include "logging/rtc_event_log/rtc_event_log.h" +#include "test/encoder_settings.h" +#include "test/fake_audio_device.h" +#include "test/fake_decoder.h" +#include "test/fake_encoder.h" +#include "test/fake_videorenderer.h" +#include "test/frame_generator_capturer.h" +#include "test/rtp_rtcp_observer.h" +#include "test/single_threaded_task_queue.h" + +namespace webrtc { + +class VoEBase; + +namespace test { + +class BaseTest; + +class CallTest : public ::testing::Test { + public: + CallTest(); + virtual ~CallTest(); + + static const size_t kNumSsrcs = 3; + static const int kDefaultWidth = 320; + static const int kDefaultHeight = 180; + static const int kDefaultFramerate = 30; + static const int kDefaultTimeoutMs; + static const int kLongTimeoutMs; + static const uint8_t kVideoSendPayloadType; + static const uint8_t kSendRtxPayloadType; + static const uint8_t kFakeVideoSendPayloadType; + static const uint8_t kRedPayloadType; + static const uint8_t kRtxRedPayloadType; + static const uint8_t kUlpfecPayloadType; + static const uint8_t kFlexfecPayloadType; + static const uint8_t kAudioSendPayloadType; + static const uint8_t kPayloadTypeH264; + static const uint8_t kPayloadTypeVP8; + static const uint8_t kPayloadTypeVP9; + static const uint32_t kSendRtxSsrcs[kNumSsrcs]; + static const uint32_t kVideoSendSsrcs[kNumSsrcs]; + static const uint32_t kAudioSendSsrc; + static const uint32_t kFlexfecSendSsrc; + static const uint32_t kReceiverLocalVideoSsrc; + static const uint32_t kReceiverLocalAudioSsrc; + static const int kNackRtpHistoryMs; + static const uint8_t kDefaultKeepalivePayloadType; + static const std::map<uint8_t, MediaType> payload_type_map_; + + protected: + // RunBaseTest overwrites the audio_state and the voice_engine of the send and + // receive Call configs to simplify test code and avoid having old VoiceEngine + // APIs in the tests. + void RunBaseTest(BaseTest* test); + + void CreateCalls(const Call::Config& sender_config, + const Call::Config& receiver_config); + void CreateSenderCall(const Call::Config& config); + void CreateReceiverCall(const Call::Config& config); + void DestroyCalls(); + + void CreateSendConfig(size_t num_video_streams, + size_t num_audio_streams, + size_t num_flexfec_streams, + Transport* send_transport); + + void CreateMatchingReceiveConfigs(Transport* rtcp_send_transport); + + void CreateFrameGeneratorCapturerWithDrift(Clock* drift_clock, + float speed, + int framerate, + int width, + int height); + void CreateFrameGeneratorCapturer(int framerate, int width, int height); + void CreateFakeAudioDevices( + std::unique_ptr<FakeAudioDevice::Capturer> capturer, + std::unique_ptr<FakeAudioDevice::Renderer> renderer); + + void CreateVideoStreams(); + void CreateAudioStreams(); + void CreateFlexfecStreams(); + + void AssociateFlexfecStreamsWithVideoStreams(); + void DissociateFlexfecStreamsFromVideoStreams(); + + void Start(); + void Stop(); + void DestroyStreams(); + void SetFakeVideoCaptureRotation(VideoRotation rotation); + + Clock* const clock_; + + std::unique_ptr<webrtc::RtcEventLog> event_log_; + std::unique_ptr<Call> sender_call_; + RtpTransportControllerSend* sender_call_transport_controller_; + std::unique_ptr<PacketTransport> send_transport_; + VideoSendStream::Config video_send_config_; + VideoEncoderConfig video_encoder_config_; + VideoSendStream* video_send_stream_; + AudioSendStream::Config audio_send_config_; + AudioSendStream* audio_send_stream_; + + std::unique_ptr<Call> receiver_call_; + std::unique_ptr<PacketTransport> receive_transport_; + std::vector<VideoReceiveStream::Config> video_receive_configs_; + std::vector<VideoReceiveStream*> video_receive_streams_; + std::vector<AudioReceiveStream::Config> audio_receive_configs_; + std::vector<AudioReceiveStream*> audio_receive_streams_; + std::vector<FlexfecReceiveStream::Config> flexfec_receive_configs_; + std::vector<FlexfecReceiveStream*> flexfec_receive_streams_; + + std::unique_ptr<test::FrameGeneratorCapturer> frame_generator_capturer_; + test::FakeEncoder fake_encoder_; + std::vector<std::unique_ptr<VideoDecoder>> allocated_decoders_; + size_t num_video_streams_; + size_t num_audio_streams_; + size_t num_flexfec_streams_; + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_; + rtc::scoped_refptr<AudioEncoderFactory> encoder_factory_; + test::FakeVideoRenderer fake_renderer_; + + SingleThreadedTaskQueueForTesting task_queue_; + + private: + // TODO(holmer): Remove once VoiceEngine is fully refactored to the new API. + // These methods are used to set up legacy voice engines and channels which is + // necessary while voice engine is being refactored to the new stream API. + struct VoiceEngineState { + VoiceEngineState() + : voice_engine(nullptr), + base(nullptr), + channel_id(-1) {} + + VoiceEngine* voice_engine; + VoEBase* base; + int channel_id; + }; + + void CreateVoiceEngines(); + void DestroyVoiceEngines(); + + VoiceEngineState voe_send_; + VoiceEngineState voe_recv_; + rtc::scoped_refptr<AudioProcessing> apm_send_; + rtc::scoped_refptr<AudioProcessing> apm_recv_; + + // The audio devices must outlive the voice engines. + std::unique_ptr<test::FakeAudioDevice> fake_send_audio_device_; + std::unique_ptr<test::FakeAudioDevice> fake_recv_audio_device_; +}; + +class BaseTest : public RtpRtcpObserver { + public: + BaseTest(); + explicit BaseTest(unsigned int timeout_ms); + virtual ~BaseTest(); + + virtual void PerformTest() = 0; + virtual bool ShouldCreateReceivers() const = 0; + + virtual size_t GetNumVideoStreams() const; + virtual size_t GetNumAudioStreams() const; + virtual size_t GetNumFlexfecStreams() const; + + virtual std::unique_ptr<FakeAudioDevice::Capturer> CreateCapturer(); + virtual std::unique_ptr<FakeAudioDevice::Renderer> CreateRenderer(); + virtual void OnFakeAudioDevicesCreated(FakeAudioDevice* send_audio_device, + FakeAudioDevice* recv_audio_device); + + virtual Call::Config GetSenderCallConfig(); + virtual Call::Config GetReceiverCallConfig(); + virtual void OnRtpTransportControllerSendCreated( + RtpTransportControllerSend* controller); + virtual void OnCallsCreated(Call* sender_call, Call* receiver_call); + + virtual test::PacketTransport* CreateSendTransport( + SingleThreadedTaskQueueForTesting* task_queue, + Call* sender_call); + virtual test::PacketTransport* CreateReceiveTransport( + SingleThreadedTaskQueueForTesting* task_queue); + + virtual void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector<VideoReceiveStream::Config>* receive_configs, + VideoEncoderConfig* encoder_config); + virtual void ModifyVideoCaptureStartResolution(int* width, + int* heigt, + int* frame_rate); + virtual void OnVideoStreamsCreated( + VideoSendStream* send_stream, + const std::vector<VideoReceiveStream*>& receive_streams); + + virtual void ModifyAudioConfigs( + AudioSendStream::Config* send_config, + std::vector<AudioReceiveStream::Config>* receive_configs); + virtual void OnAudioStreamsCreated( + AudioSendStream* send_stream, + const std::vector<AudioReceiveStream*>& receive_streams); + + virtual void ModifyFlexfecConfigs( + std::vector<FlexfecReceiveStream::Config>* receive_configs); + virtual void OnFlexfecStreamsCreated( + const std::vector<FlexfecReceiveStream*>& receive_streams); + + virtual void OnFrameGeneratorCapturerCreated( + FrameGeneratorCapturer* frame_generator_capturer); + + virtual void OnStreamsStopped(); + + std::unique_ptr<webrtc::RtcEventLog> event_log_; +}; + +class SendTest : public BaseTest { + public: + explicit SendTest(unsigned int timeout_ms); + + bool ShouldCreateReceivers() const override; +}; + +class EndToEndTest : public BaseTest { + public: + EndToEndTest(); + explicit EndToEndTest(unsigned int timeout_ms); + + bool ShouldCreateReceivers() const override; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_CALL_TEST_H_ diff --git a/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.cc b/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.cc new file mode 100644 index 0000000000..cbfb35bf33 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.cc @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/configurable_frame_size_encoder.h" + +#include <string.h> + +#include "common_video/include/video_frame.h" +#include "modules/video_coding/include/video_codec_interface.h" +#include "rtc_base/checks.h" +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +ConfigurableFrameSizeEncoder::ConfigurableFrameSizeEncoder( + size_t max_frame_size) + : callback_(NULL), + max_frame_size_(max_frame_size), + current_frame_size_(max_frame_size), + buffer_(new uint8_t[max_frame_size]) { + memset(buffer_.get(), 0, max_frame_size); +} + +ConfigurableFrameSizeEncoder::~ConfigurableFrameSizeEncoder() {} + +int32_t ConfigurableFrameSizeEncoder::InitEncode( + const VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) { + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::Encode( + const VideoFrame& inputImage, + const CodecSpecificInfo* codecSpecificInfo, + const std::vector<FrameType>* frame_types) { + EncodedImage encodedImage( + buffer_.get(), current_frame_size_, max_frame_size_); + encodedImage._completeFrame = true; + encodedImage._encodedHeight = inputImage.height(); + encodedImage._encodedWidth = inputImage.width(); + encodedImage._frameType = kVideoFrameKey; + encodedImage._timeStamp = inputImage.timestamp(); + encodedImage.capture_time_ms_ = inputImage.render_time_ms(); + RTPFragmentationHeader* fragmentation = NULL; + CodecSpecificInfo specific; + memset(&specific, 0, sizeof(specific)); + callback_->OnEncodedImage(encodedImage, &specific, fragmentation); + + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) { + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::Release() { + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::SetChannelParameters(uint32_t packet_loss, + int64_t rtt) { + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::SetRateAllocation( + const BitrateAllocation& allocation, + uint32_t framerate) { + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::SetPeriodicKeyFrames(bool enable) { + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t ConfigurableFrameSizeEncoder::SetFrameSize(size_t size) { + RTC_DCHECK_LE(size, max_frame_size_); + current_frame_size_ = size; + return WEBRTC_VIDEO_CODEC_OK; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.h b/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.h new file mode 100644 index 0000000000..8d3cbc65af --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/configurable_frame_size_encoder.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_ +#define TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_ + +#include <memory> +#include <vector> + +#include "api/video_codecs/video_encoder.h" + +namespace webrtc { +namespace test { + +class ConfigurableFrameSizeEncoder : public VideoEncoder { + public: + explicit ConfigurableFrameSizeEncoder(size_t max_frame_size); + virtual ~ConfigurableFrameSizeEncoder(); + + int32_t InitEncode(const VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) override; + + int32_t Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) override; + + int32_t RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) override; + + int32_t Release() override; + + int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; + + int32_t SetRateAllocation(const BitrateAllocation& allocation, + uint32_t framerate) override; + + int32_t SetPeriodicKeyFrames(bool enable) override; + + int32_t SetFrameSize(size_t size); + + private: + EncodedImageCallback* callback_; + const size_t max_frame_size_; + size_t current_frame_size_; + std::unique_ptr<uint8_t[]> buffer_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_ diff --git a/third_party/libwebrtc/webrtc/test/constants.cc b/third_party/libwebrtc/webrtc/test/constants.cc new file mode 100644 index 0000000000..0835777570 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/constants.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/constants.h" + +namespace webrtc { +namespace test { + +const int kAudioLevelExtensionId = 5; +const int kTOffsetExtensionId = 6; +const int kAbsSendTimeExtensionId = 7; +const int kTransportSequenceNumberExtensionId = 8; +const int kVideoRotationExtensionId = 9; +const int kVideoContentTypeExtensionId = 10; +const int kVideoTimingExtensionId = 11; + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/constants.h b/third_party/libwebrtc/webrtc/test/constants.h new file mode 100644 index 0000000000..85e8c18d53 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/constants.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +namespace webrtc { +namespace test { + +extern const int kAudioLevelExtensionId; +extern const int kTOffsetExtensionId; +extern const int kAbsSendTimeExtensionId; +extern const int kTransportSequenceNumberExtensionId; +extern const int kVideoRotationExtensionId; +extern const int kVideoContentTypeExtensionId; +extern const int kVideoTimingExtensionId; +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/direct_transport.cc b/third_party/libwebrtc/webrtc/test/direct_transport.cc new file mode 100644 index 0000000000..dddbe58909 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/direct_transport.cc @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/direct_transport.h" + +#include "call/call.h" +#include "rtc_base/ptr_util.h" +#include "system_wrappers/include/clock.h" +#include "test/single_threaded_task_queue.h" + +namespace webrtc { +namespace test { + +DirectTransport::DirectTransport( + SingleThreadedTaskQueueForTesting* task_queue, + Call* send_call, + const std::map<uint8_t, MediaType>& payload_type_map) + : DirectTransport(task_queue, + FakeNetworkPipe::Config(), + send_call, + payload_type_map) { +} + +DirectTransport::DirectTransport( + SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + const std::map<uint8_t, MediaType>& payload_type_map) + : DirectTransport( + task_queue, + config, + send_call, + std::unique_ptr<Demuxer>(new DemuxerImpl(payload_type_map))) { +} + +DirectTransport::DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + std::unique_ptr<Demuxer> demuxer) + : send_call_(send_call), + clock_(Clock::GetRealTimeClock()), + task_queue_(task_queue), + fake_network_(rtc::MakeUnique<FakeNetworkPipe>(clock_, config, + std::move(demuxer))) { + Start(); +} + +DirectTransport::DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + std::unique_ptr<FakeNetworkPipe> pipe, + Call* send_call) + : send_call_(send_call), + clock_(Clock::GetRealTimeClock()), + task_queue_(task_queue), + fake_network_(std::move(pipe)) { + Start(); +} + +DirectTransport::~DirectTransport() { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + // Constructor updates |next_scheduled_task_|, so it's guaranteed to + // be initialized. + task_queue_->CancelTask(next_scheduled_task_); +} + +void DirectTransport::SetConfig(const FakeNetworkPipe::Config& config) { + fake_network_->SetConfig(config); +} + +void DirectTransport::StopSending() { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + task_queue_->CancelTask(next_scheduled_task_); +} + +void DirectTransport::SetReceiver(PacketReceiver* receiver) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + fake_network_->SetReceiver(receiver); +} + +bool DirectTransport::SendRtp(const uint8_t* data, + size_t length, + const PacketOptions& options) { + if (send_call_) { + rtc::SentPacket sent_packet(options.packet_id, + clock_->TimeInMilliseconds()); + send_call_->OnSentPacket(sent_packet); + } + fake_network_->SendPacket(data, length); + return true; +} + +bool DirectTransport::SendRtcp(const uint8_t* data, size_t length) { + fake_network_->SendPacket(data, length); + return true; +} + +int DirectTransport::GetAverageDelayMs() { + return fake_network_->AverageDelay(); +} + +void DirectTransport::Start() { + RTC_DCHECK(task_queue_); + if (send_call_) { + send_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp); + send_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp); + } + SendPackets(); +} + +void DirectTransport::SendPackets() { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + fake_network_->Process(); + + int64_t delay_ms = fake_network_->TimeUntilNextProcess(); + next_scheduled_task_ = task_queue_->PostDelayedTask([this]() { + SendPackets(); + }, delay_ms); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/direct_transport.h b/third_party/libwebrtc/webrtc/test/direct_transport.h new file mode 100644 index 0000000000..85cd892ec2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/direct_transport.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_DIRECT_TRANSPORT_H_ +#define TEST_DIRECT_TRANSPORT_H_ + +#include <assert.h> + +#include <memory> + +#include "api/call/transport.h" +#include "call/call.h" +#include "rtc_base/sequenced_task_checker.h" +#include "rtc_base/thread_annotations.h" +#include "test/fake_network_pipe.h" +#include "test/single_threaded_task_queue.h" + +namespace webrtc { + +class Clock; +class PacketReceiver; + +namespace test { + +// Objects of this class are expected to be allocated and destroyed on the +// same task-queue - the one that's passed in via the constructor. +class DirectTransport : public Transport { + public: + DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + Call* send_call, + const std::map<uint8_t, MediaType>& payload_type_map); + + DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + const std::map<uint8_t, MediaType>& payload_type_map); + + DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + std::unique_ptr<Demuxer> demuxer); + + DirectTransport(SingleThreadedTaskQueueForTesting* task_queue, + std::unique_ptr<FakeNetworkPipe> pipe, Call* send_call); + + ~DirectTransport() override; + + void SetConfig(const FakeNetworkPipe::Config& config); + + RTC_DEPRECATED void StopSending(); + + // TODO(holmer): Look into moving this to the constructor. + virtual void SetReceiver(PacketReceiver* receiver); + + bool SendRtp(const uint8_t* data, + size_t length, + const PacketOptions& options) override; + bool SendRtcp(const uint8_t* data, size_t length) override; + + int GetAverageDelayMs(); + + private: + void SendPackets(); + void Start(); + + Call* const send_call_; + Clock* const clock_; + + SingleThreadedTaskQueueForTesting* const task_queue_; + SingleThreadedTaskQueueForTesting::TaskId next_scheduled_task_ + RTC_GUARDED_BY(&sequence_checker_); + + std::unique_ptr<FakeNetworkPipe> fake_network_; + + rtc::SequencedTaskChecker sequence_checker_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_DIRECT_TRANSPORT_H_ diff --git a/third_party/libwebrtc/webrtc/test/drifting_clock.cc b/third_party/libwebrtc/webrtc/test/drifting_clock.cc new file mode 100644 index 0000000000..5333e1de15 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/drifting_clock.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/drifting_clock.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { +const float DriftingClock::kDoubleSpeed = 2.0f; +const float DriftingClock::kNoDrift = 1.0f; +const float DriftingClock::kHalfSpeed = 0.5f; + +DriftingClock::DriftingClock(Clock* clock, float speed) + : clock_(clock), + drift_(speed - 1.0f), + start_time_(clock_->TimeInMicroseconds()) { + RTC_CHECK(clock); + RTC_CHECK_GT(speed, 0.0f); +} + +float DriftingClock::Drift() const { + int64_t now = clock_->TimeInMicroseconds(); + RTC_DCHECK_GE(now, start_time_); + return (now - start_time_) * drift_; +} + +int64_t DriftingClock::TimeInMilliseconds() const { + return clock_->TimeInMilliseconds() + Drift() / 1000.; +} + +int64_t DriftingClock::TimeInMicroseconds() const { + return clock_->TimeInMicroseconds() + Drift(); +} + +NtpTime DriftingClock::CurrentNtpTime() const { + // NTP precision is 1/2^32 seconds, i.e. 2^32 ntp fractions = 1 second. + const double kNtpFracPerMicroSecond = 4294.967296; // = 2^32 / 10^6 + + NtpTime ntp = clock_->CurrentNtpTime(); + uint64_t total_fractions = static_cast<uint64_t>(ntp); + total_fractions += Drift() * kNtpFracPerMicroSecond; + return NtpTime(total_fractions); +} + +int64_t DriftingClock::CurrentNtpInMilliseconds() const { + return clock_->CurrentNtpInMilliseconds() + Drift() / 1000.; +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/drifting_clock.h b/third_party/libwebrtc/webrtc/test/drifting_clock.h new file mode 100644 index 0000000000..a0ba93edf0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/drifting_clock.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_DRIFTING_CLOCK_H_ +#define TEST_DRIFTING_CLOCK_H_ + +#include "system_wrappers/include/clock.h" + +namespace webrtc { +namespace test { +class DriftingClock : public Clock { + public: + // TODO(danilchap): Make this constants constexpr when it would be supported. + static const float kDoubleSpeed; // 2.0f; + static const float kNoDrift; // 1.0f; + static const float kHalfSpeed; // 0.5f; + + DriftingClock(Clock* clock, float speed); + + // TODO(danilchap): Make this functions constexpr when it would be supported. + static float PercentsFaster(float percent) { return 1.0f + percent / 100.0f; } + static float PercentsSlower(float percent) { return 1.0f - percent / 100.0f; } + + int64_t TimeInMilliseconds() const override; + int64_t TimeInMicroseconds() const override; + NtpTime CurrentNtpTime() const override; + int64_t CurrentNtpInMilliseconds() const override; + + private: + float Drift() const; + + Clock* const clock_; + const float drift_; + const int64_t start_time_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_DRIFTING_CLOCK_H_ diff --git a/third_party/libwebrtc/webrtc/test/encoder_settings.cc b/third_party/libwebrtc/webrtc/test/encoder_settings.cc new file mode 100644 index 0000000000..bd700cf6d2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/encoder_settings.cc @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/encoder_settings.h" + +#include <algorithm> +#include <string> + +#include "modules/video_coding/codecs/h264/include/h264.h" +#include "modules/video_coding/codecs/vp8/include/vp8.h" +#include "modules/video_coding/codecs/vp9/include/vp9.h" +#include "rtc_base/refcountedobject.h" +#include "test/fake_decoder.h" + +namespace webrtc { +namespace test { + +const size_t DefaultVideoStreamFactory::kMaxNumberOfStreams; +const int DefaultVideoStreamFactory::kMaxBitratePerStream[] = {150000, 450000, + 1500000}; +const int DefaultVideoStreamFactory::kDefaultMinBitratePerStream[] = { + 30000, 200000, 700000}; + +// static +std::vector<VideoStream> CreateVideoStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config) { + RTC_DCHECK(encoder_config.number_of_streams <= + DefaultVideoStreamFactory::kMaxNumberOfStreams); + + std::vector<VideoStream> stream_settings(encoder_config.number_of_streams); + int bitrate_left_bps = encoder_config.max_bitrate_bps; + + for (size_t i = 0; i < encoder_config.number_of_streams; ++i) { + stream_settings[i].width = + (i + 1) * width / encoder_config.number_of_streams; + stream_settings[i].height = + (i + 1) * height / encoder_config.number_of_streams; + stream_settings[i].max_framerate = 30; + stream_settings[i].min_bitrate_bps = + DefaultVideoStreamFactory::kDefaultMinBitratePerStream[i]; + stream_settings[i].target_bitrate_bps = stream_settings[i].max_bitrate_bps = + std::min(bitrate_left_bps, + DefaultVideoStreamFactory::kMaxBitratePerStream[i]); + stream_settings[i].max_qp = 56; + bitrate_left_bps -= stream_settings[i].target_bitrate_bps; + } + + stream_settings[encoder_config.number_of_streams - 1].max_bitrate_bps += + bitrate_left_bps; + + return stream_settings; +} + +DefaultVideoStreamFactory::DefaultVideoStreamFactory() {} + +std::vector<VideoStream> DefaultVideoStreamFactory::CreateEncoderStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config) { + return CreateVideoStreams(width, height, encoder_config); +} + +void FillEncoderConfiguration(size_t num_streams, + VideoEncoderConfig* configuration) { + RTC_DCHECK_LE(num_streams, DefaultVideoStreamFactory::kMaxNumberOfStreams); + + configuration->number_of_streams = num_streams; + configuration->video_stream_factory = + new rtc::RefCountedObject<DefaultVideoStreamFactory>(); + configuration->max_bitrate_bps = 0; + for (size_t i = 0; i < num_streams; ++i) { + configuration->max_bitrate_bps += + DefaultVideoStreamFactory::kMaxBitratePerStream[i]; + } +} + +VideoReceiveStream::Decoder CreateMatchingDecoder( + const VideoSendStream::Config::EncoderSettings& encoder_settings) { + VideoReceiveStream::Decoder decoder; + decoder.payload_type = encoder_settings.payload_type; + decoder.payload_name = encoder_settings.payload_name; + if (encoder_settings.payload_name == "H264") { + decoder.decoder = H264Decoder::Create().release(); + } else if (encoder_settings.payload_name == "VP8") { + decoder.decoder = VP8Decoder::Create().release(); + } else if (encoder_settings.payload_name == "VP9") { + decoder.decoder = VP9Decoder::Create().release(); + } else { + decoder.decoder = new FakeDecoder(); + } + return decoder; +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/encoder_settings.h b/third_party/libwebrtc/webrtc/test/encoder_settings.h new file mode 100644 index 0000000000..25cfa29897 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/encoder_settings.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_ENCODER_SETTINGS_H_ +#define TEST_ENCODER_SETTINGS_H_ + +#include <vector> + +#include "call/video_receive_stream.h" +#include "call/video_send_stream.h" + +namespace webrtc { +namespace test { + +class DefaultVideoStreamFactory + : public VideoEncoderConfig::VideoStreamFactoryInterface { + public: + DefaultVideoStreamFactory(); + + static const size_t kMaxNumberOfStreams = 3; + // Defined as {150000, 450000, 1500000}; + static const int kMaxBitratePerStream[]; + // Defined as {50000, 200000, 700000}; + static const int kDefaultMinBitratePerStream[]; + + private: + std::vector<VideoStream> CreateEncoderStreams( + int width, + int height, + const VideoEncoderConfig& encoder_config) override; +}; + +// Creates |encoder_config.number_of_streams| VideoStreams where index +// |encoder_config.number_of_streams -1| have width = |width|, height = +// |height|. The total max bitrate of all VideoStreams is +// |encoder_config.max_bitrate_bps|. +std::vector<VideoStream> CreateVideoStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config); + +void FillEncoderConfiguration(size_t num_streams, + VideoEncoderConfig* configuration); + +VideoReceiveStream::Decoder CreateMatchingDecoder( + const VideoSendStream::Config::EncoderSettings& encoder_settings); +} // namespace test +} // namespace webrtc + +#endif // TEST_ENCODER_SETTINGS_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_audio_device.cc b/third_party/libwebrtc/webrtc/test/fake_audio_device.cc new file mode 100644 index 0000000000..eef8bfd015 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_audio_device.cc @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fake_audio_device.h" + +#include <algorithm> +#include <utility> + +#include "common_audio/wav_file.h" +#include "rtc_base/checks.h" +#include "rtc_base/random.h" +#include "system_wrappers/include/event_wrapper.h" + +namespace webrtc { + +namespace { + +constexpr int kFrameLengthMs = 10; +constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; + +// Assuming 10ms audio packets.. +class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer { + public: + PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + fill_with_zero_(false), + random_generator_(1), + max_amplitude_(max_amplitude) { + RTC_DCHECK_GT(max_amplitude, 0); + } + + int SamplingFrequency() const override { + return sampling_frequency_in_hz_; + } + + bool Capture(rtc::BufferT<int16_t>* buffer) override { + fill_with_zero_ = !fill_with_zero_; + buffer->SetData( + test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), + [&](rtc::ArrayView<int16_t> data) { + if (fill_with_zero_) { + std::fill(data.begin(), data.end(), 0); + } else { + std::generate(data.begin(), data.end(), [&]() { + return random_generator_.Rand(-max_amplitude_, max_amplitude_); + }); + } + return data.size(); + }); + return true; + } + + private: + int sampling_frequency_in_hz_; + bool fill_with_zero_; + Random random_generator_; + const int16_t max_amplitude_; +}; + +class WavFileReader final : public test::FakeAudioDevice::Capturer { + public: + WavFileReader(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_reader_(filename) { + RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); + RTC_CHECK_EQ(wav_reader_.num_channels(), 1); + } + + int SamplingFrequency() const override { + return sampling_frequency_in_hz_; + } + + bool Capture(rtc::BufferT<int16_t>* buffer) override { + buffer->SetData( + test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), + [&](rtc::ArrayView<int16_t> data) { + return wav_reader_.ReadSamples(data.size(), data.data()); + }); + return buffer->size() > 0; + } + + private: + int sampling_frequency_in_hz_; + WavReader wav_reader_; +}; + +class WavFileWriter final : public test::FakeAudioDevice::Renderer { + public: + WavFileWriter(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(filename, sampling_frequency_in_hz, 1) {} + + int SamplingFrequency() const override { + return sampling_frequency_in_hz_; + } + + bool Render(rtc::ArrayView<const int16_t> data) override { + wav_writer_.WriteSamples(data.data(), data.size()); + return true; + } + + private: + int sampling_frequency_in_hz_; + WavWriter wav_writer_; +}; + +class BoundedWavFileWriter : public test::FakeAudioDevice::Renderer { + public: + BoundedWavFileWriter(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(filename, sampling_frequency_in_hz, 1), + silent_audio_(test::FakeAudioDevice::SamplesPerFrame( + sampling_frequency_in_hz), 0), + started_writing_(false), + trailing_zeros_(0) {} + + int SamplingFrequency() const override { + return sampling_frequency_in_hz_; + } + + bool Render(rtc::ArrayView<const int16_t> data) override { + const int16_t kAmplitudeThreshold = 5; + + const int16_t* begin = data.begin(); + const int16_t* end = data.end(); + if (!started_writing_) { + // Cut off silence at the beginning. + while (begin < end) { + if (std::abs(*begin) > kAmplitudeThreshold) { + started_writing_ = true; + break; + } + ++begin; + } + } + if (started_writing_) { + // Cut off silence at the end. + while (begin < end) { + if (*(end - 1) != 0) { + break; + } + --end; + } + if (begin < end) { + // If it turns out that the silence was not final, need to write all the + // skipped zeros and continue writing audio. + while (trailing_zeros_ > 0) { + const size_t zeros_to_write = std::min(trailing_zeros_, + silent_audio_.size()); + wav_writer_.WriteSamples(silent_audio_.data(), zeros_to_write); + trailing_zeros_ -= zeros_to_write; + } + wav_writer_.WriteSamples(begin, end - begin); + } + // Save the number of zeros we skipped in case this needs to be restored. + trailing_zeros_ += data.end() - end; + } + return true; + } + + private: + int sampling_frequency_in_hz_; + WavWriter wav_writer_; + std::vector<int16_t> silent_audio_; + bool started_writing_; + size_t trailing_zeros_; +}; + + +class DiscardRenderer final : public test::FakeAudioDevice::Renderer { + public: + explicit DiscardRenderer(int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz) {} + + int SamplingFrequency() const override { + return sampling_frequency_in_hz_; + } + + bool Render(rtc::ArrayView<const int16_t> data) override { + return true; + } + + private: + int sampling_frequency_in_hz_; +}; + +} // namespace +namespace test { + +size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) { + return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond); +} + +std::unique_ptr<FakeAudioDevice::Capturer> + FakeAudioDevice::CreatePulsedNoiseCapturer( + int16_t max_amplitude, int sampling_frequency_in_hz) { + return std::unique_ptr<FakeAudioDevice::Capturer>( + new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz)); +} + +std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( + std::string filename, int sampling_frequency_in_hz) { + return std::unique_ptr<FakeAudioDevice::Capturer>( + new WavFileReader(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( + std::string filename) { + int sampling_frequency_in_hz = WavReader(filename).sample_rate(); + return std::unique_ptr<FakeAudioDevice::Capturer>( + new WavFileReader(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter( + std::string filename, int sampling_frequency_in_hz) { + return std::unique_ptr<FakeAudioDevice::Renderer>( + new WavFileWriter(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr<FakeAudioDevice::Renderer> + FakeAudioDevice::CreateBoundedWavFileWriter( + std::string filename, int sampling_frequency_in_hz) { + return std::unique_ptr<FakeAudioDevice::Renderer>( + new BoundedWavFileWriter(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr<FakeAudioDevice::Renderer> + FakeAudioDevice::CreateDiscardRenderer(int sampling_frequency_in_hz) { + return std::unique_ptr<FakeAudioDevice::Renderer>( + new DiscardRenderer(sampling_frequency_in_hz)); +} + + +FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer, + std::unique_ptr<Renderer> renderer, + float speed) + : capturer_(std::move(capturer)), + renderer_(std::move(renderer)), + speed_(speed), + audio_callback_(nullptr), + rendering_(false), + capturing_(false), + done_rendering_(true, true), + done_capturing_(true, true), + tick_(EventTimerWrapper::Create()), + thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { + auto good_sample_rate = [](int sr) { + return sr == 8000 || sr == 16000 || sr == 32000 + || sr == 44100 || sr == 48000; + }; + + if (renderer_) { + const int sample_rate = renderer_->SamplingFrequency(); + playout_buffer_.resize(SamplesPerFrame(sample_rate), 0); + RTC_CHECK(good_sample_rate(sample_rate)); + } + if (capturer_) { + RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency())); + } +} + +FakeAudioDevice::~FakeAudioDevice() { + StopPlayout(); + StopRecording(); + thread_.Stop(); +} + +int32_t FakeAudioDevice::StartPlayout() { + rtc::CritScope cs(&lock_); + RTC_CHECK(renderer_); + rendering_ = true; + done_rendering_.Reset(); + return 0; +} + +int32_t FakeAudioDevice::StopPlayout() { + rtc::CritScope cs(&lock_); + rendering_ = false; + done_rendering_.Set(); + return 0; +} + +int32_t FakeAudioDevice::StartRecording() { + rtc::CritScope cs(&lock_); + RTC_CHECK(capturer_); + capturing_ = true; + done_capturing_.Reset(); + return 0; +} + +int32_t FakeAudioDevice::StopRecording() { + rtc::CritScope cs(&lock_); + capturing_ = false; + done_capturing_.Set(); + return 0; +} + +int32_t FakeAudioDevice::Init() { + RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); + thread_.Start(); + thread_.SetPriority(rtc::kHighPriority); + return 0; +} + +int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { + rtc::CritScope cs(&lock_); + RTC_DCHECK(callback || audio_callback_); + audio_callback_ = callback; + return 0; +} + +bool FakeAudioDevice::Playing() const { + rtc::CritScope cs(&lock_); + return rendering_; +} + +bool FakeAudioDevice::Recording() const { + rtc::CritScope cs(&lock_); + return capturing_; +} + +bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) { + return done_rendering_.Wait(timeout_ms); +} + +bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) { + return done_capturing_.Wait(timeout_ms); +} + +bool FakeAudioDevice::Run(void* obj) { + static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); + return true; +} + +void FakeAudioDevice::ProcessAudio() { + { + rtc::CritScope cs(&lock_); + if (capturing_) { + // Capture 10ms of audio. 2 bytes per sample. + const bool keep_capturing = capturer_->Capture(&recording_buffer_); + uint32_t new_mic_level; + if (recording_buffer_.size() > 0) { + audio_callback_->RecordedDataIsAvailable( + recording_buffer_.data(), recording_buffer_.size(), 2, 1, + capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level); + } + if (!keep_capturing) { + capturing_ = false; + done_capturing_.Set(); + } + } + if (rendering_) { + size_t samples_out; + int64_t elapsed_time_ms; + int64_t ntp_time_ms; + const int sampling_frequency = renderer_->SamplingFrequency(); + audio_callback_->NeedMorePlayData( + SamplesPerFrame(sampling_frequency), 2, 1, sampling_frequency, + playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); + const bool keep_rendering = renderer_->Render( + rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); + if (!keep_rendering) { + rendering_ = false; + done_rendering_.Set(); + } + } + } + tick_->Wait(WEBRTC_EVENT_INFINITE); +} + + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_audio_device.h b/third_party/libwebrtc/webrtc/test/fake_audio_device.h new file mode 100644 index 0000000000..f71fd016d9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_audio_device.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_FAKE_AUDIO_DEVICE_H_ +#define TEST_FAKE_AUDIO_DEVICE_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "api/array_view.h" +#include "modules/audio_device/include/fake_audio_device.h" +#include "rtc_base/buffer.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class EventTimerWrapper; + +namespace test { + +// FakeAudioDevice implements an AudioDevice module that can act both as a +// capturer and a renderer. It will use 10ms audio frames. +class FakeAudioDevice : public FakeAudioDeviceModule { + public: + // Returns the number of samples that Capturers and Renderers with this + // sampling frequency will work with every time Capture or Render is called. + static size_t SamplesPerFrame(int sampling_frequency_in_hz); + + class Capturer { + public: + virtual ~Capturer() {} + // Returns the sampling frequency in Hz of the audio data that this + // capturer produces. + virtual int SamplingFrequency() const = 0; + // Replaces the contents of |buffer| with 10ms of captured audio data + // (see FakeAudioDevice::SamplesPerFrame). Returns true if the capturer can + // keep producing data, or false when the capture finishes. + virtual bool Capture(rtc::BufferT<int16_t>* buffer) = 0; + }; + + class Renderer { + public: + virtual ~Renderer() {} + // Returns the sampling frequency in Hz of the audio data that this + // renderer receives. + virtual int SamplingFrequency() const = 0; + // Renders the passed audio data and returns true if the renderer wants + // to keep receiving data, or false otherwise. + virtual bool Render(rtc::ArrayView<const int16_t> data) = 0; + }; + + // Creates a new FakeAudioDevice. When capturing or playing, 10 ms audio + // frames will be processed every 10ms / |speed|. + // |capturer| is an object that produces audio data. Can be nullptr if this + // device is never used for recording. + // |renderer| is an object that receives audio data that would have been + // played out. Can be nullptr if this device is never used for playing. + // Use one of the Create... functions to get these instances. + FakeAudioDevice(std::unique_ptr<Capturer> capturer, + std::unique_ptr<Renderer> renderer, + float speed = 1); + ~FakeAudioDevice() override; + + // Returns a Capturer instance that generates a signal where every second + // frame is zero and every second frame is evenly distributed random noise + // with max amplitude |max_amplitude|. + static std::unique_ptr<Capturer> CreatePulsedNoiseCapturer( + int16_t max_amplitude, int sampling_frequency_in_hz); + + // Returns a Capturer instance that gets its data from a file. + static std::unique_ptr<Capturer> CreateWavFileReader( + std::string filename, int sampling_frequency_in_hz); + + // Returns a Capturer instance that gets its data from a file. + // Automatically detects sample rate. + static std::unique_ptr<Capturer> CreateWavFileReader(std::string filename); + + // Returns a Renderer instance that writes its data to a file. + static std::unique_ptr<Renderer> CreateWavFileWriter( + std::string filename, int sampling_frequency_in_hz); + + // Returns a Renderer instance that writes its data to a WAV file, cutting + // off silence at the beginning (not necessarily perfect silence, see + // kAmplitudeThreshold) and at the end (only actual 0 samples in this case). + static std::unique_ptr<Renderer> CreateBoundedWavFileWriter( + std::string filename, int sampling_frequency_in_hz); + + // Returns a Renderer instance that does nothing with the audio data. + static std::unique_ptr<Renderer> CreateDiscardRenderer( + int sampling_frequency_in_hz); + + int32_t Init() override; + int32_t RegisterAudioCallback(AudioTransport* callback) override; + + int32_t StartPlayout() override; + int32_t StopPlayout() override; + int32_t StartRecording() override; + int32_t StopRecording() override; + + bool Playing() const override; + bool Recording() const override; + + // Blocks until the Renderer refuses to receive data. + // Returns false if |timeout_ms| passes before that happens. + bool WaitForPlayoutEnd(int timeout_ms = rtc::Event::kForever); + // Blocks until the Recorder stops producing data. + // Returns false if |timeout_ms| passes before that happens. + bool WaitForRecordingEnd(int timeout_ms = rtc::Event::kForever); + + private: + static bool Run(void* obj); + void ProcessAudio(); + + const std::unique_ptr<Capturer> capturer_ RTC_GUARDED_BY(lock_); + const std::unique_ptr<Renderer> renderer_ RTC_GUARDED_BY(lock_); + const float speed_; + + rtc::CriticalSection lock_; + AudioTransport* audio_callback_ RTC_GUARDED_BY(lock_); + bool rendering_ RTC_GUARDED_BY(lock_); + bool capturing_ RTC_GUARDED_BY(lock_); + rtc::Event done_rendering_; + rtc::Event done_capturing_; + + std::vector<int16_t> playout_buffer_ RTC_GUARDED_BY(lock_); + rtc::BufferT<int16_t> recording_buffer_ RTC_GUARDED_BY(lock_); + + std::unique_ptr<EventTimerWrapper> tick_; + rtc::PlatformThread thread_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_FAKE_AUDIO_DEVICE_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_audio_device_unittest.cc b/third_party/libwebrtc/webrtc/test/fake_audio_device_unittest.cc new file mode 100644 index 0000000000..02ece3cd85 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_audio_device_unittest.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> +#include <array> + +#include "common_audio/wav_file.h" +#include "common_audio/wav_header.h" +#include "test/fake_audio_device.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { +namespace test { + +namespace { +void RunTest(const std::vector<int16_t>& input_samples, + const std::vector<int16_t>& expected_samples, + size_t samples_per_frame) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + const std::string output_filename = test::OutputPath() + + "BoundedWavFileWriterTest_" + test_info->name() + ".wav"; + + static const size_t kSamplesPerFrame = 8; + static const int kSampleRate = kSamplesPerFrame * 100; + EXPECT_EQ(FakeAudioDevice::SamplesPerFrame(kSampleRate), kSamplesPerFrame); + + { + std::unique_ptr<FakeAudioDevice::Renderer> writer = + FakeAudioDevice::CreateBoundedWavFileWriter(output_filename, 800); + + for (size_t i = 0; i < input_samples.size(); i += kSamplesPerFrame) { + EXPECT_TRUE(writer->Render(rtc::ArrayView<const int16_t>( + &input_samples[i], + std::min(kSamplesPerFrame, input_samples.size() - i)))); + } + } + + { + WavReader reader(output_filename); + std::vector<int16_t> read_samples(expected_samples.size()); + EXPECT_EQ(expected_samples.size(), + reader.ReadSamples(read_samples.size(), read_samples.data())); + EXPECT_EQ(expected_samples, read_samples); + + EXPECT_EQ(0u, reader.ReadSamples(read_samples.size(), read_samples.data())); + } + + remove(output_filename.c_str()); +} +} // namespace + +TEST(BoundedWavFileWriterTest, NoSilence) { + static const std::vector<int16_t> kInputSamples = { + 75, 1234, 243, -1231, -22222, 0, 3, 88, + 1222, -1213, -13222, -7, -3525, 5787, -25247, 8 + }; + static const std::vector<int16_t> kExpectedSamples = kInputSamples; + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, SomeStartSilence) { + static const std::vector<int16_t> kInputSamples = { + 0, 0, 0, 0, 3, 0, 0, 0, + 0, 3, -13222, -7, -3525, 5787, -25247, 8 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 10, + kInputSamples.end()); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, NegativeStartSilence) { + static const std::vector<int16_t> kInputSamples = { + 0, -4, -6, 0, 3, 0, 0, 0, + 0, 3, -13222, -7, -3525, 5787, -25247, 8 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 2, + kInputSamples.end()); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, SomeEndSilence) { + static const std::vector<int16_t> kInputSamples = { + 75, 1234, 243, -1231, -22222, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(), + kInputSamples.end() - 9); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, DoubleEndSilence) { + static const std::vector<int16_t> kInputSamples = { + 75, 1234, 243, -1231, -22222, 0, 0, 0, + 0, -1213, -13222, -7, -3525, 5787, 0, 0 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(), + kInputSamples.end() - 2); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, DoubleSilence) { + static const std::vector<int16_t> kInputSamples = { + 0, -1213, -13222, -7, -3525, 5787, 0, 0 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin() + 1, + kInputSamples.end() - 2); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +TEST(BoundedWavFileWriterTest, EndSilenceCutoff) { + static const std::vector<int16_t> kInputSamples = { + 75, 1234, 243, -1231, -22222, 0, 1, 0, + 0, 0, 0 + }; + static const std::vector<int16_t> kExpectedSamples(kInputSamples.begin(), + kInputSamples.end() - 4); + RunTest(kInputSamples, kExpectedSamples, 8); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_decoder.cc b/third_party/libwebrtc/webrtc/test/fake_decoder.cc new file mode 100644 index 0000000000..fe8aef7167 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_decoder.cc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fake_decoder.h" + +#include "api/video/i420_buffer.h" +#include "rtc_base/timeutils.h" +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +FakeDecoder::FakeDecoder() : callback_(NULL) {} + +int32_t FakeDecoder::InitDecode(const VideoCodec* config, + int32_t number_of_cores) { + config_ = *config; + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t FakeDecoder::Decode(const EncodedImage& input, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t render_time_ms) { + VideoFrame frame(I420Buffer::Create(config_.width, config_.height), + webrtc::kVideoRotation_0, + render_time_ms * rtc::kNumMicrosecsPerMillisec); + frame.set_timestamp(input._timeStamp); + frame.set_ntp_time_ms(input.ntp_time_ms_); + + callback_->Decoded(frame); + + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t FakeDecoder::RegisterDecodeCompleteCallback( + DecodedImageCallback* callback) { + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t FakeDecoder::Release() { + return WEBRTC_VIDEO_CODEC_OK; +} + +const char* FakeDecoder::kImplementationName = "fake_decoder"; +const char* FakeDecoder::ImplementationName() const { + return kImplementationName; +} + +int32_t FakeH264Decoder::Decode(const EncodedImage& input, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t render_time_ms) { + uint8_t value = 0; + for (size_t i = 0; i < input._length; ++i) { + uint8_t kStartCode[] = {0, 0, 0, 1}; + if (i < input._length - sizeof(kStartCode) && + !memcmp(&input._buffer[i], kStartCode, sizeof(kStartCode))) { + i += sizeof(kStartCode) + 1; // Skip start code and NAL header. + } + if (input._buffer[i] != value) { + EXPECT_EQ(value, input._buffer[i]) + << "Bitstream mismatch between sender and receiver."; + return -1; + } + ++value; + } + return FakeDecoder::Decode(input, + missing_frames, + fragmentation, + codec_specific_info, + render_time_ms); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_decoder.h b/third_party/libwebrtc/webrtc/test/fake_decoder.h new file mode 100644 index 0000000000..61dacf065f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_decoder.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FAKE_DECODER_H_ +#define TEST_FAKE_DECODER_H_ + +#include <vector> + +#include "modules/video_coding/include/video_codec_interface.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { +namespace test { + +class FakeDecoder : public VideoDecoder { + public: + FakeDecoder(); + virtual ~FakeDecoder() {} + + int32_t InitDecode(const VideoCodec* config, + int32_t number_of_cores) override; + + int32_t Decode(const EncodedImage& input, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t render_time_ms) override; + + int32_t RegisterDecodeCompleteCallback( + DecodedImageCallback* callback) override; + + int32_t Release() override; + + const char* ImplementationName() const override; + + static const char* kImplementationName; + + private: + VideoCodec config_; + DecodedImageCallback* callback_; +}; + +class FakeH264Decoder : public FakeDecoder { + public: + virtual ~FakeH264Decoder() {} + + int32_t Decode(const EncodedImage& input, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t render_time_ms) override; +}; + +class FakeNullDecoder : public FakeDecoder { + public: + virtual ~FakeNullDecoder() {} + + int32_t Decode(const EncodedImage& input, + bool missing_frames, + const RTPFragmentationHeader* fragmentation, + const CodecSpecificInfo* codec_specific_info, + int64_t render_time_ms) override { + return 0; + } +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_FAKE_DECODER_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_encoder.cc b/third_party/libwebrtc/webrtc/test/fake_encoder.cc new file mode 100644 index 0000000000..a7dbbd9048 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_encoder.cc @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fake_encoder.h" + +#include <string.h> + +#include <algorithm> +#include <memory> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/video_coding/include/video_codec_interface.h" +#include "rtc_base/checks.h" +#include "system_wrappers/include/sleep.h" +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +const int kKeyframeSizeFactor = 10; + +FakeEncoder::FakeEncoder(Clock* clock) + : clock_(clock), + callback_(nullptr), + configured_input_framerate_(-1), + max_target_bitrate_kbps_(-1), + pending_keyframe_(true), + debt_bytes_(0) { + // Generate some arbitrary not-all-zero data + for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) { + encoded_buffer_[i] = static_cast<uint8_t>(i); + } +} + +void FakeEncoder::SetMaxBitrate(int max_kbps) { + RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it. + rtc::CritScope cs(&crit_sect_); + max_target_bitrate_kbps_ = max_kbps; +} + +int32_t FakeEncoder::InitEncode(const VideoCodec* config, + int32_t number_of_cores, + size_t max_payload_size) { + rtc::CritScope cs(&crit_sect_); + config_ = *config; + target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000); + configured_input_framerate_ = config_.maxFramerate; + pending_keyframe_ = true; + return 0; +} + +int32_t FakeEncoder::Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) { + unsigned char max_framerate; + unsigned char num_simulcast_streams; + SimulcastStream simulcast_streams[kMaxSimulcastStreams]; + EncodedImageCallback* callback; + uint32_t target_bitrate_sum_kbps; + int max_target_bitrate_kbps; + size_t num_encoded_bytes; + int framerate; + VideoCodecMode mode; + bool keyframe; + { + rtc::CritScope cs(&crit_sect_); + max_framerate = config_.maxFramerate; + num_simulcast_streams = config_.numberOfSimulcastStreams; + for (int i = 0; i < num_simulcast_streams; ++i) { + simulcast_streams[i] = config_.simulcastStream[i]; + } + callback = callback_; + target_bitrate_sum_kbps = target_bitrate_.get_sum_kbps(); + max_target_bitrate_kbps = max_target_bitrate_kbps_; + num_encoded_bytes = sizeof(encoded_buffer_); + mode = config_.mode; + if (configured_input_framerate_ > 0) { + framerate = configured_input_framerate_; + } else { + framerate = max_framerate; + } + keyframe = pending_keyframe_; + pending_keyframe_ = false; + } + + for (FrameType frame_type : *frame_types) { + if (frame_type == kVideoFrameKey) { + keyframe = true; + break; + } + } + + RTC_DCHECK_GT(max_framerate, 0); + + size_t bitrate = + std::max(target_bitrate_sum_kbps, simulcast_streams[0].minBitrate); + if (max_target_bitrate_kbps > 0) + bitrate = std::min(bitrate, static_cast<size_t>(max_target_bitrate_kbps)); + + size_t bits_available = bitrate * 1000 / framerate; + + RTC_DCHECK_GT(num_simulcast_streams, 0); + for (unsigned char i = 0; i < num_simulcast_streams; ++i) { + CodecSpecificInfo specifics; + memset(&specifics, 0, sizeof(specifics)); + specifics.codecType = kVideoCodecGeneric; + specifics.codecSpecific.generic.simulcast_idx = i; + size_t min_stream_bits = static_cast<size_t>( + (simulcast_streams[i].minBitrate * 1000) / framerate); + size_t max_stream_bits = static_cast<size_t>( + (simulcast_streams[i].maxBitrate * 1000) / framerate); + size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits : + bits_available; + size_t stream_bytes = (stream_bits + 7) / 8; + if (keyframe) { + // The first frame is a key frame and should be larger. + // Store the overshoot bytes and distribute them over the coming frames, + // so that we on average meet the bitrate target. + debt_bytes_ += (kKeyframeSizeFactor - 1) * stream_bytes; + stream_bytes *= kKeyframeSizeFactor; + } else { + if (debt_bytes_ > 0) { + // Pay at most half of the frame size for old debts. + size_t payment_size = std::min(stream_bytes / 2, debt_bytes_); + debt_bytes_ -= payment_size; + stream_bytes -= payment_size; + } + } + + if (stream_bytes > num_encoded_bytes) + stream_bytes = num_encoded_bytes; + + // Always encode something on the first frame. + if (min_stream_bits > bits_available && i > 0) + continue; + + std::unique_ptr<uint8_t[]> encoded_buffer(new uint8_t[num_encoded_bytes]); + memcpy(encoded_buffer.get(), encoded_buffer_, num_encoded_bytes); + EncodedImage encoded(encoded_buffer.get(), stream_bytes, num_encoded_bytes); + encoded._timeStamp = input_image.timestamp(); + encoded.capture_time_ms_ = input_image.render_time_ms(); + encoded._frameType = (*frame_types)[i]; + encoded._encodedWidth = simulcast_streams[i].width; + encoded._encodedHeight = simulcast_streams[i].height; + encoded.rotation_ = input_image.rotation(); + encoded.content_type_ = (mode == kScreensharing) + ? VideoContentType::SCREENSHARE + : VideoContentType::UNSPECIFIED; + specifics.codec_name = ImplementationName(); + specifics.codecSpecific.generic.simulcast_idx = i; + RTC_DCHECK(callback); + if (callback->OnEncodedImage(encoded, &specifics, nullptr).error != + EncodedImageCallback::Result::OK) { + return -1; + } + bits_available -= std::min(encoded._length * 8, bits_available); + } + return 0; +} + +int32_t FakeEncoder::RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) { + rtc::CritScope cs(&crit_sect_); + callback_ = callback; + return 0; +} + +int32_t FakeEncoder::Release() { return 0; } + +int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { + return 0; +} + +int32_t FakeEncoder::SetRateAllocation(const BitrateAllocation& rate_allocation, + uint32_t framerate) { + rtc::CritScope cs(&crit_sect_); + target_bitrate_ = rate_allocation; + configured_input_framerate_ = framerate; + return 0; +} + +const char* FakeEncoder::kImplementationName = "fake_encoder"; +const char* FakeEncoder::ImplementationName() const { + return kImplementationName; +} + +int FakeEncoder::GetConfiguredInputFramerate() const { + rtc::CritScope cs(&crit_sect_); + return configured_input_framerate_; +} + +FakeH264Encoder::FakeH264Encoder(Clock* clock) + : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) { + FakeEncoder::RegisterEncodeCompleteCallback(this); +} + +int32_t FakeH264Encoder::RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) { + rtc::CritScope cs(&local_crit_sect_); + callback_ = callback; + return 0; +} + +EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage( + const EncodedImage& encoded_image, + const CodecSpecificInfo* codec_specific_info, + const RTPFragmentationHeader* fragments) { + const size_t kSpsSize = 8; + const size_t kPpsSize = 11; + const int kIdrFrequency = 10; + EncodedImageCallback* callback; + int current_idr_counter; + { + rtc::CritScope cs(&local_crit_sect_); + callback = callback_; + current_idr_counter = idr_counter_; + ++idr_counter_; + } + RTPFragmentationHeader fragmentation; + if (current_idr_counter % kIdrFrequency == 0 && + encoded_image._length > kSpsSize + kPpsSize + 1) { + const size_t kNumSlices = 3; + fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = kSpsSize; + fragmentation.fragmentationOffset[1] = kSpsSize; + fragmentation.fragmentationLength[1] = kPpsSize; + fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize; + fragmentation.fragmentationLength[2] = + encoded_image._length - (kSpsSize + kPpsSize); + const size_t kSpsNalHeader = 0x67; + const size_t kPpsNalHeader = 0x68; + const size_t kIdrNalHeader = 0x65; + encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader; + encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader; + encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader; + } else { + const size_t kNumSlices = 1; + fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = encoded_image._length; + const size_t kNalHeader = 0x41; + encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader; + } + uint8_t value = 0; + int fragment_counter = 0; + for (size_t i = 0; i < encoded_image._length; ++i) { + if (fragment_counter == fragmentation.fragmentationVectorSize || + i != fragmentation.fragmentationOffset[fragment_counter]) { + encoded_image._buffer[i] = value++; + } else { + ++fragment_counter; + } + } + CodecSpecificInfo specifics; + memset(&specifics, 0, sizeof(specifics)); + specifics.codecType = kVideoCodecH264; + specifics.codecSpecific.H264.packetization_mode = + H264PacketizationMode::NonInterleaved; + RTC_DCHECK(callback); + return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation); +} + +DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms) + : test::FakeEncoder(clock), delay_ms_(delay_ms) { + // The encoder could be created on a different thread than + // it is being used on. + sequence_checker_.Detach(); +} + +void DelayedEncoder::SetDelay(int delay_ms) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + delay_ms_ = delay_ms; +} + +int32_t DelayedEncoder::Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + SleepMs(delay_ms_); + + return FakeEncoder::Encode(input_image, codec_specific_info, frame_types); +} + +MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock) + : test::FakeH264Encoder(clock), + current_queue_(0), + queue1_(nullptr), + queue2_(nullptr) { + // The encoder could be created on a different thread than + // it is being used on. + sequence_checker_.Detach(); +} + +int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config, + int32_t number_of_cores, + size_t max_payload_size) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + queue1_.reset(new rtc::TaskQueue("Queue 1")); + queue2_.reset(new rtc::TaskQueue("Queue 2")); + + return FakeH264Encoder::InitEncode(config, number_of_cores, max_payload_size); +} + +class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask { + public: + EncodeTask(MultithreadedFakeH264Encoder* encoder, + const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) + : encoder_(encoder), + input_image_(input_image), + codec_specific_info_(), + frame_types_(*frame_types) { + if (codec_specific_info) + codec_specific_info_ = *codec_specific_info; + } + + private: + bool Run() override { + encoder_->EncodeCallback(input_image_, &codec_specific_info_, + &frame_types_); + return true; + } + + MultithreadedFakeH264Encoder* const encoder_; + VideoFrame input_image_; + CodecSpecificInfo codec_specific_info_; + std::vector<FrameType> frame_types_; +}; + +int32_t MultithreadedFakeH264Encoder::Encode( + const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + std::unique_ptr<rtc::TaskQueue>& queue = + (current_queue_++ % 2 == 0) ? queue1_ : queue2_; + + if (!queue) { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + + queue->PostTask(std::unique_ptr<rtc::QueuedTask>( + new EncodeTask(this, input_image, codec_specific_info, frame_types))); + + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t MultithreadedFakeH264Encoder::EncodeCallback( + const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) { + return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types); +} + +int32_t MultithreadedFakeH264Encoder::Release() { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + queue1_.reset(); + queue2_.reset(); + + return FakeH264Encoder::Release(); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_encoder.h b/third_party/libwebrtc/webrtc/test/fake_encoder.h new file mode 100644 index 0000000000..06c0e0392d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_encoder.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FAKE_ENCODER_H_ +#define TEST_FAKE_ENCODER_H_ + +#include <vector> +#include <memory> + +#include "api/video_codecs/video_encoder.h" +#include "common_types.h" // NOLINT(build/include) +#include "rtc_base/criticalsection.h" +#include "rtc_base/sequenced_task_checker.h" +#include "rtc_base/task_queue.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { +namespace test { + +class FakeEncoder : public VideoEncoder { + public: + explicit FakeEncoder(Clock* clock); + virtual ~FakeEncoder() = default; + + // Sets max bitrate. Not thread-safe, call before registering the encoder. + void SetMaxBitrate(int max_kbps); + + int32_t InitEncode(const VideoCodec* config, + int32_t number_of_cores, + size_t max_payload_size) override; + int32_t Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) override; + int32_t RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) override; + int32_t Release() override; + int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; + int32_t SetRateAllocation(const BitrateAllocation& rate_allocation, + uint32_t framerate) override; + const char* ImplementationName() const override; + int GetConfiguredInputFramerate() const; + + static const char* kImplementationName; + + protected: + Clock* const clock_; + VideoCodec config_ RTC_GUARDED_BY(crit_sect_); + EncodedImageCallback* callback_ RTC_GUARDED_BY(crit_sect_); + BitrateAllocation target_bitrate_ RTC_GUARDED_BY(crit_sect_); + int configured_input_framerate_ RTC_GUARDED_BY(crit_sect_); + int max_target_bitrate_kbps_ RTC_GUARDED_BY(crit_sect_); + bool pending_keyframe_ RTC_GUARDED_BY(crit_sect_); + rtc::CriticalSection crit_sect_; + + uint8_t encoded_buffer_[100000]; + + // Current byte debt to be payed over a number of frames. + // The debt is acquired by keyframes overshooting the bitrate target. + size_t debt_bytes_; +}; + +class FakeH264Encoder : public FakeEncoder, public EncodedImageCallback { + public: + explicit FakeH264Encoder(Clock* clock); + virtual ~FakeH264Encoder() = default; + + int32_t RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) override; + + Result OnEncodedImage(const EncodedImage& encodedImage, + const CodecSpecificInfo* codecSpecificInfo, + const RTPFragmentationHeader* fragments) override; + + private: + EncodedImageCallback* callback_ RTC_GUARDED_BY(local_crit_sect_); + int idr_counter_ RTC_GUARDED_BY(local_crit_sect_); + rtc::CriticalSection local_crit_sect_; +}; + +class DelayedEncoder : public test::FakeEncoder { + public: + DelayedEncoder(Clock* clock, int delay_ms); + virtual ~DelayedEncoder() = default; + + void SetDelay(int delay_ms); + int32_t Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) override; + + private: + int delay_ms_ RTC_ACCESS_ON(sequence_checker_); + rtc::SequencedTaskChecker sequence_checker_; +}; + +// This class implements a multi-threaded fake encoder by posting +// FakeH264Encoder::Encode(.) tasks to |queue1_| and |queue2_|, in an +// alternating fashion. The class itself does not need to be thread safe, +// as it is called from the task queue in VideoStreamEncoder. +class MultithreadedFakeH264Encoder : public test::FakeH264Encoder { + public: + explicit MultithreadedFakeH264Encoder(Clock* clock); + virtual ~MultithreadedFakeH264Encoder() = default; + + int32_t InitEncode(const VideoCodec* config, + int32_t number_of_cores, + size_t max_payload_size) override; + + int32_t Encode(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) override; + + int32_t EncodeCallback(const VideoFrame& input_image, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types); + + int32_t Release() override; + + protected: + class EncodeTask; + + int current_queue_ RTC_ACCESS_ON(sequence_checker_); + std::unique_ptr<rtc::TaskQueue> queue1_ RTC_ACCESS_ON(sequence_checker_); + std::unique_ptr<rtc::TaskQueue> queue2_ RTC_ACCESS_ON(sequence_checker_); + rtc::SequencedTaskChecker sequence_checker_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_FAKE_ENCODER_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_network_pipe.cc b/third_party/libwebrtc/webrtc/test/fake_network_pipe.cc new file mode 100644 index 0000000000..6678f1c374 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_network_pipe.cc @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fake_network_pipe.h" + +#include <assert.h> +#include <math.h> +#include <string.h> + +#include <algorithm> +#include <cmath> + +#include "call/call.h" +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +namespace { +constexpr int64_t kDefaultProcessIntervalMs = 5; +} + +DemuxerImpl::DemuxerImpl(const std::map<uint8_t, MediaType>& payload_type_map) + : packet_receiver_(nullptr), payload_type_map_(payload_type_map) {} + +void DemuxerImpl::SetReceiver(PacketReceiver* receiver) { + packet_receiver_ = receiver; +} + +void DemuxerImpl::DeliverPacket(const NetworkPacket* packet, + const PacketTime& packet_time) { + // No packet receiver means that this demuxer will terminate the flow of + // packets. + if (!packet_receiver_) + return; + const uint8_t* const packet_data = packet->data(); + const size_t packet_length = packet->data_length(); + MediaType media_type = MediaType::ANY; + if (!RtpHeaderParser::IsRtcp(packet_data, packet_length)) { + RTC_CHECK_GE(packet_length, 2); + const uint8_t payload_type = packet_data[1] & 0x7f; + std::map<uint8_t, MediaType>::const_iterator it = + payload_type_map_.find(payload_type); + RTC_CHECK(it != payload_type_map_.end()) + << "payload type " << static_cast<int>(payload_type) << " unknown."; + media_type = it->second; + } + packet_receiver_->DeliverPacket(media_type, packet_data, packet_length, + packet_time); +} + +FakeNetworkPipe::FakeNetworkPipe(Clock* clock, + const FakeNetworkPipe::Config& config, + std::unique_ptr<Demuxer> demuxer) + : FakeNetworkPipe(clock, config, std::move(demuxer), 1) {} + +FakeNetworkPipe::FakeNetworkPipe(Clock* clock, + const FakeNetworkPipe::Config& config, + std::unique_ptr<Demuxer> demuxer, + uint64_t seed) + : clock_(clock), + demuxer_(std::move(demuxer)), + random_(seed), + config_(), + dropped_packets_(0), + sent_packets_(0), + total_packet_delay_(0), + bursting_(false), + next_process_time_(clock_->TimeInMilliseconds()), + last_log_time_(clock_->TimeInMilliseconds()) { + SetConfig(config); +} + +FakeNetworkPipe::~FakeNetworkPipe() { + while (!capacity_link_.empty()) { + delete capacity_link_.front(); + capacity_link_.pop(); + } + while (!delay_link_.empty()) { + delete *delay_link_.begin(); + delay_link_.erase(delay_link_.begin()); + } +} + +void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) { + RTC_CHECK(demuxer_); + demuxer_->SetReceiver(receiver); +} + +void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) { + rtc::CritScope crit(&lock_); + config_ = config; // Shallow copy of the struct. + double prob_loss = config.loss_percent / 100.0; + if (config_.avg_burst_loss_length == -1) { + // Uniform loss + prob_loss_bursting_ = prob_loss; + prob_start_bursting_ = prob_loss; + } else { + // Lose packets according to a gilbert-elliot model. + int avg_burst_loss_length = config.avg_burst_loss_length; + int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss)); + + RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length) + << "For a total packet loss of " << config.loss_percent << "%% then" + << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1 + << " or higher."; + + prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length); + prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length; + } +} + +void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) { + RTC_CHECK(demuxer_); + rtc::CritScope crit(&lock_); + if (config_.queue_length_packets > 0 && + capacity_link_.size() >= config_.queue_length_packets) { + // Too many packet on the link, drop this one. + ++dropped_packets_; + return; + } + + int64_t time_now = clock_->TimeInMilliseconds(); + + // Delay introduced by the link capacity. + int64_t capacity_delay_ms = 0; + if (config_.link_capacity_kbps > 0) { + const int bytes_per_millisecond = config_.link_capacity_kbps / 8; + // To round to the closest millisecond we add half a milliseconds worth of + // bytes to the delay calculation. + capacity_delay_ms = (data_length + capacity_delay_error_bytes_ + + bytes_per_millisecond / 2) / + bytes_per_millisecond; + capacity_delay_error_bytes_ += + data_length - capacity_delay_ms * bytes_per_millisecond; + } + int64_t network_start_time = time_now; + + // Check if there already are packets on the link and change network start + // time forward if there is. + if (!capacity_link_.empty() && + network_start_time < capacity_link_.back()->arrival_time()) + network_start_time = capacity_link_.back()->arrival_time(); + + int64_t arrival_time = network_start_time + capacity_delay_ms; + NetworkPacket* packet = new NetworkPacket(data, data_length, time_now, + arrival_time); + capacity_link_.push(packet); +} + +float FakeNetworkPipe::PercentageLoss() { + rtc::CritScope crit(&lock_); + if (sent_packets_ == 0) + return 0; + + return static_cast<float>(dropped_packets_) / + (sent_packets_ + dropped_packets_); +} + +int FakeNetworkPipe::AverageDelay() { + rtc::CritScope crit(&lock_); + if (sent_packets_ == 0) + return 0; + + return static_cast<int>(total_packet_delay_ / + static_cast<int64_t>(sent_packets_)); +} + +void FakeNetworkPipe::Process() { + int64_t time_now = clock_->TimeInMilliseconds(); + std::queue<NetworkPacket*> packets_to_deliver; + { + rtc::CritScope crit(&lock_); + if (time_now - last_log_time_ > 5000) { + int64_t queueing_delay_ms = 0; + if (!capacity_link_.empty()) { + queueing_delay_ms = time_now - capacity_link_.front()->send_time(); + } + RTC_LOG(LS_INFO) << "Network queue: " << queueing_delay_ms << " ms."; + last_log_time_ = time_now; + } + // Check the capacity link first. + while (!capacity_link_.empty() && + time_now >= capacity_link_.front()->arrival_time()) { + // Time to get this packet. + NetworkPacket* packet = capacity_link_.front(); + capacity_link_.pop(); + + // Drop packets at an average rate of |config_.loss_percent| with + // and average loss burst length of |config_.avg_burst_loss_length|. + if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) || + (!bursting_ && random_.Rand<double>() < prob_start_bursting_)) { + bursting_ = true; + delete packet; + continue; + } else { + bursting_ = false; + } + + int arrival_time_jitter = random_.Gaussian( + config_.queue_delay_ms, config_.delay_standard_deviation_ms); + + // If reordering is not allowed then adjust arrival_time_jitter + // to make sure all packets are sent in order. + if (!config_.allow_reordering && !delay_link_.empty() && + packet->arrival_time() + arrival_time_jitter < + (*delay_link_.rbegin())->arrival_time()) { + arrival_time_jitter = + (*delay_link_.rbegin())->arrival_time() - packet->arrival_time(); + } + packet->IncrementArrivalTime(arrival_time_jitter); + delay_link_.insert(packet); + } + + // Check the extra delay queue. + while (!delay_link_.empty() && + time_now >= (*delay_link_.begin())->arrival_time()) { + // Deliver this packet. + NetworkPacket* packet = *delay_link_.begin(); + packets_to_deliver.push(packet); + delay_link_.erase(delay_link_.begin()); + // |time_now| might be later than when the packet should have arrived, due + // to NetworkProcess being called too late. For stats, use the time it + // should have been on the link. + total_packet_delay_ += packet->arrival_time() - packet->send_time(); + } + sent_packets_ += packets_to_deliver.size(); + } + while (!packets_to_deliver.empty()) { + NetworkPacket* packet = packets_to_deliver.front(); + packets_to_deliver.pop(); + demuxer_->DeliverPacket(packet, PacketTime()); + delete packet; + } + + next_process_time_ = !delay_link_.empty() + ? (*delay_link_.begin())->arrival_time() + : time_now + kDefaultProcessIntervalMs; +} + +int64_t FakeNetworkPipe::TimeUntilNextProcess() const { + rtc::CritScope crit(&lock_); + return std::max<int64_t>(next_process_time_ - clock_->TimeInMilliseconds(), + 0); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_network_pipe.h b/third_party/libwebrtc/webrtc/test/fake_network_pipe.h new file mode 100644 index 0000000000..1cfaa382f4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_network_pipe.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FAKE_NETWORK_PIPE_H_ +#define TEST_FAKE_NETWORK_PIPE_H_ + +#include <string.h> +#include <map> +#include <memory> +#include <queue> +#include <set> + +#include "common_types.h" // NOLINT(build/include) +#include "rtc_base/constructormagic.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/random.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class Clock; +class PacketReceiver; +enum class MediaType; + +class NetworkPacket { + public: + NetworkPacket(const uint8_t* data, + size_t length, + int64_t send_time, + int64_t arrival_time) + : data_(new uint8_t[length]), + data_length_(length), + send_time_(send_time), + arrival_time_(arrival_time) { + memcpy(data_.get(), data, length); + } + + uint8_t* data() const { return data_.get(); } + size_t data_length() const { return data_length_; } + int64_t send_time() const { return send_time_; } + int64_t arrival_time() const { return arrival_time_; } + void IncrementArrivalTime(int64_t extra_delay) { + arrival_time_ += extra_delay; + } + + private: + // The packet data. + std::unique_ptr<uint8_t[]> data_; + // Length of data_. + size_t data_length_; + // The time the packet was sent out on the network. + const int64_t send_time_; + // The time the packet should arrive at the receiver. + int64_t arrival_time_; +}; + +class Demuxer { + public: + virtual ~Demuxer() = default; + virtual void SetReceiver(PacketReceiver* receiver) = 0; + virtual void DeliverPacket(const NetworkPacket* packet, + const PacketTime& packet_time) = 0; +}; + +class DemuxerImpl final : public Demuxer { + public: + explicit DemuxerImpl(const std::map<uint8_t, MediaType>& payload_type_map); + + void SetReceiver(PacketReceiver* receiver) override; + void DeliverPacket(const NetworkPacket* packet, + const PacketTime& packet_time) override; + + private: + PacketReceiver* packet_receiver_; + const std::map<uint8_t, MediaType> payload_type_map_; + RTC_DISALLOW_COPY_AND_ASSIGN(DemuxerImpl); +}; + +// Class faking a network link. This is a simple and naive solution just faking +// capacity and adding an extra transport delay in addition to the capacity +// introduced delay. + +class FakeNetworkPipe { + public: + struct Config { + Config() {} + // Queue length in number of packets. + size_t queue_length_packets = 0; + // Delay in addition to capacity induced delay. + int queue_delay_ms = 0; + // Standard deviation of the extra delay. + int delay_standard_deviation_ms = 0; + // Link capacity in kbps. + int link_capacity_kbps = 0; + // Random packet loss. + int loss_percent = 0; + // If packets are allowed to be reordered. + bool allow_reordering = false; + // The average length of a burst of lost packets. + int avg_burst_loss_length = -1; + }; + + FakeNetworkPipe(Clock* clock, + const FakeNetworkPipe::Config& config, + std::unique_ptr<Demuxer> demuxer); + FakeNetworkPipe(Clock* clock, + const FakeNetworkPipe::Config& config, + std::unique_ptr<Demuxer> demuxer, + uint64_t seed); + virtual ~FakeNetworkPipe(); + + // Sets a new configuration. This won't affect packets already in the pipe. + void SetConfig(const FakeNetworkPipe::Config& config); + + // Sends a new packet to the link. + virtual void SendPacket(const uint8_t* packet, size_t packet_length); + + // Must not be called in parallel with SendPacket or Process. + void SetReceiver(PacketReceiver* receiver); + + // Processes the network queues and trigger PacketReceiver::IncomingPacket for + // packets ready to be delivered. + virtual void Process(); + int64_t TimeUntilNextProcess() const; + + // Get statistics. + float PercentageLoss(); + int AverageDelay(); + size_t dropped_packets() { return dropped_packets_; } + size_t sent_packets() { return sent_packets_; } + + protected: + Clock* const clock_; + rtc::CriticalSection lock_; + const std::unique_ptr<Demuxer> demuxer_; + std::queue<NetworkPacket*> capacity_link_; + Random random_; + + // Since we need to access both the packet with the earliest and latest + // arrival time we need to use a multiset to keep all packets sorted, + // hence, we cannot use a priority queue. + struct PacketArrivalTimeComparator { + bool operator()(const NetworkPacket* p1, const NetworkPacket* p2) { + return p1->arrival_time() < p2->arrival_time(); + } + }; + std::multiset<NetworkPacket*, PacketArrivalTimeComparator> delay_link_; + + // Link configuration. + Config config_; + + // Statistics. + size_t dropped_packets_; + size_t sent_packets_; + int64_t total_packet_delay_; + + // Are we currently dropping a burst of packets? + bool bursting_; + + // The probability to drop the packet if we are currently dropping a + // burst of packet + double prob_loss_bursting_; + + // The probability to drop a burst of packets. + double prob_start_bursting_; + + int64_t next_process_time_; + + int64_t last_log_time_; + + int64_t capacity_delay_error_bytes_ = 0; + + RTC_DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe); +}; + +} // namespace webrtc + +#endif // TEST_FAKE_NETWORK_PIPE_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_network_pipe_unittest.cc b/third_party/libwebrtc/webrtc/test/fake_network_pipe_unittest.cc new file mode 100644 index 0000000000..759003b294 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_network_pipe_unittest.cc @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> + +#include "call/call.h" +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "system_wrappers/include/clock.h" +#include "test/fake_network_pipe.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Return; +using ::testing::Invoke; + +namespace webrtc { + +class TestDemuxer : public Demuxer { + public: + void IncomingPacket(NetworkPacket* packet) { + DeliverPacket(packet, PacketTime()); + } + + MOCK_METHOD1(SetReceiver, void(PacketReceiver* receiver)); + MOCK_METHOD2(DeliverPacket, + void(const NetworkPacket* packet, + const PacketTime& packet_time)); +}; + +class ReorderTestDemuxer : public TestDemuxer { + public: + void DeliverPacket(const NetworkPacket* packet, + const PacketTime& packet_time) override { + RTC_DCHECK_GE(packet->data_length(), sizeof(int)); + int seq_num; + memcpy(&seq_num, packet->data(), sizeof(int)); + delivered_sequence_numbers_.push_back(seq_num); + } + std::vector<int> delivered_sequence_numbers_; +}; + +class MockReceiver : public PacketReceiver { + public: + MOCK_METHOD4( + DeliverPacket, + DeliveryStatus(MediaType, const uint8_t*, size_t, const PacketTime&)); +}; + +class FakeNetworkPipeTest : public ::testing::Test { + public: + FakeNetworkPipeTest() : fake_clock_(12345) {} + + protected: + void SendPackets(FakeNetworkPipe* pipe, int number_packets, int packet_size) { + RTC_DCHECK_GE(packet_size, sizeof(int)); + std::unique_ptr<uint8_t[]> packet(new uint8_t[packet_size]); + for (int i = 0; i < number_packets; ++i) { + // Set a sequence number for the packets by + // using the first bytes in the packet. + memcpy(packet.get(), &i, sizeof(int)); + pipe->SendPacket(packet.get(), packet_size); + } + } + + int PacketTimeMs(int capacity_kbps, int packet_size) const { + return 8 * packet_size / capacity_kbps; + } + + SimulatedClock fake_clock_; +}; + +// Test the capacity link and verify we get as many packets as we expect. +TEST_F(FakeNetworkPipeTest, CapacityTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 20; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to + // get through the pipe. + const int kNumPackets = 10; + const int kPacketSize = 1000; + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link. + const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, + kPacketSize); + + // Time haven't increased yet, so we souldn't get any packets. + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); + + // Advance enough time to release one packet. + fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + + // Release all but one packet + fake_clock_.AdvanceTimeMilliseconds(9 * kPacketTimeMs - 1); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(8); + pipe->Process(); + + // And the last one. + fake_clock_.AdvanceTimeMilliseconds(1); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); +} + +// Test the extra network delay. +TEST_F(FakeNetworkPipeTest, ExtraDelayTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 20; + config.queue_delay_ms = 100; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + const int kNumPackets = 2; + const int kPacketSize = 1000; + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link. + const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, + kPacketSize); + + // Increase more than kPacketTimeMs, but not more than the extra delay. + fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); + + // Advance the network delay to get the first packet. + fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + + // Advance one more kPacketTimeMs to get the last packet. + fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); +} + +// Test the number of buffers and packets are dropped when sending too many +// packets too quickly. +TEST_F(FakeNetworkPipeTest, QueueLengthTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 2; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + const int kPacketSize = 1000; + const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, + kPacketSize); + + // Send three packets and verify only 2 are delivered. + SendPackets(pipe.get(), 3, kPacketSize); + + // Increase time enough to deliver all three packets, verify only two are + // delivered. + fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(2); + pipe->Process(); +} + +// Test we get statistics as expected. +TEST_F(FakeNetworkPipeTest, StatisticsTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 2; + config.queue_delay_ms = 20; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + const int kPacketSize = 1000; + const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, + kPacketSize); + + // Send three packets and verify only 2 are delivered. + SendPackets(pipe.get(), 3, kPacketSize); + fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs + + config.queue_delay_ms); + + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(2); + pipe->Process(); + + // Packet 1: kPacketTimeMs + config.queue_delay_ms, + // packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average. + EXPECT_EQ(pipe->AverageDelay(), 170); + EXPECT_EQ(pipe->sent_packets(), 2u); + EXPECT_EQ(pipe->dropped_packets(), 1u); + EXPECT_EQ(pipe->PercentageLoss(), 1/3.f); +} + +// Change the link capacity half-way through the test and verify that the +// delivery times change accordingly. +TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 20; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to + // get through the pipe. + const int kNumPackets = 10; + const int kPacketSize = 1000; + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link. + int packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); + + // Time hasn't increased yet, so we souldn't get any packets. + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); + + // Advance time in steps to release one packet at a time. + for (int i = 0; i < kNumPackets; ++i) { + fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + } + + // Change the capacity. + config.link_capacity_kbps /= 2; // Reduce to 50%. + pipe->SetConfig(config); + + // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two + // seconds to get them through the pipe. + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link. + packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); + + // Time hasn't increased yet, so we souldn't get any packets. + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); + + // Advance time in steps to release one packet at a time. + for (int i = 0; i < kNumPackets; ++i) { + fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + } + + // Check that all the packets were sent. + EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->sent_packets()); + fake_clock_.AdvanceTimeMilliseconds(pipe->TimeUntilNextProcess()); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); +} + +// Change the link capacity half-way through the test and verify that the +// delivery times change accordingly. +TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 20; + config.link_capacity_kbps = 80; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + // Add 10 packets of 1000 bytes, = 80 kb. + const int kNumPackets = 10; + const int kPacketSize = 1000; + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link at the initial speed. + int packet_time_1_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); + + // Change the capacity. + config.link_capacity_kbps *= 2; // Double the capacity. + pipe->SetConfig(config); + + // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two + // seconds to get them through the pipe. + SendPackets(pipe.get(), kNumPackets, kPacketSize); + + // Time to get one packet through the link at the new capacity. + int packet_time_2_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); + + // Time hasn't increased yet, so we souldn't get any packets. + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); + + // Advance time in steps to release one packet at a time. + for (int i = 0; i < kNumPackets; ++i) { + fake_clock_.AdvanceTimeMilliseconds(packet_time_1_ms); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + } + + // Advance time in steps to release one packet at a time. + for (int i = 0; i < kNumPackets; ++i) { + fake_clock_.AdvanceTimeMilliseconds(packet_time_2_ms); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); + pipe->Process(); + } + + // Check that all the packets were sent. + EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->sent_packets()); + fake_clock_.AdvanceTimeMilliseconds(pipe->TimeUntilNextProcess()); + EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); + pipe->Process(); +} + +// At first disallow reordering and then allow reordering. +TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) { + FakeNetworkPipe::Config config; + config.queue_length_packets = 1000; + config.link_capacity_kbps = 800; + config.queue_delay_ms = 100; + config.delay_standard_deviation_ms = 10; + ReorderTestDemuxer* demuxer = new ReorderTestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + const uint32_t kNumPackets = 100; + const int kPacketSize = 10; + SendPackets(pipe.get(), kNumPackets, kPacketSize); + fake_clock_.AdvanceTimeMilliseconds(1000); + pipe->Process(); + + // Confirm that all packets have been delivered in order. + EXPECT_EQ(kNumPackets, demuxer->delivered_sequence_numbers_.size()); + int last_seq_num = -1; + for (int seq_num : demuxer->delivered_sequence_numbers_) { + EXPECT_GT(seq_num, last_seq_num); + last_seq_num = seq_num; + } + + config.allow_reordering = true; + pipe->SetConfig(config); + SendPackets(pipe.get(), kNumPackets, kPacketSize); + fake_clock_.AdvanceTimeMilliseconds(1000); + demuxer->delivered_sequence_numbers_.clear(); + pipe->Process(); + + // Confirm that all packets have been delivered + // and that reordering has occured. + EXPECT_EQ(kNumPackets, demuxer->delivered_sequence_numbers_.size()); + bool reordering_has_occured = false; + last_seq_num = -1; + for (int seq_num : demuxer->delivered_sequence_numbers_) { + if (last_seq_num > seq_num) { + reordering_has_occured = true; + break; + } + last_seq_num = seq_num; + } + EXPECT_TRUE(reordering_has_occured); +} + +TEST_F(FakeNetworkPipeTest, BurstLoss) { + const int kLossPercent = 5; + const int kAvgBurstLength = 3; + const int kNumPackets = 10000; + const int kPacketSize = 10; + + FakeNetworkPipe::Config config; + config.queue_length_packets = kNumPackets; + config.loss_percent = kLossPercent; + config.avg_burst_loss_length = kAvgBurstLength; + ReorderTestDemuxer* demuxer = new ReorderTestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + + SendPackets(pipe.get(), kNumPackets, kPacketSize); + fake_clock_.AdvanceTimeMilliseconds(1000); + pipe->Process(); + + // Check that the average loss is |kLossPercent| percent. + int lost_packets = kNumPackets - demuxer->delivered_sequence_numbers_.size(); + double loss_fraction = lost_packets / static_cast<double>(kNumPackets); + + EXPECT_NEAR(kLossPercent / 100.0, loss_fraction, 0.05); + + // Find the number of bursts that has occurred. + size_t received_packets = demuxer->delivered_sequence_numbers_.size(); + int num_bursts = 0; + for (size_t i = 0; i < received_packets - 1; ++i) { + int diff = demuxer->delivered_sequence_numbers_[i + 1] - + demuxer->delivered_sequence_numbers_[i]; + if (diff > 1) + ++num_bursts; + } + + double average_burst_length = static_cast<double>(lost_packets) / num_bursts; + + EXPECT_NEAR(kAvgBurstLength, average_burst_length, 0.3); +} + +TEST_F(FakeNetworkPipeTest, SetReceiver) { + FakeNetworkPipe::Config config; + TestDemuxer* demuxer = new TestDemuxer(); + std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( + &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); + MockReceiver packet_receiver; + EXPECT_CALL(*demuxer, SetReceiver(&packet_receiver)).Times(1); + pipe->SetReceiver(&packet_receiver); +} + +TEST(DemuxerImplTest, Demuxing) { + constexpr uint8_t kVideoPayloadType = 100; + constexpr uint8_t kAudioPayloadType = 101; + constexpr int64_t kTimeNow = 12345; + constexpr int64_t kArrivalTime = kTimeNow - 1; + constexpr size_t kPacketSize = 10; + DemuxerImpl demuxer({{kVideoPayloadType, MediaType::VIDEO}, + {kAudioPayloadType, MediaType::AUDIO}}); + + MockReceiver mock_receiver; + demuxer.SetReceiver(&mock_receiver); + + std::vector<uint8_t> data(kPacketSize); + data[1] = kVideoPayloadType; + std::unique_ptr<NetworkPacket> packet( + new NetworkPacket(&data[0], kPacketSize, kTimeNow, kArrivalTime)); + EXPECT_CALL(mock_receiver, DeliverPacket(MediaType::VIDEO, _, _, _)) + .WillOnce(Return(PacketReceiver::DELIVERY_OK)); + demuxer.DeliverPacket(packet.get(), PacketTime()); + + data[1] = kAudioPayloadType; + packet.reset( + new NetworkPacket(&data[0], kPacketSize, kTimeNow, kArrivalTime)); + EXPECT_CALL(mock_receiver, DeliverPacket(MediaType::AUDIO, _, _, _)) + .WillOnce(Return(PacketReceiver::DELIVERY_OK)); + demuxer.DeliverPacket(packet.get(), PacketTime()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_texture_frame.cc b/third_party/libwebrtc/webrtc/test/fake_texture_frame.cc new file mode 100644 index 0000000000..4c4ea94fd2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_texture_frame.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fake_texture_frame.h" + +namespace webrtc { +namespace test { + +VideoFrame FakeNativeBuffer::CreateFrame(int width, + int height, + uint32_t timestamp, + int64_t render_time_ms, + VideoRotation rotation) { + return VideoFrame(new rtc::RefCountedObject<FakeNativeBuffer>(width, height), + timestamp, render_time_ms, rotation); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fake_texture_frame.h b/third_party/libwebrtc/webrtc/test/fake_texture_frame.h new file mode 100644 index 0000000000..17261ff8ae --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_texture_frame.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_FAKE_TEXTURE_FRAME_H_ +#define TEST_FAKE_TEXTURE_FRAME_H_ + +#include "api/video/i420_buffer.h" +#include "api/video/video_frame.h" +#include "common_video/include/video_frame_buffer.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { + +class FakeNativeBuffer : public VideoFrameBuffer { + public: + static VideoFrame CreateFrame(int width, + int height, + uint32_t timestamp, + int64_t render_time_ms, + VideoRotation rotation); + + FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} + + Type type() const override { return Type::kNative; } + int width() const override { return width_; } + int height() const override { return height_; } + + private: + rtc::scoped_refptr<I420BufferInterface> ToI420() override { + rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(width_, height_); + I420Buffer::SetBlack(buffer); + return buffer; + } + + const int width_; + const int height_; +}; + +} // namespace test +} // namespace webrtc +#endif // TEST_FAKE_TEXTURE_FRAME_H_ diff --git a/third_party/libwebrtc/webrtc/test/fake_videorenderer.h b/third_party/libwebrtc/webrtc/test/fake_videorenderer.h new file mode 100644 index 0000000000..bc9c1db710 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fake_videorenderer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FAKE_VIDEORENDERER_H_ +#define TEST_FAKE_VIDEORENDERER_H_ + +#include "api/video/video_frame.h" +#include "media/base/videosinkinterface.h" + +namespace webrtc { +namespace test { + +class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> { + public: + void OnFrame(const webrtc::VideoFrame& frame) override {} +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_FAKE_VIDEORENDERER_H_ diff --git a/third_party/libwebrtc/webrtc/test/field_trial.cc b/third_party/libwebrtc/webrtc/test/field_trial.cc new file mode 100644 index 0000000000..00e5b69041 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/field_trial.cc @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/field_trial.h" + +#include <algorithm> +#include <cassert> +#include <cstdio> +#include <cstdlib> +#include <map> +#include <string> + +#include "system_wrappers/include/field_trial.h" +#include "system_wrappers/include/field_trial_default.h" + +namespace webrtc { +namespace { +bool field_trials_initiated_ = false; +} // namespace + +namespace test { +// Note: this code is copied from src/base/metrics/field_trial.cc since the aim +// is to mimic chromium --force-fieldtrials. +void InitFieldTrialsFromString(const std::string& trials_string) { + static const char kPersistentStringSeparator = '/'; + + // Catch an error if this is called more than once. + assert(!field_trials_initiated_); + field_trials_initiated_ = true; + + if (trials_string.empty()) + return; + + size_t next_item = 0; + std::map<std::string, std::string> field_trials; + while (next_item < trials_string.length()) { + size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); + if (name_end == trials_string.npos || next_item == name_end) + break; + size_t group_name_end = trials_string.find(kPersistentStringSeparator, + name_end + 1); + if (group_name_end == trials_string.npos || name_end + 1 == group_name_end) + break; + std::string name(trials_string, next_item, name_end - next_item); + std::string group_name(trials_string, name_end + 1, + group_name_end - name_end - 1); + next_item = group_name_end + 1; + + // Fail if duplicate with different group name. + if (field_trials.find(name) != field_trials.end() && + field_trials.find(name)->second != group_name) { + break; + } + + field_trials[name] = group_name; + + // Successfully parsed all field trials from the string. + if (next_item == trials_string.length()) { + webrtc::field_trial::InitFieldTrialsFromString(trials_string.c_str()); + return; + } + } + // Using fprintf as RTC_LOG does not print when this is called early in main. + fprintf(stderr, "Invalid field trials string.\n"); + + // Using abort so it crashes in both debug and release mode. + abort(); +} + +ScopedFieldTrials::ScopedFieldTrials(const std::string& config) + : previous_field_trials_(webrtc::field_trial::GetFieldTrialString()) { + assert(field_trials_initiated_); + field_trials_initiated_ = false; + current_field_trials_ = config; + InitFieldTrialsFromString(current_field_trials_); +} + +ScopedFieldTrials::~ScopedFieldTrials() { + // Should still be initialized, since InitFieldTrials is called from ctor. + // That's why we don't restore the flag. + assert(field_trials_initiated_); + webrtc::field_trial::InitFieldTrialsFromString(previous_field_trials_); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/field_trial.h b/third_party/libwebrtc/webrtc/test/field_trial.h new file mode 100644 index 0000000000..99ace4e864 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/field_trial.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FIELD_TRIAL_H_ +#define TEST_FIELD_TRIAL_H_ + +#include <string> +#include <map> + +namespace webrtc { +namespace test { + +// Parses enabled field trials from a string config, such as the one passed +// to chrome's argument --force-fieldtrials and initializes webrtc::field_trial +// with such a config. +// E.g.: +// "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/" +// Assigns the process to group "Enabled" on WebRTCExperimentFoo trial +// and to group "Enabled100kbps" on WebRTCExperimentBar. +// +// E.g. invalid config: +// "WebRTC-experiment1/Enabled" (note missing / separator at the end). +// +// Note: This method crashes with an error message if an invalid config is +// passed to it. That can be used to find out if a binary is parsing the flags. +void InitFieldTrialsFromString(const std::string& config); + +// This class is used to override field-trial configs within specific tests. +// After this class goes out of scope previous field trials will be restored. +class ScopedFieldTrials { + public: + explicit ScopedFieldTrials(const std::string& config); + ~ScopedFieldTrials(); + private: + std::string current_field_trials_; + const char* previous_field_trials_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_FIELD_TRIAL_H_ diff --git a/third_party/libwebrtc/webrtc/test/frame_generator.cc b/third_party/libwebrtc/webrtc/test/frame_generator.cc new file mode 100644 index 0000000000..e5d9950301 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_generator.cc @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/frame_generator.h" + +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include <memory> + +#include "api/video/i420_buffer.h" +#include "common_video/include/video_frame_buffer.h" +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "rtc_base/checks.h" +#include "rtc_base/keep_ref_until_done.h" +#include "rtc_base/random.h" +#include "system_wrappers/include/clock.h" +#include "test/frame_utils.h" + +namespace webrtc { +namespace test { +namespace { + +// SquareGenerator is a FrameGenerator that draws a given amount of randomly +// sized and colored squares. Between each new generated frame, the squares +// are moved slightly towards the lower right corner. +class SquareGenerator : public FrameGenerator { + public: + SquareGenerator(int width, int height, int num_squares) { + ChangeResolution(width, height); + for (int i = 0; i < num_squares; ++i) { + squares_.emplace_back(new Square(width, height, i + 1)); + } + } + + void ChangeResolution(size_t width, size_t height) override { + rtc::CritScope lock(&crit_); + width_ = static_cast<int>(width); + height_ = static_cast<int>(height); + RTC_CHECK(width_ > 0); + RTC_CHECK(height_ > 0); + } + + VideoFrame* NextFrame() override { + rtc::CritScope lock(&crit_); + + rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(width_, height_)); + + memset(buffer->MutableDataY(), 127, height_ * buffer->StrideY()); + memset(buffer->MutableDataU(), 127, + buffer->ChromaHeight() * buffer->StrideU()); + memset(buffer->MutableDataV(), 127, + buffer->ChromaHeight() * buffer->StrideV()); + + for (const auto& square : squares_) + square->Draw(buffer); + + frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0)); + return frame_.get(); + } + + private: + class Square { + public: + Square(int width, int height, int seed) + : random_generator_(seed), + x_(random_generator_.Rand(0, width)), + y_(random_generator_.Rand(0, height)), + length_(random_generator_.Rand(1, width > 4 ? width / 4 : 1)), + yuv_y_(random_generator_.Rand(0, 255)), + yuv_u_(random_generator_.Rand(0, 255)), + yuv_v_(random_generator_.Rand(0, 255)) {} + + void Draw(const rtc::scoped_refptr<I420Buffer>& buffer) { + x_ = (x_ + random_generator_.Rand(0, 4)) % (buffer->width() - length_); + y_ = (y_ + random_generator_.Rand(0, 4)) % (buffer->height() - length_); + for (int y = y_; y < y_ + length_; ++y) { + uint8_t* pos_y = + (buffer->MutableDataY() + x_ + y * buffer->StrideY()); + memset(pos_y, yuv_y_, length_); + } + + for (int y = y_; y < y_ + length_; y = y + 2) { + uint8_t* pos_u = + (buffer->MutableDataU() + x_ / 2 + y / 2 * buffer->StrideU()); + memset(pos_u, yuv_u_, length_ / 2); + uint8_t* pos_v = + (buffer->MutableDataV() + x_ / 2 + y / 2 * buffer->StrideV()); + memset(pos_v, yuv_v_, length_ / 2); + } + } + + private: + Random random_generator_; + int x_; + int y_; + const int length_; + const uint8_t yuv_y_; + const uint8_t yuv_u_; + const uint8_t yuv_v_; + }; + + rtc::CriticalSection crit_; + int width_ RTC_GUARDED_BY(&crit_); + int height_ RTC_GUARDED_BY(&crit_); + std::vector<std::unique_ptr<Square>> squares_ RTC_GUARDED_BY(&crit_); + std::unique_ptr<VideoFrame> frame_ RTC_GUARDED_BY(&crit_); +}; + +class YuvFileGenerator : public FrameGenerator { + public: + YuvFileGenerator(std::vector<FILE*> files, + size_t width, + size_t height, + int frame_repeat_count) + : file_index_(0), + files_(files), + width_(width), + height_(height), + frame_size_(CalcBufferSize(VideoType::kI420, + static_cast<int>(width_), + static_cast<int>(height_))), + frame_buffer_(new uint8_t[frame_size_]), + frame_display_count_(frame_repeat_count), + current_display_count_(0) { + RTC_DCHECK_GT(width, 0); + RTC_DCHECK_GT(height, 0); + RTC_DCHECK_GT(frame_repeat_count, 0); + } + + virtual ~YuvFileGenerator() { + for (FILE* file : files_) + fclose(file); + } + + VideoFrame* NextFrame() override { + if (current_display_count_ == 0) + ReadNextFrame(); + if (++current_display_count_ >= frame_display_count_) + current_display_count_ = 0; + + temp_frame_.reset( + new VideoFrame(last_read_buffer_, 0, 0, webrtc::kVideoRotation_0)); + return temp_frame_.get(); + } + + void ReadNextFrame() { + last_read_buffer_ = + test::ReadI420Buffer(static_cast<int>(width_), + static_cast<int>(height_), + files_[file_index_]); + if (!last_read_buffer_) { + // No more frames to read in this file, rewind and move to next file. + rewind(files_[file_index_]); + file_index_ = (file_index_ + 1) % files_.size(); + last_read_buffer_ = + test::ReadI420Buffer(static_cast<int>(width_), + static_cast<int>(height_), + files_[file_index_]); + RTC_CHECK(last_read_buffer_); + } + } + + private: + size_t file_index_; + const std::vector<FILE*> files_; + const size_t width_; + const size_t height_; + const size_t frame_size_; + const std::unique_ptr<uint8_t[]> frame_buffer_; + const int frame_display_count_; + int current_display_count_; + rtc::scoped_refptr<I420Buffer> last_read_buffer_; + std::unique_ptr<VideoFrame> temp_frame_; +}; + +// SlideGenerator works similarly to YuvFileGenerator but it fills the frames +// with randomly sized and colored squares instead of reading their content +// from files. +class SlideGenerator : public FrameGenerator { + public: + SlideGenerator(int width, int height, int frame_repeat_count) + : width_(width), + height_(height), + frame_display_count_(frame_repeat_count), + current_display_count_(0), + random_generator_(1234) { + RTC_DCHECK_GT(width, 0); + RTC_DCHECK_GT(height, 0); + RTC_DCHECK_GT(frame_repeat_count, 0); + } + + VideoFrame* NextFrame() override { + if (current_display_count_ == 0) + GenerateNewFrame(); + if (++current_display_count_ >= frame_display_count_) + current_display_count_ = 0; + + frame_.reset( + new VideoFrame(buffer_, 0, 0, webrtc::kVideoRotation_0)); + return frame_.get(); + } + + // Generates some randomly sized and colored squares scattered + // over the frame. + void GenerateNewFrame() { + // The squares should have a varying order of magnitude in order + // to simulate variation in the slides' complexity. + const int kSquareNum = 1 << (4 + (random_generator_.Rand(0, 3) * 2)); + + buffer_ = I420Buffer::Create(width_, height_); + memset(buffer_->MutableDataY(), 127, height_ * buffer_->StrideY()); + memset(buffer_->MutableDataU(), 127, + buffer_->ChromaHeight() * buffer_->StrideU()); + memset(buffer_->MutableDataV(), 127, + buffer_->ChromaHeight() * buffer_->StrideV()); + + for (int i = 0; i < kSquareNum; ++i) { + int length = random_generator_.Rand(1, width_ > 4 ? width_ / 4 : 1); + // Limit the length of later squares so that they don't overwrite the + // previous ones too much. + length = (length * (kSquareNum - i)) / kSquareNum; + + int x = random_generator_.Rand(0, width_ - length); + int y = random_generator_.Rand(0, height_ - length); + uint8_t yuv_y = random_generator_.Rand(0, 255); + uint8_t yuv_u = random_generator_.Rand(0, 255); + uint8_t yuv_v = random_generator_.Rand(0, 255); + + for (int yy = y; yy < y + length; ++yy) { + uint8_t* pos_y = + (buffer_->MutableDataY() + x + yy * buffer_->StrideY()); + memset(pos_y, yuv_y, length); + } + for (int yy = y; yy < y + length; yy += 2) { + uint8_t* pos_u = + (buffer_->MutableDataU() + x / 2 + yy / 2 * buffer_->StrideU()); + memset(pos_u, yuv_u, length / 2); + uint8_t* pos_v = + (buffer_->MutableDataV() + x / 2 + yy / 2 * buffer_->StrideV()); + memset(pos_v, yuv_v, length / 2); + } + } + } + + private: + const int width_; + const int height_; + const int frame_display_count_; + int current_display_count_; + Random random_generator_; + rtc::scoped_refptr<I420Buffer> buffer_; + std::unique_ptr<VideoFrame> frame_; +}; + +class ScrollingImageFrameGenerator : public FrameGenerator { + public: + ScrollingImageFrameGenerator(Clock* clock, + const std::vector<FILE*>& files, + size_t source_width, + size_t source_height, + size_t target_width, + size_t target_height, + int64_t scroll_time_ms, + int64_t pause_time_ms) + : clock_(clock), + start_time_(clock->TimeInMilliseconds()), + scroll_time_(scroll_time_ms), + pause_time_(pause_time_ms), + num_frames_(files.size()), + target_width_(static_cast<int>(target_width)), + target_height_(static_cast<int>(target_height)), + current_frame_num_(num_frames_ - 1), + current_source_frame_(nullptr), + file_generator_(files, source_width, source_height, 1) { + RTC_DCHECK(clock_ != nullptr); + RTC_DCHECK_GT(num_frames_, 0); + RTC_DCHECK_GE(source_height, target_height); + RTC_DCHECK_GE(source_width, target_width); + RTC_DCHECK_GE(scroll_time_ms, 0); + RTC_DCHECK_GE(pause_time_ms, 0); + RTC_DCHECK_GT(scroll_time_ms + pause_time_ms, 0); + } + + virtual ~ScrollingImageFrameGenerator() {} + + VideoFrame* NextFrame() override { + const int64_t kFrameDisplayTime = scroll_time_ + pause_time_; + const int64_t now = clock_->TimeInMilliseconds(); + int64_t ms_since_start = now - start_time_; + + size_t frame_num = (ms_since_start / kFrameDisplayTime) % num_frames_; + UpdateSourceFrame(frame_num); + + double scroll_factor; + int64_t time_into_frame = ms_since_start % kFrameDisplayTime; + if (time_into_frame < scroll_time_) { + scroll_factor = static_cast<double>(time_into_frame) / scroll_time_; + } else { + scroll_factor = 1.0; + } + CropSourceToScrolledImage(scroll_factor); + + return current_frame_ ? &*current_frame_ : nullptr; + } + + void UpdateSourceFrame(size_t frame_num) { + while (current_frame_num_ != frame_num) { + current_source_frame_ = file_generator_.NextFrame(); + current_frame_num_ = (current_frame_num_ + 1) % num_frames_; + } + RTC_DCHECK(current_source_frame_ != nullptr); + } + + void CropSourceToScrolledImage(double scroll_factor) { + int scroll_margin_x = current_source_frame_->width() - target_width_; + int pixels_scrolled_x = + static_cast<int>(scroll_margin_x * scroll_factor + 0.5); + int scroll_margin_y = current_source_frame_->height() - target_height_; + int pixels_scrolled_y = + static_cast<int>(scroll_margin_y * scroll_factor + 0.5); + + rtc::scoped_refptr<I420BufferInterface> i420_buffer = + current_source_frame_->video_frame_buffer()->ToI420(); + int offset_y = + (i420_buffer->StrideY() * pixels_scrolled_y) + pixels_scrolled_x; + int offset_u = (i420_buffer->StrideU() * (pixels_scrolled_y / 2)) + + (pixels_scrolled_x / 2); + int offset_v = (i420_buffer->StrideV() * (pixels_scrolled_y / 2)) + + (pixels_scrolled_x / 2); + + current_frame_ = rtc::Optional<webrtc::VideoFrame>(webrtc::VideoFrame( + new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( + target_width_, target_height_, &i420_buffer->DataY()[offset_y], + i420_buffer->StrideY(), &i420_buffer->DataU()[offset_u], + i420_buffer->StrideU(), &i420_buffer->DataV()[offset_v], + i420_buffer->StrideV(), KeepRefUntilDone(i420_buffer)), + kVideoRotation_0, 0)); + } + + Clock* const clock_; + const int64_t start_time_; + const int64_t scroll_time_; + const int64_t pause_time_; + const size_t num_frames_; + const int target_width_; + const int target_height_; + + size_t current_frame_num_; + VideoFrame* current_source_frame_; + rtc::Optional<VideoFrame> current_frame_; + YuvFileGenerator file_generator_; +}; + +} // namespace + +FrameForwarder::FrameForwarder() : sink_(nullptr) {} +FrameForwarder::~FrameForwarder() {} + +void FrameForwarder::IncomingCapturedFrame(const VideoFrame& video_frame) { + rtc::CritScope lock(&crit_); + if (sink_) + sink_->OnFrame(video_frame); +} + +void FrameForwarder::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) { + rtc::CritScope lock(&crit_); + RTC_DCHECK(!sink_ || sink_ == sink); + sink_ = sink; + sink_wants_ = wants; +} + +void FrameForwarder::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) { + rtc::CritScope lock(&crit_); + RTC_DCHECK_EQ(sink, sink_); + sink_ = nullptr; +} + +rtc::VideoSinkWants FrameForwarder::sink_wants() const { + rtc::CritScope lock(&crit_); + return sink_wants_; +} + +bool FrameForwarder::has_sinks() const { + rtc::CritScope lock(&crit_); + return sink_ != nullptr; +} + +std::unique_ptr<FrameGenerator> FrameGenerator::CreateSquareGenerator( + int width, + int height) { + return std::unique_ptr<FrameGenerator>( + new SquareGenerator(width, height, 10)); +} + +std::unique_ptr<FrameGenerator> +FrameGenerator::CreateSquareGenerator(int width, int height, int num_squares) { + return std::unique_ptr<FrameGenerator>( + new SquareGenerator(width, height, num_squares)); +} + +std::unique_ptr<FrameGenerator> FrameGenerator::CreateSlideGenerator( + int width, int height, int frame_repeat_count) { + return std::unique_ptr<FrameGenerator>(new SlideGenerator( + width, height, frame_repeat_count)); +} + +std::unique_ptr<FrameGenerator> FrameGenerator::CreateFromYuvFile( + std::vector<std::string> filenames, + size_t width, + size_t height, + int frame_repeat_count) { + RTC_DCHECK(!filenames.empty()); + std::vector<FILE*> files; + for (const std::string& filename : filenames) { + FILE* file = fopen(filename.c_str(), "rb"); + RTC_DCHECK(file != nullptr); + files.push_back(file); + } + + return std::unique_ptr<FrameGenerator>( + new YuvFileGenerator(files, width, height, frame_repeat_count)); +} + +std::unique_ptr<FrameGenerator> +FrameGenerator::CreateScrollingInputFromYuvFiles( + Clock* clock, + std::vector<std::string> filenames, + size_t source_width, + size_t source_height, + size_t target_width, + size_t target_height, + int64_t scroll_time_ms, + int64_t pause_time_ms) { + RTC_DCHECK(!filenames.empty()); + std::vector<FILE*> files; + for (const std::string& filename : filenames) { + FILE* file = fopen(filename.c_str(), "rb"); + RTC_DCHECK(file != nullptr); + files.push_back(file); + } + + return std::unique_ptr<FrameGenerator>(new ScrollingImageFrameGenerator( + clock, files, source_width, source_height, target_width, target_height, + scroll_time_ms, pause_time_ms)); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/frame_generator.h b/third_party/libwebrtc/webrtc/test/frame_generator.h new file mode 100644 index 0000000000..d37166f2fa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_generator.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_FRAME_GENERATOR_H_ +#define TEST_FRAME_GENERATOR_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "api/video/video_frame.h" +#include "media/base/videosourceinterface.h" +#include "rtc_base/criticalsection.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +class Clock; +namespace test { + +// FrameForwarder can be used as an implementation +// of rtc::VideoSourceInterface<VideoFrame> where the caller controls when +// a frame should be forwarded to its sink. +// Currently this implementation only support one sink. +class FrameForwarder : public rtc::VideoSourceInterface<VideoFrame> { + public: + FrameForwarder(); + virtual ~FrameForwarder(); + // Forwards |video_frame| to the registered |sink_|. + virtual void IncomingCapturedFrame(const VideoFrame& video_frame); + rtc::VideoSinkWants sink_wants() const; + bool has_sinks() const; + + protected: + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override; + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override; + + rtc::CriticalSection crit_; + rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(crit_); + rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(crit_); +}; + +class FrameGenerator { + public: + virtual ~FrameGenerator() = default; + + // Returns video frame that remains valid until next call. + virtual VideoFrame* NextFrame() = 0; + + // Change the capture resolution. + virtual void ChangeResolution(size_t width, size_t height) { + RTC_NOTREACHED(); + } + + // Creates a frame generator that produces frames with small squares that + // move randomly towards the lower right corner. + static std::unique_ptr<FrameGenerator> CreateSquareGenerator(int width, + int height); + static std::unique_ptr<FrameGenerator> CreateSquareGenerator(int width, + int height, + int num_squares); + + // Creates a frame generator that repeatedly plays a set of yuv files. + // The frame_repeat_count determines how many times each frame is shown, + // with 1 = show each frame once, etc. + static std::unique_ptr<FrameGenerator> CreateFromYuvFile( + std::vector<std::string> files, + size_t width, + size_t height, + int frame_repeat_count); + + // Creates a frame generator which takes a set of yuv files (wrapping a + // frame generator created by CreateFromYuvFile() above), but outputs frames + // that have been cropped to specified resolution: source_width/source_height + // is the size of the source images, target_width/target_height is the size of + // the cropped output. For each source image read, the cropped viewport will + // be scrolled top to bottom/left to right for scroll_tim_ms milliseconds. + // After that the image will stay in place for pause_time_ms milliseconds, + // and then this will be repeated with the next file from the input set. + static std::unique_ptr<FrameGenerator> CreateScrollingInputFromYuvFiles( + Clock* clock, + std::vector<std::string> filenames, + size_t source_width, + size_t source_height, + size_t target_width, + size_t target_height, + int64_t scroll_time_ms, + int64_t pause_time_ms); + + // Creates a frame generator that produces randomly generated slides. + // frame_repeat_count determines how many times each slide is shown. + static std::unique_ptr<FrameGenerator> CreateSlideGenerator( + int width, int height, int frame_repeat_count); +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_FRAME_GENERATOR_H_ diff --git a/third_party/libwebrtc/webrtc/test/frame_generator_capturer.cc b/third_party/libwebrtc/webrtc/test/frame_generator_capturer.cc new file mode 100644 index 0000000000..a8983b7ba2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_generator_capturer.cc @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/frame_generator_capturer.h" + +#include <utility> +#include <vector> + +#include "rtc_base/criticalsection.h" +#include "rtc_base/logging.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/timeutils.h" +#include "system_wrappers/include/clock.h" +#include "test/frame_generator.h" +#include "call/video_send_stream.h" + +namespace webrtc { +namespace test { + +class FrameGeneratorCapturer::InsertFrameTask : public rtc::QueuedTask { + public: + // Repeats in |repeat_interval_ms|. One-time if |repeat_interval_ms| == 0. + InsertFrameTask( + webrtc::test::FrameGeneratorCapturer* frame_generator_capturer, + uint32_t repeat_interval_ms) + : frame_generator_capturer_(frame_generator_capturer), + repeat_interval_ms_(repeat_interval_ms), + intended_run_time_ms_(-1) {} + + private: + bool Run() override { + bool task_completed = true; + if (repeat_interval_ms_ > 0) { + // This is not a one-off frame. Check if the frame interval for this + // task queue is the same same as the current configured frame rate. + uint32_t current_interval_ms = + 1000 / frame_generator_capturer_->GetCurrentConfiguredFramerate(); + if (repeat_interval_ms_ != current_interval_ms) { + // Frame rate has changed since task was started, create a new instance. + rtc::TaskQueue::Current()->PostDelayedTask( + std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask( + frame_generator_capturer_, current_interval_ms)), + current_interval_ms); + } else { + // Schedule the next frame capture event to happen at approximately the + // correct absolute time point. + int64_t delay_ms; + int64_t time_now_ms = rtc::TimeMillis(); + if (intended_run_time_ms_ > 0) { + delay_ms = time_now_ms - intended_run_time_ms_; + } else { + delay_ms = 0; + intended_run_time_ms_ = time_now_ms; + } + intended_run_time_ms_ += repeat_interval_ms_; + if (delay_ms < repeat_interval_ms_) { + rtc::TaskQueue::Current()->PostDelayedTask( + std::unique_ptr<rtc::QueuedTask>(this), + repeat_interval_ms_ - delay_ms); + } else { + rtc::TaskQueue::Current()->PostDelayedTask( + std::unique_ptr<rtc::QueuedTask>(this), 0); + RTC_LOG(LS_ERROR) + << "Frame Generator Capturer can't keep up with requested fps"; + } + // Repost of this instance, make sure it is not deleted. + task_completed = false; + } + } + frame_generator_capturer_->InsertFrame(); + // Task should be deleted only if it's not repeating. + return task_completed; + } + + webrtc::test::FrameGeneratorCapturer* const frame_generator_capturer_; + const uint32_t repeat_interval_ms_; + int64_t intended_run_time_ms_; +}; + +FrameGeneratorCapturer* FrameGeneratorCapturer::Create(int width, + int height, + int target_fps, + Clock* clock) { + std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer( + clock, FrameGenerator::CreateSquareGenerator(width, height), target_fps)); + if (!capturer->Init()) + return nullptr; + + return capturer.release(); +} + +FrameGeneratorCapturer* FrameGeneratorCapturer::Create(int width, + int height, + int num_squares, + int target_fps, + Clock* clock) { + std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer( + clock, FrameGenerator::CreateSquareGenerator(width, height, num_squares), + target_fps)); + if (!capturer->Init()) + return nullptr; + + return capturer.release(); +} + +FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile( + const std::string& file_name, + size_t width, + size_t height, + int target_fps, + Clock* clock) { + std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer( + clock, + FrameGenerator::CreateFromYuvFile(std::vector<std::string>(1, file_name), + width, height, 1), + target_fps)); + if (!capturer->Init()) + return nullptr; + + return capturer.release(); +} + +FrameGeneratorCapturer* FrameGeneratorCapturer::CreateSlideGenerator( + int width, + int height, + int frame_repeat_count, + int target_fps, + Clock* clock) { + std::unique_ptr<FrameGeneratorCapturer> capturer(new FrameGeneratorCapturer( + clock, FrameGenerator::CreateSlideGenerator(width, height, + frame_repeat_count), + target_fps)); + if (!capturer->Init()) + return nullptr; + + return capturer.release(); +} + +FrameGeneratorCapturer::FrameGeneratorCapturer( + Clock* clock, + std::unique_ptr<FrameGenerator> frame_generator, + int target_fps) + : clock_(clock), + sending_(false), + sink_(nullptr), + sink_wants_observer_(nullptr), + frame_generator_(std::move(frame_generator)), + target_fps_(target_fps), + first_frame_capture_time_(-1), + task_queue_("FrameGenCapQ", + rtc::TaskQueue::Priority::HIGH) { + RTC_DCHECK(frame_generator_); + RTC_DCHECK_GT(target_fps, 0); +} + +FrameGeneratorCapturer::~FrameGeneratorCapturer() { + Stop(); +} + +void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) { + rtc::CritScope cs(&lock_); + fake_rotation_ = rotation; +} + +bool FrameGeneratorCapturer::Init() { + // This check is added because frame_generator_ might be file based and should + // not crash because a file moved. + if (frame_generator_.get() == nullptr) + return false; + + int framerate_fps = GetCurrentConfiguredFramerate(); + task_queue_.PostDelayedTask( + std::unique_ptr<rtc::QueuedTask>( + new InsertFrameTask(this, 1000 / framerate_fps)), + 1000 / framerate_fps); + + return true; +} + +void FrameGeneratorCapturer::InsertFrame() { + rtc::CritScope cs(&lock_); + if (sending_) { + VideoFrame* frame = frame_generator_->NextFrame(); + frame->set_timestamp_us(clock_->TimeInMicroseconds()); + frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds()); + frame->set_rotation(fake_rotation_); + if (first_frame_capture_time_ == -1) { + first_frame_capture_time_ = frame->ntp_time_ms(); + } + + if (sink_) { + rtc::Optional<VideoFrame> out_frame = AdaptFrame(*frame); + if (out_frame) + sink_->OnFrame(*out_frame); + } + } +} + +void FrameGeneratorCapturer::Start() { + rtc::CritScope cs(&lock_); + sending_ = true; +} + +void FrameGeneratorCapturer::Stop() { + rtc::CritScope cs(&lock_); + sending_ = false; +} + +void FrameGeneratorCapturer::ChangeResolution(size_t width, size_t height) { + rtc::CritScope cs(&lock_); + frame_generator_->ChangeResolution(width, height); +} + +void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) { + rtc::CritScope cs(&lock_); + RTC_DCHECK(!sink_wants_observer_); + sink_wants_observer_ = observer; +} + +void FrameGeneratorCapturer::AddOrUpdateSink( + rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) { + rtc::CritScope cs(&lock_); + RTC_CHECK(!sink_ || sink_ == sink); + sink_ = sink; + if (sink_wants_observer_) + sink_wants_observer_->OnSinkWantsChanged(sink, wants); + + // Handle framerate within this class, just pass on resolution for possible + // adaptation. + rtc::VideoSinkWants resolution_wants = wants; + resolution_wants.max_framerate_fps = std::numeric_limits<int>::max(); + VideoCapturer::AddOrUpdateSink(sink, resolution_wants); + + // Ignore any requests for framerate higher than initially configured. + if (wants.max_framerate_fps < target_fps_) { + wanted_fps_.emplace(wants.max_framerate_fps); + } else { + wanted_fps_.reset(); + } +} + +void FrameGeneratorCapturer::RemoveSink( + rtc::VideoSinkInterface<VideoFrame>* sink) { + rtc::CritScope cs(&lock_); + RTC_CHECK(sink_ == sink); + sink_ = nullptr; +} + +void FrameGeneratorCapturer::ForceFrame() { + // One-time non-repeating task, + // therefore repeat_interval_ms is 0 in InsertFrameTask() + task_queue_.PostTask( + std::unique_ptr<rtc::QueuedTask>(new InsertFrameTask(this, 0))); +} + +int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() { + rtc::CritScope cs(&lock_); + if (wanted_fps_ && *wanted_fps_ < target_fps_) + return *wanted_fps_; + return target_fps_; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/frame_generator_capturer.h b/third_party/libwebrtc/webrtc/test/frame_generator_capturer.h new file mode 100644 index 0000000000..3a3fe82431 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_generator_capturer.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_FRAME_GENERATOR_CAPTURER_H_ +#define TEST_FRAME_GENERATOR_CAPTURER_H_ + +#include <memory> +#include <string> + +#include "api/video/video_frame.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/task_queue.h" +#include "test/video_capturer.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class EventTimerWrapper; + +namespace test { + +class FrameGenerator; + +class FrameGeneratorCapturer : public VideoCapturer { + public: + class SinkWantsObserver { + public: + // OnSinkWantsChanged is called when FrameGeneratorCapturer::AddOrUpdateSink + // is called. + virtual void OnSinkWantsChanged(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) = 0; + + protected: + virtual ~SinkWantsObserver() {} + }; + + static FrameGeneratorCapturer* Create(int width, + int height, + int target_fps, + Clock* clock); + + static FrameGeneratorCapturer* Create(int width, + int height, + int num_squares, + int target_fps, + Clock* clock); + + static FrameGeneratorCapturer* CreateFromYuvFile(const std::string& file_name, + size_t width, + size_t height, + int target_fps, + Clock* clock); + + static FrameGeneratorCapturer* CreateSlideGenerator(int width, + int height, + int frame_repeat_count, + int target_fps, + Clock* clock); + virtual ~FrameGeneratorCapturer(); + + void Start() override; + void Stop() override; + void ChangeResolution(size_t width, size_t height); + + void SetSinkWantsObserver(SinkWantsObserver* observer); + + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override; + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override; + + void ForceFrame(); + void SetFakeRotation(VideoRotation rotation); + + int64_t first_frame_capture_time() const { return first_frame_capture_time_; } + + FrameGeneratorCapturer(Clock* clock, + std::unique_ptr<FrameGenerator> frame_generator, + int target_fps); + bool Init(); + + private: + class InsertFrameTask; + + void InsertFrame(); + static bool Run(void* obj); + int GetCurrentConfiguredFramerate(); + + Clock* const clock_; + bool sending_; + rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(&lock_); + SinkWantsObserver* sink_wants_observer_ RTC_GUARDED_BY(&lock_); + + rtc::CriticalSection lock_; + std::unique_ptr<FrameGenerator> frame_generator_; + + int target_fps_ RTC_GUARDED_BY(&lock_); + rtc::Optional<int> wanted_fps_ RTC_GUARDED_BY(&lock_); + VideoRotation fake_rotation_ = kVideoRotation_0; + + int64_t first_frame_capture_time_; + // Must be the last field, so it will be deconstructed first as tasks + // in the TaskQueue access other fields of the instance of this class. + rtc::TaskQueue task_queue_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_FRAME_GENERATOR_CAPTURER_H_ diff --git a/third_party/libwebrtc/webrtc/test/frame_generator_unittest.cc b/third_party/libwebrtc/webrtc/test/frame_generator_unittest.cc new file mode 100644 index 0000000000..ba4627dc3b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_generator_unittest.cc @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdio.h> + +#include <memory> +#include <string> + +#include "test/frame_generator.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { +namespace test { + +static const int kFrameWidth = 4; +static const int kFrameHeight = 4; + +class FrameGeneratorTest : public ::testing::Test { + public: + void SetUp() override { + two_frame_filename_ = + test::TempFilename(test::OutputPath(), "2_frame_yuv_file"); + one_frame_filename_ = + test::TempFilename(test::OutputPath(), "1_frame_yuv_file"); + + FILE* file = fopen(two_frame_filename_.c_str(), "wb"); + WriteYuvFile(file, 0, 0, 0); + WriteYuvFile(file, 127, 127, 127); + fclose(file); + file = fopen(one_frame_filename_.c_str(), "wb"); + WriteYuvFile(file, 255, 255, 255); + fclose(file); + } + void TearDown() override { + remove(one_frame_filename_.c_str()); + remove(two_frame_filename_.c_str()); + } + + protected: + void WriteYuvFile(FILE* file, uint8_t y, uint8_t u, uint8_t v) { + assert(file); + std::unique_ptr<uint8_t[]> plane_buffer(new uint8_t[y_size]); + memset(plane_buffer.get(), y, y_size); + fwrite(plane_buffer.get(), 1, y_size, file); + memset(plane_buffer.get(), u, uv_size); + fwrite(plane_buffer.get(), 1, uv_size, file); + memset(plane_buffer.get(), v, uv_size); + fwrite(plane_buffer.get(), 1, uv_size, file); + } + + void CheckFrameAndMutate(VideoFrame* frame, uint8_t y, uint8_t u, uint8_t v) { + // Check that frame is valid, has the correct color and timestamp are clean. + ASSERT_NE(nullptr, frame); + rtc::scoped_refptr<I420BufferInterface> i420_buffer = + frame->video_frame_buffer()->ToI420(); + const uint8_t* buffer; + buffer = i420_buffer->DataY(); + for (int i = 0; i < y_size; ++i) + ASSERT_EQ(y, buffer[i]); + buffer = i420_buffer->DataU(); + for (int i = 0; i < uv_size; ++i) + ASSERT_EQ(u, buffer[i]); + buffer = i420_buffer->DataV(); + for (int i = 0; i < uv_size; ++i) + ASSERT_EQ(v, buffer[i]); + EXPECT_EQ(0, frame->ntp_time_ms()); + EXPECT_EQ(0, frame->render_time_ms()); + EXPECT_EQ(0u, frame->timestamp()); + + // Mutate to something arbitrary non-zero. + frame->set_ntp_time_ms(11); + frame->set_timestamp_us(12); + frame->set_timestamp(13); + } + + uint64_t Hash(VideoFrame* frame) { + // Generate a 64-bit hash from the frame's buffer. + uint64_t hash = 19; + rtc::scoped_refptr<I420BufferInterface> i420_buffer = + frame->video_frame_buffer()->ToI420(); + const uint8_t* buffer = i420_buffer->DataY(); + for (int i = 0; i < y_size; ++i) { + hash = (37 * hash) + buffer[i]; + } + buffer = i420_buffer->DataU(); + for (int i = 0; i < uv_size; ++i) { + hash = (37 * hash) + buffer[i]; + } + buffer = i420_buffer->DataV(); + for (int i = 0; i < uv_size; ++i) { + hash = (37 * hash) + buffer[i]; + } + return hash; + } + + std::string two_frame_filename_; + std::string one_frame_filename_; + const int y_size = kFrameWidth * kFrameHeight; + const int uv_size = ((kFrameHeight + 1) / 2) * ((kFrameWidth + 1) / 2); +}; + +TEST_F(FrameGeneratorTest, SingleFrameFile) { + std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile( + std::vector<std::string>(1, one_frame_filename_), kFrameWidth, + kFrameHeight, 1)); + CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255); + CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255); +} + +TEST_F(FrameGeneratorTest, TwoFrameFile) { + std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile( + std::vector<std::string>(1, two_frame_filename_), kFrameWidth, + kFrameHeight, 1)); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); + CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); +} + +TEST_F(FrameGeneratorTest, MultipleFrameFiles) { + std::vector<std::string> files; + files.push_back(two_frame_filename_); + files.push_back(one_frame_filename_); + + std::unique_ptr<FrameGenerator> generator( + FrameGenerator::CreateFromYuvFile(files, kFrameWidth, kFrameHeight, 1)); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); + CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127); + CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); +} + +TEST_F(FrameGeneratorTest, TwoFrameFileWithRepeat) { + const int kRepeatCount = 3; + std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile( + std::vector<std::string>(1, two_frame_filename_), kFrameWidth, + kFrameHeight, kRepeatCount)); + for (int i = 0; i < kRepeatCount; ++i) + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); + for (int i = 0; i < kRepeatCount; ++i) + CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); +} + +TEST_F(FrameGeneratorTest, MultipleFrameFilesWithRepeat) { + const int kRepeatCount = 3; + std::vector<std::string> files; + files.push_back(two_frame_filename_); + files.push_back(one_frame_filename_); + std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile( + files, kFrameWidth, kFrameHeight, kRepeatCount)); + for (int i = 0; i < kRepeatCount; ++i) + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); + for (int i = 0; i < kRepeatCount; ++i) + CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127); + for (int i = 0; i < kRepeatCount; ++i) + CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255); + CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0); +} + +TEST_F(FrameGeneratorTest, SlideGenerator) { + const int kGenCount = 9; + const int kRepeatCount = 3; + std::unique_ptr<FrameGenerator> generator( + FrameGenerator::CreateSlideGenerator( + kFrameWidth, kFrameHeight, kRepeatCount)); + uint64_t hashes[kGenCount]; + for (int i = 0; i < kGenCount; ++i) { + hashes[i] = Hash(generator->NextFrame()); + } + // Check that the buffer changes only every |kRepeatCount| frames. + for (int i = 1; i < kGenCount; ++i) { + if (i % kRepeatCount == 0) { + EXPECT_NE(hashes[i-1], hashes[i]); + } else { + EXPECT_EQ(hashes[i-1], hashes[i]); + } + } +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/frame_utils.cc b/third_party/libwebrtc/webrtc/test/frame_utils.cc new file mode 100644 index 0000000000..1d5fe7c8f4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_utils.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdio.h> +#include <string.h> + +#include "api/video/i420_buffer.h" +#include "api/video/video_frame.h" +#include "test/frame_utils.h" + +namespace webrtc { +namespace test { + +bool EqualPlane(const uint8_t* data1, + const uint8_t* data2, + int stride1, + int stride2, + int width, + int height) { + for (int y = 0; y < height; ++y) { + if (memcmp(data1, data2, width) != 0) + return false; + data1 += stride1; + data2 += stride2; + } + return true; +} + +bool FramesEqual(const webrtc::VideoFrame& f1, const webrtc::VideoFrame& f2) { + if (f1.timestamp() != f2.timestamp() || + f1.ntp_time_ms() != f2.ntp_time_ms() || + f1.render_time_ms() != f2.render_time_ms()) { + return false; + } + return FrameBufsEqual(f1.video_frame_buffer(), f2.video_frame_buffer()); +} + +bool FrameBufsEqual(const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& f1, + const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& f2) { + if (f1 == f2) { + return true; + } + // Exlude nullptr (except if both are nullptr, as above) + if (!f1 || !f2) { + return false; + } + + if (f1->width() != f2->width() || f1->height() != f2->height() || + f1->type() != f2->type()) { + return false; + } + + rtc::scoped_refptr<webrtc::I420BufferInterface> f1_i420 = f1->ToI420(); + rtc::scoped_refptr<webrtc::I420BufferInterface> f2_i420 = f2->ToI420(); + return EqualPlane(f1_i420->DataY(), f2_i420->DataY(), + f1_i420->StrideY(), f2_i420->StrideY(), + f1_i420->width(), f1_i420->height()) && + EqualPlane(f1_i420->DataU(), f2_i420->DataU(), + f1_i420->StrideU(), f2_i420->StrideU(), + f1_i420->ChromaWidth(), f1_i420->ChromaHeight()) && + EqualPlane(f1_i420->DataV(), f2_i420->DataV(), + f1_i420->StrideV(), f2_i420->StrideV(), + f1_i420->ChromaWidth(), f1_i420->ChromaHeight()); +} + +rtc::scoped_refptr<I420Buffer> ReadI420Buffer(int width, int height, FILE *f) { + int half_width = (width + 1) / 2; + rtc::scoped_refptr<I420Buffer> buffer( + // Explicit stride, no padding between rows. + I420Buffer::Create(width, height, width, half_width, half_width)); + size_t size_y = static_cast<size_t>(width) * height; + size_t size_uv = static_cast<size_t>(half_width) * ((height + 1) / 2); + + if (fread(buffer->MutableDataY(), 1, size_y, f) < size_y) + return nullptr; + if (fread(buffer->MutableDataU(), 1, size_uv, f) < size_uv) + return nullptr; + if (fread(buffer->MutableDataV(), 1, size_uv, f) < size_uv) + return nullptr; + return buffer; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/frame_utils.h b/third_party/libwebrtc/webrtc/test/frame_utils.h new file mode 100644 index 0000000000..80466e1c29 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/frame_utils.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_FRAME_UTILS_H_ +#define TEST_FRAME_UTILS_H_ + +#include <stdint.h> + +#include "rtc_base/scoped_ref_ptr.h" + +namespace webrtc { +class I420Buffer; +class VideoFrame; +class VideoFrameBuffer; +namespace test { + +bool EqualPlane(const uint8_t* data1, + const uint8_t* data2, + int stride1, + int stride2, + int width, + int height); + +static inline bool EqualPlane(const uint8_t* data1, + const uint8_t* data2, + int stride, + int width, + int height) { + return EqualPlane(data1, data2, stride, stride, width, height); +} + +bool FramesEqual(const webrtc::VideoFrame& f1, const webrtc::VideoFrame& f2); + +bool FrameBufsEqual(const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& f1, + const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& f2); + +rtc::scoped_refptr<I420Buffer> ReadI420Buffer(int width, int height, FILE *); + +} // namespace test +} // namespace webrtc + +#endif // TEST_FRAME_UTILS_H_ diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/BUILD.gn b/third_party/libwebrtc/webrtc/test/fuzzers/BUILD.gn new file mode 100644 index 0000000000..8a1cb97df2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/BUILD.gn @@ -0,0 +1,411 @@ +# 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. + +import("../../webrtc.gni") +import("//build/config/features.gni") +import("//testing/libfuzzer/fuzzer_test.gni") + +rtc_static_library("webrtc_fuzzer_main") { + sources = [ + "webrtc_fuzzer_main.cc", + ] + deps = [ + "../../rtc_base:rtc_base_approved", + "../../system_wrappers:field_trial_default", + "../../system_wrappers:metrics_default", + "//testing/libfuzzer:libfuzzer_main", + ] +} + +template("webrtc_fuzzer_test") { + fuzzer_test(target_name) { + forward_variables_from(invoker, "*") + deps += [ + ":webrtc_fuzzer_main", + + # Link unconditionally with webrtc's TaskQueue, regardless of + # rtc_link_task_queue_impl flag. + "../../rtc_base:rtc_task_queue_impl", + ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs = [ "//build/config/clang:find_bad_constructs" ] + } + } +} + +webrtc_fuzzer_test("h264_depacketizer_fuzzer") { + sources = [ + "h264_depacketizer_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + ] +} + +webrtc_fuzzer_test("vp8_depacketizer_fuzzer") { + sources = [ + "vp8_depacketizer_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + ] +} + +webrtc_fuzzer_test("vp9_depacketizer_fuzzer") { + sources = [ + "vp9_depacketizer_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + ] +} + +webrtc_fuzzer_test("vp8_qp_parser_fuzzer") { + sources = [ + "vp8_qp_parser_fuzzer.cc", + ] + deps = [ + "../../modules/video_coding:video_coding_utility", + "../../modules/video_coding/", + ] +} + +webrtc_fuzzer_test("vp9_qp_parser_fuzzer") { + sources = [ + "vp9_qp_parser_fuzzer.cc", + ] + deps = [ + "../../modules/video_coding:video_coding_utility", + "../../modules/video_coding/", + ] +} + +webrtc_fuzzer_test("h264_bitstream_parser_fuzzer") { + sources = [ + "h264_bitstream_parser_fuzzer.cc", + ] + deps = [ + "../../common_video", + "../../modules/video_coding/", + ] +} + +webrtc_fuzzer_test("flexfec_header_reader_fuzzer") { + sources = [ + "flexfec_header_reader_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + ] +} + +webrtc_fuzzer_test("flexfec_sender_fuzzer") { + sources = [ + "flexfec_sender_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../system_wrappers", + ] + libfuzzer_options = [ "max_len=200" ] +} + +webrtc_fuzzer_test("ulpfec_header_reader_fuzzer") { + sources = [ + "ulpfec_header_reader_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../modules/rtp_rtcp:fec_test_helper", + "../../rtc_base:rtc_base_approved", + ] +} + +webrtc_fuzzer_test("ulpfec_generator_fuzzer") { + sources = [ + "ulpfec_generator_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../modules/rtp_rtcp:fec_test_helper", + "../../rtc_base:rtc_base_approved", + ] +} + +webrtc_fuzzer_test("ulpfec_receiver_fuzzer") { + sources = [ + "ulpfec_receiver_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + ] + libfuzzer_options = [ "max_len=2000" ] +} + +webrtc_fuzzer_test("flexfec_receiver_fuzzer") { + sources = [ + "flexfec_receiver_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + ] + libfuzzer_options = [ "max_len=2000" ] +} + +webrtc_fuzzer_test("packet_buffer_fuzzer") { + sources = [ + "packet_buffer_fuzzer.cc", + ] + deps = [ + "../../modules/video_coding/", + "../../system_wrappers", + ] + libfuzzer_options = [ "max_len=2000" ] +} + +webrtc_fuzzer_test("rtcp_receiver_fuzzer") { + sources = [ + "rtcp_receiver_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + "../../system_wrappers:system_wrappers", + ] + seed_corpus = "corpora/rtcp-corpus" +} + +webrtc_fuzzer_test("rtp_packet_fuzzer") { + sources = [ + "rtp_packet_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + ] + seed_corpus = "corpora/rtp-corpus" +} + +webrtc_fuzzer_test("rtp_header_fuzzer") { + sources = [ + "rtp_header_fuzzer.cc", + ] + deps = [ + "../../modules/rtp_rtcp", + ] +} + +webrtc_fuzzer_test("congestion_controller_feedback_fuzzer") { + sources = [ + "congestion_controller_feedback_fuzzer.cc", + ] + deps = [ + "../../logging:rtc_event_log_api", + "../../logging:rtc_event_log_impl", + "../../modules/congestion_controller", + "../../modules/pacing", + "../../modules/remote_bitrate_estimator:remote_bitrate_estimator", + "../../modules/rtp_rtcp", + ] +} + +rtc_static_library("audio_decoder_fuzzer") { + sources = [ + "audio_decoder_fuzzer.cc", + "audio_decoder_fuzzer.h", + ] + deps = [ + "../..:webrtc_common", + "../../api:optional", + "../../api/audio_codecs:audio_codecs_api", + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + ] +} + +webrtc_fuzzer_test("audio_decoder_ilbc_fuzzer") { + sources = [ + "audio_decoder_ilbc_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:ilbc", + ] +} + +webrtc_fuzzer_test("audio_decoder_isac_fuzzer") { + sources = [ + "audio_decoder_isac_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:isac", + ] +} + +webrtc_fuzzer_test("audio_decoder_isac_incoming_packet_fuzzer") { + sources = [ + "audio_decoder_isac_incoming_packet_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:isac", + ] +} + +webrtc_fuzzer_test("audio_decoder_isacfix_fuzzer") { + sources = [ + "audio_decoder_isacfix_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:isac_fix", + ] +} + +webrtc_fuzzer_test("audio_decoder_opus_fuzzer") { + sources = [ + "audio_decoder_opus_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:webrtc_opus", + ] +} + +webrtc_fuzzer_test("audio_decoder_opus_redundant_fuzzer") { + sources = [ + "audio_decoder_opus_redundant_fuzzer.cc", + ] + deps = [ + ":audio_decoder_fuzzer", + "../../modules/audio_coding:webrtc_opus", + ] +} + +webrtc_fuzzer_test("turn_unwrap_fuzzer") { + sources = [ + "turn_unwrap_fuzzer.cc", + ] + deps = [ + "../../media:media", + ] +} + +webrtc_fuzzer_test("neteq_rtp_fuzzer") { + sources = [ + "neteq_rtp_fuzzer.cc", + ] + deps = [ + "../../api:array_view", + "../../modules/audio_coding:neteq", + "../../modules/audio_coding:neteq_test_tools", + "../../modules/audio_coding:neteq_tools_minimal", + "../../modules/audio_coding:pcm16b", + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_base_tests_utils", + ] +} + +webrtc_fuzzer_test("neteq_signal_fuzzer") { + sources = [ + "neteq_signal_fuzzer.cc", + ] + deps = [ + "../../api:array_view", + "../../modules/audio_coding:neteq", + "../../modules/audio_coding:neteq_test_tools", + "../../modules/audio_coding:neteq_tools_minimal", + "../../modules/audio_coding:pcm16b", + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_base_tests_utils", + ] +} + +webrtc_fuzzer_test("residual_echo_detector_fuzzer") { + sources = [ + "residual_echo_detector_fuzzer.cc", + ] + deps = [ + "../../modules/audio_processing:audio_processing", + "../../rtc_base:rtc_base_approved", + ] +} + +webrtc_fuzzer_test("sdp_parser_fuzzer") { + sources = [ + "sdp_parser_fuzzer.cc", + ] + deps = [ + "../../pc:libjingle_peerconnection", + ] + seed_corpus = "corpora/sdp-corpus" +} + +webrtc_fuzzer_test("stun_parser_fuzzer") { + sources = [ + "stun_parser_fuzzer.cc", + ] + deps = [ + "../../p2p:rtc_p2p", + ] + seed_corpus = "corpora/stun-corpus" + dict = "corpora/stun.tokens" +} + +webrtc_fuzzer_test("stun_validator_fuzzer") { + sources = [ + "stun_validator_fuzzer.cc", + ] + deps = [ + "../../p2p:rtc_p2p", + ] + seed_corpus = "corpora/stun-corpus" + dict = "corpora/stun.tokens" +} + +webrtc_fuzzer_test("pseudotcp_parser_fuzzer") { + sources = [ + "pseudotcp_parser_fuzzer.cc", + ] + deps = [ + "../../p2p:rtc_p2p", + "../../rtc_base:rtc_base", + ] +} + +webrtc_fuzzer_test("transport_feedback_packet_loss_tracker_fuzzer") { + sources = [ + "transport_feedback_packet_loss_tracker_fuzzer.cc", + ] + deps = [ + "../../api:array_view", + "../../modules/rtp_rtcp", + "../../rtc_base:rtc_base_approved", + "../../voice_engine", + ] +} + +webrtc_fuzzer_test("audio_processing_fuzzer") { + sources = [ + "audio_processing_fuzzer.cc", + "audio_processing_fuzzer.h", + "audio_processing_fuzzer_configs.cc", + ] + deps = [ + "../../api:optional", + "../../modules:module_api", + "../../modules/audio_processing", + "../../rtc_base:rtc_base_approved", + ] +} diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/DEPS b/third_party/libwebrtc/webrtc/test/fuzzers/DEPS new file mode 100644 index 0000000000..cdbb5660e9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+webrtc", +] diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/OWNERS b/third_party/libwebrtc/webrtc/test/fuzzers/OWNERS new file mode 100644 index 0000000000..6e7454380e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/OWNERS @@ -0,0 +1 @@ +henrik.lundin@webrtc.org diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.cc new file mode 100644 index 0000000000..f6ac4cb0bb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fuzzers/audio_decoder_fuzzer.h" + +#include <limits> + +#include "api/audio_codecs/audio_decoder.h" +#include "api/optional.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { +template <typename T, unsigned int B = sizeof(T)> +bool ParseInt(const uint8_t** data, size_t* remaining_size, T* value) { + static_assert(std::numeric_limits<T>::is_integer, "Type must be an integer."); + static_assert(sizeof(T) <= sizeof(uint64_t), + "Cannot read wider than uint64_t."); + static_assert(B <= sizeof(T), "T must be at least B bytes wide."); + if (B > *remaining_size) + return false; + uint64_t val = ByteReader<uint64_t, B>::ReadBigEndian(*data); + *data += B; + *remaining_size -= B; + *value = static_cast<T>(val); + return true; +} +} // namespace + +// This function reads two bytes from the beginning of |data|, interprets them +// as the first packet length, and reads this many bytes if available. The +// payload is inserted into the decoder, and the process continues until no more +// data is available. Either AudioDecoder::Decode or +// AudioDecoder::DecodeRedundant is used, depending on the value of +// |decode_type|. +void FuzzAudioDecoder(DecoderFunctionType decode_type, + const uint8_t* data, + size_t size, + AudioDecoder* decoder, + int sample_rate_hz, + size_t max_decoded_bytes, + int16_t* decoded) { + const uint8_t* data_ptr = data; + size_t remaining_size = size; + size_t packet_len; + while (ParseInt<size_t, 2>(&data_ptr, &remaining_size, &packet_len) && + packet_len <= remaining_size) { + AudioDecoder::SpeechType speech_type; + switch (decode_type) { + case DecoderFunctionType::kNormalDecode: + decoder->Decode(data_ptr, packet_len, sample_rate_hz, max_decoded_bytes, + decoded, &speech_type); + break; + case DecoderFunctionType::kRedundantDecode: + decoder->DecodeRedundant(data_ptr, packet_len, sample_rate_hz, + max_decoded_bytes, decoded, &speech_type); + break; + } + data_ptr += packet_len; + remaining_size -= packet_len; + } +} + +// This function is similar to FuzzAudioDecoder, but also reads fuzzed data into +// RTP header values. The fuzzed data and values are sent to the decoder's +// IncomingPacket method. +void FuzzAudioDecoderIncomingPacket(const uint8_t* data, + size_t size, + AudioDecoder* decoder) { + const uint8_t* data_ptr = data; + size_t remaining_size = size; + size_t packet_len; + while (ParseInt<size_t, 2>(&data_ptr, &remaining_size, &packet_len)) { + uint16_t rtp_sequence_number; + if (!ParseInt(&data_ptr, &remaining_size, &rtp_sequence_number)) + break; + uint32_t rtp_timestamp; + if (!ParseInt(&data_ptr, &remaining_size, &rtp_timestamp)) + break; + uint32_t arrival_timestamp; + if (!ParseInt(&data_ptr, &remaining_size, &arrival_timestamp)) + break; + if (remaining_size < packet_len) + break; + decoder->IncomingPacket(data_ptr, packet_len, rtp_sequence_number, + rtp_timestamp, arrival_timestamp); + data_ptr += packet_len; + remaining_size -= packet_len; + } +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.h b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.h new file mode 100644 index 0000000000..504ecf6c02 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_fuzzer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FUZZERS_AUDIO_DECODER_FUZZER_H_ +#define TEST_FUZZERS_AUDIO_DECODER_FUZZER_H_ + +#include <stddef.h> + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class AudioDecoder; + +enum class DecoderFunctionType { + kNormalDecode, + kRedundantDecode, +}; + +void FuzzAudioDecoder(DecoderFunctionType decode_type, + const uint8_t* data, + size_t size, + AudioDecoder* decoder, + int sample_rate_hz, + size_t max_decoded_bytes, + int16_t* decoded); + +void FuzzAudioDecoderIncomingPacket(const uint8_t* data, + size_t size, + AudioDecoder* decoder); +} // namespace webrtc + +#endif // TEST_FUZZERS_AUDIO_DECODER_FUZZER_H_ diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc new file mode 100644 index 0000000000..a68725d6aa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + AudioDecoderIlbcImpl dec; + static const int kSampleRateHz = 8000; + static const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; + int16_t output[kAllocatedOuputSizeSamples]; + FuzzAudioDecoder(DecoderFunctionType::kNormalDecode, data, size, &dec, + kSampleRateHz, sizeof(output), output); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_fuzzer.cc new file mode 100644 index 0000000000..e79996e05b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_fuzzer.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + const int sample_rate_hz = size % 2 == 0 ? 16000 : 32000; // 16 or 32 kHz. + static const size_t kAllocatedOuputSizeSamples = 32000 / 10; // 100 ms. + int16_t output[kAllocatedOuputSizeSamples]; + AudioDecoderIsacFloatImpl dec(sample_rate_hz); + FuzzAudioDecoder(DecoderFunctionType::kNormalDecode, data, size, &dec, + sample_rate_hz, sizeof(output), output); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_incoming_packet_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_incoming_packet_fuzzer.cc new file mode 100644 index 0000000000..5645142a03 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isac_incoming_packet_fuzzer.cc @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + AudioDecoderIsacFloatImpl dec(16000); + FuzzAudioDecoderIncomingPacket(data, size, &dec); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isacfix_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isacfix_fuzzer.cc new file mode 100644 index 0000000000..444395b17d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_isacfix_fuzzer.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + static const int kSampleRateHz = 16000; + static const size_t kAllocatedOuputSizeSamples = 16000 / 10; // 100 ms. + int16_t output[kAllocatedOuputSizeSamples]; + AudioDecoderIsacFixImpl dec(kSampleRateHz); + FuzzAudioDecoder(DecoderFunctionType::kNormalDecode, data, size, &dec, + kSampleRateHz, sizeof(output), output); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc new file mode 100644 index 0000000000..a015f98b5b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_fuzzer.cc @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/opus/audio_decoder_opus.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + const size_t channels = (size % 2) + 1; // 1 or 2 channels. + AudioDecoderOpusImpl dec(channels); + const int kSampleRateHz = 48000; + const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; // 100 ms. + int16_t output[kAllocatedOuputSizeSamples]; + FuzzAudioDecoder(DecoderFunctionType::kNormalDecode, data, size, &dec, + kSampleRateHz, sizeof(output), output); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc new file mode 100644 index 0000000000..efcba0f35d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_decoder_opus_redundant_fuzzer.cc @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/codecs/opus/audio_decoder_opus.h" +#include "test/fuzzers/audio_decoder_fuzzer.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + const size_t channels = (size % 2) + 1; // 1 or 2 channels. + AudioDecoderOpusImpl dec(channels); + const int kSampleRateHz = 48000; + const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; // 100 ms. + int16_t output[kAllocatedOuputSizeSamples]; + FuzzAudioDecoder(DecoderFunctionType::kRedundantDecode, data, size, &dec, + kSampleRateHz, sizeof(output), output); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.cc new file mode 100644 index 0000000000..a44d446096 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/fuzzers/audio_processing_fuzzer.h" + +#include <algorithm> +#include <array> +#include <cmath> + +#include "modules/audio_processing/include/audio_processing.h" +#include "modules/include/module_common_types.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { +size_t ByteToNativeRate(uint8_t data) { + using Rate = AudioProcessing::NativeRate; + switch (data % 4) { + case 0: + return static_cast<size_t>(Rate::kSampleRate8kHz); + case 1: + return static_cast<size_t>(Rate::kSampleRate16kHz); + case 2: + return static_cast<size_t>(Rate::kSampleRate32kHz); + default: + return static_cast<size_t>(Rate::kSampleRate48kHz); + } +} + +template <class T> +bool ParseSequence(size_t size, + const uint8_t** data, + size_t* remaining_size, + T* result_data) { + const size_t data_size_bytes = sizeof(T) * size; + if (data_size_bytes > *remaining_size) { + return false; + } + + std::copy(*data, *data + data_size_bytes, + reinterpret_cast<uint8_t*>(result_data)); + + *data += data_size_bytes; + *remaining_size -= data_size_bytes; + return true; +} + +void FuzzAudioProcessing(const uint8_t* data, + size_t size, + bool is_float, + AudioProcessing* apm) { + AudioFrame fixed_frame; + std::array<float, 480> float_frame{}; + float* const first_channel = &float_frame[0]; + + while (size > 0) { + // Decide input/output rate for this iteration. + const auto input_rate_byte = ParseByte(&data, &size); + const auto output_rate_byte = ParseByte(&data, &size); + if (!input_rate_byte || !output_rate_byte) { + return; + } + const auto input_rate_hz = ByteToNativeRate(*input_rate_byte); + const auto output_rate_hz = ByteToNativeRate(*output_rate_byte); + + const size_t samples_per_input_channel = + rtc::CheckedDivExact(input_rate_hz, 100ul); + fixed_frame.samples_per_channel_ = samples_per_input_channel; + fixed_frame.sample_rate_hz_ = input_rate_hz; + + // Two channels breaks AEC3. + fixed_frame.num_channels_ = 1; + + // Fill the arrays with audio samples from the data. + if (is_float) { + if (!ParseSequence(samples_per_input_channel, &data, &size, + &float_frame[0])) { + return; + } + } else if (!ParseSequence(samples_per_input_channel, &data, &size, + fixed_frame.mutable_data())) { + return; + } + + // Filter obviously wrong values like inf/nan and values that will + // lead to inf/nan in calculations. 1e6 leads to DCHECKS failing. + for (auto& x : float_frame) { + if (!std::isnormal(x) || std::abs(x) > 1e5) { + x = 0; + } + } + + // Make the APM call depending on capture/render mode and float / + // fix interface. + const auto is_capture = ParseBool(&data, &size); + if (!is_capture) { + return; + } + if (*is_capture) { + auto apm_return_code = + is_float ? (apm->ProcessStream( + &first_channel, StreamConfig(input_rate_hz, 1), + StreamConfig(output_rate_hz, 1), &first_channel)) + : (apm->ProcessStream(&fixed_frame)); + RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError); + } else { + auto apm_return_code = + is_float ? (apm->ProcessReverseStream( + &first_channel, StreamConfig(input_rate_hz, 1), + StreamConfig(output_rate_hz, 1), &first_channel)) + : (apm->ProcessReverseStream(&fixed_frame)); + RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError); + } + } +} + +} // namespace + +rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size) { + if (1 > *remaining_size) { + return rtc::nullopt; + } + auto res = (**data) % 2; + *data += 1; + *remaining_size -= 1; + return res; +} + +rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size) { + if (1 > *remaining_size) { + return rtc::nullopt; + } + auto res = **data; + *data += 1; + *remaining_size -= 1; + return res; +} + +void FuzzAudioProcessing(const uint8_t* data, + size_t size, + std::unique_ptr<AudioProcessing> apm) { + const auto is_float = ParseBool(&data, &size); + if (!is_float) { + return; + } + + FuzzAudioProcessing(data, size, *is_float, apm.get()); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.h b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.h new file mode 100644 index 0000000000..337d9b215d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_ +#define TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_ + +#include <memory> + +#include "modules/audio_processing/include/audio_processing.h" +namespace webrtc { + +rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size); +rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size); + +void FuzzAudioProcessing(const uint8_t* data, + size_t size, + std::unique_ptr<AudioProcessing> apm); +} // namespace webrtc + +#endif // TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_ diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer_configs.cc b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer_configs.cc new file mode 100644 index 0000000000..15e0beeba9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/audio_processing_fuzzer_configs.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_processing/include/audio_processing.h" +#include "test/fuzzers/audio_processing_fuzzer.h" + +#include "api/optional.h" + +namespace webrtc { + +std::unique_ptr<AudioProcessing> CreateAPM(const uint8_t** data, + size_t* remaining_size) { + // Parse boolean values for optionally enabling different + // configurable public components of APM. + auto exp_agc = ParseBool(data, remaining_size); + auto exp_ns = ParseBool(data, remaining_size); + auto bf = ParseBool(data, remaining_size); + auto ef = ParseBool(data, remaining_size); + auto raf = ParseBool(data, remaining_size); + auto da = ParseBool(data, remaining_size); + auto ie = ParseBool(data, remaining_size); + auto red = ParseBool(data, remaining_size); + auto lc = ParseBool(data, remaining_size); + auto hpf = ParseBool(data, remaining_size); + auto aec3 = ParseBool(data, remaining_size); + + auto use_aec = ParseBool(data, remaining_size); + auto use_aecm = ParseBool(data, remaining_size); + auto use_agc = ParseBool(data, remaining_size); + auto use_ns = ParseBool(data, remaining_size); + auto use_le = ParseBool(data, remaining_size); + auto use_vad = ParseBool(data, remaining_size); + auto use_agc_limiter = ParseBool(data, remaining_size); + + if (!(exp_agc && exp_ns && bf && ef && raf && da && ie && red && lc && hpf && + aec3 && use_aec && use_aecm && use_agc && use_ns && use_le && use_vad && + use_agc_limiter)) { + return nullptr; + } + + // Filter out incompatible settings that lead to CHECK failures. + if (*use_aecm && *use_aec) { + return nullptr; + } + + // Components can be enabled through webrtc::Config and + // webrtc::AudioProcessingConfig. + Config config; + + std::unique_ptr<EchoControlFactory> echo_control_factory; + if (*aec3) { + echo_control_factory.reset(new EchoCanceller3Factory()); + } + + config.Set<ExperimentalAgc>(new ExperimentalAgc(*exp_agc)); + config.Set<ExperimentalNs>(new ExperimentalNs(*exp_ns)); + if (*bf) { + config.Set<Beamforming>(new Beamforming()); + } + config.Set<ExtendedFilter>(new ExtendedFilter(*ef)); + config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(*raf)); + config.Set<DelayAgnostic>(new DelayAgnostic(*da)); + config.Set<Intelligibility>(new Intelligibility(*ie)); + + std::unique_ptr<AudioProcessing> apm(AudioProcessing::Create( + config, nullptr, std::move(echo_control_factory), nullptr)); + + webrtc::AudioProcessing::Config apm_config; + apm_config.residual_echo_detector.enabled = *red; + apm_config.level_controller.enabled = *lc; + apm_config.high_pass_filter.enabled = *hpf; + + apm->ApplyConfig(apm_config); + + apm->echo_cancellation()->Enable(*use_aec); + apm->echo_control_mobile()->Enable(*use_aecm); + apm->gain_control()->Enable(*use_agc); + apm->noise_suppression()->Enable(*use_ns); + apm->level_estimator()->Enable(*use_le); + apm->voice_detection()->Enable(*use_vad); + apm->gain_control()->enable_limiter(*use_agc_limiter); + + return apm; +} + +void FuzzOneInput(const uint8_t* data, size_t size) { + auto apm = CreateAPM(&data, &size); + if (apm) { + FuzzAudioProcessing(data, size, std::move(apm)); + } +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/congestion_controller_feedback_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/congestion_controller_feedback_fuzzer.cc new file mode 100644 index 0000000000..084c8c300a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/congestion_controller_feedback_fuzzer.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/congestion_controller/include/receive_side_congestion_controller.h" +#include "modules/pacing/packet_router.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { + +void FuzzOneInput(const uint8_t* data, size_t size) { + size_t i = 0; + if (size < sizeof(int64_t) + sizeof(uint8_t) + sizeof(uint32_t)) + return; + SimulatedClock clock(data[i++]); + PacketRouter packet_router; + ReceiveSideCongestionController cc(&clock, &packet_router); + RemoteBitrateEstimator* rbe = cc.GetRemoteBitrateEstimator(true); + RTPHeader header; + header.ssrc = ByteReader<uint32_t>::ReadBigEndian(&data[i]); + i += sizeof(uint32_t); + header.extension.hasTransportSequenceNumber = true; + int64_t arrival_time_ms = std::min<int64_t>( + std::max<int64_t>(ByteReader<int64_t>::ReadBigEndian(&data[i]), 0), + std::numeric_limits<int64_t>::max() / 2); + i += sizeof(int64_t); + const size_t kMinPacketSize = + sizeof(size_t) + sizeof(uint16_t) + sizeof(uint8_t); + while (i + kMinPacketSize < size) { + size_t payload_size = ByteReader<size_t>::ReadBigEndian(&data[i]) % 1500; + i += sizeof(size_t); + header.extension.transportSequenceNumber = + ByteReader<uint16_t>::ReadBigEndian(&data[i]); + i += sizeof(uint16_t); + rbe->IncomingPacket(arrival_time_ms, payload_size, header); + clock.AdvanceTimeMilliseconds(5); + arrival_time_ms += ByteReader<uint8_t>::ReadBigEndian(&data[i]); + i += sizeof(uint8_t); + } + rbe->Process(); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/README b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/README new file mode 100644 index 0000000000..d29e169417 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/README @@ -0,0 +1,34 @@ +This is a collection of corpora for various WebRTC fuzzers. To use +them, the gn targets define seed_corpus=$corpus_dir, which causes the +ClusterFuzz upload bot to bundle $corpus_dir and upload it. + +The format is simple: one file per test case. Specific notes are +included below. + +### SDP ### +This corpus was initially assembled manually from the following +sources: + + - curl --silent https://www.ietf.org/rfc/rfc4317.txt | grep '^[ a-z]*=[^=]*$' | sed 's/^[[:space:]]*//' | awk -v RS='(^|\n)v=' '/./ {print "v="$0 > NR".sdp"}' + - all the SDPs used in the parser unit tests + - some manually gathered SDPs from Firefox and Opera + +The SDP tokens come from: + + - grep "^static const " webrtc/api/webrtcsdp.cc | cut -d'=' -f2 | cut -d ';' -f1 | tr -d '"' | tr -d "'" | tr -d ' ' | sort -u | grep -v '^(\n|\r|\r\n)$|^$' | sed -e 's/^/"/' -e 's/$/"/' | tail -n +2 + +### STUN ### +This corpus was initially assembled from the STUN unit tests, together +with a crash that it found relatively quickly. + +### RT(C)P ### +This corpus was initially assembled from the unittests. RTCP was +minimised first. + +There is also rt(c?)p-corpus-with-extra-byte, in which each sample is +prefixed by the byte 0xff. Some of the rtp fuzzers need to decide +which header extensions to enable, and the first byte of the fuzz data +is used for this. + +### PseudoTCP ### +Very small corpus minimised from the unit tests.
\ No newline at end of file diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/pseudotcp-corpus/785b96587d0eb44dd5d75b7a886f37e2ac504511 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/pseudotcp-corpus/785b96587d0eb44dd5d75b7a886f37e2ac504511 Binary files differnew file mode 100644 index 0000000000..21f5cffa12 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/pseudotcp-corpus/785b96587d0eb44dd5d75b7a886f37e2ac504511 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/0.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/0.rtcp Binary files differnew file mode 100644 index 0000000000..802eecf052 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/0.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/1.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/1.rtcp Binary files differnew file mode 100644 index 0000000000..c062793b3c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/1.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/10.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/10.rtcp Binary files differnew file mode 100644 index 0000000000..fdc7780218 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/10.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/11.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/11.rtcp Binary files differnew file mode 100644 index 0000000000..994f721dca --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/11.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/12.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/12.rtcp Binary files differnew file mode 100644 index 0000000000..557fe9c23a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/12.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/13.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/13.rtcp Binary files differnew file mode 100644 index 0000000000..0f1b1809a7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/13.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/14.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/14.rtcp Binary files differnew file mode 100644 index 0000000000..df6bfed86c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/14.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/15.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/15.rtcp Binary files differnew file mode 100644 index 0000000000..3b31b3079d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/15.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/16.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/16.rtcp Binary files differnew file mode 100644 index 0000000000..0496ddf910 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/16.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/17.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/17.rtcp Binary files differnew file mode 100644 index 0000000000..755b7198ba --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/17.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/18.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/18.rtcp Binary files differnew file mode 100644 index 0000000000..04fd1e3417 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/18.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/19.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/19.rtcp Binary files differnew file mode 100644 index 0000000000..8ae9812f10 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/19.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/2.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/2.rtcp Binary files differnew file mode 100644 index 0000000000..ba38a0a599 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/2.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/20.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/20.rtcp Binary files differnew file mode 100644 index 0000000000..debb7de940 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/20.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/21.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/21.rtcp Binary files differnew file mode 100644 index 0000000000..3fcbd405e2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/21.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/22.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/22.rtcp Binary files differnew file mode 100644 index 0000000000..3defd8c253 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/22.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/23.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/23.rtcp Binary files differnew file mode 100644 index 0000000000..211ccbd5be --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/23.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/24.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/24.rtcp Binary files differnew file mode 100644 index 0000000000..8ded9be7fd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/24.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/25.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/25.rtcp Binary files differnew file mode 100644 index 0000000000..b5c8146cef --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/25.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/26.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/26.rtcp Binary files differnew file mode 100644 index 0000000000..0fd4f25511 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/26.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/27.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/27.rtcp Binary files differnew file mode 100644 index 0000000000..2c8bb63c9c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/27.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/28.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/28.rtcp Binary files differnew file mode 100644 index 0000000000..6a20bc27d8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/28.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/29.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/29.rtcp Binary files differnew file mode 100644 index 0000000000..76fd214197 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/29.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/3.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/3.rtcp Binary files differnew file mode 100644 index 0000000000..72307e08bd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/3.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/30.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/30.rtcp Binary files differnew file mode 100644 index 0000000000..cfa38faa67 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/30.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/31.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/31.rtcp Binary files differnew file mode 100644 index 0000000000..8abf725057 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/31.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/32.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/32.rtcp Binary files differnew file mode 100644 index 0000000000..76518c88dd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/32.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/33.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/33.rtcp Binary files differnew file mode 100644 index 0000000000..92964965a6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/33.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/34.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/34.rtcp Binary files differnew file mode 100644 index 0000000000..9045c158b5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/34.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/35.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/35.rtcp Binary files differnew file mode 100644 index 0000000000..f86df02448 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/35.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/36.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/36.rtcp Binary files differnew file mode 100644 index 0000000000..d274d416a2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/36.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/37.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/37.rtcp Binary files differnew file mode 100644 index 0000000000..b4f04f4069 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/37.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/38.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/38.rtcp Binary files differnew file mode 100644 index 0000000000..8d65e0ff35 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/38.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/39.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/39.rtcp Binary files differnew file mode 100644 index 0000000000..fb969f85f0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/39.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/4.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/4.rtcp Binary files differnew file mode 100644 index 0000000000..5170185122 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/4.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/40.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/40.rtcp Binary files differnew file mode 100644 index 0000000000..279047c6b2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/40.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/41.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/41.rtcp Binary files differnew file mode 100644 index 0000000000..09a8a589bd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/41.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/42.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/42.rtcp Binary files differnew file mode 100644 index 0000000000..f727b190a7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/42.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/43.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/43.rtcp Binary files differnew file mode 100644 index 0000000000..9aab33a48a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/43.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/44.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/44.rtcp Binary files differnew file mode 100644 index 0000000000..2eba529c3a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/44.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/45.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/45.rtcp Binary files differnew file mode 100644 index 0000000000..50c0beabed --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/45.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/46.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/46.rtcp Binary files differnew file mode 100644 index 0000000000..2de424a5d1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/46.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/47.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/47.rtcp new file mode 100644 index 0000000000..71d530b41f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/47.rtcp @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/48.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/48.rtcp Binary files differnew file mode 100644 index 0000000000..665695029a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/48.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/49.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/49.rtcp Binary files differnew file mode 100644 index 0000000000..33b0f3d873 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/49.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/5.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/5.rtcp Binary files differnew file mode 100644 index 0000000000..46bef3242a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/5.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/50.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/50.rtcp Binary files differnew file mode 100644 index 0000000000..5bec125397 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/50.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/51.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/51.rtcp Binary files differnew file mode 100644 index 0000000000..ff94fb84b7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/51.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/52.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/52.rtcp Binary files differnew file mode 100644 index 0000000000..55cc76cd81 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/52.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/53.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/53.rtcp Binary files differnew file mode 100644 index 0000000000..ac11523c94 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/53.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/54.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/54.rtcp Binary files differnew file mode 100644 index 0000000000..f3f0bb8fa1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/54.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/55.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/55.rtcp new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/55.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/56.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/56.rtcp Binary files differnew file mode 100644 index 0000000000..f0012f1efa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/56.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/57.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/57.rtcp Binary files differnew file mode 100644 index 0000000000..61517f01d8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/57.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/58.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/58.rtcp Binary files differnew file mode 100644 index 0000000000..3688310a05 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/58.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/59.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/59.rtcp Binary files differnew file mode 100644 index 0000000000..e914f83b16 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/59.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/6.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/6.rtcp Binary files differnew file mode 100644 index 0000000000..dcad8f6b40 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/6.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/60.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/60.rtcp Binary files differnew file mode 100644 index 0000000000..8e999e7832 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/60.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/61.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/61.rtcp Binary files differnew file mode 100644 index 0000000000..eb38d237aa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/61.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/62.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/62.rtcp Binary files differnew file mode 100644 index 0000000000..6df94b715f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/62.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/63.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/63.rtcp Binary files differnew file mode 100644 index 0000000000..a3b2acb3a8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/63.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/64.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/64.rtcp Binary files differnew file mode 100644 index 0000000000..4d50c0f4ae --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/64.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/65.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/65.rtcp Binary files differnew file mode 100644 index 0000000000..537d10c6ce --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/65.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/66.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/66.rtcp Binary files differnew file mode 100644 index 0000000000..f280f3ca09 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/66.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/7.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/7.rtcp Binary files differnew file mode 100644 index 0000000000..f8f74e12c6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/7.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/8.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/8.rtcp Binary files differnew file mode 100644 index 0000000000..f0ceba83f4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/8.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/9.rtcp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/9.rtcp Binary files differnew file mode 100644 index 0000000000..7cc07893c3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtcp-corpus/9.rtcp diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-0 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-0 Binary files differnew file mode 100644 index 0000000000..c93ce82ec0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-0 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-1 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-1 Binary files differnew file mode 100644 index 0000000000..84834aefea --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-1 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-2 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-2 Binary files differnew file mode 100644 index 0000000000..3a5aedba9b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-2 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-3 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-3 Binary files differnew file mode 100644 index 0000000000..300309ff37 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-3 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-4 b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-4 Binary files differnew file mode 100644 index 0000000000..84834aefea --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/rtp-corpus/rtp-4 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/10.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/10.sdp new file mode 100644 index 0000000000..36319c4476 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/10.sdp @@ -0,0 +1,11 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:97 iLBC/8000 +m=audio 49172 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=sendonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/11.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/11.sdp new file mode 100644 index 0000000000..c3dbce401f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/11.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=audio 49174 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=recvonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/12.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/12.sdp new file mode 100644 index 0000000000..26d4ff6266 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/12.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/13.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/13.sdp new file mode 100644 index 0000000000..f625e3890c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/13.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49174 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 49170 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/14.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/14.sdp new file mode 100644 index 0000000000..c36b9fe6cb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/14.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 newhost.biloxi.example.com +t=0 0 +m=audio 49178 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 49188 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/15.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/15.sdp new file mode 100644 index 0000000000..26d4ff6266 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/15.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/16.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/16.sdp new file mode 100644 index 0000000000..1d187a0dc5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/16.sdp @@ -0,0 +1,10 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=audio 51372 RTP/AVP 97 101 +a=rtpmap:97 iLBC/8000 +a=rtpmap:101 telephone-event/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/17.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/17.sdp new file mode 100644 index 0000000000..a328d16a16 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/17.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 0 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=audio 49170 RTP/AVP 97 101 +a=rtpmap:97 iLBC/8000 +a=rtpmap:101 telephone-event/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/18.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/18.sdp new file mode 100644 index 0000000000..1e0d3f5705 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/18.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 99 +a=rtpmap:99 iLBC/8000 +m=video 51372 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/19.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/19.sdp new file mode 100644 index 0000000000..a9a5e12138 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/19.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 99 +a=rtpmap:99 iLBC/8000 +m=video 51374 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/2.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/2.sdp new file mode 100644 index 0000000000..96c4975ec0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/2.sdp @@ -0,0 +1,12 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 8 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/20.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/20.sdp new file mode 100644 index 0000000000..b2c072af1d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/20.sdp @@ -0,0 +1,10 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 99 +a=rtpmap:99 iLBC/8000 +m=video 51372 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/21.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/21.sdp new file mode 100644 index 0000000000..28e949133e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/21.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 99 +a=rtpmap:99 iLBC/8000 +m=video 51374 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/22.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/22.sdp new file mode 100644 index 0000000000..96c4975ec0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/22.sdp @@ -0,0 +1,12 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 8 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/23.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/23.sdp new file mode 100644 index 0000000000..36c7d70148 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/23.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49174 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 49172 RTP/AVP 32 +c=IN IP4 otherhost.biloxi.example.com +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/24.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/24.sdp new file mode 100644 index 0000000000..6cf5dc5894 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/24.sdp @@ -0,0 +1,8 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/25.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/25.sdp new file mode 100644 index 0000000000..ac1ec85b29 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/25.sdp @@ -0,0 +1,8 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 placeholder.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +a=sendonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/26.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/26.sdp new file mode 100644 index 0000000000..f0eb0d62a7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/26.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/27.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/27.sdp new file mode 100644 index 0000000000..1e4f3b3e19 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/27.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49178 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/28.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/28.sdp new file mode 100644 index 0000000000..36319c4476 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/28.sdp @@ -0,0 +1,11 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:97 iLBC/8000 +m=audio 49172 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=sendonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/29.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/29.sdp new file mode 100644 index 0000000000..c3dbce401f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/29.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=audio 49174 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=recvonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/3.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/3.sdp new file mode 100644 index 0000000000..b0142f5dcf --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/3.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49174 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 49170 RTP/AVP 32 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/30.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/30.sdp new file mode 100644 index 0000000000..0798631d2e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/30.sdp @@ -0,0 +1,11 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +a=sendonly +m=audio 49174 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=recvonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/31.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/31.sdp new file mode 100644 index 0000000000..78efdd8fcb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/31.sdp @@ -0,0 +1,11 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:97 iLBC/8000 +m=audio 49172 RTP/AVP 98 +a=rtpmap:98 telephone-event/8000 +a=sendonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/32.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/32.sdp new file mode 100644 index 0000000000..6cf5dc5894 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/32.sdp @@ -0,0 +1,8 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/33.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/33.sdp new file mode 100644 index 0000000000..23f462f5a6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/33.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/34.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/34.sdp new file mode 100644 index 0000000000..b52b947486 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/34.sdp @@ -0,0 +1,11 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=audio 48282 RTP/AVP 98 +c=IN IP4 mediaserver.biloxi.example.com +a=rtpmap:98 telephone-event/8000 +a=recvonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/35.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/35.sdp new file mode 100644 index 0000000000..07ad4f8758 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/35.sdp @@ -0,0 +1,11 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=audio 49172 RTP/AVP 98 +c=IN IP4 host.atlanta.example.com +a=rtpmap:98 telephone-event/8000 +a=sendonly diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/36.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/36.sdp new file mode 100644 index 0000000000..c75c6977bb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/36.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/37.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/37.sdp new file mode 100644 index 0000000000..d05dbd61fd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/37.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/38.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/38.sdp new file mode 100644 index 0000000000..253ac0705a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/38.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 49172 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/39.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/39.sdp new file mode 100644 index 0000000000..57d3203c74 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/39.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 49168 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/4.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/4.sdp new file mode 100644 index 0000000000..96c4975ec0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/4.sdp @@ -0,0 +1,12 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 8 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/40.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/40.sdp new file mode 100644 index 0000000000..26d4ff6266 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/40.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/41.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/41.sdp new file mode 100644 index 0000000000..f625e3890c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/41.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49174 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 49170 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/42.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/42.sdp new file mode 100644 index 0000000000..2dda9bb252 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/42.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49174 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 0 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/43.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/43.sdp new file mode 100644 index 0000000000..83a2bf9e66 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/43.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 +m=video 0 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/44.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/44.sdp new file mode 100644 index 0000000000..e187d7df7d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/44.sdp @@ -0,0 +1,5 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/45.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/45.sdp new file mode 100644 index 0000000000..9e344f035a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/45.sdp @@ -0,0 +1,5 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/46.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/46.sdp new file mode 100644 index 0000000000..8a63ca0992 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/46.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/47.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/47.sdp new file mode 100644 index 0000000000..66dadbb93f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/47.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/48.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/48.sdp new file mode 100644 index 0000000000..6df76ab942 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/48.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 0.0.0.0 +t=0 0 +m=audio 23442 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/49.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/49.sdp new file mode 100644 index 0000000000..23f462f5a6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/49.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/5.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/5.sdp new file mode 100644 index 0000000000..264ab8024f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/5.sdp @@ -0,0 +1,10 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 0 8 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +m=video 0 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/50.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/50.sdp new file mode 100644 index 0000000000..8a63ca0992 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/50.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/51.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/51.sdp new file mode 100644 index 0000000000..23f462f5a6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/51.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/52.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/52.sdp new file mode 100644 index 0000000000..7c1730eb1e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/52.sdp @@ -0,0 +1,7 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/53.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/53.sdp new file mode 100644 index 0000000000..599157691a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/53.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 0.0.0.0 +t=0 0 +m=audio 9322 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/54.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/54.sdp new file mode 100644 index 0000000000..66dadbb93f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/54.sdp @@ -0,0 +1,7 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/55.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/55.sdp new file mode 100644 index 0000000000..bd724c471b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/55.sdp @@ -0,0 +1,8 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 97 +a=rtpmap:97 iLBC/8000 + diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/6.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/6.sdp new file mode 100644 index 0000000000..3f80345e30 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/6.sdp @@ -0,0 +1,9 @@ +v=0 +o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 51372 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 0 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/7.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/7.sdp new file mode 100644 index 0000000000..920ad8229e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/7.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 0 +a=rtpmap:0 PCMU/8000 +m=video 0 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/8.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/8.sdp new file mode 100644 index 0000000000..96c4975ec0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/8.sdp @@ -0,0 +1,12 @@ +v=0 +o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com +s= +c=IN IP4 host.atlanta.example.com +t=0 0 +m=audio 49170 RTP/AVP 0 8 97 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:97 iLBC/8000 +m=video 51372 RTP/AVP 31 32 +a=rtpmap:31 H261/90000 +a=rtpmap:32 MPV/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/9.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/9.sdp new file mode 100644 index 0000000000..a9a5e12138 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/9.sdp @@ -0,0 +1,9 @@ +v=0 +o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com +s= +c=IN IP4 host.biloxi.example.com +t=0 0 +m=audio 49172 RTP/AVP 99 +a=rtpmap:99 iLBC/8000 +m=video 51374 RTP/AVP 31 +a=rtpmap:31 H261/90000 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-1.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-1.sdp new file mode 100644 index 0000000000..6d664bc051 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-1.sdp @@ -0,0 +1,58 @@ +v=0 +o=mozilla...THIS_IS_SDPARTA-46.0.1 5115930144083302970 0 IN IP4 0.0.0.0 +s=- +t=0 0 +a=fingerprint:sha-256 24:67:5E:1B:9A:B9:CF:36:C5:30:8F:35:F7:B1:50:66:88:81:92:CB:29:BA:53:A5:02:C8:0A:A5:4E:9C:AE:D9 +a=group:BUNDLE sdparta_0 sdparta_1 sdparta_2 +a=ice-options:trickle +a=msid-semantic:WMS * +m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 +c=IN IP4 0.0.0.0 +a=sendrecv +a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level +a=fmtp:109 maxplaybackrate=48000;stereo=1 +a=ice-pwd:b9f3911b591ae61e2d7f6af0531fd2a3 +a=ice-ufrag:3edc9012 +a=mid:sdparta_0 +a=msid:{258e92fb-547c-40ca-92e9-efe0cedb4cba} {bd1fafff-bfd0-40d4-b0a3-2a87cff307ee} +a=rtcp-mux +a=rtpmap:109 opus/48000/2 +a=rtpmap:9 G722/8000/1 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=setup:actpass +a=ssrc:2121669360 cname:{387b0735-bde2-43a4-8484-7f5663b60f24} +m=video 9 UDP/TLS/RTP/SAVPF 120 126 97 +c=IN IP4 0.0.0.0 +a=sendrecv +a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1 +a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1 +a=fmtp:120 max-fs=12288;max-fr=60 +a=ice-pwd:b9f3911b591ae61e2d7f6af0531fd2a3 +a=ice-ufrag:3edc9012 +a=mid:sdparta_1 +a=msid:{258e92fb-547c-40ca-92e9-efe0cedb4cba} {9e8f5867-a9aa-4489-8bd4-3a8a57a5e592} +a=rtcp-fb:120 nack +a=rtcp-fb:120 nack pli +a=rtcp-fb:120 ccm fir +a=rtcp-fb:126 nack +a=rtcp-fb:126 nack pli +a=rtcp-fb:126 ccm fir +a=rtcp-fb:97 nack +a=rtcp-fb:97 nack pli +a=rtcp-fb:97 ccm fir +a=rtcp-mux +a=rtpmap:120 VP8/90000 +a=rtpmap:126 H264/90000 +a=rtpmap:97 H264/90000 +a=setup:actpass +a=ssrc:2158832026 cname:{387b0735-bde2-43a4-8484-7f5663b60f24} +m=application 9 DTLS/SCTP 5000 +c=IN IP4 0.0.0.0 +a=sendrecv +a=ice-pwd:b9f3911b591ae61e2d7f6af0531fd2a3 +a=ice-ufrag:3edc9012 +a=mid:sdparta_2 +a=sctpmap:5000 webrtc-datachannel 256 +a=setup:actpass +a=ssrc:2670959794 cname:{387b0735-bde2-43a4-8484-7f5663b60f24} diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-2.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-2.sdp new file mode 100644 index 0000000000..07806eb225 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/firefox-2.sdp @@ -0,0 +1,43 @@ +v=0 +o=mozilla...THIS_IS_SDPARTA-46.0.1 3068771576687940834 0 IN IP4 0.0.0.0 +s=- +t=0 0 +a=fingerprint:sha-256 AD:87:B3:11:E4:E2:BA:EF:D2:3F:2E:AC:24:57:8E:DC:1F:67:41:29:44:C4:96:E3:62:90:CC:90:59:CA:2C:84 +a=group:BUNDLE sdparta_0 sdparta_1 sdparta_2 +a=ice-options:trickle +a=msid-semantic:WMS * +m=audio 9 UDP/TLS/RTP/SAVPF 109 +c=IN IP4 0.0.0.0 +a=recvonly +a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level +a=fmtp:109 maxplaybackrate=48000;stereo=1 +a=ice-pwd:ff4c4dc6fe92e1f22d2c10352d8967d5 +a=ice-ufrag:a539544b +a=mid:sdparta_0 +a=rtcp-mux +a=rtpmap:109 opus/48000/2 +a=setup:active +a=ssrc:600995474 cname:{5b598a29-a81b-4ffe-a2c5-507778057e7a} +m=video 9 UDP/TLS/RTP/SAVPF 120 +c=IN IP4 0.0.0.0 +a=recvonly +a=fmtp:120 max-fs=12288;max-fr=60 +a=ice-pwd:ff4c4dc6fe92e1f22d2c10352d8967d5 +a=ice-ufrag:a539544b +a=mid:sdparta_1 +a=rtcp-fb:120 nack +a=rtcp-fb:120 nack pli +a=rtcp-fb:120 ccm fir +a=rtcp-mux +a=rtpmap:120 VP8/90000 +a=setup:active +a=ssrc:3480150809 cname:{5b598a29-a81b-4ffe-a2c5-507778057e7a} +m=application 9 DTLS/SCTP 5000 +c=IN IP4 0.0.0.0 +a=sendrecv +a=ice-pwd:ff4c4dc6fe92e1f22d2c10352d8967d5 +a=ice-ufrag:a539544b +a=mid:sdparta_2 +a=sctpmap:5000 webrtc-datachannel 256 +a=setup:active +a=ssrc:3021788991 cname:{5b598a29-a81b-4ffe-a2c5-507778057e7a} diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-1.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-1.sdp new file mode 100644 index 0000000000..42d15e81f4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-1.sdp @@ -0,0 +1,85 @@ +v=0 +o=- 1656229333038673902 2 IN IP4 127.0.0.1 +s=- +t=0 0 +a=group:BUNDLE audio video data +a=msid-semantic: WMS Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 +m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:1Jyk4q3nLIL5NiMx +a=ice-pwd:GL8/iarMqPIhImfnsG2dyXlH +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:actpass +a=mid:audio +a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level +a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time +a=sendrecv +a=rtcp-mux +a=rtpmap:111 opus/48000/2 +a=rtcp-fb:111 transport-cc +a=fmtp:111 minptime=10; useinbandfec=1 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=rtpmap:9 G722/8000 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:106 CN/32000 +a=rtpmap:105 CN/16000 +a=rtpmap:13 CN/8000 +a=rtpmap:126 telephone-event/8000 +a=maxptime:60 +a=ssrc:2233075910 cname:VhHMGYCjn4alR9zP +a=ssrc:2233075910 msid:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 689d3496-0896-4d52-bce6-8e90512a368b +a=ssrc:2233075910 mslabel:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 +a=ssrc:2233075910 label:689d3496-0896-4d52-bce6-8e90512a368b +m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96 97 98 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:1Jyk4q3nLIL5NiMx +a=ice-pwd:GL8/iarMqPIhImfnsG2dyXlH +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:actpass +a=mid:video +a=extmap:2 urn:ietf:params:rtp-hdrext:toffset +a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time +a=extmap:4 urn:3gpp:video-orientation +a=sendrecv +a=rtcp-mux +a=rtpmap:100 VP8/90000 +a=rtcp-fb:100 ccm fir +a=rtcp-fb:100 nack +a=rtcp-fb:100 nack pli +a=rtcp-fb:100 goog-remb +a=rtcp-fb:100 transport-cc +a=rtpmap:101 VP9/90000 +a=rtcp-fb:101 ccm fir +a=rtcp-fb:101 nack +a=rtcp-fb:101 nack pli +a=rtcp-fb:101 goog-remb +a=rtcp-fb:101 transport-cc +a=rtpmap:116 red/90000 +a=rtpmap:117 ulpfec/90000 +a=rtpmap:96 rtx/90000 +a=fmtp:96 apt=100 +a=rtpmap:97 rtx/90000 +a=fmtp:97 apt=101 +a=rtpmap:98 rtx/90000 +a=fmtp:98 apt=116 +a=ssrc-group:FID 50498894 2399294607 +a=ssrc:50498894 cname:VhHMGYCjn4alR9zP +a=ssrc:50498894 msid:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 1aef96f4-fc4c-4f86-98f3-0fbf4f625f70 +a=ssrc:50498894 mslabel:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 +a=ssrc:50498894 label:1aef96f4-fc4c-4f86-98f3-0fbf4f625f70 +a=ssrc:2399294607 cname:VhHMGYCjn4alR9zP +a=ssrc:2399294607 msid:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 1aef96f4-fc4c-4f86-98f3-0fbf4f625f70 +a=ssrc:2399294607 mslabel:Ppsa09YmDLBombOh5e8HqfqxEIPF69a46Hd4 +a=ssrc:2399294607 label:1aef96f4-fc4c-4f86-98f3-0fbf4f625f70 +m=application 9 DTLS/SCTP 5000 +c=IN IP4 0.0.0.0 +a=ice-ufrag:1Jyk4q3nLIL5NiMx +a=ice-pwd:GL8/iarMqPIhImfnsG2dyXlH +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:actpass +a=mid:data +a=sctpmap:5000 webrtc-datachannel 1024 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-2.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-2.sdp new file mode 100644 index 0000000000..6ed4e3b4a8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/opera-2.sdp @@ -0,0 +1,73 @@ +v=0 +o=- 2013283641453412290 2 IN IP4 127.0.0.1 +s=- +t=0 0 +a=group:BUNDLE audio video data +a=msid-semantic: WMS +m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:YVa3KTlFDCwsfPOQ +a=ice-pwd:ByUn1Od88VokVM0rtQ/bbeZa +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:active +a=mid:audio +a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level +a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time +a=recvonly +a=rtcp-mux +a=rtpmap:111 opus/48000/2 +a=rtcp-fb:111 transport-cc +a=fmtp:111 minptime=10; useinbandfec=1 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=rtpmap:9 G722/8000 +a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 +a=rtpmap:106 CN/32000 +a=rtpmap:105 CN/16000 +a=rtpmap:13 CN/8000 +a=rtpmap:126 telephone-event/8000 +a=maxptime:60 +m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96 97 98 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:YVa3KTlFDCwsfPOQ +a=ice-pwd:ByUn1Od88VokVM0rtQ/bbeZa +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:active +a=mid:video +a=extmap:2 urn:ietf:params:rtp-hdrext:toffset +a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time +a=extmap:4 urn:3gpp:video-orientation +a=recvonly +a=rtcp-mux +a=rtpmap:100 VP8/90000 +a=rtcp-fb:100 ccm fir +a=rtcp-fb:100 nack +a=rtcp-fb:100 nack pli +a=rtcp-fb:100 goog-remb +a=rtcp-fb:100 transport-cc +a=rtpmap:101 VP9/90000 +a=rtcp-fb:101 ccm fir +a=rtcp-fb:101 nack +a=rtcp-fb:101 nack pli +a=rtcp-fb:101 goog-remb +a=rtcp-fb:101 transport-cc +a=rtpmap:116 red/90000 +a=rtpmap:117 ulpfec/90000 +a=rtpmap:96 rtx/90000 +a=fmtp:96 apt=100 +a=rtpmap:97 rtx/90000 +a=fmtp:97 apt=101 +a=rtpmap:98 rtx/90000 +a=fmtp:98 apt=116 +m=application 9 DTLS/SCTP 5000 +c=IN IP4 0.0.0.0 +b=AS:30 +a=ice-ufrag:YVa3KTlFDCwsfPOQ +a=ice-pwd:ByUn1Od88VokVM0rtQ/bbeZa +a=fingerprint:sha-256 5A:16:96:94:B2:AC:60:27:64:C5:FE:46:6C:02:C0:CD:49:E3:E2:0B:5B:C9:D4:86:C4:B3:A4:F2:23:80:7A:DA +a=setup:active +a=mid:data +a=sctpmap:5000 webrtc-datachannel 1024 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-1.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-1.sdp new file mode 100644 index 0000000000..ce349ac30f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-1.sdp @@ -0,0 +1,52 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS local_stream_1 +m=audio 2345 RTP/SAVPF 111 103 104 +c=IN IP4 74.125.127.126 +a=rtcp:2347 IN IP4 74.125.127.126 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host generation 2 +a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx raddr 192.168.1.5 rport 2346 generation 2 +a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx raddr 192.168.1.5 rport 2348 generation 2 +a=ice-ufrag:ufrag_voice +a=ice-pwd:pwd_voice +a=mid:audio_content_name +a=sendrecv +a=rtcp-mux +a=rtcp-rsize +a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 dummy_session_params +a=rtpmap:111 opus/48000/2 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=ssrc:1 cname:stream_1_cname +a=ssrc:1 msid:local_stream_1 audio_track_id_1 +a=ssrc:1 mslabel:local_stream_1 +a=ssrc:1 label:audio_track_id_1 +m=video 3457 RTP/SAVPF 120 +c=IN IP4 74.125.224.39 +a=rtcp:3456 IN IP4 74.125.224.39 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host generation 2 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host generation 2 +a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay generation 2 +a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay generation 2 +a=ice-ufrag:ufrag_video +a=ice-pwd:pwd_video +a=mid:video_content_name +a=sendrecv +a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32 +a=rtpmap:120 VP8/90000 +a=ssrc-group:FEC 2 3 +a=ssrc:2 cname:stream_1_cname +a=ssrc:2 msid:local_stream_1 video_track_id_1 +a=ssrc:2 mslabel:local_stream_1 +a=ssrc:2 label:video_track_id_1 +a=ssrc:3 cname:stream_1_cname +a=ssrc:3 msid:local_stream_1 video_track_id_1 +a=ssrc:3 mslabel:local_stream_1 +a=ssrc:3 label:video_track_id_1 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-2.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-2.sdp new file mode 100644 index 0000000000..a35392513f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-2.sdp @@ -0,0 +1,40 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS local_stream_1 +m=audio 9 RTP/SAVPF 111 103 104 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:ufrag_voice +a=ice-pwd:pwd_voice +a=mid:audio_content_name +a=sendrecv +a=rtcp-mux +a=rtcp-rsize +a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 dummy_session_params +a=rtpmap:111 opus/48000/2 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=ssrc:1 cname:stream_1_cname +a=ssrc:1 msid:local_stream_1 audio_track_id_1 +a=ssrc:1 mslabel:local_stream_1 +a=ssrc:1 label:audio_track_id_1 +m=video 9 RTP/SAVPF 120 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:ufrag_video +a=ice-pwd:pwd_video +a=mid:video_content_name +a=sendrecv +a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32 +a=rtpmap:120 VP8/90000 +a=ssrc-group:FEC 2 3 +a=ssrc:2 cname:stream_1_cname +a=ssrc:2 msid:local_stream_1 video_track_id_1 +a=ssrc:2 mslabel:local_stream_1 +a=ssrc:2 label:video_track_id_1 +a=ssrc:3 cname:stream_1_cname +a=ssrc:3 msid:local_stream_1 video_track_id_1 +a=ssrc:3 mslabel:local_stream_1 +a=ssrc:3 label:video_track_id_1 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-3.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-3.sdp new file mode 100644 index 0000000000..50f8e55ef7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-3.sdp @@ -0,0 +1,13 @@ +m=application 9 RTP/SAVPF 101 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:ufrag_data +a=ice-pwd:pwd_data +a=mid:data_content_name +a=sendrecv +a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5 +a=rtpmap:101 google-data/90000 +a=ssrc:10 cname:data_channel_cname +a=ssrc:10 msid:data_channel data_channeld0 +a=ssrc:10 mslabel:data_channel +a=ssrc:10 label:data_channeld0 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-4.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-4.sdp new file mode 100644 index 0000000000..709db42c00 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-4.sdp @@ -0,0 +1,11 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS +m=audio 9 RTP/SAVPF 111 103 104 +c=IN IP4 0.0.0.0 +a=x-google-flag:conference +m=video 9 RTP/SAVPF 120 +c=IN IP4 0.0.0.0 +a=x-google-flag:conference diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-5.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-5.sdp new file mode 100644 index 0000000000..c440386062 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-5.sdp @@ -0,0 +1,5 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS local_stream diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-6.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-6.sdp new file mode 100644 index 0000000000..e07b5647bf --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-6.sdp @@ -0,0 +1,12 @@ +m=audio 9 RTP/SAVPF 111 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:ufrag_voice +a=ice-pwd:pwd_voice +a=mid:audio_content_name +a=sendrecv +a=rtpmap:111 opus/48000/2 +a=ssrc:1 cname:stream_1_cname +a=ssrc:1 msid:local_stream audio_track_id_1 +a=ssrc:1 mslabel:local_stream +a=ssrc:1 label:audio_track_id_1 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-7.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-7.sdp new file mode 100644 index 0000000000..8bdacc2baa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-7.sdp @@ -0,0 +1,12 @@ +m=video 9 RTP/SAVPF 120 +c=IN IP4 0.0.0.0 +a=rtcp:9 IN IP4 0.0.0.0 +a=ice-ufrag:ufrag_video +a=ice-pwd:pwd_video +a=mid:video_content_name +a=sendrecv +a=rtpmap:120 VP8/90000 +a=ssrc:2 cname:stream_1_cname +a=ssrc:2 msid:local_stream video_track_id_1 +a=ssrc:2 mslabel:local_stream +a=ssrc:2 label:video_track_id_1 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-8.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-8.sdp new file mode 100644 index 0000000000..9688fc46a2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-8.sdp @@ -0,0 +1,64 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS local_stream_1 local_stream_2 +m=audio 2345 RTP/SAVPF 111 103 104 +c=IN IP4 74.125.127.126 +a=rtcp:2347 IN IP4 74.125.127.126 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host generation 2 +a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx raddr 192.168.1.5 rport 2346 generation 2 +a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx raddr 192.168.1.5 rport 2348 generation 2 +a=ice-ufrag:ufrag_voice +a=ice-pwd:pwd_voice +a=mid:audio_content_name +a=sendrecv +a=rtcp-mux +a=rtcp-rsize +a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 dummy_session_params +a=rtpmap:111 opus/48000/2 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=ssrc:1 cname:stream_1_cname +a=ssrc:1 msid:local_stream_1 audio_track_id_1 +a=ssrc:1 mslabel:local_stream_1 +a=ssrc:1 label:audio_track_id_1 +a=ssrc:4 cname:stream_2_cname +a=ssrc:4 msid:local_stream_2 audio_track_id_2 +a=ssrc:4 mslabel:local_stream_2 +a=ssrc:4 label:audio_track_id_2 +m=video 3457 RTP/SAVPF 120 +c=IN IP4 74.125.224.39 +a=rtcp:3456 IN IP4 74.125.224.39 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host generation 2 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host generation 2 +a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay generation 2 +a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay generation 2 +a=ice-ufrag:ufrag_video +a=ice-pwd:pwd_video +a=mid:video_content_name +a=sendrecv +a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32 +a=rtpmap:120 VP8/90000 +a=ssrc-group:FEC 2 3 +a=ssrc:2 cname:stream_1_cname +a=ssrc:2 msid:local_stream_1 video_track_id_1 +a=ssrc:2 mslabel:local_stream_1 +a=ssrc:2 label:video_track_id_1 +a=ssrc:3 cname:stream_1_cname +a=ssrc:3 msid:local_stream_1 video_track_id_1 +a=ssrc:3 mslabel:local_stream_1 +a=ssrc:3 label:video_track_id_1 +a=ssrc:5 cname:stream_2_cname +a=ssrc:5 msid:local_stream_2 video_track_id_2 +a=ssrc:5 mslabel:local_stream_2 +a=ssrc:5 label:video_track_id_2 +a=ssrc:6 cname:stream_2_cname +a=ssrc:6 msid:local_stream_2 video_track_id_3 +a=ssrc:6 mslabel:local_stream_2 +a=ssrc:6 label:video_track_id_3 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-9.sdp b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-9.sdp new file mode 100644 index 0000000000..8c7c4c7c3d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp-corpus/unittest-9.sdp @@ -0,0 +1,66 @@ +v=0 +o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1 +s=- +t=0 0 +a=msid-semantic: WMS local_stream_1 local_stream_2 +m=audio 2345 RTP/SAVPF 111 103 104 +c=IN IP4 74.125.127.126 +a=rtcp:2347 IN IP4 74.125.127.126 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host generation 2 +a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx raddr 192.168.1.5 rport 2346 generation 2 +a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx raddr 192.168.1.5 rport 2348 generation 2 +a=ice-ufrag:ufrag_voice +a=ice-pwd:pwd_voice +a=mid:audio_content_name +a=msid:local_stream_1 audio_track_id_1 +a=sendrecv +a=rtcp-mux +a=rtcp-rsize +a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 dummy_session_params +a=rtpmap:111 opus/48000/2 +a=rtpmap:103 ISAC/16000 +a=rtpmap:104 ISAC/32000 +a=ssrc:1 cname:stream_1_cname +a=ssrc:1 msid:local_stream_1 audio_track_id_1 +a=ssrc:1 mslabel:local_stream_1 +a=ssrc:1 label:audio_track_id_1 +a=ssrc:4 cname:stream_2_cname +a=ssrc:4 msid:local_stream_2 audio_track_id_2 +a=ssrc:4 mslabel:local_stream_2 +a=ssrc:4 label:audio_track_id_2 +m=video 3457 RTP/SAVPF 120 +c=IN IP4 74.125.224.39 +a=rtcp:3456 IN IP4 74.125.224.39 +a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host generation 2 +a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host generation 2 +a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host generation 2 +a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host generation 2 +a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay generation 2 +a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay generation 2 +a=ice-ufrag:ufrag_video +a=ice-pwd:pwd_video +a=mid:video_content_name +a=msid:local_stream_1 video_track_id_1 +a=sendrecv +a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32 +a=rtpmap:120 VP8/90000 +a=ssrc-group:FEC 2 3 +a=ssrc:2 cname:stream_1_cname +a=ssrc:2 msid:local_stream_1 video_track_id_1 +a=ssrc:2 mslabel:local_stream_1 +a=ssrc:2 label:video_track_id_1 +a=ssrc:3 cname:stream_1_cname +a=ssrc:3 msid:local_stream_1 video_track_id_1 +a=ssrc:3 mslabel:local_stream_1 +a=ssrc:3 label:video_track_id_1 +a=ssrc:5 cname:stream_2_cname +a=ssrc:5 msid:local_stream_2 video_track_id_2 +a=ssrc:5 mslabel:local_stream_2 +a=ssrc:5 label:video_track_id_2 +a=ssrc:6 cname:stream_2_cname +a=ssrc:6 msid:local_stream_2 video_track_id_3 +a=ssrc:6 mslabel:local_stream_2 +a=ssrc:6 label:video_track_id_3 diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp.tokens b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp.tokens new file mode 100644 index 0000000000..ddfdad5811 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/sdp.tokens @@ -0,0 +1,56 @@ +"0.0.0.0" +"127.0.0.1" +"application" +"audio" +"candidate" +"cname" +"conference" +"crypto" +"default" +"extmap" +"fingerprint" +"fmtp" +"generation" +"group" +"host" +"ice-lite" +"ice-options" +"ice-pwd" +"ice-ufrag" +"inactive" +"IP4" +"IP6" +"ISAC" +"label" +"mid" +"msid" +"msid-semantic" +"mslabel" +"network-cost" +"network-id" +"prflx" +"pwd" +"raddr" +"recvonly" +"relay" +"rport" +"rtcp" +"rtcp-fb" +"rtcp-mux" +"rtcp-rsize" +"rtpmap" +"sctpmap" +"sctp-port" +"sendonly" +"sendrecv" +"setup" +"srflx" +"ssrc" +"ssrc-group" +"tcptype" +"typ" +"ufrag" +"video" +"webrtc-datachannel" +"WMS" +"x-google-flag"
\ No newline at end of file diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/0.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/0.stun Binary files differnew file mode 100644 index 0000000000..205997706f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/0.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/1.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/1.stun Binary files differnew file mode 100644 index 0000000000..1f82c03ffa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/1.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/10.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/10.stun Binary files differnew file mode 100644 index 0000000000..a6b06b2be8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/10.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/11.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/11.stun Binary files differnew file mode 100644 index 0000000000..1f82c03ffa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/11.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/12.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/12.stun Binary files differnew file mode 100644 index 0000000000..cb91baa250 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/12.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/13.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/13.stun Binary files differnew file mode 100644 index 0000000000..63298fce7d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/13.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/14.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/14.stun Binary files differnew file mode 100644 index 0000000000..31f9f732d4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/14.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/15.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/15.stun Binary files differnew file mode 100644 index 0000000000..3d15a67193 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/15.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/16.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/16.stun Binary files differnew file mode 100644 index 0000000000..8ccf0af26d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/16.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/17.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/17.stun Binary files differnew file mode 100644 index 0000000000..9c3efa0b80 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/17.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/2.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/2.stun Binary files differnew file mode 100644 index 0000000000..50fe614adb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/2.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/3.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/3.stun Binary files differnew file mode 100644 index 0000000000..50fe614adb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/3.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/4.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/4.stun Binary files differnew file mode 100644 index 0000000000..a6b06b2be8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/4.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/5.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/5.stun Binary files differnew file mode 100644 index 0000000000..c0a79fa7ab --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/5.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/6.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/6.stun Binary files differnew file mode 100644 index 0000000000..1f43a4787d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/6.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/7.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/7.stun Binary files differnew file mode 100644 index 0000000000..f5e824a68d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/7.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/8.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/8.stun Binary files differnew file mode 100644 index 0000000000..99f4e3bcf8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/8.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/9.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/9.stun Binary files differnew file mode 100644 index 0000000000..cbbcab4e74 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/9.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/validator-crash-1.stun b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/validator-crash-1.stun Binary files differnew file mode 100644 index 0000000000..5428c38d75 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun-corpus/validator-crash-1.stun diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun.tokens b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun.tokens new file mode 100644 index 0000000000..e01130f12e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/corpora/stun.tokens @@ -0,0 +1,2 @@ +"2112A442" +"12214A24" diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_header_reader_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_header_reader_fuzzer.cc new file mode 100644 index 0000000000..a5694ea300 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_header_reader_fuzzer.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "rtc_base/scoped_ref_ptr.h" + +namespace webrtc { + +using Packet = ForwardErrorCorrection::Packet; +using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; + +void FuzzOneInput(const uint8_t* data, size_t size) { + ReceivedFecPacket packet; + packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + const size_t packet_size = + std::min(size, static_cast<size_t>(IP_PACKET_SIZE)); + memcpy(packet.pkt->data, data, packet_size); + packet.pkt->length = packet_size; + + FlexfecHeaderReader flexfec_reader; + flexfec_reader.ReadFecHeader(&packet); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_receiver_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_receiver_fuzzer.cc new file mode 100644 index 0000000000..14208bd7ec --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_receiver_fuzzer.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "modules/rtp_rtcp/include/flexfec_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { + +namespace { +class DummyCallback : public RecoveredPacketReceiver { + void OnRecoveredPacket(const uint8_t* packet, size_t length) override {} +}; +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + constexpr size_t kMinDataNeeded = 12; + if (size < kMinDataNeeded) { + return; + } + + uint32_t flexfec_ssrc; + memcpy(&flexfec_ssrc, data + 0, 4); + uint16_t flexfec_seq_num; + memcpy(&flexfec_seq_num, data + 4, 2); + uint32_t media_ssrc; + memcpy(&media_ssrc, data + 6, 4); + uint16_t media_seq_num; + memcpy(&media_seq_num, data + 10, 2); + + DummyCallback callback; + FlexfecReceiver receiver(flexfec_ssrc, media_ssrc, &callback); + + std::unique_ptr<uint8_t[]> packet; + size_t packet_length; + size_t i = kMinDataNeeded; + while (i < size) { + packet_length = kRtpHeaderSize + data[i++]; + packet = std::unique_ptr<uint8_t[]>(new uint8_t[packet_length]); + if (i + packet_length >= size) { + break; + } + memcpy(packet.get(), data + i, packet_length); + i += packet_length; + if (i < size && data[i++] % 2 == 0) { + // Simulate FlexFEC packet. + ByteWriter<uint16_t>::WriteBigEndian(packet.get() + 2, flexfec_seq_num++); + ByteWriter<uint32_t>::WriteBigEndian(packet.get() + 8, flexfec_ssrc); + } else { + // Simulate media packet. + ByteWriter<uint16_t>::WriteBigEndian(packet.get() + 2, media_seq_num++); + ByteWriter<uint32_t>::WriteBigEndian(packet.get() + 8, media_ssrc); + } + RtpPacketReceived parsed_packet; + if (parsed_packet.Parse(packet.get(), packet_length)) { + receiver.OnRtpPacket(parsed_packet); + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_sender_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_sender_fuzzer.cc new file mode 100644 index 0000000000..64bc3ed247 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/flexfec_sender_fuzzer.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> + +#include "modules/rtp_rtcp/include/flexfec_sender.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +namespace { + +constexpr int kFlexfecPayloadType = 123; +constexpr uint32_t kMediaSsrc = 1234; +constexpr uint32_t kFlexfecSsrc = 5678; +const std::vector<RtpExtension> kNoRtpHeaderExtensions; +const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes; + +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + size_t i = 0; + if (size < 5) { + return; + } + + SimulatedClock clock(1 + data[i++]); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + FecProtectionParams params = { + data[i++], static_cast<int>(data[i++] % 100), + data[i++] <= 127 ? kFecMaskRandom : kFecMaskBursty}; + sender.SetFecParameters(params); + uint16_t seq_num = data[i++]; + + while (i + 1 < size) { + // Everything past the base RTP header (12 bytes) is payload, + // from the perspective of FlexFEC. + size_t payload_size = data[i++]; + if (i + kRtpHeaderSize + payload_size >= size) + break; + std::unique_ptr<uint8_t[]> packet( + new uint8_t[kRtpHeaderSize + payload_size]); + memcpy(packet.get(), &data[i], kRtpHeaderSize + payload_size); + i += kRtpHeaderSize + payload_size; + ByteWriter<uint16_t>::WriteBigEndian(&packet[2], seq_num++); + ByteWriter<uint32_t>::WriteBigEndian(&packet[8], kMediaSsrc); + RtpPacketToSend rtp_packet(nullptr); + if (!rtp_packet.Parse(packet.get(), kRtpHeaderSize + payload_size)) + break; + sender.AddRtpPacketAndGenerateFec(rtp_packet); + if (sender.FecAvailable()) { + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = + sender.GetFecPackets(); + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/h264_bitstream_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/h264_bitstream_parser_fuzzer.cc new file mode 100644 index 0000000000..a9384d73f3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/h264_bitstream_parser_fuzzer.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include <stdint.h> + +#include "common_video/h264/h264_bitstream_parser.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + H264BitstreamParser h264_bitstream_parser; + h264_bitstream_parser.ParseBitstream(data, size); + int qp; + h264_bitstream_parser.GetLastSliceQp(&qp); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/h264_depacketizer_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/h264_depacketizer_fuzzer.cc new file mode 100644 index 0000000000..2cefb1e1b3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/h264_depacketizer_fuzzer.cc @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtp_format_h264.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + RtpDepacketizerH264 depacketizer; + RtpDepacketizer::ParsedPayload parsed_payload; + depacketizer.Parse(&parsed_payload, data, size); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/neteq_rtp_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/neteq_rtp_fuzzer.cc new file mode 100644 index 0000000000..0f26367b68 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/neteq_rtp_fuzzer.cc @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <cmath> +#include <memory> +#include <vector> + +#include "api/array_view.h" +#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" +#include "modules/audio_coding/neteq/tools/audio_checksum.h" +#include "modules/audio_coding/neteq/tools/encode_neteq_input.h" +#include "modules/audio_coding/neteq/tools/neteq_test.h" +#include "modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace test { +namespace { +constexpr int kPayloadType = 95; + +class SineGenerator : public EncodeNetEqInput::Generator { + public: + explicit SineGenerator(int sample_rate_hz) + : sample_rate_hz_(sample_rate_hz) {} + + rtc::ArrayView<const int16_t> Generate(size_t num_samples) override { + if (samples_.size() < num_samples) { + samples_.resize(num_samples); + } + + rtc::ArrayView<int16_t> output(samples_.data(), num_samples); + for (auto& x : output) { + x = static_cast<int16_t>(2000.0 * std::sin(phase_)); + phase_ += 2 * kPi * kFreqHz / sample_rate_hz_; + } + return output; + } + + private: + static constexpr int kFreqHz = 300; // The sinewave frequency. + const int sample_rate_hz_; + const double kPi = std::acos(-1); + std::vector<int16_t> samples_; + double phase_ = 0.0; +}; + +class FuzzRtpInput : public NetEqInput { + public: + explicit FuzzRtpInput(rtc::ArrayView<const uint8_t> data) : data_(data) { + AudioEncoderPcm16B::Config config; + config.payload_type = kPayloadType; + config.sample_rate_hz = 32000; + std::unique_ptr<AudioEncoder> encoder(new AudioEncoderPcm16B(config)); + std::unique_ptr<EncodeNetEqInput::Generator> generator( + new SineGenerator(config.sample_rate_hz)); + input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder), + std::numeric_limits<int64_t>::max())); + packet_ = input_->PopPacket(); + FuzzHeader(); + } + + rtc::Optional<int64_t> NextPacketTime() const override { + return packet_->time_ms; + } + + rtc::Optional<int64_t> NextOutputEventTime() const override { + return input_->NextOutputEventTime(); + } + + std::unique_ptr<PacketData> PopPacket() override { + RTC_DCHECK(packet_); + std::unique_ptr<PacketData> packet_to_return = std::move(packet_); + packet_ = input_->PopPacket(); + FuzzHeader(); + return packet_to_return; + } + + void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); } + + bool ended() const override { return ended_; } + + rtc::Optional<RTPHeader> NextHeader() const override { + RTC_DCHECK(packet_); + return packet_->header; + } + + private: + void FuzzHeader() { + constexpr size_t kNumBytesToFuzz = 11; + if (data_ix_ + kNumBytesToFuzz > data_.size()) { + ended_ = true; + return; + } + RTC_DCHECK(packet_); + const size_t start_ix = data_ix_; + packet_->header.payloadType = + ByteReader<uint8_t>::ReadLittleEndian(&data_[data_ix_]); + packet_->header.payloadType &= 0x7F; + data_ix_ += sizeof(uint8_t); + packet_->header.sequenceNumber = + ByteReader<uint16_t>::ReadLittleEndian(&data_[data_ix_]); + data_ix_ += sizeof(uint16_t); + packet_->header.timestamp = + ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]); + data_ix_ += sizeof(uint32_t); + packet_->header.ssrc = + ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]); + data_ix_ += sizeof(uint32_t); + RTC_CHECK_EQ(data_ix_ - start_ix, kNumBytesToFuzz); + } + + bool ended_ = false; + rtc::ArrayView<const uint8_t> data_; + size_t data_ix_ = 0; + std::unique_ptr<EncodeNetEqInput> input_; + std::unique_ptr<PacketData> packet_; +}; +} // namespace + +void FuzzOneInputTest(const uint8_t* data, size_t size) { + std::unique_ptr<FuzzRtpInput> input( + new FuzzRtpInput(rtc::ArrayView<const uint8_t>(data, size))); + std::unique_ptr<AudioChecksum> output(new AudioChecksum); + NetEqTest::Callbacks callbacks; + NetEq::Config config; + NetEqTest::DecoderMap codecs; + codecs[0] = std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu"); + codecs[8] = std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma"); + codecs[103] = std::make_pair(NetEqDecoder::kDecoderISAC, "isac"); + codecs[104] = std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb"); + codecs[111] = std::make_pair(NetEqDecoder::kDecoderOpus, "opus"); + codecs[93] = std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb"); + codecs[94] = std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb"); + codecs[96] = + std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48"); + codecs[9] = std::make_pair(NetEqDecoder::kDecoderG722, "g722"); + codecs[106] = std::make_pair(NetEqDecoder::kDecoderAVT, "avt"); + codecs[114] = std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16"); + codecs[115] = std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32"); + codecs[116] = std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48"); + codecs[117] = std::make_pair(NetEqDecoder::kDecoderRED, "red"); + codecs[13] = std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb"); + codecs[98] = std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb"); + codecs[99] = std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32"); + codecs[100] = std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48"); + // This is the payload type that will be used for encoding. + codecs[kPayloadType] = + std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32"); + NetEqTest::ExtDecoderMap ext_codecs; + + NetEqTest test(config, codecs, ext_codecs, std::move(input), + std::move(output), callbacks); + test.Run(); +} + +} // namespace test + +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzOneInputTest(data, size); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/neteq_signal_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/neteq_signal_fuzzer.cc new file mode 100644 index 0000000000..f0b79113ae --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/neteq_signal_fuzzer.cc @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <cmath> +#include <limits> +#include <memory> +#include <vector> + +#include "api/array_view.h" +#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" +#include "modules/audio_coding/neteq/tools/audio_checksum.h" +#include "modules/audio_coding/neteq/tools/encode_neteq_input.h" +#include "modules/audio_coding/neteq/tools/neteq_test.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/random.h" + +namespace webrtc { +namespace test { +namespace { +// Helper class to take care of the fuzzer input, read from it, and keep track +// of when the end of the data has been reached. +class FuzzData { + public: + explicit FuzzData(rtc::ArrayView<const uint8_t> data) : data_(data) {} + + // Returns true if n bytes can be read. + bool CanReadBytes(size_t n) const { return data_ix_ + n <= data_.size(); } + + // Reads and returns data of type T. + template <typename T> + T Read() { + RTC_CHECK(CanReadBytes(sizeof(T))); + T x = ByteReader<T>::ReadLittleEndian(&data_[data_ix_]); + data_ix_ += sizeof(T); + return x; + } + + // Reads and returns data of type T. Returns default_value if not enough + // fuzzer input remains to read a T. + template <typename T> + T ReadOrDefaultValue(T default_value) { + if (!CanReadBytes(sizeof(T))) { + return default_value; + } + return Read<T>(); + } + + // Like ReadOrDefaultValue, but replaces the value 0 with default_value. + template <typename T> + T ReadOrDefaultValueNotZero(T default_value) { + static_assert(std::is_integral<T>::value, ""); + T x = ReadOrDefaultValue(default_value); + return x == 0 ? default_value : x; + } + + // Returns one of the elements from the provided input array. The selection + // is based on the fuzzer input data. If not enough fuzzer data is available, + // the method will return the first element in the input array. The reason for + // not flaggin this as an error is that the method is called from the + // FuzzSignalInput constructor, and in constructors we typically do not handle + // errors. The code will work anyway, and the fuzzer will likely see that + // providing more data will actually make this method return something else. + template <typename T> + T SelectOneOf(rtc::ArrayView<const T> select_from) { + RTC_CHECK_LE(select_from.size(), std::numeric_limits<uint8_t>::max()); + // Read an index between 0 and select_from.size() - 1 from the fuzzer data. + uint8_t index = ReadOrDefaultValue<uint8_t>(0) % select_from.size(); + return select_from[index]; + } + + private: + rtc::ArrayView<const uint8_t> data_; + size_t data_ix_ = 0; +}; + +// Generate a mixture of sine wave and gaussian noise. +class SineAndNoiseGenerator : public EncodeNetEqInput::Generator { + public: + // The noise generator is seeded with a value from the fuzzer data, but 0 is + // avoided (since it is not allowed by the Random class). + SineAndNoiseGenerator(int sample_rate_hz, FuzzData* fuzz_data) + : sample_rate_hz_(sample_rate_hz), + fuzz_data_(*fuzz_data), + noise_generator_(fuzz_data_.ReadOrDefaultValueNotZero<uint64_t>(1)) {} + + // Generates num_samples of the sine-gaussian mixture. + rtc::ArrayView<const int16_t> Generate(size_t num_samples) override { + if (samples_.size() < num_samples) { + samples_.resize(num_samples); + } + + rtc::ArrayView<int16_t> output(samples_.data(), num_samples); + // Randomize an amplitude between 0 and 32768; use 65000/2 if we are out of + // fuzzer data. + const float amplitude = fuzz_data_.ReadOrDefaultValue<uint16_t>(65000) / 2; + // Randomize a noise standard deviation between 0 and 1999. + const float noise_std = fuzz_data_.ReadOrDefaultValue<uint16_t>(0) % 2000; + for (auto& x : output) { + x = rtc::saturated_cast<int16_t>(amplitude * std::sin(phase_) + + noise_generator_.Gaussian(0, noise_std)); + phase_ += 2 * kPi * kFreqHz / sample_rate_hz_; + } + return output; + } + + private: + static constexpr int kFreqHz = 300; // The sinewave frequency. + const int sample_rate_hz_; + const double kPi = std::acos(-1); + std::vector<int16_t> samples_; + double phase_ = 0.0; + FuzzData& fuzz_data_; + Random noise_generator_; +}; + +class FuzzSignalInput : public NetEqInput { + public: + explicit FuzzSignalInput(FuzzData* fuzz_data, + int sample_rate, + uint8_t payload_type) + : fuzz_data_(*fuzz_data) { + AudioEncoderPcm16B::Config config; + config.payload_type = payload_type; + config.sample_rate_hz = sample_rate; + std::unique_ptr<AudioEncoder> encoder(new AudioEncoderPcm16B(config)); + std::unique_ptr<EncodeNetEqInput::Generator> generator( + new SineAndNoiseGenerator(config.sample_rate_hz, fuzz_data)); + input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder), + std::numeric_limits<int64_t>::max())); + packet_ = input_->PopPacket(); + + // Select an output event period. This is how long time we wait between each + // call to NetEq::GetAudio. 10 ms is nominal, 9 and 11 ms will both lead to + // clock drift (in different directions). + constexpr int output_event_periods[] = {9, 10, 11}; + output_event_period_ms_ = + fuzz_data_.SelectOneOf(rtc::ArrayView<const int>(output_event_periods)); + } + + rtc::Optional<int64_t> NextPacketTime() const override { + return packet_->time_ms; + } + + rtc::Optional<int64_t> NextOutputEventTime() const override { + return next_output_event_ms_; + } + + std::unique_ptr<PacketData> PopPacket() override { + RTC_DCHECK(packet_); + std::unique_ptr<PacketData> packet_to_return = std::move(packet_); + do { + packet_ = input_->PopPacket(); + // If the next value from the fuzzer input is 0, the packet is discarded + // and the next one is pulled from the source. + } while (fuzz_data_.CanReadBytes(1) && fuzz_data_.Read<uint8_t>() == 0); + if (fuzz_data_.CanReadBytes(1)) { + // Generate jitter by setting an offset for the arrival time. + const int8_t arrival_time_offset_ms = fuzz_data_.Read<int8_t>(); + // The arrival time can not be before the previous packets. + packet_->time_ms = std::max(packet_to_return->time_ms, + packet_->time_ms + arrival_time_offset_ms); + } else { + // Mark that we are at the end of the test. However, the current packet is + // still valid (but it may not have been fuzzed as expected). + ended_ = true; + } + return packet_to_return; + } + + void AdvanceOutputEvent() override { + next_output_event_ms_ += output_event_period_ms_; + } + + bool ended() const override { return ended_; } + + rtc::Optional<RTPHeader> NextHeader() const override { + RTC_DCHECK(packet_); + return packet_->header; + } + + private: + bool ended_ = false; + FuzzData& fuzz_data_; + std::unique_ptr<EncodeNetEqInput> input_; + std::unique_ptr<PacketData> packet_; + int64_t next_output_event_ms_ = 0; + int64_t output_event_period_ms_ = 10; +}; +} // namespace + +void FuzzOneInputTest(const uint8_t* data, size_t size) { + if (size < 1) + return; + FuzzData fuzz_data(rtc::ArrayView<const uint8_t>(data, size)); + + // Allowed sample rates and payload types used in the test. + std::pair<int, uint8_t> rate_types[] = { + {8000, 93}, {16000, 94}, {32000, 95}, {48000, 96}}; + const auto rate_type = fuzz_data.SelectOneOf( + rtc::ArrayView<const std::pair<int, uint8_t>>(rate_types)); + const int sample_rate = rate_type.first; + const uint8_t payload_type = rate_type.second; + + // Set up the input signal generator. + std::unique_ptr<FuzzSignalInput> input( + new FuzzSignalInput(&fuzz_data, sample_rate, payload_type)); + + // Output sink for the test. + std::unique_ptr<AudioChecksum> output(new AudioChecksum); + + // Configure NetEq and the NetEqTest object. + NetEqTest::Callbacks callbacks; + NetEq::Config config; + config.enable_post_decode_vad = true; + config.enable_fast_accelerate = true; + NetEqTest::DecoderMap codecs; + codecs[0] = std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu"); + codecs[8] = std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma"); + codecs[103] = std::make_pair(NetEqDecoder::kDecoderISAC, "isac"); + codecs[104] = std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb"); + codecs[111] = std::make_pair(NetEqDecoder::kDecoderOpus, "opus"); + codecs[9] = std::make_pair(NetEqDecoder::kDecoderG722, "g722"); + codecs[106] = std::make_pair(NetEqDecoder::kDecoderAVT, "avt"); + codecs[114] = std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16"); + codecs[115] = std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32"); + codecs[116] = std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48"); + codecs[117] = std::make_pair(NetEqDecoder::kDecoderRED, "red"); + codecs[13] = std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb"); + codecs[98] = std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb"); + codecs[99] = std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32"); + codecs[100] = std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48"); + // One of these payload types will be used for encoding. + codecs[rate_types[0].second] = + std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb"); + codecs[rate_types[1].second] = + std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb"); + codecs[rate_types[2].second] = + std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32"); + codecs[rate_types[3].second] = + std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48"); + NetEqTest::ExtDecoderMap ext_codecs; + + NetEqTest test(config, codecs, ext_codecs, std::move(input), + std::move(output), callbacks); + test.Run(); +} + +} // namespace test + +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzOneInputTest(data, size); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/packet_buffer_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/packet_buffer_fuzzer.cc new file mode 100644 index 0000000000..df6baf48e5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/packet_buffer_fuzzer.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/video_coding/packet_buffer.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +namespace { +class NullCallback : public video_coding::OnReceivedFrameCallback { + void OnReceivedFrame(std::unique_ptr<video_coding::RtpFrameObject> frame) {} +}; +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + // Two bytes for the sequence number, + // one byte for |is_first_packet_in_frame| and |markerBit|. + constexpr size_t kMinDataNeeded = 3; + if (size < kMinDataNeeded) { + return; + } + + VCMPacket packet; + NullCallback callback; + SimulatedClock clock(0); + rtc::scoped_refptr<video_coding::PacketBuffer> packet_buffer( + video_coding::PacketBuffer::Create(&clock, 8, 1024, &callback)); + + size_t i = kMinDataNeeded; + while (i < size) { + memcpy(&packet.seqNum, &data[i - kMinDataNeeded], 2); + packet.is_first_packet_in_frame = data[i] & 1; + packet.markerBit = data[i] & 2; + packet_buffer->InsertPacket(&packet); + i += kMinDataNeeded; + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/pseudotcp_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/pseudotcp_parser_fuzzer.cc new file mode 100644 index 0000000000..90123c3206 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/pseudotcp_parser_fuzzer.cc @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. +* +* Use of this source code is governed by a BSD-style license +* that can be found in the LICENSE file in the root of the source +* tree. An additional intellectual property rights grant can be found +* in the file PATENTS. All contributing project authors may +* be found in the AUTHORS file in the root of the source tree. +*/ + +#include <stddef.h> +#include <stdint.h> + +#include "p2p/base/pseudotcp.h" +#include "rtc_base/thread.h" + +namespace webrtc { +class FakeIPseudoTcpNotify : public cricket::IPseudoTcpNotify { + public: + void OnTcpOpen(cricket::PseudoTcp* tcp) {} + void OnTcpReadable(cricket::PseudoTcp* tcp) {} + void OnTcpWriteable(cricket::PseudoTcp* tcp) {} + void OnTcpClosed(cricket::PseudoTcp* tcp, uint32_t error) {} + + cricket::IPseudoTcpNotify::WriteResult TcpWritePacket(cricket::PseudoTcp* tcp, + const char* buffer, + size_t len) { + return cricket::IPseudoTcpNotify::WriteResult::WR_SUCCESS; + } +}; + +struct Environment { + explicit Environment(cricket::IPseudoTcpNotify* notifier): + ptcp(notifier, 0) { + } + + // We need the thread to avoid some uninteresting crashes, since the + // production code expects there to be a thread object available. + rtc::AutoThread thread; + cricket::PseudoTcp ptcp; +}; + +Environment* env = new Environment(new FakeIPseudoTcpNotify()); + +void FuzzOneInput(const uint8_t* data, size_t size) { + env->ptcp.NotifyPacket(reinterpret_cast<const char*>(data), size); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/residual_echo_detector_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/residual_echo_detector_fuzzer.cc new file mode 100644 index 0000000000..c3c81237c8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/residual_echo_detector_fuzzer.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <math.h> +#include <string.h> + +#include <algorithm> +#include <bitset> +#include <vector> + +#include "modules/audio_processing/residual_echo_detector.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +void FuzzOneInput(const uint8_t* data, size_t size) { + // Number of times to update the echo detector. + constexpr size_t kNrOfUpdates = 7; + // Each round of updates requires a call to both AnalyzeRender and + // AnalyzeCapture, so the amount of needed input bytes doubles. Also, two + // bytes are used to set the call order. + constexpr size_t kNrOfNeededInputBytes = 2 * kNrOfUpdates * sizeof(float) + 2; + // The maximum audio energy that an audio frame can have is equal to the + // number of samples in the frame multiplied by 2^30. We use a single sample + // to represent an audio frame in this test, so it should have a maximum value + // equal to the square root of that value. + const float maxFuzzedValue = sqrtf(20 * 48) * 32768; + if (size < kNrOfNeededInputBytes) { + return; + } + size_t read_idx = 0; + // Use the first two bytes to choose the call order. + uint16_t call_order_int; + memcpy(&call_order_int, &data[read_idx], 2); + read_idx += 2; + std::bitset<16> call_order(call_order_int); + + ResidualEchoDetector echo_detector; + std::vector<float> input(1); + // Call AnalyzeCaptureAudio once to prevent the flushing of the buffer. + echo_detector.AnalyzeCaptureAudio(input); + for (size_t i = 0; i < 2 * kNrOfUpdates; ++i) { + // Convert 4 input bytes to a float. + RTC_DCHECK_LE(read_idx + sizeof(float), size); + memcpy(input.data(), &data[read_idx], sizeof(float)); + read_idx += sizeof(float); + if (!isfinite(input[0]) || fabs(input[0]) > maxFuzzedValue) { + // Ignore infinity, nan values and values that are unrealistically large. + continue; + } + if (call_order[i]) { + echo_detector.AnalyzeRenderAudio(input); + } else { + echo_detector.AnalyzeCaptureAudio(input); + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/rtcp_receiver_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/rtcp_receiver_fuzzer.cc new file mode 100644 index 0000000000..8782f0c0a8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/rtcp_receiver_fuzzer.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtcp_receiver.h" +#include "rtc_base/checks.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { +namespace { + +class NullModuleRtpRtcp : public RTCPReceiver::ModuleRtpRtcp { + public: + void SetTmmbn(std::vector<rtcp::TmmbItem>) override {} + void OnRequestSendReport() override {} + void OnReceivedNack(const std::vector<uint16_t>&) override {}; + void OnReceivedRtcpReportBlocks(const ReportBlockList&) override {}; +}; + +} + +void FuzzOneInput(const uint8_t* data, size_t size) { + NullModuleRtpRtcp rtp_rtcp_module; + SimulatedClock clock(1234); + + RTCPReceiver receiver(&clock, false, nullptr, nullptr, nullptr, nullptr, + nullptr, &rtp_rtcp_module); + + receiver.IncomingPacket(data, size); +} +} // namespace webrtc + diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/rtp_header_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/rtp_header_fuzzer.cc new file mode 100644 index 0000000000..09bf81197e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/rtp_header_fuzzer.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <bitset> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" + +namespace webrtc { +// We decide which header extensions to register by reading two bytes +// from the beginning of |data| and interpreting it as a bitmask over +// the RTPExtensionType enum. This assert ensures two bytes are enough. +static_assert(kRtpExtensionNumberOfExtensions <= 16, + "Insufficient bits read to configure all header extensions. Add " + "an extra byte and update the switches."); + +void FuzzOneInput(const uint8_t* data, size_t size) { + if (size <= 2) + return; + + // Don't use the configuration byte as part of the packet. + std::bitset<16> extensionMask(*reinterpret_cast<const uint16_t*>(data)); + data += 2; + size -= 2; + + RtpPacketReceived::ExtensionManager extensions; + // Skip i = 0 since it maps to ExtensionNone and extension id = 0 is invalid. + for (int i = 0; i < kRtpExtensionNumberOfExtensions; i++) { + RTPExtensionType extension_type = static_cast<RTPExtensionType>(i); + if (extensionMask[i] && extension_type != kRtpExtensionNone) { + // Extensions are registered with an ID, which you signal to the + // peer so they know what to expect. This code only cares about + // parsing so the value of the ID isn't relevant; we use i. + extensions.RegisterByType(i, extension_type); + } + } + + RTPHeader rtp_header; + RtpUtility::RtpHeaderParser rtp_parser(data, size); + rtp_parser.Parse(&rtp_header, &extensions); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/rtp_packet_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/rtp_packet_fuzzer.cc new file mode 100644 index 0000000000..9a30c88eaa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/rtp_packet_fuzzer.cc @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" + +namespace webrtc { + +// We decide which header extensions to register by reading two bytes +// from the beginning of |data| and interpreting it as a bitmask over +// the RTPExtensionType enum. This assert ensures two bytes are enough. +static_assert(kRtpExtensionNumberOfExtensions <= 16, + "Insufficient bits read to configure all header extensions. Add " + "an extra byte and update the switches."); + +void FuzzOneInput(const uint8_t* data, size_t size) { + if (size <= 2) + return; + + // Don't use the configuration bytes as part of the packet. + std::bitset<16> extensionMask(*reinterpret_cast<const uint16_t*>(data)); + data += 2; + size -= 2; + + RtpPacketReceived::ExtensionManager extensions; + // Skip i = 0 since it maps to ExtensionNone and extension id = 0 is invalid. + for (int i = 1; i < kRtpExtensionNumberOfExtensions; i++) { + RTPExtensionType extension_type = static_cast<RTPExtensionType>(i); + if (extensionMask[i] && extension_type != kRtpExtensionNone) { + // Extensions are registered with an ID, which you signal to the + // peer so they know what to expect. This code only cares about + // parsing so the value of the ID isn't relevant; we use i. + extensions.RegisterByType(i, extension_type); + } + } + + RtpPacketReceived packet(&extensions); + packet.Parse(data, size); + + // Call packet accessors because they have extra checks. + packet.Marker(); + packet.PayloadType(); + packet.SequenceNumber(); + packet.Timestamp(); + packet.Ssrc(); + packet.Csrcs(); + + // Each extension has its own getter. It is supported behaviour to + // call GetExtension on an extension which was not registered, so we + // don't check the bitmask here. + for (int i = 0; i < kRtpExtensionNumberOfExtensions; i++) { + switch (static_cast<RTPExtensionType>(i)) { + case kRtpExtensionNone: + case kRtpExtensionNumberOfExtensions: + break; + case kRtpExtensionTransmissionTimeOffset: + int32_t offset; + packet.GetExtension<TransmissionOffset>(&offset); + break; + case kRtpExtensionAudioLevel: + bool voice_activity; + uint8_t audio_level; + packet.GetExtension<AudioLevel>(&voice_activity, &audio_level); + break; + case kRtpExtensionAbsoluteSendTime: + uint32_t sendtime; + packet.GetExtension<AbsoluteSendTime>(&sendtime); + break; + case kRtpExtensionVideoRotation: + uint8_t rotation; + packet.GetExtension<VideoOrientation>(&rotation); + break; + case kRtpExtensionTransportSequenceNumber: + uint16_t seqnum; + packet.GetExtension<TransportSequenceNumber>(&seqnum); + break; + case kRtpExtensionPlayoutDelay: + PlayoutDelay playout; + packet.GetExtension<PlayoutDelayLimits>(&playout); + break; + case kRtpExtensionVideoContentType: + VideoContentType content_type; + packet.GetExtension<VideoContentTypeExtension>(&content_type); + break; + case kRtpExtensionVideoTiming: + VideoSendTiming timing; + packet.GetExtension<VideoTimingExtension>(&timing); + break; + case kRtpExtensionRtpStreamId: { + std::string rsid; + packet.GetExtension<RtpStreamId>(&rsid); + break; + } + case kRtpExtensionRepairedRtpStreamId: { + std::string rsid; + packet.GetExtension<RepairedRtpStreamId>(&rsid); + break; + } + case kRtpExtensionMid: { + std::string mid; + packet.GetExtension<RtpMid>(&mid); + break; + } + case kRtpExtensionCsrcAudioLevel: { + CsrcAudioLevelList levels; + packet.GetExtension<CsrcAudioLevel>(&levels); + break; + } + } + } +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/sdp_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/sdp_parser_fuzzer.cc new file mode 100644 index 0000000000..e47156c571 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/sdp_parser_fuzzer.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stddef.h> +#include <stdint.h> + +#include "api/jsepsessiondescription.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + std::string message(reinterpret_cast<const char*>(data), size); + webrtc::SdpParseError error; + + std::unique_ptr<webrtc::SessionDescriptionInterface> sdp( + CreateSessionDescription("offer", message, &error)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/stun_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/stun_parser_fuzzer.cc new file mode 100644 index 0000000000..02e42bcbc8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/stun_parser_fuzzer.cc @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stddef.h> +#include <stdint.h> + +#include "p2p/base/stun.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + const char* message = reinterpret_cast<const char*>(data); + + // Normally we'd check the integrity first, but those checks are + // fuzzed separately in stun_validator_fuzzer.cc. We still want to + // fuzz this target since the integrity checks could be forged by a + // malicious adversary who receives a call. + std::unique_ptr<cricket::IceMessage> stun_msg(new cricket::IceMessage()); + rtc::ByteBufferReader buf(message, size); + stun_msg->Read(&buf); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/stun_validator_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/stun_validator_fuzzer.cc new file mode 100644 index 0000000000..9873ff40fb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/stun_validator_fuzzer.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stddef.h> +#include <stdint.h> + +#include "p2p/base/stun.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + const char* message = reinterpret_cast<const char*>(data); + + cricket::StunMessage::ValidateFingerprint(message, size); + cricket::StunMessage::ValidateMessageIntegrity(message, size, ""); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc new file mode 100644 index 0000000000..31bc1639e2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "api/array_view.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "voice_engine/transport_feedback_packet_loss_tracker.h" + +namespace webrtc { + +namespace { + +template <typename T> +T FuzzInput(const uint8_t** data, size_t* size) { + RTC_CHECK_GE(*size, sizeof(T)); + T rc = ByteReader<T>::ReadBigEndian(*data); + *data += sizeof(T); + *size -= sizeof(T); + return rc; +} + +size_t FuzzInRange(const uint8_t** data, + size_t* size, + size_t lower, + size_t upper) { + // Achieve a close-to-uniform distribution. + RTC_CHECK_LE(lower, upper); + RTC_CHECK_LT(upper - lower, 1 << (8 * sizeof(uint16_t))); + const size_t range = upper - lower; + const uint16_t fuzzed = FuzzInput<uint16_t>(data, size); + const size_t offset = (static_cast<float>(fuzzed) / 0x10000) * (range + 1); + RTC_CHECK_LE(offset, range); // (fuzzed <= 0xffff) -> (offset < range + 1) + return lower + offset; +} + +class TransportFeedbackGenerator { + public: + explicit TransportFeedbackGenerator(const uint8_t** data, size_t* size) + : data_(data), size_(size) {} + + bool GetNextTransportFeedbackVector( + std::vector<PacketFeedback>* feedback_vector) { + RTC_CHECK(feedback_vector->empty()); + + uint16_t remaining_packets = 0; + if (!ReadData<uint16_t>(&remaining_packets)) { + return false; + } + + if (remaining_packets == 0) { + return true; + } + + uint16_t seq_num; + if (!ReadData<uint16_t>(&seq_num)) { // Fuzz base sequence number. + return false; + } + + while (remaining_packets > 0) { + uint8_t status_byte = 0; + if (!ReadData<uint8_t>(&status_byte)) { + return false; + } + // Each status byte contains 8 statuses. + for (size_t i = 0; i < 8 && remaining_packets > 0; ++i) { + // Any positive integer signals reception. kNotReceived signals loss. + // Other values are just illegal. + constexpr int64_t kArrivalTimeMs = 1234; + + const bool received = (status_byte & (0x01 << i)); + feedback_vector->emplace_back(PacketFeedback( + received ? kArrivalTimeMs : PacketFeedback::kNotReceived, + seq_num++)); + --remaining_packets; + } + } + + return true; + } + + private: + template <typename T> + bool ReadData(T* value) { + if (*size_ < sizeof(T)) { + return false; + } else { + *value = FuzzInput<T>(data_, size_); + return true; + } + } + + const uint8_t** data_; + size_t* size_; +}; + +bool Setup(const uint8_t** data, + size_t* size, + std::unique_ptr<TransportFeedbackPacketLossTracker>* tracker) { + if (*size < 3 * sizeof(uint16_t)) { + return false; + } + + constexpr size_t kSeqNumHalf = 0x8000u; + + const int64_t max_window_size_ms = FuzzInRange(data, size, 1, 1 << 16); + const size_t plr_min_num_packets = FuzzInRange(data, size, 1, kSeqNumHalf); + const size_t rplr_min_num_pairs = FuzzInRange(data, size, 1, kSeqNumHalf - 1); + + tracker->reset(new TransportFeedbackPacketLossTracker( + max_window_size_ms, plr_min_num_packets, rplr_min_num_pairs)); + + return true; +} + +bool FuzzSequenceNumberDelta(const uint8_t** data, + size_t* size, + uint16_t* delta) { + // Fuzz with a higher likelihood for immediately consecutive pairs + // than you would by just fuzzing 1-256. + // Note: Values higher than 256 still possible, but that would be in a new + // packet-sending block. + // * Fuzzed value in [0 : 127] (50% chance) -> delta is 1. + // * Fuzzed value in [128 : 255] (50% chance) -> delta in range [2 : 129]. + if (*size < sizeof(uint8_t)) { + return false; + } + uint8_t fuzzed = FuzzInput<uint8_t>(data, size); + *delta = (fuzzed < 128) ? 1 : (fuzzed - 128 + 2); + return true; +} + +bool FuzzClockAdvancement(const uint8_t** data, + size_t* size, + int64_t* time_ms) { + // Fuzzing 64-bit worth of delta would be extreme overkill, as 32-bit is + // already ~49 days long. We'll fuzz deltas up to a smaller value, and this + // way also guarantee that wrap-around is impossible, as in real life. + + // Higher likelihood for more likely cases: + // 5% chance of delta = 0. + // 20% chance of delta in range [1 : 10] (uniformly distributed) + // 55% chance of delta in range [11 : 500] (uniformly distributed) + // 20% chance of delta in range [501 : 10000] (uniformly distributed) + struct ProbabilityDistribution { + float probability; + size_t lower; + size_t higher; + }; + constexpr ProbabilityDistribution clock_probability_distribution[] = { + {0.05, 0, 0}, {0.20, 1, 10}, {0.55, 11, 500}, {0.20, 501, 10000}}; + + if (*size < sizeof(uint8_t)) { + return false; + } + const float fuzzed = FuzzInput<uint8_t>(data, size) / 256.0f; + + float cumulative_probability = 0; + for (const auto& dist : clock_probability_distribution) { + cumulative_probability += dist.probability; + if (fuzzed < cumulative_probability) { + if (dist.lower == dist.higher) { + *time_ms += dist.lower; + return true; + } else if (*size < sizeof(uint16_t)) { + return false; + } else { + *time_ms += FuzzInRange(data, size, dist.lower, dist.higher); + return true; + } + } + } + + RTC_NOTREACHED(); + return false; +} + +bool FuzzPacketSendBlock( + std::unique_ptr<TransportFeedbackPacketLossTracker>& tracker, + const uint8_t** data, + size_t* size, + int64_t* time_ms) { + // We want to test with block lengths between 1 and 2^16, inclusive. + if (*size < sizeof(uint8_t)) { + return false; + } + size_t packet_block_len = 1 + FuzzInput<uint8_t>(data, size); + + // First sent sequence number uniformly selected. + if (*size < sizeof(uint16_t)) { + return false; + } + uint16_t seq_num = FuzzInput<uint16_t>(data, size); + tracker->OnPacketAdded(seq_num, *time_ms); + tracker->Validate(); + + bool may_continue = FuzzClockAdvancement(data, size, time_ms); + if (!may_continue) { + return false; + } + + for (size_t i = 1; i < packet_block_len; i++) { + uint16_t delta; + may_continue = FuzzSequenceNumberDelta(data, size, &delta); + if (!may_continue) + return false; + may_continue = FuzzClockAdvancement(data, size, time_ms); + if (!may_continue) + return false; + seq_num += delta; + tracker->OnPacketAdded(seq_num, *time_ms); + tracker->Validate(); + } + + return true; +} + +bool FuzzTransportFeedbackBlock( + std::unique_ptr<TransportFeedbackPacketLossTracker>& tracker, + const uint8_t** data, + size_t* size) { + // Fuzz the number of back-to-back feedbacks. At least one, or this would + // be meaningless - we'd go straight back to fuzzing another packet + // transmission block. + if (*size < sizeof(uint8_t)) { + return false; + } + + size_t feedbacks_num = 1 + (FuzzInput<uint8_t>(data, size) & 0x3f); + TransportFeedbackGenerator feedback_generator(data, size); + + for (size_t i = 0; i < feedbacks_num; i++) { + std::vector<PacketFeedback> feedback_vector; + bool may_continue = + feedback_generator.GetNextTransportFeedbackVector(&feedback_vector); + if (!may_continue) { + return false; + } + tracker->OnPacketFeedbackVector(feedback_vector); + tracker->Validate(); + } + + return true; +} + +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + std::unique_ptr<TransportFeedbackPacketLossTracker> tracker; + bool may_continue; + + may_continue = Setup(&data, &size, &tracker); + + // We never expect this to wrap around, so it makes sense to just start with + // a sane value, and keep on incrementing by a fuzzed delta. + if (size < sizeof(uint32_t)) { + return; + } + int64_t time_ms = FuzzInput<uint32_t>(&data, &size); + + while (may_continue) { + may_continue = FuzzPacketSendBlock(tracker, &data, &size, &time_ms); + if (!may_continue) { + return; + } + may_continue = FuzzTransportFeedbackBlock(tracker, &data, &size); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/turn_unwrap_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/turn_unwrap_fuzzer.cc new file mode 100644 index 0000000000..ed9f34d711 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/turn_unwrap_fuzzer.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stddef.h> +#include <stdint.h> + +#include "media/base/turnutils.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + size_t content_position; + size_t content_size; + cricket::UnwrapTurnPacket(data, size, &content_position, &content_size); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_generator_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_generator_fuzzer.cc new file mode 100644 index 0000000000..03728f6bac --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_generator_fuzzer.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/ulpfec_generator.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace { +constexpr uint8_t kFecPayloadType = 96; +constexpr uint8_t kRedPayloadType = 97; +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + UlpfecGenerator generator; + size_t i = 0; + if (size < 4) + return; + FecProtectionParams params = { + data[i++] % 128, static_cast<int>(data[i++] % 10), kFecMaskBursty}; + generator.SetFecParameters(params); + uint16_t seq_num = data[i++]; + + while (i + 3 < size) { + size_t rtp_header_length = data[i++] % 10 + 12; + size_t payload_size = data[i++] % 10; + if (i + payload_size + rtp_header_length + 2 > size) + break; + std::unique_ptr<uint8_t[]> packet( + new uint8_t[payload_size + rtp_header_length]); + memcpy(packet.get(), &data[i], payload_size + rtp_header_length); + ByteWriter<uint16_t>::WriteBigEndian(&packet[2], seq_num++); + i += payload_size + rtp_header_length; + // Make sure sequence numbers are increasing. + const bool protect = data[i++] % 2 == 1; + if (protect) { + generator.AddRtpPacketAndGenerateFec(packet.get(), payload_size, + rtp_header_length); + } + const size_t num_fec_packets = generator.NumAvailableFecPackets(); + if (num_fec_packets > 0) { + std::vector<std::unique_ptr<RedPacket>> fec_packets = + generator.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType, 100, + rtp_header_length); + RTC_CHECK_EQ(num_fec_packets, fec_packets.size()); + } + } +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_header_reader_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_header_reader_fuzzer.cc new file mode 100644 index 0000000000..6a6394f763 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_header_reader_fuzzer.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" +#include "rtc_base/scoped_ref_ptr.h" + +namespace webrtc { + +using Packet = ForwardErrorCorrection::Packet; +using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; + +void FuzzOneInput(const uint8_t* data, size_t size) { + ReceivedFecPacket packet; + packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + const size_t packet_size = + std::min(size, static_cast<size_t>(IP_PACKET_SIZE)); + memcpy(packet.pkt->data, data, packet_size); + packet.pkt->length = packet_size; + + UlpfecHeaderReader ulpfec_reader; + ulpfec_reader.ReadFecHeader(&packet); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_receiver_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_receiver_fuzzer.cc new file mode 100644 index 0000000000..c850fec996 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/ulpfec_receiver_fuzzer.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "modules/rtp_rtcp/include/ulpfec_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { + +namespace { +class DummyCallback : public RecoveredPacketReceiver { + void OnRecoveredPacket(const uint8_t* packet, size_t length) override {} +}; +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + constexpr size_t kMinDataNeeded = 12; + if (size < kMinDataNeeded) { + return; + } + + uint32_t ulpfec_ssrc = ByteReader<uint32_t>::ReadLittleEndian(data + 0); + uint16_t ulpfec_seq_num = ByteReader<uint16_t>::ReadLittleEndian(data + 4); + uint32_t media_ssrc = ByteReader<uint32_t>::ReadLittleEndian(data + 6); + uint16_t media_seq_num = ByteReader<uint16_t>::ReadLittleEndian(data + 10); + + DummyCallback callback; + std::unique_ptr<UlpfecReceiver> receiver( + UlpfecReceiver::Create(ulpfec_ssrc, &callback)); + + std::unique_ptr<uint8_t[]> packet; + size_t packet_length; + size_t i = kMinDataNeeded; + while (i < size) { + packet_length = kRtpHeaderSize + data[i++]; + packet = std::unique_ptr<uint8_t[]>(new uint8_t[packet_length]); + if (i + packet_length >= size) { + break; + } + memcpy(packet.get(), data + i, packet_length); + i += packet_length; + // Overwrite the RTPHeader fields for the sequence number and SSRC with + // consistent values for either a received UlpFEC packet or received media + // packet. (We're still relying on libfuzzer to manage to generate packet + // headers that interact together; this just ensures that we have two + // consistent streams). + if (i < size && data[i++] % 2 == 0) { + // Simulate UlpFEC packet. + ByteWriter<uint16_t>::WriteBigEndian(packet.get() + 2, ulpfec_seq_num++); + ByteWriter<uint32_t>::WriteBigEndian(packet.get() + 8, ulpfec_ssrc); + } else { + // Simulate media packet. + ByteWriter<uint16_t>::WriteBigEndian(packet.get() + 2, media_seq_num++); + ByteWriter<uint32_t>::WriteBigEndian(packet.get() + 8, media_ssrc); + } + RtpPacketReceived parsed_packet; + RTPHeader parsed_header; + if (parsed_packet.Parse(packet.get(), packet_length)) { + parsed_packet.GetHeader(&parsed_header); + receiver->AddReceivedRedPacket(parsed_header, packet.get(), + packet_length, 0); + } + } + + receiver->ProcessReceivedFec(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/vp8_depacketizer_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/vp8_depacketizer_fuzzer.cc new file mode 100644 index 0000000000..bd9ac8ffb2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/vp8_depacketizer_fuzzer.cc @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + RtpDepacketizerVp8 depacketizer; + RtpDepacketizer::ParsedPayload parsed_payload; + depacketizer.Parse(&parsed_payload, data, size); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/vp8_qp_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/vp8_qp_parser_fuzzer.cc new file mode 100644 index 0000000000..2ecfd820c8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/vp8_qp_parser_fuzzer.cc @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/video_coding/utility/vp8_header_parser.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + int qp; + vp8::GetQp(data, size, &qp); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/vp9_depacketizer_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/vp9_depacketizer_fuzzer.cc new file mode 100644 index 0000000000..8f62b429ff --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/vp9_depacketizer_fuzzer.cc @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + RtpDepacketizerVp9 depacketizer; + RtpDepacketizer::ParsedPayload parsed_payload; + depacketizer.Parse(&parsed_payload, data, size); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/vp9_qp_parser_fuzzer.cc b/third_party/libwebrtc/webrtc/test/fuzzers/vp9_qp_parser_fuzzer.cc new file mode 100644 index 0000000000..3cff95f5b7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/vp9_qp_parser_fuzzer.cc @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/video_coding/utility/vp9_uncompressed_header_parser.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + int qp; + vp9::GetQp(data, size, &qp); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/fuzzers/webrtc_fuzzer_main.cc b/third_party/libwebrtc/webrtc/test/fuzzers/webrtc_fuzzer_main.cc new file mode 100644 index 0000000000..ca4bc15c71 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/fuzzers/webrtc_fuzzer_main.cc @@ -0,0 +1,41 @@ +/* + * 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 intended to provide a common interface for fuzzing functions. +// It's intended to set sane defaults, such as removing logging for further +// fuzzing efficiency. + +#include "rtc_base/logging.h" + +namespace { +bool g_initialized = false; +void InitializeWebRtcFuzzDefaults() { + if (g_initialized) + return; + + // Remove default logging to prevent huge slowdowns. + // TODO(pbos): Disable in Chromium: http://crbug.com/561667 +#if !defined(WEBRTC_CHROMIUM_BUILD) + rtc::LogMessage::LogToDebug(rtc::LS_NONE); +#endif // !defined(WEBRTC_CHROMIUM_BUILD) + + g_initialized = true; +} +} + +namespace webrtc { +extern void FuzzOneInput(const uint8_t* data, size_t size); +} // namespace webrtc + +extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) { + InitializeWebRtcFuzzDefaults(); + webrtc::FuzzOneInput(data, size); + return 0; +} diff --git a/third_party/libwebrtc/webrtc/test/gl/gl_renderer.cc b/third_party/libwebrtc/webrtc/test/gl/gl_renderer.cc new file mode 100644 index 0000000000..ef7ab9c126 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/gl/gl_renderer.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/gl/gl_renderer.h" + +#include <string.h> + +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { + +GlRenderer::GlRenderer() + : is_init_(false), buffer_(NULL), width_(0), height_(0) {} + +void GlRenderer::Init() { + RTC_DCHECK(!is_init_); + is_init_ = true; + + glGenTextures(1, &texture_); +} + +void GlRenderer::Destroy() { + if (!is_init_) { + return; + } + + is_init_ = false; + + delete[] buffer_; + buffer_ = NULL; + + glDeleteTextures(1, &texture_); +} + +void GlRenderer::ResizeViewport(size_t width, size_t height) { + // TODO(pbos): Aspect ratio, letterbox the video. + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glOrtho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f); + glMatrixMode(GL_MODELVIEW); +} + +void GlRenderer::ResizeVideo(size_t width, size_t height) { + RTC_DCHECK(is_init_); + width_ = width; + height_ = height; + + buffer_size_ = width * height * 4; // BGRA + + delete[] buffer_; + buffer_ = new uint8_t[buffer_size_]; + RTC_DCHECK(buffer_); + memset(buffer_, 0, buffer_size_); + glBindTexture(GL_TEXTURE_2D, texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8, static_cast<GLvoid*>(buffer_)); +} + +void GlRenderer::OnFrame(const webrtc::VideoFrame& frame) { + RTC_DCHECK(is_init_); + + if (static_cast<size_t>(frame.width()) != width_ || + static_cast<size_t>(frame.height()) != height_) { + ResizeVideo(frame.width(), frame.height()); + } + + webrtc::ConvertFromI420(frame, VideoType::kBGRA, 0, buffer_); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture_); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8, buffer_); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glLoadIdentity(); + + glBegin(GL_QUADS); + { + glTexCoord2f(0.0f, 0.0f); + glVertex3f(0.0f, 0.0f, 0.0f); + + glTexCoord2f(0.0f, 1.0f); + glVertex3f(0.0f, 1.0f, 0.0f); + + glTexCoord2f(1.0f, 1.0f); + glVertex3f(1.0f, 1.0f, 0.0f); + + glTexCoord2f(1.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 0.0f); + } + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glFlush(); +} +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/gl/gl_renderer.h b/third_party/libwebrtc/webrtc/test/gl/gl_renderer.h new file mode 100644 index 0000000000..382739d307 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/gl/gl_renderer.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_GL_GL_RENDERER_H_ +#define TEST_GL_GL_RENDERER_H_ + +#ifdef WEBRTC_MAC +#include <OpenGL/gl.h> +#else +#include <GL/gl.h> +#endif + +#include "test/video_renderer.h" +#include "typedefs.h" // NOLINT(build/include) + + +namespace webrtc { +namespace test { + +class GlRenderer : public VideoRenderer { + public: + void OnFrame(const webrtc::VideoFrame& frame) override; + + protected: + GlRenderer(); + + void Init(); + void Destroy(); + + void ResizeViewport(size_t width, size_t height); + + private: + bool is_init_; + uint8_t* buffer_; + GLuint texture_; + size_t width_, height_, buffer_size_; + + void ResizeVideo(size_t width, size_t height); +}; +} // test +} // webrtc + +#endif // TEST_GL_GL_RENDERER_H_ diff --git a/third_party/libwebrtc/webrtc/test/gmock.h b/third_party/libwebrtc/webrtc/test/gmock.h new file mode 100644 index 0000000000..f137d080a4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/gmock.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_GMOCK_H_ +#define TEST_GMOCK_H_ + +#include "rtc_base/ignore_wundef.h" + +RTC_PUSH_IGNORING_WUNDEF() +#include "testing/gmock/include/gmock/gmock.h" +RTC_POP_IGNORING_WUNDEF() + +#endif // TEST_GMOCK_H_ diff --git a/third_party/libwebrtc/webrtc/test/gtest.h b/third_party/libwebrtc/webrtc/test/gtest.h new file mode 100644 index 0000000000..928ec496f0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/gtest.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_GTEST_H_ +#define TEST_GTEST_H_ + +#include "rtc_base/ignore_wundef.h" + +RTC_PUSH_IGNORING_WUNDEF() +#include "testing/gtest/include/gtest/gtest.h" +RTC_POP_IGNORING_WUNDEF() + +// GTEST_HAS_DEATH_TEST is set to 1 when death tests are supported, but appears +// to be left unset if they're not supported. Rather than depend on this, we +// set it to 0 ourselves here. +#ifndef GTEST_HAS_DEATH_TEST +#define GTEST_HAS_DEATH_TEST 0 +#endif + +#endif // TEST_GTEST_H_ diff --git a/third_party/libwebrtc/webrtc/test/ios/Info.plist b/third_party/libwebrtc/webrtc/test/ios/Info.plist new file mode 100644 index 0000000000..e02ce91165 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/ios/Info.plist @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>${IOS_BUNDLE_ID_PREFIX}.gtest.${GTEST_BUNDLE_ID_SUFFIX:rfc1034identifier}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSAllowsArbitraryLoads</key> + <true/> + </dict> + <key>UIFileSharingEnabled</key> + <true/> + <key>UISupportedInterfaceOrientation</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UIBackgroundModes</key> + <array> + <string>fetch</string> + </array> + <key>NSMicrophoneUsageDescription</key> + <string>For testing purposes</string> +</dict> +</plist> diff --git a/third_party/libwebrtc/webrtc/test/ios/test_support.h b/third_party/libwebrtc/webrtc/test/ios/test_support.h new file mode 100644 index 0000000000..7bc2993b9e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/ios/test_support.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_IOS_TEST_SUPPORT_H_ +#define TEST_IOS_TEST_SUPPORT_H_ + +namespace rtc { +namespace test { +// Launches an iOS app that serves as a host for a test suite. +// This is necessary as iOS doesn't like processes without a gui +// running for longer than a few seconds. +void RunTestsFromIOSApp(); +void InitTestSuite(int (*test_suite)(void), int argc, char* argv[]); + +} // namespace test +} // namespace rtc + +#endif // TEST_IOS_TEST_SUPPORT_H_ diff --git a/third_party/libwebrtc/webrtc/test/ios/test_support.mm b/third_party/libwebrtc/webrtc/test/ios/test_support.mm new file mode 100644 index 0000000000..603bc8c19c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/ios/test_support.mm @@ -0,0 +1,108 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import <UIKit/UIKit.h> + +#include "test/ios/test_support.h" + +#import "sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.h" + +// Springboard will kill any iOS app that fails to check in after launch within +// a given time. Starting a UIApplication before invoking TestSuite::Run +// prevents this from happening. + +// InitIOSRunHook saves the TestSuite and argc/argv, then invoking +// RunTestsFromIOSApp calls UIApplicationMain(), providing an application +// delegate class: WebRtcUnitTestDelegate. The delegate implements +// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run +// method. + +// Since the executable isn't likely to be a real iOS UI, the delegate puts up a +// window displaying the app name. If a bunch of apps using MainHook are being +// run in a row, this provides an indication of which one is currently running. + +static int (*g_test_suite)(void) = NULL; +static int g_argc; +static char **g_argv; + +@interface UIApplication (Testing) +- (void)_terminateWithStatus:(int)status; +@end + +@interface WebRtcUnitTestDelegate : NSObject { + UIWindow *_window; +} +- (void)runTests; +@end + +@implementation WebRtcUnitTestDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + CGRect bounds = [[UIScreen mainScreen] bounds]; + + _window = [[UIWindow alloc] initWithFrame:bounds]; + [_window setBackgroundColor:[UIColor whiteColor]]; + [_window makeKeyAndVisible]; + + // Add a label with the app name. + UILabel *label = [[UILabel alloc] initWithFrame:bounds]; + label.text = [[NSProcessInfo processInfo] processName]; + label.textAlignment = NSTextAlignmentCenter; + [_window addSubview:label]; + + // An NSInternalInconsistencyException is thrown if the app doesn't have a + // root view controller. Set an empty one here. + [_window setRootViewController:[[UIViewController alloc] init]]; + + // We want to call `RTCUIApplicationStatusObserver sharedInstance` as early as + // possible in the application lifecycle to set observation properly. + __unused RTCUIApplicationStatusObserver *observer = + [RTCUIApplicationStatusObserver sharedInstance]; + + // Queue up the test run. + [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + return YES; +} + +- (void)runTests { + int exitStatus = g_test_suite(); + + // If a test app is too fast, it will exit before Instruments has has a + // a chance to initialize and no test results will be seen. + // TODO(crbug.com/137010): Figure out how much time is actually needed, and + // sleep only to make sure that much time has elapsed since launch. + [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; + + // Use the hidden selector to try and cleanly take down the app (otherwise + // things can think the app crashed even on a zero exit status). + UIApplication *application = [UIApplication sharedApplication]; + [application _terminateWithStatus:exitStatus]; + + exit(exitStatus); +} + +@end +namespace rtc { +namespace test { + +void InitTestSuite(int (*test_suite)(void), int argc, char *argv[]) { + g_test_suite = test_suite; + g_argc = argc; + g_argv = argv; +} + +void RunTestsFromIOSApp() { + @autoreleasepool { + exit(UIApplicationMain(g_argc, g_argv, nil, @"WebRtcUnitTestDelegate")); + } +} +} // namespace test +} // namespace rtc diff --git a/third_party/libwebrtc/webrtc/test/layer_filtering_transport.cc b/third_party/libwebrtc/webrtc/test/layer_filtering_transport.cc new file mode 100644 index 0000000000..a8a337da65 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/layer_filtering_transport.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/checks.h" +#include "test/layer_filtering_transport.h" + +namespace webrtc { +namespace test { + +LayerFilteringTransport::LayerFilteringTransport( + SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + uint8_t vp8_video_payload_type, + uint8_t vp9_video_payload_type, + int selected_tl, + int selected_sl, + const std::map<uint8_t, MediaType>& payload_type_map) + : DirectTransport(task_queue, config, send_call, payload_type_map), + vp8_video_payload_type_(vp8_video_payload_type), + vp9_video_payload_type_(vp9_video_payload_type), + selected_tl_(selected_tl), + selected_sl_(selected_sl), + discarded_last_packet_(false) {} + +LayerFilteringTransport::LayerFilteringTransport( + SingleThreadedTaskQueueForTesting* task_queue, + std::unique_ptr<FakeNetworkPipe> pipe, + Call* send_call, + uint8_t vp8_video_payload_type, + uint8_t vp9_video_payload_type, + int selected_tl, + int selected_sl) + : DirectTransport(task_queue, std::move(pipe), send_call), + vp8_video_payload_type_(vp8_video_payload_type), + vp9_video_payload_type_(vp9_video_payload_type), + selected_tl_(selected_tl), + selected_sl_(selected_sl), + discarded_last_packet_(false) {} + +bool LayerFilteringTransport::DiscardedLastPacket() const { + return discarded_last_packet_; +} + +bool LayerFilteringTransport::SendRtp(const uint8_t* packet, + size_t length, + const PacketOptions& options) { + if (selected_tl_ == -1 && selected_sl_ == -1) { + // Nothing to change, forward the packet immediately. + return test::DirectTransport::SendRtp(packet, length, options); + } + + bool set_marker_bit = false; + RtpUtility::RtpHeaderParser parser(packet, length); + RTPHeader header; + parser.Parse(&header); + + RTC_DCHECK_LE(length, IP_PACKET_SIZE); + uint8_t temp_buffer[IP_PACKET_SIZE]; + memcpy(temp_buffer, packet, length); + + if (header.payloadType == vp8_video_payload_type_ || + header.payloadType == vp9_video_payload_type_) { + const uint8_t* payload = packet + header.headerLength; + RTC_DCHECK_GT(length, header.headerLength); + const size_t payload_length = length - header.headerLength; + RTC_DCHECK_GT(payload_length, header.paddingLength); + const size_t payload_data_length = payload_length - header.paddingLength; + + const bool is_vp8 = header.payloadType == vp8_video_payload_type_; + std::unique_ptr<RtpDepacketizer> depacketizer( + RtpDepacketizer::Create(is_vp8 ? kRtpVideoVp8 : kRtpVideoVp9)); + RtpDepacketizer::ParsedPayload parsed_payload; + if (depacketizer->Parse(&parsed_payload, payload, payload_data_length)) { + const int temporal_idx = static_cast<int>( + is_vp8 ? parsed_payload.type.Video.codecHeader.VP8.temporalIdx + : parsed_payload.type.Video.codecHeader.VP9.temporal_idx); + const int spatial_idx = static_cast<int>( + is_vp8 ? kNoSpatialIdx + : parsed_payload.type.Video.codecHeader.VP9.spatial_idx); + if (selected_sl_ >= 0 && spatial_idx == selected_sl_ && + parsed_payload.type.Video.codecHeader.VP9.end_of_frame) { + // This layer is now the last in the superframe. + set_marker_bit = true; + } else if ((selected_tl_ >= 0 && temporal_idx != kNoTemporalIdx && + temporal_idx > selected_tl_) || + (selected_sl_ >= 0 && spatial_idx != kNoSpatialIdx && + spatial_idx > selected_sl_)) { + // Truncate packet to a padding packet. + length = header.headerLength + 1; + temp_buffer[0] |= (1 << 5); // P = 1. + temp_buffer[1] &= 0x7F; // M = 0. + discarded_last_packet_ = true; + temp_buffer[header.headerLength] = 1; // One byte of padding. + } + } else { + RTC_NOTREACHED() << "Parse error"; + } + } + + // We are discarding some of the packets (specifically, whole layers), so + // make sure the marker bit is set properly, and that sequence numbers are + // continuous. + if (set_marker_bit) + temp_buffer[1] |= kRtpMarkerBitMask; + + return test::DirectTransport::SendRtp(temp_buffer, length, options); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/layer_filtering_transport.h b/third_party/libwebrtc/webrtc/test/layer_filtering_transport.h new file mode 100644 index 0000000000..fe3b3d6d70 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/layer_filtering_transport.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_LAYER_FILTERING_TRANSPORT_H_ +#define TEST_LAYER_FILTERING_TRANSPORT_H_ + +#include "call/call.h" +#include "test/direct_transport.h" +#include "test/fake_network_pipe.h" +#include "test/single_threaded_task_queue.h" + +#include <map> + +namespace webrtc { + +namespace test { + +class LayerFilteringTransport : public test::DirectTransport { + public: + LayerFilteringTransport(SingleThreadedTaskQueueForTesting* task_queue, + const FakeNetworkPipe::Config& config, + Call* send_call, + uint8_t vp8_video_payload_type, + uint8_t vp9_video_payload_type, + int selected_tl, + int selected_sl, + const std::map<uint8_t, MediaType>& payload_type_map); + LayerFilteringTransport(SingleThreadedTaskQueueForTesting* task_queue, + std::unique_ptr<FakeNetworkPipe> pipe, + Call* send_call, + uint8_t vp8_video_payload_type, + uint8_t vp9_video_payload_type, + int selected_tl, + int selected_sl); + bool DiscardedLastPacket() const; + bool SendRtp(const uint8_t* data, + size_t length, + const PacketOptions& options) override; + + private: + // Used to distinguish between VP8 and VP9. + const uint8_t vp8_video_payload_type_; + const uint8_t vp9_video_payload_type_; + // Discard or invalidate all temporal/spatial layers with id greater than the + // selected one. -1 to disable filtering. + const int selected_tl_; + const int selected_sl_; + bool discarded_last_packet_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_LAYER_FILTERING_TRANSPORT_H_ diff --git a/third_party/libwebrtc/webrtc/test/linux/glx_renderer.cc b/third_party/libwebrtc/webrtc/test/linux/glx_renderer.cc new file mode 100644 index 0000000000..4dbf1c97d9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/linux/glx_renderer.cc @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/linux/glx_renderer.h" + +#include <assert.h> +#include <stdlib.h> + +#include <X11/Xatom.h> +#include <X11/Xlib.h> + +#include "common_video/libyuv/include/webrtc_libyuv.h" + +namespace webrtc { +namespace test { + +GlxRenderer::GlxRenderer(size_t width, size_t height) + : width_(width), + height_(height), + display_(NULL), + context_(NULL) { + assert(width > 0); + assert(height > 0); +} + +GlxRenderer::~GlxRenderer() { Destroy(); } + +bool GlxRenderer::Init(const char* window_title) { + if ((display_ = XOpenDisplay(NULL)) == NULL) { + Destroy(); + return false; + } + + int screen = DefaultScreen(display_); + + XVisualInfo* vi; + int attr_list[] = { GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, + None, }; + + if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) { + Destroy(); + return false; + } + + context_ = glXCreateContext(display_, vi, 0, true); + if (context_ == NULL) { + Destroy(); + return false; + } + + XSetWindowAttributes window_attributes; + window_attributes.colormap = XCreateColormap( + display_, RootWindow(display_, vi->screen), vi->visual, AllocNone); + window_attributes.border_pixel = 0; + window_attributes.event_mask = StructureNotifyMask | ExposureMask; + window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0, + width_, height_, 0, vi->depth, InputOutput, + vi->visual, CWBorderPixel | CWColormap | CWEventMask, + &window_attributes); + XFree(vi); + + XSetStandardProperties(display_, window_, window_title, window_title, None, + NULL, 0, NULL); + + Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True); + if (wm_delete != None) { + XSetWMProtocols(display_, window_, &wm_delete, 1); + } + + XMapRaised(display_, window_); + + if (!glXMakeCurrent(display_, window_, context_)) { + Destroy(); + return false; + } + GlRenderer::Init(); + if (!glXMakeCurrent(display_, None, NULL)) { + Destroy(); + return false; + } + + Resize(width_, height_); + return true; +} + +void GlxRenderer::Destroy() { + if (context_ != NULL) { + glXMakeCurrent(display_, window_, context_); + GlRenderer::Destroy(); + glXMakeCurrent(display_, None, NULL); + glXDestroyContext(display_, context_); + context_ = NULL; + } + + if (display_ != NULL) { + XCloseDisplay(display_); + display_ = NULL; + } +} + +GlxRenderer* GlxRenderer::Create(const char* window_title, size_t width, + size_t height) { + GlxRenderer* glx_renderer = new GlxRenderer(width, height); + if (!glx_renderer->Init(window_title)) { + // TODO(pbos): Add GLX-failed warning here? + delete glx_renderer; + return NULL; + } + return glx_renderer; +} + +void GlxRenderer::Resize(size_t width, size_t height) { + width_ = width; + height_ = height; + if (!glXMakeCurrent(display_, window_, context_)) { + abort(); + } + GlRenderer::ResizeViewport(width_, height_); + if (!glXMakeCurrent(display_, None, NULL)) { + abort(); + } + + XSizeHints* size_hints = XAllocSizeHints(); + if (size_hints == NULL) { + abort(); + } + size_hints->flags = PAspect; + size_hints->min_aspect.x = size_hints->max_aspect.x = width_; + size_hints->min_aspect.y = size_hints->max_aspect.y = height_; + XSetWMNormalHints(display_, window_, size_hints); + XFree(size_hints); + + XWindowChanges wc; + wc.width = static_cast<int>(width); + wc.height = static_cast<int>(height); + XConfigureWindow(display_, window_, CWWidth | CWHeight, &wc); +} + +void GlxRenderer::OnFrame(const webrtc::VideoFrame& frame) { + if (static_cast<size_t>(frame.width()) != width_ || + static_cast<size_t>(frame.height()) != height_) { + Resize(static_cast<size_t>(frame.width()), + static_cast<size_t>(frame.height())); + } + + XEvent event; + if (!glXMakeCurrent(display_, window_, context_)) { + abort(); + } + while (XPending(display_)) { + XNextEvent(display_, &event); + switch (event.type) { + case ConfigureNotify: + GlRenderer::ResizeViewport(event.xconfigure.width, + event.xconfigure.height); + break; + default: + break; + } + } + + GlRenderer::OnFrame(frame); + glXSwapBuffers(display_, window_); + + if (!glXMakeCurrent(display_, None, NULL)) { + abort(); + } +} +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/linux/glx_renderer.h b/third_party/libwebrtc/webrtc/test/linux/glx_renderer.h new file mode 100644 index 0000000000..63ef624262 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/linux/glx_renderer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_LINUX_GLX_RENDERER_H_ +#define TEST_LINUX_GLX_RENDERER_H_ + +#include <GL/glx.h> +#include <X11/Xlib.h> + +#include "test/gl/gl_renderer.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +class GlxRenderer : public GlRenderer { + public: + static GlxRenderer* Create(const char* window_title, size_t width, + size_t height); + virtual ~GlxRenderer(); + + void OnFrame(const webrtc::VideoFrame& frame) override; + + private: + GlxRenderer(size_t width, size_t height); + + bool Init(const char* window_title); + void Resize(size_t width, size_t height); + void Destroy(); + + size_t width_, height_; + + Display* display_; + Window window_; + GLXContext context_; +}; +} // test +} // webrtc + +#endif // TEST_LINUX_GLX_RENDERER_H_ diff --git a/third_party/libwebrtc/webrtc/test/linux/video_renderer_linux.cc b/third_party/libwebrtc/webrtc/test/linux/video_renderer_linux.cc new file mode 100644 index 0000000000..942848942f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/linux/video_renderer_linux.cc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/video_renderer.h" + +#include "test/linux/glx_renderer.h" + +namespace webrtc { +namespace test { + +VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title, + size_t width, + size_t height) { + GlxRenderer* glx_renderer = GlxRenderer::Create(window_title, width, height); + if (glx_renderer != NULL) { + return glx_renderer; + } + return NULL; +} +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/mac/run_test.mm b/third_party/libwebrtc/webrtc/test/mac/run_test.mm new file mode 100644 index 0000000000..38c6c8f8c1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mac/run_test.mm @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import <Cocoa/Cocoa.h> + +#include "test/run_test.h" + +// Converting a C++ function pointer to an Objective-C block. +typedef void(^TestBlock)(); +TestBlock functionToBlock(void(*function)()) { + return [^(void) { function(); } copy]; +} + +// Class calling the test function on the platform specific thread. +@interface TestRunner : NSObject { + BOOL running_; +} +- (void)runAllTests:(TestBlock)ignored; +- (BOOL)running; +@end + +@implementation TestRunner +- (id)init { + self = [super init]; + if (self) { + running_ = YES; + } + return self; +} + +- (void)runAllTests:(TestBlock)testBlock { + @autoreleasepool { + testBlock(); + running_ = NO; + } +} + +- (BOOL)running { + return running_; +} +@end + +namespace webrtc { +namespace test { + +void RunTest(void(*test)()) { + @autoreleasepool { + [NSApplication sharedApplication]; + + // Convert the function pointer to an Objective-C block and call on a + // separate thread, to avoid blocking the main thread. + TestRunner *testRunner = [[TestRunner alloc] init]; + TestBlock testBlock = functionToBlock(test); + [NSThread detachNewThreadSelector:@selector(runAllTests:) + toTarget:testRunner + withObject:testBlock]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + while ([testRunner running] && [runLoop runMode:NSDefaultRunLoopMode + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]) + ; + } +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.h b/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.h new file mode 100644 index 0000000000..19349c037a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MAC_VIDEO_RENDERER_MAC_H_ +#define TEST_MAC_VIDEO_RENDERER_MAC_H_ + +#include "rtc_base/constructormagic.h" +#include "test/gl/gl_renderer.h" + +@class CocoaWindow; + +namespace webrtc { +namespace test { + +class MacRenderer : public GlRenderer { + public: + MacRenderer(); + virtual ~MacRenderer(); + + bool Init(const char* window_title, int width, int height); + + // Implements GlRenderer. + void OnFrame(const VideoFrame& frame) override; + + private: + CocoaWindow* window_; + + RTC_DISALLOW_COPY_AND_ASSIGN(MacRenderer); +}; +} // test +} // webrtc + +#endif // TEST_MAC_VIDEO_RENDERER_MAC_H_ diff --git a/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.mm b/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.mm new file mode 100644 index 0000000000..56bf360986 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mac/video_renderer_mac.mm @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/mac/video_renderer_mac.h" + +#import <Cocoa/Cocoa.h> + +// Creates a Cocoa Window with an OpenGL context, used together with an OpenGL +// renderer. +@interface CocoaWindow : NSObject { + @private + NSWindow *window_; + NSOpenGLContext *context_; + NSString *title_; + int width_; + int height_; +} + +- (id)initWithTitle:(NSString *)title width:(int)width height:(int)height; +// 'createWindow' must be called on the main thread. +- (void)createWindow:(NSObject *)ignored; +- (void)makeCurrentContext; + +@end + +@implementation CocoaWindow + static NSInteger nextXOrigin_; + static NSInteger nextYOrigin_; + +- (id)initWithTitle:(NSString *)title width:(int)width height:(int)height { + if (self = [super init]) { + title_ = title; + width_ = width; + height_ = height; + } + return self; +} + +- (void)createWindow:(NSObject *)ignored { + NSInteger xOrigin = nextXOrigin_; + NSRect screenFrame = [[NSScreen mainScreen] frame]; + if (nextXOrigin_ + width_ < screenFrame.size.width) { + nextXOrigin_ += width_; + } else { + xOrigin = 0; + nextXOrigin_ = 0; + nextYOrigin_ += height_; + } + if (nextYOrigin_ + height_ > screenFrame.size.height) { + xOrigin = 0; + nextXOrigin_ = 0; + nextYOrigin_ = 0; + } + NSInteger yOrigin = nextYOrigin_; + NSRect windowFrame = NSMakeRect(xOrigin, yOrigin, width_, height_); + window_ = [[NSWindow alloc] initWithContentRect:windowFrame + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + + NSRect viewFrame = NSMakeRect(0, 0, width_, height_); + NSOpenGLView *view = [[NSOpenGLView alloc] initWithFrame:viewFrame pixelFormat:nil]; + context_ = [view openGLContext]; + + [[window_ contentView] addSubview:view]; + [window_ setTitle:title_]; + [window_ makeKeyAndOrderFront:NSApp]; +} + +- (void)makeCurrentContext { + [context_ makeCurrentContext]; +} + +@end + +namespace webrtc { +namespace test { + +VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title, + size_t width, + size_t height) { + MacRenderer* renderer = new MacRenderer(); + if (!renderer->Init(window_title, width, height)) { + delete renderer; + return NULL; + } + return renderer; +} + +MacRenderer::MacRenderer() + : window_(NULL) {} + +MacRenderer::~MacRenderer() { + GlRenderer::Destroy(); +} + +bool MacRenderer::Init(const char* window_title, int width, int height) { + window_ = [[CocoaWindow alloc] + initWithTitle:[NSString stringWithUTF8String:window_title] + width:width + height:height]; + if (!window_) + return false; + [window_ performSelectorOnMainThread:@selector(createWindow:) + withObject:nil + waitUntilDone:YES]; + + [window_ makeCurrentContext]; + GlRenderer::Init(); + GlRenderer::ResizeViewport(width, height); + return true; +} + +void MacRenderer::OnFrame(const VideoFrame& frame) { + [window_ makeCurrentContext]; + GlRenderer::OnFrame(frame); +} + +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_decoder.cc b/third_party/libwebrtc/webrtc/test/mock_audio_decoder.cc new file mode 100644 index 0000000000..5af9f370cd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_decoder.cc @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/mock_audio_decoder.h" + +namespace webrtc { + +MockAudioDecoder::MockAudioDecoder() = default; +MockAudioDecoder::~MockAudioDecoder() { + Die(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_decoder.h b/third_party/libwebrtc/webrtc/test/mock_audio_decoder.h new file mode 100644 index 0000000000..67cd0f775c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_decoder.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_AUDIO_DECODER_H_ +#define TEST_MOCK_AUDIO_DECODER_H_ + +#include "api/audio_codecs/audio_decoder.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockAudioDecoder : public AudioDecoder { + public: + MockAudioDecoder(); + ~MockAudioDecoder(); + MOCK_METHOD0(Die, void()); + MOCK_METHOD5(DecodeInternal, + int(const uint8_t*, size_t, int, int16_t*, SpeechType*)); + MOCK_CONST_METHOD0(HasDecodePlc, bool()); + MOCK_METHOD2(DecodePlc, size_t(size_t, int16_t*)); + MOCK_METHOD0(Reset, void()); + MOCK_METHOD5(IncomingPacket, + int(const uint8_t*, size_t, uint16_t, uint32_t, uint32_t)); + MOCK_METHOD0(ErrorCode, int()); + MOCK_CONST_METHOD2(PacketDuration, int(const uint8_t*, size_t)); + MOCK_CONST_METHOD0(Channels, size_t()); + MOCK_CONST_METHOD0(SampleRateHz, int()); +}; + +} // namespace webrtc +#endif // TEST_MOCK_AUDIO_DECODER_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_decoder_factory.h b/third_party/libwebrtc/webrtc/test/mock_audio_decoder_factory.h new file mode 100644 index 0000000000..bc504d871e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_decoder_factory.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_AUDIO_DECODER_FACTORY_H_ +#define TEST_MOCK_AUDIO_DECODER_FACTORY_H_ + +#include <memory> +#include <vector> + +#include "api/audio_codecs/audio_decoder_factory.h" +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "rtc_base/refcountedobject.h" +#include "rtc_base/scoped_ref_ptr.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockAudioDecoderFactory : public AudioDecoderFactory { + public: + MOCK_METHOD0(GetSupportedDecoders, std::vector<AudioCodecSpec>()); + MOCK_METHOD1(IsSupportedDecoder, bool(const SdpAudioFormat&)); + std::unique_ptr<AudioDecoder> MakeAudioDecoder(const SdpAudioFormat& format) { + std::unique_ptr<AudioDecoder> return_value; + MakeAudioDecoderMock(format, &return_value); + return return_value; + } + MOCK_METHOD2(MakeAudioDecoderMock, + void(const SdpAudioFormat& format, + std::unique_ptr<AudioDecoder>* return_value)); + + // Creates a MockAudioDecoderFactory with no formats and that may not be + // invoked to create a codec - useful for initializing a voice engine, for + // example. + static rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> + CreateUnusedFactory() { + using testing::_; + using testing::AnyNumber; + using testing::Return; + + rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> factory = + new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>; + ON_CALL(*factory.get(), GetSupportedDecoders()) + .WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>())); + EXPECT_CALL(*factory.get(), GetSupportedDecoders()).Times(AnyNumber()); + ON_CALL(*factory, IsSupportedDecoder(_)).WillByDefault(Return(false)); + EXPECT_CALL(*factory, IsSupportedDecoder(_)).Times(AnyNumber()); + EXPECT_CALL(*factory.get(), MakeAudioDecoderMock(_, _)).Times(0); + return factory; + } + + // Creates a MockAudioDecoderFactory with no formats that may be invoked to + // create a codec any number of times. It will, though, return nullptr on each + // call, since it supports no codecs. + static rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> + CreateEmptyFactory() { + using testing::_; + using testing::AnyNumber; + using testing::Return; + using testing::SetArgPointee; + + rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> factory = + new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>; + ON_CALL(*factory.get(), GetSupportedDecoders()) + .WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>())); + EXPECT_CALL(*factory.get(), GetSupportedDecoders()).Times(AnyNumber()); + ON_CALL(*factory, IsSupportedDecoder(_)).WillByDefault(Return(false)); + EXPECT_CALL(*factory, IsSupportedDecoder(_)).Times(AnyNumber()); + ON_CALL(*factory.get(), MakeAudioDecoderMock(_, _)) + .WillByDefault(SetArgPointee<1>(nullptr)); + EXPECT_CALL(*factory.get(), MakeAudioDecoderMock(_, _)).Times(AnyNumber()); + return factory; + } +}; + +} // namespace webrtc + +#endif // TEST_MOCK_AUDIO_DECODER_FACTORY_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_encoder.cc b/third_party/libwebrtc/webrtc/test/mock_audio_encoder.cc new file mode 100644 index 0000000000..cd89bdd4e8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_encoder.cc @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/mock_audio_encoder.h" + +namespace webrtc { + +MockAudioEncoder::MockAudioEncoder() = default; +MockAudioEncoder::~MockAudioEncoder() { + Die(); +} + +MockAudioEncoder::FakeEncoding::FakeEncoding( + const AudioEncoder::EncodedInfo& info) + : info_(info) {} + +MockAudioEncoder::FakeEncoding::FakeEncoding(size_t encoded_bytes) { + info_.encoded_bytes = encoded_bytes; +} + +AudioEncoder::EncodedInfo MockAudioEncoder::FakeEncoding::operator()( + uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer* encoded) { + encoded->SetSize(encoded->size() + info_.encoded_bytes); + return info_; +} + +MockAudioEncoder::CopyEncoding::~CopyEncoding() = default; + +MockAudioEncoder::CopyEncoding::CopyEncoding( + AudioEncoder::EncodedInfo info, + rtc::ArrayView<const uint8_t> payload) + : info_(info), payload_(payload) {} + +MockAudioEncoder::CopyEncoding::CopyEncoding( + rtc::ArrayView<const uint8_t> payload) + : payload_(payload) { + info_.encoded_bytes = payload_.size(); +} + +AudioEncoder::EncodedInfo MockAudioEncoder::CopyEncoding::operator()( + uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer* encoded) { + RTC_CHECK(encoded); + RTC_CHECK_LE(info_.encoded_bytes, payload_.size()); + encoded->AppendData(payload_.data(), info_.encoded_bytes); + return info_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_encoder.h b/third_party/libwebrtc/webrtc/test/mock_audio_encoder.h new file mode 100644 index 0000000000..8196cf18a7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_encoder.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_AUDIO_ENCODER_H_ +#define TEST_MOCK_AUDIO_ENCODER_H_ + +#include <string> + +#include "api/array_view.h" +#include "api/audio_codecs/audio_encoder.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockAudioEncoder : public AudioEncoder { + public: + // TODO(nisse): Valid overrides commented out, because the gmock + // methods don't use any override declarations, and we want to avoid + // warnings from -Winconsistent-missing-override. See + // http://crbug.com/428099. + MockAudioEncoder(); + ~MockAudioEncoder(); + MOCK_METHOD0(Die, void()); + MOCK_METHOD1(Mark, void(std::string desc)); + MOCK_CONST_METHOD0(SampleRateHz, int()); + MOCK_CONST_METHOD0(NumChannels, size_t()); + MOCK_CONST_METHOD0(RtpTimestampRateHz, int()); + MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, size_t()); + MOCK_CONST_METHOD0(Max10MsFramesInAPacket, size_t()); + MOCK_CONST_METHOD0(GetTargetBitrate, int()); + MOCK_METHOD0(Reset, void()); + MOCK_METHOD1(SetFec, bool(bool enable)); + MOCK_METHOD1(SetDtx, bool(bool enable)); + MOCK_METHOD1(SetApplication, bool(Application application)); + MOCK_METHOD1(SetMaxPlaybackRate, void(int frequency_hz)); + MOCK_METHOD1(SetMaxBitrate, void(int max_bps)); + MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); + MOCK_METHOD2(OnReceivedUplinkBandwidth, + void(int target_audio_bitrate_bps, + rtc::Optional<int64_t> probing_interval_ms)); + MOCK_METHOD1(OnReceivedUplinkPacketLossFraction, + void(float uplink_packet_loss_fraction)); + + MOCK_METHOD2(EnableAudioNetworkAdaptor, + bool(const std::string& config_string, RtcEventLog* event_log)); + + // Note, we explicitly chose not to create a mock for the Encode method. + MOCK_METHOD3(EncodeImpl, + EncodedInfo(uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer* encoded)); + + class FakeEncoding { + public: + // Creates a functor that will return |info| and adjust the rtc::Buffer + // given as input to it, so it is info.encoded_bytes larger. + explicit FakeEncoding(const AudioEncoder::EncodedInfo& info); + + // Shorthand version of the constructor above, for when only setting + // encoded_bytes in the EncodedInfo object matters. + explicit FakeEncoding(size_t encoded_bytes); + + AudioEncoder::EncodedInfo operator()(uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer* encoded); + + private: + AudioEncoder::EncodedInfo info_; + }; + + class CopyEncoding { + public: + ~CopyEncoding(); + + // Creates a functor that will return |info| and append the data in the + // payload to the buffer given as input to it. Up to info.encoded_bytes are + // appended - make sure the payload is big enough! Since it uses an + // ArrayView, it _does not_ copy the payload. Make sure it doesn't fall out + // of scope! + CopyEncoding(AudioEncoder::EncodedInfo info, + rtc::ArrayView<const uint8_t> payload); + + // Shorthand version of the constructor above, for when you wish to append + // the whole payload and do not care about any EncodedInfo attribute other + // than encoded_bytes. + explicit CopyEncoding(rtc::ArrayView<const uint8_t> payload); + + AudioEncoder::EncodedInfo operator()(uint32_t timestamp, + rtc::ArrayView<const int16_t> audio, + rtc::Buffer* encoded); + + private: + AudioEncoder::EncodedInfo info_; + rtc::ArrayView<const uint8_t> payload_; + }; +}; + +} // namespace webrtc + +#endif // TEST_MOCK_AUDIO_ENCODER_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_audio_encoder_factory.h b/third_party/libwebrtc/webrtc/test/mock_audio_encoder_factory.h new file mode 100644 index 0000000000..9b63f7d18f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_audio_encoder_factory.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_AUDIO_ENCODER_FACTORY_H_ +#define TEST_MOCK_AUDIO_ENCODER_FACTORY_H_ + +#include <memory> +#include <vector> + +#include "api/audio_codecs/audio_encoder_factory.h" +#include "rtc_base/scoped_ref_ptr.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockAudioEncoderFactory : public AudioEncoderFactory { + public: + MOCK_METHOD0(GetSupportedEncoders, std::vector<AudioCodecSpec>()); + MOCK_METHOD1(QueryAudioEncoder, + rtc::Optional<AudioCodecInfo>(const SdpAudioFormat& format)); + + std::unique_ptr<AudioEncoder> MakeAudioEncoder(int payload_type, + const SdpAudioFormat& format) { + std::unique_ptr<AudioEncoder> return_value; + MakeAudioEncoderMock(payload_type, format, &return_value); + return return_value; + } + MOCK_METHOD3(MakeAudioEncoderMock, + void(int payload_type, + const SdpAudioFormat& format, + std::unique_ptr<AudioEncoder>* return_value)); + + // Creates a MockAudioEncoderFactory with no formats and that may not be + // invoked to create a codec - useful for initializing a voice engine, for + // example. + static rtc::scoped_refptr<webrtc::MockAudioEncoderFactory> + CreateUnusedFactory() { + using testing::_; + using testing::AnyNumber; + using testing::Return; + + rtc::scoped_refptr<webrtc::MockAudioEncoderFactory> factory = + new rtc::RefCountedObject<webrtc::MockAudioEncoderFactory>; + ON_CALL(*factory.get(), GetSupportedEncoders()) + .WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>())); + ON_CALL(*factory.get(), QueryAudioEncoder(_)) + .WillByDefault(Return(rtc::Optional<AudioCodecInfo>())); + + EXPECT_CALL(*factory.get(), GetSupportedEncoders()).Times(AnyNumber()); + EXPECT_CALL(*factory.get(), QueryAudioEncoder(_)).Times(AnyNumber()); + EXPECT_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _)).Times(0); + return factory; + } + + // Creates a MockAudioEncoderFactory with no formats that may be invoked to + // create a codec any number of times. It will, though, return nullptr on each + // call, since it supports no codecs. + static rtc::scoped_refptr<webrtc::MockAudioEncoderFactory> + CreateEmptyFactory() { + using testing::_; + using testing::AnyNumber; + using testing::Return; + using testing::SetArgPointee; + + rtc::scoped_refptr<webrtc::MockAudioEncoderFactory> factory = + new rtc::RefCountedObject<webrtc::MockAudioEncoderFactory>; + ON_CALL(*factory.get(), GetSupportedEncoders()) + .WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>())); + ON_CALL(*factory.get(), QueryAudioEncoder(_)) + .WillByDefault(Return(rtc::Optional<AudioCodecInfo>())); + ON_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _)) + .WillByDefault(SetArgPointee<2>(nullptr)); + + EXPECT_CALL(*factory.get(), GetSupportedEncoders()).Times(AnyNumber()); + EXPECT_CALL(*factory.get(), QueryAudioEncoder(_)).Times(AnyNumber()); + EXPECT_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _)) + .Times(AnyNumber()); + return factory; + } +}; + +} // namespace webrtc + +#endif // TEST_MOCK_AUDIO_ENCODER_FACTORY_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_transport.h b/third_party/libwebrtc/webrtc/test/mock_transport.h new file mode 100644 index 0000000000..9837593f33 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_transport.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_TRANSPORT_H_ +#define TEST_MOCK_TRANSPORT_H_ + +#include "api/call/transport.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockTransport : public Transport { + public: + MOCK_METHOD3(SendRtp, + bool(const uint8_t* data, + size_t len, + const PacketOptions& options)); + MOCK_METHOD2(SendRtcp, bool(const uint8_t* data, size_t len)); +}; +} // namespace webrtc +#endif // TEST_MOCK_TRANSPORT_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_voe_channel_proxy.h b/third_party/libwebrtc/webrtc/test/mock_voe_channel_proxy.h new file mode 100644 index 0000000000..9bc48b10a0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_voe_channel_proxy.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_MOCK_VOE_CHANNEL_PROXY_H_ +#define TEST_MOCK_VOE_CHANNEL_PROXY_H_ + +#include <string> + +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "test/gmock.h" +#include "voice_engine/channel_proxy.h" + +namespace webrtc { +namespace test { + +class MockVoEChannelProxy : public voe::ChannelProxy { + public: + // GTest doesn't like move-only types, like std::unique_ptr + bool SetEncoder(int payload_type, + std::unique_ptr<AudioEncoder> encoder) { + return SetEncoderForMock(payload_type, &encoder); + } + MOCK_METHOD2(SetEncoderForMock, + bool(int payload_type, + std::unique_ptr<AudioEncoder>* encoder)); + MOCK_METHOD1( + ModifyEncoder, + void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier)); + MOCK_METHOD1(SetRTCPStatus, void(bool enable)); + MOCK_METHOD1(SetLocalSSRC, void(uint32_t ssrc)); + MOCK_METHOD1(SetRTCP_CNAME, void(const std::string& c_name)); + MOCK_METHOD2(SetNACKStatus, void(bool enable, int max_packets)); + MOCK_METHOD2(SetSendAudioLevelIndicationStatus, void(bool enable, int id)); + MOCK_METHOD2(SetReceiveAudioLevelIndicationStatus, void(bool enable, int id)); + MOCK_METHOD1(EnableSendTransportSequenceNumber, void(int id)); + MOCK_METHOD1(EnableReceiveTransportSequenceNumber, void(int id)); + MOCK_METHOD2(RegisterSenderCongestionControlObjects, + void(RtpTransportControllerSendInterface* transport, + RtcpBandwidthObserver* bandwidth_observer)); + MOCK_METHOD1(RegisterReceiverCongestionControlObjects, + void(PacketRouter* packet_router)); + MOCK_METHOD0(ResetSenderCongestionControlObjects, void()); + MOCK_METHOD0(ResetReceiverCongestionControlObjects, void()); + MOCK_CONST_METHOD0(GetRTCPStatistics, CallStatistics()); + MOCK_CONST_METHOD0(GetRemoteRTCPReportBlocks, std::vector<ReportBlock>()); + MOCK_CONST_METHOD0(GetNetworkStatistics, NetworkStatistics()); + MOCK_CONST_METHOD0(GetDecodingCallStatistics, AudioDecodingCallStats()); + MOCK_CONST_METHOD0(GetANAStatistics, ANAStats()); + MOCK_CONST_METHOD0(GetSpeechOutputLevel, int()); + MOCK_CONST_METHOD0(GetSpeechOutputLevelFullRange, int()); + MOCK_CONST_METHOD0(GetTotalOutputEnergy, double()); + MOCK_CONST_METHOD0(GetTotalOutputDuration, double()); + MOCK_CONST_METHOD0(GetDelayEstimate, uint32_t()); + MOCK_METHOD2(SetSendTelephoneEventPayloadType, bool(int payload_type, + int payload_frequency)); + MOCK_METHOD2(SendTelephoneEventOutband, bool(int event, int duration_ms)); + MOCK_METHOD2(SetBitrate, void(int bitrate_bps, int64_t probing_interval_ms)); + // TODO(solenberg): Talk the compiler into accepting this mock method: + // MOCK_METHOD1(SetSink, void(std::unique_ptr<AudioSinkInterface> sink)); + MOCK_METHOD1(SetInputMute, void(bool muted)); + MOCK_METHOD1(RegisterTransport, void(Transport* transport)); + MOCK_METHOD1(OnRtpPacket, void(const RtpPacketReceived& packet)); + MOCK_METHOD2(ReceivedRTCPPacket, bool(const uint8_t* packet, size_t length)); + MOCK_CONST_METHOD0(GetAudioDecoderFactory, + const rtc::scoped_refptr<AudioDecoderFactory>&()); + MOCK_METHOD1(SetChannelOutputVolumeScaling, void(float scaling)); + MOCK_METHOD1(SetRtcEventLog, void(RtcEventLog* event_log)); + MOCK_METHOD1(SetRtcpRttStats, void(RtcpRttStats* rtcp_rtt_stats)); + MOCK_METHOD2(GetAudioFrameWithInfo, + AudioMixer::Source::AudioFrameInfo(int sample_rate_hz, + AudioFrame* audio_frame)); + MOCK_CONST_METHOD0(PreferredSampleRate, int()); + MOCK_METHOD1(SetTransportOverhead, void(int transport_overhead_per_packet)); + MOCK_METHOD1(AssociateSendChannel, + void(const ChannelProxy& send_channel_proxy)); + MOCK_METHOD0(DisassociateSendChannel, void()); + MOCK_CONST_METHOD2(GetRtpRtcp, void(RtpRtcp** rtp_rtcp, + RtpReceiver** rtp_receiver)); + MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t()); + MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms)); + MOCK_CONST_METHOD1(GetRecCodec, bool(CodecInst* codec_inst)); + MOCK_METHOD1(SetReceiveCodecs, + void(const std::map<int, SdpAudioFormat>& codecs)); + MOCK_METHOD1(OnTwccBasedUplinkPacketLossRate, void(float packet_loss_rate)); + MOCK_METHOD1(OnRecoverableUplinkPacketLossRate, + void(float recoverable_packet_loss_rate)); + MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>()); +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_MOCK_VOE_CHANNEL_PROXY_H_ diff --git a/third_party/libwebrtc/webrtc/test/mock_voice_engine.h b/third_party/libwebrtc/webrtc/test/mock_voice_engine.h new file mode 100644 index 0000000000..57c6b58c67 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/mock_voice_engine.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef AUDIO_MOCK_VOICE_ENGINE_H_ +#define AUDIO_MOCK_VOICE_ENGINE_H_ + +#include <memory> + +#include "modules/audio_device/include/mock_audio_transport.h" +#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" +#include "test/gmock.h" +#include "test/mock_voe_channel_proxy.h" +#include "voice_engine/voice_engine_impl.h" + +namespace webrtc { +namespace voe { +class TransmitMixer; +} // namespace voe + +namespace test { + +// NOTE: This class inherits from VoiceEngineImpl so that its clients will be +// able to get the various interfaces as usual, via T::GetInterface(). +class MockVoiceEngine : public VoiceEngineImpl { + public: + // TODO(nisse): Valid overrides commented out, because the gmock + // methods don't use any override declarations, and we want to avoid + // warnings from -Winconsistent-missing-override. See + // http://crbug.com/428099. + MockVoiceEngine( + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory = nullptr) + : decoder_factory_(decoder_factory) { + // Increase ref count so this object isn't automatically deleted whenever + // interfaces are Release():d. + ++_ref_count; + // We add this default behavior to make the mock easier to use in tests. It + // will create a NiceMock of a voe::ChannelProxy. + // TODO(ossu): As long as AudioReceiveStream is implemented as a wrapper + // around Channel, we need to make sure ChannelProxy returns the same + // decoder factory as the one passed in when creating an AudioReceiveStream. + ON_CALL(*this, ChannelProxyFactory(testing::_)) + .WillByDefault(testing::Invoke([this](int channel_id) { + auto* proxy = + new testing::NiceMock<webrtc::test::MockVoEChannelProxy>(); + EXPECT_CALL(*proxy, GetAudioDecoderFactory()) + .WillRepeatedly(testing::ReturnRef(decoder_factory_)); + EXPECT_CALL(*proxy, SetReceiveCodecs(testing::_)) + .WillRepeatedly(testing::Invoke( + [](const std::map<int, SdpAudioFormat>& codecs) { + EXPECT_THAT(codecs, testing::IsEmpty()); + })); + EXPECT_CALL(*proxy, GetRtpRtcp(testing::_, testing::_)) + .WillRepeatedly( + testing::SetArgPointee<0>(GetMockRtpRtcp(channel_id))); + return proxy; + })); + + ON_CALL(*this, audio_transport()) + .WillByDefault(testing::Return(&mock_audio_transport_)); + } + virtual ~MockVoiceEngine() /* override */ { + // Decrease ref count before base class d-tor is called; otherwise it will + // trigger an assertion. + --_ref_count; + } + + // These need to be the same each call to channel_id and must not leak. + MockRtpRtcp* GetMockRtpRtcp(int channel_id) { + if (mock_rtp_rtcps_.find(channel_id) == mock_rtp_rtcps_.end()) { + mock_rtp_rtcps_[channel_id].reset(new ::testing::NiceMock<MockRtpRtcp>); + } + return mock_rtp_rtcps_[channel_id].get(); + } + + // Allows injecting a ChannelProxy factory. + MOCK_METHOD1(ChannelProxyFactory, voe::ChannelProxy*(int channel_id)); + + // VoiceEngineImpl + virtual std::unique_ptr<voe::ChannelProxy> GetChannelProxy( + int channel_id) /* override */ { + return std::unique_ptr<voe::ChannelProxy>(ChannelProxyFactory(channel_id)); + } + + // VoEBase + MOCK_METHOD3( + Init, + int(AudioDeviceModule* external_adm, + AudioProcessing* external_apm, + const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)); + MOCK_METHOD0(transmit_mixer, voe::TransmitMixer*()); + MOCK_METHOD0(Terminate, void()); + MOCK_METHOD0(CreateChannel, int()); + MOCK_METHOD1(CreateChannel, int(const ChannelConfig& config)); + MOCK_METHOD1(DeleteChannel, int(int channel)); + MOCK_METHOD1(StartPlayout, int(int channel)); + MOCK_METHOD1(StopPlayout, int(int channel)); + MOCK_METHOD1(StartSend, int(int channel)); + MOCK_METHOD1(StopSend, int(int channel)); + MOCK_METHOD0(audio_transport, AudioTransport*()); + + private: + // TODO(ossu): I'm not particularly happy about keeping the decoder factory + // here, but due to how gmock is implemented, I cannot just keep it in the + // functor implementing the default version of ChannelProxyFactory, above. + // GMock creates an unfortunate copy of the functor, which would cause us to + // return a dangling reference. Fortunately, this should go away once + // voe::Channel does. + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_; + + std::map<int, std::unique_ptr<MockRtpRtcp>> mock_rtp_rtcps_; + + MockAudioTransport mock_audio_transport_; +}; +} // namespace test +} // namespace webrtc + +#endif // AUDIO_MOCK_VOICE_ENGINE_H_ diff --git a/third_party/libwebrtc/webrtc/test/null_platform_renderer.cc b/third_party/libwebrtc/webrtc/test/null_platform_renderer.cc new file mode 100644 index 0000000000..48e4cc0d8b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/null_platform_renderer.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/video_renderer.h" + +namespace webrtc { +namespace test { + +VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title, + size_t width, + size_t height) { + return NULL; +} +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/null_transport.cc b/third_party/libwebrtc/webrtc/test/null_transport.cc new file mode 100644 index 0000000000..efbd9499d8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/null_transport.cc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/null_transport.h" + +namespace webrtc { +namespace test { + +bool NullTransport::SendRtp(const uint8_t* packet, + size_t length, + const PacketOptions& options) { + return true; +} + +bool NullTransport::SendRtcp(const uint8_t* packet, size_t length) { + return true; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/null_transport.h b/third_party/libwebrtc/webrtc/test/null_transport.h new file mode 100644 index 0000000000..f264e7b45a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/null_transport.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_NULL_TRANSPORT_H_ +#define TEST_NULL_TRANSPORT_H_ + +#include "api/call/transport.h" + +namespace webrtc { + +class PacketReceiver; + +namespace test { +class NullTransport : public Transport { + public: + bool SendRtp(const uint8_t* packet, + size_t length, + const PacketOptions& options) override; + bool SendRtcp(const uint8_t* packet, size_t length) override; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_NULL_TRANSPORT_H_ diff --git a/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.cc b/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.cc new file mode 100644 index 0000000000..2f9658a9e5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/rtcp_packet_parser.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace test { + +RtcpPacketParser::RtcpPacketParser() = default; +RtcpPacketParser::~RtcpPacketParser() = default; + +bool RtcpPacketParser::Parse(const void* data, size_t length) { + const uint8_t* const buffer = static_cast<const uint8_t*>(data); + const uint8_t* const buffer_end = buffer + length; + rtcp::CommonHeader header; + for (const uint8_t* next_packet = buffer; next_packet != buffer_end; + next_packet = header.NextPacket()) { + RTC_DCHECK_GT(buffer_end - next_packet, 0); + if (!header.Parse(next_packet, buffer_end - next_packet)) { + RTC_LOG(LS_WARNING) + << "Invalid rtcp header or unaligned rtcp packet at position " + << (next_packet - buffer); + return false; + } + switch (header.type()) { + case rtcp::App::kPacketType: + app_.Parse(header); + break; + case rtcp::Bye::kPacketType: + bye_.Parse(header, &sender_ssrc_); + break; + case rtcp::ExtendedReports::kPacketType: + xr_.Parse(header, &sender_ssrc_); + break; + case rtcp::ExtendedJitterReport::kPacketType: + ij_.Parse(header); + break; + case rtcp::Psfb::kPacketType: + switch (header.fmt()) { + case rtcp::Fir::kFeedbackMessageType: + fir_.Parse(header, &sender_ssrc_); + break; + case rtcp::Pli::kFeedbackMessageType: + pli_.Parse(header, &sender_ssrc_); + break; + case rtcp::Remb::kFeedbackMessageType: + remb_.Parse(header, &sender_ssrc_); + break; + default: + RTC_LOG(LS_WARNING) + << "Unknown rtcp payload specific feedback type " + << header.fmt(); + break; + } + break; + case rtcp::ReceiverReport::kPacketType: + receiver_report_.Parse(header, &sender_ssrc_); + break; + case rtcp::Rtpfb::kPacketType: + switch (header.fmt()) { + case rtcp::Nack::kFeedbackMessageType: + nack_.Parse(header, &sender_ssrc_); + break; + case rtcp::RapidResyncRequest::kFeedbackMessageType: + rrr_.Parse(header, &sender_ssrc_); + break; + case rtcp::Tmmbn::kFeedbackMessageType: + tmmbn_.Parse(header, &sender_ssrc_); + break; + case rtcp::Tmmbr::kFeedbackMessageType: + tmmbr_.Parse(header, &sender_ssrc_); + break; + case rtcp::TransportFeedback::kFeedbackMessageType: + transport_feedback_.Parse(header, &sender_ssrc_); + break; + default: + RTC_LOG(LS_WARNING) + << "Unknown rtcp transport feedback type " << header.fmt(); + break; + } + break; + case rtcp::Sdes::kPacketType: + sdes_.Parse(header); + break; + case rtcp::SenderReport::kPacketType: + sender_report_.Parse(header, &sender_ssrc_); + break; + default: + RTC_LOG(LS_WARNING) << "Unknown rtcp packet type " << header.type(); + break; + } + } + return true; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.h b/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.h new file mode 100644 index 0000000000..96e97c107d --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtcp_packet_parser.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +#ifndef TEST_RTCP_PACKET_PARSER_H_ +#define TEST_RTCP_PACKET_PARSER_H_ + +#include "api/array_view.h" +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" +#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.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/sdes.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { +// Parse RTCP packet of given type. Assumes RTCP header is valid and that there +// is excatly one packet of correct type in the buffer. +template <typename Packet> +bool ParseSinglePacket(const uint8_t* buffer, size_t size, Packet* packet) { + rtcp::CommonHeader header; + RTC_CHECK(header.Parse(buffer, size)); + RTC_CHECK_EQ(size, header.NextPacket() - buffer); + return packet->Parse(header); +} +// Same function, but takes raw buffer as single argument instead of pair. +template <typename Packet> +bool ParseSinglePacket(rtc::ArrayView<const uint8_t> buffer, Packet* packet) { + return ParseSinglePacket(buffer.data(), buffer.size(), packet); +} + +class RtcpPacketParser { + public: + // Keeps last parsed packet, count number of parsed packets of given type. + template <typename TypedRtcpPacket> + class PacketCounter : public TypedRtcpPacket { + public: + int num_packets() const { return num_packets_; } + void Parse(const rtcp::CommonHeader& header) { + if (TypedRtcpPacket::Parse(header)) + ++num_packets_; + } + void Parse(const rtcp::CommonHeader& header, uint32_t* sender_ssrc) { + if (TypedRtcpPacket::Parse(header)) { + ++num_packets_; + if (*sender_ssrc == 0) // Use first sender ssrc in compound packet. + *sender_ssrc = TypedRtcpPacket::sender_ssrc(); + } + } + + private: + int num_packets_ = 0; + }; + + RtcpPacketParser(); + ~RtcpPacketParser(); + + bool Parse(const void* packet, size_t packet_len); + + PacketCounter<rtcp::App>* app() { return &app_; } + PacketCounter<rtcp::Bye>* bye() { return &bye_; } + PacketCounter<rtcp::ExtendedJitterReport>* ij() { return &ij_; } + PacketCounter<rtcp::ExtendedReports>* xr() { return &xr_; } + PacketCounter<rtcp::Fir>* fir() { return &fir_; } + PacketCounter<rtcp::Nack>* nack() { return &nack_; } + PacketCounter<rtcp::Pli>* pli() { return &pli_; } + PacketCounter<rtcp::RapidResyncRequest>* rrr() { return &rrr_; } + PacketCounter<rtcp::ReceiverReport>* receiver_report() { + return &receiver_report_; + } + PacketCounter<rtcp::Remb>* remb() { return &remb_; } + PacketCounter<rtcp::Sdes>* sdes() { return &sdes_; } + PacketCounter<rtcp::SenderReport>* sender_report() { return &sender_report_; } + PacketCounter<rtcp::Tmmbn>* tmmbn() { return &tmmbn_; } + PacketCounter<rtcp::Tmmbr>* tmmbr() { return &tmmbr_; } + PacketCounter<rtcp::TransportFeedback>* transport_feedback() { + return &transport_feedback_; + } + uint32_t sender_ssrc() const { return sender_ssrc_; } + + private: + PacketCounter<rtcp::App> app_; + PacketCounter<rtcp::Bye> bye_; + PacketCounter<rtcp::ExtendedJitterReport> ij_; + PacketCounter<rtcp::ExtendedReports> xr_; + PacketCounter<rtcp::Fir> fir_; + PacketCounter<rtcp::Nack> nack_; + PacketCounter<rtcp::Pli> pli_; + PacketCounter<rtcp::RapidResyncRequest> rrr_; + PacketCounter<rtcp::ReceiverReport> receiver_report_; + PacketCounter<rtcp::Remb> remb_; + PacketCounter<rtcp::Sdes> sdes_; + PacketCounter<rtcp::SenderReport> sender_report_; + PacketCounter<rtcp::Tmmbn> tmmbn_; + PacketCounter<rtcp::Tmmbr> tmmbr_; + PacketCounter<rtcp::TransportFeedback> transport_feedback_; + uint32_t sender_ssrc_ = 0; +}; + +} // namespace test +} // namespace webrtc +#endif // TEST_RTCP_PACKET_PARSER_H_ diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_reader.cc b/third_party/libwebrtc/webrtc/test/rtp_file_reader.cc new file mode 100644 index 0000000000..0367487543 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_reader.cc @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/rtp_file_reader.h" + +#include <stdio.h> + +#include <map> +#include <string> +#include <vector> + +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/checks.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/format_macros.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace test { + +static const size_t kFirstLineLength = 40; +static uint16_t kPacketHeaderSize = 8; + +#define TRY(expr) \ + do { \ + if (!(expr)) { \ + RTC_LOG(LS_INFO) << "Failed to read"; \ + return false; \ + } \ + } while (0) + +bool ReadUint32(uint32_t* out, FILE* file) { + *out = 0; + for (size_t i = 0; i < 4; ++i) { + *out <<= 8; + uint8_t tmp; + if (fread(&tmp, 1, sizeof(uint8_t), file) != sizeof(uint8_t)) + return false; + *out |= tmp; + } + return true; +} + +bool ReadUint16(uint16_t* out, FILE* file) { + *out = 0; + for (size_t i = 0; i < 2; ++i) { + *out <<= 8; + uint8_t tmp; + if (fread(&tmp, 1, sizeof(uint8_t), file) != sizeof(uint8_t)) + return false; + *out |= tmp; + } + return true; +} + +class RtpFileReaderImpl : public RtpFileReader { + public: + virtual bool Init(const std::string& filename, + const std::set<uint32_t>& ssrc_filter) = 0; +}; + +class InterleavedRtpFileReader : public RtpFileReaderImpl { + public: + virtual ~InterleavedRtpFileReader() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + virtual bool Init(const std::string& filename, + const std::set<uint32_t>& ssrc_filter) { + file_ = fopen(filename.c_str(), "rb"); + if (file_ == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return false; + } + return true; + } + virtual bool NextPacket(RtpPacket* packet) { + assert(file_ != NULL); + packet->length = RtpPacket::kMaxPacketBufferSize; + uint32_t len = 0; + TRY(ReadUint32(&len, file_)); + if (packet->length < len) { + FATAL() << "Packet is too large to fit: " << len << " bytes vs " + << packet->length + << " bytes allocated. Consider increasing the buffer " + "size"; + } + if (fread(packet->data, 1, len, file_) != len) + return false; + + packet->length = len; + packet->original_length = len; + packet->time_ms = time_ms_; + time_ms_ += 5; + return true; + } + + private: + FILE* file_ = NULL; + int64_t time_ms_ = 0; +}; + +// Read RTP packets from file in rtpdump format, as documented at: +// http://www.cs.columbia.edu/irt/software/rtptools/ +class RtpDumpReader : public RtpFileReaderImpl { + public: + RtpDumpReader() : file_(NULL) {} + virtual ~RtpDumpReader() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + bool Init(const std::string& filename, + const std::set<uint32_t>& ssrc_filter) override { + file_ = fopen(filename.c_str(), "rb"); + if (file_ == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return false; + } + + char firstline[kFirstLineLength + 1] = {0}; + if (fgets(firstline, kFirstLineLength, file_) == NULL) { + RTC_LOG(LS_INFO) << "Can't read from file"; + return false; + } + if (strncmp(firstline, "#!rtpplay", 9) == 0) { + if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) { + RTC_LOG(LS_INFO) << "Wrong rtpplay version, must be 1.0"; + return false; + } + } else if (strncmp(firstline, "#!RTPencode", 11) == 0) { + if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) { + RTC_LOG(LS_INFO) << "Wrong RTPencode version, must be 1.0"; + return false; + } + } else { + RTC_LOG(LS_INFO) << "Wrong file format of input file"; + return false; + } + + uint32_t start_sec; + uint32_t start_usec; + uint32_t source; + uint16_t port; + uint16_t padding; + TRY(ReadUint32(&start_sec, file_)); + TRY(ReadUint32(&start_usec, file_)); + TRY(ReadUint32(&source, file_)); + TRY(ReadUint16(&port, file_)); + TRY(ReadUint16(&padding, file_)); + + return true; + } + + bool NextPacket(RtpPacket* packet) override { + uint8_t* rtp_data = packet->data; + packet->length = RtpPacket::kMaxPacketBufferSize; + + uint16_t len; + uint16_t plen; + uint32_t offset; + TRY(ReadUint16(&len, file_)); + TRY(ReadUint16(&plen, file_)); + TRY(ReadUint32(&offset, file_)); + + // Use 'len' here because a 'plen' of 0 specifies rtcp. + len -= kPacketHeaderSize; + if (packet->length < len) { + FATAL() << "Packet is too large to fit: " << len << " bytes vs " + << packet->length + << " bytes allocated. Consider increasing the buffer " + "size"; + } + if (fread(rtp_data, 1, len, file_) != len) { + return false; + } + + packet->length = len; + packet->original_length = plen; + packet->time_ms = offset; + return true; + } + + private: + FILE* file_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); +}; + +enum { + kResultFail = -1, + kResultSuccess = 0, + kResultSkip = 1, + + kPcapVersionMajor = 2, + kPcapVersionMinor = 4, + kLinktypeNull = 0, + kLinktypeEthernet = 1, + kBsdNullLoopback1 = 0x00000002, + kBsdNullLoopback2 = 0x02000000, + kEthernetIIHeaderMacSkip = 12, + kEthertypeIp = 0x0800, + kIpVersion4 = 4, + kMinIpHeaderLength = 20, + kFragmentOffsetClear = 0x0000, + kFragmentOffsetDoNotFragment = 0x4000, + kProtocolTcp = 0x06, + kProtocolUdp = 0x11, + kUdpHeaderLength = 8, + kMaxReadBufferSize = 4096 +}; + +const uint32_t kPcapBOMSwapOrder = 0xd4c3b2a1UL; +const uint32_t kPcapBOMNoSwapOrder = 0xa1b2c3d4UL; + +#define TRY_PCAP(expr) \ + do { \ + int r = (expr); \ + if (r == kResultFail) { \ + RTC_LOG(LS_INFO) << "FAIL at " << __FILE__ << ":" << __LINE__; \ + return kResultFail; \ + } else if (r == kResultSkip) { \ + return kResultSkip; \ + } \ + } while (0) + +// Read RTP packets from file in tcpdump/libpcap format, as documented at: +// http://wiki.wireshark.org/Development/LibpcapFileFormat +class PcapReader : public RtpFileReaderImpl { + public: + PcapReader() + : file_(NULL), + swap_pcap_byte_order_(false), +#ifdef WEBRTC_ARCH_BIG_ENDIAN + swap_network_byte_order_(false), +#else + swap_network_byte_order_(true), +#endif + read_buffer_(), + packets_by_ssrc_(), + packets_(), + next_packet_it_() { + } + + virtual ~PcapReader() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + bool Init(const std::string& filename, + const std::set<uint32_t>& ssrc_filter) override { + return Initialize(filename, ssrc_filter) == kResultSuccess; + } + + int Initialize(const std::string& filename, + const std::set<uint32_t>& ssrc_filter) { + file_ = fopen(filename.c_str(), "rb"); + if (file_ == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return kResultFail; + } + + if (ReadGlobalHeader() < 0) { + return kResultFail; + } + + int total_packet_count = 0; + uint32_t stream_start_ms = 0; + int32_t next_packet_pos = ftell(file_); + for (;;) { + TRY_PCAP(fseek(file_, next_packet_pos, SEEK_SET)); + int result = ReadPacket(&next_packet_pos, stream_start_ms, + ++total_packet_count, ssrc_filter); + if (result == kResultFail) { + break; + } else if (result == kResultSuccess && packets_.size() == 1) { + assert(stream_start_ms == 0); + PacketIterator it = packets_.begin(); + stream_start_ms = it->time_offset_ms; + it->time_offset_ms = 0; + } + } + + if (feof(file_) == 0) { + printf("Failed reading file!\n"); + return kResultFail; + } + + printf("Total packets in file: %d\n", total_packet_count); + printf("Total RTP/RTCP packets: %" PRIuS "\n", packets_.size()); + + for (SsrcMapIterator mit = packets_by_ssrc_.begin(); + mit != packets_by_ssrc_.end(); ++mit) { + uint32_t ssrc = mit->first; + const std::vector<uint32_t>& packet_indices = mit->second; + uint8_t pt = packets_[packet_indices[0]].rtp_header.payloadType; + printf("SSRC: %08x, %" PRIuS " packets, pt=%d\n", ssrc, + packet_indices.size(), pt); + } + + // TODO(solenberg): Better validation of identified SSRC streams. + // + // Since we're dealing with raw network data here, we will wrongly identify + // some packets as RTP. When these packets are consumed by RtpPlayer, they + // are unlikely to cause issues as they will ultimately be filtered out by + // the RtpRtcp module. However, we should really do better filtering here, + // which we can accomplish in a number of ways, e.g.: + // + // - Verify that the time stamps and sequence numbers for RTP packets are + // both increasing/decreasing. If they move in different directions, the + // SSRC is likely bogus and can be dropped. (Normally they should be inc- + // reasing but we must allow packet reordering). + // - If RTP sequence number is not changing, drop the stream. + // - Can also use srcip:port->dstip:port pairs, assuming few SSRC collisions + // for up/down streams. + + next_packet_it_ = packets_.begin(); + return kResultSuccess; + } + + bool NextPacket(RtpPacket* packet) override { + uint32_t length = RtpPacket::kMaxPacketBufferSize; + if (NextPcap(packet->data, &length, &packet->time_ms) != kResultSuccess) + return false; + packet->length = static_cast<size_t>(length); + packet->original_length = packet->length; + return true; + } + + virtual int NextPcap(uint8_t* data, uint32_t* length, uint32_t* time_ms) { + assert(data); + assert(length); + assert(time_ms); + + if (next_packet_it_ == packets_.end()) { + return -1; + } + if (*length < next_packet_it_->payload_length) { + return -1; + } + TRY_PCAP(fseek(file_, next_packet_it_->pos_in_file, SEEK_SET)); + TRY_PCAP(Read(data, next_packet_it_->payload_length)); + *length = next_packet_it_->payload_length; + *time_ms = next_packet_it_->time_offset_ms; + next_packet_it_++; + + return 0; + } + + private: + // A marker of an RTP packet within the file. + struct RtpPacketMarker { + uint32_t packet_number; // One-based index (like in WireShark) + uint32_t time_offset_ms; + uint32_t source_ip; + uint32_t dest_ip; + uint16_t source_port; + uint16_t dest_port; + RTPHeader rtp_header; + int32_t pos_in_file; // Byte offset of payload from start of file. + uint32_t payload_length; + }; + + typedef std::vector<RtpPacketMarker>::iterator PacketIterator; + typedef std::map<uint32_t, std::vector<uint32_t> > SsrcMap; + typedef std::map<uint32_t, std::vector<uint32_t> >::iterator SsrcMapIterator; + + int ReadGlobalHeader() { + uint32_t magic; + TRY_PCAP(Read(&magic, false)); + if (magic == kPcapBOMSwapOrder) { + swap_pcap_byte_order_ = true; + } else if (magic == kPcapBOMNoSwapOrder) { + swap_pcap_byte_order_ = false; + } else { + return kResultFail; + } + + uint16_t version_major; + uint16_t version_minor; + TRY_PCAP(Read(&version_major, false)); + TRY_PCAP(Read(&version_minor, false)); + if (version_major != kPcapVersionMajor || + version_minor != kPcapVersionMinor) { + return kResultFail; + } + + int32_t this_zone; // GMT to local correction. + uint32_t sigfigs; // Accuracy of timestamps. + uint32_t snaplen; // Max length of captured packets, in octets. + uint32_t network; // Data link type. + TRY_PCAP(Read(&this_zone, false)); + TRY_PCAP(Read(&sigfigs, false)); + TRY_PCAP(Read(&snaplen, false)); + TRY_PCAP(Read(&network, false)); + + // Accept only LINKTYPE_NULL and LINKTYPE_ETHERNET. + // See: http://www.tcpdump.org/linktypes.html + if (network != kLinktypeNull && network != kLinktypeEthernet) { + return kResultFail; + } + + return kResultSuccess; + } + + int ReadPacket(int32_t* next_packet_pos, + uint32_t stream_start_ms, + uint32_t number, + const std::set<uint32_t>& ssrc_filter) { + assert(next_packet_pos); + + uint32_t ts_sec; // Timestamp seconds. + uint32_t ts_usec; // Timestamp microseconds. + uint32_t incl_len; // Number of octets of packet saved in file. + uint32_t orig_len; // Actual length of packet. + TRY_PCAP(Read(&ts_sec, false)); + TRY_PCAP(Read(&ts_usec, false)); + TRY_PCAP(Read(&incl_len, false)); + TRY_PCAP(Read(&orig_len, false)); + + *next_packet_pos = ftell(file_) + incl_len; + + RtpPacketMarker marker = {0}; + marker.packet_number = number; + marker.time_offset_ms = CalcTimeDelta(ts_sec, ts_usec, stream_start_ms); + TRY_PCAP(ReadPacketHeader(&marker)); + marker.pos_in_file = ftell(file_); + + if (marker.payload_length > sizeof(read_buffer_)) { + printf("Packet too large!\n"); + return kResultFail; + } + TRY_PCAP(Read(read_buffer_, marker.payload_length)); + + RtpUtility::RtpHeaderParser rtp_parser(read_buffer_, marker.payload_length); + if (rtp_parser.RTCP()) { + rtp_parser.ParseRtcp(&marker.rtp_header); + packets_.push_back(marker); + } else { + if (!rtp_parser.Parse(&marker.rtp_header, nullptr)) { + RTC_LOG(LS_INFO) << "Not recognized as RTP/RTCP"; + return kResultSkip; + } + + uint32_t ssrc = marker.rtp_header.ssrc; + if (ssrc_filter.empty() || ssrc_filter.find(ssrc) != ssrc_filter.end()) { + packets_by_ssrc_[ssrc].push_back( + static_cast<uint32_t>(packets_.size())); + packets_.push_back(marker); + } else { + return kResultSkip; + } + } + + return kResultSuccess; + } + + int ReadPacketHeader(RtpPacketMarker* marker) { + int32_t file_pos = ftell(file_); + + // Check for BSD null/loopback frame header. The header is just 4 bytes in + // native byte order, so we check for both versions as we don't care about + // the header as such and will likely fail reading the IP header if this is + // something else than null/loopback. + uint32_t protocol; + TRY_PCAP(Read(&protocol, true)); + if (protocol == kBsdNullLoopback1 || protocol == kBsdNullLoopback2) { + int result = ReadXxpIpHeader(marker); + RTC_LOG(LS_INFO) << "Recognized loopback frame"; + if (result != kResultSkip) { + return result; + } + } + + TRY_PCAP(fseek(file_, file_pos, SEEK_SET)); + + // Check for Ethernet II, IP frame header. + uint16_t type; + TRY_PCAP(Skip(kEthernetIIHeaderMacSkip)); // Source+destination MAC. + TRY_PCAP(Read(&type, true)); + if (type == kEthertypeIp) { + int result = ReadXxpIpHeader(marker); + RTC_LOG(LS_INFO) << "Recognized ethernet 2 frame"; + if (result != kResultSkip) { + return result; + } + } + + return kResultSkip; + } + + uint32_t CalcTimeDelta(uint32_t ts_sec, uint32_t ts_usec, uint32_t start_ms) { + // Round to nearest ms. + uint64_t t2_ms = ((static_cast<uint64_t>(ts_sec) * 1000000) + ts_usec + + 500) / 1000; + uint64_t t1_ms = static_cast<uint64_t>(start_ms); + if (t2_ms < t1_ms) { + return 0; + } else { + return t2_ms - t1_ms; + } + } + + int ReadXxpIpHeader(RtpPacketMarker* marker) { + assert(marker); + + uint16_t version; + uint16_t length; + uint16_t id; + uint16_t fragment; + uint16_t protocol; + uint16_t checksum; + TRY_PCAP(Read(&version, true)); + TRY_PCAP(Read(&length, true)); + TRY_PCAP(Read(&id, true)); + TRY_PCAP(Read(&fragment, true)); + TRY_PCAP(Read(&protocol, true)); + TRY_PCAP(Read(&checksum, true)); + TRY_PCAP(Read(&marker->source_ip, true)); + TRY_PCAP(Read(&marker->dest_ip, true)); + + if (((version >> 12) & 0x000f) != kIpVersion4) { + RTC_LOG(LS_INFO) << "IP header is not IPv4"; + return kResultSkip; + } + + if (fragment != kFragmentOffsetClear && + fragment != kFragmentOffsetDoNotFragment) { + RTC_LOG(LS_INFO) << "IP fragments cannot be handled"; + return kResultSkip; + } + + // Skip remaining fields of IP header. + uint16_t header_length = (version & 0x0f00) >> (8 - 2); + assert(header_length >= kMinIpHeaderLength); + TRY_PCAP(Skip(header_length - kMinIpHeaderLength)); + + protocol = protocol & 0x00ff; + if (protocol == kProtocolTcp) { + RTC_LOG(LS_INFO) << "TCP packets are not handled"; + return kResultSkip; + } else if (protocol == kProtocolUdp) { + uint16_t length; + uint16_t checksum; + TRY_PCAP(Read(&marker->source_port, true)); + TRY_PCAP(Read(&marker->dest_port, true)); + TRY_PCAP(Read(&length, true)); + TRY_PCAP(Read(&checksum, true)); + marker->payload_length = length - kUdpHeaderLength; + } else { + RTC_LOG(LS_INFO) << "Unknown transport (expected UDP or TCP)"; + return kResultSkip; + } + + return kResultSuccess; + } + + int Read(uint32_t* out, bool expect_network_order) { + uint32_t tmp = 0; + if (fread(&tmp, 1, sizeof(uint32_t), file_) != sizeof(uint32_t)) { + return kResultFail; + } + if ((!expect_network_order && swap_pcap_byte_order_) || + (expect_network_order && swap_network_byte_order_)) { + tmp = ((tmp >> 24) & 0x000000ff) | (tmp << 24) | + ((tmp >> 8) & 0x0000ff00) | ((tmp << 8) & 0x00ff0000); + } + *out = tmp; + return kResultSuccess; + } + + int Read(uint16_t* out, bool expect_network_order) { + uint16_t tmp = 0; + if (fread(&tmp, 1, sizeof(uint16_t), file_) != sizeof(uint16_t)) { + return kResultFail; + } + if ((!expect_network_order && swap_pcap_byte_order_) || + (expect_network_order && swap_network_byte_order_)) { + tmp = ((tmp >> 8) & 0x00ff) | (tmp << 8); + } + *out = tmp; + return kResultSuccess; + } + + int Read(uint8_t* out, uint32_t count) { + if (fread(out, 1, count, file_) != count) { + return kResultFail; + } + return kResultSuccess; + } + + int Read(int32_t* out, bool expect_network_order) { + int32_t tmp = 0; + if (fread(&tmp, 1, sizeof(uint32_t), file_) != sizeof(uint32_t)) { + return kResultFail; + } + if ((!expect_network_order && swap_pcap_byte_order_) || + (expect_network_order && swap_network_byte_order_)) { + tmp = ((tmp >> 24) & 0x000000ff) | (tmp << 24) | + ((tmp >> 8) & 0x0000ff00) | ((tmp << 8) & 0x00ff0000); + } + *out = tmp; + return kResultSuccess; + } + + int Skip(uint32_t length) { + if (fseek(file_, length, SEEK_CUR) != 0) { + return kResultFail; + } + return kResultSuccess; + } + + FILE* file_; + bool swap_pcap_byte_order_; + const bool swap_network_byte_order_; + uint8_t read_buffer_[kMaxReadBufferSize]; + + SsrcMap packets_by_ssrc_; + std::vector<RtpPacketMarker> packets_; + PacketIterator next_packet_it_; + + RTC_DISALLOW_COPY_AND_ASSIGN(PcapReader); +}; + +RtpFileReader* RtpFileReader::Create(FileFormat format, + const std::string& filename, + const std::set<uint32_t>& ssrc_filter) { + RtpFileReaderImpl* reader = NULL; + switch (format) { + case kPcap: + reader = new PcapReader(); + break; + case kRtpDump: + reader = new RtpDumpReader(); + break; + case kLengthPacketInterleaved: + reader = new InterleavedRtpFileReader(); + break; + } + if (!reader->Init(filename, ssrc_filter)) { + delete reader; + return NULL; + } + return reader; +} + +RtpFileReader* RtpFileReader::Create(FileFormat format, + const std::string& filename) { + return RtpFileReader::Create(format, filename, std::set<uint32_t>()); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_reader.h b/third_party/libwebrtc/webrtc/test/rtp_file_reader.h new file mode 100644 index 0000000000..c044d3de26 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_reader.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_RTP_FILE_READER_H_ +#define TEST_RTP_FILE_READER_H_ + +#include <set> +#include <string> + +#include "common_types.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +struct RtpPacket { + // Accommodate for 50 ms packets of 32 kHz PCM16 samples (3200 bytes) plus + // some overhead. + static const size_t kMaxPacketBufferSize = 3500; + uint8_t data[kMaxPacketBufferSize]; + size_t length; + // The length the packet had on wire. Will be different from |length| when + // reading a header-only RTP dump. + size_t original_length; + + uint32_t time_ms; +}; + +class RtpFileReader { + public: + enum FileFormat { kPcap, kRtpDump, kLengthPacketInterleaved }; + + virtual ~RtpFileReader() {} + static RtpFileReader* Create(FileFormat format, + const std::string& filename); + static RtpFileReader* Create(FileFormat format, + const std::string& filename, + const std::set<uint32_t>& ssrc_filter); + + virtual bool NextPacket(RtpPacket* packet) = 0; +}; +} // namespace test +} // namespace webrtc +#endif // TEST_RTP_FILE_READER_H_ diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_reader_unittest.cc b/third_party/libwebrtc/webrtc/test/rtp_file_reader_unittest.cc new file mode 100644 index 0000000000..b41f32fc9c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_reader_unittest.cc @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <map> +#include <memory> + +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "test/gtest.h" +#include "test/rtp_file_reader.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { + +class TestRtpFileReader : public ::testing::Test { + public: + void Init(const std::string& filename, bool headers_only_file) { + std::string filepath = + test::ResourcePath("video_coding/" + filename, "rtp"); + rtp_packet_source_.reset( + test::RtpFileReader::Create(test::RtpFileReader::kRtpDump, filepath)); + ASSERT_TRUE(rtp_packet_source_.get() != NULL); + headers_only_file_ = headers_only_file; + } + + int CountRtpPackets() { + test::RtpPacket packet; + int c = 0; + while (rtp_packet_source_->NextPacket(&packet)) { + if (headers_only_file_) + EXPECT_LT(packet.length, packet.original_length); + else + EXPECT_EQ(packet.length, packet.original_length); + c++; + } + return c; + } + + private: + std::unique_ptr<test::RtpFileReader> rtp_packet_source_; + bool headers_only_file_; +}; + +TEST_F(TestRtpFileReader, Test60Packets) { + Init("pltype103", false); + EXPECT_EQ(60, CountRtpPackets()); +} + +TEST_F(TestRtpFileReader, Test60PacketsHeaderOnly) { + Init("pltype103_header_only", true); + EXPECT_EQ(60, CountRtpPackets()); +} + +typedef std::map<uint32_t, int> PacketsPerSsrc; + +class TestPcapFileReader : public ::testing::Test { + public: + void Init(const std::string& filename) { + std::string filepath = + test::ResourcePath("video_coding/" + filename, "pcap"); + rtp_packet_source_.reset( + test::RtpFileReader::Create(test::RtpFileReader::kPcap, filepath)); + ASSERT_TRUE(rtp_packet_source_.get() != NULL); + } + + int CountRtpPackets() { + int c = 0; + test::RtpPacket packet; + while (rtp_packet_source_->NextPacket(&packet)) { + EXPECT_EQ(packet.length, packet.original_length); + c++; + } + return c; + } + + PacketsPerSsrc CountRtpPacketsPerSsrc() { + PacketsPerSsrc pps; + test::RtpPacket packet; + while (rtp_packet_source_->NextPacket(&packet)) { + RtpUtility::RtpHeaderParser rtp_header_parser(packet.data, packet.length); + webrtc::RTPHeader header; + if (!rtp_header_parser.RTCP() && + rtp_header_parser.Parse(&header, nullptr)) { + pps[header.ssrc]++; + } + } + return pps; + } + + private: + std::unique_ptr<test::RtpFileReader> rtp_packet_source_; +}; + +TEST_F(TestPcapFileReader, TestEthernetIIFrame) { + Init("frame-ethernet-ii"); + EXPECT_EQ(368, CountRtpPackets()); +} + +TEST_F(TestPcapFileReader, TestLoopbackFrame) { + Init("frame-loopback"); + EXPECT_EQ(491, CountRtpPackets()); +} + +TEST_F(TestPcapFileReader, TestTwoSsrc) { + Init("ssrcs-2"); + PacketsPerSsrc pps = CountRtpPacketsPerSsrc(); + EXPECT_EQ(2UL, pps.size()); + EXPECT_EQ(370, pps[0x78d48f61]); + EXPECT_EQ(60, pps[0xae94130b]); +} + +TEST_F(TestPcapFileReader, TestThreeSsrc) { + Init("ssrcs-3"); + PacketsPerSsrc pps = CountRtpPacketsPerSsrc(); + EXPECT_EQ(3UL, pps.size()); + EXPECT_EQ(162, pps[0x938c5eaa]); + EXPECT_EQ(113, pps[0x59fe6ef0]); + EXPECT_EQ(61, pps[0xed2bd2ac]); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_writer.cc b/third_party/libwebrtc/webrtc/test/rtp_file_writer.cc new file mode 100644 index 0000000000..132ce9a0a4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_writer.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/rtp_file_writer.h" + +#include <stdio.h> + +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { +namespace test { + +static const uint16_t kPacketHeaderSize = 8; +static const char kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; + +// Write RTP packets to file in rtpdump format, as documented at: +// http://www.cs.columbia.edu/irt/software/rtptools/ +class RtpDumpWriter : public RtpFileWriter { + public: + explicit RtpDumpWriter(FILE* file) : file_(file) { + RTC_CHECK(file_ != NULL); + Init(); + } + virtual ~RtpDumpWriter() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + bool WritePacket(const RtpPacket* packet) override { + uint16_t len = static_cast<uint16_t>(packet->length + kPacketHeaderSize); + uint16_t plen = static_cast<uint16_t>(packet->original_length); + uint32_t offset = packet->time_ms; + RTC_CHECK(WriteUint16(len)); + RTC_CHECK(WriteUint16(plen)); + RTC_CHECK(WriteUint32(offset)); + return fwrite(packet->data, sizeof(uint8_t), packet->length, file_) == + packet->length; + } + + private: + bool Init() { + fprintf(file_, "%s", kFirstLine); + + RTC_CHECK(WriteUint32(0)); + RTC_CHECK(WriteUint32(0)); + RTC_CHECK(WriteUint32(0)); + RTC_CHECK(WriteUint16(0)); + RTC_CHECK(WriteUint16(0)); + + return true; + } + + bool WriteUint32(uint32_t in) { + // Loop through shifts = {24, 16, 8, 0}. + for (int shifts = 24; shifts >= 0; shifts -= 8) { + uint8_t tmp = static_cast<uint8_t>((in >> shifts) & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + } + return true; + } + + bool WriteUint16(uint16_t in) { + // Write 8 MSBs. + uint8_t tmp = static_cast<uint8_t>((in >> 8) & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + // Write 8 LSBs. + tmp = static_cast<uint8_t>(in & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + return true; + } + + FILE* file_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); +}; + +RtpFileWriter* RtpFileWriter::Create(FileFormat format, + const std::string& filename) { + FILE* file = fopen(filename.c_str(), "wb"); + if (file == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return NULL; + } + switch (format) { + case kRtpDump: + return new RtpDumpWriter(file); + } + fclose(file); + return NULL; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_writer.h b/third_party/libwebrtc/webrtc/test/rtp_file_writer.h new file mode 100644 index 0000000000..4496ca4a25 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_writer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_RTP_FILE_WRITER_H_ +#define TEST_RTP_FILE_WRITER_H_ + +#include <string> + +#include "common_types.h" // NOLINT(build/include) +#include "test/rtp_file_reader.h" + +namespace webrtc { +namespace test { +class RtpFileWriter { + public: + enum FileFormat { + kRtpDump, + }; + + virtual ~RtpFileWriter() {} + static RtpFileWriter* Create(FileFormat format, const std::string& filename); + + virtual bool WritePacket(const RtpPacket* packet) = 0; +}; +} // namespace test +} // namespace webrtc +#endif // TEST_RTP_FILE_WRITER_H_ diff --git a/third_party/libwebrtc/webrtc/test/rtp_file_writer_unittest.cc b/third_party/libwebrtc/webrtc/test/rtp_file_writer_unittest.cc new file mode 100644 index 0000000000..aec10f793b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_file_writer_unittest.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <string.h> + +#include <memory> + +#include "test/gtest.h" +#include "test/rtp_file_reader.h" +#include "test/rtp_file_writer.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { + +class RtpFileWriterTest : public ::testing::Test { + public: + void Init(const std::string& filename) { + filename_ = test::OutputPath() + filename; + rtp_writer_.reset( + test::RtpFileWriter::Create(test::RtpFileWriter::kRtpDump, filename_)); + } + + void WriteRtpPackets(int num_packets) { + ASSERT_TRUE(rtp_writer_.get() != NULL); + test::RtpPacket packet; + for (int i = 1; i <= num_packets; ++i) { + packet.length = i; + packet.original_length = i; + packet.time_ms = i; + memset(packet.data, i, packet.length); + EXPECT_TRUE(rtp_writer_->WritePacket(&packet)); + } + } + + void CloseOutputFile() { rtp_writer_.reset(); } + + void VerifyFileContents(int expected_packets) { + ASSERT_TRUE(rtp_writer_.get() == NULL) + << "Must call CloseOutputFile before VerifyFileContents"; + std::unique_ptr<test::RtpFileReader> rtp_reader( + test::RtpFileReader::Create(test::RtpFileReader::kRtpDump, filename_)); + ASSERT_TRUE(rtp_reader.get() != NULL); + test::RtpPacket packet; + int i = 0; + while (rtp_reader->NextPacket(&packet)) { + ++i; + EXPECT_EQ(static_cast<size_t>(i), packet.length); + EXPECT_EQ(static_cast<size_t>(i), packet.original_length); + EXPECT_EQ(static_cast<uint32_t>(i), packet.time_ms); + for (int j = 0; j < i; ++j) { + EXPECT_EQ(i, packet.data[j]); + } + } + EXPECT_EQ(expected_packets, i); + } + + private: + std::unique_ptr<test::RtpFileWriter> rtp_writer_; + std::string filename_; +}; + +TEST_F(RtpFileWriterTest, WriteToRtpDump) { + Init("test_rtp_file_writer.rtp"); + WriteRtpPackets(10); + CloseOutputFile(); + VerifyFileContents(10); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/rtp_rtcp_observer.h b/third_party/libwebrtc/webrtc/test/rtp_rtcp_observer.h new file mode 100644 index 0000000000..5163d2248e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/rtp_rtcp_observer.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_RTP_RTCP_OBSERVER_H_ +#define TEST_RTP_RTCP_OBSERVER_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "system_wrappers/include/field_trial.h" +#include "test/constants.h" +#include "test/direct_transport.h" +#include "test/gtest.h" +#include "typedefs.h" // NOLINT(build/include) +#include "call/video_send_stream.h" + +namespace { +const int kShortTimeoutMs = 500; +} + +namespace webrtc { +namespace test { + +class PacketTransport; +class SingleThreadedTaskQueueForTesting; + +class RtpRtcpObserver { + public: + enum Action { + SEND_PACKET, + DROP_PACKET, + }; + + virtual ~RtpRtcpObserver() {} + + virtual bool Wait() { + if (field_trial::IsEnabled("WebRTC-QuickPerfTest")) { + observation_complete_.Wait(kShortTimeoutMs); + return true; + } + return observation_complete_.Wait(timeout_ms_); + } + + virtual Action OnSendRtp(const uint8_t* packet, size_t length) { + return SEND_PACKET; + } + + virtual Action OnSendRtcp(const uint8_t* packet, size_t length) { + return SEND_PACKET; + } + + virtual Action OnReceiveRtp(const uint8_t* packet, size_t length) { + return SEND_PACKET; + } + + virtual Action OnReceiveRtcp(const uint8_t* packet, size_t length) { + return SEND_PACKET; + } + + protected: + RtpRtcpObserver() : RtpRtcpObserver(0) {} + explicit RtpRtcpObserver(int event_timeout_ms) + : observation_complete_(false, false), + parser_(RtpHeaderParser::Create()), + timeout_ms_(event_timeout_ms) { + parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset, + kTOffsetExtensionId); + parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsSendTimeExtensionId); + parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId); + } + + rtc::Event observation_complete_; + const std::unique_ptr<RtpHeaderParser> parser_; + + private: + const int timeout_ms_; +}; + +class PacketTransport : public test::DirectTransport { + public: + enum TransportType { kReceiver, kSender }; + + PacketTransport(SingleThreadedTaskQueueForTesting* task_queue, + Call* send_call, + RtpRtcpObserver* observer, + TransportType transport_type, + const std::map<uint8_t, MediaType>& payload_type_map, + const FakeNetworkPipe::Config& configuration) + : test::DirectTransport(task_queue, + configuration, + send_call, + payload_type_map), + observer_(observer), + transport_type_(transport_type) {} + + PacketTransport(SingleThreadedTaskQueueForTesting* task_queue, + Call* send_call, RtpRtcpObserver* observer, + TransportType transport_type, + std::unique_ptr<FakeNetworkPipe> nw_pipe) + : test::DirectTransport(task_queue, std::move(nw_pipe), send_call), + observer_(observer), + transport_type_(transport_type) {} + + private: + bool SendRtp(const uint8_t* packet, + size_t length, + const PacketOptions& options) override { + EXPECT_FALSE(RtpHeaderParser::IsRtcp(packet, length)); + RtpRtcpObserver::Action action; + { + if (transport_type_ == kSender) { + action = observer_->OnSendRtp(packet, length); + } else { + action = observer_->OnReceiveRtp(packet, length); + } + } + switch (action) { + case RtpRtcpObserver::DROP_PACKET: + // Drop packet silently. + return true; + case RtpRtcpObserver::SEND_PACKET: + return test::DirectTransport::SendRtp(packet, length, options); + } + return true; // Will never happen, makes compiler happy. + } + + bool SendRtcp(const uint8_t* packet, size_t length) override { + EXPECT_TRUE(RtpHeaderParser::IsRtcp(packet, length)); + RtpRtcpObserver::Action action; + { + if (transport_type_ == kSender) { + action = observer_->OnSendRtcp(packet, length); + } else { + action = observer_->OnReceiveRtcp(packet, length); + } + } + switch (action) { + case RtpRtcpObserver::DROP_PACKET: + // Drop packet silently. + return true; + case RtpRtcpObserver::SEND_PACKET: + return test::DirectTransport::SendRtcp(packet, length); + } + return true; // Will never happen, makes compiler happy. + } + + RtpRtcpObserver* const observer_; + TransportType transport_type_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_RTP_RTCP_OBSERVER_H_ diff --git a/third_party/libwebrtc/webrtc/test/run_loop.cc b/third_party/libwebrtc/webrtc/test/run_loop.cc new file mode 100644 index 0000000000..0d00ecd5e9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/run_loop.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/run_loop.h" + +#include <stdio.h> + +namespace webrtc { +namespace test { + +void PressEnterToContinue() { + puts(">> Press ENTER to continue..."); + while (getc(stdin) != '\n' && !feof(stdin)); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/run_loop.h b/third_party/libwebrtc/webrtc/test/run_loop.h new file mode 100644 index 0000000000..90063dc3e8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/run_loop.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_RUN_LOOP_H_ +#define TEST_RUN_LOOP_H_ + +namespace webrtc { +namespace test { + +// Blocks until the user presses enter. +void PressEnterToContinue(); + +} // namespace test +} // namespace webrtc + +#endif // TEST_RUN_LOOP_H_ diff --git a/third_party/libwebrtc/webrtc/test/run_test.cc b/third_party/libwebrtc/webrtc/test/run_test.cc new file mode 100644 index 0000000000..ba0bf34d23 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/run_test.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/run_test.h" + +#include <stdio.h> + +namespace webrtc { +namespace test { + +void RunTest(void(*test)()) { + (*test)(); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/run_test.h b/third_party/libwebrtc/webrtc/test/run_test.h new file mode 100644 index 0000000000..ed908570fd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/run_test.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_RUN_TEST_H_ +#define TEST_RUN_TEST_H_ + +namespace webrtc { +namespace test { + +// Running a test function on a separate thread, if required by the OS. +void RunTest(void(*test)()); + +} // namespace test +} // namespace webrtc + +#endif // TEST_RUN_TEST_H_ diff --git a/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.cc b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.cc new file mode 100644 index 0000000000..8a8cbea614 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.cc @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/single_threaded_task_queue.h" + +#include <utility> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/timeutils.h" + +namespace webrtc { +namespace test { + +SingleThreadedTaskQueueForTesting::QueuedTask::QueuedTask( + SingleThreadedTaskQueueForTesting::TaskId task_id, + int64_t earliest_execution_time, + SingleThreadedTaskQueueForTesting::Task task) + : task_id(task_id), + earliest_execution_time(earliest_execution_time), + task(task) {} + +SingleThreadedTaskQueueForTesting::QueuedTask::~QueuedTask() = default; + +SingleThreadedTaskQueueForTesting::SingleThreadedTaskQueueForTesting( + const char* name) + : thread_(Run, this, name), + running_(true), + next_task_id_(0), + wake_up_(false, false) { + thread_.Start(); +} + +SingleThreadedTaskQueueForTesting::~SingleThreadedTaskQueueForTesting() { + RTC_DCHECK_RUN_ON(&owner_thread_checker_); + { + rtc::CritScope lock(&cs_); + running_ = false; + } + wake_up_.Set(); + thread_.Stop(); +} + +SingleThreadedTaskQueueForTesting::TaskId +SingleThreadedTaskQueueForTesting::PostTask(Task task) { + return PostDelayedTask(task, 0); +} + +SingleThreadedTaskQueueForTesting::TaskId +SingleThreadedTaskQueueForTesting::PostDelayedTask(Task task, + int64_t delay_ms) { + int64_t earliest_exec_time = rtc::TimeAfter(delay_ms); + + rtc::CritScope lock(&cs_); + + TaskId id = next_task_id_++; + + // Insert after any other tasks with an earlier-or-equal target time. + auto it = tasks_.begin(); + for (; it != tasks_.end(); it++) { + if (earliest_exec_time < (*it)->earliest_execution_time) { + break; + } + } + tasks_.insert(it, rtc::MakeUnique<QueuedTask>(id, earliest_exec_time, task)); + + // This class is optimized for simplicty, not for performance. This will wake + // the thread up even if the next task in the queue is only scheduled for + // quite some time from now. In that case, the thread will just send itself + // back to sleep. + wake_up_.Set(); + + return id; +} + +void SingleThreadedTaskQueueForTesting::SendTask(Task task) { + rtc::Event done(true, false); + PostTask([&task, &done]() { + task(); + done.Set(); + }); + done.Wait(rtc::Event::kForever); +} + +bool SingleThreadedTaskQueueForTesting::CancelTask(TaskId task_id) { + rtc::CritScope lock(&cs_); + for (auto it = tasks_.begin(); it != tasks_.end(); it++) { + if ((*it)->task_id == task_id) { + tasks_.erase(it); + return true; + } + } + return false; +} + +void SingleThreadedTaskQueueForTesting::Run(void* obj) { + static_cast<SingleThreadedTaskQueueForTesting*>(obj)->RunLoop(); +} + +void SingleThreadedTaskQueueForTesting::RunLoop() { + while (true) { + std::unique_ptr<QueuedTask> queued_task; + + // An empty queue would lead to sleeping until the queue becoems non-empty. + // A queue where the earliest task is shceduled for later than now, will + // lead to sleeping until the time of the next scheduled task (or until + // more tasks are scheduled). + int wait_time = rtc::Event::kForever; + + { + rtc::CritScope lock(&cs_); + if (!running_) { + return; + } + if (!tasks_.empty()) { + int64_t remaining_delay_ms = rtc::TimeDiff( + tasks_.front()->earliest_execution_time, rtc::TimeMillis()); + if (remaining_delay_ms <= 0) { + queued_task = std::move(tasks_.front()); + tasks_.pop_front(); + } else { + wait_time = rtc::saturated_cast<int>(remaining_delay_ms); + } + } + } + + if (queued_task) { + queued_task->task(); + } else { + wake_up_.Wait(wait_time); + } + } +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.h b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.h new file mode 100644 index 0000000000..0721891263 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_SINGLE_THREADED_TASK_QUEUE_H_ +#define TEST_SINGLE_THREADED_TASK_QUEUE_H_ + +#include <functional> +#include <list> +#include <memory> + +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/thread_checker.h" + +namespace webrtc { +namespace test { + +// This class gives capabilities similar to rtc::TaskQueue, but ensures +// everything happens on the same thread. This is intended to make the +// threading model of unit-tests (specifically end-to-end tests) more closely +// resemble that of real WebRTC, thereby allowing us to replace some critical +// sections by thread-checkers. +// This task is NOT tuned for performance, but rather for simplicity. +class SingleThreadedTaskQueueForTesting { + public: + using Task = std::function<void()>; + using TaskId = size_t; + + explicit SingleThreadedTaskQueueForTesting(const char* name); + ~SingleThreadedTaskQueueForTesting(); + + // Sends one task to the task-queue, and returns a handle by which the + // task can be cancelled. + // This mimics the behavior of TaskQueue, but only for lambdas, rather than + // for both lambdas and QueuedTask objects. + TaskId PostTask(Task task); + + // Same as PostTask(), but ensures that the task will not begin execution + // less than |delay_ms| milliseconds after being posted; an upper bound + // is not provided. + TaskId PostDelayedTask(Task task, int64_t delay_ms); + + // Send one task to the queue. The function does not return until the task + // has finished executing. No support for canceling the task. + void SendTask(Task task); + + // Given an identifier to the task, attempts to eject it from the queue. + // Returns true if the task was found and cancelled. Failure possible + // only for invalid task IDs, or for tasks which have already been executed. + bool CancelTask(TaskId task_id); + + private: + struct QueuedTask { + QueuedTask(TaskId task_id, int64_t earliest_execution_time, Task task); + ~QueuedTask(); + + TaskId task_id; + int64_t earliest_execution_time; + Task task; + }; + + static void Run(void* obj); + + void RunLoop(); + + rtc::CriticalSection cs_; + std::list<std::unique_ptr<QueuedTask>> tasks_ RTC_GUARDED_BY(cs_); + rtc::ThreadChecker owner_thread_checker_; + rtc::PlatformThread thread_; + bool running_ RTC_GUARDED_BY(cs_); + + TaskId next_task_id_; + + // The task-queue will sleep when not executing a task. Wake up occurs when: + // * Upon destruction, to make sure that the |thead_| terminates, so that it + // may be joined. [Event will be set.] + // * New task added. Because we optimize for simplicity rahter than for + // performance (this class is a testing facility only), waking up occurs + // when we get a new task even if it is scheduled with a delay. The RunLoop + // is in charge of sending itself back to sleep if the next task is only + // to be executed at a later time. [Event will be set.] + // * When the next task in the queue is a delayed-task, and the time for + // its execution has come. [Event will time-out.] + rtc::Event wake_up_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_SINGLE_THREADED_TASK_QUEUE_H_ diff --git a/third_party/libwebrtc/webrtc/test/single_threaded_task_queue_unittest.cc b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue_unittest.cc new file mode 100644 index 0000000000..5bd40d704a --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/single_threaded_task_queue_unittest.cc @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/single_threaded_task_queue.h" + +#include <atomic> +#include <memory> +#include <vector> + +#include "rtc_base/event.h" +#include "rtc_base/ptr_util.h" +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +namespace { + +using TaskId = SingleThreadedTaskQueueForTesting::TaskId; + +// Test should not rely on the object under test not being faulty. If the task +// queue ever blocks forever, we want the tests to fail, rather than hang. +constexpr int kMaxWaitTimeMs = 10000; + +TEST(SingleThreadedTaskQueueForTestingTest, SanityConstructionDestruction) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); +} + +TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedTasks) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> executed(false); + rtc::Event done(true, false); + + task_queue.PostTask([&executed, &done]() { + executed.store(true); + done.Set(); + }); + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + + EXPECT_TRUE(executed.load()); +} + +TEST(SingleThreadedTaskQueueForTestingTest, + PostMultipleTasksFromSameExternalThread) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + constexpr size_t kCount = 3; + std::atomic<bool> executed[kCount]; + for (std::atomic<bool>& exec : executed) { + exec.store(false); + } + + std::vector<std::unique_ptr<rtc::Event>> done_events; + for (size_t i = 0; i < kCount; i++) { + done_events.emplace_back(rtc::MakeUnique<rtc::Event>(false, false)); + } + + // To avoid the tasks which comprise the actual test from running before they + // have all be posted, which could result in only one task ever being in the + // queue at any given time, post one waiting task that would block the + // task-queue, and unblock only after all tasks have been posted. + rtc::Event rendezvous(true, false); + task_queue.PostTask([&rendezvous]() { + ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); + }); + + // Post the tasks which comprise the test. + for (size_t i = 0; i < kCount; i++) { + task_queue.PostTask([&executed, &done_events, i]() { // |i| by value. + executed[i].store(true); + done_events[i]->Set(); + }); + } + + rendezvous.Set(); // Release the task-queue. + + // Wait until the task queue has executed all the tasks. + for (size_t i = 0; i < kCount; i++) { + ASSERT_TRUE(done_events[i]->Wait(kMaxWaitTimeMs)); + } + + for (size_t i = 0; i < kCount; i++) { + EXPECT_TRUE(executed[i].load()); + } +} + +TEST(SingleThreadedTaskQueueForTestingTest, PostToTaskQueueFromOwnThread) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> executed(false); + rtc::Event done(true, false); + + auto internally_posted_task = [&executed, &done]() { + executed.store(true); + done.Set(); + }; + + auto externally_posted_task = [&task_queue, &internally_posted_task]() { + task_queue.PostTask(internally_posted_task); + }; + + task_queue.PostTask(externally_posted_task); + + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + EXPECT_TRUE(executed.load()); +} + +TEST(SingleThreadedTaskQueueForTestingTest, TasksExecutedInSequence) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + // The first task would perform: + // accumulator = 10 * accumulator + i + // Where |i| is 1, 2 and 3 for the 1st, 2nd and 3rd tasks, respectively. + // The result would be 123 if and only iff the tasks were executed in order. + size_t accumulator = 0; + size_t expected_value = 0; // Updates to the correct value. + + // Prevent the chain from being set in motion before we've had time to + // schedule it all, lest the queue only contain one task at a time. + rtc::Event rendezvous(true, false); + task_queue.PostTask([&rendezvous]() { + ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); + }); + + for (size_t i = 0; i < 3; i++) { + task_queue.PostTask([&accumulator, i]() { // |i| passed by value. + accumulator = 10 * accumulator + i; + }); + expected_value = 10 * expected_value + i; + } + + // The test will wait for the task-queue to finish. + rtc::Event done(true, false); + task_queue.PostTask([&done]() { + done.Set(); + }); + + rendezvous.Set(); // Set the chain in motion. + + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + + EXPECT_EQ(accumulator, expected_value); +} + +TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedDelayedTask) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> executed(false); + rtc::Event done(true, false); + + constexpr int64_t delay_ms = 20; + static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests."); + + task_queue.PostDelayedTask([&executed, &done]() { + executed.store(true); + done.Set(); + }, delay_ms); + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + + EXPECT_TRUE(executed.load()); +} + +TEST(SingleThreadedTaskQueueForTestingTest, DoesNotExecuteDelayedTaskTooSoon) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> executed(false); + + constexpr int64_t delay_ms = 2000; + static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests."); + + task_queue.PostDelayedTask([&executed]() { + executed.store(true); + }, delay_ms); + + // Wait less than is enough, make sure the task was not yet executed. + rtc::Event not_done(true, false); + ASSERT_FALSE(not_done.Wait(delay_ms / 2)); + EXPECT_FALSE(executed.load()); +} + +TEST(SingleThreadedTaskQueueForTestingTest, + TaskWithLesserDelayPostedAfterFirstDelayedTaskExectuedBeforeFirst) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> earlier_executed(false); + constexpr int64_t earlier_delay_ms = 500; + + std::atomic<bool> later_executed(false); + constexpr int64_t later_delay_ms = 1000; + + static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2, + "Delay too long for tests."); + + rtc::Event done(true, false); + + auto earlier_task = [&earlier_executed, &later_executed]() { + EXPECT_FALSE(later_executed.load()); + earlier_executed.store(true); + }; + + auto later_task = [&earlier_executed, &later_executed, &done]() { + EXPECT_TRUE(earlier_executed.load()); + later_executed.store(true); + done.Set(); + }; + + task_queue.PostDelayedTask(later_task, later_delay_ms); + task_queue.PostDelayedTask(earlier_task, earlier_delay_ms); + + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + ASSERT_TRUE(earlier_executed); + ASSERT_TRUE(later_executed); +} + +TEST(SingleThreadedTaskQueueForTestingTest, + TaskWithGreaterDelayPostedAfterFirstDelayedTaskExectuedAfterFirst) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> earlier_executed(false); + constexpr int64_t earlier_delay_ms = 500; + + std::atomic<bool> later_executed(false); + constexpr int64_t later_delay_ms = 1000; + + static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2, + "Delay too long for tests."); + + rtc::Event done(true, false); + + auto earlier_task = [&earlier_executed, &later_executed]() { + EXPECT_FALSE(later_executed.load()); + earlier_executed.store(true); + }; + + auto later_task = [&earlier_executed, &later_executed, &done]() { + EXPECT_TRUE(earlier_executed.load()); + later_executed.store(true); + done.Set(); + }; + + task_queue.PostDelayedTask(earlier_task, earlier_delay_ms); + task_queue.PostDelayedTask(later_task, later_delay_ms); + + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); + ASSERT_TRUE(earlier_executed); + ASSERT_TRUE(later_executed); +} + +TEST(SingleThreadedTaskQueueForTestingTest, ExternalThreadCancelsTask) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + rtc::Event done(true, false); + + // Prevent the to-be-cancelled task from being executed before we've had + // time to cancel it. + rtc::Event rendezvous(true, false); + task_queue.PostTask([&rendezvous]() { + ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); + }); + + TaskId cancelled_task_id = task_queue.PostTask([]() { + EXPECT_TRUE(false); + }); + task_queue.PostTask([&done]() { + done.Set(); + }); + + task_queue.CancelTask(cancelled_task_id); + + // Set the tasks in motion; the cancelled task does not run (otherwise the + // test would fail). The last task ends the test, showing that the queue + // progressed beyond the cancelled task. + rendezvous.Set(); + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); +} + +// In this test, we'll set off a chain where the first task cancels the second +// task, then a third task runs (showing that we really cancelled the task, +// rather than just halted the task-queue). +TEST(SingleThreadedTaskQueueForTestingTest, InternalThreadCancelsTask) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + rtc::Event done(true, false); + + // Prevent the chain from being set-off before we've set everything up. + rtc::Event rendezvous(true, false); + task_queue.PostTask([&rendezvous]() { + ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); + }); + + // This is the canceller-task. It takes cancelled_task_id by reference, + // because the ID will only become known after the cancelled task is + // scheduled. + TaskId cancelled_task_id; + auto canceller_task = [&task_queue, &cancelled_task_id]() { + task_queue.CancelTask(cancelled_task_id); + }; + task_queue.PostTask(canceller_task); + + // This task will be cancelled by the task before it. + auto cancelled_task = []() { + EXPECT_TRUE(false); + }; + cancelled_task_id = task_queue.PostTask(cancelled_task); + + // When this task runs, it will allow the test to be finished. + auto completion_marker_task = [&done]() { + done.Set(); + }; + task_queue.PostTask(completion_marker_task); + + rendezvous.Set(); // Set the chain in motion. + + ASSERT_TRUE(done.Wait(kMaxWaitTimeMs)); +} + +TEST(SingleThreadedTaskQueueForTestingTest, SendTask) { + SingleThreadedTaskQueueForTesting task_queue("task_queue"); + + std::atomic<bool> executed(false); + + task_queue.SendTask([&executed]() { + // Intentionally delay, so that if SendTask didn't block, the sender thread + // would have time to read |executed|. + rtc::Event delay(true, false); + ASSERT_FALSE(delay.Wait(1000)); + executed.store(true); + }); + + EXPECT_TRUE(executed); +} + +TEST(SingleThreadedTaskQueueForTestingTest, + DestructTaskQueueWhileTasksPending) { + auto task_queue = + rtc::MakeUnique<SingleThreadedTaskQueueForTesting>("task_queue"); + + std::atomic<size_t> counter(0); + + constexpr size_t tasks = 10; + for (size_t i = 0; i < tasks; i++) { + task_queue->PostTask([&counter]() { + std::atomic_fetch_add(&counter, static_cast<size_t>(1)); + rtc::Event delay(true, false); + ASSERT_FALSE(delay.Wait(500)); + }); + } + + task_queue.reset(); + + EXPECT_LT(counter, tasks); +} + +} // namespace +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/statistics.cc b/third_party/libwebrtc/webrtc/test/statistics.cc new file mode 100644 index 0000000000..c43dde96fa --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/statistics.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/statistics.h" + +#include <math.h> + +namespace webrtc { +namespace test { + +Statistics::Statistics() : sum_(0.0), sum_squared_(0.0), count_(0) {} + +void Statistics::AddSample(double sample) { + sum_ += sample; + sum_squared_ += sample * sample; + ++count_; +} + +double Statistics::Mean() const { + if (count_ == 0) + return 0.0; + return sum_ / count_; +} + +double Statistics::Variance() const { + if (count_ == 0) + return 0.0; + return sum_squared_ / count_ - Mean() * Mean(); +} + +double Statistics::StandardDeviation() const { + return sqrt(Variance()); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/statistics.h b/third_party/libwebrtc/webrtc/test/statistics.h new file mode 100644 index 0000000000..d52d92dc11 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/statistics.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_STATISTICS_H_ +#define TEST_STATISTICS_H_ + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +class Statistics { + public: + Statistics(); + + void AddSample(double sample); + + double Mean() const; + double Variance() const; + double StandardDeviation() const; + + private: + double sum_; + double sum_squared_; + uint64_t count_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_STATISTICS_H_ diff --git a/third_party/libwebrtc/webrtc/test/test_main.cc b/third_party/libwebrtc/webrtc/test/test_main.cc new file mode 100644 index 0000000000..8bd2ed2244 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/test_main.cc @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/flags.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/metrics_default.h" +#include "test/field_trial.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +#if defined(WEBRTC_IOS) +#include "test/ios/test_support.h" + +DEFINE_string(NSTreatUnknownArgumentsAsOpen, "", + "Intentionally ignored flag intended for iOS simulator."); +DEFINE_string(ApplePersistenceIgnoreState, "", + "Intentionally ignored flag intended for iOS simulator."); +#endif + +DEFINE_bool(logs, false, "print logs to stderr"); + +DEFINE_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."); + +DEFINE_bool(help, false, "Print this message."); + +int main(int argc, char* argv[]) { + ::testing::InitGoogleMock(&argc, argv); + + // Default to LS_INFO, even for release builds to provide better test logging. + // TODO(pbos): Consider adding a command-line override. + if (rtc::LogMessage::GetLogToDebug() > rtc::LS_INFO) + rtc::LogMessage::LogToDebug(rtc::LS_INFO); + + if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, false)) { + return 1; + } + if (FLAG_help) { + rtc::FlagList::Print(nullptr, false); + return 0; + } + + webrtc::test::SetExecutablePath(argv[0]); + std::string fieldtrials = FLAG_force_fieldtrials; + webrtc::test::InitFieldTrialsFromString(fieldtrials); + webrtc::metrics::Enable(); + + rtc::LogMessage::SetLogToStderr(FLAG_logs); +#if defined(WEBRTC_IOS) + rtc::test::InitTestSuite(RUN_ALL_TESTS, argc, argv); + rtc::test::RunTestsFromIOSApp(); +#endif + + return RUN_ALL_TESTS(); +} diff --git a/third_party/libwebrtc/webrtc/test/testsupport/always_passing_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/always_passing_unittest.cc new file mode 100644 index 0000000000..e6318f7e0b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/always_passing_unittest.cc @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/gtest.h" + +namespace webrtc { + +// A test that always passes. Useful when all tests in a executable are +// disabled, since a gtest returns exit code 1 if no tests have executed. +TEST(AlwaysPassingTest, AlwaysPassingTest) {} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/fileutils.cc b/third_party/libwebrtc/webrtc/test/testsupport/fileutils.cc new file mode 100644 index 0000000000..2aff75a4d9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/fileutils.cc @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/fileutils.h" + +#include <assert.h> + +#ifdef WIN32 +#include <direct.h> +#include <tchar.h> +#include <windows.h> +#include <algorithm> + +#include "Shlwapi.h" +#include "WinDef.h" + +#include "rtc_base/win32.h" +#define GET_CURRENT_DIR _getcwd +#else +#include <dirent.h> +#include <unistd.h> + +#define GET_CURRENT_DIR getcwd +#endif + +#include <sys/stat.h> // To check for directory existence. +#ifndef S_ISDIR // Not defined in stat.h on Windows. +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <memory> +#include <utility> + +#include "rtc_base/checks.h" +#include "typedefs.h" // NOLINT(build/include) // For architecture defines + +namespace webrtc { +namespace test { + +#if defined(WEBRTC_IOS) +// Defined in iosfileutils.mm. No header file to discourage use elsewhere. +std::string IOSOutputPath(); +std::string IOSRootPath(); +std::string IOSResourcePath(std::string name, std::string extension); +#endif + +namespace { + +#ifdef WIN32 +const char* kPathDelimiter = "\\"; +#else +const char* kPathDelimiter = "/"; +#endif + +#ifdef WEBRTC_ANDROID +const char* kRootDirName = "/sdcard/chromium_tests_root/"; +#else +#if !defined(WEBRTC_IOS) +const char* kOutputDirName = "out"; +#endif +const char* kFallbackPath = "./"; +#endif // !defined(WEBRTC_ANDROID) + +#if !defined(WEBRTC_IOS) +const char* kResourcesDirName = "resources"; +#endif + +char relative_dir_path[FILENAME_MAX]; +bool relative_dir_path_set = false; + +} // namespace + +const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR"; + +void SetExecutablePath(const std::string& path) { + std::string working_dir = WorkingDir(); + std::string temp_path = path; + + // Handle absolute paths; convert them to relative paths to the working dir. + if (path.find(working_dir) != std::string::npos) { + temp_path = path.substr(working_dir.length() + 1); + } + // On Windows, when tests are run under memory tools like DrMemory and TSan, + // slashes occur in the path as directory separators. Make sure we replace + // such cases with backslashes in order for the paths to be correct. +#ifdef WIN32 + std::replace(temp_path.begin(), temp_path.end(), '/', '\\'); +#endif + + // Trim away the executable name; only store the relative dir path. + temp_path = temp_path.substr(0, temp_path.find_last_of(kPathDelimiter)); + strncpy(relative_dir_path, temp_path.c_str(), FILENAME_MAX); + relative_dir_path_set = true; +} + +bool FileExists(const std::string& file_name) { + struct stat file_info = {0}; + return stat(file_name.c_str(), &file_info) == 0; +} + +bool DirExists(const std::string& directory_name) { + struct stat directory_info = {0}; + return stat(directory_name.c_str(), &directory_info) == 0 && S_ISDIR( + directory_info.st_mode); +} + +#ifdef WEBRTC_ANDROID + +std::string ProjectRootPath() { + return kRootDirName; +} + +std::string OutputPath() { + return kRootDirName; +} + +std::string WorkingDir() { + return kRootDirName; +} + +#else // WEBRTC_ANDROID + +std::string ProjectRootPath() { +#if defined(WEBRTC_IOS) + return IOSRootPath(); +#else + std::string path = WorkingDir(); + if (path == kFallbackPath) { + return kCannotFindProjectRootDir; + } + if (relative_dir_path_set) { + path = path + kPathDelimiter + relative_dir_path; + } + path = path + kPathDelimiter + ".." + kPathDelimiter + ".."; + char canonical_path[FILENAME_MAX]; +#ifdef WIN32 + BOOL succeeded = PathCanonicalizeA(canonical_path, path.c_str()); +#else + bool succeeded = realpath(path.c_str(), canonical_path) != NULL; +#endif + if (succeeded) { + path = std::string(canonical_path) + kPathDelimiter; + return path; + } else { + fprintf(stderr, "Cannot find project root directory!\n"); + return kCannotFindProjectRootDir; + } +#endif +} + +std::string OutputPath() { +#if defined(WEBRTC_IOS) + return IOSOutputPath(); +#else + std::string path = ProjectRootPath(); + if (path == kCannotFindProjectRootDir) { + return kFallbackPath; + } + path += kOutputDirName; + if (!CreateDir(path)) { + return kFallbackPath; + } + return path + kPathDelimiter; +#endif +} + +std::string WorkingDir() { + char path_buffer[FILENAME_MAX]; + if (!GET_CURRENT_DIR(path_buffer, sizeof(path_buffer))) { + fprintf(stderr, "Cannot get current directory!\n"); + return kFallbackPath; + } else { + return std::string(path_buffer); + } +} + +#endif // !WEBRTC_ANDROID + +// Generate a temporary filename in a safe way. +// Largely copied from talk/base/{unixfilesystem,win32filesystem}.cc. +std::string TempFilename(const std::string &dir, const std::string &prefix) { +#ifdef WIN32 + wchar_t filename[MAX_PATH]; + if (::GetTempFileName(rtc::ToUtf16(dir).c_str(), + rtc::ToUtf16(prefix).c_str(), 0, filename) != 0) + return rtc::ToUtf8(filename); + assert(false); + return ""; +#else + int len = dir.size() + prefix.size() + 2 + 6; + std::unique_ptr<char[]> tempname(new char[len]); + + snprintf(tempname.get(), len, "%s/%sXXXXXX", dir.c_str(), + prefix.c_str()); + int fd = ::mkstemp(tempname.get()); + if (fd == -1) { + assert(false); + return ""; + } else { + ::close(fd); + } + std::string ret(tempname.get()); + return ret; +#endif +} + +rtc::Optional<std::vector<std::string>> ReadDirectory(std::string path) { + if (path.length() == 0) + return rtc::Optional<std::vector<std::string>>(); + +#if defined(WEBRTC_WIN) + // Append separator character if needed. + if (path.back() != '\\') + path += '\\'; + + // Init. + WIN32_FIND_DATA data; + HANDLE handle = ::FindFirstFile(rtc::ToUtf16(path + '*').c_str(), &data); + if (handle == INVALID_HANDLE_VALUE) + return rtc::Optional<std::vector<std::string>>(); + + // Populate output. + std::vector<std::string> found_entries; + do { + const std::string name = rtc::ToUtf8(data.cFileName); + if (name != "." && name != "..") + found_entries.emplace_back(path + name); + } while (::FindNextFile(handle, &data) == TRUE); + + // Release resources. + if (handle != INVALID_HANDLE_VALUE) + ::FindClose(handle); +#else + // Append separator character if needed. + if (path.back() != '/') + path += '/'; + + // Init. + DIR* dir = ::opendir(path.c_str()); + if (dir == nullptr) + return rtc::Optional<std::vector<std::string>>(); + + // Populate output. + std::vector<std::string> found_entries; + while (dirent* dirent = readdir(dir)) { + const std::string& name = dirent->d_name; + if (name != "." && name != "..") + found_entries.emplace_back(path + name); + } + + // Release resources. + closedir(dir); +#endif + + return rtc::Optional<std::vector<std::string>>(std::move(found_entries)); +} + +bool CreateDir(const std::string& directory_name) { + struct stat path_info = {0}; + // Check if the path exists already: + if (stat(directory_name.c_str(), &path_info) == 0) { + if (!S_ISDIR(path_info.st_mode)) { + fprintf(stderr, "Path %s exists but is not a directory! Remove this " + "file and re-run to create the directory.\n", + directory_name.c_str()); + return false; + } + } else { +#ifdef WIN32 + return _mkdir(directory_name.c_str()) == 0; +#else + return mkdir(directory_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0; +#endif + } + return true; +} + +bool RemoveDir(const std::string& directory_name) { +#ifdef WIN32 + return RemoveDirectoryA(directory_name.c_str()) != FALSE; +#else + return rmdir(directory_name.c_str()) == 0; +#endif +} + +bool RemoveFile(const std::string& file_name) { +#ifdef WIN32 + return DeleteFileA(file_name.c_str()) != FALSE; +#else + return unlink(file_name.c_str()) == 0; +#endif +} + +std::string ResourcePath(const std::string& name, + const std::string& extension) { +#if defined(WEBRTC_IOS) + return IOSResourcePath(name, extension); +#else + std::string platform = "win"; +#ifdef WEBRTC_LINUX + platform = "linux"; +#endif // WEBRTC_LINUX +#ifdef WEBRTC_MAC + platform = "mac"; +#endif // WEBRTC_MAC +#ifdef WEBRTC_ANDROID + platform = "android"; +#endif // WEBRTC_ANDROID + +#ifdef WEBRTC_ARCH_64_BITS + std::string architecture = "64"; +#else + std::string architecture = "32"; +#endif // WEBRTC_ARCH_64_BITS + + std::string resources_path = ProjectRootPath() + kResourcesDirName + + kPathDelimiter; + std::string resource_file = resources_path + name + "_" + platform + "_" + + architecture + "." + extension; + if (FileExists(resource_file)) { + return resource_file; + } + // Try without architecture. + resource_file = resources_path + name + "_" + platform + "." + extension; + if (FileExists(resource_file)) { + return resource_file; + } + // Try without platform. + resource_file = resources_path + name + "_" + architecture + "." + extension; + if (FileExists(resource_file)) { + return resource_file; + } + + // Fall back on name without architecture or platform. + return resources_path + name + "." + extension; +#endif // defined (WEBRTC_IOS) +} + +size_t GetFileSize(const std::string& filename) { + FILE* f = fopen(filename.c_str(), "rb"); + size_t size = 0; + if (f != NULL) { + if (fseek(f, 0, SEEK_END) == 0) { + size = ftell(f); + } + fclose(f); + } + return size; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/fileutils.h b/third_party/libwebrtc/webrtc/test/testsupport/fileutils.h new file mode 100644 index 0000000000..f0560cf979 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/fileutils.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdio.h> + +#ifndef TEST_TESTSUPPORT_FILEUTILS_H_ +#define TEST_TESTSUPPORT_FILEUTILS_H_ + +#include <string> +#include <vector> + +#include "api/optional.h" + +namespace webrtc { +namespace test { + +// This is the "directory" returned if the ProjectPath() function fails +// to find the project root. +extern const char* kCannotFindProjectRootDir; + +// Creates and returns the absolute path to the output directory where log files +// and other test artifacts should be put. The output directory is generally a +// directory named "out" at the top-level of the project, i.e. a subfolder to +// the path returned by ProjectRootPath(). The exception is Android where we use +// /sdcard/ instead. +// +// If symbolic links occur in the path they will be resolved and the actual +// directory will be returned. +// +// Returns the path WITH a trailing path delimiter. If the project root is not +// found, the current working directory ("./") is returned as a fallback. +std::string OutputPath(); + +// Generates an empty file with a unique name in the specified directory and +// returns the file name and path. +std::string TempFilename(const std::string &dir, const std::string &prefix); + +// Returns a path to a resource file for the currently executing platform. +// Adapts to what filenames are currently present in the +// [project-root]/resources/ dir. +// Returns an absolute path according to this priority list (the directory +// part of the path is left out for readability): +// 1. [name]_[platform]_[architecture].[extension] +// 2. [name]_[platform].[extension] +// 3. [name]_[architecture].[extension] +// 4. [name].[extension] +// Where +// * platform is either of "win", "mac" or "linux". +// * architecture is either of "32" or "64". +// +// Arguments: +// name - Name of the resource file. If a plain filename (no directory path) +// is supplied, the file is assumed to be located in resources/ +// If a directory path is prepended to the filename, a subdirectory +// hierarchy reflecting that path is assumed to be present. +// extension - File extension, without the dot, i.e. "bmp" or "yuv". +std::string ResourcePath(const std::string& name, + const std::string& extension); + +// Gets the current working directory for the executing program. +// Returns "./" if for some reason it is not possible to find the working +// directory. +std::string WorkingDir(); + +// Reads the content of a directory and, in case of success, returns a vector +// of strings with one element for each found file or directory. Each element is +// a path created by prepending |dir| to the file/directory name. "." and ".." +// are never added in the returned vector. +rtc::Optional<std::vector<std::string>> ReadDirectory(std::string path); + +// Creates a directory if it not already exists. +// Returns true if successful. Will print an error message to stderr and return +// false if a file with the same name already exists. +bool CreateDir(const std::string& directory_name); + +// Removes a directory, which must already be empty. +bool RemoveDir(const std::string& directory_name); + +// Removes a file. +bool RemoveFile(const std::string& file_name); + +// Checks if a file exists. +bool FileExists(const std::string& file_name); + +// Checks if a directory exists. +bool DirExists(const std::string& directory_name); + +// File size of the supplied file in bytes. Will return 0 if the file is +// empty or if the file does not exist/is readable. +size_t GetFileSize(const std::string& filename); + +// Sets the executable path, i.e. the path to the executable that is being used +// when launching it. This is usually the path relative to the working directory +// but can also be an absolute path. The intention with this function is to pass +// the argv[0] being sent into the main function to make it possible for +// fileutils.h to find the correct project paths even when the working directory +// is outside the project tree (which happens in some cases). +void SetExecutablePath(const std::string& path_to_executable); + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_FILEUTILS_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/fileutils_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/fileutils_unittest.cc new file mode 100644 index 0000000000..79988c0dd3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/fileutils_unittest.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/fileutils.h" + +#include <stdio.h> + +#include <fstream> +#include <iostream> +#include <list> +#include <string> + +#include "api/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/pathutils.h" +#include "test/gtest.h" + +#ifdef WIN32 +#define chdir _chdir +static const char* kPathDelimiter = "\\"; +#else +static const char* kPathDelimiter = "/"; +#endif + +static const char kTestName[] = "fileutils_unittest"; +static const char kExtension[] = "tmp"; + +namespace webrtc { +namespace test { + +namespace { + +// Remove files and directories in a directory non-recursively and writes the +// number of deleted items in |num_deleted_entries|. +void CleanDir(const std::string& dir, size_t* num_deleted_entries) { + RTC_DCHECK(num_deleted_entries); + *num_deleted_entries = 0; + rtc::Optional<std::vector<std::string>> dir_content = ReadDirectory(dir); + EXPECT_TRUE(dir_content); + for (const auto& entry : *dir_content) { + if (DirExists(entry)) { + EXPECT_TRUE(RemoveDir(entry)); + (*num_deleted_entries)++; + } else if (FileExists(entry)) { + EXPECT_TRUE(RemoveFile(entry)); + (*num_deleted_entries)++; + } else { + FAIL(); + } + } +} + +void WriteStringInFile(const std::string& what, const std::string& file_path) { + std::ofstream out(file_path); + out << what; + out.close(); +} + +} // namespace + +// Test fixture to restore the working directory between each test, since some +// of them change it with chdir during execution (not restored by the +// gtest framework). +class FileUtilsTest : public testing::Test { + protected: + FileUtilsTest() { + } + ~FileUtilsTest() override {} + // Runs before the first test + static void SetUpTestCase() { + original_working_dir_ = webrtc::test::WorkingDir(); + } + void SetUp() override { + ASSERT_EQ(chdir(original_working_dir_.c_str()), 0); + } + void TearDown() override { + ASSERT_EQ(chdir(original_working_dir_.c_str()), 0); + } + private: + static std::string original_working_dir_; +}; + +std::string FileUtilsTest::original_working_dir_ = ""; + +// Tests that the project output dir path is returned for the default working +// directory that is automatically set when the test executable is launched. +// The test is not fully testing the implementation, since we cannot be sure +// of where the executable was launched from. +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) +#define MAYBE_OutputPathFromUnchangedWorkingDir \ + DISABLED_OutputPathFromUnchangedWorkingDir +#else +#define MAYBE_OutputPathFromUnchangedWorkingDir \ + OutputPathFromUnchangedWorkingDir +#endif +TEST_F(FileUtilsTest, MAYBE_OutputPathFromUnchangedWorkingDir) { + std::string path = webrtc::test::OutputPath(); + std::string expected_end = "out"; + expected_end = kPathDelimiter + expected_end + kPathDelimiter; + ASSERT_EQ(path.length() - expected_end.length(), path.find(expected_end)); +} + +// Tests with current working directory set to a directory higher up in the +// directory tree than the project root dir. +#if defined(WEBRTC_ANDROID) || defined(WIN32) || defined(WEBRTC_IOS) +#define MAYBE_OutputPathFromRootWorkingDir DISABLED_OutputPathFromRootWorkingDir +#else +#define MAYBE_OutputPathFromRootWorkingDir OutputPathFromRootWorkingDir +#endif +TEST_F(FileUtilsTest, MAYBE_OutputPathFromRootWorkingDir) { + ASSERT_EQ(0, chdir(kPathDelimiter)); + ASSERT_EQ("./", webrtc::test::OutputPath()); +} + +TEST_F(FileUtilsTest, TempFilename) { + std::string temp_filename = webrtc::test::TempFilename( + webrtc::test::OutputPath(), "TempFilenameTest"); + ASSERT_TRUE(webrtc::test::FileExists(temp_filename)) + << "Couldn't find file: " << temp_filename; + remove(temp_filename.c_str()); +} + +// Only tests that the code executes +#if defined(WEBRTC_IOS) +#define MAYBE_CreateDir DISABLED_CreateDir +#else +#define MAYBE_CreateDir CreateDir +#endif +TEST_F(FileUtilsTest, MAYBE_CreateDir) { + std::string directory = "fileutils-unittest-empty-dir"; + // Make sure it's removed if a previous test has failed: + remove(directory.c_str()); + ASSERT_TRUE(webrtc::test::CreateDir(directory)); + remove(directory.c_str()); +} + +TEST_F(FileUtilsTest, WorkingDirReturnsValue) { + // Hard to cover all platforms. Just test that it returns something without + // crashing: + std::string working_dir = webrtc::test::WorkingDir(); + ASSERT_GT(working_dir.length(), 0u); +} + +// Due to multiple platforms, it is hard to make a complete test for +// ResourcePath. Manual testing has been performed by removing files and +// verified the result confirms with the specified documentation for the +// function. +TEST_F(FileUtilsTest, ResourcePathReturnsValue) { + std::string resource = webrtc::test::ResourcePath(kTestName, kExtension); + ASSERT_GT(resource.find(kTestName), 0u); + ASSERT_GT(resource.find(kExtension), 0u); +} + +TEST_F(FileUtilsTest, ResourcePathFromRootWorkingDir) { + ASSERT_EQ(0, chdir(kPathDelimiter)); + std::string resource = webrtc::test::ResourcePath(kTestName, kExtension); +#if !defined(WEBRTC_IOS) + ASSERT_NE(resource.find("resources"), std::string::npos); +#endif + ASSERT_GT(resource.find(kTestName), 0u); + ASSERT_GT(resource.find(kExtension), 0u); +} + +TEST_F(FileUtilsTest, GetFileSizeExistingFile) { + // Create a file with some dummy data in. + std::string temp_filename = webrtc::test::TempFilename( + webrtc::test::OutputPath(), "fileutils_unittest"); + FILE* file = fopen(temp_filename.c_str(), "wb"); + ASSERT_TRUE(file != NULL) << "Failed to open file: " << temp_filename; + ASSERT_GT(fprintf(file, "%s", "Dummy data"), 0) << + "Failed to write to file: " << temp_filename; + fclose(file); + ASSERT_GT(webrtc::test::GetFileSize(std::string(temp_filename.c_str())), 0u); + remove(temp_filename.c_str()); +} + +TEST_F(FileUtilsTest, GetFileSizeNonExistingFile) { + ASSERT_EQ(0u, webrtc::test::GetFileSize("non-existing-file.tmp")); +} + +TEST_F(FileUtilsTest, DirExists) { + // Check that an existing directory is recognized as such. + ASSERT_TRUE(webrtc::test::DirExists(webrtc::test::OutputPath())) + << "Existing directory not found"; + + // Check that a non-existing directory is recognized as such. + std::string directory = "direxists-unittest-non_existing-dir"; + ASSERT_FALSE(webrtc::test::DirExists(directory)) + << "Non-existing directory found"; + + // Check that an existing file is not recognized as an existing directory. + std::string temp_filename = webrtc::test::TempFilename( + webrtc::test::OutputPath(), "TempFilenameTest"); + ASSERT_TRUE(webrtc::test::FileExists(temp_filename)) + << "Couldn't find file: " << temp_filename; + ASSERT_FALSE(webrtc::test::DirExists(temp_filename)) + << "Existing file recognized as existing directory"; + remove(temp_filename.c_str()); +} + +TEST_F(FileUtilsTest, WriteReadDeleteFilesAndDirs) { + size_t num_deleted_entries; + + // Create an empty temporary directory for this test. + const std::string temp_directory = + OutputPath() + "TempFileUtilsTestReadDirectory" + kPathDelimiter; + CreateDir(temp_directory); + EXPECT_NO_FATAL_FAILURE(CleanDir(temp_directory, &num_deleted_entries)); + EXPECT_TRUE(DirExists(temp_directory)); + + // Add a file. + const std::string temp_filename = temp_directory + "TempFilenameTest"; + WriteStringInFile("test\n", temp_filename); + EXPECT_TRUE(FileExists(temp_filename)); + + // Add an empty directory. + const std::string temp_subdir = temp_directory + "subdir" + kPathDelimiter; + EXPECT_TRUE(CreateDir(temp_subdir)); + EXPECT_TRUE(DirExists(temp_subdir)); + + // Checks. + rtc::Optional<std::vector<std::string>> dir_content = + ReadDirectory(temp_directory); + EXPECT_TRUE(dir_content); + EXPECT_EQ(2u, dir_content->size()); + EXPECT_NO_FATAL_FAILURE(CleanDir(temp_directory, &num_deleted_entries)); + EXPECT_EQ(2u, num_deleted_entries); + EXPECT_TRUE(RemoveDir(temp_directory)); + EXPECT_FALSE(DirExists(temp_directory)); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/frame_reader.h b/third_party/libwebrtc/webrtc/test/testsupport/frame_reader.h new file mode 100644 index 0000000000..2e19af344e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/frame_reader.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_FRAME_READER_H_ +#define TEST_TESTSUPPORT_FRAME_READER_H_ + +#include <stdio.h> + +#include <string> + +#include "rtc_base/scoped_ref_ptr.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +class I420Buffer; +namespace test { + +// Handles reading of I420 frames from video files. +class FrameReader { + public: + virtual ~FrameReader() {} + + // Initializes the frame reader, i.e. opens the input file. + // This must be called before reading of frames has started. + // Returns false if an error has occurred, in addition to printing to stderr. + virtual bool Init() = 0; + + // Reads a frame from the input file. On success, returns the frame. + // Returns nullptr if encountering end of file or a read error. + virtual rtc::scoped_refptr<I420Buffer> ReadFrame() = 0; + + // Closes the input file if open. Essentially makes this class impossible + // to use anymore. Will also be invoked by the destructor. + virtual void Close() = 0; + + // Frame length in bytes of a single frame image. + virtual size_t FrameLength() = 0; + // Total number of frames in the input video source. + virtual int NumberOfFrames() = 0; +}; + +class YuvFrameReaderImpl : public FrameReader { + public: + // Creates a file handler. The input file is assumed to exist and be readable. + // Parameters: + // input_filename The file to read from. + // width, height Size of each frame to read. + YuvFrameReaderImpl(std::string input_filename, int width, int height); + ~YuvFrameReaderImpl() override; + bool Init() override; + rtc::scoped_refptr<I420Buffer> ReadFrame() override; + void Close() override; + size_t FrameLength() override; + int NumberOfFrames() override; + + private: + const std::string input_filename_; + size_t frame_length_in_bytes_; + const int width_; + const int height_; + int number_of_frames_; + FILE* input_file_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_FRAME_READER_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/frame_writer.h b/third_party/libwebrtc/webrtc/test/testsupport/frame_writer.h new file mode 100644 index 0000000000..7556050a21 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/frame_writer.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_FRAME_WRITER_H_ +#define TEST_TESTSUPPORT_FRAME_WRITER_H_ + +#include <stdio.h> + +#include <string> + +#include "api/video/video_frame.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +// Handles writing of video files. +class FrameWriter { + public: + virtual ~FrameWriter() {} + + // Initializes the file handler, i.e. opens the input and output files etc. + // This must be called before reading or writing frames has started. + // Returns false if an error has occurred, in addition to printing to stderr. + virtual bool Init() = 0; + + // Writes a frame of the configured frame length to the output file. + // Returns true if the write was successful, false otherwise. + virtual bool WriteFrame(uint8_t* frame_buffer) = 0; + + // Closes the output file if open. Essentially makes this class impossible + // to use anymore. Will also be invoked by the destructor. + virtual void Close() = 0; + + // Frame length in bytes of a single frame image. + virtual size_t FrameLength() = 0; +}; + +// Writes raw I420 frames in sequence. +class YuvFrameWriterImpl : public FrameWriter { + public: + // Creates a file handler. The input file is assumed to exist and be readable + // and the output file must be writable. + // Parameters: + // output_filename The file to write. Will be overwritten if already + // existing. + // width, height Size of each frame to read. + YuvFrameWriterImpl(std::string output_filename, int width, int height); + ~YuvFrameWriterImpl() override; + bool Init() override; + bool WriteFrame(uint8_t* frame_buffer) override; + void Close() override; + size_t FrameLength() override; + + protected: + const std::string output_filename_; + size_t frame_length_in_bytes_; + const int width_; + const int height_; + FILE* output_file_; +}; + +// Writes raw I420 frames in sequence, but with Y4M file and frame headers for +// more convenient playback in external media players. +class Y4mFrameWriterImpl : public YuvFrameWriterImpl { + public: + Y4mFrameWriterImpl(std::string output_filename, + int width, + int height, + int frame_rate); + ~Y4mFrameWriterImpl() override; + bool Init() override; + bool WriteFrame(uint8_t* frame_buffer) override; + + private: + const int frame_rate_; +}; + +// LibJpeg is not available on iOS. This class will do nothing on iOS. +class JpegFrameWriter { + public: + JpegFrameWriter(const std::string &output_filename); + // Quality can be from 0 (worst) to 100 (best). Best quality is still lossy. + // WriteFrame can be called only once. Subsequent calls will fail. + bool WriteFrame(const VideoFrame& input_frame, int quality); + +#if !defined(WEBRTC_IOS) + private: + bool frame_written_; + const std::string output_filename_; + FILE* output_file_; +#endif +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_FRAME_WRITER_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/iosfileutils.mm b/third_party/libwebrtc/webrtc/test/testsupport/iosfileutils.mm new file mode 100644 index 0000000000..a9156db656 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/iosfileutils.mm @@ -0,0 +1,63 @@ +/* + * Copyright 2015 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(WEBRTC_IOS) + +#import <Foundation/Foundation.h> +#include <string.h> + +#include "rtc_base/checks.h" +#include "sdk/objc/Framework/Classes/Common/helpers.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +using webrtc::ios::NSStringFromStdString; +using webrtc::ios::StdStringFromNSString; + +// For iOS, resource files are added to the application bundle in the root +// and not in separate folders as is the case for other platforms. This method +// therefore removes any prepended folders and uses only the actual file name. +std::string IOSResourcePath(std::string name, std::string extension) { + @autoreleasepool { + NSString* path = NSStringFromStdString(name); + NSString* fileName = path.lastPathComponent; + NSString* fileType = NSStringFromStdString(extension); + // Get full pathname for the resource identified by the name and extension. + NSString* pathString = [[NSBundle mainBundle] pathForResource:fileName + ofType:fileType]; + return StdStringFromNSString(pathString); + } +} + +std::string IOSRootPath() { + @autoreleasepool { + NSBundle* mainBundle = [NSBundle mainBundle]; + return StdStringFromNSString(mainBundle.bundlePath) + "/"; + } +} + +// For iOS, we don't have access to the output directory. Return the path to the +// temporary directory instead. This is mostly used by tests that need to write +// output files to disk. +std::string IOSOutputPath() { + @autoreleasepool { + NSString* tempDir = NSTemporaryDirectory(); + if (tempDir == nil) + tempDir = @"/tmp"; + return StdStringFromNSString(tempDir); + } +} + +} // namespace test +} // namespace webrtc + +#endif // defined(WEBRTC_IOS) diff --git a/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer.cc b/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer.cc new file mode 100644 index 0000000000..4888f65aeb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer.cc @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdio.h> + + +#include "common_types.h" // NOLINT(build/include) +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "test/testsupport/frame_writer.h" + +extern "C" { +#if defined(USE_SYSTEM_LIBJPEG) +#include <jpeglib.h> +#else +// Include directory supplied by gn +#include "jpeglib.h" // NOLINT +#endif +} + +namespace webrtc { +namespace test { + +JpegFrameWriter::JpegFrameWriter(const std::string &output_filename) + : frame_written_(false), + output_filename_(output_filename), + output_file_(nullptr) {} + +bool JpegFrameWriter::WriteFrame(const VideoFrame& input_frame, int quality) { + if (frame_written_) { + RTC_LOG(LS_ERROR) << "Only a single frame can be saved to Jpeg."; + return false; + } + const int kColorPlanes = 3; // R, G and B. + size_t rgb_len = input_frame.height() * input_frame.width() * kColorPlanes; + std::unique_ptr<uint8_t[]> rgb_buf(new uint8_t[rgb_len]); + + // kRGB24 actually corresponds to FourCC 24BG which is 24-bit BGR. + if (ConvertFromI420(input_frame, VideoType::kRGB24, 0, rgb_buf.get()) < 0) { + RTC_LOG(LS_ERROR) << "Could not convert input frame to RGB."; + return false; + } + output_file_ = fopen(output_filename_.c_str(), "wb"); + if (!output_file_) { + RTC_LOG(LS_ERROR) << "Couldn't open file to write jpeg frame to:" + << output_filename_; + return false; + } + + // Invoking LIBJPEG + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer[1]; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + jpeg_stdio_dest(&cinfo, output_file_); + + cinfo.image_width = input_frame.width(); + cinfo.image_height = input_frame.height(); + cinfo.input_components = kColorPlanes; + cinfo.in_color_space = JCS_EXT_BGR; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + + jpeg_start_compress(&cinfo, TRUE); + int row_stride = input_frame.width() * kColorPlanes; + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = &rgb_buf.get()[cinfo.next_scanline * row_stride]; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + fclose(output_file_); + + frame_written_ = true; + return true; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer_ios.cc b/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer_ios.cc new file mode 100644 index 0000000000..567e75e254 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/jpeg_frame_writer_ios.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "test/testsupport/frame_writer.h" + + +namespace webrtc { +namespace test { + +JpegFrameWriter::JpegFrameWriter(const std::string& /*output_filename*/) {} + +bool JpegFrameWriter::WriteFrame(const VideoFrame& /*input_frame*/, + int /*quality*/) { + RTC_LOG(LS_WARNING) + << "Libjpeg isn't available on IOS. Jpeg frame writer is not " + "supported. No frame will be saved."; + // Don't fail. + return true; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.cc b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.cc new file mode 100644 index 0000000000..ea5d3f2b5f --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/metrics/video_metrics.h" + +#include <assert.h> +#include <stdio.h> + +#include <algorithm> // min_element, max_element +#include <memory> + +#include "api/video/i420_buffer.h" +#include "api/video/video_frame.h" +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "test/frame_utils.h" +#include "libyuv/convert.h" + +namespace webrtc { +namespace test { + +// Copy here so our callers won't need to include libyuv for this constant. +double kMetricsPerfectPSNR = kPerfectPSNR; + +// Used for calculating min and max values. +static bool LessForFrameResultValue(const FrameResult& s1, + const FrameResult& s2) { + return s1.value < s2.value; +} + +enum VideoMetricsType { kPSNR, kSSIM, kBoth }; + +// Calculates metrics for a frame and adds statistics to the result for it. +void CalculateFrame(VideoMetricsType video_metrics_type, + const I420BufferInterface& ref, + const I420BufferInterface& test, + int frame_number, + QualityMetricsResult* result) { + FrameResult frame_result = {0, 0}; + frame_result.frame_number = frame_number; + switch (video_metrics_type) { + case kPSNR: + frame_result.value = I420PSNR(ref, test); + break; + case kSSIM: + frame_result.value = I420SSIM(ref, test); + break; + default: + assert(false); + } + result->frames.push_back(frame_result); +} + +// Calculates average, min and max values for the supplied struct, if non-NULL. +void CalculateStats(QualityMetricsResult* result) { + if (result == NULL || result->frames.size() == 0) { + return; + } + // Calculate average. + std::vector<FrameResult>::iterator iter; + double metrics_values_sum = 0.0; + for (iter = result->frames.begin(); iter != result->frames.end(); ++iter) { + metrics_values_sum += iter->value; + } + result->average = metrics_values_sum / result->frames.size(); + + // Calculate min/max statistics. + iter = std::min_element(result->frames.begin(), result->frames.end(), + LessForFrameResultValue); + result->min = iter->value; + result->min_frame_number = iter->frame_number; + iter = std::max_element(result->frames.begin(), result->frames.end(), + LessForFrameResultValue); + result->max = iter->value; + result->max_frame_number = iter->frame_number; +} + +// Single method that handles all combinations of video metrics calculation, to +// minimize code duplication. Either psnr_result or ssim_result may be NULL, +// depending on which VideoMetricsType is targeted. +int CalculateMetrics(VideoMetricsType video_metrics_type, + const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* psnr_result, + QualityMetricsResult* ssim_result) { + assert(ref_filename != NULL); + assert(test_filename != NULL); + assert(width > 0); + assert(height > 0); + + FILE* ref_fp = fopen(ref_filename, "rb"); + if (ref_fp == NULL) { + // Cannot open reference file. + fprintf(stderr, "Cannot open file %s\n", ref_filename); + return -1; + } + FILE* test_fp = fopen(test_filename, "rb"); + if (test_fp == NULL) { + // Cannot open test file. + fprintf(stderr, "Cannot open file %s\n", test_filename); + fclose(ref_fp); + return -2; + } + int frame_number = 0; + + // Read reference and test frames. + for (;;) { + rtc::scoped_refptr<I420Buffer> ref_i420_buffer( + test::ReadI420Buffer(width, height, ref_fp)); + if (!ref_i420_buffer) + break; + + rtc::scoped_refptr<I420Buffer> test_i420_buffer( + test::ReadI420Buffer(width, height, test_fp)); + + if (!test_i420_buffer) + break; + + switch (video_metrics_type) { + case kPSNR: + CalculateFrame(kPSNR, *ref_i420_buffer, *test_i420_buffer, frame_number, + psnr_result); + break; + case kSSIM: + CalculateFrame(kSSIM, *ref_i420_buffer, *test_i420_buffer, frame_number, + ssim_result); + break; + case kBoth: + CalculateFrame(kPSNR, *ref_i420_buffer, *test_i420_buffer, frame_number, + psnr_result); + CalculateFrame(kSSIM, *ref_i420_buffer, *test_i420_buffer, frame_number, + ssim_result); + break; + } + frame_number++; + } + int return_code = 0; + if (frame_number == 0) { + fprintf(stderr, "Tried to measure video metrics from empty files " + "(reference file: %s test file: %s)\n", ref_filename, + test_filename); + return_code = -3; + } else { + CalculateStats(psnr_result); + CalculateStats(ssim_result); + } + fclose(ref_fp); + fclose(test_fp); + return return_code; +} + +int I420MetricsFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* psnr_result, + QualityMetricsResult* ssim_result) { + assert(psnr_result != NULL); + assert(ssim_result != NULL); + return CalculateMetrics(kBoth, ref_filename, test_filename, width, height, + psnr_result, ssim_result); +} + +int I420PSNRFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* result) { + assert(result != NULL); + return CalculateMetrics(kPSNR, ref_filename, test_filename, width, height, + result, NULL); +} + +int I420SSIMFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* result) { + assert(result != NULL); + return CalculateMetrics(kSSIM, ref_filename, test_filename, width, height, + NULL, result); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.h b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.h new file mode 100644 index 0000000000..f72ea9b7bb --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TESTSUPPORT_METRICS_VIDEO_METRICS_H_ +#define TESTSUPPORT_METRICS_VIDEO_METRICS_H_ + +#include <limits> +#include <vector> + +namespace webrtc { +namespace test { + +// The highest PSNR value our algorithms will return. +extern double kMetricsPerfectPSNR; + +// Contains video quality metrics result for a single frame. +struct FrameResult { + int frame_number; + double value; +}; + +// Result from a PSNR/SSIM calculation operation. +// The frames in this data structure are 0-indexed. +struct QualityMetricsResult { + QualityMetricsResult() : + average(0.0), + min(std::numeric_limits<double>::max()), + max(std::numeric_limits<double>::min()), + min_frame_number(-1), + max_frame_number(-1) + {}; + double average; + double min; + double max; + int min_frame_number; + int max_frame_number; + std::vector<FrameResult> frames; +}; + +// Calculates PSNR and SSIM values for the reference and test video files +// (must be in I420 format). All calculated values are filled into the +// QualityMetricsResult structs. +// +// PSNR values have the unit decibel (dB) where a high value means the test file +// is similar to the reference file. The higher value, the more similar. The +// maximum PSNR value is kMetricsInfinitePSNR. For more info about PSNR, see +// http://en.wikipedia.org/wiki/PSNR. +// +// SSIM values range between -1.0 and 1.0, where 1.0 means the files are +// identical. For more info about SSIM, see http://en.wikipedia.org/wiki/SSIM +// This function only compares video frames up to the point when the shortest +// video ends. +// Return value: +// 0 if successful, negative on errors: +// -1 if the source file cannot be opened +// -2 if the test file cannot be opened +// -3 if any of the files are empty +// -4 if any arguments are invalid. +int I420MetricsFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* psnr_result, + QualityMetricsResult* ssim_result); + +// Calculates PSNR values for the reference and test video files (must be in +// I420 format). All calculated values are filled into the QualityMetricsResult +// struct. +// +// PSNR values have the unit decibel (dB) where a high value means the test file +// is similar to the reference file. The higher value, the more similar. The +// maximum PSNR value is kMetricsInfinitePSNR. For more info about PSNR, see +// http://en.wikipedia.org/wiki/PSNR. +// +// This function only compares video frames up to the point when the shortest +// video ends. +// +// Return value: +// 0 if successful, negative on errors: +// -1 if the source file cannot be opened +// -2 if the test file cannot be opened +// -3 if any of the files are empty +// -4 if any arguments are invalid. +int I420PSNRFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* result); + +// Calculates SSIM values for the reference and test video files (must be in +// I420 format). All calculated values are filled into the QualityMetricsResult +// struct. +// SSIM values range between -1.0 and 1.0, where 1.0 means the files are +// identical. +// This function only compares video frames up to the point when the shortest +// video ends. +// For more info about SSIM, see http://en.wikipedia.org/wiki/SSIM +// +// Return value: +// 0 if successful, negative on errors: +// -1 if the source file cannot be opened +// -2 if the test file cannot be opened +// -3 if any of the files are empty +// -4 if any arguments are invalid. +int I420SSIMFromFiles(const char* ref_filename, + const char* test_filename, + int width, + int height, + QualityMetricsResult* result); + +} // namespace test +} // namespace webrtc + +#endif // TESTSUPPORT_METRICS_VIDEO_METRICS_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics_unittest.cc new file mode 100644 index 0000000000..5b00458761 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/metrics/video_metrics_unittest.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/metrics/video_metrics.h" + +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { + +static const int kWidth = 352; +static const int kHeight = 288; + +static const int kMissingReferenceFileReturnCode = -1; +static const int kMissingTestFileReturnCode = -2; +static const int kEmptyFileReturnCode = -3; +static const double kPsnrPerfectResult = 48.0; +static const double kSsimPerfectResult = 1.0; + +class VideoMetricsTest: public testing::Test { + protected: + VideoMetricsTest() { + video_file_ = webrtc::test::ResourcePath("foreman_cif_short", "yuv"); + } + virtual ~VideoMetricsTest() {} + void SetUp() { + non_existing_file_ = webrtc::test::OutputPath() + + "video_metrics_unittest_non_existing"; + remove(non_existing_file_.c_str()); // To be sure it doesn't exist. + + // Create an empty file: + empty_file_ = webrtc::test::TempFilename( + webrtc::test::OutputPath(), "video_metrics_unittest_empty_file"); + FILE* dummy = fopen(empty_file_.c_str(), "wb"); + fclose(dummy); + } + void TearDown() { + remove(empty_file_.c_str()); + } + webrtc::test::QualityMetricsResult psnr_result_; + webrtc::test::QualityMetricsResult ssim_result_; + std::string non_existing_file_; + std::string empty_file_; + std::string video_file_; +}; + +// Tests that it is possible to run with the same reference as test file +TEST_F(VideoMetricsTest, ReturnsPerfectResultForIdenticalFilesPSNR) { + EXPECT_EQ(0, I420PSNRFromFiles(video_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, &psnr_result_)); + EXPECT_EQ(kPsnrPerfectResult, psnr_result_.average); +} + +TEST_F(VideoMetricsTest, ReturnsPerfectResultForIdenticalFilesSSIM) { + EXPECT_EQ(0, I420SSIMFromFiles(video_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, &ssim_result_)); + EXPECT_EQ(kSsimPerfectResult, ssim_result_.average); +} + +TEST_F(VideoMetricsTest, ReturnsPerfectResultForIdenticalFilesBothMetrics) { + EXPECT_EQ(0, I420MetricsFromFiles(video_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, &psnr_result_, + &ssim_result_)); + EXPECT_EQ(kPsnrPerfectResult, psnr_result_.average); + EXPECT_EQ(kSsimPerfectResult, ssim_result_.average); +} + +// Tests that the right return code is given when the reference file is missing. +TEST_F(VideoMetricsTest, MissingReferenceFilePSNR) { + EXPECT_EQ(kMissingReferenceFileReturnCode, + I420PSNRFromFiles(non_existing_file_.c_str(), + video_file_.c_str(), kWidth, kHeight, + &ssim_result_)); +} + +TEST_F(VideoMetricsTest, MissingReferenceFileSSIM) { + EXPECT_EQ(kMissingReferenceFileReturnCode, + I420SSIMFromFiles(non_existing_file_.c_str(), + video_file_.c_str(), kWidth, kHeight, + &ssim_result_)); +} + +TEST_F(VideoMetricsTest, MissingReferenceFileBothMetrics) { + EXPECT_EQ(kMissingReferenceFileReturnCode, + I420MetricsFromFiles(non_existing_file_.c_str(), + video_file_.c_str(), kWidth, kHeight, + &psnr_result_, &ssim_result_)); +} + +// Tests that the right return code is given when the test file is missing. +TEST_F(VideoMetricsTest, MissingTestFilePSNR) { + EXPECT_EQ(kMissingTestFileReturnCode, + I420PSNRFromFiles(video_file_.c_str(), non_existing_file_.c_str(), + kWidth, kHeight, &ssim_result_)); +} + +TEST_F(VideoMetricsTest, MissingTestFileSSIM) { + EXPECT_EQ(kMissingTestFileReturnCode, + I420SSIMFromFiles(video_file_.c_str(), non_existing_file_.c_str(), + kWidth, kHeight, &ssim_result_)); +} + +TEST_F(VideoMetricsTest, MissingTestFileBothMetrics) { + EXPECT_EQ(kMissingTestFileReturnCode, + I420MetricsFromFiles(video_file_.c_str(), + non_existing_file_.c_str(), kWidth, kHeight, + &psnr_result_, &ssim_result_)); +} + +// Tests that the method can be executed with empty files. +TEST_F(VideoMetricsTest, EmptyFilesPSNR) { + EXPECT_EQ(kEmptyFileReturnCode, + I420PSNRFromFiles(empty_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, &ssim_result_)); + EXPECT_EQ(kEmptyFileReturnCode, + I420PSNRFromFiles(video_file_.c_str(), empty_file_.c_str(), + kWidth, kHeight, &ssim_result_)); +} + +TEST_F(VideoMetricsTest, EmptyFilesSSIM) { + EXPECT_EQ(kEmptyFileReturnCode, + I420SSIMFromFiles(empty_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, &ssim_result_)); + EXPECT_EQ(kEmptyFileReturnCode, + I420SSIMFromFiles(video_file_.c_str(), empty_file_.c_str(), + kWidth, kHeight, &ssim_result_)); +} + +TEST_F(VideoMetricsTest, EmptyFilesBothMetrics) { + EXPECT_EQ(kEmptyFileReturnCode, + I420MetricsFromFiles(empty_file_.c_str(), video_file_.c_str(), + kWidth, kHeight, + &psnr_result_, &ssim_result_)); + EXPECT_EQ(kEmptyFileReturnCode, + I420MetricsFromFiles(video_file_.c_str(), empty_file_.c_str(), + kWidth, kHeight, + &psnr_result_, &ssim_result_)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/mock/mock_frame_reader.h b/third_party/libwebrtc/webrtc/test/testsupport/mock/mock_frame_reader.h new file mode 100644 index 0000000000..4ba416fedf --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/mock/mock_frame_reader.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_MOCK_MOCK_FRAME_READER_H_ +#define TEST_TESTSUPPORT_MOCK_MOCK_FRAME_READER_H_ + +#include "test/testsupport/frame_reader.h" + +#include "test/gmock.h" + +namespace webrtc { +namespace test { + +class MockFrameReader : public FrameReader { + public: + MOCK_METHOD0(Init, bool()); + MOCK_METHOD0(ReadFrame, rtc::scoped_refptr<I420Buffer>()); + MOCK_METHOD0(Close, void()); + MOCK_METHOD0(FrameLength, size_t()); + MOCK_METHOD0(NumberOfFrames, int()); +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_MOCK_MOCK_FRAME_READER_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.cc b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.cc new file mode 100644 index 0000000000..ba52f94e57 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/packet_reader.h" + +#include <assert.h> +#include <stdio.h> +#include <algorithm> + +namespace webrtc { +namespace test { + +PacketReader::PacketReader() + : initialized_(false) {} + +PacketReader::~PacketReader() {} + +void PacketReader::InitializeReading(uint8_t* data, + size_t data_length_in_bytes, + size_t packet_size_in_bytes) { + assert(data); + assert(packet_size_in_bytes > 0); + data_ = data; + data_length_ = data_length_in_bytes; + packet_size_ = packet_size_in_bytes; + currentIndex_ = 0; + initialized_ = true; +} + +int PacketReader::NextPacket(uint8_t** packet_pointer) { + if (!initialized_) { + fprintf(stderr, "Attempting to use uninitialized PacketReader!\n"); + return -1; + } + *packet_pointer = data_ + currentIndex_; + size_t old_index = currentIndex_; + currentIndex_ = std::min(currentIndex_ + packet_size_, data_length_); + return static_cast<int>(currentIndex_ - old_index); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.h b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.h new file mode 100644 index 0000000000..dbdb3da9e9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_PACKET_READER_H_ +#define TEST_TESTSUPPORT_PACKET_READER_H_ + +#include <cstddef> +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +// Reads chunks of data to simulate network packets from a byte array. +class PacketReader { + public: + PacketReader(); + virtual ~PacketReader(); + + // Inizializes a new reading operation. Must be done before invoking the + // NextPacket method. + // * data_length_in_bytes is the length of the data byte array. + // 0 length will result in no packets are read. + // * packet_size_in_bytes is the number of bytes to read in each NextPacket + // method call. Must be > 0 + virtual void InitializeReading(uint8_t* data, size_t data_length_in_bytes, + size_t packet_size_in_bytes); + + // Moves the supplied pointer to the beginning of the next packet. + // Returns: + // * The size of the packet ready to read (lower than the packet size for + // the last packet) + // * 0 if there are no more packets to read + // * -1 if InitializeReading has not been called (also prints to stderr). + virtual int NextPacket(uint8_t** packet_pointer); + + private: + uint8_t* data_; + size_t data_length_; + size_t packet_size_; + size_t currentIndex_; + bool initialized_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_PACKET_READER_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/packet_reader_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader_unittest.cc new file mode 100644 index 0000000000..3255151d05 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/packet_reader_unittest.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/packet_reader.h" + +#include "test/gtest.h" +#include "test/testsupport/unittest_utils.h" + +namespace webrtc { +namespace test { + +class PacketReaderTest: public PacketRelatedTest { + protected: + PacketReaderTest() {} + virtual ~PacketReaderTest() {} + void SetUp() { + reader_ = new PacketReader(); + } + void TearDown() { + delete reader_; + } + void VerifyPacketData(size_t expected_length, + int actual_length, + uint8_t* original_data_pointer, + uint8_t* new_data_pointer) { + EXPECT_EQ(static_cast<int>(expected_length), actual_length); + EXPECT_EQ(*original_data_pointer, *new_data_pointer); + EXPECT_EQ(0, memcmp(original_data_pointer, new_data_pointer, + actual_length)); + } + PacketReader* reader_; +}; + +// Test lack of initialization +TEST_F(PacketReaderTest, Uninitialized) { + uint8_t* data_pointer = NULL; + EXPECT_EQ(-1, reader_->NextPacket(&data_pointer)); + EXPECT_EQ(NULL, data_pointer); +} + +TEST_F(PacketReaderTest, InitializeZeroLengthArgument) { + reader_->InitializeReading(packet_data_, 0, kPacketSizeInBytes); + ASSERT_EQ(0, reader_->NextPacket(&packet_data_pointer_)); +} + +// Test with something smaller than one packet +TEST_F(PacketReaderTest, NormalSmallData) { + const int kDataLengthInBytes = 1499; + uint8_t data[kDataLengthInBytes]; + uint8_t* data_pointer = data; + memset(data, 1, kDataLengthInBytes); + + reader_->InitializeReading(data, kDataLengthInBytes, kPacketSizeInBytes); + int length_to_read = reader_->NextPacket(&data_pointer); + VerifyPacketData(kDataLengthInBytes, length_to_read, data, data_pointer); + EXPECT_EQ(0, data_pointer - data); // pointer hasn't moved + + // Reading another one shall result in 0 bytes: + length_to_read = reader_->NextPacket(&data_pointer); + EXPECT_EQ(0, length_to_read); + EXPECT_EQ(kDataLengthInBytes, data_pointer - data); +} + +// Test with data length that exactly matches one packet +TEST_F(PacketReaderTest, NormalOnePacketData) { + uint8_t data[kPacketSizeInBytes]; + uint8_t* data_pointer = data; + memset(data, 1, kPacketSizeInBytes); + + reader_->InitializeReading(data, kPacketSizeInBytes, kPacketSizeInBytes); + int length_to_read = reader_->NextPacket(&data_pointer); + VerifyPacketData(kPacketSizeInBytes, length_to_read, data, data_pointer); + EXPECT_EQ(0, data_pointer - data); // pointer hasn't moved + + // Reading another one shall result in 0 bytes: + length_to_read = reader_->NextPacket(&data_pointer); + EXPECT_EQ(0, length_to_read); + EXPECT_EQ(kPacketSizeInBytes, static_cast<size_t>(data_pointer - data)); +} + +// Test with data length that will result in 3 packets +TEST_F(PacketReaderTest, NormalLargeData) { + reader_->InitializeReading(packet_data_, kPacketDataLength, + kPacketSizeInBytes); + + int length_to_read = reader_->NextPacket(&packet_data_pointer_); + VerifyPacketData(kPacketSizeInBytes, length_to_read, + packet1_, packet_data_pointer_); + + length_to_read = reader_->NextPacket(&packet_data_pointer_); + VerifyPacketData(kPacketSizeInBytes, length_to_read, + packet2_, packet_data_pointer_); + + length_to_read = reader_->NextPacket(&packet_data_pointer_); + VerifyPacketData(1u, length_to_read, + packet3_, packet_data_pointer_); + + // Reading another one shall result in 0 bytes: + length_to_read = reader_->NextPacket(&packet_data_pointer_); + EXPECT_EQ(0, length_to_read); + EXPECT_EQ(kPacketDataLength, + static_cast<size_t>(packet_data_pointer_ - packet_data_)); +} + +// Test with empty data. +TEST_F(PacketReaderTest, EmptyData) { + const int kDataLengthInBytes = 0; + // But don't really try to allocate a zero-length array... + uint8_t data[kPacketSizeInBytes]; + uint8_t* data_pointer = data; + reader_->InitializeReading(data, kDataLengthInBytes, kPacketSizeInBytes); + EXPECT_EQ(kDataLengthInBytes, reader_->NextPacket(&data_pointer)); + // Do it again to make sure nothing changes + EXPECT_EQ(kDataLengthInBytes, reader_->NextPacket(&data_pointer)); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/perf_test.cc b/third_party/libwebrtc/webrtc/test/testsupport/perf_test.cc new file mode 100644 index 0000000000..b7578d101e --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/perf_test.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// A stripped-down version of Chromium's chrome/test/perf/perf_test.cc. +// ResultsToString(), PrintResult(size_t value) and AppendResult(size_t value) +// have been modified. The remainder are identical to the Chromium version. + +#include "test/testsupport/perf_test.h" + +#include <sstream> +#include <stdio.h> +#include <vector> + +namespace { + +void PrintResultsImpl(const std::string& graph_name, + const std::string& trace, + const std::string& values, + const std::string& units, + bool important) { + // <*>RESULT <graph_name>: <trace_name>= <value> <units> + // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units> + // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units> + + if (important) { + printf("*"); + } + printf("RESULT %s: %s= %s %s\n", graph_name.c_str(), trace.c_str(), + values.c_str(), units.c_str()); +} + +} // namespace + +namespace webrtc { +namespace test { + +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const double value, + const std::string& units, + bool important) { + std::ostringstream value_stream; + value_stream << value; + PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units, + important); +} + +void PrintResultMeanAndError(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const double mean, + const double error, + const std::string& units, + bool important) { + std::ostringstream value_stream; + value_stream << '{' << mean << ',' << error << '}'; + PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units, + important); +} + +void PrintResultList(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::vector<double>& values, + const std::string& units, + bool important) { + std::ostringstream value_stream; + value_stream << '['; + if (!values.empty()) { + auto it = values.begin(); + while (true) { + value_stream << *it; + if (++it == values.end()) + break; + value_stream << ','; + } + } + value_stream << ']'; + PrintResultsImpl(measurement + modifier, trace, value_stream.str(), units, + important); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/perf_test.h b/third_party/libwebrtc/webrtc/test/testsupport/perf_test.h new file mode 100644 index 0000000000..31b7b1345c --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/perf_test.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// A stripped-down version of Chromium's chrome/test/perf/perf_test.h. +// Several functions have been removed; the prototypes of the remainder have +// not been changed. + +#ifndef TEST_TESTSUPPORT_PERF_TEST_H_ +#define TEST_TESTSUPPORT_PERF_TEST_H_ + +#include <sstream> +#include <string> +#include <vector> + +namespace webrtc { +namespace test { + +// Prints numerical information to stdout in a controlled format, for +// post-processing. |measurement| is a description of the quantity being +// measured, e.g. "vm_peak"; |modifier| is provided as a convenience and +// will be appended directly to the name of the |measurement|, e.g. +// "_browser"; |trace| is a description of the particular data point, e.g. +// "reference"; |value| is the measured value; and |units| is a description +// of the units of measure, e.g. "bytes". If |important| is true, the output +// line will be specially marked, to notify the post-processor. The strings +// may be empty. They should not contain any colons (:) or equals signs (=). +// A typical post-processing step would be to produce graphs of the data +// produced for various builds, using the combined |measurement| + |modifier| +// string to specify a particular graph and the |trace| to identify a trace +// (i.e., data series) on that graph. +void PrintResult(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const double value, + const std::string& units, + bool important); + +// Like PrintResult(), but prints a (mean, standard deviation) result pair. +// The |<values>| should be two comma-separated numbers, the mean and +// standard deviation (or other error metric) of the measurement. +void PrintResultMeanAndError(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const double mean, + const double error, + const std::string& units, + bool important); + + +// Like PrintResult(), but prints an entire list of results. The |values| +// will generally be a list of comma-separated numbers. A typical +// post-processing step might produce plots of their mean and standard +// deviation. +void PrintResultList(const std::string& measurement, + const std::string& modifier, + const std::string& trace, + const std::vector<double>& values, + const std::string& units, + bool important); + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_PERF_TEST_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/perf_test_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/perf_test_unittest.cc new file mode 100644 index 0000000000..466e2b3e69 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/perf_test_unittest.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/perf_test.h" + +#include <string> + +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +TEST(PerfTest, AppendResult) { + testing::internal::CaptureStdout(); + std::string expected = "RESULT measurementmodifier: trace= 42 units\n"; + PrintResult("measurement", "modifier", "trace", 42, "units", false); + + expected += "*RESULT foobar: baz= 7 widgets\n"; + PrintResult("foo", "bar", "baz", 7, "widgets", true); + + expected += "RESULT foobar: baz= {1,2} lemurs\n"; + PrintResultMeanAndError("foo", "bar", "baz", 1, 2, "lemurs", false); + + expected += "RESULT foobar: baz= [1,2,3] units\n"; + PrintResultList("foo", "bar", "baz", {1, 2, 3}, "units", false); + + std::string output = testing::internal::GetCapturedStdout(); + EXPECT_EQ(expected, output); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.cc b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.cc new file mode 100644 index 0000000000..3d97a94472 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/test_artifacts.h" + +#include <string.h> + +#include "rtc_base/file.h" +#include "rtc_base/flags.h" +#include "rtc_base/logging.h" +#include "rtc_base/pathutils.h" +#include "test/testsupport/fileutils.h" + +namespace { +const std::string& DefaultArtifactPath() { + static const std::string path = webrtc::test::OutputPath(); + return path; +} +} + +DEFINE_string(test_artifacts_dir, + DefaultArtifactPath().c_str(), + "The output folder where test output should be saved."); + +namespace webrtc { +namespace test { + +bool GetTestArtifactsDir(std::string* out_dir) { + if (strlen(FLAG_test_artifacts_dir) == 0) { + RTC_LOG(LS_WARNING) << "No test_out_dir defined."; + return false; + } + *out_dir = FLAG_test_artifacts_dir; + return true; +} + +bool WriteToTestArtifactsDir(const char* filename, + const uint8_t* buffer, + size_t length) { + if (strlen(FLAG_test_artifacts_dir) == 0) { + RTC_LOG(LS_WARNING) << "No test_out_dir defined."; + return false; + } + + if (filename == nullptr || strlen(filename) == 0) { + RTC_LOG(LS_WARNING) << "filename must be provided."; + return false; + } + + rtc::File output = + rtc::File::Create(rtc::Pathname(FLAG_test_artifacts_dir, filename)); + + return output.IsOpen() && output.Write(buffer, length) == length; +} + +bool WriteToTestArtifactsDir(const char* filename, const std::string& content) { + return WriteToTestArtifactsDir( + filename, reinterpret_cast<const uint8_t*>(content.c_str()), + content.length()); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.h b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.h new file mode 100644 index 0000000000..ee07a9be52 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_TEST_ARTIFACTS_H_ +#define TEST_TESTSUPPORT_TEST_ARTIFACTS_H_ + +#include <stdlib.h> + +#include <string> + +namespace webrtc { +namespace test { + +// If the test_artifacts_dir flag is set, returns true and copies the location +// of the dir to |out_dir|. Otherwise, return false. +bool GetTestArtifactsDir(std::string* out_dir); + +// Writes a |length| bytes array |buffer| to |filename| in isolated output +// directory defined by swarming. If the file is existing, content will be +// appended. Otherwise a new file will be created. This function returns false +// if isolated output directory has not been defined, or |filename| indicates an +// invalid or non-writable file, or underlying file system errors. +bool WriteToTestArtifactsDir(const char* filename, + const uint8_t* buffer, + size_t length); + +bool WriteToTestArtifactsDir(const char* filename, const std::string& content); + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_TEST_ARTIFACTS_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts_unittest.cc new file mode 100644 index 0000000000..251c5cde88 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/test_artifacts_unittest.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/test_artifacts.h" + +#include <string.h> + +#include <string> + +#include "rtc_base/file.h" +#include "rtc_base/flags.h" +#include "rtc_base/pathutils.h" +#include "rtc_base/platform_file.h" +#include "test/gtest.h" + +DECLARE_string(test_artifacts_dir); + +namespace webrtc { +namespace test { + +TEST(IsolatedOutputTest, ShouldRejectInvalidIsolatedOutDir) { + const char* backup = FLAG_test_artifacts_dir; + FLAG_test_artifacts_dir = ""; + ASSERT_FALSE(WriteToTestArtifactsDir("a-file", "some-contents")); + FLAG_test_artifacts_dir = backup; +} + +TEST(IsolatedOutputTest, ShouldRejectInvalidFileName) { + ASSERT_FALSE(WriteToTestArtifactsDir(nullptr, "some-contents")); + ASSERT_FALSE(WriteToTestArtifactsDir("", "some-contents")); +} + +// Sets isolated_out_dir=<a-writable-path> to execute this test. +TEST(IsolatedOutputTest, ShouldBeAbleToWriteContent) { + const char* filename = "a-file"; + const char* content = "some-contents"; + if (WriteToTestArtifactsDir(filename, content)) { + rtc::Pathname out_file(FLAG_test_artifacts_dir, filename); + rtc::File input = rtc::File::Open(out_file); + EXPECT_TRUE(input.IsOpen()); + EXPECT_TRUE(input.Seek(0)); + uint8_t buffer[32]; + EXPECT_EQ(input.Read(buffer, strlen(content)), strlen(content)); + buffer[strlen(content)] = 0; + EXPECT_EQ(std::string(content), + std::string(reinterpret_cast<char*>(buffer))); + input.Close(); + + EXPECT_TRUE(rtc::File::Remove(out_file)); + } +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/unittest_utils.h b/third_party/libwebrtc/webrtc/test/testsupport/unittest_utils.h new file mode 100644 index 0000000000..5fee2ca454 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/unittest_utils.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_TESTSUPPORT_UNITTEST_UTILS_H_ +#define TEST_TESTSUPPORT_UNITTEST_UTILS_H_ + +namespace webrtc { +namespace test { + +const size_t kPacketSizeInBytes = 1500; +const size_t kPacketDataLength = kPacketSizeInBytes * 2 + 1; +const int kPacketDataNumberOfPackets = 3; + +// A base test fixture for packet related tests. Contains +// two full prepared packets with 1s, 2s in their data and a third packet with +// a single 3 in it (size=1). +// A packet data structure is also available, that contains these three packets +// in order. +class PacketRelatedTest: public testing::Test { + protected: + // Tree packet byte arrays with data used for verification: + uint8_t packet1_[kPacketSizeInBytes]; + uint8_t packet2_[kPacketSizeInBytes]; + uint8_t packet3_[1]; + // Construct a data structure containing these packets + uint8_t packet_data_[kPacketDataLength]; + uint8_t* packet_data_pointer_; + + PacketRelatedTest() { + packet_data_pointer_ = packet_data_; + + memset(packet1_, 1, kPacketSizeInBytes); + memset(packet2_, 2, kPacketSizeInBytes); + memset(packet3_, 3, 1); + // Fill the packet_data: + memcpy(packet_data_pointer_, packet1_, kPacketSizeInBytes); + memcpy(packet_data_pointer_ + kPacketSizeInBytes, packet2_, + kPacketSizeInBytes); + memcpy(packet_data_pointer_ + kPacketSizeInBytes * 2, packet3_, 1); + } + virtual ~PacketRelatedTest() {} + void SetUp() {} + void TearDown() {} +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_TESTSUPPORT_UNITTEST_UTILS_H_ diff --git a/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer.cc b/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer.cc new file mode 100644 index 0000000000..e0c1ed54ba --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/checks.h" +#include "test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +Y4mFrameWriterImpl::Y4mFrameWriterImpl(std::string output_filename, + int width, + int height, + int frame_rate) + : YuvFrameWriterImpl(output_filename, width, height), + frame_rate_(frame_rate) {} + +Y4mFrameWriterImpl::~Y4mFrameWriterImpl() = default; + +bool Y4mFrameWriterImpl::Init() { + if (!YuvFrameWriterImpl::Init()) { + return false; + } + int bytes_written = fprintf(output_file_, "YUV4MPEG2 W%d H%d F%d:1 C420\n", + width_, height_, frame_rate_); + if (bytes_written < 0) { + fprintf(stderr, "Failed to write Y4M file header to file %s\n", + output_filename_.c_str()); + return false; + } + return true; +} + +bool Y4mFrameWriterImpl::WriteFrame(uint8_t* frame_buffer) { + if (output_file_ == nullptr) { + fprintf(stderr, + "Y4mFrameWriterImpl is not initialized (output file is NULL)\n"); + return false; + } + int bytes_written = fprintf(output_file_, "FRAME\n"); + if (bytes_written < 0) { + fprintf(stderr, "Failed to write Y4M frame header to file %s\n", + output_filename_.c_str()); + return false; + } + return YuvFrameWriterImpl::WriteFrame(frame_buffer); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer_unittest.cc new file mode 100644 index 0000000000..d9ec09a2b7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/y4m_frame_writer_unittest.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> +#include <string> + +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" +#include "test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +namespace { +const size_t kFrameWidth = 50; +const size_t kFrameHeight = 20; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +const size_t kFrameRate = 30; + +const std::string kFileHeader = "YUV4MPEG2 W50 H20 F30:1 C420\n"; +const std::string kFrameHeader = "FRAME\n"; +} // namespace + +class Y4mFrameWriterTest : public testing::Test { + protected: + Y4mFrameWriterTest() = default; + ~Y4mFrameWriterTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "y4m_frame_writer_unittest"); + frame_writer_.reset(new Y4mFrameWriterImpl(temp_filename_, kFrameWidth, + kFrameHeight, kFrameRate)); + ASSERT_TRUE(frame_writer_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameWriter> frame_writer_; + std::string temp_filename_; +}; + +TEST_F(Y4mFrameWriterTest, InitSuccess) {} + +TEST_F(Y4mFrameWriterTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_writer_->FrameLength()); +} + +TEST_F(Y4mFrameWriterTest, WriteFrame) { + uint8_t buffer[kFrameLength]; + memset(buffer, 9, kFrameLength); // Write lots of 9s to the buffer. + bool result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + + frame_writer_->Close(); + EXPECT_EQ(kFileHeader.size() + 2 * kFrameHeader.size() + 2 * kFrameLength, + GetFileSize(temp_filename_)); +} + +TEST_F(Y4mFrameWriterTest, WriteFrameUninitialized) { + uint8_t buffer[kFrameLength]; + Y4mFrameWriterImpl frame_writer(temp_filename_, kFrameWidth, kFrameHeight, + kFrameRate); + EXPECT_FALSE(frame_writer.WriteFrame(buffer)); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader.cc b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader.cc new file mode 100644 index 0000000000..60f9994b14 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/testsupport/frame_reader.h" + +#include "api/video/i420_buffer.h" +#include "test/frame_utils.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { +namespace test { + +YuvFrameReaderImpl::YuvFrameReaderImpl(std::string input_filename, + int width, + int height) + : input_filename_(input_filename), + frame_length_in_bytes_(0), + width_(width), + height_(height), + number_of_frames_(-1), + input_file_(nullptr) {} + +YuvFrameReaderImpl::~YuvFrameReaderImpl() { + Close(); +} + +bool YuvFrameReaderImpl::Init() { + if (width_ <= 0 || height_ <= 0) { + fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", width_, + height_); + return false; + } + frame_length_in_bytes_ = + width_ * height_ + 2 * ((width_ + 1) / 2) * ((height_ + 1) / 2); + + input_file_ = fopen(input_filename_.c_str(), "rb"); + if (input_file_ == nullptr) { + fprintf(stderr, "Couldn't open input file for reading: %s\n", + input_filename_.c_str()); + return false; + } + // Calculate total number of frames. + size_t source_file_size = GetFileSize(input_filename_); + if (source_file_size <= 0u) { + fprintf(stderr, "Found empty file: %s\n", input_filename_.c_str()); + return false; + } + number_of_frames_ = + static_cast<int>(source_file_size / frame_length_in_bytes_); + return true; +} + +rtc::scoped_refptr<I420Buffer> YuvFrameReaderImpl::ReadFrame() { + if (input_file_ == nullptr) { + fprintf(stderr, + "YuvFrameReaderImpl is not initialized (input file is NULL)\n"); + return nullptr; + } + rtc::scoped_refptr<I420Buffer> buffer( + ReadI420Buffer(width_, height_, input_file_)); + if (!buffer && ferror(input_file_)) { + fprintf(stderr, "Error reading from input file: %s\n", + input_filename_.c_str()); + } + return buffer; +} + +void YuvFrameReaderImpl::Close() { + if (input_file_ != nullptr) { + fclose(input_file_); + input_file_ = nullptr; + } +} + +size_t YuvFrameReaderImpl::FrameLength() { + return frame_length_in_bytes_; +} + +int YuvFrameReaderImpl::NumberOfFrames() { + return number_of_frames_; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader_unittest.cc new file mode 100644 index 0000000000..dd4b980c71 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_reader_unittest.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> +#include <string> + +#include "api/video/i420_buffer.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" +#include "test/testsupport/frame_reader.h" + +namespace webrtc { +namespace test { + +namespace { +const std::string kInputFileContents = "bazouk"; + +const size_t kFrameWidth = 2; +const size_t kFrameHeight = 2; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +} // namespace + +class YuvFrameReaderTest : public testing::Test { + protected: + YuvFrameReaderTest() = default; + ~YuvFrameReaderTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "yuv_frame_reader_unittest"); + FILE* dummy = fopen(temp_filename_.c_str(), "wb"); + fprintf(dummy, "%s", kInputFileContents.c_str()); + fclose(dummy); + + frame_reader_.reset( + new YuvFrameReaderImpl(temp_filename_, kFrameWidth, kFrameHeight)); + ASSERT_TRUE(frame_reader_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameReader> frame_reader_; + std::string temp_filename_; +}; + +TEST_F(YuvFrameReaderTest, InitSuccess) {} + +TEST_F(YuvFrameReaderTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_reader_->FrameLength()); +} + +TEST_F(YuvFrameReaderTest, NumberOfFrames) { + EXPECT_EQ(1, frame_reader_->NumberOfFrames()); +} + +TEST_F(YuvFrameReaderTest, ReadFrame) { + rtc::scoped_refptr<I420BufferInterface> buffer = frame_reader_->ReadFrame(); + ASSERT_TRUE(buffer); + // Expect I420 packed as YUV. + EXPECT_EQ(kInputFileContents[0], buffer->DataY()[0]); + EXPECT_EQ(kInputFileContents[1], buffer->DataY()[1]); + EXPECT_EQ(kInputFileContents[2], buffer->DataY()[2]); + EXPECT_EQ(kInputFileContents[3], buffer->DataY()[3]); + EXPECT_EQ(kInputFileContents[4], buffer->DataU()[0]); + EXPECT_EQ(kInputFileContents[5], buffer->DataV()[0]); + EXPECT_FALSE(frame_reader_->ReadFrame()); // End of file. +} + +TEST_F(YuvFrameReaderTest, ReadFrameUninitialized) { + YuvFrameReaderImpl file_reader(temp_filename_, kFrameWidth, kFrameHeight); + EXPECT_FALSE(file_reader.ReadFrame()); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer.cc b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer.cc new file mode 100644 index 0000000000..1bd343c513 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/checks.h" +#include "test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +YuvFrameWriterImpl::YuvFrameWriterImpl(std::string output_filename, + int width, + int height) + : output_filename_(output_filename), + frame_length_in_bytes_(0), + width_(width), + height_(height), + output_file_(nullptr) {} + +YuvFrameWriterImpl::~YuvFrameWriterImpl() { + Close(); +} + +bool YuvFrameWriterImpl::Init() { + if (width_ <= 0 || height_ <= 0) { + fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", width_, + height_); + return false; + } + frame_length_in_bytes_ = + width_ * height_ + 2 * ((width_ + 1) / 2) * ((height_ + 1) / 2); + + output_file_ = fopen(output_filename_.c_str(), "wb"); + if (output_file_ == nullptr) { + fprintf(stderr, "Couldn't open output file for writing: %s\n", + output_filename_.c_str()); + return false; + } + return true; +} + +bool YuvFrameWriterImpl::WriteFrame(uint8_t* frame_buffer) { + RTC_DCHECK(frame_buffer); + if (output_file_ == nullptr) { + fprintf(stderr, + "YuvFrameWriterImpl is not initialized (output file is NULL)\n"); + return false; + } + size_t bytes_written = + fwrite(frame_buffer, 1, frame_length_in_bytes_, output_file_); + if (bytes_written != frame_length_in_bytes_) { + fprintf(stderr, "Failed to write %zu bytes to file %s\n", + frame_length_in_bytes_, output_filename_.c_str()); + return false; + } + return true; +} + +void YuvFrameWriterImpl::Close() { + if (output_file_ != nullptr) { + fclose(output_file_); + output_file_ = nullptr; + } +} + +size_t YuvFrameWriterImpl::FrameLength() { + return frame_length_in_bytes_; +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer_unittest.cc b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer_unittest.cc new file mode 100644 index 0000000000..49b595e1da --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/testsupport/yuv_frame_writer_unittest.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <memory> + +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" +#include "test/testsupport/frame_writer.h" + +namespace webrtc { +namespace test { + +namespace { +const size_t kFrameWidth = 50; +const size_t kFrameHeight = 20; +const size_t kFrameLength = 3 * kFrameWidth * kFrameHeight / 2; // I420. +} // namespace + +class YuvFrameWriterTest : public testing::Test { + protected: + YuvFrameWriterTest() = default; + ~YuvFrameWriterTest() override = default; + + void SetUp() override { + temp_filename_ = webrtc::test::TempFilename(webrtc::test::OutputPath(), + "yuv_frame_writer_unittest"); + frame_writer_.reset( + new YuvFrameWriterImpl(temp_filename_, kFrameWidth, kFrameHeight)); + ASSERT_TRUE(frame_writer_->Init()); + } + + void TearDown() override { remove(temp_filename_.c_str()); } + + std::unique_ptr<FrameWriter> frame_writer_; + std::string temp_filename_; +}; + +TEST_F(YuvFrameWriterTest, InitSuccess) {} + +TEST_F(YuvFrameWriterTest, FrameLength) { + EXPECT_EQ(kFrameLength, frame_writer_->FrameLength()); +} + +TEST_F(YuvFrameWriterTest, WriteFrame) { + uint8_t buffer[kFrameLength]; + memset(buffer, 9, kFrameLength); // Write lots of 9s to the buffer. + bool result = frame_writer_->WriteFrame(buffer); + ASSERT_TRUE(result); + + frame_writer_->Close(); + EXPECT_EQ(kFrameLength, GetFileSize(temp_filename_)); +} + +TEST_F(YuvFrameWriterTest, WriteFrameUninitialized) { + uint8_t buffer[kFrameLength]; + YuvFrameWriterImpl frame_writer(temp_filename_, kFrameWidth, kFrameHeight); + EXPECT_FALSE(frame_writer.WriteFrame(buffer)); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/vcm_capturer.cc b/third_party/libwebrtc/webrtc/test/vcm_capturer.cc new file mode 100644 index 0000000000..aba0263ca7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/vcm_capturer.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/vcm_capturer.h" + +#include "modules/video_capture/video_capture_factory.h" +#include "rtc_base/logging.h" +#include "call/video_send_stream.h" +namespace webrtc { +namespace test { + +VcmCapturer::VcmCapturer() : started_(false), sink_(nullptr), vcm_(nullptr) {} + +bool VcmCapturer::Init(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index) { + std::unique_ptr<VideoCaptureModule::DeviceInfo> device_info( + VideoCaptureFactory::CreateDeviceInfo()); + + char device_name[256]; + char unique_name[256]; + if (device_info->GetDeviceName(static_cast<uint32_t>(capture_device_index), + device_name, sizeof(device_name), unique_name, + sizeof(unique_name)) != 0) { + Destroy(); + return false; + } + + vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); + vcm_->RegisterCaptureDataCallback(this); + + device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); + + capability_.width = static_cast<int32_t>(width); + capability_.height = static_cast<int32_t>(height); + capability_.maxFPS = static_cast<int32_t>(target_fps); + capability_.videoType = VideoType::kI420; + + if (vcm_->StartCapture(capability_) != 0) { + Destroy(); + return false; + } + + RTC_CHECK(vcm_->CaptureStarted()); + + return true; +} + +VcmCapturer* VcmCapturer::Create(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index) { + std::unique_ptr<VcmCapturer> vcm_capturer(new VcmCapturer()); + if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { + RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width + << ", h = " << height << ", fps = " << target_fps + << ")"; + return nullptr; + } + return vcm_capturer.release(); +} + + +void VcmCapturer::Start() { + rtc::CritScope lock(&crit_); + started_ = true; +} + +void VcmCapturer::Stop() { + rtc::CritScope lock(&crit_); + started_ = false; +} + +void VcmCapturer::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) { + rtc::CritScope lock(&crit_); + RTC_CHECK(!sink_ || sink_ == sink); + sink_ = sink; + VideoCapturer::AddOrUpdateSink(sink, wants); +} + +void VcmCapturer::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) { + rtc::CritScope lock(&crit_); + RTC_CHECK(sink_ == sink); + sink_ = nullptr; +} + +void VcmCapturer::Destroy() { + if (!vcm_) + return; + + vcm_->StopCapture(); + vcm_->DeRegisterCaptureDataCallback(this); + // Release reference to VCM. + vcm_ = nullptr; +} + +VcmCapturer::~VcmCapturer() { Destroy(); } + +void VcmCapturer::OnFrame(const VideoFrame& frame) { + rtc::CritScope lock(&crit_); + if (started_ && sink_) { + rtc::Optional<VideoFrame> out_frame = AdaptFrame(frame); + if (out_frame) + sink_->OnFrame(*out_frame); + } +} + +} // test +} // webrtc diff --git a/third_party/libwebrtc/webrtc/test/vcm_capturer.h b/third_party/libwebrtc/webrtc/test/vcm_capturer.h new file mode 100644 index 0000000000..9d158c3fcd --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/vcm_capturer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_VCM_CAPTURER_H_ +#define TEST_VCM_CAPTURER_H_ + +#include <memory> + +#include "common_types.h" // NOLINT(build/include) +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "modules/video_capture/video_capture.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/scoped_ref_ptr.h" +#include "test/video_capturer.h" + +namespace webrtc { +namespace test { + +class VcmCapturer + : public VideoCapturer, + public rtc::VideoSinkInterface<VideoFrame> { + public: + static VcmCapturer* Create(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index); + virtual ~VcmCapturer(); + + void Start() override; + void Stop() override; + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override; + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override; + + void OnFrame(const VideoFrame& frame) override; + + private: + VcmCapturer(); + bool Init(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index); + void Destroy(); + + rtc::CriticalSection crit_; + bool started_ RTC_GUARDED_BY(crit_); + rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(crit_); + rtc::scoped_refptr<VideoCaptureModule> vcm_; + VideoCaptureCapability capability_; +}; + +} // test +} // webrtc + +#endif // TEST_VCM_CAPTURER_H_ diff --git a/third_party/libwebrtc/webrtc/test/video_capturer.cc b/third_party/libwebrtc/webrtc/test/video_capturer.cc new file mode 100644 index 0000000000..b95936feb9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/video_capturer.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "test/video_capturer.h" + +#include "rtc_base/basictypes.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { +namespace test { +VideoCapturer::VideoCapturer() : video_adapter_(new cricket::VideoAdapter()) {} +VideoCapturer::~VideoCapturer() {} + +rtc::Optional<VideoFrame> VideoCapturer::AdaptFrame(const VideoFrame& frame) { + int cropped_width = 0; + int cropped_height = 0; + int out_width = 0; + int out_height = 0; + + if (!video_adapter_->AdaptFrameResolution( + frame.width(), frame.height(), frame.timestamp_us() * 1000, + &cropped_width, &cropped_height, &out_width, &out_height)) { + // Drop frame in order to respect frame rate constraint. + return rtc::Optional<VideoFrame>(); + } + + rtc::Optional<VideoFrame> out_frame; + if (out_height != frame.height() || out_width != frame.width()) { + // Video adapter has requested a down-scale. Allocate a new buffer and + // return scaled version. + rtc::scoped_refptr<I420Buffer> scaled_buffer = + I420Buffer::Create(out_width, out_height); + scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); + out_frame.emplace( + VideoFrame(scaled_buffer, kVideoRotation_0, frame.timestamp_us())); + } else { + // No adaptations needed, just return the frame as is. + out_frame.emplace(frame); + } + + return out_frame; +} + +void VideoCapturer::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) { + video_adapter_->OnResolutionFramerateRequest( + wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/video_capturer.h b/third_party/libwebrtc/webrtc/test/video_capturer.h new file mode 100644 index 0000000000..eba5d61111 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/video_capturer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_VIDEO_CAPTURER_H_ +#define TEST_VIDEO_CAPTURER_H_ + +#include <stddef.h> + +#include <memory> + +#include "api/optional.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_frame.h" +#include "media/base/videoadapter.h" +#include "media/base/videosourceinterface.h" +#include "rtc_base/criticalsection.h" + +namespace cricket { +class VideoAdapter; +} // namespace cricket + +namespace webrtc { +class Clock; +namespace test { + +class VideoCapturer : public rtc::VideoSourceInterface<VideoFrame> { + public: + VideoCapturer(); + virtual ~VideoCapturer(); + + virtual void Start() = 0; + virtual void Stop() = 0; + + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override; + + protected: + rtc::Optional<VideoFrame> AdaptFrame(const VideoFrame& frame); + rtc::VideoSinkWants GetSinkWants(); + + private: + const std::unique_ptr<cricket::VideoAdapter> video_adapter_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_VIDEO_CAPTURER_H_ diff --git a/third_party/libwebrtc/webrtc/test/video_codec_settings.h b/third_party/libwebrtc/webrtc/test/video_codec_settings.h new file mode 100644 index 0000000000..b52fbc7f42 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/video_codec_settings.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_VIDEO_CODEC_SETTINGS_H_ +#define TEST_VIDEO_CODEC_SETTINGS_H_ + +#include "api/video_codecs/video_encoder.h" + +namespace webrtc { +namespace test { + +const uint16_t kTestWidth = 352; +const uint16_t kTestHeight = 288; +const uint32_t kTestFrameRate = 30; +const unsigned int kTestMinBitrateKbps = 30; +const unsigned int kTestStartBitrateKbps = 300; +const uint8_t kTestPayloadType = 100; +const int64_t kTestTimingFramesDelayMs = 200; +const uint16_t kTestOutlierFrameSizePercent = 250; + +static void CodecSettings(VideoCodecType codec_type, VideoCodec* settings) { + memset(settings, 0, sizeof(VideoCodec)); + switch (codec_type) { + case kVideoCodecVP8: + strncpy(settings->plName, "VP8", 4); + settings->codecType = kVideoCodecVP8; + // 96 to 127 dynamic payload types for video codecs. + settings->plType = kTestPayloadType; + settings->startBitrate = kTestStartBitrateKbps; + settings->minBitrate = kTestMinBitrateKbps; + settings->maxBitrate = 0; + settings->maxFramerate = kTestFrameRate; + settings->width = kTestWidth; + settings->height = kTestHeight; + settings->numberOfSimulcastStreams = 0; + settings->qpMax = 56; + settings->timing_frame_thresholds = { + kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent, + }; + *(settings->VP8()) = VideoEncoder::GetDefaultVp8Settings(); + return; + case kVideoCodecVP9: + strncpy(settings->plName, "VP9", 4); + settings->codecType = kVideoCodecVP9; + // 96 to 127 dynamic payload types for video codecs. + settings->plType = kTestPayloadType; + settings->startBitrate = 100; + settings->minBitrate = kTestMinBitrateKbps; + settings->maxBitrate = 0; + settings->maxFramerate = kTestFrameRate; + settings->width = kTestWidth; + settings->height = kTestHeight; + settings->numberOfSimulcastStreams = 0; + settings->qpMax = 56; + settings->timing_frame_thresholds = { + kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent, + }; + *(settings->VP9()) = VideoEncoder::GetDefaultVp9Settings(); + return; + case kVideoCodecH264: + strncpy(settings->plName, "H264", 5); + settings->codecType = kVideoCodecH264; + // 96 to 127 dynamic payload types for video codecs. + settings->plType = kTestPayloadType; + settings->startBitrate = kTestStartBitrateKbps; + settings->minBitrate = kTestMinBitrateKbps; + settings->maxBitrate = 0; + settings->maxFramerate = kTestFrameRate; + settings->width = kTestWidth; + settings->height = kTestHeight; + settings->numberOfSimulcastStreams = 0; + settings->qpMax = 56; + settings->timing_frame_thresholds = { + kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent, + }; + *(settings->H264()) = VideoEncoder::GetDefaultH264Settings(); + return; + case kVideoCodecI420: + strncpy(settings->plName, "I420", 5); + settings->codecType = kVideoCodecI420; + // 96 to 127 dynamic payload types for video codecs. + settings->plType = kTestPayloadType; + // Bitrate needed for this size and framerate. + settings->startBitrate = + 3 * kTestWidth * kTestHeight * 8 * kTestFrameRate / 1000 / 2; + settings->maxBitrate = settings->startBitrate; + settings->maxFramerate = kTestFrameRate; + settings->width = kTestWidth; + settings->height = kTestHeight; + settings->minBitrate = kTestMinBitrateKbps; + settings->numberOfSimulcastStreams = 0; + return; + case kVideoCodecRED: + case kVideoCodecULPFEC: + case kVideoCodecFlexfec: + case kVideoCodecGeneric: + case kVideoCodecUnknown: + RTC_NOTREACHED(); + return; + } +} +} // namespace test +} // namespace webrtc + +#endif // TEST_VIDEO_CODEC_SETTINGS_H_ diff --git a/third_party/libwebrtc/webrtc/test/video_renderer.cc b/third_party/libwebrtc/webrtc/test/video_renderer.cc new file mode 100644 index 0000000000..68a20f3752 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/video_renderer.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/video_renderer.h" + +// TODO(pbos): Android renderer + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +class NullRenderer : public VideoRenderer { + void OnFrame(const VideoFrame& video_frame) override {} +}; + +VideoRenderer* VideoRenderer::Create(const char* window_title, + size_t width, + size_t height) { + VideoRenderer* renderer = CreatePlatformRenderer(window_title, width, height); + if (renderer != nullptr) + return renderer; + + return new NullRenderer(); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/video_renderer.h b/third_party/libwebrtc/webrtc/test/video_renderer.h new file mode 100644 index 0000000000..6a00e8803b --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/video_renderer.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_VIDEO_RENDERER_H_ +#define TEST_VIDEO_RENDERER_H_ + +#include <stddef.h> + +#include "media/base/videosinkinterface.h" + +namespace webrtc { +class VideoFrame; + +namespace test { +class VideoRenderer : public rtc::VideoSinkInterface<VideoFrame> { + public: + // Creates a platform-specific renderer if possible, or a null implementation + // if failing. + static VideoRenderer* Create(const char* window_title, size_t width, + size_t height); + // Returns a renderer rendering to a platform specific window if possible, + // NULL if none can be created. + // Creates a platform-specific renderer if possible, returns NULL if a + // platform renderer could not be created. This occurs, for instance, when + // running without an X environment on Linux. + static VideoRenderer* CreatePlatformRenderer(const char* window_title, + size_t width, size_t height); + virtual ~VideoRenderer() {} + protected: + VideoRenderer() {} +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_VIDEO_RENDERER_H_ diff --git a/third_party/libwebrtc/webrtc/test/win/d3d_renderer.cc b/third_party/libwebrtc/webrtc/test/win/d3d_renderer.cc new file mode 100644 index 0000000000..1f791a91ef --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/win/d3d_renderer.cc @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/win/d3d_renderer.h" + +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { + +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1) + +struct D3dCustomVertex { + float x, y, z; + float u, v; +}; + +const char kD3DClassName[] = "d3d_renderer"; + +VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title, + size_t width, + size_t height) { + return D3dRenderer::Create(window_title, width, height); +} + +D3dRenderer::D3dRenderer(size_t width, size_t height) + : width_(width), + height_(height), + hwnd_(NULL), + d3d_(NULL), + d3d_device_(NULL), + texture_(NULL), + vertex_buffer_(NULL) { + RTC_DCHECK_GT(width, 0); + RTC_DCHECK_GT(height, 0); +} + +D3dRenderer::~D3dRenderer() { Destroy(); } + +LRESULT WINAPI D3dRenderer::WindowProc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam) { + if (msg == WM_DESTROY || (msg == WM_CHAR && wparam == VK_RETURN)) { + PostQuitMessage(0); + return 0; + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +void D3dRenderer::Destroy() { + texture_ = NULL; + vertex_buffer_ = NULL; + d3d_device_ = NULL; + d3d_ = NULL; + + if (hwnd_ != NULL) { + DestroyWindow(hwnd_); + RTC_DCHECK(!IsWindow(hwnd_)); + hwnd_ = NULL; + } +} + +bool D3dRenderer::Init(const char* window_title) { + hwnd_ = CreateWindowA(kD3DClassName, + window_title, + WS_OVERLAPPEDWINDOW, + 0, + 0, + static_cast<int>(width_), + static_cast<int>(height_), + NULL, + NULL, + NULL, + NULL); + + if (hwnd_ == NULL) { + Destroy(); + return false; + } + + d3d_ = Direct3DCreate9(D3D_SDK_VERSION); + if (d3d_ == NULL) { + Destroy(); + return false; + } + + D3DPRESENT_PARAMETERS d3d_params = {}; + + d3d_params.Windowed = TRUE; + d3d_params.SwapEffect = D3DSWAPEFFECT_COPY; + + IDirect3DDevice9* d3d_device; + if (d3d_->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hwnd_, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3d_params, + &d3d_device) != D3D_OK) { + Destroy(); + return false; + } + d3d_device_ = d3d_device; + d3d_device->Release(); + + IDirect3DVertexBuffer9* vertex_buffer; + const int kRectVertices = 4; + if (d3d_device_->CreateVertexBuffer(kRectVertices * sizeof(D3dCustomVertex), + 0, + D3DFVF_CUSTOMVERTEX, + D3DPOOL_MANAGED, + &vertex_buffer, + NULL) != D3D_OK) { + Destroy(); + return false; + } + vertex_buffer_ = vertex_buffer; + vertex_buffer->Release(); + + d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE); + Resize(width_, height_); + + ShowWindow(hwnd_, SW_SHOWNOACTIVATE); + d3d_device_->Present(NULL, NULL, NULL, NULL); + + return true; +} + +D3dRenderer* D3dRenderer::Create(const char* window_title, + size_t width, + size_t height) { + static ATOM wc_atom = 0; + if (wc_atom == 0) { + WNDCLASSA wc = {}; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WindowProc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW); + wc.lpszClassName = kD3DClassName; + + wc_atom = RegisterClassA(&wc); + if (wc_atom == 0) + return false; + } + + D3dRenderer* d3d_renderer = new D3dRenderer(width, height); + if (!d3d_renderer->Init(window_title)) { + delete d3d_renderer; + return NULL; + } + + return d3d_renderer; +} + +void D3dRenderer::Resize(size_t width, size_t height) { + width_ = width; + height_ = height; + IDirect3DTexture9* texture; + + d3d_device_->CreateTexture(static_cast<UINT>(width_), + static_cast<UINT>(height_), + 1, + 0, + D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &texture, + NULL); + texture_ = texture; + texture->Release(); + + // Vertices for the video frame to be rendered to. + static const D3dCustomVertex rect[] = { + {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f}, + {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, -1.0f, 0.0f, 1.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f, 0.0f}, + }; + + void* buf_data; + if (vertex_buffer_->Lock(0, 0, &buf_data, 0) != D3D_OK) + return; + + memcpy(buf_data, &rect, sizeof(rect)); + vertex_buffer_->Unlock(); +} + +void D3dRenderer::OnFrame(const webrtc::VideoFrame& frame) { + if (static_cast<size_t>(frame.width()) != width_ || + static_cast<size_t>(frame.height()) != height_) { + Resize(static_cast<size_t>(frame.width()), + static_cast<size_t>(frame.height())); + } + + D3DLOCKED_RECT lock_rect; + if (texture_->LockRect(0, &lock_rect, NULL, 0) != D3D_OK) + return; + + ConvertFromI420(frame, VideoType::kARGB, 0, + static_cast<uint8_t*>(lock_rect.pBits)); + texture_->UnlockRect(0); + + d3d_device_->BeginScene(); + d3d_device_->SetFVF(D3DFVF_CUSTOMVERTEX); + d3d_device_->SetStreamSource(0, vertex_buffer_, 0, sizeof(D3dCustomVertex)); + d3d_device_->SetTexture(0, texture_); + d3d_device_->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + d3d_device_->EndScene(); + + d3d_device_->Present(NULL, NULL, NULL, NULL); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/test/win/d3d_renderer.h b/third_party/libwebrtc/webrtc/test/win/d3d_renderer.h new file mode 100644 index 0000000000..68a5a802f2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/win/d3d_renderer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef TEST_WIN_D3D_RENDERER_H_ +#define TEST_WIN_D3D_RENDERER_H_ + +#include <Windows.h> +#include <d3d9.h> +#pragma comment(lib, "d3d9.lib") // located in DirectX SDK + +#include "rtc_base/scoped_ref_ptr.h" +#include "test/video_renderer.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace test { + +class D3dRenderer : public VideoRenderer { + public: + static D3dRenderer* Create(const char* window_title, size_t width, + size_t height); + virtual ~D3dRenderer(); + + void OnFrame(const webrtc::VideoFrame& frame) override; + + private: + D3dRenderer(size_t width, size_t height); + + static LRESULT WINAPI WindowProc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam); + bool Init(const char* window_title); + void Resize(size_t width, size_t height); + void Destroy(); + + size_t width_, height_; + + HWND hwnd_; + rtc::scoped_refptr<IDirect3D9> d3d_; + rtc::scoped_refptr<IDirect3DDevice9> d3d_device_; + + rtc::scoped_refptr<IDirect3DTexture9> texture_; + rtc::scoped_refptr<IDirect3DVertexBuffer9> vertex_buffer_; +}; +} // namespace test +} // namespace webrtc + +#endif // TEST_WIN_D3D_RENDERER_H_ diff --git a/third_party/libwebrtc/webrtc/test/win/run_loop_win.cc b/third_party/libwebrtc/webrtc/test/win/run_loop_win.cc new file mode 100644 index 0000000000..494adc47d6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/test/win/run_loop_win.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/run_loop.h" + +#include <assert.h> + +#include <conio.h> +#include <stdio.h> +#include <Windows.h> + +namespace webrtc { +namespace test { + +void PressEnterToContinue() { + puts(">> Press ENTER to continue..."); + + MSG msg; + BOOL ret; + while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) { + assert(ret != -1); + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} +} // namespace test +} // namespace webrtc |