mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-24 09:27:31 +09:00
[WebRTC] updated to upstream branch 49 and related.
this patch is based on 38d7a7883...226f2f0bd
This commit is contained in:
parent
e79847e7b9
commit
a3239eaa4d
2838 changed files with 151221 additions and 159688 deletions
|
|
@ -1,19 +1,21 @@
|
|||
# Names should be added to this file like so:
|
||||
# Name or Organization <email address>
|
||||
|
||||
Andrew MacDonald <andrew@webrtc.org>
|
||||
Anil Kumar <an1kumar@gmail.com>
|
||||
Ben Strong <bstrong@gmail.com>
|
||||
Bob Withers <bwit@pobox.com>
|
||||
Bridger Maxwell <bridgeyman@gmail.com>
|
||||
Christophe Dumez <ch.dumez@samsung.com>
|
||||
Colin Plumb
|
||||
Eric Rescorla, RTFM Inc.
|
||||
Eric Rescorla, RTFM Inc. <ekr@rtfm.com>
|
||||
Giji Gangadharan <giji.g@samsung.com>
|
||||
Graham Yoakum <gyoakum@skobalt.com>
|
||||
Jake Hilton <jakehilton@gmail.com>
|
||||
James H. Brown <jbrown@burgoyne.com>
|
||||
Jiawei Ou <jiawei.ou@gmail.com>
|
||||
Jie Mao <maojie0924@gmail.com>
|
||||
Luke Weber
|
||||
Luke Weber <luke.weber@gmail.com>
|
||||
Manish Jethani <manish.jethani@gmail.com>
|
||||
Martin Storsjo <martin@martin.st>
|
||||
Matthias Liebig <matthias.gcode@gmail.com>
|
||||
|
|
@ -21,8 +23,8 @@ Pali Rohar
|
|||
Paul Kapustin <pkapustin@gmail.com>
|
||||
Rafael Lopez Diez <rafalopezdiez@gmail.com>
|
||||
Ralph Giles <giles@ghostscript.com>
|
||||
Robert Nagy
|
||||
Ron Rivest
|
||||
Riku Voipio <riku.voipio@linaro.org>
|
||||
Robert Nagy <robert.nagy@gmail.com>
|
||||
Ryan Yoakum <ryoakum@skobalt.com>
|
||||
Sarah Thompson <sarah@telergy.com>
|
||||
Saul Kravitz <Saul.Kravitz@celera.com>
|
||||
|
|
@ -30,13 +32,19 @@ Silviu Caragea <silviu.cpp@gmail.com>
|
|||
Steve Reid <sreid@sea-to-sky.net>
|
||||
Vicken Simonian <vsimon@gmail.com>
|
||||
Victor Costan <costan@gmail.com>
|
||||
Alexander Brauckmann <a.brauckmann@gmail.com>
|
||||
|
||||
&yet LLC
|
||||
Agora IO
|
||||
ARM Holdings
|
||||
BroadSoft Inc.
|
||||
Google Inc.
|
||||
Intel Corporation
|
||||
MIPS Technologies
|
||||
Mozilla Foundation
|
||||
Opera Software ASA
|
||||
Sinch AB
|
||||
struktur AG
|
||||
Telenor Digital AS
|
||||
Temasys Communications
|
||||
Vonage Holdings Corp.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
vars = {
|
||||
'extra_gyp_flag': '-Dextra_gyp_flag=0',
|
||||
'chromium_git': 'https://chromium.googlesource.com',
|
||||
'chromium_revision': '719b83983be9613eb80e99a0bc645776d59b76b3',
|
||||
'chromium_revision': '099be58b08dadb64b1dc9f359ae097e978df5416',
|
||||
}
|
||||
|
||||
# NOTE: Prefer revision numbers to tags for svn deps. Use http rather than
|
||||
|
|
@ -17,14 +17,14 @@ deps = {
|
|||
'src/third_party/gflags/src':
|
||||
Var('chromium_git') + '/external/gflags/src@e7390f9185c75f8d902c05ed7d20bb94eb914d0c', # from svn revision 82
|
||||
|
||||
'src/third_party/junit':
|
||||
'src/third_party/junit-jar':
|
||||
Var('chromium_git') + '/external/webrtc/deps/third_party/junit@f35596b476aa6e62fd3b3857b9942ddcd13ce35e', # from svn revision 3367
|
||||
}
|
||||
|
||||
deps_os = {
|
||||
'win': {
|
||||
'src/third_party/winsdk_samples/src':
|
||||
Var('chromium_git') + '/external/webrtc/deps/third_party/winsdk_samples_v71@c0cbedd854cb610a53226d9817416c4ab9a7d1e9', # from svn revision 7951
|
||||
Var('chromium_git') + '/external/webrtc/deps/third_party/winsdk_samples_v71@e71b549167a665d7424d6f1dadfbff4b4aad1589',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -34,18 +34,16 @@ include_rules = [
|
|||
# WebRTC production code.
|
||||
'-base',
|
||||
'-chromium',
|
||||
'+external/webrtc/webrtc', # Android platform build.
|
||||
'+gflags',
|
||||
'+libyuv',
|
||||
'+net',
|
||||
'+talk',
|
||||
'+testing',
|
||||
'+third_party',
|
||||
'+unicode',
|
||||
'+webrtc',
|
||||
]
|
||||
|
||||
# checkdeps.py shouldn't check include paths for files in these dirs:
|
||||
skip_child_includes = [
|
||||
'webrtc/overrides',
|
||||
'+vpx',
|
||||
]
|
||||
|
||||
hooks = [
|
||||
|
|
@ -72,6 +70,21 @@ hooks = [
|
|||
'pattern': '.',
|
||||
'action': ['python', 'src/setup_links.py'],
|
||||
},
|
||||
{
|
||||
# This clobbers when necessary (based on get_landmines.py). It should be
|
||||
# an early hook but it will need to be run after syncing Chromium and
|
||||
# setting up the links, so the script actually exists.
|
||||
'name': 'landmines',
|
||||
'pattern': '.',
|
||||
'action': [
|
||||
'python',
|
||||
'src/build/landmines.py',
|
||||
'--landmine-scripts',
|
||||
'src/webrtc/build/get_landmines.py',
|
||||
'--src-dir',
|
||||
'src',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Pull sanitizer-instrumented third-party libraries if requested via
|
||||
# GYP_DEFINES. This could be done as part of sync_chromium.py above
|
||||
|
|
@ -89,6 +102,7 @@ hooks = [
|
|||
'--recursive',
|
||||
'--num_threads=10',
|
||||
'--no_auth',
|
||||
'--quiet',
|
||||
'--bucket', 'chromium-webrtc-resources',
|
||||
'src/resources'],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
andrew@webrtc.org
|
||||
henrika@webrtc.org
|
||||
mflodman@webrtc.org
|
||||
niklas.enbom@webrtc.org
|
||||
|
|
@ -6,6 +5,7 @@ tina.legrand@webrtc.org
|
|||
tommi@webrtc.org
|
||||
per-file .gitignore=*
|
||||
per-file AUTHORS=*
|
||||
per-file .gn=kjellander@webrtc.org
|
||||
per-file BUILD.gn=kjellander@webrtc.org
|
||||
per-file DEPS=*
|
||||
per-file PRESUBMIT.py=kjellander@webrtc.org
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
This folder can be used to pull together the chromium version of webrtc
|
||||
and libjingle, and build the peerconnection sample client and server. This will
|
||||
check out a new repository in which you can build peerconnection_server.
|
||||
|
||||
Steps:
|
||||
1) Create a new directory for the new repository (outside the webrtc repo):
|
||||
mkdir peerconnection
|
||||
cd peerconnection
|
||||
2) gclient config --name trunk http://webrtc.googlecode.com/svn/trunk/peerconnection
|
||||
3) gclient sync
|
||||
4) cd trunk
|
||||
5) make peerconnection_server peerconnection_client
|
||||
23
media/webrtc/trunk/README.md
Normal file
23
media/webrtc/trunk/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
**WebRTC is a free, open software project** that provides browsers and mobile
|
||||
applications with Real-Time Communications (RTC) capabilities via simple APIs.
|
||||
The WebRTC components have been optimized to best serve this purpose.
|
||||
|
||||
**Our mission:** To enable rich, high-quality RTC applications to be
|
||||
developed for the browser, mobile platforms, and IoT devices, and allow them
|
||||
all to communicate via a common set of protocols.
|
||||
|
||||
The WebRTC initiative is a project supported by Google, Mozilla and Opera,
|
||||
amongst others. This page is maintained by the Google Chrome team.
|
||||
|
||||
### Development
|
||||
|
||||
See http://www.webrtc.org/native-code/development for instructions on how to get
|
||||
started developing with the native code.
|
||||
|
||||
### More info
|
||||
|
||||
* Official web site: http://www.webrtc.org
|
||||
* Master source code repo: https://chromium.googlesource.com/external/webrtc
|
||||
* Samples and reference apps: https://github.com/webrtc
|
||||
* Mailing list: http://groups.google.com/group/discuss-webrtc
|
||||
* Continuous build: http://build.chromium.org/p/client.webrtc
|
||||
|
|
@ -917,23 +917,24 @@
|
|||
'android_app_version_name%': 'Developer Build',
|
||||
'android_app_version_code%': 0,
|
||||
|
||||
'sas_dll_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))',
|
||||
'wix_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))',
|
||||
'sas_dll_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))',
|
||||
'wix_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))',
|
||||
|
||||
'windows_sdk_default_path': '<(DEPTH)/third_party/platformsdk_win8/files',
|
||||
'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
|
||||
# 'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
|
||||
'windows_sdk_path%': '<(windows_sdk_default_path)',
|
||||
|
||||
'conditions': [
|
||||
['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', {
|
||||
'windows_sdk_path%': '<(windows_sdk_default_path)',
|
||||
}, {
|
||||
'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
|
||||
}],
|
||||
['OS=="win" and "<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(directx_sdk_default_path))"=="True"', {
|
||||
'directx_sdk_path%': '<(directx_sdk_default_path)',
|
||||
}, {
|
||||
'directx_sdk_path%': '$(DXSDK_DIR)',
|
||||
}],
|
||||
#['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', {
|
||||
# 'windows_sdk_path%': '<(windows_sdk_default_path)',
|
||||
#}, {
|
||||
# 'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
|
||||
#}],
|
||||
#['OS=="win" and "<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(directx_sdk_default_path))"=="True"', {
|
||||
# 'directx_sdk_path%': '<(directx_sdk_default_path)',
|
||||
#}, {
|
||||
# 'directx_sdk_path%': '$(DXSDK_DIR)',
|
||||
#}],
|
||||
# If use_official_google_api_keys is already set (to 0 or 1), we
|
||||
# do none of the implicit checking. If it is set to 1 and the
|
||||
# internal keys file is missing, the build will fail at compile
|
||||
|
|
@ -3410,7 +3411,7 @@
|
|||
'<(windows_sdk_path)/Include/shared',
|
||||
'<(windows_sdk_path)/Include/um',
|
||||
'<(windows_sdk_path)/Include/winrt',
|
||||
'<(directx_sdk_path)/Include',
|
||||
# '<(directx_sdk_path)/Include',
|
||||
'$(VSInstallDir)/VC/atlmfc/include',
|
||||
],
|
||||
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
|
||||
|
|
@ -3442,7 +3443,7 @@
|
|||
'VCLibrarianTool': {
|
||||
'AdditionalOptions': ['/ignore:4221'],
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(directx_sdk_path)/Lib/x86',
|
||||
# '<(directx_sdk_path)/Lib/x86',
|
||||
'<(windows_sdk_path)/Lib/win8/um/x86',
|
||||
],
|
||||
},
|
||||
|
|
@ -3488,7 +3489,7 @@
|
|||
}],
|
||||
],
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(directx_sdk_path)/Lib/x86',
|
||||
# '<(directx_sdk_path)/Lib/x86', XXXX
|
||||
'<(windows_sdk_path)/Lib/win8/um/x86',
|
||||
],
|
||||
'GenerateDebugInformation': 'true',
|
||||
|
|
|
|||
|
|
@ -7,10 +7,13 @@
|
|||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'includes': [ 'webrtc/build/common.gypi', ],
|
||||
'includes': [
|
||||
'webrtc/build/common.gypi',
|
||||
'webrtc/video/webrtc_video.gypi',
|
||||
],
|
||||
'variables': {
|
||||
'peerconnection_sample': 'third_party/libjingle/source/talk/examples/peerconnection',
|
||||
},
|
||||
},
|
||||
|
||||
# for mozilla, we want to force stuff to build but we don't want peerconnection_client or server
|
||||
# for unknown reasons, 'targets' must be outside of conditions. And don't try to build a dummy
|
||||
|
|
@ -22,19 +25,21 @@
|
|||
'target_name': 'dummy',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'webrtc/webrtc.gyp:webrtc_lib',
|
||||
'webrtc/modules/modules.gyp:audio_device',
|
||||
'webrtc/modules/modules.gyp:video_capture_module',
|
||||
'webrtc/modules/modules.gyp:video_capture_module_internal_impl',
|
||||
'webrtc/modules/modules.gyp:video_capture_module_internal_impl',
|
||||
'webrtc/modules/modules.gyp:video_render',
|
||||
# 'webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
# 'webrtc/system_wrappers/source/system_wrappers.gyp:metrics_default',
|
||||
'webrtc/video_engine/video_engine.gyp:video_engine_core',
|
||||
'webrtc/voice_engine/voice_engine.gyp:voice_engine',
|
||||
# 'webrtc/system_wrappers/source/system_wrappers.gyp:metrics_default',
|
||||
# 'webrtc/video_engine/video_engine.gyp:video_engine_core',
|
||||
'webrtc/voice_engine/voice_engine.gyp:voice_engine',
|
||||
# '<@(webrtc_video_dependencies)',
|
||||
],
|
||||
'conditions': [
|
||||
['OS!="android" and OS!="ios"', {
|
||||
'dependencies': [
|
||||
'webrtc/modules/modules.gyp:desktop_capture',
|
||||
'webrtc/modules/modules.gyp:desktop_capture',
|
||||
],
|
||||
},
|
||||
]],
|
||||
|
|
@ -86,8 +91,8 @@
|
|||
},
|
||||
},
|
||||
'dependencies': [
|
||||
'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||
'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
|
||||
#'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||
#'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
|
||||
],
|
||||
'include_dirs': [
|
||||
'src',
|
||||
|
|
@ -114,8 +119,8 @@
|
|||
'<(peerconnection_sample)/client/peer_connection_client.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||
'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
|
||||
#'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||
#'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
|
||||
# TODO(tommi): Switch to this and remove specific gtk dependency
|
||||
# sections below for cflags and link_settings.
|
||||
# '<(DEPTH)/build/linux/system.gyp:gtk',
|
||||
|
|
|
|||
|
|
@ -46,10 +46,13 @@ def FindBuildFiles():
|
|||
build_files.append(file)
|
||||
return build_files
|
||||
|
||||
|
||||
#TODO @@NG Find correct way to pass circular_check to Load
|
||||
# Causes a pickle error in gyp.input.CircularException
|
||||
# see http://stackoverflow.com/questions/4677012/python-cant-pickle-type-x-attribute-lookup-failed
|
||||
# we'll live without the check - jesup
|
||||
def Load(build_files, format, default_variables={},
|
||||
includes=[], depth='.', params=None, check=False,
|
||||
circular_check=True, duplicate_basename_check=True):
|
||||
circular_check=False, duplicate_basename_check=True):
|
||||
"""
|
||||
Loads one or more specified build files.
|
||||
default_variables and includes will be copied before use.
|
||||
|
|
|
|||
31
media/webrtc/trunk/webrtc/.gitignore
vendored
31
media/webrtc/trunk/webrtc/.gitignore
vendored
|
|
@ -1,2 +1,29 @@
|
|||
# This file is for projects that checkout webrtc/ directly (e.g. Chromium).
|
||||
*.mk
|
||||
# This file is for projects that checkout webrtc/ directly (e.g. Chromium). It
|
||||
# is a truncated copy of the .gitignore file in the parent directory.
|
||||
*.DS_Store
|
||||
*.Makefile
|
||||
*.host.mk
|
||||
*.ncb
|
||||
*.ninja
|
||||
*.props
|
||||
*.pyc
|
||||
*.rules
|
||||
*.scons
|
||||
*.sdf
|
||||
*.sln
|
||||
*.suo
|
||||
*.target.mk
|
||||
*.targets
|
||||
*.user
|
||||
*.vcproj
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.vpj
|
||||
*.vpw
|
||||
*.vpwhistu
|
||||
*.vtg
|
||||
*.xcodeproj
|
||||
*_proto.xml
|
||||
*_proto_cpp.xml
|
||||
*~
|
||||
.*.sw?
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
# TODO(kjellander): Rebase this to webrtc/build/common.gypi changes after r6330.
|
||||
|
||||
import("//build/config/crypto.gni")
|
||||
import("//build/config/linux/pkg_config.gni")
|
||||
import("//build/config/sanitizers/sanitizers.gni")
|
||||
import("build/webrtc.gni")
|
||||
import("//third_party/protobuf/proto_library.gni")
|
||||
|
||||
# Contains the defines and includes in common.gypi that are duplicated both as
|
||||
# target_defaults and direct_dependent_settings.
|
||||
|
|
@ -20,13 +21,12 @@ config("common_inherited_config") {
|
|||
defines += [ "WEBRTC_MOZILLA_BUILD" ]
|
||||
}
|
||||
if (build_with_chromium) {
|
||||
defines = [
|
||||
"WEBRTC_CHROMIUM_BUILD",
|
||||
]
|
||||
defines = [ "WEBRTC_CHROMIUM_BUILD" ]
|
||||
include_dirs = [
|
||||
# overrides must be included first as that is the mechanism for
|
||||
# The overrides must be included first as that is the mechanism for
|
||||
# selecting the override headers in Chromium.
|
||||
"overrides",
|
||||
"../webrtc_overrides",
|
||||
|
||||
# Allow includes to be prefixed with webrtc/ in case it is not an
|
||||
# immediate subdirectory of the top-level.
|
||||
"..",
|
||||
|
|
@ -41,6 +41,9 @@ config("common_inherited_config") {
|
|||
"WEBRTC_IOS",
|
||||
]
|
||||
}
|
||||
if (is_ios && rtc_use_objc_h264) {
|
||||
defines += [ "WEBRTC_OBJC_H264" ]
|
||||
}
|
||||
if (is_linux) {
|
||||
defines += [ "WEBRTC_LINUX" ]
|
||||
}
|
||||
|
|
@ -55,9 +58,6 @@ config("common_inherited_config") {
|
|||
"WEBRTC_LINUX",
|
||||
"WEBRTC_ANDROID",
|
||||
]
|
||||
if (rtc_enable_android_opensl) {
|
||||
defines += [ "WEBRTC_ANDROID_OPENSLES" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +76,7 @@ config("common_config") {
|
|||
|
||||
if (rtc_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
|
||||
|
|
@ -96,6 +97,7 @@ config("common_config") {
|
|||
if (current_cpu != "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",
|
||||
|
|
@ -104,6 +106,7 @@ config("common_config") {
|
|||
]
|
||||
cflags_cc = [
|
||||
"-Wnon-virtual-dtor",
|
||||
|
||||
# This is enabled for clang; enable for gcc as well.
|
||||
"-Woverloaded-virtual",
|
||||
]
|
||||
|
|
@ -116,13 +119,8 @@ config("common_config") {
|
|||
}
|
||||
|
||||
if (current_cpu == "arm64") {
|
||||
defines += [ "WEBRTC_ARCH_ARM" ]
|
||||
# TODO(zhongwei) Defining an unique WEBRTC_NEON and
|
||||
# distinguishing ARMv7 NEON and ARM64 NEON by
|
||||
# WEBRTC_ARCH_ARM_V7 and WEBRTC_ARCH_ARM64 should be better.
|
||||
|
||||
# This macro is used to distinguish ARMv7 NEON and ARM64 NEON
|
||||
defines += [ "WEBRTC_ARCH_ARM64_NEON" ]
|
||||
defines += [ "WEBRTC_ARCH_ARM64" ]
|
||||
defines += [ "WEBRTC_HAS_NEON" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "arm") {
|
||||
|
|
@ -130,9 +128,9 @@ config("common_config") {
|
|||
if (arm_version >= 7) {
|
||||
defines += [ "WEBRTC_ARCH_ARM_V7" ]
|
||||
if (arm_use_neon) {
|
||||
defines += [ "WEBRTC_ARCH_ARM_NEON" ]
|
||||
} else if (is_android) {
|
||||
defines += [ "WEBRTC_DETECT_ARM_NEON" ]
|
||||
defines += [ "WEBRTC_HAS_NEON" ]
|
||||
} else if (arm_optionally_use_neon) {
|
||||
defines += [ "WEBRTC_DETECT_NEON" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,10 +153,7 @@ config("common_config") {
|
|||
}
|
||||
}
|
||||
|
||||
# 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) {
|
||||
if (is_android && !is_clang) {
|
||||
# The Android NDK doesn"t provide optimized versions of these
|
||||
# functions. Ensure they are disabled for all compilers.
|
||||
cflags += [
|
||||
|
|
@ -174,17 +169,19 @@ source_set("webrtc") {
|
|||
sources = [
|
||||
"call.h",
|
||||
"config.h",
|
||||
"experiments.h",
|
||||
"frame_callback.h",
|
||||
"transport.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
configs += [ ":common_config" ]
|
||||
public_configs = [ ":common_inherited_config"]
|
||||
public_configs = [ ":common_inherited_config" ]
|
||||
|
||||
deps = [
|
||||
":webrtc_common",
|
||||
"audio",
|
||||
"base:rtc_base",
|
||||
"call",
|
||||
"common_audio",
|
||||
"common_video",
|
||||
"modules/audio_coding",
|
||||
|
|
@ -201,16 +198,20 @@ source_set("webrtc") {
|
|||
"system_wrappers",
|
||||
"tools",
|
||||
"video",
|
||||
"video_engine",
|
||||
"voice_engine",
|
||||
]
|
||||
|
||||
if (build_with_chromium) {
|
||||
deps += [
|
||||
"modules/video_capture",
|
||||
"modules/video_render",
|
||||
"modules/video_capture",
|
||||
"modules/video_render",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
defines += [ "ENABLE_RTC_EVENT_LOG" ]
|
||||
deps += [ ":rtc_event_log_proto" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_with_chromium) {
|
||||
|
|
@ -218,8 +219,8 @@ if (!build_with_chromium) {
|
|||
testonly = true
|
||||
deps = [
|
||||
":webrtc",
|
||||
"modules/video_render:video_render_internal_impl",
|
||||
"modules/video_capture:video_capture_internal_impl",
|
||||
"modules/video_render:video_render_internal_impl",
|
||||
"test",
|
||||
]
|
||||
}
|
||||
|
|
@ -229,14 +230,20 @@ source_set("webrtc_common") {
|
|||
sources = [
|
||||
"common_types.cc",
|
||||
"common_types.h",
|
||||
"config.h",
|
||||
"config.cc",
|
||||
"config.h",
|
||||
"engine_configurations.h",
|
||||
"typedefs.h",
|
||||
]
|
||||
|
||||
configs += [ ":common_config" ]
|
||||
public_configs = [ ":common_inherited_config" ]
|
||||
|
||||
if (is_clang && !is_nacl) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("gtest_prod") {
|
||||
|
|
@ -244,3 +251,48 @@ source_set("gtest_prod") {
|
|||
"test/testsupport/gtest_prod_util.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
proto_library("rtc_event_log_proto") {
|
||||
sources = [
|
||||
"call/rtc_event_log.proto",
|
||||
]
|
||||
proto_out_dir = "webrtc/call"
|
||||
}
|
||||
}
|
||||
|
||||
source_set("rtc_event_log") {
|
||||
sources = [
|
||||
"call/rtc_event_log.cc",
|
||||
"call/rtc_event_log.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
configs += [ ":common_config" ]
|
||||
public_configs = [ ":common_inherited_config" ]
|
||||
|
||||
deps = [
|
||||
":webrtc_common",
|
||||
]
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
defines += [ "ENABLE_RTC_EVENT_LOG" ]
|
||||
deps += [ ":rtc_event_log_proto" ]
|
||||
}
|
||||
if (is_clang && !is_nacl) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (use_libfuzzer || use_drfuzz) {
|
||||
# This target is only here for gn to discover fuzzer build targets under
|
||||
# webrtc/test/fuzzers/.
|
||||
group("webrtc_fuzzers_dummy") {
|
||||
testonly = true
|
||||
deps = [
|
||||
"test/fuzzers:webrtc_fuzzer_main",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
76
media/webrtc/trunk/webrtc/api/BUILD.gn
Normal file
76
media/webrtc/trunk/webrtc/api/BUILD.gn
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("../build/webrtc.gni")
|
||||
|
||||
config("ios_config") {
|
||||
libs = [
|
||||
"CoreGraphics.framework",
|
||||
"GLKit.framework",
|
||||
"OpenGLES.framework",
|
||||
"QuartzCore.framework",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_ios) {
|
||||
source_set("rtc_api_objc") {
|
||||
deps = [
|
||||
"//webrtc/base:rtc_base_objc",
|
||||
#"//talk/libjingle:libjingle_peerconnection",
|
||||
]
|
||||
cflags = [
|
||||
"-fobjc-arc",
|
||||
"-Wobjc-missing-property-synthesis",
|
||||
]
|
||||
sources = [
|
||||
# Add these when there's a BUILD.gn for peer connection APIs
|
||||
#"objc/RTCIceCandidate+Private.h",
|
||||
#"objc/RTCIceCandidate.h",
|
||||
#"objc/RTCIceCandidate.mm",
|
||||
#"objc/RTCMediaSource+Private.h",
|
||||
#"objc/RTCMediaSource.h",
|
||||
#"objc/RTCMediaSource.mm",
|
||||
#"objc/RTCMediaStreamTrack+Private.h",
|
||||
#"objc/RTCMediaStreamTrack.h",
|
||||
#"objc/RTCMediaStreamTrack.mm",
|
||||
"objc/RTCIceServer+Private.h",
|
||||
"objc/RTCIceServer.h",
|
||||
"objc/RTCIceServer.mm",
|
||||
"objc/RTCMediaConstraints+Private.h",
|
||||
"objc/RTCMediaConstraints.h",
|
||||
"objc/RTCMediaConstraints.mm",
|
||||
"objc/RTCOpenGLVideoRenderer.h",
|
||||
"objc/RTCOpenGLVideoRenderer.mm",
|
||||
"objc/RTCSessionDescription+Private.h",
|
||||
"objc/RTCSessionDescription.h",
|
||||
"objc/RTCSessionDescription.mm",
|
||||
"objc/RTCStatsReport+Private.h",
|
||||
"objc/RTCStatsReport.h",
|
||||
"objc/RTCStatsReport.mm",
|
||||
"objc/RTCVideoFrame+Private.h",
|
||||
"objc/RTCVideoFrame.h",
|
||||
"objc/RTCVideoFrame.mm",
|
||||
"objc/RTCVideoRenderer.h",
|
||||
"objc/WebRTC-Prefix.pch",
|
||||
]
|
||||
|
||||
if (is_ios) {
|
||||
sources += [
|
||||
"objc/RTCEAGLVideoView.h",
|
||||
"objc/RTCEAGLVideoView.m",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
sources += [
|
||||
"objc/RTCNSGLVideoView.h",
|
||||
"objc/RTCNSGLVideoView.m",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
1
media/webrtc/trunk/webrtc/api/OWNERS
Normal file
1
media/webrtc/trunk/webrtc/api/OWNERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
tkchin@webrtc.org
|
||||
83
media/webrtc/trunk/webrtc/api/api.gyp
Normal file
83
media/webrtc/trunk/webrtc/api/api.gyp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'includes': [ '../build/common.gypi', ],
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rtc_api_objc',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/base/base.gyp:rtc_base_objc',
|
||||
'../../talk/libjingle.gyp:libjingle_peerconnection',
|
||||
],
|
||||
'sources': [
|
||||
'objc/RTCIceCandidate+Private.h',
|
||||
'objc/RTCIceCandidate.h',
|
||||
'objc/RTCIceCandidate.mm',
|
||||
'objc/RTCIceServer+Private.h',
|
||||
'objc/RTCIceServer.h',
|
||||
'objc/RTCIceServer.mm',
|
||||
'objc/RTCMediaConstraints+Private.h',
|
||||
'objc/RTCMediaConstraints.h',
|
||||
'objc/RTCMediaConstraints.mm',
|
||||
'objc/RTCMediaSource+Private.h',
|
||||
'objc/RTCMediaSource.h',
|
||||
'objc/RTCMediaSource.mm',
|
||||
'objc/RTCMediaStreamTrack+Private.h',
|
||||
'objc/RTCMediaStreamTrack.h',
|
||||
'objc/RTCMediaStreamTrack.mm',
|
||||
'objc/RTCOpenGLVideoRenderer.h',
|
||||
'objc/RTCOpenGLVideoRenderer.mm',
|
||||
'objc/RTCSessionDescription+Private.h',
|
||||
'objc/RTCSessionDescription.h',
|
||||
'objc/RTCSessionDescription.mm',
|
||||
'objc/RTCStatsReport+Private.h',
|
||||
'objc/RTCStatsReport.h',
|
||||
'objc/RTCStatsReport.mm',
|
||||
'objc/RTCVideoFrame+Private.h',
|
||||
'objc/RTCVideoFrame.h',
|
||||
'objc/RTCVideoFrame.mm',
|
||||
'objc/RTCVideoRenderer.h',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'sources': [
|
||||
'objc/RTCEAGLVideoView.h',
|
||||
'objc/RTCEAGLVideoView.m',
|
||||
],
|
||||
'all_dependent_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework CoreGraphics',
|
||||
'-framework GLKit',
|
||||
'-framework OpenGLES',
|
||||
'-framework QuartzCore',
|
||||
]
|
||||
}
|
||||
}
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
'sources': [
|
||||
'objc/RTCNSGLVideoView.h',
|
||||
'objc/RTCNSGLVideoView.m',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'xcode_settings': {
|
||||
'CLANG_ENABLE_OBJC_ARC': 'YES',
|
||||
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
|
||||
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
|
||||
},
|
||||
}
|
||||
],
|
||||
}], # OS=="ios"
|
||||
],
|
||||
}
|
||||
40
media/webrtc/trunk/webrtc/api/api_tests.gyp
Normal file
40
media/webrtc/trunk/webrtc/api/api_tests.gyp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'includes': [ '../build/common.gypi', ],
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rtc_api_objc_test',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/api/api.gyp:rtc_api_objc',
|
||||
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
|
||||
],
|
||||
'sources': [
|
||||
'objctests/RTCIceCandidateTest.mm',
|
||||
'objctests/RTCIceServerTest.mm',
|
||||
'objctests/RTCMediaConstraintsTest.mm',
|
||||
'objctests/RTCSessionDescriptionTest.mm',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'CLANG_ENABLE_OBJC_ARC': 'YES',
|
||||
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
|
||||
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
|
||||
# |-ObjC| flag needed to make sure category method implementations
|
||||
# are included:
|
||||
# https://developer.apple.com/library/mac/qa/qa1490/_index.html
|
||||
'OTHER_LDFLAGS': ['-ObjC'],
|
||||
},
|
||||
}
|
||||
],
|
||||
}], # OS=="ios"
|
||||
],
|
||||
}
|
||||
1
media/webrtc/trunk/webrtc/api/objc/OWNERS
Normal file
1
media/webrtc/trunk/webrtc/api/objc/OWNERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
tkchin@webrtc.org
|
||||
3
media/webrtc/trunk/webrtc/api/objc/README
Normal file
3
media/webrtc/trunk/webrtc/api/objc/README
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
This is a work-in-progress to update the Objective-C API according to the W3C
|
||||
specification. The Objective-C API located at talk/app/webrtc/objc is
|
||||
deprecated, but will remain for the time being.
|
||||
35
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.h
Normal file
35
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RTCVideoRenderer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTCEAGLVideoView;
|
||||
@protocol RTCEAGLVideoViewDelegate
|
||||
|
||||
- (void)videoView:(RTCEAGLVideoView *)videoView didChangeVideoSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* RTCEAGLVideoView is an RTCVideoRenderer which renders video frames in its
|
||||
* bounds using OpenGLES 2.0.
|
||||
*/
|
||||
@interface RTCEAGLVideoView : UIView <RTCVideoRenderer>
|
||||
|
||||
@property(nonatomic, weak) id<RTCEAGLVideoViewDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
259
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.m
Normal file
259
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.m
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCEAGLVideoView.h"
|
||||
|
||||
#import <GLKit/GLKit.h>
|
||||
|
||||
#import "RTCVideoFrame.h"
|
||||
#import "RTCOpenGLVideoRenderer.h"
|
||||
|
||||
// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
|
||||
// refreshes, which should be 30fps. We wrap the display link in order to avoid
|
||||
// a retain cycle since CADisplayLink takes a strong reference onto its target.
|
||||
// The timer is paused by default.
|
||||
@interface RTCDisplayLinkTimer : NSObject
|
||||
|
||||
@property(nonatomic) BOOL isPaused;
|
||||
|
||||
- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler;
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RTCDisplayLinkTimer {
|
||||
CADisplayLink *_displayLink;
|
||||
void (^_timerHandler)(void);
|
||||
}
|
||||
|
||||
- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler {
|
||||
NSParameterAssert(timerHandler);
|
||||
if (self = [super init]) {
|
||||
_timerHandler = timerHandler;
|
||||
_displayLink =
|
||||
[CADisplayLink displayLinkWithTarget:self
|
||||
selector:@selector(displayLinkDidFire:)];
|
||||
_displayLink.paused = YES;
|
||||
// Set to half of screen refresh, which should be 30fps.
|
||||
[_displayLink setFrameInterval:2];
|
||||
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop]
|
||||
forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (BOOL)isPaused {
|
||||
return _displayLink.paused;
|
||||
}
|
||||
|
||||
- (void)setIsPaused:(BOOL)isPaused {
|
||||
_displayLink.paused = isPaused;
|
||||
}
|
||||
|
||||
- (void)invalidate {
|
||||
[_displayLink invalidate];
|
||||
}
|
||||
|
||||
- (void)displayLinkDidFire:(CADisplayLink *)displayLink {
|
||||
_timerHandler();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// RTCEAGLVideoView wraps a GLKView which is setup with
|
||||
// enableSetNeedsDisplay = NO for the purpose of gaining control of
|
||||
// exactly when to call -[GLKView display]. This need for extra
|
||||
// control is required to avoid triggering method calls on GLKView
|
||||
// that results in attempting to bind the underlying render buffer
|
||||
// when the drawable size would be empty which would result in the
|
||||
// error GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. -[GLKView display] is
|
||||
// the method that will trigger the binding of the render
|
||||
// buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
|
||||
// is disabled for the reasons above, the RTCEAGLVideoView maintains
|
||||
// its own |isDirty| flag.
|
||||
|
||||
@interface RTCEAGLVideoView () <GLKViewDelegate>
|
||||
// |videoFrame| is set when we receive a frame from a worker thread and is read
|
||||
// from the display link callback so atomicity is required.
|
||||
@property(atomic, strong) RTCVideoFrame *videoFrame;
|
||||
@property(nonatomic, readonly) GLKView *glkView;
|
||||
@property(nonatomic, readonly) RTCOpenGLVideoRenderer *glRenderer;
|
||||
@end
|
||||
|
||||
@implementation RTCEAGLVideoView {
|
||||
RTCDisplayLinkTimer *_timer;
|
||||
// This flag should only be set and read on the main thread (e.g. by
|
||||
// setNeedsDisplay)
|
||||
BOOL _isDirty;
|
||||
}
|
||||
|
||||
@synthesize delegate = _delegate;
|
||||
@synthesize videoFrame = _videoFrame;
|
||||
@synthesize glkView = _glkView;
|
||||
@synthesize glRenderer = _glRenderer;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self configure];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
[self configure];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configure {
|
||||
EAGLContext *glContext =
|
||||
[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
if (!glContext) {
|
||||
glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||
}
|
||||
_glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext];
|
||||
|
||||
// GLKView manages a framebuffer for us.
|
||||
_glkView = [[GLKView alloc] initWithFrame:CGRectZero
|
||||
context:glContext];
|
||||
_glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
|
||||
_glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
|
||||
_glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
|
||||
_glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
|
||||
_glkView.delegate = self;
|
||||
_glkView.layer.masksToBounds = YES;
|
||||
_glkView.enableSetNeedsDisplay = NO;
|
||||
[self addSubview:_glkView];
|
||||
|
||||
// Listen to application state in order to clean up OpenGL before app goes
|
||||
// away.
|
||||
NSNotificationCenter *notificationCenter =
|
||||
[NSNotificationCenter defaultCenter];
|
||||
[notificationCenter addObserver:self
|
||||
selector:@selector(willResignActive)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
[notificationCenter addObserver:self
|
||||
selector:@selector(didBecomeActive)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
// Frames are received on a separate thread, so we poll for current frame
|
||||
// using a refresh rate proportional to screen refresh frequency. This
|
||||
// occurs on the main thread.
|
||||
__weak RTCEAGLVideoView *weakSelf = self;
|
||||
_timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
|
||||
RTCEAGLVideoView *strongSelf = weakSelf;
|
||||
[strongSelf displayLinkTimerDidFire];
|
||||
}];
|
||||
[self setupGL];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
UIApplicationState appState =
|
||||
[UIApplication sharedApplication].applicationState;
|
||||
if (appState == UIApplicationStateActive) {
|
||||
[self teardownGL];
|
||||
}
|
||||
[_timer invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - UIView
|
||||
|
||||
- (void)setNeedsDisplay {
|
||||
[super setNeedsDisplay];
|
||||
_isDirty = YES;
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplayInRect:(CGRect)rect {
|
||||
[super setNeedsDisplayInRect:rect];
|
||||
_isDirty = YES;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
_glkView.frame = self.bounds;
|
||||
}
|
||||
|
||||
#pragma mark - GLKViewDelegate
|
||||
|
||||
// This method is called when the GLKView's content is dirty and needs to be
|
||||
// redrawn. This occurs on main thread.
|
||||
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
|
||||
// The renderer will draw the frame to the framebuffer corresponding to the
|
||||
// one used by |view|.
|
||||
[_glRenderer drawFrame:self.videoFrame];
|
||||
}
|
||||
|
||||
#pragma mark - RTCVideoRenderer
|
||||
|
||||
// These methods may be called on non-main thread.
|
||||
- (void)setSize:(CGSize)size {
|
||||
__weak RTCEAGLVideoView *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
RTCEAGLVideoView *strongSelf = weakSelf;
|
||||
[strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)renderFrame:(RTCVideoFrame *)frame {
|
||||
self.videoFrame = frame;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)displayLinkTimerDidFire {
|
||||
// Don't render unless video frame have changed or the view content
|
||||
// has explicitly been marked dirty.
|
||||
if (!_isDirty && _glRenderer.lastDrawnFrame == self.videoFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always reset isDirty at this point, even if -[GLKView display]
|
||||
// won't be called in the case the drawable size is empty.
|
||||
_isDirty = NO;
|
||||
|
||||
// Only call -[GLKView display] if the drawable size is
|
||||
// non-empty. Calling display will make the GLKView setup its
|
||||
// render buffer if necessary, but that will fail with error
|
||||
// GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
|
||||
if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
|
||||
[_glkView display];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupGL {
|
||||
self.videoFrame = nil;
|
||||
[_glRenderer setupGL];
|
||||
_timer.isPaused = NO;
|
||||
}
|
||||
|
||||
- (void)teardownGL {
|
||||
self.videoFrame = nil;
|
||||
_timer.isPaused = YES;
|
||||
[_glkView deleteDrawable];
|
||||
[_glRenderer teardownGL];
|
||||
}
|
||||
|
||||
- (void)didBecomeActive {
|
||||
[self setupGL];
|
||||
}
|
||||
|
||||
- (void)willResignActive {
|
||||
[self teardownGL];
|
||||
}
|
||||
|
||||
@end
|
||||
36
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate+Private.h
Normal file
36
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate+Private.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCIceCandidate.h"
|
||||
|
||||
#include "talk/app/webrtc/jsep.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCIceCandidate ()
|
||||
|
||||
/**
|
||||
* The native IceCandidateInterface representation of this RTCIceCandidate
|
||||
* object. This is needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly)
|
||||
rtc::scoped_ptr<webrtc::IceCandidateInterface> nativeCandidate;
|
||||
|
||||
/**
|
||||
* Initialize an RTCIceCandidate from a native IceCandidateInterface. No
|
||||
* ownership is taken of the native candidate.
|
||||
*/
|
||||
- (instancetype)initWithNativeCandidate:
|
||||
(webrtc::IceCandidateInterface *)candidate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
44
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.h
Normal file
44
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCIceCandidate : NSObject
|
||||
|
||||
/**
|
||||
* If present, the identifier of the "media stream identification" for the media
|
||||
* component this candidate is associated with.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable) NSString *sdpMid;
|
||||
|
||||
/**
|
||||
* The index (starting at zero) of the media description this candidate is
|
||||
* associated with in the SDP.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSInteger sdpMLineIndex;
|
||||
|
||||
/** The SDP string for this candidate. */
|
||||
@property(nonatomic, readonly) NSString *sdp;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Initialize an RTCIceCandidate from SDP.
|
||||
*/
|
||||
- (instancetype)initWithSdp:(NSString *)sdp
|
||||
sdpMLineIndex:(NSInteger)sdpMLineIndex
|
||||
sdpMid:(nullable NSString *)sdpMid
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
70
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.mm
Normal file
70
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.mm
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCIceCandidate.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCIceCandidate+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
#import "webrtc/base/objc/RTCLogging.h"
|
||||
|
||||
@implementation RTCIceCandidate
|
||||
|
||||
@synthesize sdpMid = _sdpMid;
|
||||
@synthesize sdpMLineIndex = _sdpMLineIndex;
|
||||
@synthesize sdp = _sdp;
|
||||
|
||||
- (instancetype)initWithSdp:(NSString *)sdp
|
||||
sdpMLineIndex:(NSInteger)sdpMLineIndex
|
||||
sdpMid:(NSString *)sdpMid {
|
||||
NSParameterAssert(sdp.length);
|
||||
if (self = [super init]) {
|
||||
_sdpMid = [sdpMid copy];
|
||||
_sdpMLineIndex = sdpMLineIndex;
|
||||
_sdp = [sdp copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCIceCandidate:\n%@\n%ld\n%@",
|
||||
_sdpMid,
|
||||
(long)_sdpMLineIndex,
|
||||
_sdp];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (instancetype)initWithNativeCandidate:
|
||||
(webrtc::IceCandidateInterface *)candidate {
|
||||
NSParameterAssert(candidate);
|
||||
std::string sdp;
|
||||
candidate->ToString(&sdp);
|
||||
|
||||
return [self initWithSdp:[NSString stringForStdString:sdp]
|
||||
sdpMLineIndex:candidate->sdp_mline_index()
|
||||
sdpMid:[NSString stringForStdString:candidate->sdp_mid()]];
|
||||
}
|
||||
|
||||
- (rtc::scoped_ptr<webrtc::IceCandidateInterface>)nativeCandidate {
|
||||
webrtc::SdpParseError error;
|
||||
|
||||
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
|
||||
_sdpMid.stdString, _sdpMLineIndex, _sdp.stdString, &error);
|
||||
|
||||
if (!candidate) {
|
||||
RTCLog(@"Failed to create ICE candidate: %s\nline: %s",
|
||||
error.description.c_str(),
|
||||
error.line.c_str());
|
||||
}
|
||||
|
||||
return rtc::scoped_ptr<webrtc::IceCandidateInterface>(candidate);
|
||||
}
|
||||
|
||||
@end
|
||||
28
media/webrtc/trunk/webrtc/api/objc/RTCIceServer+Private.h
Normal file
28
media/webrtc/trunk/webrtc/api/objc/RTCIceServer+Private.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCIceServer.h"
|
||||
|
||||
#include "talk/app/webrtc/peerconnectioninterface.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCIceServer ()
|
||||
|
||||
/**
|
||||
* IceServer struct representation of this RTCIceServer object's data.
|
||||
* This is needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly)
|
||||
webrtc::PeerConnectionInterface::IceServer iceServer;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
42
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.h
Normal file
42
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCIceServer : NSObject
|
||||
|
||||
/** URI(s) for this server represented as NSStrings. */
|
||||
@property(nonatomic, copy, readonly) NSArray<NSString *> *urlStrings;
|
||||
|
||||
/** Username to use if this RTCIceServer object is a TURN server. */
|
||||
@property(nonatomic, copy, readonly, nullable) NSString *username;
|
||||
|
||||
/** Credential to use if this RTCIceServer object is a TURN server. */
|
||||
@property(nonatomic, copy, readonly, nullable) NSString *credential;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/** Convenience initializer for a server with no authentication (e.g. STUN). */
|
||||
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings;
|
||||
|
||||
/**
|
||||
* Initialize an RTCIceServer with its associated URLs, optional username,
|
||||
* optional credential, and credentialType.
|
||||
*/
|
||||
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
|
||||
username:(nullable NSString *)username
|
||||
credential:(nullable NSString *)credential
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
64
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.mm
Normal file
64
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.mm
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCIceServer.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCIceServer+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
@implementation RTCIceServer
|
||||
|
||||
@synthesize urlStrings = _urlStrings;
|
||||
@synthesize username = _username;
|
||||
@synthesize credential = _credential;
|
||||
|
||||
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings {
|
||||
NSParameterAssert(urlStrings.count);
|
||||
return [self initWithURLStrings:urlStrings
|
||||
username:nil
|
||||
credential:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
|
||||
username:(NSString *)username
|
||||
credential:(NSString *)credential {
|
||||
NSParameterAssert(urlStrings.count);
|
||||
if (self = [super init]) {
|
||||
_urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES];
|
||||
_username = [username copy];
|
||||
_credential = [credential copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@",
|
||||
_urlStrings,
|
||||
_username,
|
||||
_credential];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (webrtc::PeerConnectionInterface::IceServer)iceServer {
|
||||
__block webrtc::PeerConnectionInterface::IceServer iceServer;
|
||||
|
||||
iceServer.username = [NSString stdStringForString:_username];
|
||||
iceServer.password = [NSString stdStringForString:_credential];
|
||||
|
||||
[_urlStrings enumerateObjectsUsingBlock:^(NSString *url,
|
||||
NSUInteger idx,
|
||||
BOOL *stop) {
|
||||
iceServer.urls.push_back(url.stdString);
|
||||
}];
|
||||
return iceServer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaConstraints.h"
|
||||
|
||||
#include "talk/app/webrtc/mediaconstraintsinterface.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class MediaConstraints : public MediaConstraintsInterface {
|
||||
public:
|
||||
virtual ~MediaConstraints();
|
||||
MediaConstraints();
|
||||
MediaConstraints(
|
||||
const MediaConstraintsInterface::Constraints& mandatory,
|
||||
const MediaConstraintsInterface::Constraints& optional);
|
||||
virtual const Constraints& GetMandatory() const;
|
||||
virtual const Constraints& GetOptional() const;
|
||||
|
||||
private:
|
||||
MediaConstraintsInterface::Constraints mandatory_;
|
||||
MediaConstraintsInterface::Constraints optional_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaConstraints ()
|
||||
|
||||
/**
|
||||
* A MediaConstraints representation of this RTCMediaConstraints object. This is
|
||||
* needed to pass to the underlying C++ APIs.
|
||||
*/
|
||||
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints;
|
||||
|
||||
/** Return a native Constraints object representing these constraints */
|
||||
+ (webrtc::MediaConstraintsInterface::Constraints)
|
||||
nativeConstraintsForConstraints:
|
||||
(NSDictionary<NSString *, NSString *> *)constraints;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
28
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.h
Normal file
28
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaConstraints : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/** Initialize with mandatory and/or optional constraints. */
|
||||
- (instancetype)initWithMandatoryConstraints:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)mandatory
|
||||
optionalConstraints:
|
||||
(nullable NSDictionary<NSString *, NSString *> *)optional
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
92
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.mm
Normal file
92
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.mm
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaConstraints.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCMediaConstraints+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
MediaConstraints::~MediaConstraints() {}
|
||||
|
||||
MediaConstraints::MediaConstraints() {}
|
||||
|
||||
MediaConstraints::MediaConstraints(
|
||||
const MediaConstraintsInterface::Constraints& mandatory,
|
||||
const MediaConstraintsInterface::Constraints& optional)
|
||||
: mandatory_(mandatory), optional_(optional) {}
|
||||
|
||||
const MediaConstraintsInterface::Constraints&
|
||||
MediaConstraints::GetMandatory() const {
|
||||
return mandatory_;
|
||||
}
|
||||
|
||||
const MediaConstraintsInterface::Constraints&
|
||||
MediaConstraints::GetOptional() const {
|
||||
return optional_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@implementation RTCMediaConstraints {
|
||||
NSDictionary<NSString *, NSString *> *_mandatory;
|
||||
NSDictionary<NSString *, NSString *> *_optional;
|
||||
}
|
||||
|
||||
- (instancetype)initWithMandatoryConstraints:
|
||||
(NSDictionary<NSString *, NSString *> *)mandatory
|
||||
optionalConstraints:
|
||||
(NSDictionary<NSString *, NSString *> *)optional {
|
||||
if (self = [super init]) {
|
||||
_mandatory = [[NSDictionary alloc] initWithDictionary:mandatory
|
||||
copyItems:YES];
|
||||
_optional = [[NSDictionary alloc] initWithDictionary:optional
|
||||
copyItems:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCMediaConstraints:\n%@\n%@",
|
||||
_mandatory,
|
||||
_optional];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints {
|
||||
webrtc::MediaConstraintsInterface::Constraints mandatory =
|
||||
[[self class] nativeConstraintsForConstraints:_mandatory];
|
||||
webrtc::MediaConstraintsInterface::Constraints optional =
|
||||
[[self class] nativeConstraintsForConstraints:_optional];
|
||||
|
||||
webrtc::MediaConstraints *nativeConstraints =
|
||||
new webrtc::MediaConstraints(mandatory, optional);
|
||||
return rtc::scoped_ptr<webrtc::MediaConstraints>(nativeConstraints);
|
||||
}
|
||||
|
||||
+ (webrtc::MediaConstraintsInterface::Constraints)
|
||||
nativeConstraintsForConstraints:
|
||||
(NSDictionary<NSString *, NSString *> *)constraints {
|
||||
webrtc::MediaConstraintsInterface::Constraints nativeConstraints;
|
||||
for (NSString *key in constraints) {
|
||||
NSAssert([key isKindOfClass:[NSString class]],
|
||||
@"%@ is not an NSString.", key);
|
||||
NSAssert([constraints[key] isKindOfClass:[NSString class]],
|
||||
@"%@ is not an NSString.", constraints[key]);
|
||||
nativeConstraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
|
||||
key.stdString, constraints[key].stdString));
|
||||
}
|
||||
return nativeConstraints;
|
||||
}
|
||||
|
||||
@end
|
||||
41
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource+Private.h
Normal file
41
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource+Private.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaSource.h"
|
||||
|
||||
#include "talk/app/webrtc/mediastreaminterface.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaSource ()
|
||||
|
||||
/**
|
||||
* The MediaSourceInterface object passed to this RTCMediaSource during
|
||||
* construction.
|
||||
*/
|
||||
@property(nonatomic, readonly)
|
||||
rtc::scoped_refptr<webrtc::MediaSourceInterface> nativeMediaSource;
|
||||
|
||||
/** Initialize an RTCMediaSource from a native MediaSourceInterface. */
|
||||
- (instancetype)initWithNativeMediaSource:
|
||||
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
|
||||
(RTCSourceState)state;
|
||||
|
||||
+ (RTCSourceState)sourceStateForNativeState:
|
||||
(webrtc::MediaSourceInterface::SourceState)nativeState;
|
||||
|
||||
+ (NSString *)stringForState:(RTCSourceState)state;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
31
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.h
Normal file
31
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, RTCSourceState) {
|
||||
RTCSourceStateInitializing,
|
||||
RTCSourceStateLive,
|
||||
RTCSourceStateEnded,
|
||||
RTCSourceStateMuted,
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaSource : NSObject
|
||||
|
||||
/** The current state of the RTCMediaSource. */
|
||||
@property(nonatomic, readonly) RTCSourceState state;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
84
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.mm
Normal file
84
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.mm
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaSource.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCMediaSource+Private.h"
|
||||
|
||||
@implementation RTCMediaSource {
|
||||
rtc::scoped_refptr<webrtc::MediaSourceInterface> _nativeMediaSource;
|
||||
}
|
||||
|
||||
- (RTCSourceState)state {
|
||||
return [[self class] sourceStateForNativeState:_nativeMediaSource->state()];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCMediaSource:\n%@",
|
||||
[[self class] stringForState:self.state]];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
|
||||
return _nativeMediaSource;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeMediaSource:
|
||||
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
|
||||
NSParameterAssert(nativeMediaSource);
|
||||
if (self = [super init]) {
|
||||
_nativeMediaSource = nativeMediaSource;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
|
||||
(RTCSourceState)state {
|
||||
switch (state) {
|
||||
case RTCSourceStateInitializing:
|
||||
return webrtc::MediaSourceInterface::kInitializing;
|
||||
case RTCSourceStateLive:
|
||||
return webrtc::MediaSourceInterface::kLive;
|
||||
case RTCSourceStateEnded:
|
||||
return webrtc::MediaSourceInterface::kEnded;
|
||||
case RTCSourceStateMuted:
|
||||
return webrtc::MediaSourceInterface::kMuted;
|
||||
}
|
||||
}
|
||||
|
||||
+ (RTCSourceState)sourceStateForNativeState:
|
||||
(webrtc::MediaSourceInterface::SourceState)nativeState {
|
||||
switch (nativeState) {
|
||||
case webrtc::MediaSourceInterface::kInitializing:
|
||||
return RTCSourceStateInitializing;
|
||||
case webrtc::MediaSourceInterface::kLive:
|
||||
return RTCSourceStateLive;
|
||||
case webrtc::MediaSourceInterface::kEnded:
|
||||
return RTCSourceStateEnded;
|
||||
case webrtc::MediaSourceInterface::kMuted:
|
||||
return RTCSourceStateMuted;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)stringForState:(RTCSourceState)state {
|
||||
switch (state) {
|
||||
case RTCSourceStateInitializing:
|
||||
return @"Initializing";
|
||||
case RTCSourceStateLive:
|
||||
return @"Live";
|
||||
case RTCSourceStateEnded:
|
||||
return @"Ended";
|
||||
case RTCSourceStateMuted:
|
||||
return @"Muted";
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaStreamTrack.h"
|
||||
|
||||
#include "talk/app/webrtc/mediastreaminterface.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaStreamTrack ()
|
||||
|
||||
/**
|
||||
* The native MediaStreamTrackInterface representation of this
|
||||
* RTCMediaStreamTrack object. This is needed to pass to the underlying C++
|
||||
* APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly)
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack;
|
||||
|
||||
/**
|
||||
* Initialize an RTCMediaStreamTrack from a native MediaStreamTrackInterface.
|
||||
*/
|
||||
- (instancetype)initWithNativeTrack:
|
||||
(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
+ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
|
||||
(RTCMediaStreamTrackState)state;
|
||||
|
||||
+ (RTCMediaStreamTrackState)trackStateForNativeState:
|
||||
(webrtc::MediaStreamTrackInterface::TrackState)nativeState;
|
||||
|
||||
+ (NSString *)stringForState:(RTCMediaStreamTrackState)state;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
47
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.h
Normal file
47
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Represents the state of the track. This exposes the same states in C++,
|
||||
* which include two more states than are in the W3C spec.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, RTCMediaStreamTrackState) {
|
||||
RTCMediaStreamTrackStateInitializing,
|
||||
RTCMediaStreamTrackStateLive,
|
||||
RTCMediaStreamTrackStateEnded,
|
||||
RTCMediaStreamTrackStateFailed,
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCMediaStreamTrack : NSObject
|
||||
|
||||
/**
|
||||
* The kind of track. For example, "audio" if this track represents an audio
|
||||
* track and "video" if this track represents a video track.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSString *kind;
|
||||
|
||||
/** An identifier string. */
|
||||
@property(nonatomic, readonly) NSString *trackId;
|
||||
|
||||
/** The enabled state of the track. */
|
||||
@property(nonatomic) BOOL isEnabled;
|
||||
|
||||
/** The state of the track. */
|
||||
@property(nonatomic, readonly) RTCMediaStreamTrackState readyState;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
105
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.mm
Normal file
105
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.mm
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCMediaStreamTrack.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCMediaStreamTrack+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
@implementation RTCMediaStreamTrack {
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> _nativeTrack;
|
||||
}
|
||||
|
||||
- (NSString *)kind {
|
||||
return [NSString stringForStdString:_nativeTrack->kind()];
|
||||
}
|
||||
|
||||
- (NSString *)trackId {
|
||||
return [NSString stringForStdString:_nativeTrack->id()];
|
||||
}
|
||||
|
||||
- (BOOL)isEnabled {
|
||||
return _nativeTrack->enabled();
|
||||
}
|
||||
|
||||
- (void)setIsEnabled:(BOOL)isEnabled {
|
||||
_nativeTrack->set_enabled(isEnabled);
|
||||
}
|
||||
|
||||
- (RTCMediaStreamTrackState)readyState {
|
||||
return [[self class] trackStateForNativeState:_nativeTrack->state()];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSString *readyState = [[self class] stringForState:self.readyState];
|
||||
return [NSString stringWithFormat:@"RTCMediaStreamTrack:\n%@\n%@\n%@\n%@",
|
||||
self.kind,
|
||||
self.trackId,
|
||||
self.isEnabled ? @"enabled" : @"disabled",
|
||||
readyState];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
|
||||
return _nativeTrack;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeTrack:
|
||||
(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
|
||||
NSParameterAssert(nativeTrack);
|
||||
if (self = [super init]) {
|
||||
_nativeTrack = nativeTrack;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
|
||||
(RTCMediaStreamTrackState)state {
|
||||
switch (state) {
|
||||
case RTCMediaStreamTrackStateInitializing:
|
||||
return webrtc::MediaStreamTrackInterface::kInitializing;
|
||||
case RTCMediaStreamTrackStateLive:
|
||||
return webrtc::MediaStreamTrackInterface::kLive;
|
||||
case RTCMediaStreamTrackStateEnded:
|
||||
return webrtc::MediaStreamTrackInterface::kEnded;
|
||||
case RTCMediaStreamTrackStateFailed:
|
||||
return webrtc::MediaStreamTrackInterface::kFailed;
|
||||
}
|
||||
}
|
||||
|
||||
+ (RTCMediaStreamTrackState)trackStateForNativeState:
|
||||
(webrtc::MediaStreamTrackInterface::TrackState)nativeState {
|
||||
switch (nativeState) {
|
||||
case webrtc::MediaStreamTrackInterface::kInitializing:
|
||||
return RTCMediaStreamTrackStateInitializing;
|
||||
case webrtc::MediaStreamTrackInterface::kLive:
|
||||
return RTCMediaStreamTrackStateLive;
|
||||
case webrtc::MediaStreamTrackInterface::kEnded:
|
||||
return RTCMediaStreamTrackStateEnded;
|
||||
case webrtc::MediaStreamTrackInterface::kFailed:
|
||||
return RTCMediaStreamTrackStateFailed;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)stringForState:(RTCMediaStreamTrackState)state {
|
||||
switch (state) {
|
||||
case RTCMediaStreamTrackStateInitializing:
|
||||
return @"Initializing";
|
||||
case RTCMediaStreamTrackStateLive:
|
||||
return @"Live";
|
||||
case RTCMediaStreamTrackStateEnded:
|
||||
return @"Ended";
|
||||
case RTCMediaStreamTrackStateFailed:
|
||||
return @"Failed";
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
34
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.h
Normal file
34
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#error "This file targets OSX."
|
||||
#endif
|
||||
|
||||
#import <AppKit/NSOpenGLView.h>
|
||||
|
||||
#import "RTCVideoRenderer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTCNSGLVideoView;
|
||||
@protocol RTCNSGLVideoViewDelegate
|
||||
|
||||
- (void)videoView:(RTCNSGLVideoView *)videoView didChangeVideoSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
|
||||
@interface RTCNSGLVideoView : NSOpenGLView <RTCVideoRenderer>
|
||||
|
||||
@property(nonatomic, weak) id<RTCNSGLVideoViewDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
141
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.m
Normal file
141
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.m
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCNSGLVideoView.h"
|
||||
|
||||
#import <CoreVideo/CVDisplayLink.h>
|
||||
#import <OpenGL/gl3.h>
|
||||
#import "RTCVideoFrame.h"
|
||||
#import "RTCOpenGLVideoRenderer.h"
|
||||
|
||||
@interface RTCNSGLVideoView ()
|
||||
// |videoFrame| is set when we receive a frame from a worker thread and is read
|
||||
// from the display link callback so atomicity is required.
|
||||
@property(atomic, strong) RTCVideoFrame *videoFrame;
|
||||
@property(atomic, strong) RTCOpenGLVideoRenderer *glRenderer;
|
||||
- (void)drawFrame;
|
||||
@end
|
||||
|
||||
static CVReturn OnDisplayLinkFired(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *now,
|
||||
const CVTimeStamp *outputTime,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags *flagsOut,
|
||||
void *displayLinkContext) {
|
||||
RTCNSGLVideoView *view = (__bridge RTCNSGLVideoView *)displayLinkContext;
|
||||
[view drawFrame];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
@implementation RTCNSGLVideoView {
|
||||
CVDisplayLinkRef _displayLink;
|
||||
}
|
||||
|
||||
@synthesize delegate = _delegate;
|
||||
@synthesize videoFrame = _videoFrame;
|
||||
@synthesize glRenderer = _glRenderer;
|
||||
|
||||
- (void)dealloc {
|
||||
[self teardownDisplayLink];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)rect {
|
||||
[self drawFrame];
|
||||
}
|
||||
|
||||
- (void)reshape {
|
||||
[super reshape];
|
||||
NSRect frame = [self frame];
|
||||
CGLLockContext([[self openGLContext] CGLContextObj]);
|
||||
glViewport(0, 0, frame.size.width, frame.size.height);
|
||||
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
||||
}
|
||||
|
||||
- (void)lockFocus {
|
||||
NSOpenGLContext *context = [self openGLContext];
|
||||
[super lockFocus];
|
||||
if ([context view] != self) {
|
||||
[context setView:self];
|
||||
}
|
||||
[context makeCurrentContext];
|
||||
}
|
||||
|
||||
- (void)prepareOpenGL {
|
||||
[super prepareOpenGL];
|
||||
if (!self.glRenderer) {
|
||||
self.glRenderer =
|
||||
[[RTCOpenGLVideoRenderer alloc] initWithContext:[self openGLContext]];
|
||||
}
|
||||
[self.glRenderer setupGL];
|
||||
[self setupDisplayLink];
|
||||
}
|
||||
|
||||
- (void)clearGLContext {
|
||||
[self.glRenderer teardownGL];
|
||||
self.glRenderer = nil;
|
||||
[super clearGLContext];
|
||||
}
|
||||
|
||||
#pragma mark - RTCVideoRenderer
|
||||
|
||||
// These methods may be called on non-main thread.
|
||||
- (void)setSize:(CGSize)size {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.delegate videoView:self didChangeVideoSize:size];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)renderFrame:(RTCVideoFrame *)frame {
|
||||
self.videoFrame = frame;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)drawFrame {
|
||||
RTCVideoFrame *videoFrame = self.videoFrame;
|
||||
if (self.glRenderer.lastDrawnFrame != videoFrame) {
|
||||
// This method may be called from CVDisplayLink callback which isn't on the
|
||||
// main thread so we have to lock the GL context before drawing.
|
||||
CGLLockContext([[self openGLContext] CGLContextObj]);
|
||||
[self.glRenderer drawFrame:videoFrame];
|
||||
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupDisplayLink {
|
||||
if (_displayLink) {
|
||||
return;
|
||||
}
|
||||
// Synchronize buffer swaps with vertical refresh rate.
|
||||
GLint swapInt = 1;
|
||||
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
// Create display link.
|
||||
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
|
||||
CVDisplayLinkSetOutputCallback(_displayLink,
|
||||
&OnDisplayLinkFired,
|
||||
(__bridge void *)self);
|
||||
// Set the display link for the current renderer.
|
||||
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
|
||||
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
|
||||
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
|
||||
_displayLink, cglContext, cglPixelFormat);
|
||||
CVDisplayLinkStart(_displayLink);
|
||||
}
|
||||
|
||||
- (void)teardownDisplayLink {
|
||||
if (!_displayLink) {
|
||||
return;
|
||||
}
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
_displayLink = NULL;
|
||||
}
|
||||
|
||||
@end
|
||||
58
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.h
Normal file
58
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <GLKit/GLKit.h>
|
||||
#else
|
||||
#import <AppKit/NSOpenGL.h>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTCVideoFrame;
|
||||
|
||||
// RTCOpenGLVideoRenderer issues appropriate OpenGL commands to draw a frame to
|
||||
// the currently bound framebuffer. Supports OpenGL 3.2 and OpenGLES 2.0. OpenGL
|
||||
// framebuffer creation and management should be handled elsewhere using the
|
||||
// same context used to initialize this class.
|
||||
@interface RTCOpenGLVideoRenderer : NSObject
|
||||
|
||||
// The last successfully drawn frame. Used to avoid drawing frames unnecessarily
|
||||
// hence saving battery life by reducing load.
|
||||
@property(nonatomic, readonly) RTCVideoFrame *lastDrawnFrame;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (instancetype)initWithContext:(EAGLContext *)context
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
#else
|
||||
- (instancetype)initWithContext:(NSOpenGLContext *)context
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
#endif
|
||||
|
||||
// Draws |frame| onto the currently bound OpenGL framebuffer. |setupGL| must be
|
||||
// called before this function will succeed.
|
||||
- (BOOL)drawFrame:(RTCVideoFrame *)frame;
|
||||
|
||||
// The following methods are used to manage OpenGL resources. On iOS
|
||||
// applications should release resources when placed in background for use in
|
||||
// the foreground application. In fact, attempting to call OpenGLES commands
|
||||
// while in background will result in application termination.
|
||||
|
||||
// Sets up the OpenGL state needed for rendering.
|
||||
- (void)setupGL;
|
||||
// Tears down the OpenGL state created by |setupGL|.
|
||||
- (void)teardownGL;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
485
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.mm
Normal file
485
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.mm
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCOpenGLVideoRenderer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <OpenGLES/ES3/gl.h>
|
||||
#else
|
||||
#import <OpenGL/gl3.h>
|
||||
#endif
|
||||
|
||||
#import "RTCVideoFrame.h"
|
||||
|
||||
// TODO(tkchin): check and log openGL errors. Methods here return BOOLs in
|
||||
// anticipation of that happening in the future.
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define RTC_PIXEL_FORMAT GL_LUMINANCE
|
||||
#define SHADER_VERSION
|
||||
#define VERTEX_SHADER_IN "attribute"
|
||||
#define VERTEX_SHADER_OUT "varying"
|
||||
#define FRAGMENT_SHADER_IN "varying"
|
||||
#define FRAGMENT_SHADER_OUT
|
||||
#define FRAGMENT_SHADER_COLOR "gl_FragColor"
|
||||
#define FRAGMENT_SHADER_TEXTURE "texture2D"
|
||||
#else
|
||||
#define RTC_PIXEL_FORMAT GL_RED
|
||||
#define SHADER_VERSION "#version 150\n"
|
||||
#define VERTEX_SHADER_IN "in"
|
||||
#define VERTEX_SHADER_OUT "out"
|
||||
#define FRAGMENT_SHADER_IN "in"
|
||||
#define FRAGMENT_SHADER_OUT "out vec4 fragColor;\n"
|
||||
#define FRAGMENT_SHADER_COLOR "fragColor"
|
||||
#define FRAGMENT_SHADER_TEXTURE "texture"
|
||||
#endif
|
||||
|
||||
// Vertex shader doesn't do anything except pass coordinates through.
|
||||
static const char kVertexShaderSource[] =
|
||||
SHADER_VERSION
|
||||
VERTEX_SHADER_IN " vec2 position;\n"
|
||||
VERTEX_SHADER_IN " vec2 texcoord;\n"
|
||||
VERTEX_SHADER_OUT " vec2 v_texcoord;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(position.x, position.y, 0.0, 1.0);\n"
|
||||
" v_texcoord = texcoord;\n"
|
||||
"}\n";
|
||||
|
||||
// Fragment shader converts YUV values from input textures into a final RGB
|
||||
// pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
|
||||
static const char kFragmentShaderSource[] =
|
||||
SHADER_VERSION
|
||||
"precision highp float;"
|
||||
FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
|
||||
"uniform lowp sampler2D s_textureY;\n"
|
||||
"uniform lowp sampler2D s_textureU;\n"
|
||||
"uniform lowp sampler2D s_textureV;\n"
|
||||
FRAGMENT_SHADER_OUT
|
||||
"void main() {\n"
|
||||
" float y, u, v, r, g, b;\n"
|
||||
" y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
|
||||
" u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
|
||||
" v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
|
||||
" u = u - 0.5;\n"
|
||||
" v = v - 0.5;\n"
|
||||
" r = y + 1.403 * v;\n"
|
||||
" g = y - 0.344 * u - 0.714 * v;\n"
|
||||
" b = y + 1.770 * u;\n"
|
||||
" " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
|
||||
" }\n";
|
||||
|
||||
// Compiles a shader of the given |type| with GLSL source |source| and returns
|
||||
// the shader handle or 0 on error.
|
||||
GLuint CreateShader(GLenum type, const GLchar *source) {
|
||||
GLuint shader = glCreateShader(type);
|
||||
if (!shader) {
|
||||
return 0;
|
||||
}
|
||||
glShaderSource(shader, 1, &source, NULL);
|
||||
glCompileShader(shader);
|
||||
GLint compileStatus = GL_FALSE;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
|
||||
if (compileStatus == GL_FALSE) {
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
// Links a shader program with the given vertex and fragment shaders and
|
||||
// returns the program handle or 0 on error.
|
||||
GLuint CreateProgram(GLuint vertexShader, GLuint fragmentShader) {
|
||||
if (vertexShader == 0 || fragmentShader == 0) {
|
||||
return 0;
|
||||
}
|
||||
GLuint program = glCreateProgram();
|
||||
if (!program) {
|
||||
return 0;
|
||||
}
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
GLint linkStatus = GL_FALSE;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus == GL_FALSE) {
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
// When modelview and projection matrices are identity (default) the world is
|
||||
// contained in the square around origin with unit size 2. Drawing to these
|
||||
// coordinates is equivalent to drawing to the entire screen. The texture is
|
||||
// stretched over that square using texture coordinates (u, v) that range
|
||||
// from (0, 0) to (1, 1) inclusive. Texture coordinates are flipped vertically
|
||||
// here because the incoming frame has origin in upper left hand corner but
|
||||
// OpenGL expects origin in bottom left corner.
|
||||
const GLfloat gVertices[] = {
|
||||
// X, Y, U, V.
|
||||
-1, -1, 0, 1, // Bottom left.
|
||||
1, -1, 1, 1, // Bottom right.
|
||||
1, 1, 1, 0, // Top right.
|
||||
-1, 1, 0, 0, // Top left.
|
||||
};
|
||||
|
||||
// |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
|
||||
// of 3 textures are used here, one for each of the Y, U and V planes. Having
|
||||
// two sets alleviates CPU blockage in the event that the GPU is asked to render
|
||||
// to a texture that is already in use.
|
||||
static const GLsizei kNumTextureSets = 2;
|
||||
static const GLsizei kNumTextures = 3 * kNumTextureSets;
|
||||
|
||||
@implementation RTCOpenGLVideoRenderer {
|
||||
#if TARGET_OS_IPHONE
|
||||
EAGLContext *_context;
|
||||
#else
|
||||
NSOpenGLContext *_context;
|
||||
#endif
|
||||
BOOL _isInitialized;
|
||||
NSUInteger _currentTextureSet;
|
||||
// Handles for OpenGL constructs.
|
||||
GLuint _textures[kNumTextures];
|
||||
GLuint _program;
|
||||
#if !TARGET_OS_IPHONE
|
||||
GLuint _vertexArray;
|
||||
#endif
|
||||
GLuint _vertexBuffer;
|
||||
GLint _position;
|
||||
GLint _texcoord;
|
||||
GLint _ySampler;
|
||||
GLint _uSampler;
|
||||
GLint _vSampler;
|
||||
// Used to create a non-padded plane for GPU upload when we receive padded
|
||||
// frames.
|
||||
rtc::scoped_ptr<uint8_t[]> _planeBuffer;
|
||||
}
|
||||
|
||||
@synthesize lastDrawnFrame = _lastDrawnFrame;
|
||||
|
||||
+ (void)initialize {
|
||||
// Disable dithering for performance.
|
||||
glDisable(GL_DITHER);
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (instancetype)initWithContext:(EAGLContext *)context {
|
||||
#else
|
||||
- (instancetype)initWithContext:(NSOpenGLContext *)context {
|
||||
#endif
|
||||
NSAssert(context != nil, @"context cannot be nil");
|
||||
if (self = [super init]) {
|
||||
_context = context;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)drawFrame:(RTCVideoFrame *)frame {
|
||||
if (!_isInitialized) {
|
||||
return NO;
|
||||
}
|
||||
if (_lastDrawnFrame == frame) {
|
||||
return NO;
|
||||
}
|
||||
[self ensureGLContext];
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (frame) {
|
||||
if (![self updateTextureSizesForFrame:frame] ||
|
||||
![self updateTextureDataForFrame:frame]) {
|
||||
return NO;
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
glBindVertexArray(_vertexArray);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
[_context flushBuffer];
|
||||
#endif
|
||||
_lastDrawnFrame = frame;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setupGL {
|
||||
if (_isInitialized) {
|
||||
return;
|
||||
}
|
||||
[self ensureGLContext];
|
||||
if (![self setupProgram]) {
|
||||
return;
|
||||
}
|
||||
if (![self setupTextures]) {
|
||||
return;
|
||||
}
|
||||
if (![self setupVertices]) {
|
||||
return;
|
||||
}
|
||||
glUseProgram(_program);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
_isInitialized = YES;
|
||||
}
|
||||
|
||||
- (void)teardownGL {
|
||||
if (!_isInitialized) {
|
||||
return;
|
||||
}
|
||||
[self ensureGLContext];
|
||||
glDeleteProgram(_program);
|
||||
_program = 0;
|
||||
glDeleteTextures(kNumTextures, _textures);
|
||||
glDeleteBuffers(1, &_vertexBuffer);
|
||||
_vertexBuffer = 0;
|
||||
#if !TARGET_OS_IPHONE
|
||||
glDeleteVertexArrays(1, &_vertexArray);
|
||||
#endif
|
||||
_isInitialized = NO;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)ensureGLContext {
|
||||
NSAssert(_context, @"context shouldn't be nil");
|
||||
#if TARGET_OS_IPHONE
|
||||
if ([EAGLContext currentContext] != _context) {
|
||||
[EAGLContext setCurrentContext:_context];
|
||||
}
|
||||
#else
|
||||
if ([NSOpenGLContext currentContext] != _context) {
|
||||
[_context makeCurrentContext];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)setupProgram {
|
||||
NSAssert(!_program, @"program already set up");
|
||||
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, kVertexShaderSource);
|
||||
NSAssert(vertexShader, @"failed to create vertex shader");
|
||||
GLuint fragmentShader =
|
||||
CreateShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
|
||||
NSAssert(fragmentShader, @"failed to create fragment shader");
|
||||
_program = CreateProgram(vertexShader, fragmentShader);
|
||||
// Shaders are created only to generate program.
|
||||
if (vertexShader) {
|
||||
glDeleteShader(vertexShader);
|
||||
}
|
||||
if (fragmentShader) {
|
||||
glDeleteShader(fragmentShader);
|
||||
}
|
||||
if (!_program) {
|
||||
return NO;
|
||||
}
|
||||
_position = glGetAttribLocation(_program, "position");
|
||||
_texcoord = glGetAttribLocation(_program, "texcoord");
|
||||
_ySampler = glGetUniformLocation(_program, "s_textureY");
|
||||
_uSampler = glGetUniformLocation(_program, "s_textureU");
|
||||
_vSampler = glGetUniformLocation(_program, "s_textureV");
|
||||
if (_position < 0 || _texcoord < 0 || _ySampler < 0 || _uSampler < 0 ||
|
||||
_vSampler < 0) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)setupTextures {
|
||||
glGenTextures(kNumTextures, _textures);
|
||||
// Set parameters for each of the textures we created.
|
||||
for (GLsizei i = 0; i < kNumTextures; i++) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, _textures[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)updateTextureSizesForFrame:(RTCVideoFrame *)frame {
|
||||
if (frame.height == _lastDrawnFrame.height &&
|
||||
frame.width == _lastDrawnFrame.width &&
|
||||
frame.chromaWidth == _lastDrawnFrame.chromaWidth &&
|
||||
frame.chromaHeight == _lastDrawnFrame.chromaHeight) {
|
||||
return YES;
|
||||
}
|
||||
GLsizei lumaWidth = frame.width;
|
||||
GLsizei lumaHeight = frame.height;
|
||||
GLsizei chromaWidth = frame.chromaWidth;
|
||||
GLsizei chromaHeight = frame.chromaHeight;
|
||||
for (GLint i = 0; i < kNumTextureSets; i++) {
|
||||
glActiveTexture(GL_TEXTURE0 + i * 3);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
lumaWidth,
|
||||
lumaHeight,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0);
|
||||
glActiveTexture(GL_TEXTURE0 + i * 3 + 1);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
chromaWidth,
|
||||
chromaHeight,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0);
|
||||
glActiveTexture(GL_TEXTURE0 + i * 3 + 2);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
chromaWidth,
|
||||
chromaHeight,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0);
|
||||
}
|
||||
if ((NSUInteger)frame.yPitch != frame.width ||
|
||||
(NSUInteger)frame.uPitch != frame.chromaWidth ||
|
||||
(NSUInteger)frame.vPitch != frame.chromaWidth) {
|
||||
_planeBuffer.reset(new uint8_t[frame.width * frame.height]);
|
||||
} else {
|
||||
_planeBuffer.reset();
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)uploadPlane:(const uint8_t *)plane
|
||||
sampler:(GLint)sampler
|
||||
offset:(NSUInteger)offset
|
||||
width:(size_t)width
|
||||
height:(size_t)height
|
||||
stride:(int32_t)stride {
|
||||
glActiveTexture(GL_TEXTURE0 + offset);
|
||||
// When setting texture sampler uniforms, the texture index is used not
|
||||
// the texture handle.
|
||||
glUniform1i(sampler, offset);
|
||||
#if TARGET_OS_IPHONE
|
||||
BOOL hasUnpackRowLength = _context.API == kEAGLRenderingAPIOpenGLES3;
|
||||
#else
|
||||
BOOL hasUnpackRowLength = YES;
|
||||
#endif
|
||||
const uint8_t *uploadPlane = plane;
|
||||
if ((size_t)stride != width) {
|
||||
if (hasUnpackRowLength) {
|
||||
// GLES3 allows us to specify stride.
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
uploadPlane);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
return;
|
||||
} else {
|
||||
// Make an unpadded copy and upload that instead. Quick profiling showed
|
||||
// that this is faster than uploading row by row using glTexSubImage2D.
|
||||
uint8_t *unpaddedPlane = _planeBuffer.get();
|
||||
for (size_t y = 0; y < height; ++y) {
|
||||
memcpy(unpaddedPlane + y * width, plane + y * stride, width);
|
||||
}
|
||||
uploadPlane = unpaddedPlane;
|
||||
}
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
RTC_PIXEL_FORMAT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
uploadPlane);
|
||||
}
|
||||
|
||||
- (BOOL)updateTextureDataForFrame:(RTCVideoFrame *)frame {
|
||||
NSUInteger textureOffset = _currentTextureSet * 3;
|
||||
NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
|
||||
|
||||
[self uploadPlane:frame.yPlane
|
||||
sampler:_ySampler
|
||||
offset:textureOffset
|
||||
width:frame.width
|
||||
height:frame.height
|
||||
stride:frame.yPitch];
|
||||
|
||||
[self uploadPlane:frame.uPlane
|
||||
sampler:_uSampler
|
||||
offset:textureOffset + 1
|
||||
width:frame.chromaWidth
|
||||
height:frame.chromaHeight
|
||||
stride:frame.uPitch];
|
||||
|
||||
[self uploadPlane:frame.vPlane
|
||||
sampler:_vSampler
|
||||
offset:textureOffset + 2
|
||||
width:frame.chromaWidth
|
||||
height:frame.chromaHeight
|
||||
stride:frame.vPitch];
|
||||
|
||||
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)setupVertices {
|
||||
#if !TARGET_OS_IPHONE
|
||||
NSAssert(!_vertexArray, @"vertex array already set up");
|
||||
glGenVertexArrays(1, &_vertexArray);
|
||||
if (!_vertexArray) {
|
||||
return NO;
|
||||
}
|
||||
glBindVertexArray(_vertexArray);
|
||||
#endif
|
||||
NSAssert(!_vertexBuffer, @"vertex buffer already set up");
|
||||
glGenBuffers(1, &_vertexBuffer);
|
||||
if (!_vertexBuffer) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
glDeleteVertexArrays(1, &_vertexArray);
|
||||
_vertexArray = 0;
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
// Read position attribute from |gVertices| with size of 2 and stride of 4
|
||||
// beginning at the start of the array. The last argument indicates offset
|
||||
// of data within |gVertices| as supplied to the vertex buffer.
|
||||
glVertexAttribPointer(
|
||||
_position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)0);
|
||||
glEnableVertexAttribArray(_position);
|
||||
|
||||
// Read texcoord attribute from |gVertices| with size of 2 and stride of 4
|
||||
// beginning at the first texcoord in the array. The last argument indicates
|
||||
// offset of data within |gVertices| as supplied to the vertex buffer.
|
||||
glVertexAttribPointer(_texcoord,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
4 * sizeof(GLfloat),
|
||||
(void *)(2 * sizeof(GLfloat)));
|
||||
glEnableVertexAttribArray(_texcoord);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCSessionDescription.h"
|
||||
|
||||
#include "talk/app/webrtc/jsep.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCSessionDescription ()
|
||||
|
||||
/**
|
||||
* The native SessionDescriptionInterface representation of this
|
||||
* RTCSessionDescription object. This is needed to pass to the underlying C++
|
||||
* APIs.
|
||||
*/
|
||||
@property(nonatomic, readonly)
|
||||
webrtc::SessionDescriptionInterface *nativeDescription;
|
||||
|
||||
/**
|
||||
* Initialize an RTCSessionDescription from a native
|
||||
* SessionDescriptionInterface. No ownership is taken of the native session
|
||||
* description.
|
||||
*/
|
||||
- (instancetype)initWithNativeDescription:
|
||||
(webrtc::SessionDescriptionInterface *)nativeDescription;
|
||||
|
||||
+ (std::string)stringForType:(RTCSdpType)type;
|
||||
|
||||
+ (RTCSdpType)typeForString:(const std::string &)string;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
41
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.h
Normal file
41
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Represents the session description type. This exposes the same types that are
|
||||
* in C++, which doesn't include the rollback type that is in the W3C spec.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, RTCSdpType) {
|
||||
RTCSdpTypeOffer,
|
||||
RTCSdpTypePrAnswer,
|
||||
RTCSdpTypeAnswer,
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCSessionDescription : NSObject
|
||||
|
||||
/** The type of session description. */
|
||||
@property(nonatomic, readonly) RTCSdpType type;
|
||||
|
||||
/** The SDP string representation of this session description. */
|
||||
@property(nonatomic, readonly) NSString *sdp;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/** Initialize a session description with a type and SDP string. */
|
||||
- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
92
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.mm
Normal file
92
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.mm
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCSessionDescription.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCSessionDescription+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
#import "webrtc/base/objc/RTCLogging.h"
|
||||
|
||||
@implementation RTCSessionDescription
|
||||
|
||||
@synthesize type = _type;
|
||||
@synthesize sdp = _sdp;
|
||||
|
||||
- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp {
|
||||
NSParameterAssert(sdp.length);
|
||||
if (self = [super init]) {
|
||||
_type = type;
|
||||
_sdp = [sdp copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCSessionDescription:\n%s\n%@",
|
||||
[[self class] stringForType:_type].c_str(),
|
||||
_sdp];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (webrtc::SessionDescriptionInterface *)nativeDescription {
|
||||
webrtc::SdpParseError error;
|
||||
|
||||
webrtc::SessionDescriptionInterface *description =
|
||||
webrtc::CreateSessionDescription([[self class] stringForType:_type],
|
||||
_sdp.stdString,
|
||||
&error);
|
||||
|
||||
if (!description) {
|
||||
RTCLogError(@"Failed to create session description: %s\nline: %s",
|
||||
error.description.c_str(),
|
||||
error.line.c_str());
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNativeDescription:
|
||||
(webrtc::SessionDescriptionInterface *)nativeDescription {
|
||||
NSParameterAssert(nativeDescription);
|
||||
std::string sdp;
|
||||
nativeDescription->ToString(&sdp);
|
||||
RTCSdpType type = [[self class] typeForString:nativeDescription->type()];
|
||||
|
||||
return [self initWithType:type
|
||||
sdp:[NSString stringForStdString:sdp]];
|
||||
}
|
||||
|
||||
+ (std::string)stringForType:(RTCSdpType)type {
|
||||
switch (type) {
|
||||
case RTCSdpTypeOffer:
|
||||
return webrtc::SessionDescriptionInterface::kOffer;
|
||||
case RTCSdpTypePrAnswer:
|
||||
return webrtc::SessionDescriptionInterface::kPrAnswer;
|
||||
case RTCSdpTypeAnswer:
|
||||
return webrtc::SessionDescriptionInterface::kAnswer;
|
||||
}
|
||||
}
|
||||
|
||||
+ (RTCSdpType)typeForString:(const std::string &)string {
|
||||
if (string == webrtc::SessionDescriptionInterface::kOffer) {
|
||||
return RTCSdpTypeOffer;
|
||||
} else if (string == webrtc::SessionDescriptionInterface::kPrAnswer) {
|
||||
return RTCSdpTypePrAnswer;
|
||||
} else if (string == webrtc::SessionDescriptionInterface::kAnswer) {
|
||||
return RTCSdpTypeAnswer;
|
||||
} else {
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
24
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport+Private.h
Normal file
24
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport+Private.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCStatsReport.h"
|
||||
|
||||
#include "talk/app/webrtc/statstypes.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCStatsReport ()
|
||||
|
||||
/** Initialize an RTCStatsReport object from a native StatsReport. */
|
||||
- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
34
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.h
Normal file
34
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This does not currently conform to the spec. */
|
||||
@interface RTCStatsReport : NSObject
|
||||
|
||||
/** Time since 1970-01-01T00:00:00Z in milliseconds. */
|
||||
@property(nonatomic, readonly) CFTimeInterval timestamp;
|
||||
|
||||
/** The type of stats held by this object. */
|
||||
@property(nonatomic, readonly) NSString *type;
|
||||
|
||||
/** The identifier for this object. */
|
||||
@property(nonatomic, readonly) NSString *statsId;
|
||||
|
||||
/** A dictionary holding the actual stats. */
|
||||
@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *values;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
62
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.mm
Normal file
62
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.mm
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCStatsReport.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCStatsReport+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
#import "webrtc/base/objc/RTCLogging.h"
|
||||
|
||||
@implementation RTCStatsReport
|
||||
|
||||
@synthesize timestamp = _timestamp;
|
||||
@synthesize type = _type;
|
||||
@synthesize statsId = _statsId;
|
||||
@synthesize values = _values;
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"RTCStatsReport:\n%@\n%@\n%f\n%@",
|
||||
_statsId,
|
||||
_type,
|
||||
_timestamp,
|
||||
_values];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport {
|
||||
if (self = [super init]) {
|
||||
_timestamp = nativeReport.timestamp();
|
||||
_type = [NSString stringForStdString:nativeReport.TypeToString()];
|
||||
_statsId = [NSString stringForStdString:
|
||||
nativeReport.id()->ToString()];
|
||||
|
||||
NSUInteger capacity = nativeReport.values().size();
|
||||
NSMutableDictionary *values =
|
||||
[NSMutableDictionary dictionaryWithCapacity:capacity];
|
||||
for (auto const &valuePair : nativeReport.values()) {
|
||||
NSString *key = [NSString stringForStdString:
|
||||
valuePair.second->display_name()];
|
||||
NSString *value = [NSString stringForStdString:
|
||||
valuePair.second->ToString()];
|
||||
|
||||
// Not expecting duplicate keys.
|
||||
RTC_DCHECK(values[key]);
|
||||
|
||||
values[key] = value;
|
||||
}
|
||||
_values = values;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
|
|
@ -8,13 +8,17 @@
|
|||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_BASICDEFS_H_
|
||||
#define WEBRTC_BASE_BASICDEFS_H_
|
||||
#import "RTCVideoFrame.h"
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h" // NOLINT
|
||||
#endif
|
||||
#include "talk/media/base/videoframe.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0])))
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#endif // WEBRTC_BASE_BASICDEFS_H_
|
||||
@interface RTCVideoFrame ()
|
||||
|
||||
- (instancetype)initWithNativeFrame:(const cricket::VideoFrame *)nativeFrame
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
37
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.h
Normal file
37
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RTCVideoFrame : NSObject
|
||||
|
||||
/** Width without rotation applied. */
|
||||
@property(nonatomic, readonly) size_t width;
|
||||
|
||||
/** Height without rotation applied. */
|
||||
@property(nonatomic, readonly) size_t height;
|
||||
@property(nonatomic, readonly) size_t chromaWidth;
|
||||
@property(nonatomic, readonly) size_t chromaHeight;
|
||||
@property(nonatomic, readonly) size_t chromaSize;
|
||||
// These can return NULL if the object is not backed by a buffer.
|
||||
@property(nonatomic, readonly, nullable) const uint8_t *yPlane;
|
||||
@property(nonatomic, readonly, nullable) const uint8_t *uPlane;
|
||||
@property(nonatomic, readonly, nullable) const uint8_t *vPlane;
|
||||
@property(nonatomic, readonly) int32_t yPitch;
|
||||
@property(nonatomic, readonly) int32_t uPitch;
|
||||
@property(nonatomic, readonly) int32_t vPitch;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
79
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.mm
Normal file
79
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.mm
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import "RTCVideoFrame.h"
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCVideoFrame+Private.h"
|
||||
|
||||
@implementation RTCVideoFrame {
|
||||
rtc::scoped_ptr<cricket::VideoFrame> _videoFrame;
|
||||
}
|
||||
|
||||
- (size_t)width {
|
||||
return _videoFrame->GetWidth();
|
||||
}
|
||||
|
||||
- (size_t)height {
|
||||
return _videoFrame->GetHeight();
|
||||
}
|
||||
|
||||
- (size_t)chromaWidth {
|
||||
return _videoFrame->GetChromaWidth();
|
||||
}
|
||||
|
||||
- (size_t)chromaHeight {
|
||||
return _videoFrame->GetChromaHeight();
|
||||
}
|
||||
|
||||
- (size_t)chromaSize {
|
||||
return _videoFrame->GetChromaSize();
|
||||
}
|
||||
|
||||
- (const uint8_t *)yPlane {
|
||||
const cricket::VideoFrame *const_frame = _videoFrame.get();
|
||||
return const_frame->GetYPlane();
|
||||
}
|
||||
|
||||
- (const uint8_t *)uPlane {
|
||||
const cricket::VideoFrame *const_frame = _videoFrame.get();
|
||||
return const_frame->GetUPlane();
|
||||
}
|
||||
|
||||
- (const uint8_t *)vPlane {
|
||||
const cricket::VideoFrame *const_frame = _videoFrame.get();
|
||||
return const_frame->GetVPlane();
|
||||
}
|
||||
|
||||
- (int32_t)yPitch {
|
||||
return _videoFrame->GetYPitch();
|
||||
}
|
||||
|
||||
- (int32_t)uPitch {
|
||||
return _videoFrame->GetUPitch();
|
||||
}
|
||||
|
||||
- (int32_t)vPitch {
|
||||
return _videoFrame->GetVPitch();
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (instancetype)initWithNativeFrame:(const cricket::VideoFrame *)nativeFrame {
|
||||
if (self = [super init]) {
|
||||
// Keep a shallow copy of the video frame. The underlying frame buffer is
|
||||
// not copied.
|
||||
_videoFrame.reset(nativeFrame->Copy());
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
30
media/webrtc/trunk/webrtc/api/objc/RTCVideoRenderer.h
Normal file
30
media/webrtc/trunk/webrtc/api/objc/RTCVideoRenderer.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class RTCVideoFrame;
|
||||
|
||||
@protocol RTCVideoRenderer <NSObject>
|
||||
|
||||
/** The size of the frame. */
|
||||
- (void)setSize:(CGSize)size;
|
||||
|
||||
/** The frame to be displayed. */
|
||||
- (void)renderFrame:(RTCVideoFrame *)frame;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
|
|
@ -8,5 +8,6 @@
|
|||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This file has moved.
|
||||
// TODO(tommi): Delete after removing dependencies and updating Chromium.
|
||||
#if !defined(__has_feature) || !__has_feature(objc_arc)
|
||||
#error "This file requires ARC support."
|
||||
#endif
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCIceCandidate.h"
|
||||
#import "webrtc/api/objc/RTCIceCandidate+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
@interface RTCIceCandidateTest : NSObject
|
||||
- (void)testCandidate;
|
||||
- (void)testInitFromNativeCandidate;
|
||||
@end
|
||||
|
||||
@implementation RTCIceCandidateTest
|
||||
|
||||
- (void)testCandidate {
|
||||
NSString *sdp = @"candidate:4025901590 1 udp 2122265343 "
|
||||
"fdff:2642:12a6:fe38:c001:beda:fcf9:51aa "
|
||||
"59052 typ host generation 0";
|
||||
|
||||
RTCIceCandidate *candidate = [[RTCIceCandidate alloc] initWithSdp:sdp
|
||||
sdpMLineIndex:0
|
||||
sdpMid:@"audio"];
|
||||
|
||||
rtc::scoped_ptr<webrtc::IceCandidateInterface> nativeCandidate =
|
||||
candidate.nativeCandidate;
|
||||
EXPECT_EQ("audio", nativeCandidate->sdp_mid());
|
||||
EXPECT_EQ(0, nativeCandidate->sdp_mline_index());
|
||||
|
||||
std::string sdpString;
|
||||
nativeCandidate->ToString(&sdpString);
|
||||
EXPECT_EQ(sdp.stdString, sdpString);
|
||||
}
|
||||
|
||||
- (void)testInitFromNativeCandidate {
|
||||
std::string sdp("candidate:4025901590 1 udp 2122265343 "
|
||||
"fdff:2642:12a6:fe38:c001:beda:fcf9:51aa "
|
||||
"59052 typ host generation 0");
|
||||
webrtc::IceCandidateInterface *nativeCandidate =
|
||||
webrtc::CreateIceCandidate("audio", 0, sdp, nullptr);
|
||||
|
||||
RTCIceCandidate *iceCandidate =
|
||||
[[RTCIceCandidate alloc] initWithNativeCandidate:nativeCandidate];
|
||||
EXPECT_TRUE([@"audio" isEqualToString:iceCandidate.sdpMid]);
|
||||
EXPECT_EQ(0, iceCandidate.sdpMLineIndex);
|
||||
|
||||
EXPECT_EQ(sdp, iceCandidate.sdp.stdString);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
TEST(RTCIceCandidateTest, CandidateTest) {
|
||||
@autoreleasepool {
|
||||
RTCIceCandidateTest *test = [[RTCIceCandidateTest alloc] init];
|
||||
[test testCandidate];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RTCIceCandidateTest, InitFromCandidateTest) {
|
||||
@autoreleasepool {
|
||||
RTCIceCandidateTest *test = [[RTCIceCandidateTest alloc] init];
|
||||
[test testInitFromNativeCandidate];
|
||||
}
|
||||
}
|
||||
84
media/webrtc/trunk/webrtc/api/objctests/RTCIceServerTest.mm
Normal file
84
media/webrtc/trunk/webrtc/api/objctests/RTCIceServerTest.mm
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCIceServer.h"
|
||||
#import "webrtc/api/objc/RTCIceServer+Private.h"
|
||||
|
||||
@interface RTCIceServerTest : NSObject
|
||||
- (void)testOneURLServer;
|
||||
- (void)testTwoURLServer;
|
||||
- (void)testPasswordCredential;
|
||||
@end
|
||||
|
||||
@implementation RTCIceServerTest
|
||||
|
||||
- (void)testOneURLServer {
|
||||
RTCIceServer *server = [[RTCIceServer alloc] initWithURLStrings:@[
|
||||
@"stun:stun1.example.net" ]];
|
||||
|
||||
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
|
||||
EXPECT_EQ((size_t)1, iceStruct.urls.size());
|
||||
EXPECT_EQ("stun:stun1.example.net", iceStruct.urls.front());
|
||||
EXPECT_EQ("", iceStruct.username);
|
||||
EXPECT_EQ("", iceStruct.password);
|
||||
}
|
||||
|
||||
- (void)testTwoURLServer {
|
||||
RTCIceServer *server = [[RTCIceServer alloc] initWithURLStrings:@[
|
||||
@"turn1:turn1.example.net", @"turn2:turn2.example.net" ]];
|
||||
|
||||
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
|
||||
EXPECT_EQ((size_t)2, iceStruct.urls.size());
|
||||
EXPECT_EQ("turn1:turn1.example.net", iceStruct.urls.front());
|
||||
EXPECT_EQ("turn2:turn2.example.net", iceStruct.urls.back());
|
||||
EXPECT_EQ("", iceStruct.username);
|
||||
EXPECT_EQ("", iceStruct.password);
|
||||
}
|
||||
|
||||
- (void)testPasswordCredential {
|
||||
RTCIceServer *server = [[RTCIceServer alloc]
|
||||
initWithURLStrings:@[ @"turn1:turn1.example.net" ]
|
||||
username:@"username"
|
||||
credential:@"credential"];
|
||||
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
|
||||
EXPECT_EQ((size_t)1, iceStruct.urls.size());
|
||||
EXPECT_EQ("turn1:turn1.example.net", iceStruct.urls.front());
|
||||
EXPECT_EQ("username", iceStruct.username);
|
||||
EXPECT_EQ("credential", iceStruct.password);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
TEST(RTCIceServerTest, OneURLTest) {
|
||||
@autoreleasepool {
|
||||
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
|
||||
[test testOneURLServer];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RTCIceServerTest, TwoURLTest) {
|
||||
@autoreleasepool {
|
||||
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
|
||||
[test testTwoURLServer];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RTCIceServerTest, PasswordCredentialTest) {
|
||||
@autoreleasepool {
|
||||
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
|
||||
[test testPasswordCredential];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCMediaConstraints.h"
|
||||
#import "webrtc/api/objc/RTCMediaConstraints+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
@interface RTCMediaConstraintsTest : NSObject
|
||||
- (void)testMediaConstraints;
|
||||
@end
|
||||
|
||||
@implementation RTCMediaConstraintsTest
|
||||
|
||||
- (void)testMediaConstraints {
|
||||
NSDictionary *mandatory = @{@"key1": @"value1", @"key2": @"value2"};
|
||||
NSDictionary *optional = @{@"key3": @"value3", @"key4": @"value4"};
|
||||
|
||||
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc]
|
||||
initWithMandatoryConstraints:mandatory
|
||||
optionalConstraints:optional];
|
||||
rtc::scoped_ptr<webrtc::MediaConstraints> nativeConstraints =
|
||||
[constraints nativeConstraints];
|
||||
|
||||
webrtc::MediaConstraintsInterface::Constraints nativeMandatory =
|
||||
nativeConstraints->GetMandatory();
|
||||
[self expectConstraints:mandatory inNativeConstraints:nativeMandatory];
|
||||
|
||||
webrtc::MediaConstraintsInterface::Constraints nativeOptional =
|
||||
nativeConstraints->GetOptional();
|
||||
[self expectConstraints:optional inNativeConstraints:nativeOptional];
|
||||
}
|
||||
|
||||
- (void)expectConstraints:(NSDictionary *)constraints
|
||||
inNativeConstraints:
|
||||
(webrtc::MediaConstraintsInterface::Constraints)nativeConstraints {
|
||||
EXPECT_EQ(constraints.count, nativeConstraints.size());
|
||||
|
||||
for (NSString *key in constraints) {
|
||||
NSString *value = constraints[key];
|
||||
|
||||
std::string nativeValue;
|
||||
bool found = nativeConstraints.FindFirst(key.stdString, &nativeValue);
|
||||
EXPECT_TRUE(found);
|
||||
EXPECT_EQ(value.stdString, nativeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
TEST(RTCMediaConstraintsTest, MediaConstraintsTest) {
|
||||
@autoreleasepool {
|
||||
RTCMediaConstraintsTest *test = [[RTCMediaConstraintsTest alloc] init];
|
||||
[test testMediaConstraints];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
#import "webrtc/api/objc/RTCSessionDescription.h"
|
||||
#import "webrtc/api/objc/RTCSessionDescription+Private.h"
|
||||
#import "webrtc/base/objc/NSString+StdString.h"
|
||||
|
||||
@interface RTCSessionDescriptionTest : NSObject
|
||||
- (void)testSessionDescriptionConversion;
|
||||
- (void)testInitFromNativeSessionDescription;
|
||||
@end
|
||||
|
||||
@implementation RTCSessionDescriptionTest
|
||||
|
||||
/**
|
||||
* Test conversion of an Objective-C RTCSessionDescription to a native
|
||||
* SessionDescriptionInterface (based on the types and SDP strings being equal).
|
||||
*/
|
||||
- (void)testSessionDescriptionConversion {
|
||||
RTCSessionDescription *description =
|
||||
[[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer
|
||||
sdp:[self sdp]];
|
||||
|
||||
webrtc::SessionDescriptionInterface *nativeDescription =
|
||||
description.nativeDescription;
|
||||
|
||||
EXPECT_EQ(RTCSdpTypeAnswer,
|
||||
[RTCSessionDescription typeForString:nativeDescription->type()]);
|
||||
|
||||
std::string sdp;
|
||||
nativeDescription->ToString(&sdp);
|
||||
EXPECT_EQ([self sdp].stdString, sdp);
|
||||
}
|
||||
|
||||
- (void)testInitFromNativeSessionDescription {
|
||||
webrtc::SessionDescriptionInterface *nativeDescription;
|
||||
|
||||
nativeDescription = webrtc::CreateSessionDescription(
|
||||
webrtc::SessionDescriptionInterface::kAnswer,
|
||||
[self sdp].stdString,
|
||||
nullptr);
|
||||
|
||||
RTCSessionDescription *description =
|
||||
[[RTCSessionDescription alloc] initWithNativeDescription:
|
||||
nativeDescription];
|
||||
EXPECT_EQ(webrtc::SessionDescriptionInterface::kAnswer,
|
||||
[RTCSessionDescription stringForType:description.type]);
|
||||
EXPECT_TRUE([[self sdp] isEqualToString:description.sdp]);
|
||||
}
|
||||
|
||||
- (NSString *)sdp {
|
||||
return @"v=0\r\n"
|
||||
"o=- 5319989746393411314 2 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"t=0 0\r\n"
|
||||
"a=group:BUNDLE audio video\r\n"
|
||||
"a=msid-semantic: WMS ARDAMS\r\n"
|
||||
"m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 0 8 126\r\n"
|
||||
"c=IN IP4 0.0.0.0\r\n"
|
||||
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
||||
"a=ice-ufrag:f3o+0HG7l9nwIWFY\r\n"
|
||||
"a=ice-pwd:VDctmJNCptR2TB7+meDpw7w5\r\n"
|
||||
"a=fingerprint:sha-256 A9:D5:8D:A8:69:22:39:60:92:AD:94:1A:22:2D:5E:"
|
||||
"A5:4A:A9:18:C2:35:5D:46:5E:59:BD:1C:AF:38:9F:E6:E1\r\n"
|
||||
"a=setup:active\r\n"
|
||||
"a=mid:audio\r\n"
|
||||
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"
|
||||
"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/"
|
||||
"abs-send-time\r\n"
|
||||
"a=sendrecv\r\n"
|
||||
"a=rtcp-mux\r\n"
|
||||
"a=rtpmap:111 opus/48000/2\r\n"
|
||||
"a=fmtp:111 minptime=10; useinbandfec=1\r\n"
|
||||
"a=rtpmap:103 ISAC/16000\r\n"
|
||||
"a=rtpmap:9 G722/8000\r\n"
|
||||
"a=rtpmap:0 PCMU/8000\r\n"
|
||||
"a=rtpmap:8 PCMA/8000\r\n"
|
||||
"a=rtpmap:126 telephone-event/8000\r\n"
|
||||
"a=maxptime:60\r\n"
|
||||
"a=ssrc:1504474588 cname:V+FdIC5AJpxLhdYQ\r\n"
|
||||
"a=ssrc:1504474588 msid:ARDAMS ARDAMSa0\r\n"
|
||||
"a=ssrc:1504474588 mslabel:ARDAMS\r\n"
|
||||
"a=ssrc:1504474588 label:ARDAMSa0\r\n"
|
||||
"m=video 9 UDP/TLS/RTP/SAVPF 100 116 117 96\r\n"
|
||||
"c=IN IP4 0.0.0.0\r\n"
|
||||
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
||||
"a=ice-ufrag:f3o+0HG7l9nwIWFY\r\n"
|
||||
"a=ice-pwd:VDctmJNCptR2TB7+meDpw7w5\r\n"
|
||||
"a=fingerprint:sha-256 A9:D5:8D:A8:69:22:39:60:92:AD:94:1A:22:2D:5E:"
|
||||
"A5:4A:A9:18:C2:35:5D:46:5E:59:BD:1C:AF:38:9F:E6:E1\r\n"
|
||||
"a=setup:active\r\n"
|
||||
"a=mid:video\r\n"
|
||||
"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n"
|
||||
"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/"
|
||||
"abs-send-time\r\n"
|
||||
"a=extmap:4 urn:3gpp:video-orientation\r\n"
|
||||
"a=sendrecv\r\n"
|
||||
"a=rtcp-mux\r\n"
|
||||
"a=rtpmap:100 VP8/90000\r\n"
|
||||
"a=rtcp-fb:100 ccm fir\r\n"
|
||||
"a=rtcp-fb:100 nack\r\n"
|
||||
"a=rtcp-fb:100 nack pli\r\n"
|
||||
"a=rtcp-fb:100 goog-remb\r\n"
|
||||
"a=rtpmap:116 red/90000\r\n"
|
||||
"a=rtpmap:117 ulpfec/90000\r\n"
|
||||
"a=rtpmap:96 rtx/90000\r\n"
|
||||
"a=fmtp:96 apt=100\r\n"
|
||||
"a=ssrc-group:FID 498297514 1644357692\r\n"
|
||||
"a=ssrc:498297514 cname:V+FdIC5AJpxLhdYQ\r\n"
|
||||
"a=ssrc:498297514 msid:ARDAMS ARDAMSv0\r\n"
|
||||
"a=ssrc:498297514 mslabel:ARDAMS\r\n"
|
||||
"a=ssrc:498297514 label:ARDAMSv0\r\n"
|
||||
"a=ssrc:1644357692 cname:V+FdIC5AJpxLhdYQ\r\n"
|
||||
"a=ssrc:1644357692 msid:ARDAMS ARDAMSv0\r\n"
|
||||
"a=ssrc:1644357692 mslabel:ARDAMS\r\n"
|
||||
"a=ssrc:1644357692 label:ARDAMSv0\r\n";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
TEST(RTCSessionDescriptionTest, SessionDescriptionConversionTest) {
|
||||
@autoreleasepool {
|
||||
RTCSessionDescriptionTest *test = [[RTCSessionDescriptionTest alloc] init];
|
||||
[test testSessionDescriptionConversion];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RTCSessionDescriptionTest, InitFromSessionDescriptionTest) {
|
||||
@autoreleasepool {
|
||||
RTCSessionDescriptionTest *test = [[RTCSessionDescriptionTest alloc] init];
|
||||
[test testInitFromNativeSessionDescription];
|
||||
}
|
||||
}
|
||||
38
media/webrtc/trunk/webrtc/audio/BUILD.gn
Normal file
38
media/webrtc/trunk/webrtc/audio/BUILD.gn
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("../build/webrtc.gni")
|
||||
|
||||
source_set("audio") {
|
||||
sources = [
|
||||
"audio_receive_stream.cc",
|
||||
"audio_receive_stream.h",
|
||||
"audio_send_stream.cc",
|
||||
"audio_send_stream.h",
|
||||
"audio_sink.h",
|
||||
"audio_state.cc",
|
||||
"audio_state.h",
|
||||
"conversion.h",
|
||||
"scoped_voe_interface.h",
|
||||
]
|
||||
|
||||
configs += [ "..:common_config" ]
|
||||
public_configs = [ "..:common_inherited_config" ]
|
||||
|
||||
if (is_clang) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
"..:webrtc_common",
|
||||
"../system_wrappers",
|
||||
"../voice_engine",
|
||||
]
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
solenberg@webrtc.org
|
||||
tina.legrand@webrtc.org
|
||||
|
||||
# These are for the common case of adding or renaming files. If you're doing
|
||||
# structural changes, please get a review from a reviewer in this file.
|
||||
per-file *.gyp=*
|
||||
per-file *.gypi=*
|
||||
|
||||
per-file BUILD.gn=kjellander@webrtc.org
|
||||
256
media/webrtc/trunk/webrtc/audio/audio_receive_stream.cc
Normal file
256
media/webrtc/trunk/webrtc/audio/audio_receive_stream.cc
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/audio/audio_receive_stream.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/audio/audio_sink.h"
|
||||
#include "webrtc/audio/audio_state.h"
|
||||
#include "webrtc/audio/conversion.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/call/congestion_controller.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/system_wrappers/include/tick_util.h"
|
||||
#include "webrtc/voice_engine/channel_proxy.h"
|
||||
#include "webrtc/voice_engine/include/voe_base.h"
|
||||
#include "webrtc/voice_engine/include/voe_codec.h"
|
||||
#include "webrtc/voice_engine/include/voe_neteq_stats.h"
|
||||
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
|
||||
#include "webrtc/voice_engine/include/voe_video_sync.h"
|
||||
#include "webrtc/voice_engine/include/voe_volume_control.h"
|
||||
#include "webrtc/voice_engine/voice_engine_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
bool UseSendSideBwe(const webrtc::AudioReceiveStream::Config& config) {
|
||||
if (!config.rtp.transport_cc) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& extension : config.rtp.extensions) {
|
||||
if (extension.name == RtpExtension::kTransportSequenceNumber) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string AudioReceiveStream::Config::Rtp::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << "{remote_ssrc: " << remote_ssrc;
|
||||
ss << ", local_ssrc: " << local_ssrc;
|
||||
ss << ", extensions: [";
|
||||
for (size_t i = 0; i < extensions.size(); ++i) {
|
||||
ss << extensions[i].ToString();
|
||||
if (i != extensions.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << ']';
|
||||
ss << '}';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string AudioReceiveStream::Config::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << "{rtp: " << rtp.ToString();
|
||||
ss << ", receive_transport: "
|
||||
<< (receive_transport ? "(Transport)" : "nullptr");
|
||||
ss << ", rtcp_send_transport: "
|
||||
<< (rtcp_send_transport ? "(Transport)" : "nullptr");
|
||||
ss << ", voe_channel_id: " << voe_channel_id;
|
||||
if (!sync_group.empty()) {
|
||||
ss << ", sync_group: " << sync_group;
|
||||
}
|
||||
ss << ", combined_audio_video_bwe: "
|
||||
<< (combined_audio_video_bwe ? "true" : "false");
|
||||
ss << '}';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
AudioReceiveStream::AudioReceiveStream(
|
||||
CongestionController* congestion_controller,
|
||||
const webrtc::AudioReceiveStream::Config& config,
|
||||
const rtc::scoped_refptr<webrtc::AudioState>& audio_state)
|
||||
: config_(config),
|
||||
audio_state_(audio_state),
|
||||
rtp_header_parser_(RtpHeaderParser::Create()) {
|
||||
LOG(LS_INFO) << "AudioReceiveStream: " << config_.ToString();
|
||||
RTC_DCHECK_NE(config_.voe_channel_id, -1);
|
||||
RTC_DCHECK(audio_state_.get());
|
||||
RTC_DCHECK(congestion_controller);
|
||||
RTC_DCHECK(rtp_header_parser_);
|
||||
|
||||
VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine());
|
||||
channel_proxy_ = voe_impl->GetChannelProxy(config_.voe_channel_id);
|
||||
channel_proxy_->SetLocalSSRC(config.rtp.local_ssrc);
|
||||
for (const auto& extension : config.rtp.extensions) {
|
||||
if (extension.name == RtpExtension::kAudioLevel) {
|
||||
channel_proxy_->SetReceiveAudioLevelIndicationStatus(true, extension.id);
|
||||
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionAudioLevel, extension.id);
|
||||
RTC_DCHECK(registered);
|
||||
} else if (extension.name == RtpExtension::kAbsSendTime) {
|
||||
channel_proxy_->SetReceiveAbsoluteSenderTimeStatus(true, extension.id);
|
||||
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionAbsoluteSendTime, extension.id);
|
||||
RTC_DCHECK(registered);
|
||||
} else if (extension.name == RtpExtension::kTransportSequenceNumber) {
|
||||
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionTransportSequenceNumber, extension.id);
|
||||
RTC_DCHECK(registered);
|
||||
} else {
|
||||
RTC_NOTREACHED() << "Unsupported RTP extension.";
|
||||
}
|
||||
}
|
||||
// Configure bandwidth estimation.
|
||||
channel_proxy_->SetCongestionControlObjects(
|
||||
nullptr, nullptr, congestion_controller->packet_router());
|
||||
if (config.combined_audio_video_bwe) {
|
||||
if (UseSendSideBwe(config)) {
|
||||
remote_bitrate_estimator_ =
|
||||
congestion_controller->GetRemoteBitrateEstimator(true);
|
||||
} else {
|
||||
remote_bitrate_estimator_ =
|
||||
congestion_controller->GetRemoteBitrateEstimator(false);
|
||||
}
|
||||
RTC_DCHECK(remote_bitrate_estimator_);
|
||||
}
|
||||
}
|
||||
|
||||
AudioReceiveStream::~AudioReceiveStream() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString();
|
||||
channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr);
|
||||
if (remote_bitrate_estimator_) {
|
||||
remote_bitrate_estimator_->RemoveStream(config_.rtp.remote_ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioReceiveStream::Start() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
void AudioReceiveStream::Stop() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
void AudioReceiveStream::SignalNetworkState(NetworkState state) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
|
||||
// TODO(solenberg): Tests call this function on a network thread, libjingle
|
||||
// calls on the worker thread. We should move towards always using a network
|
||||
// thread. Then this check can be enabled.
|
||||
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
|
||||
size_t length,
|
||||
const PacketTime& packet_time) {
|
||||
// TODO(solenberg): Tests call this function on a network thread, libjingle
|
||||
// calls on the worker thread. We should move towards always using a network
|
||||
// thread. Then this check can be enabled.
|
||||
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
|
||||
RTPHeader header;
|
||||
if (!rtp_header_parser_->Parse(packet, length, &header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only forward if the parsed header has one of the headers necessary for
|
||||
// bandwidth estimation. RTP timestamps has different rates for audio and
|
||||
// video and shouldn't be mixed.
|
||||
if (remote_bitrate_estimator_ &&
|
||||
(header.extension.hasAbsoluteSendTime ||
|
||||
header.extension.hasTransportSequenceNumber)) {
|
||||
int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
|
||||
if (packet_time.timestamp >= 0)
|
||||
arrival_time_ms = (packet_time.timestamp + 500) / 1000;
|
||||
size_t payload_size = length - header.headerLength;
|
||||
remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
|
||||
header, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
webrtc::AudioReceiveStream::Stats stats;
|
||||
stats.remote_ssrc = config_.rtp.remote_ssrc;
|
||||
ScopedVoEInterface<VoECodec> codec(voice_engine());
|
||||
|
||||
webrtc::CallStatistics call_stats = channel_proxy_->GetRTCPStatistics();
|
||||
webrtc::CodecInst codec_inst = {0};
|
||||
if (codec->GetRecCodec(config_.voe_channel_id, codec_inst) == -1) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
stats.bytes_rcvd = call_stats.bytesReceived;
|
||||
stats.packets_rcvd = call_stats.packetsReceived;
|
||||
stats.packets_lost = call_stats.cumulativeLost;
|
||||
stats.fraction_lost = Q8ToFloat(call_stats.fractionLost);
|
||||
stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_;
|
||||
if (codec_inst.pltype != -1) {
|
||||
stats.codec_name = codec_inst.plname;
|
||||
}
|
||||
stats.ext_seqnum = call_stats.extendedMax;
|
||||
if (codec_inst.plfreq / 1000 > 0) {
|
||||
stats.jitter_ms = call_stats.jitterSamples / (codec_inst.plfreq / 1000);
|
||||
}
|
||||
stats.delay_estimate_ms = channel_proxy_->GetDelayEstimate();
|
||||
stats.audio_level = channel_proxy_->GetSpeechOutputLevelFullRange();
|
||||
|
||||
// Get jitter buffer and total delay (alg + jitter + playout) stats.
|
||||
auto ns = channel_proxy_->GetNetworkStatistics();
|
||||
stats.jitter_buffer_ms = ns.currentBufferSize;
|
||||
stats.jitter_buffer_preferred_ms = ns.preferredBufferSize;
|
||||
stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
|
||||
stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
|
||||
stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
|
||||
stats.accelerate_rate = Q14ToFloat(ns.currentAccelerateRate);
|
||||
stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate);
|
||||
|
||||
auto ds = channel_proxy_->GetDecodingCallStatistics();
|
||||
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
|
||||
stats.decoding_calls_to_neteq = ds.calls_to_neteq;
|
||||
stats.decoding_normal = ds.decoded_normal;
|
||||
stats.decoding_plc = ds.decoded_plc;
|
||||
stats.decoding_cng = ds.decoded_cng;
|
||||
stats.decoding_plc_cng = ds.decoded_plc_cng;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
void AudioReceiveStream::SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
channel_proxy_->SetSink(std::move(sink));
|
||||
}
|
||||
|
||||
const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return config_;
|
||||
}
|
||||
|
||||
VoiceEngine* AudioReceiveStream::voice_engine() const {
|
||||
internal::AudioState* audio_state =
|
||||
static_cast<internal::AudioState*>(audio_state_.get());
|
||||
VoiceEngine* voice_engine = audio_state->voice_engine();
|
||||
RTC_DCHECK(voice_engine);
|
||||
return voice_engine;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
67
media/webrtc/trunk/webrtc/audio/audio_receive_stream.h
Normal file
67
media/webrtc/trunk/webrtc/audio/audio_receive_stream.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
|
||||
#define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
|
||||
|
||||
#include "webrtc/audio_receive_stream.h"
|
||||
#include "webrtc/audio_state.h"
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
class CongestionController;
|
||||
class RemoteBitrateEstimator;
|
||||
|
||||
namespace voe {
|
||||
class ChannelProxy;
|
||||
} // namespace voe
|
||||
|
||||
namespace internal {
|
||||
|
||||
class AudioReceiveStream final : public webrtc::AudioReceiveStream {
|
||||
public:
|
||||
AudioReceiveStream(CongestionController* congestion_controller,
|
||||
const webrtc::AudioReceiveStream::Config& config,
|
||||
const rtc::scoped_refptr<webrtc::AudioState>& audio_state);
|
||||
~AudioReceiveStream() override;
|
||||
|
||||
// webrtc::ReceiveStream implementation.
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
void SignalNetworkState(NetworkState state) override;
|
||||
bool DeliverRtcp(const uint8_t* packet, size_t length) override;
|
||||
bool DeliverRtp(const uint8_t* packet,
|
||||
size_t length,
|
||||
const PacketTime& packet_time) override;
|
||||
|
||||
// webrtc::AudioReceiveStream implementation.
|
||||
webrtc::AudioReceiveStream::Stats GetStats() const override;
|
||||
|
||||
void SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) override;
|
||||
|
||||
const webrtc::AudioReceiveStream::Config& config() const;
|
||||
|
||||
private:
|
||||
VoiceEngine* voice_engine() const;
|
||||
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator_ = nullptr;
|
||||
const webrtc::AudioReceiveStream::Config config_;
|
||||
rtc::scoped_refptr<webrtc::AudioState> audio_state_;
|
||||
rtc::scoped_ptr<RtpHeaderParser> rtp_header_parser_;
|
||||
rtc::scoped_ptr<voe::ChannelProxy> channel_proxy_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioReceiveStream);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
|
||||
328
media/webrtc/trunk/webrtc/audio/audio_receive_stream_unittest.cc
Normal file
328
media/webrtc/trunk/webrtc/audio/audio_receive_stream_unittest.cc
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/audio/audio_receive_stream.h"
|
||||
#include "webrtc/audio/conversion.h"
|
||||
#include "webrtc/call/mock/mock_congestion_controller.h"
|
||||
#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
|
||||
#include "webrtc/modules/pacing/packet_router.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "webrtc/modules/utility/include/mock/mock_process_thread.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
#include "webrtc/test/mock_voe_channel_proxy.h"
|
||||
#include "webrtc/test/mock_voice_engine.h"
|
||||
#include "webrtc/video/call_stats.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using testing::_;
|
||||
using testing::Return;
|
||||
|
||||
AudioDecodingCallStats MakeAudioDecodeStatsForTest() {
|
||||
AudioDecodingCallStats audio_decode_stats;
|
||||
audio_decode_stats.calls_to_silence_generator = 234;
|
||||
audio_decode_stats.calls_to_neteq = 567;
|
||||
audio_decode_stats.decoded_normal = 890;
|
||||
audio_decode_stats.decoded_plc = 123;
|
||||
audio_decode_stats.decoded_cng = 456;
|
||||
audio_decode_stats.decoded_plc_cng = 789;
|
||||
return audio_decode_stats;
|
||||
}
|
||||
|
||||
const int kChannelId = 2;
|
||||
const uint32_t kRemoteSsrc = 1234;
|
||||
const uint32_t kLocalSsrc = 5678;
|
||||
const size_t kOneByteExtensionHeaderLength = 4;
|
||||
const size_t kOneByteExtensionLength = 4;
|
||||
const int kAbsSendTimeId = 2;
|
||||
const int kAudioLevelId = 3;
|
||||
const int kTransportSequenceNumberId = 4;
|
||||
const int kJitterBufferDelay = -7;
|
||||
const int kPlayoutBufferDelay = 302;
|
||||
const unsigned int kSpeechOutputLevel = 99;
|
||||
const CallStatistics kCallStats = {
|
||||
345, 678, 901, 234, -12, 3456, 7890, 567, 890, 123};
|
||||
const CodecInst kCodecInst = {
|
||||
123, "codec_name_recv", 96000, -187, 0, -103};
|
||||
const NetworkStatistics kNetworkStats = {
|
||||
123, 456, false, 0, 0, 789, 12, 345, 678, 901, -1, -1, -1, -1, -1, 0};
|
||||
const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
|
||||
|
||||
struct ConfigHelper {
|
||||
ConfigHelper()
|
||||
: simulated_clock_(123456),
|
||||
call_stats_(&simulated_clock_),
|
||||
congestion_controller_(&process_thread_,
|
||||
&call_stats_,
|
||||
&bitrate_observer_) {
|
||||
using testing::Invoke;
|
||||
|
||||
EXPECT_CALL(voice_engine_,
|
||||
RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
|
||||
EXPECT_CALL(voice_engine_,
|
||||
DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
|
||||
AudioState::Config config;
|
||||
config.voice_engine = &voice_engine_;
|
||||
audio_state_ = AudioState::Create(config);
|
||||
|
||||
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId))
|
||||
.WillOnce(Invoke([this](int channel_id) {
|
||||
EXPECT_FALSE(channel_proxy_);
|
||||
channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
|
||||
EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kLocalSsrc)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetReceiveAbsoluteSenderTimeStatus(true, kAbsSendTimeId))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetReceiveAudioLevelIndicationStatus(true, kAudioLevelId))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetCongestionControlObjects(
|
||||
nullptr, nullptr, &packet_router_))
|
||||
.Times(1);
|
||||
EXPECT_CALL(congestion_controller_, packet_router())
|
||||
.WillOnce(Return(&packet_router_));
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetCongestionControlObjects(nullptr, nullptr, nullptr))
|
||||
.Times(1);
|
||||
return channel_proxy_;
|
||||
}));
|
||||
stream_config_.voe_channel_id = kChannelId;
|
||||
stream_config_.rtp.local_ssrc = kLocalSsrc;
|
||||
stream_config_.rtp.remote_ssrc = kRemoteSsrc;
|
||||
stream_config_.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
|
||||
stream_config_.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
|
||||
}
|
||||
|
||||
MockCongestionController* congestion_controller() {
|
||||
return &congestion_controller_;
|
||||
}
|
||||
MockRemoteBitrateEstimator* remote_bitrate_estimator() {
|
||||
return &remote_bitrate_estimator_;
|
||||
}
|
||||
AudioReceiveStream::Config& config() { return stream_config_; }
|
||||
rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
|
||||
MockVoiceEngine& voice_engine() { return voice_engine_; }
|
||||
|
||||
void SetupMockForBweFeedback(bool send_side_bwe) {
|
||||
EXPECT_CALL(congestion_controller_,
|
||||
GetRemoteBitrateEstimator(send_side_bwe))
|
||||
.WillOnce(Return(&remote_bitrate_estimator_));
|
||||
EXPECT_CALL(remote_bitrate_estimator_,
|
||||
RemoveStream(stream_config_.rtp.remote_ssrc));
|
||||
}
|
||||
|
||||
void SetupMockForGetStats() {
|
||||
using testing::DoAll;
|
||||
using testing::SetArgReferee;
|
||||
|
||||
ASSERT_TRUE(channel_proxy_);
|
||||
EXPECT_CALL(*channel_proxy_, GetRTCPStatistics())
|
||||
.WillOnce(Return(kCallStats));
|
||||
EXPECT_CALL(*channel_proxy_, GetDelayEstimate())
|
||||
.WillOnce(Return(kJitterBufferDelay + kPlayoutBufferDelay));
|
||||
EXPECT_CALL(*channel_proxy_, GetSpeechOutputLevelFullRange())
|
||||
.WillOnce(Return(kSpeechOutputLevel));
|
||||
EXPECT_CALL(*channel_proxy_, GetNetworkStatistics())
|
||||
.WillOnce(Return(kNetworkStats));
|
||||
EXPECT_CALL(*channel_proxy_, GetDecodingCallStatistics())
|
||||
.WillOnce(Return(kAudioDecodeStats));
|
||||
|
||||
EXPECT_CALL(voice_engine_, GetRecCodec(kChannelId, _))
|
||||
.WillOnce(DoAll(SetArgReferee<1>(kCodecInst), Return(0)));
|
||||
}
|
||||
|
||||
private:
|
||||
SimulatedClock simulated_clock_;
|
||||
CallStats call_stats_;
|
||||
PacketRouter packet_router_;
|
||||
testing::NiceMock<MockBitrateObserver> bitrate_observer_;
|
||||
testing::NiceMock<MockProcessThread> process_thread_;
|
||||
MockCongestionController congestion_controller_;
|
||||
MockRemoteBitrateEstimator remote_bitrate_estimator_;
|
||||
testing::StrictMock<MockVoiceEngine> voice_engine_;
|
||||
rtc::scoped_refptr<AudioState> audio_state_;
|
||||
AudioReceiveStream::Config stream_config_;
|
||||
testing::StrictMock<MockVoEChannelProxy>* channel_proxy_ = nullptr;
|
||||
};
|
||||
|
||||
void BuildOneByteExtension(std::vector<uint8_t>::iterator it,
|
||||
int id,
|
||||
uint32_t extension_value,
|
||||
size_t value_length) {
|
||||
const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&(*it), kRtpOneByteHeaderExtensionId);
|
||||
it += 2;
|
||||
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&(*it), kOneByteExtensionLength / 4);
|
||||
it += 2;
|
||||
const size_t kExtensionDataLength = kOneByteExtensionLength - 1;
|
||||
uint32_t shifted_value = extension_value
|
||||
<< (8 * (kExtensionDataLength - value_length));
|
||||
*it = (id << 4) + (value_length - 1);
|
||||
++it;
|
||||
ByteWriter<uint32_t, kExtensionDataLength>::WriteBigEndian(&(*it),
|
||||
shifted_value);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> CreateRtpHeaderWithOneByteExtension(
|
||||
int extension_id,
|
||||
uint32_t extension_value,
|
||||
size_t value_length) {
|
||||
std::vector<uint8_t> header;
|
||||
header.resize(webrtc::kRtpHeaderSize + kOneByteExtensionHeaderLength +
|
||||
kOneByteExtensionLength);
|
||||
header[0] = 0x80; // Version 2.
|
||||
header[0] |= 0x10; // Set extension bit.
|
||||
header[1] = 100; // Payload type.
|
||||
header[1] |= 0x80; // Marker bit is set.
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&header[2], 0x1234); // Sequence number.
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&header[4], 0x5678); // Timestamp.
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&header[8], 0x4321); // SSRC.
|
||||
|
||||
BuildOneByteExtension(header.begin() + webrtc::kRtpHeaderSize, extension_id,
|
||||
extension_value, value_length);
|
||||
return header;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(AudioReceiveStreamTest, ConfigToString) {
|
||||
AudioReceiveStream::Config config;
|
||||
config.rtp.remote_ssrc = kRemoteSsrc;
|
||||
config.rtp.local_ssrc = kLocalSsrc;
|
||||
config.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
|
||||
config.voe_channel_id = kChannelId;
|
||||
config.combined_audio_video_bwe = true;
|
||||
EXPECT_EQ(
|
||||
"{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: "
|
||||
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 2}]}, "
|
||||
"receive_transport: nullptr, rtcp_send_transport: nullptr, "
|
||||
"voe_channel_id: 2, combined_audio_video_bwe: true}",
|
||||
config.ToString());
|
||||
}
|
||||
|
||||
TEST(AudioReceiveStreamTest, ConstructDestruct) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioReceiveStream recv_stream(
|
||||
helper.congestion_controller(), helper.config(), helper.audio_state());
|
||||
}
|
||||
|
||||
MATCHER_P(VerifyHeaderExtension, expected_extension, "") {
|
||||
return arg.extension.hasAbsoluteSendTime ==
|
||||
expected_extension.hasAbsoluteSendTime &&
|
||||
arg.extension.absoluteSendTime ==
|
||||
expected_extension.absoluteSendTime &&
|
||||
arg.extension.hasTransportSequenceNumber ==
|
||||
expected_extension.hasTransportSequenceNumber &&
|
||||
arg.extension.transportSequenceNumber ==
|
||||
expected_extension.transportSequenceNumber;
|
||||
}
|
||||
|
||||
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) {
|
||||
ConfigHelper helper;
|
||||
helper.config().combined_audio_video_bwe = true;
|
||||
helper.SetupMockForBweFeedback(false);
|
||||
internal::AudioReceiveStream recv_stream(
|
||||
helper.congestion_controller(), helper.config(), helper.audio_state());
|
||||
const int kAbsSendTimeValue = 1234;
|
||||
std::vector<uint8_t> rtp_packet =
|
||||
CreateRtpHeaderWithOneByteExtension(kAbsSendTimeId, kAbsSendTimeValue, 3);
|
||||
PacketTime packet_time(5678000, 0);
|
||||
const size_t kExpectedHeaderLength = 20;
|
||||
RTPHeaderExtension expected_extension;
|
||||
expected_extension.hasAbsoluteSendTime = true;
|
||||
expected_extension.absoluteSendTime = kAbsSendTimeValue;
|
||||
EXPECT_CALL(*helper.remote_bitrate_estimator(),
|
||||
IncomingPacket(packet_time.timestamp / 1000,
|
||||
rtp_packet.size() - kExpectedHeaderLength,
|
||||
VerifyHeaderExtension(expected_extension), false))
|
||||
.Times(1);
|
||||
EXPECT_TRUE(
|
||||
recv_stream.DeliverRtp(&rtp_packet[0], rtp_packet.size(), packet_time));
|
||||
}
|
||||
|
||||
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweFeedback) {
|
||||
ConfigHelper helper;
|
||||
helper.config().combined_audio_video_bwe = true;
|
||||
helper.config().rtp.transport_cc = true;
|
||||
helper.config().rtp.extensions.push_back(RtpExtension(
|
||||
RtpExtension::kTransportSequenceNumber, kTransportSequenceNumberId));
|
||||
helper.SetupMockForBweFeedback(true);
|
||||
internal::AudioReceiveStream recv_stream(
|
||||
helper.congestion_controller(), helper.config(), helper.audio_state());
|
||||
const int kTransportSequenceNumberValue = 1234;
|
||||
std::vector<uint8_t> rtp_packet = CreateRtpHeaderWithOneByteExtension(
|
||||
kTransportSequenceNumberId, kTransportSequenceNumberValue, 2);
|
||||
PacketTime packet_time(5678000, 0);
|
||||
const size_t kExpectedHeaderLength = 20;
|
||||
RTPHeaderExtension expected_extension;
|
||||
expected_extension.hasTransportSequenceNumber = true;
|
||||
expected_extension.transportSequenceNumber = kTransportSequenceNumberValue;
|
||||
EXPECT_CALL(*helper.remote_bitrate_estimator(),
|
||||
IncomingPacket(packet_time.timestamp / 1000,
|
||||
rtp_packet.size() - kExpectedHeaderLength,
|
||||
VerifyHeaderExtension(expected_extension), false))
|
||||
.Times(1);
|
||||
EXPECT_TRUE(
|
||||
recv_stream.DeliverRtp(&rtp_packet[0], rtp_packet.size(), packet_time));
|
||||
}
|
||||
|
||||
TEST(AudioReceiveStreamTest, GetStats) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioReceiveStream recv_stream(
|
||||
helper.congestion_controller(), helper.config(), helper.audio_state());
|
||||
helper.SetupMockForGetStats();
|
||||
AudioReceiveStream::Stats stats = recv_stream.GetStats();
|
||||
EXPECT_EQ(kRemoteSsrc, stats.remote_ssrc);
|
||||
EXPECT_EQ(static_cast<int64_t>(kCallStats.bytesReceived), stats.bytes_rcvd);
|
||||
EXPECT_EQ(static_cast<uint32_t>(kCallStats.packetsReceived),
|
||||
stats.packets_rcvd);
|
||||
EXPECT_EQ(kCallStats.cumulativeLost, stats.packets_lost);
|
||||
EXPECT_EQ(Q8ToFloat(kCallStats.fractionLost), stats.fraction_lost);
|
||||
EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name);
|
||||
EXPECT_EQ(kCallStats.extendedMax, stats.ext_seqnum);
|
||||
EXPECT_EQ(kCallStats.jitterSamples / (kCodecInst.plfreq / 1000),
|
||||
stats.jitter_ms);
|
||||
EXPECT_EQ(kNetworkStats.currentBufferSize, stats.jitter_buffer_ms);
|
||||
EXPECT_EQ(kNetworkStats.preferredBufferSize,
|
||||
stats.jitter_buffer_preferred_ms);
|
||||
EXPECT_EQ(static_cast<uint32_t>(kJitterBufferDelay + kPlayoutBufferDelay),
|
||||
stats.delay_estimate_ms);
|
||||
EXPECT_EQ(static_cast<int32_t>(kSpeechOutputLevel), stats.audio_level);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
|
||||
stats.speech_expand_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSecondaryDecodedRate),
|
||||
stats.secondary_decoded_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentAccelerateRate),
|
||||
stats.accelerate_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentPreemptiveRate),
|
||||
stats.preemptive_expand_rate);
|
||||
EXPECT_EQ(kAudioDecodeStats.calls_to_silence_generator,
|
||||
stats.decoding_calls_to_silence_generator);
|
||||
EXPECT_EQ(kAudioDecodeStats.calls_to_neteq, stats.decoding_calls_to_neteq);
|
||||
EXPECT_EQ(kAudioDecodeStats.decoded_normal, stats.decoding_normal);
|
||||
EXPECT_EQ(kAudioDecodeStats.decoded_plc, stats.decoding_plc);
|
||||
EXPECT_EQ(kAudioDecodeStats.decoded_cng, stats.decoding_cng);
|
||||
EXPECT_EQ(kAudioDecodeStats.decoded_plc_cng, stats.decoding_plc_cng);
|
||||
EXPECT_EQ(kCallStats.capture_start_ntp_time_ms_,
|
||||
stats.capture_start_ntp_time_ms);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
221
media/webrtc/trunk/webrtc/audio/audio_send_stream.cc
Normal file
221
media/webrtc/trunk/webrtc/audio/audio_send_stream.cc
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/audio/audio_send_stream.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/audio/audio_state.h"
|
||||
#include "webrtc/audio/conversion.h"
|
||||
#include "webrtc/audio/scoped_voe_interface.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/call/congestion_controller.h"
|
||||
#include "webrtc/modules/pacing/paced_sender.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/voice_engine/channel_proxy.h"
|
||||
#include "webrtc/voice_engine/include/voe_audio_processing.h"
|
||||
#include "webrtc/voice_engine/include/voe_codec.h"
|
||||
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
|
||||
#include "webrtc/voice_engine/include/voe_volume_control.h"
|
||||
#include "webrtc/voice_engine/voice_engine_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
std::string AudioSendStream::Config::Rtp::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << "{ssrc: " << ssrc;
|
||||
ss << ", extensions: [";
|
||||
for (size_t i = 0; i < extensions.size(); ++i) {
|
||||
ss << extensions[i].ToString();
|
||||
if (i != extensions.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << ']';
|
||||
ss << ", c_name: " << c_name;
|
||||
ss << '}';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string AudioSendStream::Config::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << "{rtp: " << rtp.ToString();
|
||||
ss << ", voe_channel_id: " << voe_channel_id;
|
||||
// TODO(solenberg): Encoder config.
|
||||
ss << ", cng_payload_type: " << cng_payload_type;
|
||||
ss << ", red_payload_type: " << red_payload_type;
|
||||
ss << '}';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
AudioSendStream::AudioSendStream(
|
||||
const webrtc::AudioSendStream::Config& config,
|
||||
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
|
||||
CongestionController* congestion_controller)
|
||||
: config_(config), audio_state_(audio_state) {
|
||||
LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
|
||||
RTC_DCHECK_NE(config_.voe_channel_id, -1);
|
||||
RTC_DCHECK(audio_state_.get());
|
||||
RTC_DCHECK(congestion_controller);
|
||||
|
||||
VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine());
|
||||
channel_proxy_ = voe_impl->GetChannelProxy(config_.voe_channel_id);
|
||||
channel_proxy_->SetCongestionControlObjects(
|
||||
congestion_controller->pacer(),
|
||||
congestion_controller->GetTransportFeedbackObserver(),
|
||||
congestion_controller->packet_router());
|
||||
channel_proxy_->SetRTCPStatus(true);
|
||||
channel_proxy_->SetLocalSSRC(config.rtp.ssrc);
|
||||
channel_proxy_->SetRTCP_CNAME(config.rtp.c_name);
|
||||
|
||||
for (const auto& extension : config.rtp.extensions) {
|
||||
if (extension.name == RtpExtension::kAbsSendTime) {
|
||||
channel_proxy_->SetSendAbsoluteSenderTimeStatus(true, extension.id);
|
||||
} else if (extension.name == RtpExtension::kAudioLevel) {
|
||||
channel_proxy_->SetSendAudioLevelIndicationStatus(true, extension.id);
|
||||
} else if (extension.name == RtpExtension::kTransportSequenceNumber) {
|
||||
channel_proxy_->EnableSendTransportSequenceNumber(extension.id);
|
||||
} else {
|
||||
RTC_NOTREACHED() << "Registering unsupported RTP extension.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioSendStream::~AudioSendStream() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
|
||||
channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void AudioSendStream::Start() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
void AudioSendStream::Stop() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
void AudioSendStream::SignalNetworkState(NetworkState state) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
|
||||
// TODO(solenberg): Tests call this function on a network thread, libjingle
|
||||
// calls on the worker thread. We should move towards always using a network
|
||||
// thread. Then this check can be enabled.
|
||||
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event,
|
||||
uint32_t duration_ms) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type) &&
|
||||
channel_proxy_->SendTelephoneEventOutband(event, duration_ms);
|
||||
}
|
||||
|
||||
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
webrtc::AudioSendStream::Stats stats;
|
||||
stats.local_ssrc = config_.rtp.ssrc;
|
||||
ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine());
|
||||
ScopedVoEInterface<VoECodec> codec(voice_engine());
|
||||
ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
|
||||
|
||||
webrtc::CallStatistics call_stats = channel_proxy_->GetRTCPStatistics();
|
||||
stats.bytes_sent = call_stats.bytesSent;
|
||||
stats.packets_sent = call_stats.packetsSent;
|
||||
// RTT isn't known until a RTCP report is received. Until then, VoiceEngine
|
||||
// returns 0 to indicate an error value.
|
||||
if (call_stats.rttMs > 0) {
|
||||
stats.rtt_ms = call_stats.rttMs;
|
||||
}
|
||||
// TODO(solenberg): [was ajm]: Re-enable this metric once we have a reliable
|
||||
// implementation.
|
||||
stats.aec_quality_min = -1;
|
||||
|
||||
webrtc::CodecInst codec_inst = {0};
|
||||
if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) {
|
||||
RTC_DCHECK_NE(codec_inst.pltype, -1);
|
||||
stats.codec_name = codec_inst.plname;
|
||||
|
||||
// Get data from the last remote RTCP report.
|
||||
for (const auto& block : channel_proxy_->GetRemoteRTCPReportBlocks()) {
|
||||
// Lookup report for send ssrc only.
|
||||
if (block.source_SSRC == stats.local_ssrc) {
|
||||
stats.packets_lost = block.cumulative_num_packets_lost;
|
||||
stats.fraction_lost = Q8ToFloat(block.fraction_lost);
|
||||
stats.ext_seqnum = block.extended_highest_sequence_number;
|
||||
// Convert samples to milliseconds.
|
||||
if (codec_inst.plfreq / 1000 > 0) {
|
||||
stats.jitter_ms =
|
||||
block.interarrival_jitter / (codec_inst.plfreq / 1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local speech level.
|
||||
{
|
||||
unsigned int level = 0;
|
||||
int error = volume->GetSpeechInputLevelFullRange(level);
|
||||
RTC_DCHECK_EQ(0, error);
|
||||
stats.audio_level = static_cast<int32_t>(level);
|
||||
}
|
||||
|
||||
bool echo_metrics_on = false;
|
||||
int error = processing->GetEcMetricsStatus(echo_metrics_on);
|
||||
RTC_DCHECK_EQ(0, error);
|
||||
if (echo_metrics_on) {
|
||||
// These can also be negative, but in practice -1 is only used to signal
|
||||
// insufficient data, since the resolution is limited to multiples of 4 ms.
|
||||
int median = -1;
|
||||
int std = -1;
|
||||
float dummy = 0.0f;
|
||||
error = processing->GetEcDelayMetrics(median, std, dummy);
|
||||
RTC_DCHECK_EQ(0, error);
|
||||
stats.echo_delay_median_ms = median;
|
||||
stats.echo_delay_std_ms = std;
|
||||
|
||||
// These can take on valid negative values, so use the lowest possible level
|
||||
// as default rather than -1.
|
||||
int erl = -100;
|
||||
int erle = -100;
|
||||
int dummy1 = 0;
|
||||
int dummy2 = 0;
|
||||
error = processing->GetEchoMetrics(erl, erle, dummy1, dummy2);
|
||||
RTC_DCHECK_EQ(0, error);
|
||||
stats.echo_return_loss = erl;
|
||||
stats.echo_return_loss_enhancement = erle;
|
||||
}
|
||||
|
||||
internal::AudioState* audio_state =
|
||||
static_cast<internal::AudioState*>(audio_state_.get());
|
||||
stats.typing_noise_detected = audio_state->typing_noise_detected();
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
const webrtc::AudioSendStream::Config& AudioSendStream::config() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return config_;
|
||||
}
|
||||
|
||||
VoiceEngine* AudioSendStream::voice_engine() const {
|
||||
internal::AudioState* audio_state =
|
||||
static_cast<internal::AudioState*>(audio_state_.get());
|
||||
VoiceEngine* voice_engine = audio_state->voice_engine();
|
||||
RTC_DCHECK(voice_engine);
|
||||
return voice_engine;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
61
media/webrtc/trunk/webrtc/audio/audio_send_stream.h
Normal file
61
media/webrtc/trunk/webrtc/audio/audio_send_stream.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
|
||||
#define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
|
||||
|
||||
#include "webrtc/audio_send_stream.h"
|
||||
#include "webrtc/audio_state.h"
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
class CongestionController;
|
||||
class VoiceEngine;
|
||||
|
||||
namespace voe {
|
||||
class ChannelProxy;
|
||||
} // namespace voe
|
||||
|
||||
namespace internal {
|
||||
class AudioSendStream final : public webrtc::AudioSendStream {
|
||||
public:
|
||||
AudioSendStream(const webrtc::AudioSendStream::Config& config,
|
||||
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
|
||||
CongestionController* congestion_controller);
|
||||
~AudioSendStream() override;
|
||||
|
||||
// webrtc::SendStream implementation.
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
void SignalNetworkState(NetworkState state) override;
|
||||
bool DeliverRtcp(const uint8_t* packet, size_t length) override;
|
||||
|
||||
// webrtc::AudioSendStream implementation.
|
||||
bool SendTelephoneEvent(int payload_type, uint8_t event,
|
||||
uint32_t duration_ms) override;
|
||||
webrtc::AudioSendStream::Stats GetStats() const override;
|
||||
|
||||
const webrtc::AudioSendStream::Config& config() const;
|
||||
|
||||
private:
|
||||
VoiceEngine* voice_engine() const;
|
||||
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
const webrtc::AudioSendStream::Config config_;
|
||||
rtc::scoped_refptr<webrtc::AudioState> audio_state_;
|
||||
rtc::scoped_ptr<voe::ChannelProxy> channel_proxy_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
|
||||
245
media/webrtc/trunk/webrtc/audio/audio_send_stream_unittest.cc
Normal file
245
media/webrtc/trunk/webrtc/audio/audio_send_stream_unittest.cc
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/audio/audio_send_stream.h"
|
||||
#include "webrtc/audio/audio_state.h"
|
||||
#include "webrtc/audio/conversion.h"
|
||||
#include "webrtc/call/congestion_controller.h"
|
||||
#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
|
||||
#include "webrtc/modules/pacing/paced_sender.h"
|
||||
#include "webrtc/test/mock_voe_channel_proxy.h"
|
||||
#include "webrtc/test/mock_voice_engine.h"
|
||||
#include "webrtc/video/call_stats.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using testing::_;
|
||||
using testing::Return;
|
||||
|
||||
const int kChannelId = 1;
|
||||
const uint32_t kSsrc = 1234;
|
||||
const char* kCName = "foo_name";
|
||||
const int kAudioLevelId = 2;
|
||||
const int kAbsSendTimeId = 3;
|
||||
const int kTransportSequenceNumberId = 4;
|
||||
const int kEchoDelayMedian = 254;
|
||||
const int kEchoDelayStdDev = -3;
|
||||
const int kEchoReturnLoss = -65;
|
||||
const int kEchoReturnLossEnhancement = 101;
|
||||
const unsigned int kSpeechInputLevel = 96;
|
||||
const CallStatistics kCallStats = {
|
||||
1345, 1678, 1901, 1234, 112, 13456, 17890, 1567, -1890, -1123};
|
||||
const CodecInst kCodecInst = {-121, "codec_name_send", 48000, -231, 0, -671};
|
||||
const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354};
|
||||
const int kTelephoneEventPayloadType = 123;
|
||||
const uint8_t kTelephoneEventCode = 45;
|
||||
const uint32_t kTelephoneEventDuration = 6789;
|
||||
|
||||
struct ConfigHelper {
|
||||
ConfigHelper()
|
||||
: stream_config_(nullptr),
|
||||
call_stats_(Clock::GetRealTimeClock()),
|
||||
process_thread_(ProcessThread::Create("AudioTestThread")),
|
||||
congestion_controller_(process_thread_.get(),
|
||||
&call_stats_,
|
||||
&bitrate_observer_) {
|
||||
using testing::Invoke;
|
||||
using testing::StrEq;
|
||||
|
||||
EXPECT_CALL(voice_engine_,
|
||||
RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
|
||||
EXPECT_CALL(voice_engine_,
|
||||
DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
|
||||
AudioState::Config config;
|
||||
config.voice_engine = &voice_engine_;
|
||||
audio_state_ = AudioState::Create(config);
|
||||
|
||||
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId))
|
||||
.WillOnce(Invoke([this](int channel_id) {
|
||||
EXPECT_FALSE(channel_proxy_);
|
||||
channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
|
||||
EXPECT_CALL(*channel_proxy_, SetRTCPStatus(true)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kSsrc)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetRTCP_CNAME(StrEq(kCName))).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetSendAbsoluteSenderTimeStatus(true, kAbsSendTimeId)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetSendAudioLevelIndicationStatus(true, kAudioLevelId)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, EnableSendTransportSequenceNumber(
|
||||
kTransportSequenceNumberId))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetCongestionControlObjects(
|
||||
congestion_controller_.pacer(),
|
||||
congestion_controller_.GetTransportFeedbackObserver(),
|
||||
congestion_controller_.packet_router()))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetCongestionControlObjects(nullptr, nullptr, nullptr))
|
||||
.Times(1);
|
||||
return channel_proxy_;
|
||||
}));
|
||||
stream_config_.voe_channel_id = kChannelId;
|
||||
stream_config_.rtp.ssrc = kSsrc;
|
||||
stream_config_.rtp.c_name = kCName;
|
||||
stream_config_.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
|
||||
stream_config_.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
|
||||
stream_config_.rtp.extensions.push_back(RtpExtension(
|
||||
RtpExtension::kTransportSequenceNumber, kTransportSequenceNumberId));
|
||||
}
|
||||
|
||||
AudioSendStream::Config& config() { return stream_config_; }
|
||||
rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
|
||||
CongestionController* congestion_controller() {
|
||||
return &congestion_controller_;
|
||||
}
|
||||
|
||||
void SetupMockForSendTelephoneEvent() {
|
||||
EXPECT_TRUE(channel_proxy_);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetSendTelephoneEventPayloadType(kTelephoneEventPayloadType))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
void SetupMockForGetStats() {
|
||||
using testing::DoAll;
|
||||
using testing::SetArgReferee;
|
||||
|
||||
std::vector<ReportBlock> report_blocks;
|
||||
webrtc::ReportBlock block = kReportBlock;
|
||||
report_blocks.push_back(block); // Has wrong SSRC.
|
||||
block.source_SSRC = kSsrc;
|
||||
report_blocks.push_back(block); // Correct block.
|
||||
block.fraction_lost = 0;
|
||||
report_blocks.push_back(block); // Duplicate SSRC, bad fraction_lost.
|
||||
|
||||
EXPECT_TRUE(channel_proxy_);
|
||||
EXPECT_CALL(*channel_proxy_, GetRTCPStatistics())
|
||||
.WillRepeatedly(Return(kCallStats));
|
||||
EXPECT_CALL(*channel_proxy_, GetRemoteRTCPReportBlocks())
|
||||
.WillRepeatedly(Return(report_blocks));
|
||||
|
||||
EXPECT_CALL(voice_engine_, GetSendCodec(kChannelId, _))
|
||||
.WillRepeatedly(DoAll(SetArgReferee<1>(kCodecInst), Return(0)));
|
||||
EXPECT_CALL(voice_engine_, GetSpeechInputLevelFullRange(_))
|
||||
.WillRepeatedly(DoAll(SetArgReferee<0>(kSpeechInputLevel), Return(0)));
|
||||
EXPECT_CALL(voice_engine_, GetEcMetricsStatus(_))
|
||||
.WillRepeatedly(DoAll(SetArgReferee<0>(true), Return(0)));
|
||||
EXPECT_CALL(voice_engine_, GetEchoMetrics(_, _, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgReferee<0>(kEchoReturnLoss),
|
||||
SetArgReferee<1>(kEchoReturnLossEnhancement),
|
||||
Return(0)));
|
||||
EXPECT_CALL(voice_engine_, GetEcDelayMetrics(_, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgReferee<0>(kEchoDelayMedian),
|
||||
SetArgReferee<1>(kEchoDelayStdDev), Return(0)));
|
||||
}
|
||||
|
||||
private:
|
||||
testing::StrictMock<MockVoiceEngine> voice_engine_;
|
||||
rtc::scoped_refptr<AudioState> audio_state_;
|
||||
AudioSendStream::Config stream_config_;
|
||||
testing::StrictMock<MockVoEChannelProxy>* channel_proxy_ = nullptr;
|
||||
CallStats call_stats_;
|
||||
testing::NiceMock<MockBitrateObserver> bitrate_observer_;
|
||||
rtc::scoped_ptr<ProcessThread> process_thread_;
|
||||
CongestionController congestion_controller_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(AudioSendStreamTest, ConfigToString) {
|
||||
AudioSendStream::Config config(nullptr);
|
||||
config.rtp.ssrc = kSsrc;
|
||||
config.rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
|
||||
config.rtp.c_name = kCName;
|
||||
config.voe_channel_id = kChannelId;
|
||||
config.cng_payload_type = 42;
|
||||
config.red_payload_type = 17;
|
||||
EXPECT_EQ(
|
||||
"{rtp: {ssrc: 1234, extensions: [{name: "
|
||||
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}], "
|
||||
"c_name: foo_name}, voe_channel_id: 1, cng_payload_type: 42, "
|
||||
"red_payload_type: 17}",
|
||||
config.ToString());
|
||||
}
|
||||
|
||||
TEST(AudioSendStreamTest, ConstructDestruct) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
|
||||
helper.congestion_controller());
|
||||
}
|
||||
|
||||
TEST(AudioSendStreamTest, SendTelephoneEvent) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
|
||||
helper.congestion_controller());
|
||||
helper.SetupMockForSendTelephoneEvent();
|
||||
EXPECT_TRUE(send_stream.SendTelephoneEvent(kTelephoneEventPayloadType,
|
||||
kTelephoneEventCode, kTelephoneEventDuration));
|
||||
}
|
||||
|
||||
TEST(AudioSendStreamTest, GetStats) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
|
||||
helper.congestion_controller());
|
||||
helper.SetupMockForGetStats();
|
||||
AudioSendStream::Stats stats = send_stream.GetStats();
|
||||
EXPECT_EQ(kSsrc, stats.local_ssrc);
|
||||
EXPECT_EQ(static_cast<int64_t>(kCallStats.bytesSent), stats.bytes_sent);
|
||||
EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent);
|
||||
EXPECT_EQ(static_cast<int32_t>(kReportBlock.cumulative_num_packets_lost),
|
||||
stats.packets_lost);
|
||||
EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost);
|
||||
EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name);
|
||||
EXPECT_EQ(static_cast<int32_t>(kReportBlock.extended_highest_sequence_number),
|
||||
stats.ext_seqnum);
|
||||
EXPECT_EQ(static_cast<int32_t>(kReportBlock.interarrival_jitter /
|
||||
(kCodecInst.plfreq / 1000)),
|
||||
stats.jitter_ms);
|
||||
EXPECT_EQ(kCallStats.rttMs, stats.rtt_ms);
|
||||
EXPECT_EQ(static_cast<int32_t>(kSpeechInputLevel), stats.audio_level);
|
||||
EXPECT_EQ(-1, stats.aec_quality_min);
|
||||
EXPECT_EQ(kEchoDelayMedian, stats.echo_delay_median_ms);
|
||||
EXPECT_EQ(kEchoDelayStdDev, stats.echo_delay_std_ms);
|
||||
EXPECT_EQ(kEchoReturnLoss, stats.echo_return_loss);
|
||||
EXPECT_EQ(kEchoReturnLossEnhancement, stats.echo_return_loss_enhancement);
|
||||
EXPECT_FALSE(stats.typing_noise_detected);
|
||||
}
|
||||
|
||||
TEST(AudioSendStreamTest, GetStatsTypingNoiseDetected) {
|
||||
ConfigHelper helper;
|
||||
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
|
||||
helper.congestion_controller());
|
||||
helper.SetupMockForGetStats();
|
||||
EXPECT_FALSE(send_stream.GetStats().typing_noise_detected);
|
||||
|
||||
internal::AudioState* internal_audio_state =
|
||||
static_cast<internal::AudioState*>(helper.audio_state().get());
|
||||
VoiceEngineObserver* voe_observer =
|
||||
static_cast<VoiceEngineObserver*>(internal_audio_state);
|
||||
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_WARNING);
|
||||
EXPECT_TRUE(send_stream.GetStats().typing_noise_detected);
|
||||
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_OFF_WARNING);
|
||||
EXPECT_FALSE(send_stream.GetStats().typing_noise_detected);
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
53
media/webrtc/trunk/webrtc/audio/audio_sink.h
Normal file
53
media/webrtc/trunk/webrtc/audio/audio_sink.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_AUDIO_SINK_H_
|
||||
#define WEBRTC_AUDIO_AUDIO_SINK_H_
|
||||
|
||||
#if defined(WEBRTC_POSIX) && !defined(__STDC_FORMAT_MACROS)
|
||||
// Avoid conflict with format_macros.h.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Represents a simple push audio sink.
|
||||
class AudioSinkInterface {
|
||||
public:
|
||||
virtual ~AudioSinkInterface() {}
|
||||
|
||||
struct Data {
|
||||
Data(int16_t* data,
|
||||
size_t samples_per_channel,
|
||||
int sample_rate,
|
||||
size_t channels,
|
||||
uint32_t timestamp)
|
||||
: data(data),
|
||||
samples_per_channel(samples_per_channel),
|
||||
sample_rate(sample_rate),
|
||||
channels(channels),
|
||||
timestamp(timestamp) {}
|
||||
|
||||
int16_t* data; // The actual 16bit audio data.
|
||||
size_t samples_per_channel; // Number of frames in the buffer.
|
||||
int sample_rate; // Sample rate in Hz.
|
||||
size_t channels; // Number of channels in the audio data.
|
||||
uint32_t timestamp; // The RTP timestamp of the first sample.
|
||||
};
|
||||
|
||||
virtual void OnData(const Data& audio) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_AUDIO_SINK_H_
|
||||
79
media/webrtc/trunk/webrtc/audio/audio_state.cc
Normal file
79
media/webrtc/trunk/webrtc/audio/audio_state.cc
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/audio/audio_state.h"
|
||||
|
||||
#include "webrtc/base/atomicops.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/voice_engine/include/voe_errors.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace internal {
|
||||
|
||||
AudioState::AudioState(const AudioState::Config& config)
|
||||
: config_(config), voe_base_(config.voice_engine) {
|
||||
process_thread_checker_.DetachFromThread();
|
||||
// Only one AudioState should be created per VoiceEngine.
|
||||
RTC_CHECK(voe_base_->RegisterVoiceEngineObserver(*this) != -1);
|
||||
}
|
||||
|
||||
AudioState::~AudioState() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
voe_base_->DeRegisterVoiceEngineObserver();
|
||||
}
|
||||
|
||||
VoiceEngine* AudioState::voice_engine() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return config_.voice_engine;
|
||||
}
|
||||
|
||||
bool AudioState::typing_noise_detected() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
return typing_noise_detected_;
|
||||
}
|
||||
|
||||
// Reference count; implementation copied from rtc::RefCountedObject.
|
||||
int AudioState::AddRef() const {
|
||||
return rtc::AtomicOps::Increment(&ref_count_);
|
||||
}
|
||||
|
||||
// Reference count; implementation copied from rtc::RefCountedObject.
|
||||
int AudioState::Release() const {
|
||||
int count = rtc::AtomicOps::Decrement(&ref_count_);
|
||||
if (!count) {
|
||||
delete this;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void AudioState::CallbackOnError(int channel_id, int err_code) {
|
||||
RTC_DCHECK(process_thread_checker_.CalledOnValidThread());
|
||||
|
||||
// All call sites in VoE, as of this writing, specify -1 as channel_id.
|
||||
RTC_DCHECK(channel_id == -1);
|
||||
LOG(LS_INFO) << "VoiceEngine error " << err_code << " reported on channel "
|
||||
<< channel_id << ".";
|
||||
if (err_code == VE_TYPING_NOISE_WARNING) {
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
typing_noise_detected_ = true;
|
||||
} else if (err_code == VE_TYPING_NOISE_OFF_WARNING) {
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
typing_noise_detected_ = false;
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
rtc::scoped_refptr<AudioState> AudioState::Create(
|
||||
const AudioState::Config& config) {
|
||||
return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
|
||||
}
|
||||
} // namespace webrtc
|
||||
61
media/webrtc/trunk/webrtc/audio/audio_state.h
Normal file
61
media/webrtc/trunk/webrtc/audio/audio_state.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_AUDIO_STATE_H_
|
||||
#define WEBRTC_AUDIO_AUDIO_STATE_H_
|
||||
|
||||
#include "webrtc/audio_state.h"
|
||||
#include "webrtc/audio/scoped_voe_interface.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "webrtc/voice_engine/include/voe_base.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace internal {
|
||||
|
||||
class AudioState final : public webrtc::AudioState,
|
||||
public webrtc::VoiceEngineObserver {
|
||||
public:
|
||||
explicit AudioState(const AudioState::Config& config);
|
||||
~AudioState() override;
|
||||
|
||||
VoiceEngine* voice_engine();
|
||||
bool typing_noise_detected() const;
|
||||
|
||||
private:
|
||||
// rtc::RefCountInterface implementation.
|
||||
int AddRef() const override;
|
||||
int Release() const override;
|
||||
|
||||
// webrtc::VoiceEngineObserver implementation.
|
||||
void CallbackOnError(int channel_id, int err_code) override;
|
||||
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
rtc::ThreadChecker process_thread_checker_;
|
||||
const webrtc::AudioState::Config config_;
|
||||
|
||||
// We hold one interface pointer to the VoE to make sure it is kept alive.
|
||||
ScopedVoEInterface<VoEBase> voe_base_;
|
||||
|
||||
// The critical section isn't strictly needed in this case, but xSAN bots may
|
||||
// trigger on unprotected cross-thread access.
|
||||
mutable rtc::CriticalSection crit_sect_;
|
||||
bool typing_noise_detected_ GUARDED_BY(crit_sect_) = false;
|
||||
|
||||
// Reference count; implementation copied from rtc::RefCountedObject.
|
||||
mutable volatile int ref_count_ = 0;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioState);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_AUDIO_STATE_H_
|
||||
80
media/webrtc/trunk/webrtc/audio/audio_state_unittest.cc
Normal file
80
media/webrtc/trunk/webrtc/audio/audio_state_unittest.cc
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/audio/audio_state.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/test/mock_voice_engine.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
struct ConfigHelper {
|
||||
ConfigHelper() {
|
||||
EXPECT_CALL(voice_engine_,
|
||||
RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(voice_engine_,
|
||||
DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0));
|
||||
config_.voice_engine = &voice_engine_;
|
||||
}
|
||||
AudioState::Config& config() { return config_; }
|
||||
MockVoiceEngine& voice_engine() { return voice_engine_; }
|
||||
|
||||
private:
|
||||
testing::StrictMock<MockVoiceEngine> voice_engine_;
|
||||
AudioState::Config config_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(AudioStateTest, Create) {
|
||||
ConfigHelper helper;
|
||||
rtc::scoped_refptr<AudioState> audio_state =
|
||||
AudioState::Create(helper.config());
|
||||
EXPECT_TRUE(audio_state.get());
|
||||
}
|
||||
|
||||
TEST(AudioStateTest, ConstructDestruct) {
|
||||
ConfigHelper helper;
|
||||
rtc::scoped_ptr<internal::AudioState> audio_state(
|
||||
new internal::AudioState(helper.config()));
|
||||
}
|
||||
|
||||
TEST(AudioStateTest, GetVoiceEngine) {
|
||||
ConfigHelper helper;
|
||||
rtc::scoped_ptr<internal::AudioState> audio_state(
|
||||
new internal::AudioState(helper.config()));
|
||||
EXPECT_EQ(audio_state->voice_engine(), &helper.voice_engine());
|
||||
}
|
||||
|
||||
TEST(AudioStateTest, TypingNoiseDetected) {
|
||||
ConfigHelper helper;
|
||||
rtc::scoped_ptr<internal::AudioState> audio_state(
|
||||
new internal::AudioState(helper.config()));
|
||||
VoiceEngineObserver* voe_observer =
|
||||
static_cast<VoiceEngineObserver*>(audio_state.get());
|
||||
EXPECT_FALSE(audio_state->typing_noise_detected());
|
||||
|
||||
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
|
||||
EXPECT_FALSE(audio_state->typing_noise_detected());
|
||||
|
||||
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_WARNING);
|
||||
EXPECT_TRUE(audio_state->typing_noise_detected());
|
||||
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
|
||||
EXPECT_TRUE(audio_state->typing_noise_detected());
|
||||
|
||||
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_OFF_WARNING);
|
||||
EXPECT_FALSE(audio_state->typing_noise_detected());
|
||||
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
|
||||
EXPECT_FALSE(audio_state->typing_noise_detected());
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
27
media/webrtc/trunk/webrtc/audio/conversion.h
Normal file
27
media/webrtc/trunk/webrtc/audio/conversion.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_CONVERSION_H_
|
||||
#define WEBRTC_AUDIO_CONVERSION_H_
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Convert fixed point number with 8 bit fractional part, to floating point.
|
||||
inline float Q8ToFloat(uint32_t v) {
|
||||
return static_cast<float>(v) / (1 << 8);
|
||||
}
|
||||
|
||||
// Convert fixed point number with 14 bit fractional part, to floating point.
|
||||
inline float Q14ToFloat(uint32_t v) {
|
||||
return static_cast<float>(v) / (1 << 14);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_CONVERSION_H_
|
||||
45
media/webrtc/trunk/webrtc/audio/scoped_voe_interface.h
Normal file
45
media/webrtc/trunk/webrtc/audio/scoped_voe_interface.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_
|
||||
#define WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class VoiceEngine;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Utility template for obtaining and holding a reference to a VoiceEngine
|
||||
// interface and making sure it is released when this object goes out of scope.
|
||||
template<class T> class ScopedVoEInterface {
|
||||
public:
|
||||
explicit ScopedVoEInterface(webrtc::VoiceEngine* e)
|
||||
: ptr_(T::GetInterface(e)) {
|
||||
RTC_DCHECK(ptr_);
|
||||
}
|
||||
~ScopedVoEInterface() {
|
||||
if (ptr_) {
|
||||
ptr_->Release();
|
||||
}
|
||||
}
|
||||
T* operator->() {
|
||||
RTC_DCHECK(ptr_);
|
||||
return ptr_;
|
||||
}
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_SCOPED_VOE_INTERFACE_H_
|
||||
28
media/webrtc/trunk/webrtc/audio/webrtc_audio.gypi
Normal file
28
media/webrtc/trunk/webrtc/audio/webrtc_audio.gypi
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
{
|
||||
'variables': {
|
||||
'webrtc_audio_dependencies': [
|
||||
'<(webrtc_root)/common.gyp:webrtc_common',
|
||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
|
||||
'<(webrtc_root)/webrtc.gyp:rtc_event_log',
|
||||
],
|
||||
'webrtc_audio_sources': [
|
||||
'audio/audio_receive_stream.cc',
|
||||
'audio/audio_receive_stream.h',
|
||||
'audio/audio_send_stream.cc',
|
||||
'audio/audio_send_stream.h',
|
||||
'audio/audio_sink.h',
|
||||
'audio/audio_state.cc',
|
||||
'audio/audio_state.h',
|
||||
'audio/conversion.h',
|
||||
'audio/scoped_voe_interface.h',
|
||||
],
|
||||
},
|
||||
}
|
||||
124
media/webrtc/trunk/webrtc/audio_receive_stream.h
Normal file
124
media/webrtc/trunk/webrtc/audio_receive_stream.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_RECEIVE_STREAM_H_
|
||||
#define WEBRTC_AUDIO_RECEIVE_STREAM_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/config.h"
|
||||
#include "webrtc/stream.h"
|
||||
#include "webrtc/transport.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AudioDecoder;
|
||||
class AudioSinkInterface;
|
||||
|
||||
// WORK IN PROGRESS
|
||||
// This class is under development and is not yet intended for for use outside
|
||||
// of WebRtc/Libjingle. Please use the VoiceEngine API instead.
|
||||
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4690
|
||||
|
||||
class AudioReceiveStream : public ReceiveStream {
|
||||
public:
|
||||
struct Stats {
|
||||
uint32_t remote_ssrc = 0;
|
||||
int64_t bytes_rcvd = 0;
|
||||
uint32_t packets_rcvd = 0;
|
||||
uint32_t packets_lost = 0;
|
||||
float fraction_lost = 0.0f;
|
||||
std::string codec_name;
|
||||
uint32_t ext_seqnum = 0;
|
||||
uint32_t jitter_ms = 0;
|
||||
uint32_t jitter_buffer_ms = 0;
|
||||
uint32_t jitter_buffer_preferred_ms = 0;
|
||||
uint32_t delay_estimate_ms = 0;
|
||||
int32_t audio_level = -1;
|
||||
float expand_rate = 0.0f;
|
||||
float speech_expand_rate = 0.0f;
|
||||
float secondary_decoded_rate = 0.0f;
|
||||
float accelerate_rate = 0.0f;
|
||||
float preemptive_expand_rate = 0.0f;
|
||||
int32_t decoding_calls_to_silence_generator = 0;
|
||||
int32_t decoding_calls_to_neteq = 0;
|
||||
int32_t decoding_normal = 0;
|
||||
int32_t decoding_plc = 0;
|
||||
int32_t decoding_cng = 0;
|
||||
int32_t decoding_plc_cng = 0;
|
||||
int64_t capture_start_ntp_time_ms = 0;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
std::string ToString() const;
|
||||
|
||||
// Receive-stream specific RTP settings.
|
||||
struct Rtp {
|
||||
std::string ToString() const;
|
||||
|
||||
// Synchronization source (stream identifier) to be received.
|
||||
uint32_t remote_ssrc = 0;
|
||||
|
||||
// Sender SSRC used for sending RTCP (such as receiver reports).
|
||||
uint32_t local_ssrc = 0;
|
||||
|
||||
// Enable feedback for send side bandwidth estimation.
|
||||
// See
|
||||
// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions
|
||||
// for details.
|
||||
bool transport_cc = false;
|
||||
|
||||
// RTP header extensions used for the received stream.
|
||||
std::vector<RtpExtension> extensions;
|
||||
} rtp;
|
||||
|
||||
Transport* receive_transport = nullptr;
|
||||
Transport* rtcp_send_transport = nullptr;
|
||||
|
||||
// Underlying VoiceEngine handle, used to map AudioReceiveStream to lower-
|
||||
// level components.
|
||||
// TODO(solenberg): Remove when VoiceEngine channels are created outside
|
||||
// of Call.
|
||||
int voe_channel_id = -1;
|
||||
|
||||
// Identifier for an A/V synchronization group. Empty string to disable.
|
||||
// TODO(pbos): Synchronize streams in a sync group, not just one video
|
||||
// stream to one audio stream. Tracked by issue webrtc:4762.
|
||||
std::string sync_group;
|
||||
|
||||
// Decoders for every payload that we can receive. Call owns the
|
||||
// AudioDecoder instances once the Config is submitted to
|
||||
// Call::CreateReceiveStream().
|
||||
// TODO(solenberg): Use unique_ptr<> once our std lib fully supports C++11.
|
||||
std::map<uint8_t, AudioDecoder*> decoder_map;
|
||||
|
||||
// TODO(pbos): Remove config option once combined A/V BWE is always on.
|
||||
bool combined_audio_video_bwe = false;
|
||||
};
|
||||
|
||||
virtual Stats GetStats() const = 0;
|
||||
|
||||
// Sets an audio sink that receives unmixed audio from the receive stream.
|
||||
// Ownership of the sink is passed to the stream and can be used by the
|
||||
// caller to do lifetime management (i.e. when the sink's dtor is called).
|
||||
// Only one sink can be set and passing a null sink, clears an existing one.
|
||||
// NOTE: Audio must still somehow be pulled through AudioTransport for audio
|
||||
// to stream through this sink. In practice, this happens if mixed audio
|
||||
// is being pulled+rendered and/or if audio is being pulled for the purposes
|
||||
// of feeding to the AEC.
|
||||
virtual void SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) = 0;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_RECEIVE_STREAM_H_
|
||||
99
media/webrtc/trunk/webrtc/audio_send_stream.h
Normal file
99
media/webrtc/trunk/webrtc/audio_send_stream.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_AUDIO_SEND_STREAM_H_
|
||||
#define WEBRTC_AUDIO_SEND_STREAM_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/config.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
|
||||
#include "webrtc/stream.h"
|
||||
#include "webrtc/transport.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// WORK IN PROGRESS
|
||||
// This class is under development and is not yet intended for for use outside
|
||||
// of WebRtc/Libjingle. Please use the VoiceEngine API instead.
|
||||
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4690
|
||||
|
||||
class AudioSendStream : public SendStream {
|
||||
public:
|
||||
struct Stats {
|
||||
// TODO(solenberg): Harmonize naming and defaults with receive stream stats.
|
||||
uint32_t local_ssrc = 0;
|
||||
int64_t bytes_sent = 0;
|
||||
int32_t packets_sent = 0;
|
||||
int32_t packets_lost = -1;
|
||||
float fraction_lost = -1.0f;
|
||||
std::string codec_name;
|
||||
int32_t ext_seqnum = -1;
|
||||
int32_t jitter_ms = -1;
|
||||
int64_t rtt_ms = -1;
|
||||
int32_t audio_level = -1;
|
||||
float aec_quality_min = -1.0f;
|
||||
int32_t echo_delay_median_ms = -1;
|
||||
int32_t echo_delay_std_ms = -1;
|
||||
int32_t echo_return_loss = -100;
|
||||
int32_t echo_return_loss_enhancement = -100;
|
||||
bool typing_noise_detected = false;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
Config() = delete;
|
||||
explicit Config(Transport* send_transport)
|
||||
: send_transport(send_transport) {}
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
// Receive-stream specific RTP settings.
|
||||
struct Rtp {
|
||||
std::string ToString() const;
|
||||
|
||||
// Sender SSRC.
|
||||
uint32_t ssrc = 0;
|
||||
|
||||
// RTP header extensions used for the sent stream.
|
||||
std::vector<RtpExtension> extensions;
|
||||
|
||||
// RTCP CNAME, see RFC 3550.
|
||||
std::string c_name;
|
||||
} rtp;
|
||||
|
||||
// Transport for outgoing packets. The transport is expected to exist for
|
||||
// the entire life of the AudioSendStream and is owned by the API client.
|
||||
Transport* send_transport = nullptr;
|
||||
|
||||
// Underlying VoiceEngine handle, used to map AudioSendStream to lower-level
|
||||
// components.
|
||||
// TODO(solenberg): Remove when VoiceEngine channels are created outside
|
||||
// of Call.
|
||||
int voe_channel_id = -1;
|
||||
|
||||
// Ownership of the encoder object is transferred to Call when the config is
|
||||
// passed to Call::CreateAudioSendStream().
|
||||
// TODO(solenberg): Implement, once we configure codecs through the new API.
|
||||
// rtc::scoped_ptr<AudioEncoder> encoder;
|
||||
int cng_payload_type = -1; // pt, or -1 to disable Comfort Noise Generator.
|
||||
int red_payload_type = -1; // pt, or -1 to disable REDundant coding.
|
||||
};
|
||||
|
||||
// TODO(solenberg): Make payload_type a config property instead.
|
||||
virtual bool SendTelephoneEvent(int payload_type, uint8_t event,
|
||||
uint32_t duration_ms) = 0;
|
||||
virtual Stats GetStats() const = 0;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_SEND_STREAM_H_
|
||||
48
media/webrtc/trunk/webrtc/audio_state.h
Normal file
48
media/webrtc/trunk/webrtc/audio_state.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef WEBRTC_AUDIO_STATE_H_
|
||||
#define WEBRTC_AUDIO_STATE_H_
|
||||
|
||||
#include "webrtc/base/refcount.h"
|
||||
#include "webrtc/base/scoped_ref_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AudioDeviceModule;
|
||||
class VoiceEngine;
|
||||
|
||||
// WORK IN PROGRESS
|
||||
// This class is under development and is not yet intended for for use outside
|
||||
// of WebRtc/Libjingle. Please use the VoiceEngine API instead.
|
||||
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4690
|
||||
|
||||
// AudioState holds the state which must be shared between multiple instances of
|
||||
// webrtc::Call for audio processing purposes.
|
||||
class AudioState : public rtc::RefCountInterface {
|
||||
public:
|
||||
struct Config {
|
||||
// VoiceEngine used for audio streams and audio/video synchronization.
|
||||
// AudioState will tickle the VoE refcount to keep it alive for as long as
|
||||
// the AudioState itself.
|
||||
VoiceEngine* voice_engine = nullptr;
|
||||
|
||||
// The AudioDeviceModule associated with the Calls.
|
||||
AudioDeviceModule* audio_device_module = nullptr;
|
||||
};
|
||||
|
||||
// TODO(solenberg): Replace scoped_refptr with shared_ptr once we can use it.
|
||||
static rtc::scoped_refptr<AudioState> Create(
|
||||
const AudioState::Config& config);
|
||||
|
||||
virtual ~AudioState() {}
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_AUDIO_STATE_H_
|
||||
|
|
@ -10,6 +10,13 @@ import("//build/config/crypto.gni")
|
|||
import("//build/config/ui.gni")
|
||||
import("../build/webrtc.gni")
|
||||
|
||||
# Enable OpenSSL (BoringSSL) for iOS. This is covered in webrtc/supplement.gypi
|
||||
# for the GYP build.
|
||||
import("//build_overrides/webrtc.gni")
|
||||
if (is_ios && !build_with_chromium) {
|
||||
use_openssl = true
|
||||
}
|
||||
|
||||
config("rtc_base_config") {
|
||||
include_dirs = [
|
||||
"//third_party/jsoncpp/overrides/include",
|
||||
|
|
@ -21,15 +28,15 @@ config("rtc_base_config") {
|
|||
"LOGGING=1",
|
||||
]
|
||||
|
||||
# TODO(henrike): issue 3307, make rtc_base build without disabling
|
||||
# these flags.
|
||||
cflags_cc = [ "-Wno-non-virtual-dtor" ]
|
||||
if (is_posix) {
|
||||
# TODO(henrike): issue 3307, make rtc_base build without disabling
|
||||
# these flags.
|
||||
cflags_cc = [ "-Wno-non-virtual-dtor" ]
|
||||
}
|
||||
}
|
||||
|
||||
config("rtc_base_chromium_config") {
|
||||
defines = [
|
||||
"NO_MAIN_THREAD_WRAPPING",
|
||||
]
|
||||
defines = [ "NO_MAIN_THREAD_WRAPPING" ]
|
||||
}
|
||||
|
||||
config("openssl_config") {
|
||||
|
|
@ -39,19 +46,15 @@ config("openssl_config") {
|
|||
]
|
||||
}
|
||||
|
||||
config("nss_config") {
|
||||
defines = [
|
||||
"SSL_USE_NSS",
|
||||
"HAVE_NSS_SSL_H",
|
||||
"SSL_USE_NSS_RNG",
|
||||
]
|
||||
}
|
||||
|
||||
config("ios_config") {
|
||||
libs = [
|
||||
"AVFoundation.framework",
|
||||
"CFNetwork.framework",
|
||||
|
||||
#"Foundation.framework", # Already included in //build/config:default_libs.
|
||||
"Security.framework",
|
||||
"SystemConfiguration.framework",
|
||||
|
||||
#"UIKit.framework", # Already included in //build/config:default_libs.
|
||||
]
|
||||
}
|
||||
|
|
@ -59,6 +62,7 @@ config("ios_config") {
|
|||
config("mac_config") {
|
||||
libs = [
|
||||
"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.
|
||||
|
|
@ -77,13 +81,8 @@ if (is_linux && !build_with_chromium) {
|
|||
# WebRTC cannot use as we don't sync src/crypto from Chromium.
|
||||
group("linux_system_ssl") {
|
||||
if (use_openssl) {
|
||||
deps = [ "//third_party/boringssl" ]
|
||||
} else {
|
||||
deps = [ "//net/third_party/nss/ssl:libssl" ]
|
||||
|
||||
public_configs = [
|
||||
"//net/third_party/nss/ssl:ssl_config",
|
||||
"//third_party/nss:system_nss_no_ssl_config",
|
||||
deps = [
|
||||
"//third_party/boringssl",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -99,12 +98,28 @@ if (rtc_build_ssl == 0) {
|
|||
|
||||
# The subset of rtc_base approved for use outside of libjingle.
|
||||
static_library("rtc_base_approved") {
|
||||
deps = []
|
||||
configs += [ "..:common_config" ]
|
||||
public_configs = [ "..:common_inherited_config" ]
|
||||
|
||||
sources = [
|
||||
"array_view.h",
|
||||
"atomicops.h",
|
||||
"bitbuffer.cc",
|
||||
"bitbuffer.h",
|
||||
"buffer.cc",
|
||||
"buffer.h",
|
||||
"bufferqueue.cc",
|
||||
"bufferqueue.h",
|
||||
"bytebuffer.cc",
|
||||
"bytebuffer.h",
|
||||
"byteorder.h",
|
||||
"checks.cc",
|
||||
"checks.h",
|
||||
"constructormagic.h",
|
||||
"criticalsection.cc",
|
||||
"criticalsection.h",
|
||||
"deprecation.h",
|
||||
"event.cc",
|
||||
"event.h",
|
||||
"event_tracer.cc",
|
||||
|
|
@ -115,14 +130,23 @@ static_library("rtc_base_approved") {
|
|||
"md5.h",
|
||||
"md5digest.cc",
|
||||
"md5digest.h",
|
||||
"optional.h",
|
||||
"platform_file.cc",
|
||||
"platform_file.h",
|
||||
"platform_thread.cc",
|
||||
"platform_thread.h",
|
||||
"platform_thread_types.h",
|
||||
"random.cc",
|
||||
"random.h",
|
||||
"safe_conversions.h",
|
||||
"safe_conversions_impl.h",
|
||||
"scoped_ptr.h",
|
||||
"stringencode.cc",
|
||||
"stringencode.h",
|
||||
"stringutils.cc",
|
||||
"stringutils.h",
|
||||
"systeminfo.cc",
|
||||
"systeminfo.h",
|
||||
"template_util.h",
|
||||
"thread_annotations.h",
|
||||
"thread_checker.h",
|
||||
|
|
@ -132,13 +156,29 @@ static_library("rtc_base_approved") {
|
|||
"timeutils.h",
|
||||
"trace_event.h",
|
||||
]
|
||||
|
||||
if (build_with_chromium) {
|
||||
# Dependency on chromium's logging (in //base).
|
||||
deps += [ "//base:base" ]
|
||||
sources += [
|
||||
"../../webrtc_overrides/webrtc/base/logging.cc",
|
||||
"../../webrtc_overrides/webrtc/base/logging.h",
|
||||
]
|
||||
include_dirs = [ "../../webrtc_overrides" ]
|
||||
} else {
|
||||
sources += [
|
||||
"logging.cc",
|
||||
"logging.h",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
static_library("rtc_base") {
|
||||
cflags = []
|
||||
cflags_cc = []
|
||||
libs = []
|
||||
deps = [
|
||||
deps = []
|
||||
public_deps = [
|
||||
":rtc_base_approved",
|
||||
]
|
||||
|
||||
|
|
@ -152,16 +192,15 @@ static_library("rtc_base") {
|
|||
":rtc_base_config",
|
||||
]
|
||||
|
||||
defines = [
|
||||
"LOGGING=1",
|
||||
]
|
||||
defines = [ "LOGGING=1" ]
|
||||
|
||||
sources = [
|
||||
"arraysize.h",
|
||||
"asyncfile.cc",
|
||||
"asyncfile.h",
|
||||
"asynchttprequest.cc",
|
||||
"asynchttprequest.h",
|
||||
"asyncinvoker-inl.h",
|
||||
"asyncinvoker.cc",
|
||||
"asyncinvoker.h",
|
||||
"asyncpacketsocket.cc",
|
||||
"asyncpacketsocket.h",
|
||||
"asyncresolverinterface.cc",
|
||||
|
|
@ -176,24 +215,16 @@ static_library("rtc_base") {
|
|||
"autodetectproxy.h",
|
||||
"base64.cc",
|
||||
"base64.h",
|
||||
"basicdefs.h",
|
||||
"buffer.cc",
|
||||
"buffer.h",
|
||||
"bytebuffer.cc",
|
||||
"bytebuffer.h",
|
||||
"byteorder.h",
|
||||
"common.cc",
|
||||
"common.h",
|
||||
"cpumonitor.cc",
|
||||
"cpumonitor.h",
|
||||
"crc32.cc",
|
||||
"crc32.h",
|
||||
"criticalsection.cc",
|
||||
"criticalsection.h",
|
||||
"cryptstring.cc",
|
||||
"cryptstring.h",
|
||||
"diskcache.cc",
|
||||
"diskcache.h",
|
||||
"filerotatingstream.cc",
|
||||
"filerotatingstream.h",
|
||||
"fileutils.cc",
|
||||
"fileutils.h",
|
||||
"firewallsocketserver.cc",
|
||||
|
|
@ -228,6 +259,8 @@ static_library("rtc_base") {
|
|||
"nethelpers.h",
|
||||
"network.cc",
|
||||
"network.h",
|
||||
"networkmonitor.cc",
|
||||
"networkmonitor.h",
|
||||
"nullsocketserver.h",
|
||||
"pathutils.cc",
|
||||
"pathutils.h",
|
||||
|
|
@ -241,9 +274,10 @@ static_library("rtc_base") {
|
|||
"ratelimiter.h",
|
||||
"ratetracker.cc",
|
||||
"ratetracker.h",
|
||||
"rtccertificate.cc",
|
||||
"rtccertificate.h",
|
||||
"scoped_autorelease_pool.h",
|
||||
"scoped_autorelease_pool.mm",
|
||||
"scoped_ptr.h",
|
||||
"sha1.cc",
|
||||
"sha1.h",
|
||||
"sha1digest.cc",
|
||||
|
|
@ -280,8 +314,6 @@ static_library("rtc_base") {
|
|||
"sslstreamadapterhelper.h",
|
||||
"stream.cc",
|
||||
"stream.h",
|
||||
"systeminfo.cc",
|
||||
"systeminfo.h",
|
||||
"task.cc",
|
||||
"task.h",
|
||||
"taskparent.cc",
|
||||
|
|
@ -300,47 +332,38 @@ static_library("rtc_base") {
|
|||
|
||||
if (is_posix) {
|
||||
sources += [
|
||||
"ifaddrs-android.h",
|
||||
"ifaddrs_converter.cc",
|
||||
"unixfilesystem.cc",
|
||||
"unixfilesystem.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",
|
||||
]
|
||||
|
||||
deps += [ "..:webrtc_common" ]
|
||||
|
||||
if (is_mac) {
|
||||
sources += [ "macifaddrs_converter.cc" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "../overrides/webrtc/base/win32socketinit.cc" ]
|
||||
sources += [ "../../webrtc_overrides/webrtc/base/win32socketinit.cc" ]
|
||||
}
|
||||
|
||||
include_dirs = [
|
||||
"../overrides",
|
||||
"../../webrtc_overrides",
|
||||
"../../boringssl/src/include",
|
||||
]
|
||||
|
||||
public_configs += [ ":rtc_base_chromium_config" ]
|
||||
} else {
|
||||
sources += [
|
||||
"asyncinvoker.cc",
|
||||
"asyncinvoker.h",
|
||||
"asyncinvoker-inl.h",
|
||||
"atomicops.h",
|
||||
"bandwidthsmoother.cc",
|
||||
"bandwidthsmoother.h",
|
||||
"basictypes.h",
|
||||
"bind.h",
|
||||
"bind.h.pump",
|
||||
"callback.h",
|
||||
"callback.h.pump",
|
||||
"constructormagic.h",
|
||||
"filelock.cc",
|
||||
"filelock.h",
|
||||
"fileutils_mock.h",
|
||||
"genericslot.h",
|
||||
"genericslot.h.pump",
|
||||
|
|
@ -348,8 +371,8 @@ static_library("rtc_base") {
|
|||
"httpserver.h",
|
||||
"json.cc",
|
||||
"json.h",
|
||||
"logging.cc",
|
||||
"logging.h",
|
||||
"logsinks.cc",
|
||||
"logsinks.h",
|
||||
"mathutils.h",
|
||||
"multipart.cc",
|
||||
"multipart.h",
|
||||
|
|
@ -368,8 +391,8 @@ static_library("rtc_base") {
|
|||
"refcount.h",
|
||||
"referencecountedsingletonfactory.h",
|
||||
"rollingaccumulator.h",
|
||||
"scopedptrcollection.h",
|
||||
"scoped_ref_ptr.h",
|
||||
"scopedptrcollection.h",
|
||||
"sec_buffer.h",
|
||||
"sharedexclusivelock.cc",
|
||||
"sharedexclusivelock.h",
|
||||
|
|
@ -384,8 +407,8 @@ static_library("rtc_base") {
|
|||
"virtualsocketserver.cc",
|
||||
"virtualsocketserver.h",
|
||||
"window.h",
|
||||
"windowpickerfactory.h",
|
||||
"windowpicker.h",
|
||||
"windowpickerfactory.h",
|
||||
]
|
||||
|
||||
deps += [ "..:webrtc_common" ]
|
||||
|
|
@ -475,31 +498,6 @@ static_library("rtc_base") {
|
|||
"opensslstreamadapter.cc",
|
||||
"opensslstreamadapter.h",
|
||||
]
|
||||
} else {
|
||||
public_configs += [ ":nss_config" ]
|
||||
if (rtc_build_ssl) {
|
||||
if (build_with_chromium) {
|
||||
deps += [ "//crypto:platform" ]
|
||||
} else {
|
||||
deps += [ "//net/third_party/nss/ssl:libssl" ]
|
||||
if (is_linux) {
|
||||
deps += [ ":linux_system_ssl" ]
|
||||
} else {
|
||||
deps += [
|
||||
"//third_party/nss:nspr",
|
||||
"//third_party/nss:nss",
|
||||
]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
configs += [ "external_ssl_library" ]
|
||||
}
|
||||
sources += [
|
||||
"nssidentity.cc",
|
||||
"nssidentity.h",
|
||||
"nssstreamadapter.cc",
|
||||
"nssstreamadapter.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
|
|
@ -510,12 +508,17 @@ static_library("rtc_base") {
|
|||
|
||||
libs += [
|
||||
"log",
|
||||
"GLESv2"
|
||||
"GLESv2",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_ios) {
|
||||
all_dependent_configs += [ ":ios_config" ]
|
||||
all_dependent_configs = [ ":ios_config" ]
|
||||
|
||||
sources += [
|
||||
"macconversion.cc",
|
||||
"macconversion.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (use_x11) {
|
||||
|
|
@ -559,8 +562,6 @@ static_library("rtc_base") {
|
|||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
"schanneladapter.cc",
|
||||
"schanneladapter.h",
|
||||
"win32.cc",
|
||||
"win32.h",
|
||||
"win32filesystem.cc",
|
||||
|
|
@ -608,4 +609,32 @@ static_library("rtc_base") {
|
|||
"linux.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_nacl) {
|
||||
deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
|
||||
defines += [ "timezone=_timezone" ]
|
||||
sources -= [ "ifaddrs_converter.cc" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (is_ios) {
|
||||
source_set("rtc_base_objc") {
|
||||
deps = [
|
||||
":rtc_base",
|
||||
]
|
||||
cflags = [ "-fobjc-arc" ]
|
||||
configs += [ "..:common_config" ]
|
||||
public_configs = [ "..:common_inherited_config" ]
|
||||
|
||||
sources = [
|
||||
"objc/NSString+StdString.h",
|
||||
"objc/NSString+StdString.mm",
|
||||
"objc/RTCCameraPreviewView.h",
|
||||
"objc/RTCCameraPreviewView.m",
|
||||
"objc/RTCDispatcher.h",
|
||||
"objc/RTCDispatcher.m",
|
||||
"objc/RTCLogging.h",
|
||||
"objc/RTCLogging.mm",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,4 +9,10 @@ pthatcher@webrtc.org
|
|||
sergeyu@chromium.org
|
||||
tommi@webrtc.org
|
||||
|
||||
# These are for the common case of adding or renaming files. If you're doing
|
||||
# structural changes, please get a review from a reviewer in this file.
|
||||
per-file *.gyp=*
|
||||
per-file *.gypi=*
|
||||
|
||||
per-file BUILD.gn=kjellander@webrtc.org
|
||||
|
||||
|
|
|
|||
133
media/webrtc/trunk/webrtc/base/array_view.h
Normal file
133
media/webrtc/trunk/webrtc/base/array_view.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_ARRAY_VIEW_H_
|
||||
#define WEBRTC_BASE_ARRAY_VIEW_H_
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Many functions read from or write to arrays. The obvious way to do this is
|
||||
// to use two arguments, a pointer to the first element and an element count:
|
||||
//
|
||||
// bool Contains17(const int* arr, size_t size) {
|
||||
// for (size_t i = 0; i < size; ++i) {
|
||||
// if (arr[i] == 17)
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// This is flexible, since it doesn't matter how the array is stored (C array,
|
||||
// std::vector, rtc::Buffer, ...), but it's error-prone because the caller has
|
||||
// to correctly specify the array length:
|
||||
//
|
||||
// Contains17(arr, arraysize(arr)); // C array
|
||||
// Contains17(&arr[0], arr.size()); // std::vector
|
||||
// Contains17(arr, size); // pointer + size
|
||||
// ...
|
||||
//
|
||||
// It's also kind of messy to have two separate arguments for what is
|
||||
// conceptually a single thing.
|
||||
//
|
||||
// Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't
|
||||
// own) and a count, and supports the basic things you'd expect, such as
|
||||
// indexing and iteration. It allows us to write our function like this:
|
||||
//
|
||||
// bool Contains17(rtc::ArrayView<const int> arr) {
|
||||
// for (auto e : arr) {
|
||||
// if (e == 17)
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// And even better, because a bunch of things will implicitly convert to
|
||||
// ArrayView, we can call it like this:
|
||||
//
|
||||
// Contains17(arr); // C array
|
||||
// Contains17(arr); // std::vector
|
||||
// Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size
|
||||
// ...
|
||||
//
|
||||
// One important point is that ArrayView<T> and ArrayView<const T> are
|
||||
// different types, which allow and don't allow mutation of the array elements,
|
||||
// respectively. The implicit conversions work just like you'd hope, so that
|
||||
// e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const
|
||||
// int>, but const vector<int> will convert only to ArrayView<const int>.
|
||||
// (ArrayView itself can be the source type in such conversions, so
|
||||
// ArrayView<int> will convert to ArrayView<const int>.)
|
||||
//
|
||||
// Note: ArrayView is tiny (just a pointer and a count) and trivially copyable,
|
||||
// so it's probably cheaper to pass it by value than by const reference.
|
||||
template <typename T>
|
||||
class ArrayView final {
|
||||
public:
|
||||
// Construct an empty ArrayView.
|
||||
ArrayView() : ArrayView(static_cast<T*>(nullptr), 0) {}
|
||||
|
||||
// Construct an ArrayView for a (pointer,size) pair.
|
||||
template <typename U>
|
||||
ArrayView(U* data, size_t size)
|
||||
: data_(size == 0 ? nullptr : data), size_(size) {
|
||||
CheckInvariant();
|
||||
}
|
||||
|
||||
// Construct an ArrayView for an array.
|
||||
template <typename U, size_t N>
|
||||
ArrayView(U (&array)[N]) : ArrayView(&array[0], N) {}
|
||||
|
||||
// Construct an ArrayView for any type U that has a size() method whose
|
||||
// return value converts implicitly to size_t, and a data() method whose
|
||||
// return value converts implicitly to T*. In particular, this means we allow
|
||||
// conversion from ArrayView<T> to ArrayView<const T>, but not the other way
|
||||
// around. Other allowed conversions include std::vector<T> to ArrayView<T>
|
||||
// or ArrayView<const T>, const std::vector<T> to ArrayView<const T>, and
|
||||
// rtc::Buffer to ArrayView<uint8_t> (with the same const behavior as
|
||||
// std::vector).
|
||||
template <typename U>
|
||||
ArrayView(U& u) : ArrayView(u.data(), u.size()) {}
|
||||
|
||||
// Indexing, size, and iteration. These allow mutation even if the ArrayView
|
||||
// is const, because the ArrayView doesn't own the array. (To prevent
|
||||
// mutation, use ArrayView<const T>.)
|
||||
size_t size() const { return size_; }
|
||||
bool empty() const { return size_ == 0; }
|
||||
T* data() const { return data_; }
|
||||
T& operator[](size_t idx) const {
|
||||
RTC_DCHECK_LT(idx, size_);
|
||||
RTC_DCHECK(data_); // Follows from size_ > idx and the class invariant.
|
||||
return data_[idx];
|
||||
}
|
||||
T* begin() const { return data_; }
|
||||
T* end() const { return data_ + size_; }
|
||||
const T* cbegin() const { return data_; }
|
||||
const T* cend() const { return data_ + size_; }
|
||||
|
||||
// Comparing two ArrayViews compares their (pointer,size) pairs; it does
|
||||
// *not* dereference the pointers.
|
||||
friend bool operator==(const ArrayView& a, const ArrayView& b) {
|
||||
return a.data_ == b.data_ && a.size_ == b.size_;
|
||||
}
|
||||
friend bool operator!=(const ArrayView& a, const ArrayView& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
private:
|
||||
// Invariant: !data_ iff size_ == 0.
|
||||
void CheckInvariant() const { RTC_DCHECK_EQ(!data_, size_ == 0); }
|
||||
T* data_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_ARRAY_VIEW_H_
|
||||
233
media/webrtc/trunk/webrtc/base/array_view_unittest.cc
Normal file
233
media/webrtc/trunk/webrtc/base/array_view_unittest.cc
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/array_view.h"
|
||||
#include "webrtc/base/buffer.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
void Call(ArrayView<T>) {}
|
||||
} // namespace
|
||||
|
||||
TEST(ArrayViewTest, TestConstructFromPtrAndArray) {
|
||||
char arr[] = "Arrr!";
|
||||
const char carr[] = "Carrr!";
|
||||
Call<const char>(arr);
|
||||
Call<const char>(carr);
|
||||
Call<char>(arr);
|
||||
// Call<char>(carr); // Compile error, because can't drop const.
|
||||
// Call<int>(arr); // Compile error, because incompatible types.
|
||||
ArrayView<int*> x;
|
||||
EXPECT_EQ(0u, x.size());
|
||||
EXPECT_EQ(nullptr, x.data());
|
||||
ArrayView<char> y = arr;
|
||||
EXPECT_EQ(6u, y.size());
|
||||
EXPECT_EQ(arr, y.data());
|
||||
ArrayView<const char> z(arr + 1, 3);
|
||||
EXPECT_EQ(3u, z.size());
|
||||
EXPECT_EQ(arr + 1, z.data());
|
||||
ArrayView<const char> w(arr, 2);
|
||||
EXPECT_EQ(2u, w.size());
|
||||
EXPECT_EQ(arr, w.data());
|
||||
ArrayView<char> q(arr, 0);
|
||||
EXPECT_EQ(0u, q.size());
|
||||
EXPECT_EQ(nullptr, q.data());
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
// DCHECK error (nullptr with nonzero size).
|
||||
EXPECT_DEATH(ArrayView<int>(static_cast<int*>(nullptr), 5), "");
|
||||
#endif
|
||||
// These are compile errors, because incompatible types.
|
||||
// ArrayView<int> m = arr;
|
||||
// ArrayView<float> n(arr + 2, 2);
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestCopyConstructor) {
|
||||
char arr[] = "Arrr!";
|
||||
ArrayView<char> x = arr;
|
||||
EXPECT_EQ(6u, x.size());
|
||||
EXPECT_EQ(arr, x.data());
|
||||
ArrayView<char> y = x; // Copy non-const -> non-const.
|
||||
EXPECT_EQ(6u, y.size());
|
||||
EXPECT_EQ(arr, y.data());
|
||||
ArrayView<const char> z = x; // Copy non-const -> const.
|
||||
EXPECT_EQ(6u, z.size());
|
||||
EXPECT_EQ(arr, z.data());
|
||||
ArrayView<const char> w = z; // Copy const -> const.
|
||||
EXPECT_EQ(6u, w.size());
|
||||
EXPECT_EQ(arr, w.data());
|
||||
// ArrayView<char> v = z; // Compile error, because can't drop const.
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestCopyAssignment) {
|
||||
char arr[] = "Arrr!";
|
||||
ArrayView<char> x(arr);
|
||||
EXPECT_EQ(6u, x.size());
|
||||
EXPECT_EQ(arr, x.data());
|
||||
ArrayView<char> y;
|
||||
y = x; // Copy non-const -> non-const.
|
||||
EXPECT_EQ(6u, y.size());
|
||||
EXPECT_EQ(arr, y.data());
|
||||
ArrayView<const char> z;
|
||||
z = x; // Copy non-const -> const.
|
||||
EXPECT_EQ(6u, z.size());
|
||||
EXPECT_EQ(arr, z.data());
|
||||
ArrayView<const char> w;
|
||||
w = z; // Copy const -> const.
|
||||
EXPECT_EQ(6u, w.size());
|
||||
EXPECT_EQ(arr, w.data());
|
||||
// ArrayView<char> v;
|
||||
// v = z; // Compile error, because can't drop const.
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestStdVector) {
|
||||
std::vector<int> v;
|
||||
v.push_back(3);
|
||||
v.push_back(11);
|
||||
Call<const int>(v);
|
||||
Call<int>(v);
|
||||
// Call<unsigned int>(v); // Compile error, because incompatible types.
|
||||
ArrayView<int> x = v;
|
||||
EXPECT_EQ(2u, x.size());
|
||||
EXPECT_EQ(v.data(), x.data());
|
||||
ArrayView<const int> y;
|
||||
y = v;
|
||||
EXPECT_EQ(2u, y.size());
|
||||
EXPECT_EQ(v.data(), y.data());
|
||||
// ArrayView<double> d = v; // Compile error, because incompatible types.
|
||||
const std::vector<int> cv;
|
||||
Call<const int>(cv);
|
||||
// Call<int>(cv); // Compile error, because can't drop const.
|
||||
ArrayView<const int> z = cv;
|
||||
EXPECT_EQ(0u, z.size());
|
||||
EXPECT_EQ(nullptr, z.data());
|
||||
// ArrayView<int> w = cv; // Compile error, because can't drop const.
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestRtcBuffer) {
|
||||
rtc::Buffer b = "so buffer";
|
||||
Call<const uint8_t>(b);
|
||||
Call<uint8_t>(b);
|
||||
// Call<int8_t>(b); // Compile error, because incompatible types.
|
||||
ArrayView<uint8_t> x = b;
|
||||
EXPECT_EQ(10u, x.size());
|
||||
EXPECT_EQ(b.data(), x.data());
|
||||
ArrayView<const uint8_t> y;
|
||||
y = b;
|
||||
EXPECT_EQ(10u, y.size());
|
||||
EXPECT_EQ(b.data(), y.data());
|
||||
// ArrayView<char> d = b; // Compile error, because incompatible types.
|
||||
const rtc::Buffer cb = "very const";
|
||||
Call<const uint8_t>(cb);
|
||||
// Call<uint8_t>(cb); // Compile error, because can't drop const.
|
||||
ArrayView<const uint8_t> z = cb;
|
||||
EXPECT_EQ(11u, z.size());
|
||||
EXPECT_EQ(cb.data(), z.data());
|
||||
// ArrayView<uint8_t> w = cb; // Compile error, because can't drop const.
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestSwap) {
|
||||
const char arr[] = "Arrr!";
|
||||
const char aye[] = "Aye, Cap'n!";
|
||||
ArrayView<const char> x(arr);
|
||||
EXPECT_EQ(6u, x.size());
|
||||
EXPECT_EQ(arr, x.data());
|
||||
ArrayView<const char> y(aye);
|
||||
EXPECT_EQ(12u, y.size());
|
||||
EXPECT_EQ(aye, y.data());
|
||||
using std::swap;
|
||||
swap(x, y);
|
||||
EXPECT_EQ(12u, x.size());
|
||||
EXPECT_EQ(aye, x.data());
|
||||
EXPECT_EQ(6u, y.size());
|
||||
EXPECT_EQ(arr, y.data());
|
||||
// ArrayView<char> z;
|
||||
// swap(x, z); // Compile error, because can't drop const.
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestIndexing) {
|
||||
char arr[] = "abcdefg";
|
||||
ArrayView<char> x(arr);
|
||||
const ArrayView<char> y(arr);
|
||||
ArrayView<const char> z(arr);
|
||||
EXPECT_EQ(8u, x.size());
|
||||
EXPECT_EQ(8u, y.size());
|
||||
EXPECT_EQ(8u, z.size());
|
||||
EXPECT_EQ('b', x[1]);
|
||||
EXPECT_EQ('c', y[2]);
|
||||
EXPECT_EQ('d', z[3]);
|
||||
x[3] = 'X';
|
||||
y[2] = 'Y';
|
||||
// z[1] = 'Z'; // Compile error, because z's element type is const char.
|
||||
EXPECT_EQ('b', x[1]);
|
||||
EXPECT_EQ('Y', y[2]);
|
||||
EXPECT_EQ('X', z[3]);
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
EXPECT_DEATH(z[8], ""); // DCHECK error (index out of bounds).
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestIterationEmpty) {
|
||||
ArrayView<std::vector<std::vector<std::vector<std::string>>>> av;
|
||||
EXPECT_FALSE(av.begin());
|
||||
EXPECT_FALSE(av.cbegin());
|
||||
EXPECT_FALSE(av.end());
|
||||
EXPECT_FALSE(av.cend());
|
||||
for (auto& e : av) {
|
||||
EXPECT_TRUE(false);
|
||||
EXPECT_EQ(42u, e.size()); // Dummy use of e to prevent unused var warning.
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestIteration) {
|
||||
char arr[] = "Arrr!";
|
||||
ArrayView<char> av(arr);
|
||||
EXPECT_EQ('A', *av.begin());
|
||||
EXPECT_EQ('A', *av.cbegin());
|
||||
EXPECT_EQ('\0', *(av.end() - 1));
|
||||
EXPECT_EQ('\0', *(av.cend() - 1));
|
||||
char i = 0;
|
||||
for (auto& e : av) {
|
||||
EXPECT_EQ(arr + i, &e);
|
||||
e = 's' + i;
|
||||
++i;
|
||||
}
|
||||
i = 0;
|
||||
for (auto& e : ArrayView<const char>(av)) {
|
||||
EXPECT_EQ(arr + i, &e);
|
||||
// e = 'q' + i; // Compile error, because e is a const char&.
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestEmpty) {
|
||||
EXPECT_TRUE(ArrayView<int>().empty());
|
||||
const int a[] = {1, 2, 3};
|
||||
EXPECT_FALSE(ArrayView<const int>(a).empty());
|
||||
}
|
||||
|
||||
TEST(ArrayViewTest, TestCompare) {
|
||||
int a[] = {1, 2, 3};
|
||||
int b[] = {1, 2, 3};
|
||||
EXPECT_EQ(ArrayView<int>(a), ArrayView<int>(a));
|
||||
EXPECT_EQ(ArrayView<int>(), ArrayView<int>());
|
||||
EXPECT_NE(ArrayView<int>(a), ArrayView<int>(b));
|
||||
EXPECT_NE(ArrayView<int>(a), ArrayView<int>());
|
||||
EXPECT_NE(ArrayView<int>(a), ArrayView<int>(a, 2));
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
@ -24,16 +24,7 @@
|
|||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||
// its part, can't decide which to use (another mystery). Matching of
|
||||
// template overloads: the final frontier.
|
||||
#ifndef _MSC_VER
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
#endif
|
||||
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,116 +1,2 @@
|
|||
/*
|
||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/asynchttprequest.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
enum {
|
||||
MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
|
||||
MSG_LAUNCH_REQUEST
|
||||
};
|
||||
static const int kDefaultHTTPTimeout = 30 * 1000; // 30 sec
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AsyncHttpRequest
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
|
||||
: start_delay_(0),
|
||||
firewall_(NULL),
|
||||
port_(80),
|
||||
secure_(false),
|
||||
timeout_(kDefaultHTTPTimeout),
|
||||
fail_redirect_(false),
|
||||
factory_(Thread::Current()->socketserver(), user_agent),
|
||||
pool_(&factory_),
|
||||
client_(user_agent.c_str(), &pool_),
|
||||
error_(HE_NONE) {
|
||||
client_.SignalHttpClientComplete.connect(this,
|
||||
&AsyncHttpRequest::OnComplete);
|
||||
}
|
||||
|
||||
AsyncHttpRequest::~AsyncHttpRequest() {
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::OnWorkStart() {
|
||||
if (start_delay_ <= 0) {
|
||||
LaunchRequest();
|
||||
} else {
|
||||
Thread::Current()->PostDelayed(start_delay_, this, MSG_LAUNCH_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::OnWorkStop() {
|
||||
// worker is already quitting, no need to explicitly quit
|
||||
LOG(LS_INFO) << "HttpRequest cancelled";
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::OnComplete(HttpClient* client, HttpErrorType error) {
|
||||
Thread::Current()->Clear(this, MSG_TIMEOUT);
|
||||
|
||||
set_error(error);
|
||||
if (!error) {
|
||||
LOG(LS_INFO) << "HttpRequest completed successfully";
|
||||
|
||||
std::string value;
|
||||
if (client_.response().hasHeader(HH_LOCATION, &value)) {
|
||||
response_redirect_ = value.c_str();
|
||||
}
|
||||
} else {
|
||||
LOG(LS_INFO) << "HttpRequest completed with error: " << error;
|
||||
}
|
||||
|
||||
worker()->Quit();
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::OnMessage(Message* message) {
|
||||
switch (message->message_id) {
|
||||
case MSG_TIMEOUT:
|
||||
LOG(LS_INFO) << "HttpRequest timed out";
|
||||
client_.reset();
|
||||
worker()->Quit();
|
||||
break;
|
||||
case MSG_LAUNCH_REQUEST:
|
||||
LaunchRequest();
|
||||
break;
|
||||
default:
|
||||
SignalThread::OnMessage(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::DoWork() {
|
||||
// Do nothing while we wait for the request to finish. We only do this so
|
||||
// that we can be a SignalThread; in the future this class should not be
|
||||
// a SignalThread, since it does not need to spawn a new thread.
|
||||
Thread::Current()->ProcessMessages(Thread::kForever);
|
||||
}
|
||||
|
||||
void AsyncHttpRequest::LaunchRequest() {
|
||||
factory_.SetProxy(proxy_);
|
||||
if (secure_)
|
||||
factory_.UseSSL(host_.c_str());
|
||||
|
||||
bool transparent_proxy = (port_ == 80) &&
|
||||
((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
|
||||
if (transparent_proxy) {
|
||||
client_.set_proxy(proxy_);
|
||||
}
|
||||
client_.set_fail_redirect(fail_redirect_);
|
||||
client_.set_server(SocketAddress(host_, port_));
|
||||
|
||||
LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
|
||||
|
||||
Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
|
||||
client_.start();
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
// TODO(pthatcher): Remove this file once chromium's GYP file doesn't
|
||||
// refer to it.
|
||||
|
|
|
|||
|
|
@ -1,104 +1,2 @@
|
|||
/*
|
||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
||||
#define WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
||||
|
||||
#include <string>
|
||||
#include "webrtc/base/event.h"
|
||||
#include "webrtc/base/httpclient.h"
|
||||
#include "webrtc/base/signalthread.h"
|
||||
#include "webrtc/base/socketpool.h"
|
||||
#include "webrtc/base/sslsocketfactory.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class FirewallManager;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AsyncHttpRequest
|
||||
// Performs an HTTP request on a background thread. Notifies on the foreground
|
||||
// thread once the request is done (successfully or unsuccessfully).
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AsyncHttpRequest : public SignalThread {
|
||||
public:
|
||||
explicit AsyncHttpRequest(const std::string &user_agent);
|
||||
~AsyncHttpRequest() override;
|
||||
|
||||
// If start_delay is less than or equal to zero, this starts immediately.
|
||||
// Start_delay defaults to zero.
|
||||
int start_delay() const { return start_delay_; }
|
||||
void set_start_delay(int delay) { start_delay_ = delay; }
|
||||
|
||||
const ProxyInfo& proxy() const { return proxy_; }
|
||||
void set_proxy(const ProxyInfo& proxy) {
|
||||
proxy_ = proxy;
|
||||
}
|
||||
void set_firewall(FirewallManager * firewall) {
|
||||
firewall_ = firewall;
|
||||
}
|
||||
|
||||
// The DNS name of the host to connect to.
|
||||
const std::string& host() { return host_; }
|
||||
void set_host(const std::string& host) { host_ = host; }
|
||||
|
||||
// The port to connect to on the target host.
|
||||
int port() { return port_; }
|
||||
void set_port(int port) { port_ = port; }
|
||||
|
||||
// Whether the request should use SSL.
|
||||
bool secure() { return secure_; }
|
||||
void set_secure(bool secure) { secure_ = secure; }
|
||||
|
||||
// Time to wait on the download, in ms.
|
||||
int timeout() { return timeout_; }
|
||||
void set_timeout(int timeout) { timeout_ = timeout; }
|
||||
|
||||
// Fail redirects to allow analysis of redirect urls, etc.
|
||||
bool fail_redirect() const { return fail_redirect_; }
|
||||
void set_fail_redirect(bool redirect) { fail_redirect_ = redirect; }
|
||||
|
||||
// Returns the redirect when redirection occurs
|
||||
const std::string& response_redirect() { return response_redirect_; }
|
||||
|
||||
HttpRequestData& request() { return client_.request(); }
|
||||
HttpResponseData& response() { return client_.response(); }
|
||||
HttpErrorType error() { return error_; }
|
||||
|
||||
protected:
|
||||
void set_error(HttpErrorType error) { error_ = error; }
|
||||
void OnWorkStart() override;
|
||||
void OnWorkStop() override;
|
||||
void OnComplete(HttpClient* client, HttpErrorType error);
|
||||
void OnMessage(Message* message) override;
|
||||
void DoWork() override;
|
||||
|
||||
private:
|
||||
void LaunchRequest();
|
||||
|
||||
int start_delay_;
|
||||
ProxyInfo proxy_;
|
||||
FirewallManager* firewall_;
|
||||
std::string host_;
|
||||
int port_;
|
||||
bool secure_;
|
||||
int timeout_;
|
||||
bool fail_redirect_;
|
||||
SslSocketFactory factory_;
|
||||
ReuseSocketPool pool_;
|
||||
HttpClient client_;
|
||||
HttpErrorType error_;
|
||||
std::string response_redirect_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
||||
// TODO(pthatcher): Remove this file once chromium's GYP file doesn't
|
||||
// refer to it.
|
||||
|
|
|
|||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "webrtc/base/asynchttprequest.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/httpserver.h"
|
||||
#include "webrtc/base/socketstream.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
static const SocketAddress kServerAddr("127.0.0.1", 0);
|
||||
static const SocketAddress kServerHostnameAddr("localhost", 0);
|
||||
static const char kServerGetPath[] = "/get";
|
||||
static const char kServerPostPath[] = "/post";
|
||||
static const char kServerResponse[] = "This is a test";
|
||||
|
||||
class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
|
||||
public:
|
||||
TestHttpServer(Thread* thread, const SocketAddress& addr) :
|
||||
socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
|
||||
SOCK_STREAM)) {
|
||||
socket_->Bind(addr);
|
||||
socket_->Listen(5);
|
||||
socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
|
||||
}
|
||||
|
||||
SocketAddress address() const { return socket_->GetLocalAddress(); }
|
||||
void Close() const { socket_->Close(); }
|
||||
|
||||
private:
|
||||
void OnAccept(AsyncSocket* socket) {
|
||||
AsyncSocket* new_socket = socket_->Accept(NULL);
|
||||
if (new_socket) {
|
||||
HandleConnection(new SocketStream(new_socket));
|
||||
}
|
||||
}
|
||||
rtc::scoped_ptr<AsyncSocket> socket_;
|
||||
};
|
||||
|
||||
class AsyncHttpRequestTest : public testing::Test,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
AsyncHttpRequestTest()
|
||||
: started_(false),
|
||||
done_(false),
|
||||
server_(Thread::Current(), kServerAddr) {
|
||||
server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
|
||||
}
|
||||
|
||||
bool started() const { return started_; }
|
||||
bool done() const { return done_; }
|
||||
|
||||
AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
|
||||
const std::string& path) {
|
||||
rtc::AsyncHttpRequest* request =
|
||||
new rtc::AsyncHttpRequest("unittest");
|
||||
request->SignalWorkDone.connect(this,
|
||||
&AsyncHttpRequestTest::OnRequestDone);
|
||||
request->request().verb = rtc::HV_GET;
|
||||
request->set_host(host);
|
||||
request->set_port(port);
|
||||
request->request().path = path;
|
||||
request->response().document.reset(new MemoryStream());
|
||||
return request;
|
||||
}
|
||||
AsyncHttpRequest* CreatePostRequest(const std::string& host, int port,
|
||||
const std::string& path,
|
||||
const std::string content_type,
|
||||
StreamInterface* content) {
|
||||
rtc::AsyncHttpRequest* request =
|
||||
new rtc::AsyncHttpRequest("unittest");
|
||||
request->SignalWorkDone.connect(this,
|
||||
&AsyncHttpRequestTest::OnRequestDone);
|
||||
request->request().verb = rtc::HV_POST;
|
||||
request->set_host(host);
|
||||
request->set_port(port);
|
||||
request->request().path = path;
|
||||
request->request().setContent(content_type, content);
|
||||
request->response().document.reset(new MemoryStream());
|
||||
return request;
|
||||
}
|
||||
|
||||
const TestHttpServer& server() const { return server_; }
|
||||
|
||||
protected:
|
||||
void OnRequest(HttpServer* server, HttpServerTransaction* t) {
|
||||
started_ = true;
|
||||
|
||||
if (t->request.path == kServerGetPath) {
|
||||
t->response.set_success("text/plain", new MemoryStream(kServerResponse));
|
||||
} else if (t->request.path == kServerPostPath) {
|
||||
// reverse the data and reply
|
||||
size_t size;
|
||||
StreamInterface* in = t->request.document.get();
|
||||
StreamInterface* out = new MemoryStream();
|
||||
in->GetSize(&size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
char ch;
|
||||
in->SetPosition(size - i - 1);
|
||||
in->Read(&ch, 1, NULL, NULL);
|
||||
out->Write(&ch, 1, NULL, NULL);
|
||||
}
|
||||
out->Rewind();
|
||||
t->response.set_success("text/plain", out);
|
||||
} else {
|
||||
t->response.set_error(404);
|
||||
}
|
||||
server_.Respond(t);
|
||||
}
|
||||
void OnRequestDone(SignalThread* thread) {
|
||||
done_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool started_;
|
||||
bool done_;
|
||||
TestHttpServer server_;
|
||||
};
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
kServerHostnameAddr.hostname(), server().address().port(),
|
||||
kServerGetPath);
|
||||
EXPECT_FALSE(started());
|
||||
req->Start();
|
||||
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
|
||||
EXPECT_TRUE_WAIT(done(), 5000);
|
||||
std::string response;
|
||||
EXPECT_EQ(200U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->Rewind();
|
||||
req->response().document->ReadLine(&response);
|
||||
EXPECT_EQ(kServerResponse, response);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
kServerHostnameAddr.hostname(), server().address().port(),
|
||||
"/bad");
|
||||
req->Start();
|
||||
EXPECT_TRUE_WAIT(done(), 5000);
|
||||
size_t size;
|
||||
EXPECT_EQ(404U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->GetSize(&size);
|
||||
EXPECT_EQ(0U, size);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
"127.0.0.1", server().address().port(),
|
||||
kServerGetPath);
|
||||
// Stop the server before we send the request.
|
||||
server().Close();
|
||||
req->Start();
|
||||
EXPECT_TRUE_WAIT(done(), 10000);
|
||||
size_t size;
|
||||
EXPECT_EQ(500U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->GetSize(&size);
|
||||
EXPECT_EQ(0U, size);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
"invalid", server().address().port(),
|
||||
kServerGetPath);
|
||||
req->Start();
|
||||
EXPECT_TRUE_WAIT(done(), 5000);
|
||||
size_t size;
|
||||
EXPECT_EQ(500U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->GetSize(&size);
|
||||
EXPECT_EQ(0U, size);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
|
||||
AsyncHttpRequest* req = CreatePostRequest(
|
||||
kServerHostnameAddr.hostname(), server().address().port(),
|
||||
kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
|
||||
req->Start();
|
||||
EXPECT_TRUE_WAIT(done(), 5000);
|
||||
std::string response;
|
||||
EXPECT_EQ(200U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->Rewind();
|
||||
req->response().document->ReadLine(&response);
|
||||
EXPECT_EQ("4321dcba", response);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
// Ensure that we shut down properly even if work is outstanding.
|
||||
TEST_F(AsyncHttpRequestTest, TestCancel) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
kServerHostnameAddr.hostname(), server().address().port(),
|
||||
kServerGetPath);
|
||||
req->Start();
|
||||
req->Destroy(true);
|
||||
}
|
||||
|
||||
TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
|
||||
AsyncHttpRequest* req = CreateGetRequest(
|
||||
kServerHostnameAddr.hostname(), server().address().port(),
|
||||
kServerGetPath);
|
||||
req->set_start_delay(10); // Delay 10ms.
|
||||
req->Start();
|
||||
Thread::SleepMs(5);
|
||||
EXPECT_FALSE(started()); // Should not have started immediately.
|
||||
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
|
||||
EXPECT_TRUE_WAIT(done(), 5000);
|
||||
std::string response;
|
||||
EXPECT_EQ(200U, req->response().scode);
|
||||
ASSERT_TRUE(req->response().document);
|
||||
req->response().document->Rewind();
|
||||
req->response().document->ReadLine(&response);
|
||||
EXPECT_EQ(kServerResponse, response);
|
||||
req->Release();
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "webrtc/base/asyncinvoker.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
namespace rtc {
|
||||
|
|
@ -35,7 +36,7 @@ void AsyncInvoker::OnMessage(Message* msg) {
|
|||
closure->Execute();
|
||||
}
|
||||
|
||||
void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
|
||||
void AsyncInvoker::Flush(Thread* thread, uint32_t id /*= MQID_ANY*/) {
|
||||
if (destroying_) return;
|
||||
|
||||
// Run this on |thread| to reduce the number of context switches.
|
||||
|
|
@ -56,7 +57,7 @@ void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
|
|||
|
||||
void AsyncInvoker::DoInvoke(Thread* thread,
|
||||
const scoped_refptr<AsyncClosure>& closure,
|
||||
uint32 id) {
|
||||
uint32_t id) {
|
||||
if (destroying_) {
|
||||
LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
|
||||
return;
|
||||
|
|
@ -64,6 +65,41 @@ void AsyncInvoker::DoInvoke(Thread* thread,
|
|||
thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
|
||||
}
|
||||
|
||||
void AsyncInvoker::DoInvokeDelayed(Thread* thread,
|
||||
const scoped_refptr<AsyncClosure>& closure,
|
||||
uint32_t delay_ms,
|
||||
uint32_t id) {
|
||||
if (destroying_) {
|
||||
LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
|
||||
return;
|
||||
}
|
||||
thread->PostDelayed(delay_ms, this, id,
|
||||
new ScopedRefMessageData<AsyncClosure>(closure));
|
||||
}
|
||||
|
||||
GuardedAsyncInvoker::GuardedAsyncInvoker() : thread_(Thread::Current()) {
|
||||
thread_->SignalQueueDestroyed.connect(this,
|
||||
&GuardedAsyncInvoker::ThreadDestroyed);
|
||||
}
|
||||
|
||||
GuardedAsyncInvoker::~GuardedAsyncInvoker() {
|
||||
}
|
||||
|
||||
bool GuardedAsyncInvoker::Flush(uint32_t id) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
if (thread_ == nullptr)
|
||||
return false;
|
||||
invoker_.Flush(thread_, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuardedAsyncInvoker::ThreadDestroyed() {
|
||||
rtc::CritScope cs(&crit_);
|
||||
// We should never get more than one notification about the thread dying.
|
||||
RTC_DCHECK(thread_ != nullptr);
|
||||
thread_ = nullptr;
|
||||
}
|
||||
|
||||
NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(AsyncInvoker* invoker,
|
||||
Thread* calling_thread)
|
||||
: invoker_(invoker), calling_thread_(calling_thread) {
|
||||
|
|
|
|||
|
|
@ -74,21 +74,31 @@ class AsyncInvoker : public MessageHandler {
|
|||
// Call |functor| asynchronously on |thread|, with no callback upon
|
||||
// completion. Returns immediately.
|
||||
template <class ReturnT, class FunctorT>
|
||||
void AsyncInvoke(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
uint32 id = 0) {
|
||||
void AsyncInvoke(Thread* thread, const FunctorT& functor, uint32_t id = 0) {
|
||||
scoped_refptr<AsyncClosure> closure(
|
||||
new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor));
|
||||
DoInvoke(thread, closure, id);
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously on |thread| with |delay_ms|, with no callback
|
||||
// upon completion. Returns immediately.
|
||||
template <class ReturnT, class FunctorT>
|
||||
void AsyncInvokeDelayed(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
uint32_t delay_ms,
|
||||
uint32_t id = 0) {
|
||||
scoped_refptr<AsyncClosure> closure(
|
||||
new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor));
|
||||
DoInvokeDelayed(thread, closure, delay_ms, id);
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously on |thread|, calling |callback| when done.
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
void AsyncInvoke(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
void (HostT::*callback)(ReturnT),
|
||||
HostT* callback_host,
|
||||
uint32 id = 0) {
|
||||
uint32_t id = 0) {
|
||||
scoped_refptr<AsyncClosure> closure(
|
||||
new RefCountedObject<NotifyingAsyncClosure<ReturnT, FunctorT, HostT> >(
|
||||
this, Thread::Current(), functor, callback, callback_host));
|
||||
|
|
@ -102,7 +112,7 @@ class AsyncInvoker : public MessageHandler {
|
|||
const FunctorT& functor,
|
||||
void (HostT::*callback)(),
|
||||
HostT* callback_host,
|
||||
uint32 id = 0) {
|
||||
uint32_t id = 0) {
|
||||
scoped_refptr<AsyncClosure> closure(
|
||||
new RefCountedObject<NotifyingAsyncClosure<void, FunctorT, HostT> >(
|
||||
this, Thread::Current(), functor, callback, callback_host));
|
||||
|
|
@ -114,22 +124,106 @@ class AsyncInvoker : public MessageHandler {
|
|||
// before returning. Optionally filter by message id.
|
||||
// The destructor will not wait for outstanding calls, so if that
|
||||
// behavior is desired, call Flush() before destroying this object.
|
||||
void Flush(Thread* thread, uint32 id = MQID_ANY);
|
||||
void Flush(Thread* thread, uint32_t id = MQID_ANY);
|
||||
|
||||
// Signaled when this object is destructed.
|
||||
sigslot::signal0<> SignalInvokerDestroyed;
|
||||
|
||||
private:
|
||||
void OnMessage(Message* msg) override;
|
||||
void DoInvoke(Thread* thread, const scoped_refptr<AsyncClosure>& closure,
|
||||
uint32 id);
|
||||
|
||||
void DoInvoke(Thread* thread,
|
||||
const scoped_refptr<AsyncClosure>& closure,
|
||||
uint32_t id);
|
||||
void DoInvokeDelayed(Thread* thread,
|
||||
const scoped_refptr<AsyncClosure>& closure,
|
||||
uint32_t delay_ms,
|
||||
uint32_t id);
|
||||
bool destroying_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
|
||||
};
|
||||
|
||||
// Similar to AsyncInvoker, but guards against the Thread being destroyed while
|
||||
// there are outstanding dangling pointers to it. It will connect to the current
|
||||
// thread in the constructor, and will get notified when that thread is
|
||||
// destroyed. After GuardedAsyncInvoker is constructed, it can be used from
|
||||
// other threads to post functors to the thread it was constructed on. If that
|
||||
// thread dies, any further calls to AsyncInvoke() will be safely ignored.
|
||||
class GuardedAsyncInvoker : public sigslot::has_slots<> {
|
||||
public:
|
||||
GuardedAsyncInvoker();
|
||||
~GuardedAsyncInvoker() override;
|
||||
|
||||
// Synchronously execute all outstanding calls we own, and wait for calls to
|
||||
// complete before returning. Optionally filter by message id. The destructor
|
||||
// will not wait for outstanding calls, so if that behavior is desired, call
|
||||
// Flush() first. Returns false if the thread has died.
|
||||
bool Flush(uint32_t id = MQID_ANY);
|
||||
|
||||
// Call |functor| asynchronously with no callback upon completion. Returns
|
||||
// immediately. Returns false if the thread has died.
|
||||
template <class ReturnT, class FunctorT>
|
||||
bool AsyncInvoke(const FunctorT& functor, uint32_t id = 0) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
if (thread_ == nullptr)
|
||||
return false;
|
||||
invoker_.AsyncInvoke<ReturnT, FunctorT>(thread_, functor, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously with |delay_ms|, with no callback upon
|
||||
// completion. Returns immediately. Returns false if the thread has died.
|
||||
template <class ReturnT, class FunctorT>
|
||||
bool AsyncInvokeDelayed(const FunctorT& functor,
|
||||
uint32_t delay_ms,
|
||||
uint32_t id = 0) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
if (thread_ == nullptr)
|
||||
return false;
|
||||
invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(thread_, functor, delay_ms,
|
||||
id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously, calling |callback| when done. Returns false
|
||||
// if the thread has died.
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
bool AsyncInvoke(const FunctorT& functor,
|
||||
void (HostT::*callback)(ReturnT),
|
||||
HostT* callback_host,
|
||||
uint32_t id = 0) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
if (thread_ == nullptr)
|
||||
return false;
|
||||
invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(thread_, functor, callback,
|
||||
callback_host, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously calling |callback| when done. Overloaded for
|
||||
// void return. Returns false if the thread has died.
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
bool AsyncInvoke(const FunctorT& functor,
|
||||
void (HostT::*callback)(),
|
||||
HostT* callback_host,
|
||||
uint32_t id = 0) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
if (thread_ == nullptr)
|
||||
return false;
|
||||
invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(thread_, functor, callback,
|
||||
callback_host, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Callback when |thread_| is destroyed.
|
||||
void ThreadDestroyed();
|
||||
|
||||
CriticalSection crit_;
|
||||
Thread* thread_ GUARDED_BY(crit_);
|
||||
AsyncInvoker invoker_ GUARDED_BY(crit_);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
||||
#endif // WEBRTC_BASE_ASYNCINVOKER_H_
|
||||
|
|
|
|||
|
|
@ -28,16 +28,17 @@ struct PacketTimeUpdateParams {
|
|||
int rtp_sendtime_extension_id; // extension header id present in packet.
|
||||
std::vector<char> srtp_auth_key; // Authentication key.
|
||||
int srtp_auth_tag_len; // Authentication tag length.
|
||||
int64 srtp_packet_index; // Required for Rtp Packet authentication.
|
||||
int64_t srtp_packet_index; // Required for Rtp Packet authentication.
|
||||
};
|
||||
|
||||
// This structure holds meta information for the packet which is about to send
|
||||
// over network.
|
||||
struct PacketOptions {
|
||||
PacketOptions() : dscp(DSCP_NO_CHANGE) {}
|
||||
explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {}
|
||||
PacketOptions() : dscp(DSCP_NO_CHANGE), packet_id(-1) {}
|
||||
explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp), packet_id(-1) {}
|
||||
|
||||
DiffServCodePoint dscp;
|
||||
int packet_id; // 16 bits, -1 represents "not set".
|
||||
PacketTimeUpdateParams packet_time_params;
|
||||
};
|
||||
|
||||
|
|
@ -45,19 +46,19 @@ struct PacketOptions {
|
|||
// received by socket.
|
||||
struct PacketTime {
|
||||
PacketTime() : timestamp(-1), not_before(-1) {}
|
||||
PacketTime(int64 timestamp, int64 not_before)
|
||||
: timestamp(timestamp), not_before(not_before) {
|
||||
}
|
||||
PacketTime(int64_t timestamp, int64_t not_before)
|
||||
: timestamp(timestamp), not_before(not_before) {}
|
||||
|
||||
int64 timestamp; // Receive time after socket delivers the data.
|
||||
int64 not_before; // Earliest possible time the data could have arrived,
|
||||
// indicating the potential error in the |timestamp| value,
|
||||
// in case the system, is busy. For example, the time of
|
||||
// the last select() call.
|
||||
// If unknown, this value will be set to zero.
|
||||
int64_t timestamp; // Receive time after socket delivers the data.
|
||||
|
||||
// Earliest possible time the data could have arrived, indicating the
|
||||
// potential error in the |timestamp| value, in case the system, is busy. For
|
||||
// example, the time of the last select() call.
|
||||
// If unknown, this value will be set to zero.
|
||||
int64_t not_before;
|
||||
};
|
||||
|
||||
inline PacketTime CreatePacketTime(int64 not_before) {
|
||||
inline PacketTime CreatePacketTime(int64_t not_before) {
|
||||
return PacketTime(TimeMicros(), not_before);
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +110,9 @@ class AsyncPacketSocket : public sigslot::has_slots<> {
|
|||
const SocketAddress&,
|
||||
const PacketTime&> SignalReadPacket;
|
||||
|
||||
// Emitted each time a packet is sent.
|
||||
sigslot::signal2<AsyncPacketSocket*, const SentPacket&> SignalSentPacket;
|
||||
|
||||
// Emitted when the socket is currently able to send.
|
||||
sigslot::signal1<AsyncPacketSocket*> SignalReadyToSend;
|
||||
|
||||
|
|
@ -130,7 +134,7 @@ class AsyncPacketSocket : public sigslot::has_slots<> {
|
|||
sigslot::signal2<AsyncPacketSocket*, AsyncPacketSocket*> SignalNewConnection;
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncPacketSocket);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncPacketSocket);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ AsyncSocket::ConnState AsyncSocketAdapter::GetState() const {
|
|||
return socket_->GetState();
|
||||
}
|
||||
|
||||
int AsyncSocketAdapter::EstimateMTU(uint16* mtu) {
|
||||
int AsyncSocketAdapter::EstimateMTU(uint16_t* mtu) {
|
||||
return socket_->EstimateMTU(mtu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class AsyncSocketAdapter : public AsyncSocket, public sigslot::has_slots<> {
|
|||
int GetError() const override;
|
||||
void SetError(int error) override;
|
||||
ConnState GetState() const override;
|
||||
int EstimateMTU(uint16* mtu) override;
|
||||
int EstimateMTU(uint16_t* mtu) override;
|
||||
int GetOption(Option opt, int* value) override;
|
||||
int SetOption(Option opt, int value) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace rtc {
|
|||
|
||||
static const size_t kMaxPacketSize = 64 * 1024;
|
||||
|
||||
typedef uint16 PacketLength;
|
||||
typedef uint16_t PacketLength;
|
||||
static const size_t kPacketLenSize = sizeof(PacketLength);
|
||||
|
||||
static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
|
||||
|
|
@ -127,10 +127,11 @@ void AsyncTCPSocketBase::SetError(int error) {
|
|||
int AsyncTCPSocketBase::SendTo(const void *pv, size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) {
|
||||
if (addr == GetRemoteAddress())
|
||||
const SocketAddress& remote_address = GetRemoteAddress();
|
||||
if (addr == remote_address)
|
||||
return Send(pv, cb, options);
|
||||
|
||||
ASSERT(false);
|
||||
// Remote address may be empty if there is a sudden network change.
|
||||
ASSERT(remote_address.IsNil());
|
||||
socket_->SetError(ENOTCONN);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -267,6 +268,9 @@ int AsyncTCPSocket::Send(const void *pv, size_t cb,
|
|||
return res;
|
||||
}
|
||||
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::Time());
|
||||
SignalSentPacket(this, sent_packet);
|
||||
|
||||
// We claim to have sent the whole thing, even if we only sent partial
|
||||
return static_cast<int>(cb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class AsyncTCPSocketBase : public AsyncPacketSocket {
|
|||
char* inbuf_, * outbuf_;
|
||||
size_t insize_, inpos_, outsize_, outpos_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocketBase);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncTCPSocketBase);
|
||||
};
|
||||
|
||||
class AsyncTCPSocket : public AsyncTCPSocketBase {
|
||||
|
|
@ -95,7 +95,7 @@ class AsyncTCPSocket : public AsyncTCPSocketBase {
|
|||
void HandleIncomingConnection(AsyncSocket* socket) override;
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocket);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncTCPSocket);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
|||
|
|
@ -60,13 +60,19 @@ SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
|
|||
|
||||
int AsyncUDPSocket::Send(const void *pv, size_t cb,
|
||||
const rtc::PacketOptions& options) {
|
||||
return socket_->Send(pv, cb);
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::Time());
|
||||
int ret = socket_->Send(pv, cb);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::SendTo(const void *pv, size_t cb,
|
||||
const SocketAddress& addr,
|
||||
const rtc::PacketOptions& options) {
|
||||
return socket_->SendTo(pv, cb, addr);
|
||||
rtc::SentPacket sent_packet(options.packet_id, rtc::Time());
|
||||
int ret = socket_->SendTo(pv, cb, addr);
|
||||
SignalSentPacket(this, sent_packet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsyncUDPSocket::Close() {
|
||||
|
|
|
|||
|
|
@ -11,139 +11,77 @@
|
|||
#ifndef WEBRTC_BASE_ATOMICOPS_H_
|
||||
#define WEBRTC_BASE_ATOMICOPS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/basictypes.h"
|
||||
#include "webrtc/base/common.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#if defined(WEBRTC_WIN)
|
||||
// Include winsock2.h before including <windows.h> to maintain consistency with
|
||||
// win32.h. We can't include win32.h directly here since it pulls in
|
||||
// headers such as basictypes.h which causes problems in Chromium where webrtc
|
||||
// exists as two separate projects, webrtc and libjingle.
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif // defined(WEBRTC_WIN)
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// A single-producer, single-consumer, fixed-size queue.
|
||||
// All methods not ending in Unsafe can be safely called without locking,
|
||||
// provided that calls to consumer methods (Peek/Pop) or producer methods (Push)
|
||||
// only happen on a single thread per method type. If multiple threads need to
|
||||
// read simultaneously or write simultaneously, other synchronization is
|
||||
// necessary. Synchronization is also required if a call into any Unsafe method
|
||||
// could happen at the same time as a call to any other method.
|
||||
template <typename T>
|
||||
class FixedSizeLockFreeQueue {
|
||||
private:
|
||||
// Atomic primitives and memory barrier
|
||||
#if defined(__arm__)
|
||||
typedef uint32 Atomic32;
|
||||
|
||||
// Copied from google3/base/atomicops-internals-arm-v6plus.h
|
||||
static inline void MemoryBarrier() {
|
||||
asm volatile("dmb":::"memory");
|
||||
}
|
||||
|
||||
// Adapted from google3/base/atomicops-internals-arm-v6plus.h
|
||||
static inline void AtomicIncrement(volatile Atomic32* ptr) {
|
||||
Atomic32 str_success, value;
|
||||
asm volatile (
|
||||
"1:\n"
|
||||
"ldrex %1, [%2]\n"
|
||||
"add %1, %1, #1\n"
|
||||
"strex %0, %1, [%2]\n"
|
||||
"teq %0, #0\n"
|
||||
"bne 1b"
|
||||
: "=&r"(str_success), "=&r"(value)
|
||||
: "r" (ptr)
|
||||
: "cc", "memory");
|
||||
}
|
||||
#elif !defined(SKIP_ATOMIC_CHECK)
|
||||
#error "No atomic operations defined for the given architecture."
|
||||
#endif
|
||||
|
||||
class AtomicOps {
|
||||
public:
|
||||
// Constructs an empty queue, with capacity 0.
|
||||
FixedSizeLockFreeQueue() : pushed_count_(0),
|
||||
popped_count_(0),
|
||||
capacity_(0),
|
||||
data_() {}
|
||||
// Constructs an empty queue with the given capacity.
|
||||
FixedSizeLockFreeQueue(size_t capacity) : pushed_count_(0),
|
||||
popped_count_(0),
|
||||
capacity_(capacity),
|
||||
data_(new T[capacity]) {}
|
||||
|
||||
// Pushes a value onto the queue. Returns true if the value was successfully
|
||||
// pushed (there was space in the queue). This method can be safely called at
|
||||
// the same time as PeekFront/PopFront.
|
||||
bool PushBack(T value) {
|
||||
if (capacity_ == 0) {
|
||||
LOG(LS_WARNING) << "Queue capacity is 0.";
|
||||
return false;
|
||||
}
|
||||
if (IsFull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_[pushed_count_ % capacity_] = value;
|
||||
// Make sure the data is written before the count is incremented, so other
|
||||
// threads can't see the value exists before being able to read it.
|
||||
MemoryBarrier();
|
||||
AtomicIncrement(&pushed_count_);
|
||||
return true;
|
||||
#if defined(WEBRTC_WIN)
|
||||
// Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
|
||||
static int Increment(volatile int* i) {
|
||||
return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
|
||||
}
|
||||
|
||||
// Retrieves the oldest value pushed onto the queue. Returns true if there was
|
||||
// an item to peek (the queue was non-empty). This method can be safely called
|
||||
// at the same time as PushBack.
|
||||
bool PeekFront(T* value_out) {
|
||||
if (capacity_ == 0) {
|
||||
LOG(LS_WARNING) << "Queue capacity is 0.";
|
||||
return false;
|
||||
}
|
||||
if (IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*value_out = data_[popped_count_ % capacity_];
|
||||
return true;
|
||||
static int Decrement(volatile int* i) {
|
||||
return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
|
||||
}
|
||||
|
||||
// Retrieves the oldest value pushed onto the queue and removes it from the
|
||||
// queue. Returns true if there was an item to pop (the queue was non-empty).
|
||||
// This method can be safely called at the same time as PushBack.
|
||||
bool PopFront(T* value_out) {
|
||||
if (PeekFront(value_out)) {
|
||||
AtomicIncrement(&popped_count_);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
static int AcquireLoad(volatile const int* i) {
|
||||
return *i;
|
||||
}
|
||||
|
||||
// Clears the current items in the queue and sets the new (fixed) size. This
|
||||
// method cannot be called at the same time as any other method.
|
||||
void ClearAndResizeUnsafe(int new_capacity) {
|
||||
capacity_ = new_capacity;
|
||||
data_.reset(new T[new_capacity]);
|
||||
pushed_count_ = 0;
|
||||
popped_count_ = 0;
|
||||
static void ReleaseStore(volatile int* i, int value) {
|
||||
*i = value;
|
||||
}
|
||||
|
||||
// Returns true if there is no space left in the queue for new elements.
|
||||
int IsFull() const { return pushed_count_ == popped_count_ + capacity_; }
|
||||
// Returns true if there are no elements in the queue.
|
||||
int IsEmpty() const { return pushed_count_ == popped_count_; }
|
||||
// Returns the current number of elements in the queue. This is always in the
|
||||
// range [0, capacity]
|
||||
size_t Size() const { return pushed_count_ - popped_count_; }
|
||||
|
||||
// Returns the capacity of the queue (max size).
|
||||
size_t capacity() const { return capacity_; }
|
||||
|
||||
private:
|
||||
volatile Atomic32 pushed_count_;
|
||||
volatile Atomic32 popped_count_;
|
||||
size_t capacity_;
|
||||
rtc::scoped_ptr<T[]> data_;
|
||||
DISALLOW_COPY_AND_ASSIGN(FixedSizeLockFreeQueue);
|
||||
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
|
||||
return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
|
||||
new_value,
|
||||
old_value);
|
||||
}
|
||||
// Pointer variants.
|
||||
template <typename T>
|
||||
static T* AcquireLoadPtr(T* volatile* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
template <typename T>
|
||||
static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
|
||||
return static_cast<T*>(::InterlockedCompareExchangePointer(
|
||||
reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value));
|
||||
}
|
||||
#else
|
||||
static int Increment(volatile int* i) {
|
||||
return __sync_add_and_fetch(i, 1);
|
||||
}
|
||||
static int Decrement(volatile int* i) {
|
||||
return __sync_sub_and_fetch(i, 1);
|
||||
}
|
||||
static int AcquireLoad(volatile const int* i) {
|
||||
return __atomic_load_n(i, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
static void ReleaseStore(volatile int* i, int value) {
|
||||
__atomic_store_n(i, value, __ATOMIC_RELEASE);
|
||||
}
|
||||
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
|
||||
return __sync_val_compare_and_swap(i, old_value, new_value);
|
||||
}
|
||||
// Pointer variants.
|
||||
template <typename T>
|
||||
static T* AcquireLoadPtr(T* volatile* ptr) {
|
||||
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
template <typename T>
|
||||
static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
|
||||
return __sync_val_compare_and_swap(ptr, old_value, new_value);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBRTC_BASE_ATOMICOPS_H_
|
||||
|
|
|
|||
|
|
@ -8,72 +8,5 @@
|
|||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#if !defined(__arm__)
|
||||
// For testing purposes, define faked versions of the atomic operations
|
||||
#include "webrtc/base/basictypes.h"
|
||||
namespace rtc {
|
||||
typedef uint32 Atomic32;
|
||||
static inline void MemoryBarrier() { }
|
||||
static inline void AtomicIncrement(volatile Atomic32* ptr) {
|
||||
*ptr = *ptr + 1;
|
||||
}
|
||||
}
|
||||
#define SKIP_ATOMIC_CHECK
|
||||
#endif
|
||||
|
||||
#include "webrtc/base/atomicops.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/helpers.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
TEST(FixedSizeLockFreeQueueTest, TestDefaultConstruct) {
|
||||
rtc::FixedSizeLockFreeQueue<int> queue;
|
||||
EXPECT_EQ(0u, queue.capacity());
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
EXPECT_FALSE(queue.PushBack(1));
|
||||
int val;
|
||||
EXPECT_FALSE(queue.PopFront(&val));
|
||||
}
|
||||
|
||||
TEST(FixedSizeLockFreeQueueTest, TestConstruct) {
|
||||
rtc::FixedSizeLockFreeQueue<int> queue(5);
|
||||
EXPECT_EQ(5u, queue.capacity());
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
int val;
|
||||
EXPECT_FALSE(queue.PopFront(&val));
|
||||
}
|
||||
|
||||
TEST(FixedSizeLockFreeQueueTest, TestPushPop) {
|
||||
rtc::FixedSizeLockFreeQueue<int> queue(2);
|
||||
EXPECT_EQ(2u, queue.capacity());
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
EXPECT_TRUE(queue.PushBack(1));
|
||||
EXPECT_EQ(1u, queue.Size());
|
||||
EXPECT_TRUE(queue.PushBack(2));
|
||||
EXPECT_EQ(2u, queue.Size());
|
||||
EXPECT_FALSE(queue.PushBack(3));
|
||||
EXPECT_EQ(2u, queue.Size());
|
||||
int val;
|
||||
EXPECT_TRUE(queue.PopFront(&val));
|
||||
EXPECT_EQ(1, val);
|
||||
EXPECT_EQ(1u, queue.Size());
|
||||
EXPECT_TRUE(queue.PopFront(&val));
|
||||
EXPECT_EQ(2, val);
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
EXPECT_FALSE(queue.PopFront(&val));
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
}
|
||||
|
||||
TEST(FixedSizeLockFreeQueueTest, TestResize) {
|
||||
rtc::FixedSizeLockFreeQueue<int> queue(2);
|
||||
EXPECT_EQ(2u, queue.capacity());
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
EXPECT_TRUE(queue.PushBack(1));
|
||||
EXPECT_EQ(1u, queue.Size());
|
||||
|
||||
queue.ClearAndResizeUnsafe(5);
|
||||
EXPECT_EQ(5u, queue.capacity());
|
||||
EXPECT_EQ(0u, queue.Size());
|
||||
int val;
|
||||
EXPECT_FALSE(queue.PopFront(&val));
|
||||
}
|
||||
// TODO(pbos): Move AtomicOps tests to here from
|
||||
// webrtc/base/criticalsection_unittest.cc.
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ void AutoDetectProxy::OnMessage(Message *msg) {
|
|||
|
||||
IPAddress address_ip = proxy().address.ipaddr();
|
||||
|
||||
uint16 address_port = proxy().address.port();
|
||||
uint16_t address_port = proxy().address.port();
|
||||
|
||||
char autoconfig_url[kSavedStringLimit];
|
||||
SaveStringToStack(autoconfig_url,
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class AutoDetectProxy : public SignalThread {
|
|||
AsyncSocket* socket_;
|
||||
int next_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy);
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy);
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
|||
|
|
@ -12,14 +12,13 @@
|
|||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/httpcommon.h"
|
||||
#include "webrtc/base/httpcommon-inl.h"
|
||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
static const char kUserAgent[] = "";
|
||||
static const char kPath[] = "/";
|
||||
static const char kHost[] = "relay.google.com";
|
||||
static const uint16 kPort = 443;
|
||||
static const uint16_t kPort = 443;
|
||||
static const bool kSecure = true;
|
||||
// At most, AutoDetectProxy should take ~6 seconds. Each connect step is
|
||||
// allotted 2 seconds, with the initial resolution + connect given an
|
||||
|
|
@ -37,10 +36,10 @@ class AutoDetectProxyTest : public testing::Test, public sigslot::has_slots<> {
|
|||
AutoDetectProxyTest() : auto_detect_proxy_(NULL), done_(false) {}
|
||||
|
||||
protected:
|
||||
bool Create(const std::string &user_agent,
|
||||
const std::string &path,
|
||||
const std::string &host,
|
||||
uint16 port,
|
||||
bool Create(const std::string& user_agent,
|
||||
const std::string& path,
|
||||
const std::string& host,
|
||||
uint16_t port,
|
||||
bool secure,
|
||||
bool startnow) {
|
||||
auto_detect_proxy_ = new AutoDetectProxy(user_agent);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
namespace rtc {
|
||||
|
||||
BandwidthSmoother::BandwidthSmoother(int initial_bandwidth_guess,
|
||||
uint32 time_between_increase,
|
||||
uint32_t time_between_increase,
|
||||
double percent_increase,
|
||||
size_t samples_count_to_average,
|
||||
double min_sample_count_percent)
|
||||
|
|
@ -33,7 +33,7 @@ BandwidthSmoother::~BandwidthSmoother() = default;
|
|||
|
||||
// Samples a new bandwidth measurement
|
||||
// returns true if the bandwidth estimation changed
|
||||
bool BandwidthSmoother::Sample(uint32 sample_time, int bandwidth) {
|
||||
bool BandwidthSmoother::Sample(uint32_t sample_time, int bandwidth) {
|
||||
if (bandwidth < 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace rtc {
|
|||
class BandwidthSmoother {
|
||||
public:
|
||||
BandwidthSmoother(int initial_bandwidth_guess,
|
||||
uint32 time_between_increase,
|
||||
uint32_t time_between_increase,
|
||||
double percent_increase,
|
||||
size_t samples_count_to_average,
|
||||
double min_sample_count_percent);
|
||||
|
|
@ -40,16 +40,16 @@ class BandwidthSmoother {
|
|||
// Samples a new bandwidth measurement.
|
||||
// bandwidth is expected to be non-negative.
|
||||
// returns true if the bandwidth estimation changed
|
||||
bool Sample(uint32 sample_time, int bandwidth);
|
||||
bool Sample(uint32_t sample_time, int bandwidth);
|
||||
|
||||
int get_bandwidth_estimation() const {
|
||||
return bandwidth_estimation_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 time_between_increase_;
|
||||
uint32_t time_between_increase_;
|
||||
double percent_increase_;
|
||||
uint32 time_at_last_change_;
|
||||
uint32_t time_at_last_change_;
|
||||
int bandwidth_estimation_;
|
||||
RollingAccumulator<int> accumulator_;
|
||||
double min_sample_count_percent_;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,46 @@
|
|||
}],
|
||||
],
|
||||
}],
|
||||
# TODO(tkchin): Mac support. There are a bunch of problems right now because
|
||||
# of some settings pulled down from Chromium.
|
||||
['OS=="ios"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rtc_base_objc',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'rtc_base',
|
||||
],
|
||||
'sources': [
|
||||
'objc/NSString+StdString.h',
|
||||
'objc/NSString+StdString.mm',
|
||||
'objc/RTCDispatcher.h',
|
||||
'objc/RTCDispatcher.m',
|
||||
'objc/RTCLogging.h',
|
||||
'objc/RTCLogging.mm',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="ios"', {
|
||||
'sources': [
|
||||
'objc/RTCCameraPreviewView.h',
|
||||
'objc/RTCCameraPreviewView.m',
|
||||
],
|
||||
'all_dependent_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework AVFoundation',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
'xcode_settings': {
|
||||
'CLANG_ENABLE_OBJC_ARC': 'YES',
|
||||
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
|
||||
},
|
||||
}
|
||||
],
|
||||
}], # OS=="ios"
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
|
|
@ -29,31 +69,56 @@
|
|||
'target_name': 'rtc_base_approved',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'array_view.h',
|
||||
'atomicops.h',
|
||||
'bitbuffer.cc',
|
||||
'bitbuffer.h',
|
||||
'buffer.cc',
|
||||
'buffer.h',
|
||||
'bufferqueue.cc',
|
||||
'bufferqueue.h',
|
||||
'bytebuffer.cc',
|
||||
'bytebuffer.h',
|
||||
'byteorder.h',
|
||||
'checks.cc',
|
||||
'checks.h',
|
||||
'common.cc',
|
||||
'common.h',
|
||||
'constructormagic.h',
|
||||
'criticalsection.cc',
|
||||
'criticalsection.h',
|
||||
'deprecation.h',
|
||||
'event.cc',
|
||||
'event.h',
|
||||
'event_tracer.cc',
|
||||
'event_tracer.h',
|
||||
'exp_filter.cc',
|
||||
'exp_filter.h',
|
||||
'logging.cc',
|
||||
'logging.h',
|
||||
'md5.cc',
|
||||
'md5.h',
|
||||
'md5digest.cc',
|
||||
'md5digest.h',
|
||||
'optional.h',
|
||||
'platform_file.cc',
|
||||
'platform_file.h',
|
||||
'platform_thread.cc',
|
||||
'platform_thread.h',
|
||||
'platform_thread_types.h',
|
||||
'random.cc',
|
||||
'random.h',
|
||||
'ratetracker.cc',
|
||||
'ratetracker.h',
|
||||
'safe_conversions.h',
|
||||
'safe_conversions_impl.h',
|
||||
'scoped_ptr.h',
|
||||
'stringencode.cc',
|
||||
'stringencode.h',
|
||||
'stringutils.cc',
|
||||
'stringutils.h',
|
||||
'systeminfo.cc',
|
||||
'systeminfo.h',
|
||||
'template_util.h',
|
||||
'thread_annotations.h',
|
||||
'thread_checker.h',
|
||||
|
|
@ -64,6 +129,22 @@
|
|||
'trace_event.h',
|
||||
],
|
||||
'conditions': [
|
||||
['build_with_chromium==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/base/base.gyp:base',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../../webrtc_overrides',
|
||||
],
|
||||
'sources': [
|
||||
'../../webrtc_overrides/webrtc/base/logging.cc',
|
||||
'../../webrtc_overrides/webrtc/base/logging.h',
|
||||
],
|
||||
'sources!': [
|
||||
'logging.cc',
|
||||
'logging.h',
|
||||
],
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
'sources': [
|
||||
'macutils.cc',
|
||||
|
|
@ -82,19 +163,22 @@
|
|||
'target_name': 'rtc_base',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common.gyp:webrtc_common',
|
||||
'../common.gyp:webrtc_common',
|
||||
'rtc_base_approved',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'rtc_base_approved',
|
||||
],
|
||||
'defines': [
|
||||
'FEATURE_ENABLE_SSL',
|
||||
'SSL_USE_OPENSSL',
|
||||
'HAVE_OPENSSL_SSL_H',
|
||||
'LOGGING=1',
|
||||
],
|
||||
'sources': [
|
||||
'arraysize.h',
|
||||
'asyncfile.cc',
|
||||
'asyncfile.h',
|
||||
'asynchttprequest.cc',
|
||||
'asynchttprequest.h',
|
||||
'asyncinvoker.cc',
|
||||
'asyncinvoker.h',
|
||||
'asyncinvoker-inl.h',
|
||||
|
|
@ -108,33 +192,16 @@
|
|||
'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.cc',
|
||||
'buffer.h',
|
||||
'bytebuffer.cc',
|
||||
'bytebuffer.h',
|
||||
'byteorder.h',
|
||||
'callback.h',
|
||||
# 'callback.h.pump',
|
||||
'constructormagic.h',
|
||||
'common.cc',
|
||||
'common.h',
|
||||
'cpumonitor.cc',
|
||||
'cpumonitor.h',
|
||||
'crc32.cc',
|
||||
'crc32.h',
|
||||
'criticalsection.cc',
|
||||
'criticalsection.h',
|
||||
'cryptstring.cc',
|
||||
'cryptstring.h',
|
||||
'dbus.cc',
|
||||
|
|
@ -143,8 +210,8 @@
|
|||
'diskcache.h',
|
||||
'diskcache_win32.cc',
|
||||
'diskcache_win32.h',
|
||||
'filelock.cc',
|
||||
'filelock.h',
|
||||
'filerotatingstream.cc',
|
||||
'filerotatingstream.h',
|
||||
'fileutils.cc',
|
||||
'fileutils.h',
|
||||
'fileutils_mock.h',
|
||||
|
|
@ -169,15 +236,16 @@
|
|||
'httpserver.h',
|
||||
'ifaddrs-android.cc',
|
||||
'ifaddrs-android.h',
|
||||
'ifaddrs_converter.cc',
|
||||
'ifaddrs_converter.h',
|
||||
'macifaddrs_converter.cc',
|
||||
'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',
|
||||
|
|
@ -185,8 +253,8 @@
|
|||
'linuxfdwalk.c',
|
||||
'linuxfdwalk.h',
|
||||
'linked_ptr.h',
|
||||
'logging.cc',
|
||||
'logging.h',
|
||||
'logsinks.cc',
|
||||
'logsinks.h',
|
||||
'macasyncsocket.cc',
|
||||
'macasyncsocket.h',
|
||||
'maccocoasocketserver.h',
|
||||
|
|
@ -221,7 +289,18 @@
|
|||
'nethelpers.h',
|
||||
'network.cc',
|
||||
'network.h',
|
||||
'networkmonitor.cc',
|
||||
'networkmonitor.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',
|
||||
|
|
@ -240,16 +319,13 @@
|
|||
'proxyserver.h',
|
||||
'ratelimiter.cc',
|
||||
'ratelimiter.h',
|
||||
'ratetracker.cc',
|
||||
'ratetracker.h',
|
||||
'refcount.h',
|
||||
'referencecountedsingletonfactory.h',
|
||||
'rollingaccumulator.h',
|
||||
'schanneladapter.cc',
|
||||
'schanneladapter.h',
|
||||
'rtccertificate.cc',
|
||||
'rtccertificate.h',
|
||||
'scoped_autorelease_pool.h',
|
||||
'scoped_autorelease_pool.mm',
|
||||
'scoped_ptr.h',
|
||||
'scoped_ref_ptr.h',
|
||||
'scopedptrcollection.h',
|
||||
'sec_buffer.h',
|
||||
|
|
@ -293,8 +369,6 @@
|
|||
'sslstreamadapterhelper.h',
|
||||
'stream.cc',
|
||||
'stream.h',
|
||||
'systeminfo.cc',
|
||||
'systeminfo.h',
|
||||
'task.cc',
|
||||
'task.h',
|
||||
'taskparent.cc',
|
||||
|
|
@ -343,11 +417,6 @@
|
|||
'worker.h',
|
||||
'x11windowpicker.cc',
|
||||
'x11windowpicker.h',
|
||||
'../overrides/webrtc/base/basictypes.h',
|
||||
'../overrides/webrtc/base/constructormagic.h',
|
||||
'../overrides/webrtc/base/logging.cc',
|
||||
'../overrides/webrtc/base/logging.h',
|
||||
'../overrides/webrtc/base/win32socketinit.cc',
|
||||
],
|
||||
# TODO(henrike): issue 3307, make rtc_base build without disabling
|
||||
# these flags.
|
||||
|
|
@ -364,6 +433,8 @@
|
|||
],
|
||||
'defines': [
|
||||
'FEATURE_ENABLE_SSL',
|
||||
'SSL_USE_OPENSSL',
|
||||
'HAVE_OPENSSL_SSL_H',
|
||||
],
|
||||
},
|
||||
'include_dirs': [
|
||||
|
|
@ -373,39 +444,30 @@
|
|||
'conditions': [
|
||||
['build_with_chromium==1', {
|
||||
'include_dirs': [
|
||||
'../overrides',
|
||||
'../../webrtc_overrides',
|
||||
'../../boringssl/src/include',
|
||||
],
|
||||
'sources': [
|
||||
'../../webrtc_overrides/webrtc/base/win32socketinit.cc',
|
||||
],
|
||||
'sources!': [
|
||||
'asyncinvoker.cc',
|
||||
'asyncinvoker.h',
|
||||
'asyncinvoker-inl.h',
|
||||
'atomicops.h',
|
||||
'bandwidthsmoother.cc',
|
||||
'bandwidthsmoother.h',
|
||||
'basictypes.h',
|
||||
'bind.h',
|
||||
# 'bind.h.pump',
|
||||
'callback.h',
|
||||
# 'callback.h.pump',
|
||||
'constructormagic.h',
|
||||
'dbus.cc',
|
||||
'dbus.h',
|
||||
'diskcache_win32.cc',
|
||||
'diskcache_win32.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',
|
||||
|
|
@ -414,6 +476,8 @@
|
|||
'x11windowpicker.h',
|
||||
'logging.cc',
|
||||
'logging.h',
|
||||
'logsinks.cc',
|
||||
'logsinks.h',
|
||||
'macasyncsocket.cc',
|
||||
'macasyncsocket.h',
|
||||
'maccocoasocketserver.h',
|
||||
|
|
@ -495,92 +559,17 @@
|
|||
'WEBRTC_EXTERNAL_JSON',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'sources!': [
|
||||
'../overrides/webrtc/base/basictypes.h',
|
||||
'../overrides/webrtc/base/constructormagic.h',
|
||||
'../overrides/webrtc/base/win32socketinit.cc',
|
||||
'../overrides/webrtc/base/logging.cc',
|
||||
'../overrides/webrtc/base/logging.h',
|
||||
],
|
||||
}],
|
||||
['use_openssl==1', {
|
||||
'defines': [
|
||||
'SSL_USE_OPENSSL',
|
||||
'HAVE_OPENSSL_SSL_H',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'SSL_USE_OPENSSL',
|
||||
'HAVE_OPENSSL_SSL_H',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'openssl.h',
|
||||
'openssladapter.cc',
|
||||
'openssladapter.h',
|
||||
'openssldigest.cc',
|
||||
'openssldigest.h',
|
||||
'opensslidentity.cc',
|
||||
'opensslidentity.h',
|
||||
'opensslstreamadapter.cc',
|
||||
'opensslstreamadapter.h',
|
||||
],
|
||||
'conditions': [
|
||||
['build_ssl==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/third_party/boringssl/boringssl.gyp:boringssl',
|
||||
],
|
||||
}, {
|
||||
'include_dirs': [
|
||||
'<(ssl_root)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, {
|
||||
'sources': [
|
||||
'nssidentity.cc',
|
||||
'nssidentity.h',
|
||||
'nssstreamadapter.cc',
|
||||
'nssstreamadapter.h',
|
||||
],
|
||||
'conditions': [
|
||||
['use_legacy_ssl_defaults!=1', {
|
||||
'defines': [
|
||||
'SSL_USE_NSS',
|
||||
'HAVE_NSS_SSL_H',
|
||||
'SSL_USE_NSS_RNG',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'SSL_USE_NSS',
|
||||
'HAVE_NSS_SSL_H',
|
||||
'SSL_USE_NSS_RNG',
|
||||
],
|
||||
['OS=="win" and clang==1', {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'AdditionalOptions': [
|
||||
# Disable warnings failing when compiling with Clang on Windows.
|
||||
# https://bugs.chromium.org/p/webrtc/issues/detail?id=5366
|
||||
'-Wno-missing-braces',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
['build_ssl==1', {
|
||||
'conditions': [
|
||||
# On some platforms, the rest of NSS is bundled. On others,
|
||||
# it's pulled from the system.
|
||||
['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',
|
||||
],
|
||||
}],
|
||||
['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/build/linux/system.gyp:ssl',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, {
|
||||
'include_dirs': [
|
||||
'<(ssl_root)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
['OS == "android"', {
|
||||
|
|
@ -597,9 +586,13 @@
|
|||
],
|
||||
}],
|
||||
['OS=="ios"', {
|
||||
'sources/': [
|
||||
['include', 'macconversion.*'],
|
||||
],
|
||||
'all_dependent_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework CFNetwork',
|
||||
'-framework Foundation',
|
||||
'-framework Security',
|
||||
'-framework SystemConfiguration',
|
||||
|
|
@ -685,6 +678,9 @@
|
|||
],
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'sources!': [
|
||||
'ifaddrs_converter.cc',
|
||||
],
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lcrypt32.lib',
|
||||
|
|
@ -702,8 +698,6 @@
|
|||
['exclude', 'win32[a-z0-9]*\\.(h|cc)$'],
|
||||
],
|
||||
'sources!': [
|
||||
'schanneladapter.cc',
|
||||
'schanneladapter.h',
|
||||
'winping.cc',
|
||||
'winping.h',
|
||||
'winfirewall.cc',
|
||||
|
|
@ -738,6 +732,7 @@
|
|||
}],
|
||||
['OS!="ios" and OS!="mac"', {
|
||||
'sources!': [
|
||||
'macifaddrs_converter.cc',
|
||||
'scoped_autorelease_pool.mm',
|
||||
],
|
||||
}],
|
||||
|
|
@ -747,6 +742,15 @@
|
|||
'linux.h',
|
||||
],
|
||||
}],
|
||||
['build_ssl==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/third_party/boringssl/boringssl.gyp:boringssl',
|
||||
],
|
||||
}, {
|
||||
'include_dirs': [
|
||||
'<(ssl_root)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
'unittest_main.cc',
|
||||
# Also use this as a convenient dumping ground for misc files that are
|
||||
# included by multiple targets below.
|
||||
'fakecpumonitor.h',
|
||||
'fakenetwork.h',
|
||||
'fakesslidentity.h',
|
||||
'faketaskrunner.h',
|
||||
|
|
@ -23,7 +22,6 @@
|
|||
'testbase64.h',
|
||||
'testechoserver.h',
|
||||
'testutils.h',
|
||||
'win32toolhelp.h',
|
||||
],
|
||||
'defines': [
|
||||
'GTEST_RELATIVE_PATH',
|
||||
|
|
@ -31,6 +29,7 @@
|
|||
'dependencies': [
|
||||
'base.gyp:rtc_base',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/test/test.gyp:field_trial',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
|
|
@ -46,24 +45,25 @@
|
|||
'type': 'none',
|
||||
'direct_dependent_settings': {
|
||||
'sources': [
|
||||
'asynchttprequest_unittest.cc',
|
||||
'array_view_unittest.cc',
|
||||
'atomicops_unittest.cc',
|
||||
'autodetectproxy_unittest.cc',
|
||||
'bandwidthsmoother_unittest.cc',
|
||||
'base64_unittest.cc',
|
||||
'basictypes_unittest.cc',
|
||||
'bind_unittest.cc',
|
||||
'bitbuffer_unittest.cc',
|
||||
'buffer_unittest.cc',
|
||||
'bufferqueue_unittest.cc',
|
||||
'bytebuffer_unittest.cc',
|
||||
'byteorder_unittest.cc',
|
||||
'callback_unittest.cc',
|
||||
'cpumonitor_unittest.cc',
|
||||
'crc32_unittest.cc',
|
||||
'criticalsection_unittest.cc',
|
||||
'event_tracer_unittest.cc',
|
||||
'event_unittest.cc',
|
||||
'exp_filter_unittest.cc',
|
||||
'filelock_unittest.cc',
|
||||
'filerotatingstream_unittest.cc',
|
||||
'fileutils_unittest.cc',
|
||||
'helpers_unittest.cc',
|
||||
'httpbase_unittest.cc',
|
||||
|
|
@ -77,17 +77,19 @@
|
|||
'multipart_unittest.cc',
|
||||
'nat_unittest.cc',
|
||||
'network_unittest.cc',
|
||||
'nullsocketserver_unittest.cc',
|
||||
'optional_unittest.cc',
|
||||
'optionsfile_unittest.cc',
|
||||
'pathutils_unittest.cc',
|
||||
'physicalsocketserver_unittest.cc',
|
||||
'platform_thread_unittest.cc',
|
||||
'profiler_unittest.cc',
|
||||
'proxy_unittest.cc',
|
||||
'proxydetect_unittest.cc',
|
||||
'random_unittest.cc',
|
||||
'ratelimiter_unittest.cc',
|
||||
'ratetracker_unittest.cc',
|
||||
'referencecountedsingletonfactory_unittest.cc',
|
||||
'rollingaccumulator_unittest.cc',
|
||||
'rtccertificate_unittests.cc',
|
||||
'scopedptrcollection_unittest.cc',
|
||||
'sha1digest_unittest.cc',
|
||||
'sharedexclusivelock_unittest.cc',
|
||||
|
|
@ -95,9 +97,6 @@
|
|||
'sigslot_unittest.cc',
|
||||
'sigslottester.h',
|
||||
'sigslottester.h.pump',
|
||||
'socket_unittest.cc',
|
||||
'socket_unittest.h',
|
||||
'socketaddress_unittest.cc',
|
||||
'stream_unittest.cc',
|
||||
'stringencode_unittest.cc',
|
||||
'stringutils_unittest.cc',
|
||||
|
|
@ -110,7 +109,6 @@
|
|||
'timeutils_unittest.cc',
|
||||
'urlencode_unittest.cc',
|
||||
'versionparsing_unittest.cc',
|
||||
'virtualsocket_unittest.cc',
|
||||
# TODO(ronghuawu): Reenable this test.
|
||||
# 'windowpicker_unittest.cc',
|
||||
],
|
||||
|
|
@ -127,24 +125,29 @@
|
|||
'sources': [
|
||||
'win32_unittest.cc',
|
||||
'win32regkey_unittest.cc',
|
||||
'win32socketserver_unittest.cc',
|
||||
'win32toolhelp_unittest.cc',
|
||||
'win32window_unittest.cc',
|
||||
'win32windowpicker_unittest.cc',
|
||||
'winfirewall_unittest.cc',
|
||||
],
|
||||
'sources!': [
|
||||
# TODO(ronghuawu): Fix TestUdpReadyToSendIPv6 on windows bot
|
||||
# then reenable these tests.
|
||||
'physicalsocketserver_unittest.cc',
|
||||
'socket_unittest.cc',
|
||||
'win32socketserver_unittest.cc',
|
||||
# TODO(pbos): Reenable this test.
|
||||
'win32windowpicker_unittest.cc',
|
||||
],
|
||||
}],
|
||||
['OS=="win" and clang==1', {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'AdditionalOptions': [
|
||||
# Disable warnings failing when compiling with Clang on Windows.
|
||||
# https://bugs.chromium.org/p/webrtc/issues/detail?id=5366
|
||||
'-Wno-missing-braces',
|
||||
'-Wno-unused-const-variable',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
'sources': [
|
||||
'macsocketserver_unittest.cc',
|
||||
'macutils_unittest.cc',
|
||||
],
|
||||
}],
|
||||
|
|
|
|||
|
|
@ -12,97 +12,41 @@
|
|||
#define WEBRTC_BASE_BASICTYPES_H_
|
||||
|
||||
#include <stddef.h> // for NULL, size_t
|
||||
|
||||
#if !(defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
#include <stdint.h> // for uintptr_t
|
||||
#endif
|
||||
#include <stdint.h> // for uintptr_t and (u)int_t types.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h" // NOLINT
|
||||
#endif
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
|
||||
#if !defined(INT_TYPES_DEFINED)
|
||||
#define INT_TYPES_DEFINED
|
||||
#ifdef COMPILER_MSVC
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef __int64 int64;
|
||||
#ifndef INT64_C
|
||||
#define INT64_C(x) x ## I64
|
||||
#endif
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(x) x ## UI64
|
||||
#endif
|
||||
#define INT64_F "I64"
|
||||
#else // COMPILER_MSVC
|
||||
// On Mac OS X, cssmconfig.h defines uint64 as uint64_t
|
||||
// TODO(fbarchard): Use long long for compatibility with chromium on BSD/OSX.
|
||||
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
||||
typedef uint64_t uint64;
|
||||
typedef int64_t int64;
|
||||
#ifndef INT64_C
|
||||
#define INT64_C(x) x ## LL
|
||||
#endif
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(x) x ## ULL
|
||||
#endif
|
||||
#define INT64_F "l"
|
||||
#elif defined(__LP64__)
|
||||
typedef unsigned long uint64; // NOLINT
|
||||
typedef long int64; // NOLINT
|
||||
#ifndef INT64_C
|
||||
#define INT64_C(x) x ## L
|
||||
#endif
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(x) x ## UL
|
||||
#endif
|
||||
#define INT64_F "l"
|
||||
#else // __LP64__
|
||||
typedef unsigned long long uint64; // NOLINT
|
||||
typedef long long int64; // NOLINT
|
||||
#ifndef INT64_C
|
||||
#define INT64_C(x) x ## LL
|
||||
#endif
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(x) x ## ULL
|
||||
#endif
|
||||
#define INT64_F "ll"
|
||||
#endif // __LP64__
|
||||
#endif // COMPILER_MSVC
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
typedef unsigned short uint16; // NOLINT
|
||||
typedef short int16; // NOLINT
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char int8;
|
||||
#endif // INT_TYPES_DEFINED
|
||||
|
||||
// Detect compiler is for x86 or x64.
|
||||
#if defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(__i386__) || defined(_M_IX86)
|
||||
#define CPU_X86 1
|
||||
#endif
|
||||
|
||||
// Detect compiler is for arm.
|
||||
#if defined(__arm__) || defined(_M_ARM)
|
||||
#define CPU_ARM 1
|
||||
#endif
|
||||
|
||||
#if defined(CPU_X86) && defined(CPU_ARM)
|
||||
#error CPU_X86 and CPU_ARM both defined.
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||
|
||||
#if !defined(RTC_ARCH_CPU_BIG_ENDIAN) && !defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
|
||||
// x86, arm or GCC provided __BYTE_ORDER__ macros
|
||||
#if CPU_X86 || CPU_ARM || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define ARCH_CPU_LITTLE_ENDIAN
|
||||
#define RTC_ARCH_CPU_LITTLE_ENDIAN
|
||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define ARCH_CPU_BIG_ENDIAN
|
||||
#define RTC_ARCH_CPU_BIG_ENDIAN
|
||||
#else
|
||||
#error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined.
|
||||
#error RTC_ARCH_CPU_BIG_ENDIAN or RTC_ARCH_CPU_LITTLE_ENDIAN should be defined.
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||
#error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined.
|
||||
|
||||
#if defined(RTC_ARCH_CPU_BIG_ENDIAN) && defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
|
||||
#error RTC_ARCH_CPU_BIG_ENDIAN and RTC_ARCH_CPU_LITTLE_ENDIAN both defined.
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
|
|
@ -111,15 +55,20 @@ typedef int socklen_t;
|
|||
|
||||
// The following only works for C++
|
||||
#ifdef __cplusplus
|
||||
#define ALIGNP(p, t) \
|
||||
(reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
|
||||
((t) - 1)) & ~((t) - 1))))
|
||||
|
||||
#ifndef ALIGNP
|
||||
#define ALIGNP(p, t) \
|
||||
(reinterpret_cast<uint8_t*>(((reinterpret_cast<uintptr_t>(p) + \
|
||||
((t) - 1)) & ~((t) - 1))))
|
||||
#endif
|
||||
|
||||
#define RTC_IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
|
||||
|
||||
// Use these to declare and define a static local variable (static T;) so that
|
||||
// it is leaked so that its destructors are not called at exit.
|
||||
#define LIBJINGLE_DEFINE_STATIC_LOCAL(type, name, arguments) \
|
||||
// Use these to declare and define a static local variable that gets leaked so
|
||||
// that its destructors are not called at exit.
|
||||
#define RTC_DEFINE_STATIC_LOCAL(type, name, arguments) \
|
||||
static type& name = *new type arguments
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // WEBRTC_BASE_BASICTYPES_H_
|
||||
|
|
|
|||
|
|
@ -15,42 +15,15 @@
|
|||
namespace rtc {
|
||||
|
||||
TEST(BasicTypesTest, Endian) {
|
||||
uint16 v16 = 0x1234u;
|
||||
uint8 first_byte = *reinterpret_cast<uint8*>(&v16);
|
||||
#if defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||
uint16_t v16 = 0x1234u;
|
||||
uint8_t first_byte = *reinterpret_cast<uint8_t*>(&v16);
|
||||
#if defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
|
||||
EXPECT_EQ(0x34u, first_byte);
|
||||
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
||||
#elif defined(RTC_ARCH_CPU_BIG_ENDIAN)
|
||||
EXPECT_EQ(0x12u, first_byte);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(BasicTypesTest, SizeOfTypes) {
|
||||
int8 i8 = -1;
|
||||
uint8 u8 = 1u;
|
||||
int16 i16 = -1;
|
||||
uint16 u16 = 1u;
|
||||
int32 i32 = -1;
|
||||
uint32 u32 = 1u;
|
||||
int64 i64 = -1;
|
||||
uint64 u64 = 1u;
|
||||
EXPECT_EQ(1u, sizeof(i8));
|
||||
EXPECT_EQ(1u, sizeof(u8));
|
||||
EXPECT_EQ(2u, sizeof(i16));
|
||||
EXPECT_EQ(2u, sizeof(u16));
|
||||
EXPECT_EQ(4u, sizeof(i32));
|
||||
EXPECT_EQ(4u, sizeof(u32));
|
||||
EXPECT_EQ(8u, sizeof(i64));
|
||||
EXPECT_EQ(8u, sizeof(u64));
|
||||
EXPECT_GT(0, i8);
|
||||
EXPECT_LT(0u, u8);
|
||||
EXPECT_GT(0, i16);
|
||||
EXPECT_LT(0u, u16);
|
||||
EXPECT_GT(0, i32);
|
||||
EXPECT_LT(0u, u32);
|
||||
EXPECT_GT(0, i64);
|
||||
EXPECT_LT(0u, u64);
|
||||
}
|
||||
|
||||
TEST(BasicTypesTest, SizeOfConstants) {
|
||||
EXPECT_EQ(8u, sizeof(INT64_C(0)));
|
||||
EXPECT_EQ(8u, sizeof(UINT64_C(0)));
|
||||
|
|
@ -65,9 +38,9 @@ TEST(BasicTypesTest, SizeOfConstants) {
|
|||
#if !defined(CPU_X86) && (defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS))
|
||||
#error expected CPU_X86 to be defined.
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_LITTLE_ENDIAN) && \
|
||||
#if !defined(RTC_ARCH_CPU_LITTLE_ENDIAN) && \
|
||||
(defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) || defined(CPU_X86))
|
||||
#error expected ARCH_CPU_LITTLE_ENDIAN to be defined.
|
||||
#error expected RTC_ARCH_CPU_LITTLE_ENDIAN to be defined.
|
||||
#endif
|
||||
|
||||
// TODO(fbarchard): Test all macros in basictypes.h
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,12 +12,13 @@
|
|||
// /home/build/google3/third_party/gtest/scripts/pump.py bind.h.pump
|
||||
|
||||
// Bind() is an overloaded function that converts method calls into function
|
||||
// objects (aka functors). It captures any arguments to the method by value
|
||||
// when Bind is called, producing a stateful, nullary function object. Care
|
||||
// should be taken about the lifetime of objects captured by Bind(); the
|
||||
// returned functor knows nothing about the lifetime of the method's object or
|
||||
// any arguments passed by pointer, and calling the functor with a destroyed
|
||||
// object will surely do bad things.
|
||||
// objects (aka functors). The method object is captured as a scoped_refptr<> if
|
||||
// possible, and as a raw pointer otherwise. Any arguments to the method are
|
||||
// captured by value. The return value of Bind is a stateful, nullary function
|
||||
// object. Care should be taken about the lifetime of objects captured by
|
||||
// Bind(); the returned functor knows nothing about the lifetime of a non
|
||||
// ref-counted method object or any arguments passed by pointer, and calling the
|
||||
// functor with a destroyed object will surely do bad things.
|
||||
//
|
||||
// Example usage:
|
||||
// struct Foo {
|
||||
|
|
@ -34,10 +35,34 @@
|
|||
// cout << rtc::Bind(&Foo::Test3, &foo, 3)() << endl;
|
||||
// cout << rtc::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl;
|
||||
// }
|
||||
//
|
||||
// Example usage of ref counted objects:
|
||||
// struct Bar {
|
||||
// int AddRef();
|
||||
// int Release();
|
||||
//
|
||||
// void Test() {}
|
||||
// void BindThis() {
|
||||
// // The functor passed to AsyncInvoke() will keep this object alive.
|
||||
// invoker.AsyncInvoke(rtc::Bind(&Bar::Test, this));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// int main() {
|
||||
// rtc::scoped_refptr<Bar> bar = new rtc::RefCountedObject<Bar>();
|
||||
// auto functor = rtc::Bind(&Bar::Test, bar);
|
||||
// bar = nullptr;
|
||||
// // The functor stores an internal scoped_refptr<Bar>, so this is safe.
|
||||
// functor();
|
||||
// }
|
||||
//
|
||||
|
||||
#ifndef WEBRTC_BASE_BIND_H_
|
||||
#define WEBRTC_BASE_BIND_H_
|
||||
|
||||
#include "webrtc/base/scoped_ref_ptr.h"
|
||||
#include "webrtc/base/template_util.h"
|
||||
|
||||
#define NONAME
|
||||
|
||||
namespace rtc {
|
||||
|
|
@ -49,9 +74,60 @@ namespace detail {
|
|||
// references stripped. This trick allows the compiler to dictate the Bind
|
||||
// parameter types rather than deduce them.
|
||||
template <class T> struct identity { typedef T type; };
|
||||
|
||||
// IsRefCounted<T>::value will be true for types that can be used in
|
||||
// rtc::scoped_refptr<T>, i.e. types that implements nullary functions AddRef()
|
||||
// and Release(), regardless of their return types. AddRef() and Release() can
|
||||
// be defined in T or any superclass of T.
|
||||
template <typename T>
|
||||
class IsRefCounted {
|
||||
// This is a complex implementation detail done with SFINAE.
|
||||
|
||||
// Define types such that sizeof(Yes) != sizeof(No).
|
||||
struct Yes { char dummy[1]; };
|
||||
struct No { char dummy[2]; };
|
||||
// Define two overloaded template functions with return types of different
|
||||
// size. This way, we can use sizeof() on the return type to determine which
|
||||
// function the compiler would have chosen. One function will be preferred
|
||||
// over the other if it is possible to create it without compiler errors,
|
||||
// otherwise the compiler will simply remove it, and default to the less
|
||||
// preferred function.
|
||||
template <typename R>
|
||||
static Yes test(R* r, decltype(r->AddRef(), r->Release(), 42));
|
||||
template <typename C> static No test(...);
|
||||
|
||||
public:
|
||||
// Trick the compiler to tell if it's possible to call AddRef() and Release().
|
||||
static const bool value = sizeof(test<T>((T*)nullptr, 42)) == sizeof(Yes);
|
||||
};
|
||||
|
||||
// TernaryTypeOperator is a helper class to select a type based on a static bool
|
||||
// value.
|
||||
template <bool condition, typename IfTrueT, typename IfFalseT>
|
||||
struct TernaryTypeOperator {};
|
||||
|
||||
template <typename IfTrueT, typename IfFalseT>
|
||||
struct TernaryTypeOperator<true, IfTrueT, IfFalseT> {
|
||||
typedef IfTrueT type;
|
||||
};
|
||||
|
||||
template <typename IfTrueT, typename IfFalseT>
|
||||
struct TernaryTypeOperator<false, IfTrueT, IfFalseT> {
|
||||
typedef IfFalseT type;
|
||||
};
|
||||
|
||||
// PointerType<T>::type will be scoped_refptr<T> for ref counted types, and T*
|
||||
// otherwise.
|
||||
template <class T>
|
||||
struct PointerType {
|
||||
typedef typename TernaryTypeOperator<IsRefCounted<T>::value,
|
||||
scoped_refptr<T>,
|
||||
T*>::type type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
$var n = 5
|
||||
$var n = 9
|
||||
$range i 0..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
|
@ -68,9 +144,9 @@ class MethodFunctor$i {
|
|||
return (object_->*method_)($for j , [[p$(j)_]]); }
|
||||
private:
|
||||
MethodT method_;
|
||||
ObjectT* object_;$for j [[
|
||||
typename detail::PointerType<ObjectT>::type object_;$for j [[
|
||||
|
||||
P$j p$(j)_;]]
|
||||
typename rtc::remove_reference<P$j>::type p$(j)_;]]
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -87,7 +163,7 @@ Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
|
|||
private:
|
||||
FunctorT functor_;$for j [[
|
||||
|
||||
P$j p$(j)_;]]
|
||||
typename rtc::remove_reference<P$j>::type p$(j)_;]]
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -115,6 +191,18 @@ Bind(FP_T(method), const ObjectT* object$for j [[,
|
|||
method, object$for j [[, p$j]]);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
|
||||
|
||||
template <class ObjectT, class R$for j [[,
|
||||
class P$j]]>
|
||||
MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
|
||||
Bind(FP_T(method), const scoped_refptr<ObjectT>& object$for j [[,
|
||||
typename detail::identity<P$j>::type p$j]]) {
|
||||
return MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
|
||||
method, object.get()$for j [[, p$j]]);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)($for j , [[P$j]])
|
||||
|
||||
|
|
|
|||
|
|
@ -11,27 +11,111 @@
|
|||
#include "webrtc/base/bind.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
|
||||
#include "webrtc/base/refcount.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
namespace {
|
||||
|
||||
struct LifeTimeCheck;
|
||||
|
||||
struct MethodBindTester {
|
||||
void NullaryVoid() { ++call_count; }
|
||||
int NullaryInt() { ++call_count; return 1; }
|
||||
int NullaryConst() const { ++call_count; return 2; }
|
||||
void UnaryVoid(int dummy) { ++call_count; }
|
||||
template <class T> T Identity(T value) { ++call_count; return value; }
|
||||
int UnaryByRef(int& value) const { ++call_count; return ++value; } // NOLINT
|
||||
int UnaryByPointer(int* value) const {
|
||||
++call_count;
|
||||
return ++(*value);
|
||||
}
|
||||
int UnaryByRef(const int& value) const {
|
||||
++call_count;
|
||||
return ++const_cast<int&>(value);
|
||||
}
|
||||
int Multiply(int a, int b) const { ++call_count; return a * b; }
|
||||
void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
|
||||
EXPECT_TRUE(object.get() != nullptr);
|
||||
}
|
||||
|
||||
mutable int call_count;
|
||||
};
|
||||
|
||||
struct A { int dummy; };
|
||||
struct B: public RefCountInterface { int dummy; };
|
||||
struct C: public A, B {};
|
||||
struct D {
|
||||
int AddRef();
|
||||
};
|
||||
struct E: public D {
|
||||
int Release();
|
||||
};
|
||||
struct F {
|
||||
void AddRef();
|
||||
void Release();
|
||||
};
|
||||
|
||||
struct LifeTimeCheck {
|
||||
LifeTimeCheck() : ref_count_(0) {}
|
||||
void AddRef() { ++ref_count_; }
|
||||
void Release() { --ref_count_; }
|
||||
void NullaryVoid() {}
|
||||
int ref_count_;
|
||||
};
|
||||
|
||||
int Return42() { return 42; }
|
||||
int Negate(int a) { return -a; }
|
||||
int Multiply(int a, int b) { return a * b; }
|
||||
|
||||
} // namespace
|
||||
|
||||
// Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
|
||||
// compile time.
|
||||
static_assert(
|
||||
is_same<
|
||||
rtc::remove_reference<const scoped_refptr<RefCountInterface>&>::type,
|
||||
const scoped_refptr<RefCountInterface>>::value,
|
||||
"const scoped_refptr& should be captured by value");
|
||||
|
||||
static_assert(is_same<rtc::remove_reference<const scoped_refptr<F>&>::type,
|
||||
const scoped_refptr<F>>::value,
|
||||
"const scoped_refptr& should be captured by value");
|
||||
|
||||
static_assert(
|
||||
is_same<rtc::remove_reference<const int&>::type, const int>::value,
|
||||
"const int& should be captured as const int");
|
||||
|
||||
static_assert(is_same<rtc::remove_reference<const F&>::type, const F>::value,
|
||||
"const F& should be captured as const F");
|
||||
|
||||
static_assert(is_same<rtc::remove_reference<F&>::type, F>::value,
|
||||
"F& should be captured as F");
|
||||
|
||||
#define EXPECT_IS_CAPTURED_AS_PTR(T) \
|
||||
static_assert(is_same<detail::PointerType<T>::type, T*>::value, \
|
||||
"PointerType")
|
||||
#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
|
||||
static_assert( \
|
||||
is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
|
||||
"PointerType")
|
||||
|
||||
EXPECT_IS_CAPTURED_AS_PTR(void);
|
||||
EXPECT_IS_CAPTURED_AS_PTR(int);
|
||||
EXPECT_IS_CAPTURED_AS_PTR(double);
|
||||
EXPECT_IS_CAPTURED_AS_PTR(A);
|
||||
EXPECT_IS_CAPTURED_AS_PTR(D);
|
||||
EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
|
||||
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
|
||||
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
|
||||
|
||||
TEST(BindTest, BindToMethod) {
|
||||
MethodBindTester object = {0};
|
||||
EXPECT_EQ(0, object.call_count);
|
||||
|
|
@ -51,11 +135,20 @@ TEST(BindTest, BindToMethod) {
|
|||
&object, string_value)());
|
||||
EXPECT_EQ(6, object.call_count);
|
||||
int value = 11;
|
||||
EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByRef, &object, value)());
|
||||
// Bind binds by value, even if the method signature is by reference, so
|
||||
// "reference" binds require pointers.
|
||||
EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByPointer, &object, &value)());
|
||||
EXPECT_EQ(12, value);
|
||||
EXPECT_EQ(7, object.call_count);
|
||||
EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
|
||||
// It's possible to bind to a function that takes a const reference, though
|
||||
// the capture will be a copy. See UnaryByRef hackery above where it removes
|
||||
// the const to make sure the underlying storage is, in fact, a copy.
|
||||
EXPECT_EQ(13, Bind(&MethodBindTester::UnaryByRef, &object, value)());
|
||||
// But the original value is unmodified.
|
||||
EXPECT_EQ(12, value);
|
||||
EXPECT_EQ(8, object.call_count);
|
||||
EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
|
||||
EXPECT_EQ(9, object.call_count);
|
||||
}
|
||||
|
||||
TEST(BindTest, BindToFunction) {
|
||||
|
|
@ -64,4 +157,82 @@ TEST(BindTest, BindToFunction) {
|
|||
EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
|
||||
}
|
||||
|
||||
// Test Bind where method object implements RefCountInterface and is passed as a
|
||||
// pointer.
|
||||
TEST(BindTest, CapturePointerAsScopedRefPtr) {
|
||||
LifeTimeCheck object;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
scoped_refptr<LifeTimeCheck> scoped_object(&object);
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
{
|
||||
auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
|
||||
EXPECT_EQ(object.ref_count_, 2);
|
||||
scoped_object = nullptr;
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
}
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
}
|
||||
|
||||
// Test Bind where method object implements RefCountInterface and is passed as a
|
||||
// scoped_refptr<>.
|
||||
TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
|
||||
LifeTimeCheck object;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
scoped_refptr<LifeTimeCheck> scoped_object(&object);
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
{
|
||||
auto functor = Bind(&LifeTimeCheck::NullaryVoid, scoped_object);
|
||||
EXPECT_EQ(object.ref_count_, 2);
|
||||
scoped_object = nullptr;
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
}
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
}
|
||||
|
||||
// Test Bind where method object is captured as scoped_refptr<> and the functor
|
||||
// dies while there are references left.
|
||||
TEST(BindTest, FunctorReleasesObjectOnDestruction) {
|
||||
LifeTimeCheck object;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
scoped_refptr<LifeTimeCheck> scoped_object(&object);
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
Bind(&LifeTimeCheck::NullaryVoid, &object)();
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
scoped_object = nullptr;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
}
|
||||
|
||||
// Test Bind with scoped_refptr<> argument.
|
||||
TEST(BindTest, ScopedRefPointerArgument) {
|
||||
LifeTimeCheck object;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
scoped_refptr<LifeTimeCheck> scoped_object(&object);
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
{
|
||||
MethodBindTester bind_tester;
|
||||
auto functor =
|
||||
Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object);
|
||||
EXPECT_EQ(object.ref_count_, 2);
|
||||
}
|
||||
EXPECT_EQ(object.ref_count_, 1);
|
||||
scoped_object = nullptr;
|
||||
EXPECT_EQ(object.ref_count_, 0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const int* Ref(const int& a) { return &a; }
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Test Bind with non-scoped_refptr<> reference argument, which should be
|
||||
// modified to a non-reference capture.
|
||||
TEST(BindTest, RefArgument) {
|
||||
const int x = 42;
|
||||
EXPECT_EQ(&x, Ref(x));
|
||||
// Bind() should make a copy of |x|, i.e. the pointers should be different.
|
||||
auto functor = Bind(&Ref, x);
|
||||
EXPECT_NE(&x, functor());
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue