[WebRTC] updated to upstream branch 49 and related.

this patch is based on 38d7a7883...226f2f0bd
This commit is contained in:
roytam1 2021-10-01 10:48:39 +08:00
commit a3239eaa4d
2838 changed files with 151221 additions and 159688 deletions

View file

@ -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.

View file

@ -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'],
},

View file

@ -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

View file

@ -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

View 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

View file

@ -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',

View file

@ -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',

View file

@ -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.

View file

@ -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?

View file

@ -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",
]
}
}

View 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",
]
}
}
}

View file

@ -0,0 +1 @@
tkchin@webrtc.org

View 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"
],
}

View 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"
],
}

View file

@ -0,0 +1 @@
tkchin@webrtc.org

View 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.

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -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

View 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

View 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

View 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

View 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

View 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

View file

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 "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

View 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

View 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

View 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

View 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

View 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

View file

@ -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

View 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

View 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

View 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

View file

@ -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

View file

@ -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];
}
}

View 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];
}
}

View file

@ -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];
}
}

View file

@ -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];
}
}

View 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",
]
}

View file

@ -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

View 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

View 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_

View 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

View 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

View 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_

View 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

View 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_

View 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

View 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_

View 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

View 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_

View 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_

View 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',
],
},
}

View 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_

View 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_

View 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_

View file

@ -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",
]
}
}

View file

@ -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

View 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_

View 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

View file

@ -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)))

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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) {

View file

@ -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_

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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() {

View file

@ -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_

View file

@ -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.

View file

@ -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,

View file

@ -81,7 +81,7 @@ class AutoDetectProxy : public SignalThread {
AsyncSocket* socket_;
int next_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy);
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy);
};
} // namespace rtc

View file

@ -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);

View file

@ -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;
}

View file

@ -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_;

View file

@ -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)',
],
}],
],
},
],

View file

@ -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',
],
}],

View file

@ -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_

View file

@ -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

View file

@ -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]])

View file

@ -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