diff options
author | Android Chromium Automerger <chromium-automerger@android> | 2014-06-19 21:56:31 +0000 |
---|---|---|
committer | Android Chromium Automerger <chromium-automerger@android> | 2014-06-19 21:56:31 +0000 |
commit | c497bcd46d65650cbafb85ae4e71db44cd656b08 (patch) | |
tree | a38edd8a90c7ca5474ea1165100e59ac82a5a5cb | |
parent | ad3bcf43404f06080840b0787fad7a394e7925d8 (diff) | |
parent | 68f4c7b51ec6434b302de9e97ee01f5ccdb48aa2 (diff) | |
download | webrtc-c497bcd46d65650cbafb85ae4e71db44cd656b08.tar.gz |
Merge third_party/webrtc from https://chromium.googlesource.com/external/webrtc/trunk/webrtc.git at 68f4c7b51ec6434b302de9e97ee01f5ccdb48aa2
This commit was generated by merge_from_chromium.py.
Change-Id: Iedf6d850648d6a5904340109e1f71ce52d44113b
33 files changed, 1930 insertions, 273 deletions
diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 00000000..a86c8a76 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,174 @@ +# 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("//build/config/arm.gni") +import("//build/config/crypto.gni") +import("//build/config/linux/pkg_config.gni") +import("build/webrtc.gni") + +# Contains the defines and includes in common.gypi that are duplicated both as +# target_defaults and direct_dependent_settings. +config("common_inherited_config") { + defines = [] + if (build_with_mozilla) { + defines += [ "WEBRTC_MOZILLA_BUILD" ] + } + if (build_with_chromium) { + defines = [ + "WEBRTC_CHROMIUM_BUILD", + "LOGGING_INSIDE_WEBRTC", + ] + include_dirs = [ + # overrides must be included first as that is the mechanism for + # selecting the override headers in Chromium. + "overrides", + # Allow includes to be prefixed with webrtc/ in case it is not an + # immediate subdirectory of the top-level. + "..", + ] + } + if (is_posix) { + defines += [ "WEBRTC_POSIX" ] + } + if (is_ios) { + defines += [ + "WEBRTC_MAC", + "WEBRTC_IOS", + ] + } + if (is_linux) { + defines += [ "WEBRTC_LINUX" ] + } + if (is_mac) { + defines += [ "WEBRTC_MAC" ] + } + if (is_win) { + defines += [ "WEBRTC_WIN" ] + } + if (is_android) { + defines += [ + "WEBRTC_LINUX", + "WEBRTC_ANDROID", + ] + if (enable_android_opensl) { + defines += [ "WEBRTC_ANDROID_OPENSLES" ] + } + } +} + +pkg_config("dbus-glib") { + packages = [ "dbus-glib-1" ] +} + +config("common_config") { + if (restrict_webrtc_logging) { + defines = [ "WEBRTC_RESTRICT_LOGGING" ] + } + + if (have_dbus_glib) { + defines += [ "HAVE_DBUS_GLIB" ] + # TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h> + # is still not found even if the execution of + # build/config/linux/pkg-config.py dbus-glib-1 returns correct include + # dirs on Linux. + all_dependent_configs = [ "dbus-glib" ] + } + + if (enable_video) { + defines += [ "WEBRTC_MODULE_UTILITY_VIDEO" ] + } + + if (!build_with_chromium) { + if (is_posix) { + # -Wextra is currently disabled in Chromium"s common.gypi. Enable + # for targets that can handle it. For Android/arm64 right now + # there will be an "enumeral and non-enumeral type in conditional + # expression" warning in android_tools/ndk_experimental"s version + # of stlport. + # See: https://code.google.com/p/chromium/issues/detail?id=379699 + if (cpu_arch != "arm64" || !is_android) { + cflags = [ + "-Wextra", + # We need to repeat some flags from Chromium"s common.gypi + # here that get overridden by -Wextra. + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", + "-Wno-strict-overflow", + ] + cflags_cc = [ + "-Wnon-virtual-dtor", + # This is enabled for clang; enable for gcc as well. + "-Woverloaded-virtual", + ] + } + } + + if (is_clang) { + cflags += [ "-Wthread-safety" ] + } + } + + if (cpu_arch == "arm") { + defines += [ "WEBRTC_ARCH_ARM" ] + if (arm_version == 7) { + defines += [ "WEBRTC_ARCH_ARM_V7" ] + if (arm_use_neon) { + defines += [ "WEBRTC_ARCH_ARM_NEON" ] + } else { + defines += [ "WEBRTC_DETECT_ARM_NEON" ] + } + } + } + + if (cpu_arch == "mipsel") { + defines += [ "MIPS32_LE" ] + if (mips_fpu) { + defines += [ "MIPS_FPU_LE" ] + cflags += [ "-mhard-float" ] + } else { + cflags += [ "-msoft-float" ] + } + if (mips_arch_variant == "mips32r2") { + defines += [ "MIPS32_R2_LE" ] + cflags += [ "-mips32r2" ] + cflags_cc += [ "-mips32r2" ] + } + if (mips_dsp_rev == 1) { + defines += [ "MIPS_DSP_R1_LE" ] + cflags += [ "-mdsp" ] + cflags_cc += [ "-mdsp" ] + } else if (mips_dsp_rev == 2) { + defines += [ + "MIPS_DSP_R1_LE", + "MIPS_DSP_R2_LE", + ] + cflags += [ "-mdspr2" ] + cflags_cc += [ "-mdspr2" ] + } + } + + # TODO(kjellander): Handle warnings on Windows where WebRTC differ from the + # default warnings set in build/config/compiler/BUILD.gn. + + if (is_android && is_clang) { + # The Android NDK doesn"t provide optimized versions of these + # functions. Ensure they are disabled for all compilers. + cflags += [ + "-fno-builtin-cos", + "-fno-builtin-sin", + "-fno-builtin-cosf", + "-fno-builtin-sinf", + ] + } +} + +static_library("webrtc") { + deps = [ + "base:webrtc_base", + ] +} diff --git a/base/BUILD.gn b/base/BUILD.gn new file mode 100644 index 00000000..41180901 --- /dev/null +++ b/base/BUILD.gn @@ -0,0 +1,723 @@ +# 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("//build/config/crypto.gni") +import("../build/webrtc.gni") + +config("webrtc_base_config") { + include_dirs = [ + "//third_party/jsoncpp/overrides/include", + "//third_party/jsoncpp/source/include", + ] + + defines = [ + "FEATURE_ENABLE_SSL", + "GTEST_RELATIVE_PATH", + ] + + # TODO(henrike): issue 3307, make webrtc_base build without disabling + # these flags. + cflags_cc = [ "-Wno-non-virtual-dtor" ] +} + +config("webrtc_base_chromium_config") { + defines = [ + "NO_MAIN_THREAD_WRAPPING", + "SSL_USE_NSS", + ] +} + +config("openssl_config") { + defines = [ + "SSL_USE_OPENSSL", + "HAVE_OPENSSL_SSL_H", + ] +} + +config("no_openssl_config") { + defines = [ + "SSL_USE_NSS", + "HAVE_NSS_SSL_H", + "SSL_USE_NSS_RNG", + ] +} + +config("android_config") { + defines = [ "HAVE_OPENSSL_SSL_H" ] +} + +config("no_android_config") { + defines = [ + "HAVE_NSS_SSL_H", + "SSL_USE_NSS_RNG", + ] +} + +config("ios_config") { + ldflags = [ + #"Foundation.framework", # Already included in //build/config:default_libs. + "Security.framework", + "SystemConfiguration.framework", + #"UIKit.framework", # Already included in //build/config:default_libs. + ] +} + +config("mac_config") { + ldflags = [ + "Cocoa.framework", + #"Foundation.framework", # Already included in //build/config:default_libs. + #"IOKit.framework", # Already included in //build/config:default_libs. + #"Security.framework", # Already included in //build/config:default_libs. + "SystemConfiguration.framework", + ] +} + +config("mac_x86_config") { + libs = [ + #"Carbon.framework", # Already included in //build/config:default_libs. + ] +} + +config("linux_system_ssl_config") { + visibility = ":*" # Only targets in this file can depend on this. + + # TODO(kjellander): Find out how to convert GYP include_dirs+ (i.e. insert + # first in the include path?). + include_dirs = [ "//net/third_party/nss/ssl" ] + + configs = [ "//third_party/nss:system_nss_no_ssl_config" ] +} + +# Provides the same functionality as the build/linux/system.gyp:ssl GYP target. +# This cannot be in build/linux/BUILD.gn since targets in build/ are not allowed +# to depend on targets outside of it. This could be replaced by the Chromium +# //crypto:platform target, but as WebRTC currently don't sync src/crypto from +# Chromium, it is not possible today. +config("linux_system_ssl") { + if (use_openssl) { + deps = [ "//third_party/openssl" ] + } else { + deps = [ "//net/third_party/nss/ssl:libssl" ] + + direct_dependent_configs = [ + ":linux_system_ssl_config", + ] + + if (is_clang) { + cflags = [ + # There is a broken header guard in /usr/include/nss/secmod.h: + # https://bugzilla.mozilla.org/show_bug.cgi?id=884072 + "-Wno-header-guard", + ] + } + } +} + +static_library("webrtc_base") { + cflags = [] + cflags_cc = [] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ + "..:common_inherited_config", + "..:common_config", + ":webrtc_base_config", + ] + + direct_dependent_configs = [ + "..:common_inherited_config", + ":webrtc_base_config", + ] + + defines = [ + "LOGGING=1", + "USE_WEBRTC_DEV_BRANCH", + ] + + sources = [ + "asyncfile.cc", + "asyncfile.h", + "asynchttprequest.cc", + "asynchttprequest.h", + "asyncinvoker.cc", + "asyncinvoker.h", + "asyncinvoker-inl.h", + "asyncpacketsocket.h", + "asyncresolverinterface.h", + "asyncsocket.cc", + "asyncsocket.h", + "asynctcpsocket.cc", + "asynctcpsocket.h", + "asyncudpsocket.cc", + "asyncudpsocket.h", + "atomicops.h", + "autodetectproxy.cc", + "autodetectproxy.h", + "bandwidthsmoother.cc", + "bandwidthsmoother.h", + "base64.cc", + "base64.h", + "basicdefs.h", + "basictypes.h", + "bind.h", + "bind.h.pump", + "buffer.h", + "bytebuffer.cc", + "bytebuffer.h", + "byteorder.h", + "callback.h", + "callback.h.pump", + "checks.cc", + "checks.h", + "common.cc", + "common.h", + "constructormagic.h", + "cpumonitor.cc", + "cpumonitor.h", + "crc32.cc", + "crc32.h", + "criticalsection.h", + "cryptstring.h", + "dbus.cc", + "dbus.h", + "diskcache.cc", + "diskcache.h", + "event.cc", + "event.h", + "filelock.cc", + "filelock.h", + "fileutils.cc", + "fileutils.h", + "fileutils_mock.h", + "firewallsocketserver.cc", + "firewallsocketserver.h", + "flags.cc", + "flags.h", + "genericslot.h", + "genericslot.h.pump", + "gunit_prod.h", + "helpers.cc", + "helpers.h", + "httpbase.cc", + "httpbase.h", + "httpclient.cc", + "httpclient.h", + "httpcommon-inl.h", + "httpcommon.cc", + "httpcommon.h", + "httprequest.cc", + "httprequest.h", + "httpserver.cc", + "httpserver.h", + "ifaddrs-android.cc", + "ifaddrs-android.h", + "iosfilesystem.mm", + "ipaddress.cc", + "ipaddress.h", + "json.cc", + "json.h", + "latebindingsymboltable.cc", + "latebindingsymboltable.cc.def", + "latebindingsymboltable.h", + "latebindingsymboltable.h.def", + "libdbusglibsymboltable.cc", + "libdbusglibsymboltable.h", + "linux.cc", + "linux.h", + "linuxfdwalk.c", + "linuxfdwalk.h", + "linuxwindowpicker.cc", + "linuxwindowpicker.h", + "linked_ptr.h", + "logging.cc", + "logging.h", + "macasyncsocket.cc", + "macasyncsocket.h", + "maccocoasocketserver.h", + "maccocoasocketserver.mm", + "maccocoathreadhelper.h", + "maccocoathreadhelper.mm", + "macconversion.cc", + "macconversion.h", + "macsocketserver.cc", + "macsocketserver.h", + "macutils.cc", + "macutils.h", + "macwindowpicker.cc", + "macwindowpicker.h", + "mathutils.h", + "md5.cc", + "md5.h", + "md5digest.h", + "messagedigest.cc", + "messagedigest.h", + "messagehandler.cc", + "messagehandler.h", + "messagequeue.cc", + "messagequeue.h", + "multipart.cc", + "multipart.h", + "natserver.cc", + "natserver.h", + "natsocketfactory.cc", + "natsocketfactory.h", + "nattypes.cc", + "nattypes.h", + "nethelpers.cc", + "nethelpers.h", + "network.cc", + "network.h", + "nssidentity.cc", + "nssidentity.h", + "nssstreamadapter.cc", + "nssstreamadapter.h", + "nullsocketserver.h", + "openssl.h", + "openssladapter.cc", + "openssladapter.h", + "openssldigest.cc", + "openssldigest.h", + "opensslidentity.cc", + "opensslidentity.h", + "opensslstreamadapter.cc", + "opensslstreamadapter.h", + "optionsfile.cc", + "optionsfile.h", + "pathutils.cc", + "pathutils.h", + "physicalsocketserver.cc", + "physicalsocketserver.h", + "posix.cc", + "posix.h", + "profiler.cc", + "profiler.h", + "proxydetect.cc", + "proxydetect.h", + "proxyinfo.cc", + "proxyinfo.h", + "proxyserver.cc", + "proxyserver.h", + "ratelimiter.cc", + "ratelimiter.h", + "ratetracker.cc", + "ratetracker.h", + "refcount.h", + "referencecountedsingletonfactory.h", + "rollingaccumulator.h", + "schanneladapter.cc", + "schanneladapter.h", + "scoped_autorelease_pool.h", + "scoped_autorelease_pool.mm", + "scoped_ptr.h", + "scoped_ref_ptr.h", + "scopedptrcollection.h", + "sec_buffer.h", + "sha1.cc", + "sha1.h", + "sha1digest.h", + "sharedexclusivelock.cc", + "sharedexclusivelock.h", + "signalthread.cc", + "signalthread.h", + "sigslot.h", + "sigslotrepeater.h", + "socket.h", + "socketadapters.cc", + "socketadapters.h", + "socketaddress.cc", + "socketaddress.h", + "socketaddresspair.cc", + "socketaddresspair.h", + "socketfactory.h", + "socketpool.cc", + "socketpool.h", + "socketserver.h", + "socketstream.cc", + "socketstream.h", + "ssladapter.cc", + "ssladapter.h", + "sslconfig.h", + "sslfingerprint.cc", + "sslfingerprint.h", + "sslidentity.cc", + "sslidentity.h", + "sslroots.h", + "sslsocketfactory.cc", + "sslsocketfactory.h", + "sslstreamadapter.cc", + "sslstreamadapter.h", + "sslstreamadapterhelper.cc", + "sslstreamadapterhelper.h", + "stream.cc", + "stream.h", + "stringdigest.h", + "stringencode.cc", + "stringencode.h", + "stringutils.cc", + "stringutils.h", + "systeminfo.cc", + "systeminfo.h", + "task.cc", + "task.h", + "taskparent.cc", + "taskparent.h", + "taskrunner.cc", + "taskrunner.h", + "testclient.cc", + "testclient.h", + "thread.cc", + "thread.h", + "timeutils.cc", + "timeutils.h", + "timing.cc", + "timing.h", + "transformadapter.cc", + "transformadapter.h", + "unixfilesystem.cc", + "unixfilesystem.h", + "urlencode.cc", + "urlencode.h", + "versionparsing.cc", + "versionparsing.h", + "virtualsocketserver.cc", + "virtualsocketserver.h", + "win32.cc", + "win32.h", + "win32filesystem.cc", + "win32filesystem.h", + "win32regkey.cc", + "win32regkey.h", + "win32securityerrors.cc", + "win32socketinit.cc", + "win32socketinit.h", + "win32socketserver.cc", + "win32socketserver.h", + "win32window.cc", + "win32window.h", + "win32windowpicker.cc", + "win32windowpicker.h", + "window.h", + "windowpicker.h", + "windowpickerfactory.h", + "winfirewall.cc", + "winfirewall.h", + "winping.cc", + "winping.h", + "worker.cc", + "worker.h", + ] + + if (build_with_chromium) { + sources += [ + "../overrides/webrtc/base/basictypes.h", + "../overrides/webrtc/base/constructormagic.h", + "../overrides/webrtc/base/logging.cc", + "../overrides/webrtc/base/logging.h", + ] + if (is_win) { + sources += [ "../overrides/webrtc/base/win32socketinit.cc" ] + } + sources -= [ + "asyncinvoker.cc", + "asyncinvoker.h", + "asyncinvoker-inl.h", + "asyncresolverinterface.h", + "atomicops.h", + "bandwidthsmoother.cc", + "bandwidthsmoother.h", + "basictypes.h", + "bind.h", + "bind.h.pump", + "buffer.h", + "callback.h", + "callback.h.pump", + "constructormagic.h", + "dbus.cc", + "dbus.h", + "filelock.cc", + "filelock.h", + "fileutils_mock.h", + "genericslot.h", + "genericslot.h.pump", + "httpserver.cc", + "httpserver.h", + "json.cc", + "json.h", + "latebindingsymboltable.cc", + "latebindingsymboltable.cc.def", + "latebindingsymboltable.h", + "latebindingsymboltable.h.def", + "libdbusglibsymboltable.cc", + "libdbusglibsymboltable.h", + "linuxfdwalk.c", + "linuxfdwalk.h", + "linuxwindowpicker.cc", + "linuxwindowpicker.h", + "logging.cc", + "logging.h", + #"macasyncsocket.cc", + #"macasyncsocket.h", + #"maccocoasocketserver.h", + #"maccocoasocketserver.mm", + #"macsocketserver.cc", + #"macsocketserver.h", + #"macwindowpicker.cc", + #"macwindowpicker.h", + "mathutils.h", + "multipart.cc", + "multipart.h", + "natserver.cc", + "natserver.h", + "natsocketfactory.cc", + "natsocketfactory.h", + "nattypes.cc", + "nattypes.h", + "openssl.h", + "optionsfile.cc", + "optionsfile.h", + "posix.cc", + "posix.h", + "profiler.cc", + "profiler.h", + "proxyserver.cc", + "proxyserver.h", + "refcount.h", + "referencecountedsingletonfactory.h", + "rollingaccumulator.h", + #"safe_conversions.h", + #"safe_conversions_impl.h", + "scopedptrcollection.h", + "scoped_ref_ptr.h", + "sec_buffer.h", + "sharedexclusivelock.cc", + "sharedexclusivelock.h", + "sslconfig.h", + "sslroots.h", + "stringdigest.h", + #"testbase64.h", + "testclient.cc", + "testclient.h", + #"testutils.h", + "transformadapter.cc", + "transformadapter.h", + "versionparsing.cc", + "versionparsing.h", + "virtualsocketserver.cc", + "virtualsocketserver.h", + #"win32regkey.cc", + #"win32regkey.h", + #"win32socketinit.cc", + #"win32socketinit.h", + #"win32socketserver.cc", + #"win32socketserver.h", + #"win32toolhelp.h", + "window.h", + "windowpickerfactory.h", + "windowpicker.h", + ] + + include_dirs = [ + "../overrides", + "../../openssl/openssl/include", + ] + + direct_dependent_configs += [ ":webrtc_base_chromium_config" ] + } else { + if (is_win) { + sources += [ + "diskcache_win32.cc", + "diskcache_win32.h", + ] + } + + deps = [ "//third_party/jsoncpp" ] + } + + # TODO(henrike): issue 3307, make webrtc_base build without disabling + # these flags. + cflags += [ + "-Wno-extra", + "-Wno-all", + ] + cflags_cc += [ "-Wno-non-virtual-dtor" ] + + if (use_openssl) { + direct_dependent_configs += [ ":openssl_config" ] + + deps = [ "//third_party/openssl" ] + } else { + direct_dependent_configs += [ ":no_openssl_config" ] + } + + if (is_android) { + direct_dependent_configs += [ ":android_config" ] + + libs = [ + "log", + "GLESv2" + ] + } else { + direct_dependent_configs += [ ":no_android_config" ] + + sources -= [ + "ifaddrs-android.cc", + "ifaddrs-android.h", + ] + } + + if (is_ios) { + all_dependent_configs += [ ":ios_config" ] + + deps = [ "//net/third_party/nss/ssl:libssl" ] + } + + if (is_linux) { + libs = [ + "crypto", + "dl", + "rt", + "Xext", + "X11", + "Xcomposite", + "Xrender", + ] + configs += [ "//third_party/nss:system_nss_no_ssl_config" ] + } else { + sources -= [ + "dbus.cc", + "dbus.h", + "libdbusglibsymboltable.cc", + "libdbusglibsymboltable.h", + "linuxfdwalk.c", + "linuxfdwalk.h", + "linuxwindowpicker.cc", + "linuxwindowpicker.h", + ] + } + + if (is_mac) { + all_dependent_configs = [ ":mac_config" ] + + libs = [ + "crypto", # $(SDKROOT)/usr/lib/libcrypto.dylib + "ssl", # $(SDKROOT)/usr/lib/libssl.dylib + ] + if (cpu_arch == "x86") { + all_dependent_configs += [ ":mac_x86_config" ] + } + } else { + sources -= [ + "macasyncsocket.cc", + "macasyncsocket.h", + "maccocoasocketserver.h", + #"maccocoasocketserver.mm", # Seems to be excluded by default with GN. + "macconversion.cc", + "macconversion.h", + "macsocketserver.cc", + "macsocketserver.h", + "macutils.cc", + "macutils.h", + "macwindowpicker.cc", + "macwindowpicker.h", + ] + } + + if (is_win) { + libs = [ + "crypt32.lib", + "iphlpapi.lib", + "secur32.lib", + ] + + cflags += [ + # Suppress warnings about WIN32_LEAN_AND_MEAN. + "/wd4005", + "/wd4703", + ] + + defines += [ "_CRT_NONSTDC_NO_DEPRECATE" ] + } else { + sources -= [ + "schanneladapter.cc", + "schanneladapter.h", + "winping.cc", + "winping.h", + "winfirewall.cc", + "winfirewall.h", + # The files below were covered by a regex exclude in GYP. + "win32.cc", + "win32.h", + "win32filesystem.cc", + "win32filesystem.h", + "win32regkey.cc", + "win32regkey.h", + "win32securityerrors.cc", + "win32socketinit.cc", + "win32socketinit.h", + "win32socketserver.cc", + "win32socketserver.h", + "win32window.cc", + "win32window.h", + "win32windowpicker.cc", + "win32windowpicker.h", + ] + } + + if (is_posix) { + if (is_debug) { + defines += [ "_DEBUG" ] + } + } else { + sources -= [ + "latebindingsymboltable.cc", + "latebindingsymboltable.h", + "posix.cc", + "posix.h", + "unixfilesystem.cc", + "unixfilesystem.h", + ] + } + + if (is_ios || (is_mac && cpu_arch != "x86")) { + defines += [ "CARBON_DEPRECATED=YES" ] + } + + if (is_ios || !is_posix) { + sources -= [ + "openssl.h", + "openssladapter.cc", + "openssladapter.h", + "openssldigest.cc", + "openssldigest.h", + "opensslidentity.cc", + "opensslidentity.h", + "opensslstreamadapter.cc", + "opensslstreamadapter.h", + ] + } + + if (!is_linux && !is_android) { + sources -= [ + "linux.cc", + "linux.h", + ] + } + + if (is_mac || is_ios || is_win) { + deps += [ + "//net/third_party/nss/ssl:libssl", + "//third_party/nss:nspr", + "//third_party/nss:nss", + ] + } + + if (is_posix && !is_mac && !is_ios && !is_android) { + configs += [ ":linux_system_ssl" ] + } +} diff --git a/base/base.gyp b/base/base.gyp index 5cb1fd9b..330ea82a 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -452,8 +452,22 @@ ], }, }, { - 'dependencies': [ - '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp', + 'conditions': [ + ['build_json==1', { + 'dependencies': [ + '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp', + ], + }, { + 'include_dirs': [ + '<(json_root)', + ], + 'defines': [ + # When defined changes the include path for json.h to where it + # is expected to be when building json outside of the standalone + # build. + 'WEBRTC_EXTERNAL_JSON', + ], + }], ], 'sources!': [ '../overrides/webrtc/base/basictypes.h', @@ -474,8 +488,16 @@ 'HAVE_OPENSSL_SSL_H', ], }, - 'dependencies': [ - '<(DEPTH)/third_party/openssl/openssl.gyp:openssl', + 'conditions': [ + ['build_ssl==1', { + 'dependencies': [ + '<(DEPTH)/third_party/openssl/openssl.gyp:openssl', + ], + }, { + 'include_dirs': [ + '<(ssl_root)', + ], + }], ], }, { 'defines': [ @@ -533,8 +555,16 @@ ], }, }, - 'dependencies': [ - '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl', + 'conditions': [ + ['build_ssl==1', { + 'dependencies': [ + '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl', + ] + }, { + 'include_dirs': [ + '<(ssl_root)', + ], + }], ], }], ['OS=="linux"', { @@ -693,15 +723,31 @@ ], }], ['OS == "mac" or OS == "ios" or OS == "win"', { - 'dependencies': [ - '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl', - '<(DEPTH)/third_party/nss/nss.gyp:nspr', - '<(DEPTH)/third_party/nss/nss.gyp:nss', + 'conditions': [ + ['build_ssl==1', { + 'dependencies': [ + '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl', + '<(DEPTH)/third_party/nss/nss.gyp:nspr', + '<(DEPTH)/third_party/nss/nss.gyp:nss', + ], + }, { + 'include_dirs': [ + '<(ssl_root)', + ], + }], ], }], ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { - 'dependencies': [ - '<(DEPTH)/build/linux/system.gyp:ssl', + 'conditions': [ + ['build_ssl==1', { + 'dependencies': [ + '<(DEPTH)/build/linux/system.gyp:ssl', + ], + }, { + 'include_dirs': [ + '<(ssl_root)', + ], + }], ], }], ], diff --git a/base/json.h b/base/json.h index a8f76be1..9d45ded9 100644 --- a/base/json.h +++ b/base/json.h @@ -14,7 +14,7 @@ #include <string> #include <vector> -#if !defined(WEBRTC_EXTERNAL) +#if !defined(WEBRTC_EXTERNAL_JSON) #include "json/json.h" #else #include "third_party/jsoncpp/json.h" diff --git a/base/profiler_unittest.cc b/base/profiler_unittest.cc index 5a607914..8f4421e9 100644 --- a/base/profiler_unittest.cc +++ b/base/profiler_unittest.cc @@ -30,13 +30,15 @@ namespace rtc { TEST(ProfilerTest, TestFunction) { ASSERT_TRUE(Profiler::Instance()->Clear()); + // Profile a long-running function. const char* function_name = TestFunc(); const ProfilerEvent* event = Profiler::Instance()->GetEvent(function_name); ASSERT_TRUE(event != NULL); EXPECT_FALSE(event->is_started()); EXPECT_EQ(1, event->event_count()); - EXPECT_NEAR(kWaitSec, event->mean(), kTolerance); + EXPECT_NEAR(kWaitSec, event->mean(), kTolerance * 3); + // Run it a second time. TestFunc(); EXPECT_FALSE(event->is_started()); @@ -78,7 +80,9 @@ TEST(ProfilerTest, TestScopedEvents) { // Check the result. EXPECT_FALSE(event2->is_started()); EXPECT_EQ(1, event2->event_count()); - EXPECT_NEAR(kEvent2WaitSec, event2->mean(), kTolerance); + + // The difference here can be as much as 0.33, so we need high tolerance. + EXPECT_NEAR(kEvent2WaitSec, event2->mean(), kTolerance * 4); // Make sure event1 is unchanged. EXPECT_FALSE(event1->is_started()); EXPECT_EQ(1, event1->event_count()); diff --git a/build/common.gypi b/build/common.gypi index da96c1d3..cbc398e4 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -54,6 +54,12 @@ 'webrtc_vp8_dir%': '<(webrtc_vp8_dir)', 'include_opus%': '<(include_opus)', 'rbe_components_path%': '<(rbe_components_path)', + 'external_libraries%': '0', + 'json_root%': '<(DEPTH)/third_party/jsoncpp/source/include/', + # openssl needs to be defined or gyp will complain. Is is only used when + # when providing external libraries so just use current directory as a + # placeholder. + 'ssl_root%': '.', # The Chromium common.gypi we use treats all gyp files without # chromium_code==1 as third party code. This disables many of the @@ -85,9 +91,11 @@ 'enable_protobuf%': 1, # Disable these to not build components which can be externally provided. + 'build_json%': 1, 'build_libjpeg%': 1, 'build_libyuv%': 1, 'build_libvpx%': 1, + 'build_ssl%': 1, # Disable by default 'have_dbus_glib%': 0, diff --git a/build/webrtc.gni b/build/webrtc.gni new file mode 100644 index 00000000..e269a262 --- /dev/null +++ b/build/webrtc.gni @@ -0,0 +1,57 @@ +# 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. + +declare_args() { + # Assume Chromium build for now, since that's the priority case for getting GN + # up and running with WebRTC. + build_with_chromium = true + build_with_libjingle = true + + if (build_with_libjingle) { + include_tests = false + restrict_webrtc_logging = true + } else { + include_tests = true + restrict_webrtc_logging = false + } + + # Adds video support to dependencies shared by voice and video engine. + # This should normally be enabled; the intended use is to disable only + # when building voice engine exclusively. + enable_video = true + + # Selects fixed-point code where possible. + prefer_fixed_point = false + + build_libjpeg = true + # Enables the use of protocol buffers for debug recordings. + enable_protobuf = true + + # Disable by default. + have_dbus_glib = false + + # Enable to use the Mozilla internal settings. + build_with_mozilla = false + + # Define MIPS architecture variant, MIPS DSP variant and MIPS FPU + # This may be subject to change in accordance to Chromium's MIPS flags + mips_arch_variant = "mips32r1" + mips_dsp_rev = 0 + mips_fpu = true + + enable_android_opensl = true + + if (is_ios) { + build_libjpeg = false + enable_protobuf = false + } + + if (cpu_arch == "arm") { + prefer_fixed_point = true + } +} diff --git a/modules/audio_coding/codecs/isac/fix/source/isacfix.c b/modules/audio_coding/codecs/isac/fix/source/isacfix.c index 688ec07a..76359080 100644 --- a/modules/audio_coding/codecs/isac/fix/source/isacfix.c +++ b/modules/audio_coding/codecs/isac/fix/source/isacfix.c @@ -608,15 +608,11 @@ int16_t WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_MainStruct *ISAC_main_inst, { ISACFIX_SubStruct *ISAC_inst; Bitstr_dec streamdata; - uint16_t partOfStream[5]; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; - /* Set stream pointer to point at partOfStream */ - streamdata.stream = (uint16_t *)partOfStream; - /* typecast pointer to real structure */ ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; @@ -696,15 +692,11 @@ int16_t WebRtcIsacfix_UpdateBwEstimate(ISACFIX_MainStruct *ISAC_main_inst, { ISACFIX_SubStruct *ISAC_inst; Bitstr_dec streamdata; - uint16_t partOfStream[5]; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; - /* Set stream pointer to point at partOfStream */ - streamdata.stream = (uint16_t *)partOfStream; - /* typecast pointer to real structure */ ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; @@ -811,7 +803,6 @@ int16_t WebRtcIsacfix_Decode(ISACFIX_MainStruct *ISAC_main_inst, return -1; } - (ISAC_inst->ISACdec_obj.bitstr_obj).stream = (uint16_t *)encoded; ISAC_inst->ISACdec_obj.bitstr_obj.stream_size = (len + 1) >> 1; /* convert bitstream from int16_t to bytes */ @@ -913,7 +904,7 @@ int16_t WebRtcIsacfix_DecodeNb(ISACFIX_MainStruct *ISAC_main_inst, return -1; } - (ISAC_inst->ISACdec_obj.bitstr_obj).stream = (uint16_t *)encoded; + ISAC_inst->ISACdec_obj.bitstr_obj.stream_size = (len + 1) >> 1; /* convert bitstream from int16_t to bytes */ #ifndef WEBRTC_ARCH_BIG_ENDIAN @@ -1288,15 +1279,11 @@ int16_t WebRtcIsacfix_ReadFrameLen(const int16_t* encoded, int16_t* frameLength) { Bitstr_dec streamdata; - uint16_t partOfStream[5]; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; - /* Set stream pointer to point at partOfStream */ - streamdata.stream = (uint16_t *)partOfStream; - streamdata.W_upper = 0xFFFFFFFF; streamdata.streamval = 0; streamdata.stream_index = 0; @@ -1337,15 +1324,11 @@ int16_t WebRtcIsacfix_ReadBwIndex(const int16_t* encoded, int16_t* rateIndex) { Bitstr_dec streamdata; - uint16_t partOfStream[5]; #ifndef WEBRTC_ARCH_BIG_ENDIAN int k; #endif int16_t err; - /* Set stream pointer to point at partOfStream */ - streamdata.stream = (uint16_t *)partOfStream; - streamdata.W_upper = 0xFFFFFFFF; streamdata.streamval = 0; streamdata.stream_index = 0; diff --git a/modules/audio_coding/codecs/isac/fix/source/structs.h b/modules/audio_coding/codecs/isac/fix/source/structs.h index b4d2bd89..bd20ba01 100644 --- a/modules/audio_coding/codecs/isac/fix/source/structs.h +++ b/modules/audio_coding/codecs/isac/fix/source/structs.h @@ -26,7 +26,7 @@ /* Bitstream struct for decoder */ typedef struct Bitstreamstruct_dec { - uint16_t *stream; /* Pointer to bytestream to decode */ + uint16_t stream[STREAM_MAXW16_60MS]; /* Array bytestream to decode */ uint32_t W_upper; /* Upper boundary of interval W */ uint32_t streamval; uint16_t stream_index; /* Index to the current position in bytestream */ diff --git a/modules/audio_coding/neteq/neteq.gypi b/modules/audio_coding/neteq/neteq.gypi index ccdc9f5d..21ccee41 100644 --- a/modules/audio_coding/neteq/neteq.gypi +++ b/modules/audio_coding/neteq/neteq.gypi @@ -182,10 +182,13 @@ 'tools', ], 'sources': [ + 'tools/audio_checksum.h', 'tools/audio_loop.cc', 'tools/audio_loop.h', + 'tools/audio_sink.h', 'tools/input_audio_file.cc', 'tools/input_audio_file.h', + 'tools/output_audio_file.h', 'tools/packet.cc', 'tools/packet.h', 'tools/packet_source.h', diff --git a/modules/audio_coding/neteq/tools/audio_checksum.h b/modules/audio_coding/neteq/tools/audio_checksum.h new file mode 100644 index 00000000..ac568265 --- /dev/null +++ b/modules/audio_coding/neteq/tools/audio_checksum.h @@ -0,0 +1,60 @@ +/* + * 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 WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_CHECKSUM_H_ +#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_CHECKSUM_H_ + +#include <string> + +#include "webrtc/base/constructormagic.h" +#include "webrtc/base/md5digest.h" +#include "webrtc/base/stringencode.h" +#include "webrtc/modules/audio_coding/neteq/tools/audio_sink.h" +#include "webrtc/system_wrappers/interface/compile_assert.h" +#include "webrtc/typedefs.h" + +namespace webrtc { +namespace test { + +class AudioChecksum : public AudioSink { + public: + AudioChecksum() : finished_(false) {} + + virtual bool WriteArray(const int16_t* audio, size_t num_samples) OVERRIDE { + if (finished_) + return false; + +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Big-endian gives a different checksum" +#endif + checksum_.Update(audio, num_samples * sizeof(*audio)); + return true; + } + + // Finalizes the computations, and returns the checksum. + std::string Finish() { + if (!finished_) { + finished_ = true; + checksum_.Finish(checksum_result_, rtc::Md5Digest::kSize); + } + return rtc::hex_encode(checksum_result_, rtc::Md5Digest::kSize); + } + + private: + rtc::Md5Digest checksum_; + char checksum_result_[rtc::Md5Digest::kSize]; + bool finished_; + + DISALLOW_COPY_AND_ASSIGN(AudioChecksum); +}; + +} // namespace test +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_CHECKSUM_H_ diff --git a/modules/audio_coding/neteq/tools/audio_sink.h b/modules/audio_coding/neteq/tools/audio_sink.h new file mode 100644 index 00000000..5743c364 --- /dev/null +++ b/modules/audio_coding/neteq/tools/audio_sink.h @@ -0,0 +1,46 @@ +/* + * 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 WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_SINK_H_ +#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_SINK_H_ + +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/typedefs.h" + +namespace webrtc { +namespace test { + +// Interface class for an object receiving raw output audio from test +// applications. +class AudioSink { + public: + AudioSink() {} + virtual ~AudioSink() {} + + // Writes |num_samples| from |audio| to the AudioSink. Returns true if + // successful, otherwise false. + virtual bool WriteArray(const int16_t* audio, size_t num_samples) = 0; + + // Writes |audio_frame| to the AudioSink. Returns true if successful, + // otherwise false. + bool WriteAudioFrame(const AudioFrame& audio_frame) { + return WriteArray( + audio_frame.data_, + audio_frame.samples_per_channel_ * audio_frame.num_channels_); + } + + private: + DISALLOW_COPY_AND_ASSIGN(AudioSink); +}; + +} // namespace test +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_SINK_H_ diff --git a/modules/audio_coding/neteq/tools/output_audio_file.h b/modules/audio_coding/neteq/tools/output_audio_file.h new file mode 100644 index 00000000..1d612807 --- /dev/null +++ b/modules/audio_coding/neteq/tools/output_audio_file.h @@ -0,0 +1,50 @@ +/* + * 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 WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_OUTPUT_AUDIO_FILE_H_ +#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_OUTPUT_AUDIO_FILE_H_ + +#include <assert.h> +#include <stdio.h> +#include <string> + +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/audio_coding/neteq/tools/audio_sink.h" + +namespace webrtc { +namespace test { + +class OutputAudioFile : public AudioSink { + public: + // Creates an OutputAudioFile, opening a file named |file_name| for writing. + // The file format is 16-bit signed host-endian PCM. + explicit OutputAudioFile(const std::string& file_name) { + out_file_ = fopen(file_name.c_str(), "wb"); + } + + virtual ~OutputAudioFile() { + if (out_file_) + fclose(out_file_); + } + + virtual bool WriteArray(const int16_t* audio, size_t num_samples) OVERRIDE { + assert(out_file_); + return fwrite(audio, sizeof(*audio), num_samples, out_file_) == num_samples; + } + + private: + FILE* out_file_; + + DISALLOW_COPY_AND_ASSIGN(OutputAudioFile); +}; + +} // namespace test +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_OUTPUT_AUDIO_FILE_H_ diff --git a/modules/audio_coding/neteq/tools/packet_source.h b/modules/audio_coding/neteq/tools/packet_source.h index c539b8e8..669bc14e 100644 --- a/modules/audio_coding/neteq/tools/packet_source.h +++ b/modules/audio_coding/neteq/tools/packet_source.h @@ -24,7 +24,8 @@ class PacketSource { PacketSource() {} virtual ~PacketSource() {} - // Returns a pointer to the next packet. + // Returns a pointer to the next packet. Returns NULL if the source is + // depleted, or if an error occurred. virtual Packet* NextPacket() = 0; private: diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.cc b/modules/audio_coding/neteq/tools/rtp_file_source.cc index 82786353..6490d468 100644 --- a/modules/audio_coding/neteq/tools/rtp_file_source.cc +++ b/modules/audio_coding/neteq/tools/rtp_file_source.cc @@ -47,47 +47,54 @@ bool RtpFileSource::RegisterRtpHeaderExtension(RTPExtensionType type, } Packet* RtpFileSource::NextPacket() { - uint16_t length; - if (fread(&length, sizeof(uint16_t), 1, in_file_) == 0) { - assert(false); - return NULL; - } - length = ntohs(length); - - uint16_t plen; - if (fread(&plen, sizeof(uint16_t), 1, in_file_) == 0) { - assert(false); - return NULL; - } - plen = ntohs(plen); - - uint32_t offset; - if (fread(&offset, sizeof(uint32_t), 1, in_file_) == 0) { - assert(false); - return NULL; - } - - // Use length here because a plen of 0 specifies RTCP. - size_t packet_size_bytes = length - kPacketHeaderSize; - if (packet_size_bytes <= 0) { - // May be an RTCP packet. - return NULL; - } - uint8_t* packet_memory = new uint8_t[packet_size_bytes]; - if (fread(packet_memory, 1, packet_size_bytes, in_file_) != - packet_size_bytes) { - assert(false); - delete[] packet_memory; - return NULL; - } - Packet* packet = new Packet( - packet_memory, packet_size_bytes, plen, ntohl(offset), *parser_.get()); - if (!packet->valid_header()) { - assert(false); - delete packet; - return NULL; + while (!EndOfFile()) { + uint16_t length; + if (fread(&length, sizeof(length), 1, in_file_) == 0) { + assert(false); + return NULL; + } + length = ntohs(length); + + uint16_t plen; + if (fread(&plen, sizeof(plen), 1, in_file_) == 0) { + assert(false); + return NULL; + } + plen = ntohs(plen); + + uint32_t offset; + if (fread(&offset, sizeof(offset), 1, in_file_) == 0) { + assert(false); + return NULL; + } + offset = ntohl(offset); + + // Use length here because a plen of 0 specifies RTCP. + assert(length >= kPacketHeaderSize); + size_t packet_size_bytes = length - kPacketHeaderSize; + if (packet_size_bytes == 0) { + // May be an RTCP packet. + // Read the next one. + continue; + } + scoped_ptr<uint8_t> packet_memory(new uint8_t[packet_size_bytes]); + if (fread(packet_memory.get(), 1, packet_size_bytes, in_file_) != + packet_size_bytes) { + assert(false); + return NULL; + } + scoped_ptr<Packet> packet(new Packet(packet_memory.release(), + packet_size_bytes, + plen, + offset, + *parser_.get())); + if (!packet->valid_header()) { + assert(false); + return NULL; + } + return packet.release(); } - return packet; + return NULL; } bool RtpFileSource::EndOfFile() const { diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.h b/modules/audio_coding/neteq/tools/rtp_file_source.h index 527018e1..6b92a886 100644 --- a/modules/audio_coding/neteq/tools/rtp_file_source.h +++ b/modules/audio_coding/neteq/tools/rtp_file_source.h @@ -37,7 +37,8 @@ class RtpFileSource : public PacketSource { // Registers an RTP header extension and binds it to |id|. virtual bool RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); - // Returns a pointer to the next packet. + // Returns a pointer to the next packet. Returns NULL if end of file was + // reached, or if a the data was corrupt. virtual Packet* NextPacket(); // Returns true if the end of file has been reached. diff --git a/modules/audio_processing/aec/aec_core_neon.c b/modules/audio_processing/aec/aec_core_neon.c index d751a4b1..cec0a7e3 100644 --- a/modules/audio_processing/aec/aec_core_neon.c +++ b/modules/audio_processing/aec/aec_core_neon.c @@ -18,6 +18,7 @@ #include <arm_neon.h> #include <math.h> +#include <string.h> // memset #include "webrtc/modules/audio_processing/aec/aec_core_internal.h" #include "webrtc/modules/audio_processing/aec/aec_rdft.h" @@ -25,6 +26,85 @@ enum { kShiftExponentIntoTopMantissa = 8 }; enum { kFloatExponentShift = 23 }; +__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) { + return aRe * bRe - aIm * bIm; +} + +static void FilterAdaptationNEON(AecCore* aec, + float* fft, + float ef[2][PART_LEN1]) { + int i; + const int num_partitions = aec->num_partitions; + for (i = 0; i < num_partitions; i++) { + int xPos = (i + aec->xfBufBlockPos) * PART_LEN1; + int pos = i * PART_LEN1; + int j; + // Check for wrap + if (i + aec->xfBufBlockPos >= num_partitions) { + xPos -= num_partitions * PART_LEN1; + } + + // Process the whole array... + for (j = 0; j < PART_LEN; j += 4) { + // Load xfBuf and ef. + const float32x4_t xfBuf_re = vld1q_f32(&aec->xfBuf[0][xPos + j]); + const float32x4_t xfBuf_im = vld1q_f32(&aec->xfBuf[1][xPos + j]); + const float32x4_t ef_re = vld1q_f32(&ef[0][j]); + const float32x4_t ef_im = vld1q_f32(&ef[1][j]); + // Calculate the product of conjugate(xfBuf) by ef. + // re(conjugate(a) * b) = aRe * bRe + aIm * bIm + // im(conjugate(a) * b)= aRe * bIm - aIm * bRe + const float32x4_t a = vmulq_f32(xfBuf_re, ef_re); + const float32x4_t e = vmlaq_f32(a, xfBuf_im, ef_im); + const float32x4_t c = vmulq_f32(xfBuf_re, ef_im); + const float32x4_t f = vmlsq_f32(c, xfBuf_im, ef_re); + // Interleave real and imaginary parts. + const float32x4x2_t g_n_h = vzipq_f32(e, f); + // Store + vst1q_f32(&fft[2 * j + 0], g_n_h.val[0]); + vst1q_f32(&fft[2 * j + 4], g_n_h.val[1]); + } + // ... and fixup the first imaginary entry. + fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN], + -aec->xfBuf[1][xPos + PART_LEN], + ef[0][PART_LEN], + ef[1][PART_LEN]); + + aec_rdft_inverse_128(fft); + memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN); + + // fft scaling + { + const float scale = 2.0f / PART_LEN2; + const float32x4_t scale_ps = vmovq_n_f32(scale); + for (j = 0; j < PART_LEN; j += 4) { + const float32x4_t fft_ps = vld1q_f32(&fft[j]); + const float32x4_t fft_scale = vmulq_f32(fft_ps, scale_ps); + vst1q_f32(&fft[j], fft_scale); + } + } + aec_rdft_forward_128(fft); + + { + const float wt1 = aec->wfBuf[1][pos]; + aec->wfBuf[0][pos + PART_LEN] += fft[1]; + for (j = 0; j < PART_LEN; j += 4) { + float32x4_t wtBuf_re = vld1q_f32(&aec->wfBuf[0][pos + j]); + float32x4_t wtBuf_im = vld1q_f32(&aec->wfBuf[1][pos + j]); + const float32x4_t fft0 = vld1q_f32(&fft[2 * j + 0]); + const float32x4_t fft4 = vld1q_f32(&fft[2 * j + 4]); + const float32x4x2_t fft_re_im = vuzpq_f32(fft0, fft4); + wtBuf_re = vaddq_f32(wtBuf_re, fft_re_im.val[0]); + wtBuf_im = vaddq_f32(wtBuf_im, fft_re_im.val[1]); + + vst1q_f32(&aec->wfBuf[0][pos + j], wtBuf_re); + vst1q_f32(&aec->wfBuf[1][pos + j], wtBuf_im); + } + aec->wfBuf[1][pos] = wt1; + } + } +} + extern const float WebRtcAec_weightCurve[65]; extern const float WebRtcAec_overDriveCurve[65]; @@ -218,6 +298,7 @@ static void OverdriveAndSuppressNEON(AecCore* aec, } void WebRtcAec_InitAec_neon(void) { + WebRtcAec_FilterAdaptation = FilterAdaptationNEON; WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressNEON; } diff --git a/modules/audio_processing/aec/system_delay_unittest.cc b/modules/audio_processing/aec/system_delay_unittest.cc index e85fc28f..a13d4762 100644 --- a/modules/audio_processing/aec/system_delay_unittest.cc +++ b/modules/audio_processing/aec/system_delay_unittest.cc @@ -248,12 +248,14 @@ TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) { } } -TEST_F(SystemDelayTest, - DISABLED_ON_ANDROID(CorrectDelayAfterStableBufferBuildUp)) { +TEST_F(SystemDelayTest, CorrectDelayAfterStableBufferBuildUp) { // In this test we start by establishing the device buffer size during stable // conditions, but with an empty internal far-end buffer. Once that is done we // verify that the system delay is increased correctly until we have reach an // internal buffer size of 75% of what's been reported. + + // This test assumes the reported delays are used. + WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); for (size_t i = 0; i < kNumSampleRates; i++) { Init(kSampleRateHz[i]); @@ -330,11 +332,14 @@ TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) { } } -TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(CorrectDelayDuringDrift)) { +TEST_F(SystemDelayTest, CorrectDelayDuringDrift) { // This drift test should verify that the system delay is never exceeding the // device buffer. The drift is simulated by decreasing the reported device // buffer size by 1 ms every 100 ms. If the device buffer size goes below 30 // ms we jump (add) 10 ms to give a repeated pattern. + + // This test assumes the reported delays are used. + WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); for (size_t i = 0; i < kNumSampleRates; i++) { Init(kSampleRateHz[i]); RunStableStartup(); @@ -361,13 +366,16 @@ TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(CorrectDelayDuringDrift)) { } } -TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(ShouldRecoverAfterGlitch)) { +TEST_F(SystemDelayTest, ShouldRecoverAfterGlitch) { // This glitch test should verify that the system delay recovers if there is // a glitch in data. The data glitch is constructed as 200 ms of buffering // after which the stable procedure continues. The glitch is never reported by // the device. // The system is said to be in a non-causal state if the difference between // the device buffer and system delay is less than a block (64 samples). + + // This test assumes the reported delays are used. + WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); for (size_t i = 0; i < kNumSampleRates; i++) { Init(kSampleRateHz[i]); RunStableStartup(); diff --git a/modules/audio_processing/test/audio_processing_unittest.cc b/modules/audio_processing/test/audio_processing_unittest.cc index 406c3de5..65c2d8d4 100644 --- a/modules/audio_processing/test/audio_processing_unittest.cc +++ b/modules/audio_processing/test/audio_processing_unittest.cc @@ -827,7 +827,7 @@ TEST_F(ApmTest, EchoCancellation) { EXPECT_FALSE(apm_->echo_cancellation()->aec_core() != NULL); } -TEST_F(ApmTest, DISABLED_ON_ANDROID(EchoCancellationReportsCorrectDelays)) { +TEST_F(ApmTest, DISABLED_EchoCancellationReportsCorrectDelays) { // Enable AEC only. EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_drift_compensation(false)); @@ -836,6 +836,9 @@ TEST_F(ApmTest, DISABLED_ON_ANDROID(EchoCancellationReportsCorrectDelays)) { EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_delay_logging(true)); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); + Config config; + config.Set<ReportedDelay>(new ReportedDelay(true)); + apm_->SetExtraOptions(config); // Internally in the AEC the amount of lookahead the delay estimation can // handle is 15 blocks and the maximum delay is set to 60 blocks. diff --git a/modules/audio_processing/test/process_test.cc b/modules/audio_processing/test/process_test.cc index 01f9dcec..a36a072c 100644 --- a/modules/audio_processing/test/process_test.cc +++ b/modules/audio_processing/test/process_test.cc @@ -78,6 +78,7 @@ void usage() { printf(" --no_delay_logging\n"); printf(" --aec_suppression_level LEVEL [0 - 2]\n"); printf(" --extended_filter\n"); + printf(" --no_reported_delay\n"); printf("\n -aecm Echo control mobile\n"); printf(" --aecm_echo_path_in_file FILE\n"); printf(" --aecm_echo_path_out_file FILE\n"); @@ -257,6 +258,11 @@ void void_main(int argc, char* argv[]) { config.Set<DelayCorrection>(new DelayCorrection(true)); apm->SetExtraOptions(config); + } else if (strcmp(argv[i], "--no_reported_delay") == 0) { + Config config; + config.Set<ReportedDelay>(new ReportedDelay(false)); + apm->SetExtraOptions(config); + } else if (strcmp(argv[i], "-aecm") == 0) { ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); diff --git a/modules/bitrate_controller/bitrate_controller_impl.cc b/modules/bitrate_controller/bitrate_controller_impl.cc index 48f59b85..cff5dd18 100644 --- a/modules/bitrate_controller/bitrate_controller_impl.cc +++ b/modules/bitrate_controller/bitrate_controller_impl.cc @@ -139,6 +139,21 @@ void BitrateControllerImpl::SetBitrateObserver( it->second->start_bitrate_ = start_bitrate; it->second->min_bitrate_ = min_bitrate; it->second->max_bitrate_ = max_bitrate; + // Set the send-side bandwidth to the max of the sum of start bitrates and + // the current estimate, so that if the user wants to immediately use more + // bandwidth, that can be enforced. + uint32_t sum_start_bitrate = 0; + BitrateObserverConfList::iterator it; + for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); + ++it) { + sum_start_bitrate += it->second->start_bitrate_; + } + uint32_t current_estimate; + uint8_t loss; + uint32_t rtt; + bandwidth_estimation_.CurrentEstimate(¤t_estimate, &loss, &rtt); + bandwidth_estimation_.SetSendBitrate(std::max(sum_start_bitrate, + current_estimate)); } else { // Add new settings. bitrate_observers_.push_back(BitrateObserverConfiguration(observer, @@ -159,12 +174,10 @@ void BitrateControllerImpl::SetBitrateObserver( } void BitrateControllerImpl::UpdateMinMaxBitrate() { - uint32_t sum_start_bitrate = 0; uint32_t sum_min_bitrate = 0; uint32_t sum_max_bitrate = 0; BitrateObserverConfList::iterator it; for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) { - sum_start_bitrate += it->second->start_bitrate_; sum_min_bitrate += it->second->min_bitrate_; sum_max_bitrate += it->second->max_bitrate_; } diff --git a/modules/bitrate_controller/bitrate_controller_unittest.cc b/modules/bitrate_controller/bitrate_controller_unittest.cc index b15eb29d..8523d505 100644 --- a/modules/bitrate_controller/bitrate_controller_unittest.cc +++ b/modules/bitrate_controller/bitrate_controller_unittest.cc @@ -83,6 +83,24 @@ TEST_F(BitrateControllerTest, Basic) { controller_->RemoveBitrateObserver(&bitrate_observer); } +TEST_F(BitrateControllerTest, UpdatingBitrateObserver) { + TestBitrateObserver bitrate_observer; + controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 1500000); + clock_.AdvanceTimeMilliseconds(25); + controller_->Process(); + EXPECT_EQ(200000u, bitrate_observer.last_bitrate_); + + controller_->SetBitrateObserver(&bitrate_observer, 1500000, 100000, 1500000); + clock_.AdvanceTimeMilliseconds(25); + controller_->Process(); + EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_); + + controller_->SetBitrateObserver(&bitrate_observer, 500000, 100000, 1500000); + clock_.AdvanceTimeMilliseconds(25); + controller_->Process(); + EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_); +} + TEST_F(BitrateControllerTest, OneBitrateObserverOneRtcpObserver) { TestBitrateObserver bitrate_observer; controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 300000); diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index fe33e1b7..70fe7174 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -17,11 +17,6 @@ #include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/trace.h" -#ifdef MATLAB -#include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h" -extern MatlabEngine eng; // Global variable defined elsewhere. -#endif - #ifdef _WIN32 // Disable warning C4355: 'this' : used in base member initializer list. #pragma warning(disable : 4355) @@ -66,7 +61,9 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) configuration.outgoing_transport, configuration.audio_messages, configuration.paced_sender), - rtcp_sender_(configuration.id, configuration.audio, configuration.clock, + rtcp_sender_(configuration.id, + configuration.audio, + configuration.clock, configuration.receive_statistics), rtcp_receiver_(configuration.id, configuration.clock, this), clock_(configuration.clock), @@ -83,15 +80,13 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) CriticalSectionWrapper::CreateCriticalSection()), default_module_( static_cast<ModuleRtpRtcpImpl*>(configuration.default_module)), + padding_index_(-1), // Start padding at the first child module. nack_method_(kNackOff), nack_last_time_sent_full_(0), nack_last_seq_number_sent_(0), simulcast_(false), key_frame_req_method_(kKeyFrameReqFirRtp), remote_bitrate_(configuration.remote_bitrate_estimator), -#ifdef MATLAB - , plot1_(NULL), -#endif rtt_stats_(configuration.rtt_stats), critical_section_rtt_(CriticalSectionWrapper::CreateCriticalSection()), rtt_ms_(0) { @@ -121,12 +116,6 @@ ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl() { if (default_module_) { default_module_->DeRegisterChildModule(this); } -#ifdef MATLAB - if (plot1_) { - eng.DeletePlot(plot1_); - plot1_ = NULL; - } -#endif } void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) { @@ -148,7 +137,7 @@ void ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* remove_module) { CriticalSectionScoped double_lock( critical_section_module_ptrs_feedback_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module == remove_module) { @@ -252,8 +241,9 @@ void ModuleRtpRtcpImpl::SetRTXSendStatus(int mode) { rtp_sender_.SetRTXStatus(mode); } -void ModuleRtpRtcpImpl::RTXSendStatus(int* mode, uint32_t* ssrc, - int* payload_type) const { +void ModuleRtpRtcpImpl::RTXSendStatus(int* mode, + uint32_t* ssrc, + int* payload_type) const { rtp_sender_.RTXStatus(mode, ssrc, payload_type); } @@ -372,7 +362,7 @@ int32_t ModuleRtpRtcpImpl::SetCSRCs( // For default we need to update all child modules too. CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { @@ -443,7 +433,7 @@ bool ModuleRtpRtcpImpl::SendingMedia() const { } CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RTPSender& rtp_sender = (*it)->rtp_sender_; if (rtp_sender.SendingMedia()) { @@ -488,7 +478,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData( return -1; } int idx = 0; - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); for (; idx < rtp_video_hdr->simulcastIdx; ++it) { if (it == child_modules_.end()) { return -1; @@ -515,7 +505,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData( fragmentation, rtp_video_hdr); } else { - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); // Send to all "child" modules while (it != child_modules_.end()) { if ((*it)->SendingMedia()) { @@ -546,7 +536,7 @@ bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc, } } else { CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) { return (*it)->rtp_sender_.TimeToSendPacket(sequence_number, @@ -568,13 +558,15 @@ int ModuleRtpRtcpImpl::TimeToSendPadding(int bytes) { } } else { CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); - while (it != child_modules_.end()) { + // Decide what media stream to pad on based on a round-robin scheme. + for (size_t i = 0; i < child_modules_.size(); ++i) { + padding_index_ = (padding_index_ + 1) % child_modules_.size(); // Send padding on one of the modules sending media. - if ((*it)->SendingMedia()) { - return (*it)->rtp_sender_.TimeToSendPadding(bytes); + if (child_modules_[padding_index_]->SendingMedia() && + child_modules_[padding_index_]->rtp_sender_.GetTargetBitrate() > 0) { + return child_modules_[padding_index_]->rtp_sender_.TimeToSendPadding( + bytes); } - ++it; } } return 0; @@ -603,8 +595,7 @@ uint16_t ModuleRtpRtcpImpl::MaxDataPayloadLength() const { if (IsDefaultModule()) { // For default we need to update all child modules too. CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::const_iterator it = - child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { @@ -1001,28 +992,28 @@ void ModuleRtpRtcpImpl::SetTargetSendBitrate( if (IsDefaultModule()) { CriticalSectionScoped lock(critical_section_module_ptrs_.get()); if (simulcast_) { - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); for (size_t i = 0; it != child_modules_.end() && i < stream_bitrates.size(); ++it) { if ((*it)->SendingMedia()) { RTPSender& rtp_sender = (*it)->rtp_sender_; - rtp_sender.SetTargetSendBitrate(stream_bitrates[i]); + rtp_sender.SetTargetBitrate(stream_bitrates[i]); ++i; } } } else { if (stream_bitrates.size() > 1) return; - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); for (; it != child_modules_.end(); ++it) { RTPSender& rtp_sender = (*it)->rtp_sender_; - rtp_sender.SetTargetSendBitrate(stream_bitrates[0]); + rtp_sender.SetTargetBitrate(stream_bitrates[0]); } } } else { if (stream_bitrates.size() > 1) return; - rtp_sender_.SetTargetSendBitrate(stream_bitrates[0]); + rtp_sender_.SetTargetBitrate(stream_bitrates[0]); } } @@ -1054,7 +1045,7 @@ int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication( int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) { if (IsDefaultModule()) { CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { @@ -1084,7 +1075,7 @@ int32_t ModuleRtpRtcpImpl::GenericFECStatus( if (IsDefaultModule()) { // For default we need to check all child modules too. CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { @@ -1118,7 +1109,7 @@ int32_t ModuleRtpRtcpImpl::SetFecParameters( // For default we need to update all child modules too. CriticalSectionScoped lock(critical_section_module_ptrs_.get()); - std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { @@ -1172,8 +1163,7 @@ void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate, if (nack_rate != NULL) *nack_rate = 0; - std::list<ModuleRtpRtcpImpl*>::const_iterator it = - child_modules_.begin(); + std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h index ef00a461..55826b6f 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -21,10 +21,6 @@ #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/test/testsupport/gtest_prod_util.h" -#ifdef MATLAB -class MatlabPlot; -#endif - namespace webrtc { class ModuleRtpRtcpImpl : public RtpRtcp { @@ -426,7 +422,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp { scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_; scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_feedback_; ModuleRtpRtcpImpl* default_module_; - std::list<ModuleRtpRtcpImpl*> child_modules_; + std::vector<ModuleRtpRtcpImpl*> child_modules_; + size_t padding_index_; // Send side NACKMethod nack_method_; @@ -439,10 +436,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp { RemoteBitrateEstimator* remote_bitrate_; -#ifdef MATLAB - MatlabPlot* plot1_; -#endif - RtcpRttStats* rtt_stats_; // The processed RTT from RtcpRttStats. diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc index 4b6fa32f..eb76cfe7 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc @@ -12,13 +12,22 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/common_types.h" +#include "webrtc/modules/pacing/include/mock/mock_paced_sender.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "webrtc/system_wrappers/interface/scoped_vector.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::SaveArg; namespace webrtc { namespace { const uint32_t kSenderSsrc = 0x12345; const uint32_t kReceiverSsrc = 0x23456; +const uint32_t kSenderRtxSsrc = 0x32345; const uint32_t kOneWayNetworkDelayMs = 100; class RtcpRttStatsTestImpl : public RtcpRttStats { @@ -215,4 +224,245 @@ TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) { EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets); EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets); } + +class RtpSendingTestTransport : public Transport { + public: + void ResetCounters() { bytes_received_.clear(); } + + virtual int SendPacket(int channel, const void* data, int length) { + RTPHeader header; + scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); + EXPECT_TRUE( + parser->Parse(static_cast<const uint8_t*>(data), length, &header)); + bytes_received_[header.ssrc] += length; + ++packets_received_[header.ssrc]; + return length; + } + + virtual int SendRTCPPacket(int channel, const void* data, int length) { + return length; + } + + int GetPacketsReceived(uint32_t ssrc) const { + std::map<uint32_t, int>::const_iterator it = packets_received_.find(ssrc); + if (it == packets_received_.end()) + return 0; + return it->second; + } + + int GetBytesReceived(uint32_t ssrc) const { + std::map<uint32_t, int>::const_iterator it = bytes_received_.find(ssrc); + if (it == bytes_received_.end()) + return 0; + return it->second; + } + + int GetTotalBytesReceived() const { + int sum = 0; + for (std::map<uint32_t, int>::const_iterator it = bytes_received_.begin(); + it != bytes_received_.end(); + ++it) { + sum += it->second; + } + return sum; + } + + private: + std::map<uint32_t, int> bytes_received_; + std::map<uint32_t, int> packets_received_; +}; + +class RtpSendingTest : public ::testing::Test { + protected: + // Map from SSRC to number of received packets and bytes. + typedef std::map<uint32_t, std::pair<int, int> > PaddingMap; + + RtpSendingTest() { + // Send module. + RtpRtcp::Configuration config; + config.audio = false; + config.clock = Clock::GetRealTimeClock(); + config.outgoing_transport = &transport_; + config.receive_statistics = receive_statistics_.get(); + config.rtt_stats = &rtt_stats_; + config.paced_sender = &pacer_; + memset(&codec_, 0, sizeof(VideoCodec)); + codec_.plType = 100; + strncpy(codec_.plName, "VP8", 3); + codec_.numberOfSimulcastStreams = 3; + codec_.simulcastStream[0].width = 320; + codec_.simulcastStream[0].height = 180; + codec_.simulcastStream[0].maxBitrate = 300; + codec_.simulcastStream[1].width = 640; + codec_.simulcastStream[1].height = 360; + codec_.simulcastStream[1].maxBitrate = 600; + codec_.simulcastStream[2].width = 1280; + codec_.simulcastStream[2].height = 720; + codec_.simulcastStream[2].maxBitrate = 1200; + // We need numberOfSimulcastStreams + 1 RTP modules since we need one + // default module. + for (int i = 0; i < codec_.numberOfSimulcastStreams + 1; ++i) { + RtpRtcp* sender = RtpRtcp::CreateRtpRtcp(config); + EXPECT_EQ(0, sender->RegisterSendPayload(codec_)); + EXPECT_EQ(0, sender->SetSendingStatus(true)); + EXPECT_EQ(0, sender->SetSendingMediaStatus(true)); + sender->SetSSRC(kSenderSsrc + i); + sender->SetRemoteSSRC(kReceiverSsrc + i); + senders_.push_back(sender); + config.default_module = senders_[0]; + } + std::vector<uint32_t> bitrates; + bitrates.push_back(codec_.simulcastStream[0].maxBitrate); + bitrates.push_back(codec_.simulcastStream[1].maxBitrate); + bitrates.push_back(codec_.simulcastStream[2].maxBitrate); + senders_[0]->SetTargetSendBitrate(bitrates); + } + + ~RtpSendingTest() { + for (int i = senders_.size() - 1; i >= 0; --i) { + delete senders_[i]; + } + } + + void SendFrameOnSender(int sender_index, + const uint8_t* payload, + size_t length) { + RTPVideoHeader rtp_video_header = { + codec_.simulcastStream[sender_index].width, + codec_.simulcastStream[sender_index].height, + true, + 0, + kRtpVideoVp8, + {}}; + uint32_t seq_num = 0; + uint32_t ssrc = 0; + int64_t capture_time_ms = 0; + bool retransmission = false; + EXPECT_CALL(pacer_, SendPacket(_, _, _, _, _, _)) + .WillRepeatedly(DoAll(SaveArg<1>(&ssrc), + SaveArg<2>(&seq_num), + SaveArg<3>(&capture_time_ms), + SaveArg<5>(&retransmission), + Return(true))); + EXPECT_EQ(0, + senders_[sender_index]->SendOutgoingData(kVideoFrameKey, + codec_.plType, + 0, + 0, + payload, + length, + NULL, + &rtp_video_header)); + EXPECT_TRUE(senders_[sender_index]->TimeToSendPacket( + ssrc, seq_num, capture_time_ms, retransmission)); + } + + void ExpectPadding(const PaddingMap& expected_padding) { + int expected_total_bytes = 0; + for (PaddingMap::const_iterator it = expected_padding.begin(); + it != expected_padding.end(); + ++it) { + int packets_received = transport_.GetBytesReceived(it->first); + if (it->second.first > 0) { + EXPECT_GE(packets_received, it->second.first) + << "On SSRC: " << it->first; + } + int bytes_received = transport_.GetBytesReceived(it->first); + expected_total_bytes += bytes_received; + if (it->second.second > 0) { + EXPECT_GE(bytes_received, it->second.second) + << "On SSRC: " << it->first; + } else { + EXPECT_EQ(0, bytes_received) << "On SSRC: " << it->first; + } + } + EXPECT_EQ(expected_total_bytes, transport_.GetTotalBytesReceived()); + } + + scoped_ptr<ReceiveStatistics> receive_statistics_; + RtcpRttStatsTestImpl rtt_stats_; + std::vector<RtpRtcp*> senders_; + RtpSendingTestTransport transport_; + NiceMock<MockPacedSender> pacer_; + VideoCodec codec_; +}; + +TEST_F(RtpSendingTest, RoundRobinPadding) { + // We have to send on an SSRC to be allowed to pad, since a marker bit must + // be sent prior to padding packets. + const uint8_t payload[200] = {0}; + for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) { + SendFrameOnSender(i + 1, payload, sizeof(payload)); + } + transport_.ResetCounters(); + senders_[0]->TimeToSendPadding(500); + PaddingMap expected_padding; + expected_padding[kSenderSsrc + 1] = std::make_pair(2, 500); + expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0); + expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1000); + expected_padding[kSenderSsrc + 2] = std::make_pair(4, 1000); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1500); + expected_padding[kSenderSsrc + 3] = std::make_pair(6, 1500); + ExpectPadding(expected_padding); +} + +TEST_F(RtpSendingTest, RoundRobinPaddingRtx) { + // Enable RTX to allow padding to be sent prior to media. + for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) { + senders_[i]->SetRtxSendPayloadType(96); + senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i); + senders_[i]->SetRTXSendStatus(kRtxRetransmitted); + } + transport_.ResetCounters(); + senders_[0]->TimeToSendPadding(500); + PaddingMap expected_padding; + expected_padding[kSenderSsrc + 1] = std::make_pair(0, 0); + expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0); + expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0); + expected_padding[kSenderRtxSsrc + 1] = std::make_pair(2, 500); + expected_padding[kSenderRtxSsrc + 2] = std::make_pair(0, 0); + expected_padding[kSenderRtxSsrc + 3] = std::make_pair(0, 0); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1000); + expected_padding[kSenderRtxSsrc + 2] = std::make_pair(4, 500); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1500); + + expected_padding[kSenderRtxSsrc + 3] = std::make_pair(6, 500); + ExpectPadding(expected_padding); +} + +TEST_F(RtpSendingTest, RoundRobinPaddingRtxRedundantPayloads) { + for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) { + senders_[i]->SetRtxSendPayloadType(96); + senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i); + senders_[i]->SetRTXSendStatus(kRtxRetransmitted | kRtxRedundantPayloads); + senders_[i]->SetStorePacketsStatus(true, 100); + } + // First send payloads so that we have something to retransmit. + const size_t kPayloadSize = 500; + const uint8_t payload[kPayloadSize] = {0}; + for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) { + SendFrameOnSender(i + 1, payload, sizeof(payload)); + } + transport_.ResetCounters(); + senders_[0]->TimeToSendPadding(500); + PaddingMap expected_padding; + expected_padding[kSenderSsrc + 1] = std::make_pair<int, int>(0, 0); + expected_padding[kSenderSsrc + 2] = std::make_pair<int, int>(0, 0); + expected_padding[kSenderSsrc + 3] = std::make_pair<int, int>(0, 0); + expected_padding[kSenderRtxSsrc + 1] = std::make_pair<int, int>(1, 500); + expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(0, 0); + expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(0, 0); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1000); + expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(2, 1000); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1500); + expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(3, 1500); + ExpectPadding(expected_padding); +} } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc index 6e59a2d7..7cfcd722 100644 --- a/modules/rtp_rtcp/source/rtp_sender.cc +++ b/modules/rtp_rtcp/source/rtp_sender.cc @@ -89,7 +89,7 @@ RTPSender::RTPSender(const int32_t id, rtx_(kRtxOff), payload_type_rtx_(-1), target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()), - target_bitrate_kbps_(0) { + target_bitrate_(0) { memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_)); memset(nack_byte_count_, 0, sizeof(nack_byte_count_)); memset(csrcs_, 0, sizeof(csrcs_)); @@ -127,8 +127,14 @@ RTPSender::~RTPSender() { delete video_; } -void RTPSender::SetTargetSendBitrate(const uint32_t bits) { - SetTargetBitrateKbps(static_cast<uint16_t>(bits / 1000)); +void RTPSender::SetTargetBitrate(uint32_t bitrate) { + CriticalSectionScoped cs(target_bitrate_critsect_.get()); + target_bitrate_ = bitrate; +} + +uint32_t RTPSender::GetTargetBitrate() { + CriticalSectionScoped cs(target_bitrate_critsect_.get()); + return target_bitrate_; } uint16_t RTPSender::ActualSendBitrateKbit() const { @@ -330,7 +336,6 @@ void RTPSender::RTXStatus(int* mode, uint32_t* ssrc, *payload_type = payload_type_rtx_; } - void RTPSender::SetRtxPayloadType(int payload_type) { CriticalSectionScoped cs(send_critsect_); payload_type_rtx_ = payload_type; @@ -465,8 +470,8 @@ bool RTPSender::SendPaddingAccordingToBitrate( // Current bitrate since last estimate(1 second) averaged with the // estimate since then, to get the most up to date bitrate. uint32_t current_bitrate = bitrate_sent_.BitrateNow(); - uint16_t target_bitrate_kbps = GetTargetBitrateKbps(); - int bitrate_diff = target_bitrate_kbps * 1000 - current_bitrate; + uint32_t target_bitrate = GetTargetBitrate(); + int bitrate_diff = target_bitrate - current_bitrate; if (bitrate_diff <= 0) { return true; } @@ -477,7 +482,7 @@ bool RTPSender::SendPaddingAccordingToBitrate( } else { bytes = (bitrate_diff / 8); // Cap at 200 ms of target send data. - int bytes_cap = target_bitrate_kbps * 25; // 1000 / 8 / 5. + int bytes_cap = target_bitrate / 1000 * 25; // 1000 / 8 / 5. if (bytes > bytes_cap) { bytes = bytes_cap; } @@ -656,12 +661,12 @@ void RTPSender::OnReceivedNACK( "num_seqnum", nack_sequence_numbers.size(), "avg_rtt", avg_rtt); const int64_t now = clock_->TimeInMilliseconds(); uint32_t bytes_re_sent = 0; - uint16_t target_bitrate_kbps = GetTargetBitrateKbps(); + uint32_t target_bitrate = GetTargetBitrate(); // Enough bandwidth to send NACK? if (!ProcessNACKBitRate(now)) { LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target " - << target_bitrate_kbps; + << target_bitrate; return; } @@ -681,10 +686,10 @@ void RTPSender::OnReceivedNACK( break; } // Delay bandwidth estimate (RTT * BW). - if (target_bitrate_kbps != 0 && avg_rtt) { + if (target_bitrate != 0 && avg_rtt) { // kbits/s * ms = bits => bits/8 = bytes uint32_t target_bytes = - (static_cast<uint32_t>(target_bitrate_kbps) * avg_rtt) >> 3; + (static_cast<uint32_t>(target_bitrate / 1000) * avg_rtt) >> 3; if (bytes_re_sent > target_bytes) { break; // Ignore the rest of the packets in the list. } @@ -699,33 +704,34 @@ void RTPSender::OnReceivedNACK( bool RTPSender::ProcessNACKBitRate(const uint32_t now) { uint32_t num = 0; - int32_t byte_count = 0; - const uint32_t avg_interval = 1000; - uint16_t target_bitrate_kbps = GetTargetBitrateKbps(); + int byte_count = 0; + const int kAvgIntervalMs = 1000; + uint32_t target_bitrate = GetTargetBitrate(); CriticalSectionScoped cs(send_critsect_); - if (target_bitrate_kbps == 0) { + if (target_bitrate == 0) { return true; } for (num = 0; num < NACK_BYTECOUNT_SIZE; ++num) { - if ((now - nack_byte_count_times_[num]) > avg_interval) { + if ((now - nack_byte_count_times_[num]) > kAvgIntervalMs) { // Don't use data older than 1sec. break; } else { byte_count += nack_byte_count_[num]; } } - int32_t time_interval = avg_interval; + int time_interval = kAvgIntervalMs; if (num == NACK_BYTECOUNT_SIZE) { // More than NACK_BYTECOUNT_SIZE nack messages has been received // during the last msg_interval. time_interval = now - nack_byte_count_times_[num - 1]; if (time_interval < 0) { - time_interval = avg_interval; + time_interval = kAvgIntervalMs; } } - return (byte_count * 8) < (target_bitrate_kbps * time_interval); + return (byte_count * 8) < + static_cast<int>(target_bitrate / 1000 * time_interval); } void RTPSender::UpdateNACKBitRate(const uint32_t bytes, @@ -882,8 +888,13 @@ int RTPSender::TimeToSendPadding(int bytes) { int bytes_sent = SendRedundantPayloads(payload_type, bytes); bytes -= bytes_sent; if (bytes > 0) { - int padding_sent = SendPadData(payload_type, timestamp, capture_time_ms, - bytes, kDontStore, true, true); + int padding_sent = SendPadData(payload_type, + timestamp, + capture_time_ms, + bytes, + kDontStore, + true, + rtx_ == kRtxOff); bytes_sent += padding_sent; } return bytes_sent; @@ -1659,14 +1670,4 @@ void RTPSender::BitrateUpdated(const BitrateStatistics& stats) { bitrate_callback_->Notify(stats, ssrc_); } } - -void RTPSender::SetTargetBitrateKbps(uint16_t bitrate_kbps) { - CriticalSectionScoped cs(target_bitrate_critsect_.get()); - target_bitrate_kbps_ = bitrate_kbps; -} - -uint16_t RTPSender::GetTargetBitrateKbps() { - CriticalSectionScoped cs(target_bitrate_critsect_.get()); - return target_bitrate_kbps_; -} } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h index 17457ff2..17b026ca 100644 --- a/modules/rtp_rtcp/source/rtp_sender.h +++ b/modules/rtp_rtcp/source/rtp_sender.h @@ -83,7 +83,8 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer { // was sent within the statistics window. bool GetSendSideDelay(int* avg_send_delay_ms, int* max_send_delay_ms) const; - void SetTargetSendBitrate(const uint32_t bits); + void SetTargetBitrate(uint32_t bitrate); + uint32_t GetTargetBitrate(); virtual uint16_t MaxDataPayloadLength() const OVERRIDE; // with RTP and FEC headers. @@ -329,9 +330,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer { bool is_retransmit); bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const; - void SetTargetBitrateKbps(uint16_t bitrate_kbps); - uint16_t GetTargetBitrateKbps(); - Clock* clock_; Bitrate bitrate_sent_; @@ -399,7 +397,7 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer { // that by the time the function returns there is no guarantee // that the target bitrate is still valid. scoped_ptr<CriticalSectionWrapper> target_bitrate_critsect_; - uint16_t target_bitrate_kbps_ GUARDED_BY(target_bitrate_critsect_); + uint16_t target_bitrate_ GUARDED_BY(target_bitrate_critsect_); }; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 67a4a57d..18482890 100644 --- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -444,7 +444,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) { kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); - rtp_sender_->SetTargetSendBitrate(300000); + rtp_sender_->SetTargetBitrate(300000); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, kPayload, @@ -498,7 +498,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) { kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); - rtp_sender_->SetTargetSendBitrate(300000); + rtp_sender_->SetTargetBitrate(300000); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, kPayload, @@ -580,7 +580,7 @@ TEST_F(RtpSenderTest, SendPadding) { kAbsoluteSendTimeExtensionId); webrtc::RTPHeader rtp_header; - rtp_sender_->SetTargetSendBitrate(300000); + rtp_sender_->SetTargetBitrate(300000); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, kPayload, @@ -698,7 +698,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) { kTransmissionTimeOffsetExtensionId); rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); - rtp_sender_->SetTargetSendBitrate(300000); + rtp_sender_->SetTargetBitrate(300000); const size_t kNumPayloadSizes = 10; const int kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700, 750, 800, 850, 900, 950}; diff --git a/modules/video_coding/codecs/vp8/vp8_impl.cc b/modules/video_coding/codecs/vp8/vp8_impl.cc index dfe76e01..4901edff 100644 --- a/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -214,7 +214,10 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst, } config_->g_lag_in_frames = 0; // 0- no frame lagging - if (codec_.width * codec_.height > 1280 * 960 && number_of_cores >= 6) { + if (codec_.width * codec_.height >= 1920 * 1080 && number_of_cores > 8) { + config_->g_threads = 8; // 8 threads for 1080p on high perf machines. + } else if (codec_.width * codec_.height > 1280 * 960 && + number_of_cores >= 6) { config_->g_threads = 3; // 3 threads for 1080p. } else if (codec_.width * codec_.height > 640 * 480 && number_of_cores >= 3) { config_->g_threads = 2; // 2 threads for qHD/HD. diff --git a/test/w3c/getusermedia_conformance_test.html b/test/w3c/getusermedia_conformance_test.html index 6ddb6030..7b724a93 100644 --- a/test/w3c/getusermedia_conformance_test.html +++ b/test/w3c/getusermedia_conformance_test.html @@ -52,15 +52,16 @@ Notice that this requires the site you're browsing to use HTTPS. </p> <div id="log"></div> - <video id="local-view" autoplay="autoplay" muted="true"></video> - <!-- These files are in place when executing on W3C. --> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/common/vendor-prefix.js" - data-prefixed-objects= '[{"ancestors":["navigator"], "name":"getUserMedia"}, - {"ancestors":["window"], "name":"RTCPeerConnection"}]' - data-prefixed-prototypes='[{"ancestors":["HTMLMediaElement"],"name":"srcObject"}]'></script> + data-prefixed-objects= + '[{"ancestors":["navigator"], "name":"getUserMedia"}, + {"ancestors":["window"], "name":"RTCPeerConnection"}]' + data-prefixed-prototypes= + '[{"ancestors":["HTMLMediaElement"],"name":"srcObject"}]'> + </script> <script src="getusermedia_conformance_test.js"></script> </body> diff --git a/test/w3c/getusermedia_conformance_test.js b/test/w3c/getusermedia_conformance_test.js index fe1dcc8c..d7c78280 100644 --- a/test/w3c/getusermedia_conformance_test.js +++ b/test/w3c/getusermedia_conformance_test.js @@ -6,7 +6,7 @@ // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. -setup({timeout:10000}); +setup({timeout:5000}); // Helper functions to minimize code duplication. function failedCallback(test) { @@ -19,6 +19,14 @@ function invokeGetUserMedia(test, okCallback) { failedCallback(test)); } +function createInvisibleVideoTag() { + var video = document.createElement('video'); + video.autoplay = true; + video.style.display = 'none'; + document.body.appendChild(video); + return video; +} + // 4.2 MediaStream. var mediaStreamTest = async_test('4.2 MediaStream'); @@ -56,21 +64,25 @@ function verifyMediaStream(stream) { }, '[MediaStream] removeTrack function'); test(function () { - // Missing in Chrome. assert_inherits(stream, 'clone'); assert_true(typeof stream.clone === 'function'); }, '[MediaStream] clone function'); test(function () { - assert_own_property(stream, 'ended'); - assert_true(typeof stream.ended === 'boolean'); - assert_readonly(stream, 'ended'); - }, '[MediaStream] ended attribute'); + assert_own_property(stream, 'active'); + assert_true(typeof stream.active === 'boolean'); + assert_readonly(stream, 'active'); + }, '[MediaStream] active attribute'); + + test(function () { + assert_own_property(stream, 'onactive'); + assert_true(stream.onactive === null); + }, '[MediaStream] onactive EventHandler'); test(function () { - assert_own_property(stream, 'onended'); - assert_true(stream.onended === null); - }, '[MediaStream] onended EventHandler'); + assert_own_property(stream, 'oninactive'); + assert_true(stream.oninactive === null); + }, '[MediaStream] oninactive EventHandler'); test(function () { assert_own_property(stream, 'onaddtrack'); @@ -86,28 +98,43 @@ function verifyMediaStream(stream) { mediaStreamTest.step(function() { var okCallback = mediaStreamTest.step_func(function (stream) { verifyMediaStream(stream); - var videoTracks = stream.getVideoTracks(); assert_true(videoTracks.length > 0); + mediaStreamTest.done(); + }); + + invokeGetUserMedia(mediaStreamTest, okCallback); +}); + +var mediaStreamCallbacksTest = async_test('4.2.2 MediaStream callbacks'); + +mediaStreamCallbacksTest.step(function() { + var addCallbackCalled = false; + var onAddTrackCallback = mediaStreamCallbacksTest.step_func(function (event) { + assert_true(event.track instanceof MediaStreamTrack); + addCallbackCalled = true; + }); + var onRemoveTrackCallback = + mediaStreamCallbacksTest.step_func(function (event) { + assert_true(event.track instanceof MediaStreamTrack); + assert_true(addCallbackCalled, 'Add should have been called after remove.'); + mediaStreamCallbacksTest.done(); + }); + var okCallback = mediaStreamCallbacksTest.step_func(function (stream) { + var videoTracks = stream.getVideoTracks(); // Verify event handlers are working. - stream.onaddtrack = onAddTrackCallback - stream.onremovetrack = onRemoveTrackCallback + stream.onaddtrack = onAddTrackCallback; + stream.onremovetrack = onRemoveTrackCallback; stream.removeTrack(videoTracks[0]); stream.addTrack(videoTracks[0]); - mediaStreamTest.done(); - }); - var onAddTrackCallback = mediaStreamTest.step_func(function () { - // TODO(kjellander): verify number of tracks. - mediaStreamTest.done(); }); - var onRemoveTrackCallback = mediaStreamTest.step_func(function () { - // TODO(kjellander): verify number of tracks. - mediaStreamTest.done(); - }); - invokeGetUserMedia(mediaStreamTest, okCallback); + + invokeGetUserMedia(mediaStreamCallbacksTest, okCallback); }); +// TODO(phoglund): add test for onactive/oninactive. + // 4.3 MediaStreamTrack. var mediaStreamTrackTest = async_test('4.3 MediaStreamTrack'); @@ -140,7 +167,6 @@ function verifyTrack(type, track) { }, '[MediaStreamTrack (' + type + ')] enabled attribute'); test(function () { - // Missing in Chrome. assert_own_property(track, 'muted'); assert_readonly(track, 'muted'); assert_true(typeof track.muted === 'boolean'); @@ -250,59 +276,113 @@ mediaStreamTrackTest.step(function() { var mediaStreamTrackEventTest = async_test('4.4 MediaStreamTrackEvent'); mediaStreamTrackEventTest.step(function() { var okCallback = mediaStreamTrackEventTest.step_func(function (stream) { - // TODO(kjellander): verify attributes + // TODO(kjellander): verify attributes. mediaStreamTrackEventTest.done(); }); invokeGetUserMedia(mediaStreamTrackEventTest, okCallback); }); -// 4.5 Video and Audio Tracks tests. -var avTracksTest = async_test('4.5 Video and Audio Tracks'); -avTracksTest.step(function() { - var okCallback = avTracksTest.step_func(function (stream) { - // TODO(kjellander): verify attributes - avTracksTest.done(); - }); - invokeGetUserMedia(avTracksTest, okCallback); -}); +// 6. Media streams as media elements. -// 5. The model: sources, sinks, constraints, and states +var playingInMediaElementTest = async_test( + '6.2 Loading and Playing a MediaStream in a Media Element'); +playingInMediaElementTest.step(function() { + var video = createInvisibleVideoTag(); -// 6. Source states -// 6.1 Dictionary MediaSourceStates Members + var okCallback = playingInMediaElementTest.step_func(function (stream) { + video.onplay = playingInMediaElementTest.step_func(function() { + // This depends on what webcam we're actually running with, but the + // resolution should at least be greater than or equal to QVGA. + assert_greater_than_equal(video.videoWidth, 320); + assert_greater_than_equal(video.videoHeight, 240); -// 7. Source capabilities -// 7.1 Dictionary CapabilityRange Members -// 7.2 CapabilityList array -// 7.3 Dictionary AllVideoCapabilities Members -// 7.4 Dictionary AllAudioCapabilities Members + playingInMediaElementTest.done(); + }); + video.srcObject = stream; + }); + invokeGetUserMedia(playingInMediaElementTest, okCallback); +}); -// 8. URL tests. -var createObjectURLTest = async_test('8.1 URL createObjectURL method'); -createObjectURLTest.step(function() { - var okCallback = createObjectURLTest.step_func(function (stream) { - var url = URL.createObjectURL(stream); - assert_true(typeof url === 'string'); - createObjectURLTest.done(); +// Verifies a media element track (for instance belonging to a video tag) +// after it has been assigned a media stream. +function verifyOneMediaElementTrack(track, correspondingMediaStreamTrack) { + assert_equals(track.id, correspondingMediaStreamTrack.id); + assert_equals(track.kind, 'main'); + assert_equals(track.label, correspondingMediaStreamTrack.label); + assert_equals(track.language, ''); +} + +var setsUpMediaTracksRightTest = async_test( + '6.2 Sets up <video> audio and video tracks right'); +setsUpMediaTracksRightTest.step(function() { + var video = createInvisibleVideoTag(); + + var okCallback = setsUpMediaTracksRightTest.step_func(function (stream) { + video.onplay = setsUpMediaTracksRightTest.step_func(function() { + // Verify the requirements on the video tag's streams as outlined in 6.2. + // There could be any number of tracks depending on what device we have + // connected, so verify all of them. There should be at least one of audio + // and video each though. + assert_inherits(video, 'videoTracks', + 'Browser missing videoTracks support on media elements.'); + assert_readonly(video, 'videoTracks'); + assert_greater_than_equal(video.videoTracks.length, 1); + assert_equals(video.videoTracks.length, stream.getVideoTracks().length); + + for (var i = 0; i < video.videoTracks.length; i++) { + verifyOneMediaElementTrack(video.videoTracks[i], + stream.getVideoTracks()[i]); + } + + assert_inherits(video, 'audioTracks', + 'Browser missing audioTracks support on media elements.'); + assert_readonly(video, 'audioTracks'); + assert_greater_than_equal(video.audioTracks.length, 1); + assert_equals(video.audioTracks.length, stream.getAudioTracks().length); + + for (var i = 0; i < video.audioTracks.length; i++) { + verifyOneMediaElementTrack(audio.audioTracks[i], + stream.getAudioTracks()[i]); + } + + setsUpMediaTracksRightTest.done(); + }); + video.srcObject = stream; }); - invokeGetUserMedia(createObjectURLTest, okCallback); + invokeGetUserMedia(setsUpMediaTracksRightTest, okCallback); }); -// 9. MediaStreams as Media Elements. -var mediaElementsTest = async_test('9. MediaStreams as Media Elements'); +var mediaElementsTest = + async_test('6.3 Media Element Attributes when Playing a MediaStream'); function verifyVideoTagWithStream(videoTag) { test(function () { + assert_equals(videoTag.currentSrc, ''); + }, '[Video tag] currentSrc attribute'); + + test(function () { + assert_equals(videoTag.preload, 'none'); + }, '[Video tag] preload attribute'); + + test(function () { assert_equals(videoTag.buffered.length, 0); }, '[Video tag] buffered attribute'); test(function () { - // Attempts to alter currentTime shall be ignored. + // Where 1 is NETWORK_IDLE. + assert_equals(videoTag.networkState, 1); + }, '[Video tag] networkState attribute'); + + test(function () { + // 0 is HAVE_NOTHING, 4 is HAVE_ENOUGH_DATA. + assert_true(videoTag.readyState == 0 || videoTag.readyState == 4); + }, '[Video tag] readyState attribute'); + + test(function () { assert_true(videoTag.currentTime >= 0); - assert_throws('InvalidStateError', - function () { videoTag.currentTime = 1234; }, - 'Attempts to modify currentTime shall throw ' + - 'InvalidStateError'); + assert_throws( + 'InvalidStateError', function () { videoTag.currentTime = 1234; }, + 'Attempts to modify currentTime shall throw InvalidStateError'); }, '[Video tag] currentTime attribute'); test(function () { @@ -315,16 +395,16 @@ function verifyVideoTagWithStream(videoTag) { test(function () { assert_equals(videoTag.defaultPlaybackRate, 1.0); - assert_throws('DOMException', - function () { videoTag.defaultPlaybackRate = 2.0; }, - 'Attempts to alter videoTag.defaultPlaybackRate MUST fail'); + assert_throws( + 'DOMException', function () { videoTag.defaultPlaybackRate = 2.0; }, + 'Attempts to alter videoTag.defaultPlaybackRate MUST fail'); }, '[Video tag] defaultPlaybackRate attribute'); test(function () { assert_equals(videoTag.playbackRate, 1.0); - assert_throws('DOMException', - function () { videoTag.playbackRate = 2.0; }, - 'Attempts to alter videoTag.playbackRate MUST fail'); + assert_throws( + 'DOMException', function () { videoTag.playbackRate = 2.0; }, + 'Attempts to alter videoTag.playbackRate MUST fail'); }, '[Video tag] playbackRate attribute'); test(function () { @@ -335,56 +415,96 @@ function verifyVideoTagWithStream(videoTag) { test(function () { assert_equals(videoTag.seekable.length, 0); - assert_equals(videoTag.seekable.start(), videoTag.currentTime); - assert_equals(videoTag.seekable.end(), videoTag.currentTime); - assert_equals(videoTag.startDate, NaN, 'videoTag.startDate'); + // This is wrong in the standard: start() and end() must have arguments, but + // since the time range is empty as we assert in the line above, there is no + // valid argument with which we can call the methods. + // assert_equals(videoTag.seekable.start(), videoTag.currentTime); + // assert_equals(videoTag.seekable.end(), videoTag.currentTime); }, '[Video tag] seekable attribute'); test(function () { + assert_equals(videoTag.startDate, NaN, 'videoTag.startDate'); + }, '[Video tag] startDate attribute'); + + test(function () { assert_false(videoTag.loop); }, '[Video tag] loop attribute'); + }; mediaElementsTest.step(function() { var okCallback = mediaElementsTest.step_func(function (stream) { - var videoTag = document.getElementById('local-view'); - videoTag.srcObject = stream; - verifyVideoTagWithStream(videoTag); + var video = createInvisibleVideoTag(); + video.srcObject = stream; + verifyVideoTagWithStream(video); mediaElementsTest.done(); }); invokeGetUserMedia(mediaElementsTest, okCallback); }); -// 11. Obtaining local multimedia content. +// 9. Enumerating local media devices. +// TODO(phoglund): add tests. -// 11.1 NavigatorUserMedia. -var getUserMediaTest = async_test('11.1 NavigatorUserMedia'); -getUserMediaTest.step(function() { - var okCallback = getUserMediaTest.step_func(function (stream) { +// 10. Obtaining local multimedia content. + +function testGetUserMedia(test, constraints) { + var okCallback = test.step_func(function (stream) { assert_true(stream !== null); - getUserMediaTest.done(); + test.done(); }); + navigator.getUserMedia(constraints, okCallback, failedCallback(test)); +} - // All three arguments are mandatory, so pass all of them. - navigator.getUserMedia({ video: true, audio: true }, okCallback, - failedCallback(getUserMediaTest)); - navigator.getUserMedia({ video: true, audio: false }, okCallback, - failedCallback(getUserMediaTest)); - navigator.getUserMedia({ video: false, audio: true }, okCallback, - failedCallback(getUserMediaTest)); +var getUserMediaTestAudioVideo = async_test('10.1.1 NavigatorUserMedia A/V'); +getUserMediaTestAudioVideo.step(function() { + testGetUserMedia(getUserMediaTestAudioVideo, { video: true, audio: true }); +}); + +var getUserMediaTestVideo = async_test('10.1.1 NavigatorUserMedia V'); +getUserMediaTestVideo.step(function() { + testGetUserMedia(getUserMediaTestVideo, { video: true, audio: false }); +}); + +var getUserMediaTestAudio = async_test('10.1.1 NavigatorUserMedia A'); +getUserMediaTestAudio.step(function() { + testGetUserMedia(getUserMediaTestAudio, { video: false, audio: true }); +}); + +var getUserMediaTestNull = async_test('10.1.1 NavigatorUserMedia Null'); +getUserMediaTestNull.step(function() { + testGetUserMedia(getUserMediaTestNull, null); +}); + +var getUserMediaTestPeerIdentity = + async_test('10.2 NavigatorUserMedia with peerIdentity'); +getUserMediaTestPeerIdentity.step(function() { + var peerIdentity = 'my_identity'; + var okCallback = getUserMediaTestPeerIdentity.step_func(function (stream) { + assert_true(stream !== null); + stream.getVideoTracks().forEach(function(track) { + assert_equals(track.peerIdentity, peerIdentity); + }); + stream.getAudioTracks().forEach(function(track) { + assert_equals(track.peerIdentity, peerIdentity); + }); + getUserMediaTestPeerIdentity.done(); + }); + navigator.getUserMedia( + {video: true, audio: true, peerIdentity: 'my_identity' }, + okCallback, failedCallback(getUserMediaTestPeerIdentity)); }); -// 11.2 MediaStreamConstraints. -var constraintsTest = async_test('11.2 MediaStreamConstraints'); +// 10.2 MediaStreamConstraints. +var constraintsTest = async_test('10.2 MediaStreamConstraints'); constraintsTest.step(function() { var okCallback = constraintsTest.step_func(function (stream) { assert_true(stream !== null); constraintsTest.done(); }); - // Constraints on video. - // See http://webrtc.googlecode.com/svn/trunk/samples/js/demos/html/constraints-and-stats.html + // See https://googlechrome.github.io/webrtc/samples/web/content/constraints/ // for more examples of constraints. + // TODO(phoglund): test more constraints; the possibilities here are endless. var constraints = {}; constraints.audio = true; constraints.video = { mandatory: {}, optional: [] }; @@ -396,9 +516,9 @@ constraintsTest.step(function() { failedCallback(constraintsTest)); }); -// 11.3 NavigatorUserMediaSuccessCallback. +// 10.4 NavigatorUserMediaSuccessCallback. var successCallbackTest = - async_test('11.3 NavigatorUserMediaSuccessCallback'); + async_test('10.4 NavigatorUserMediaSuccessCallback'); successCallbackTest.step(function() { var okCallback = successCallbackTest.step_func(function (stream) { assert_true(stream !== null); @@ -407,3 +527,5 @@ successCallbackTest.step(function() { invokeGetUserMedia(successCallbackTest, okCallback); }); +// 11. Constrainable Pattern. +// TODO(phoglund): add tests. diff --git a/video_engine/overuse_frame_detector.cc b/video_engine/overuse_frame_detector.cc index ac9519f3..764c2584 100644 --- a/video_engine/overuse_frame_detector.cc +++ b/video_engine/overuse_frame_detector.cc @@ -42,8 +42,8 @@ const int kMaxRampUpDelayMs = 240 * 1000; // Expontential back-off factor, to prevent annoying up-down behaviour. const double kRampUpBackoffFactor = 2.0; -// The initial average encode time (set to a fairly small value). -const float kInitialAvgEncodeTimeMs = 5.0f; +// Max number of overuses detected before always applying the rampup delay. +const int kMaxOverusesBeforeApplyRampupDelay = 7; // The maximum exponent to use in VCMExpFilter. const float kSampleDiffMs = 33.0f; @@ -115,6 +115,7 @@ class OveruseFrameDetector::EncodeTimeAvg { public: EncodeTimeAvg() : kWeightFactor(0.5f), + kInitialAvgEncodeTimeMs(5.0f), filtered_encode_time_ms_(new VCMExpFilter(kWeightFactor)) { filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs); } @@ -132,6 +133,7 @@ class OveruseFrameDetector::EncodeTimeAvg { private: const float kWeightFactor; + const float kInitialAvgEncodeTimeMs; scoped_ptr<VCMExpFilter> filtered_encode_time_ms_; }; @@ -378,6 +380,7 @@ OveruseFrameDetector::OveruseFrameDetector(Clock* clock) last_capture_time_(0), last_overuse_time_(0), checks_above_threshold_(0), + num_overuse_detections_(0), last_rampup_time_(0), in_quick_rampup_(false), current_rampup_delay_ms_(kStandardRampUpDelayMs), @@ -514,7 +517,8 @@ int32_t OveruseFrameDetector::Process() { // back and forth between this load, the system doesn't seem to handle it. bool check_for_backoff = last_rampup_time_ > last_overuse_time_; if (check_for_backoff) { - if (now - last_rampup_time_ < kStandardRampUpDelayMs) { + if (now - last_rampup_time_ < kStandardRampUpDelayMs || + num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) { // Going up was not ok for very long, back off. current_rampup_delay_ms_ *= kRampUpBackoffFactor; if (current_rampup_delay_ms_ > kMaxRampUpDelayMs) @@ -528,6 +532,7 @@ int32_t OveruseFrameDetector::Process() { last_overuse_time_ = now; in_quick_rampup_ = false; checks_above_threshold_ = 0; + ++num_overuse_detections_; if (observer_ != NULL) observer_->OveruseDetected(); @@ -541,11 +546,12 @@ int32_t OveruseFrameDetector::Process() { int rampup_delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; - LOG(LS_INFO) << " Frame stats: capture avg: " << capture_deltas_.Mean() - << " capture stddev " << capture_deltas_.StdDev() - << " encode usage " << encode_usage_->Value() - << " encode rsd " << encode_rsd_->Value() - << " rampup delay " << rampup_delay; + LOG(LS_VERBOSE) << " Frame stats: capture avg: " << capture_deltas_.Mean() + << " capture stddev " << capture_deltas_.StdDev() + << " encode usage " << encode_usage_->Value() + << " encode rsd " << encode_rsd_->Value() + << " overuse detections " << num_overuse_detections_ + << " rampup delay " << rampup_delay; return 0; } diff --git a/video_engine/overuse_frame_detector.h b/video_engine/overuse_frame_detector.h index ef6d6aba..efd23dc4 100644 --- a/video_engine/overuse_frame_detector.h +++ b/video_engine/overuse_frame_detector.h @@ -124,6 +124,7 @@ class OveruseFrameDetector : public Module { int64_t last_overuse_time_; int checks_above_threshold_; + int num_overuse_detections_; int64_t last_rampup_time_; bool in_quick_rampup_; |